比赛打完了,来继续搞了,因为那个主动防御正在写,所以想找找思路正好想到可以来逆向一下PT的驱动模块看看pt大大是怎么写的程序。

PT x64版本的驱动模块是这个kEvP64.sys。

0x0

先来看看DriverEntry

 //IDA伪代码
__int64 __fastcall sub_3A010(struct _DRIVER_OBJECT *a1, __int64 a2)
{
char *v2; // rdi@1
signed __int64 i; // rcx@1
char *v4; // rdi@4
__int64 v5; // rsi@4
signed __int64 j; // rcx@4
_UNKNOWN *v7; // rdi@7
char *v8; // rsi@7
signed __int64 k; // rcx@7
__int64 result; // rax@11
unsigned int v11; // [sp+48h] [bp-A0h]@10
NTSTATUS v12; // [sp+48h] [bp-A0h]@12
NTSTATUS v13; // [sp+48h] [bp-A0h]@14
char v14; // [sp+ACh] [bp-3Ch]@1
char v15; // [sp+C0h] [bp-28h]@4
struct _DRIVER_OBJECT *DriverObject; // [sp+F0h] [bp+8h]@1 DriverObject = a1;
v2 = &v14;
for ( i = 4i64; i; --i )
*v2++ = ;
v4 = &v15;
v5 = a2;
for ( j = 16i64; j; --j )
*v4++ = *(_BYTE *)v5++;
v7 = &unk_37C60;
v8 = &v15;
for ( k = 16i64; k; --k )
{
*(_BYTE *)v7 = *v8++;
v7 = (char *)v7 + ;
}
RtlGetVersion(&unk_37AE0);
v11 = sub_19A30();
if ( (v11 & 0x80000000) == )
{
sub_39010();
DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_29870;
RtlInitUnicodeString(&DeviceName, L"\\Device\\kEvP64");
v12 = IoCreateDevice(DriverObject, , &DeviceName, 0x22u, 0x100u, , &DeviceObject);
if ( v12 >= )
{
DriverObject->MajorFunction[] = (PDRIVER_DISPATCH)sub_298F0;
DriverObject->MajorFunction[] = (PDRIVER_DISPATCH)sub_298F0;
DriverObject->MajorFunction[] = (PDRIVER_DISPATCH)sub_29940;
RtlInitUnicodeString(&SymbolicLinkName, L"\\DosDevices\\kEvP64");
v13 = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
if ( v13 >= )
{
FltRegisterFilter(DriverObject, &unk_300C0, &qword_37AA8);
*((_DWORD *)DriverObject->DriverSection + ) |= 0x20u;
qword_37C28 = (__int64)DriverObject;
result = 0i64;
}
else
{
IoDeleteDevice(DeviceObject);
result = (unsigned int)v13;
}
}
else
{
result = (unsigned int)v12;
}
}
else
{
result = v11;
}
return result;
}

函数的26、27行把程序的注册表目录的字符串保存到了局部数组中,然后又存在了一个全局的缓冲区里,应该是一个全局数组。

然后是进行系统版本的判断,对于驱动模块来说判断系统很重要,否则很容易造成蓝屏。

使用RtlGetVersion获得一个有关系统信息的结构,WDK中对这个函数的描述如下

RtlGetVersion
The RtlGetVersion routine returns version information about the currently running operating system. NTSTATUS
RtlGetVersion(
IN OUT PRTL_OSVERSIONINFOW lpVersionInformation
);

来看看pt是怎么对版本进行的判断,

首先是对IRQL进行的判断,代码如下

   if ( (signed int)(unsigned __int8)sub_11030() >  )
{
v0 = sub_11030();
DbgPrint("EX: Pageable code called at IRQL %d\n", v0);
sub_11020();
}

其中sub_11030的反汇编如下

刚开始没明白是什么意思,后来查了一下原来X64的IRQL储存在CR8里,这个以前还真的不知道,学到了。

判断了一下IRQL是否合理,然后就是具体的判断了。

   v2 = dword_37964;
v4 = dword_37968;
v3 = (unsigned __int16)word_37A74;
DbgPrint(
"[kEvP64]Windows %d.%d, SP%d.%d, build %d\n",
(unsigned int)dword_37964,
(unsigned int)dword_37968,
(unsigned __int16)word_37A74);
dword_37908 = ;
dword_378E0 = ;
if ( v2 == && v4 == )
{
dword_378FC = ;
if ( !v3 )
return 3221225659i64;
if ( v3 == )
return 3221225659i64;
if ( v3 != && v3 != )
return 3221225659i64;
return 0i64;
}
if ( v2 == && v4 == )
{
dword_378FC = ;
if ( v3 && v3 != && v3 != )
return 3221225659i64;
return 0i64;
}
if ( v2 == && !v4 )
{
dword_378FC = ;
if ( v3 )
{
if ( v3 == )
{
dword_37C40 = ;
dword_37C50 = ;
}
else
{
if ( v3 != )
return 3221225659i64;
dword_37C40 = ;
dword_37C50 = ;
}
}
else
{
dword_37C40 = ;
dword_37C50 = ;
}
dword_37C58 = ;
dword_37C70 = ;
dword_37C54 = ;
dword_378E4 = ;
dword_37A90 = ;
dword_378F8 = ;
dword_378F0 = ;
dword_37AC0 = ;
dword_37C44 = ;
dword_37C48 = ;
dword_37BF4 = ;
dword_37930 = ;
dword_378F4 = ;
dword_37AB0 = ;
dword_37C4C = ;
dword_37920 = ;
dword_37AC4 = ;
dword_37BF8 = ;
dword_37888 = ;
dword_37908 = ;
dword_377CC = ;
dword_37894 = ;
dword_377C4 = ;
dword_377B0 = ;
dword_377B4 = ;
dword_377B8 = ;
dword_377BC = ;
dword_377C0 = ;
dword_3788C = ;
dword_37890 = ;
dword_37898 = ;
dword_3789C = ;
dword_378A0 = ;
return 0i64;
}
if ( v2 == && v4 == )
{
dword_378FC = ;
if ( v3 && v3 != )
return 3221225659i64;
dword_37C58 = ;
dword_37C70 = ;
dword_37C54 = ;
dword_378E4 = ;
dword_37A90 = ;
dword_378F8 = ;
dword_37C40 = ;
dword_37C50 = ;
dword_378F0 = ;
dword_37AC0 = ;
dword_37C44 = ;
dword_37C48 = ;
dword_37BF4 = ;
dword_37C30 = ;
dword_37C14 = ;
dword_37930 = ;
dword_378F4 = ;
dword_37BF8 = ;
dword_37888 = ;
dword_37AB0 = ;
dword_37C4C = ;
dword_37920 = ;
dword_37AC4 = ;
dword_37908 = ;
dword_377CC = ;
dword_37894 = ;
dword_377C4 = ;
dword_377B0 = ;
dword_377B4 = ;
dword_377B8 = ;
dword_377BC = ;
dword_377C0 = ;
dword_3788C = ;
dword_37890 = ;
dword_37898 = ;
dword_3789C = ;
dword_378A0 = ;
DbgPrint("[kEvP64]Initialized version-specific data for Windows 7 SP%d\n", v3);
return 0i64;
}
if ( v2 == && v4 == )
{
dword_378FC = ;
dword_37C58 = ;
dword_37C70 = ;
dword_37C54 = -;
dword_378E4 = -;
dword_37A90 = ;
dword_378F8 = ;
dword_37C40 = ;
dword_37C50 = ;
dword_378F0 = ;
dword_37AC0 = ;
dword_37908 = ;
dword_37C10 = ;
dword_378E0 = ;
dword_37C44 = ;
dword_37C48 = ;
dword_37BF4 = ;
dword_37C30 = ;
dword_37C14 = ;
dword_37930 = ;
dword_378F4 = ;
dword_37BF8 = ;
dword_37888 = ;
dword_37AB0 = ;
dword_37C4C = ;
dword_37920 = ;
dword_37AC4 = ;
dword_377CC = ;
dword_37894 = ;
dword_377C4 = ;
dword_377B0 = ;
dword_377B4 = ;
dword_377B8 = ;
dword_377BC = ;
dword_377C0 = ;
dword_3788C = ;
dword_37890 = ;
dword_37898 = ;
dword_3789C = ;
dword_378A0 = ;
DbgPrint("[kEvP64]Initialized version-specific data for Windows 8 SP%d\n", v3);
return 0i64;
}
if ( v2 == && v4 == )
{
dword_378FC = ;
dword_37C54 = -;
dword_378E4 = -;
dword_37C58 = ;
dword_378F8 = ;
dword_37C70 = ;
dword_37A90 = ;
dword_37C40 = ;
dword_37C50 = ;
dword_378F0 = ;
dword_37AC0 = ;
dword_37908 = ;
dword_37C10 = ;
dword_378E0 = ;
dword_37C44 = ;
dword_37C48 = ;
dword_37BF4 = ;
dword_37C30 = ;
dword_37C14 = ;
dword_37930 = ;
dword_378F4 = ;
dword_37BF8 = ;
dword_37888 = ;
dword_37AB0 = ;
dword_37C4C = ;
dword_37920 = ;
dword_37AC4 = ;
dword_377CC = ;
dword_37894 = ;
dword_377C4 = ;
dword_377B0 = ;
dword_377B4 = ;
dword_377B8 = ;
dword_377BC = ;
dword_377C0 = ;
dword_3788C = ;
dword_37890 = ;
dword_37898 = ;
dword_3789C = ;
dword_378A0 = ;
DbgPrint("[kEvP64]Initialized version-specific data for Windows 8.1 SP%d\n", v3);
return 0i64;
}
if ( v2 == && !v4 )
{
dword_378FC = ;
dword_37C54 = -;
dword_378E4 = -;
dword_37C58 = ;
dword_378F8 = ;
dword_37C70 = ;
dword_37A90 = ;
dword_378F0 = ;
dword_37C40 = ;
dword_37C50 = ;
dword_37AC0 = ;
dword_37908 = ;
dword_37C10 = ;
dword_378E0 = ;
dword_37C44 = ;
dword_37C48 = ;
dword_37BF4 = ;
dword_37C30 = ;
dword_37C14 = ;
dword_37930 = ;
dword_378F4 = ;
dword_37BF8 = ;
dword_37888 = ;
dword_37AB0 = ;
dword_37C4C = ;
dword_37920 = ;
dword_37AC4 = ;
dword_377CC = ;
dword_37894 = ;
dword_377C4 = ;
dword_377B0 = ;
dword_377B4 = ;
dword_377B8 = ;
dword_377BC = ;
dword_377C0 = ;
dword_3788C = ;
dword_37890 = ;
dword_37898 = ;
dword_3789C = ;
dword_378A0 = ;
return 0i64;
}
if ( v2 == && v4 || v2 > 0xA )
{
dword_378FC = -;
result = 3221225659i64;
}
else
{
result = 3221225659i64;
}
return result;
}

其中v2,v3,v4都是结构体中的成员,就是上面用RtlGetVersion获取到的结构体。

类似于return 3221225659i64;这种是NTSTATUS值,0就是STATUS_SUCESS,下面还可以看到

(v11 & 0x80000000) == 0

这种写法就是NT_SUCESS()宏

来具体看下这种判断过程是怎么个意思

 dword_37960 = ;
v2 = RtlGetVersion(&dword_37960);

这个是指定使用了RTL_OSVERSIONINFOEXW结构,因为RtlGetVersion这个函数其实可以支持两种格式的输出。

根据反汇编的结果还原了一下C的源码,应该是根据不同的系统版本设置了全局变量不同的值,但是目前还不知道这些变量的作用,判断系统方法比较简单,根据dwMajorVersion判断主版本号,dwMinorVersion判断副版本号,再根据需要去判断wServicePackMajor的值就可以实现了。

 RTL_OSVERSIONINFOEXW Struct={};
ULONG Version;
NTSTATUS CheckVersion(void)
{
ULONG MajorVersion;
ULONG MinorVersion;
ULONG ServicePackMajor;
ULONG IRQL;
ULONG result;
RtlGetVersion(&Struct);
if(KeGetCurrentirql()>PASSIVE_LEVEL)
{
IRQL=KeGetCurrentirql();
DbgPrint("EX: Pageable code called at IRQL %d\n", IRQL);
_asm{int 0x2c};
}
MajorVersion=Struct.dwMajorVersion;
MinorVersion=Struct.dwMinorVersion;
ServicePackMajor=Struct.wServicePackMajor;
DbgPrint(
"[kEvP64]Windows %d.%d, SP%d.%d, build %d\n",Struct.dwMajorVersion,Struct.dwMinorVersion,Struct.wServicePackMajor);
if(MajorVersion==&&MinorVersion==)
{
//WINDOWS_XP
Version=;
if(!ServicePackMajor)
return ;
if(ServicePackMajor==)
return ;
if(ServicePackMajor!=&&ServicePackMajor!=)
return ;
return STATUS_SUCCESS;
}
if(MajorVersion==&&MinorVersion==)
{
//WINDOWS_2003
Version=;
if(ServicePackMajor&&ServicePackMajor!=&&ServicePackMajor!=)
return ;
return STATUS_SUCCESS;
}
if(MajorVersion==&&!MinorVersion)
{
//WINDOWS_2003
Version=;
if(ServicePackMajor)
{
if(ServicePackMajor==)
{
dword_37C40 = ;
dword_37C50 = ;
}
else
{
if(ServicePackMajor!=)
return ;
dword_37C40 = ;
dword_37C50 = ;
}
}
else
{
dword_37C40 = ;
dword_37C50 = ;
}
dword_37C58 = ;
dword_37C70 = ;
dword_37C54 = ;
dword_378E4 = ;
dword_37A90 = ;
dword_378F8 = ;
dword_378F0 = ;
dword_37AC0 = ;
dword_37C44 = ;
dword_37C48 = ;
dword_37BF4 = ;
dword_37930 = ;
dword_378F4 = ;
dword_37AB0 = ;
dword_37C4C = ;
dword_37920 = ;
dword_37AC4 = ;
dword_37BF8 = ;
dword_37888 = ;
dword_37908 = ;
dword_377CC = ;
dword_37894 = ;
dword_377C4 = ;
dword_377B0 = ;
dword_377B4 = ;
dword_377B8 = ;
dword_377BC = ;
dword_377C0 = ;
dword_3788C = ;
dword_37890 = ;
dword_37898 = ;
dword_3789C = ;
dword_378A0 = ;
return STATUS_SUCCESS;
}
if(MajorVersion==&&MinorVersion==)
{
//WINDOWS_7
Version=;
if(ServicePackMajor&&ServicePackMajor!=)
return ;
dword_37C58 = ;
dword_37C70 = ;
dword_37C54 = ;
dword_378E4 = ;
dword_37A90 = ;
dword_378F8 = ;
dword_37C40 = ;
dword_37C50 = ;
dword_378F0 = ;
dword_37AC0 = ;
dword_37C44 = ;
dword_37C48 = ;
dword_37BF4 = ;
dword_37C30 = ;
dword_37C14 = ;
dword_37930 = ;
dword_378F4 = ;
dword_37BF8 = ;
dword_37888 = ;
dword_37AB0 = ;
dword_37C4C = ;
dword_37920 = ;
dword_37AC4 = ;
dword_37908 = ;
dword_377CC = ;
dword_37894 = ;
dword_377C4 = ;
dword_377B0 = ;
dword_377B4 = ;
dword_377B8 = ;
dword_377BC = ;
dword_377C0 = ;
dword_3788C = ;
dword_37890 = ;
dword_37898 = ;
dword_3789C = ;
dword_378A0 = ;
DbgPrint("[kEvP64]Initialized version-specific data for Windows 7 SP%d\n", ServicePackMajor);
return STATUS_SUCCESS; }
if(MajorVersion==&&MinorVersion==)
{
//WINDOWS_8
dword_378FC = ;
dword_37C58 = ;
dword_37C70 = ;
dword_37C54 = -;
dword_378E4 = -;
dword_37A90 = ;
dword_378F8 = ;
dword_37C40 = ;
dword_37C50 = ;
dword_378F0 = ;
dword_37AC0 = ;
dword_37908 = ;
dword_37C10 = ;
dword_378E0 = ;
dword_37C44 = ;
dword_37C48 = ;
dword_37BF4 = ;
dword_37C30 = ;
dword_37C14 = ;
dword_37930 = ;
dword_378F4 = ;
dword_37BF8 = ;
dword_37888 = ;
dword_37AB0 = ;
dword_37C4C = ;
dword_37920 = ;
dword_37AC4 = ;
dword_377CC = ;
dword_37894 = ;
dword_377C4 = ;
dword_377B0 = ;
dword_377B4 = ;
dword_377B8 = ;
dword_377BC = ;
dword_377C0 = ;
dword_3788C = ;
dword_37890 = ;
dword_37898 = ;
dword_3789C = ;
dword_378A0 = ;
DbgPrint("[kEvP64]Initialized version-specific data for Windows 8 SP%d\n", ServicePackMajor);
return STATUS_SUCCESS;
}
if ( MajorVersion == && MinorVersion == )
{
//WINDOWS_8.1
dword_378FC = ;
dword_37C54 = -;
dword_378E4 = -;
dword_37C58 = ;
dword_378F8 = ;
dword_37C70 = ;
dword_37A90 = ;
dword_37C40 = ;
dword_37C50 = ;
dword_378F0 = ;
dword_37AC0 = ;
dword_37908 = ;
dword_37C10 = ;
dword_378E0 = ;
dword_37C44 = ;
dword_37C48 = ;
dword_37BF4 = ;
dword_37C30 = ;
dword_37C14 = ;
dword_37930 = ;
dword_378F4 = ;
dword_37BF8 = ;
dword_37888 = ;
dword_37AB0 = ;
dword_37C4C = ;
dword_37920 = ;
dword_37AC4 = ;
dword_377CC = ;
dword_37894 = ;
dword_377C4 = ;
dword_377B0 = ;
dword_377B4 = ;
dword_377B8 = ;
dword_377BC = ;
dword_377C0 = ;
dword_3788C = ;
dword_37890 = ;
dword_37898 = ;
dword_3789C = ;
dword_378A0 = ;
DbgPrint("[kEvP64]Initialized version-specific data for Windows 8.1 SP%d\n", ServicePackMajor);
return STATUS_SUCCESS;
}
if ( MajorVersion == && !MinorVersion )
{
//WINDOWS_10
dword_378FC = ;
dword_37C54 = -;
dword_378E4 = -;
dword_37C58 = ;
dword_378F8 = ;
dword_37C70 = ;
dword_37A90 = ;
dword_378F0 = ;
dword_37C40 = ;
dword_37C50 = ;
dword_37AC0 = ;
dword_37908 = ;
dword_37C10 = ;
dword_378E0 = ;
dword_37C44 = ;
dword_37C48 = ;
dword_37BF4 = ;
dword_37C30 = ;
dword_37C14 = ;
dword_37930 = ;
dword_378F4 = ;
dword_37BF8 = ;
dword_37888 = ;
dword_37AB0 = ;
dword_37C4C = ;
dword_37920 = ;
dword_37AC4 = ;
dword_377CC = ;
dword_37894 = ;
dword_377C4 = ;
dword_377B0 = ;
dword_377B4 = ;
dword_377B8 = ;
dword_377BC = ;
dword_377C0 = ;
dword_3788C = ;
dword_37890 = ;
dword_37898 = ;
dword_3789C = ;
dword_378A0 = ;
return STATUS_SUCCESS;
}
if ( MajorVersion == && MajorVersion || MinorVersion > 0xA )
{
dword_378FC = -;
result = ;
}
else
{
result = ;
}
return result;
}

因为代码比较长,我默认折叠了,想看的可以看下。

我们继续往下看了,接下来主要做了如下几件事:

  1. 创建一个设备
  2. 创建符号链接
  3. 设置设备分发函数
  4. 注册一个过滤驱动

首先作者实现了一个获取导出函数地址的函数,我想这是因为作者想使用一些已经导出但是没有在WDK文档中的函数吧。我这里取名为GetFuncAddress了。我用C重写了一下这个函数,如下

//根据反汇编写的
PVOID GetFuncAddress(WCHAR *Name)
{
ULONG IRQL;
UNICODE_STRING UnicodeFindName;
WCHAR *BufPointer=Name;
if(KeGetCurrentirql()>)
{
IRQL=KeGetCurrentirql();
DbgPrint("EX: Pageable code called at IRQL %d\n", IRQL);
_asm{int 0x2C};
}
RtlInitUnicodeString(&UnicodeFindName,BufPointer);
return MmGetSystemRoutineAddress(&UnicodeFindName);
}

然后作者用这个函数获取一些函数的地址(先判断了一下系统的版本),函数的列表如下

"ExfUnblockPushLock"
"ObGetObjectType"
"ObDereferenceObject"
"PsAcquireProcessExitSynchronization"
"PsIsProtectedProcess"
"PsReleaseProcessExitSynchronization"
"PsResumeProcess"
"PsSuspendProcess"
"KeSetAffinityThread"

这些部分都在第39行的sub_39010();函数中,程序判断完系统版本后马上就执行了这个函数。

这个函数的伪代码如下

 __int64 sub_39010()
{
unsigned __int8 v0; // al@2
__int64 result; // rax@15 if ( (signed int)(unsigned __int8)sub_11030() > )
{
v0 = sub_11030();
DbgPrint("EX: Pageable code called at IRQL %d\n", v0);
sub_11020();
}
if ( (unsigned int)dword_378FC >= 0x3E )
qword_37AB8 = (__int64)sub_392B0(L"ExfUnblockPushLock");
qword_37928 = (__int64)sub_392B0(L"ObGetObjectType");
qword_378E8 = (__int64)sub_392B0(L"ObDereferenceObject");
qword_378D8 = (__int64)sub_392B0(L"PsAcquireProcessExitSynchronization");
qword_37A98 = (__int64)sub_392B0(L"PsIsProtectedProcess");
qword_37C38 = (__int64)sub_392B0(L"PsReleaseProcessExitSynchronization");
qword_37900 = (__int64)sub_392B0(L"PsResumeProcess");
qword_37C20 = (__int64)sub_392B0(L"PsSuspendProcess");
qword_378B8 = (__int64)sub_392B0(L"KeSetAffinityThread");
sub_26AD0((__int64)qword_39A00, (__int64)"KfdClassify2");
sub_26AD0((__int64)qword_39A00, (__int64)"GetCalloutEntry ");
sub_26AD0((__int64)qword_39A00, (__int64)"InitDefaultCallout ");
qword_377F8 = sub_26AD0((__int64)qword_39A70, (__int64)"KeInsertQueueApc");
if ( !qword_377F8 )
qword_377F8 = (__int64)sub_392B0(L"KeInsertQueueApc");
qword_37800 = sub_26AD0((__int64)qword_39A70, (__int64)"PsSetCreateProcessNotifyRoutine");
if ( !qword_37800 )
qword_37800 = (__int64)sub_392B0(L"PsSetCreateProcessNotifyRoutine");
qword_37808 = sub_26AD0((__int64)qword_39A70, (__int64)"PsSetCreateThreadNotifyRoutine");
if ( !qword_37808 )
qword_37808 = (__int64)sub_392B0(L"PsSetCreateThreadNotifyRoutine");
qword_37810 = sub_26AD0((__int64)qword_39A70, (__int64)"PsSetLoadImageNotifyRoutine");
if ( !qword_37810 )
qword_37810 = (__int64)sub_392B0(L"PsSetLoadImageNotifyRoutine");
qword_37818 = sub_26AD0((__int64)qword_39A70, (__int64)"CmUnRegisterCallback");
if ( !qword_37818 )
qword_37818 = (__int64)sub_392B0(L"CmUnRegisterCallback");
result = sub_26AD0((__int64)qword_39A70, (__int64)"IoRegisterShutdownNotification");
qword_37820 = result;
if ( !result )
{
result = (__int64)sub_392B0(L"IoRegisterShutdownNotification");
qword_37820 = result;
}
return result;
}

这个函数首先判断了一下IRQL这个在之前就已经分析过了,然后判断了一下系统版本,通过验证之后用自己实现的GetFuncAddress函数来获取这些函数的地址,并把地址储存在全局变量中sub_392B0就是GetFuncAddress(),然后又调用了sub_26AD0()这个函数,这个函数中又调用了这个函数

 //IDA伪代码,被sub_39010()调用
PVOID __fastcall sub_260D0(unsigned int a1)
{
PVOID result; // rax@3
int v2; // [sp+20h] [bp-28h]@4
int v3; // [sp+24h] [bp-24h]@4
SIZE_T NumberOfBytes; // [sp+28h] [bp-20h]@1
PVOID P; // [sp+30h] [bp-18h]@2
unsigned int v6; // [sp+50h] [bp+8h]@1 v6 = a1;
for ( LODWORD(NumberOfBytes) = ; ; LODWORD(NumberOfBytes) = v3 + )
{
P = ExAllocatePool(, (unsigned int)NumberOfBytes);
if ( !P )
return 0i64;
v3 = ;
v2 = ZwQuerySystemInformation(v6, P, (unsigned int)NumberOfBytes, &v3);
if ( v2 == - )
{
ExFreePoolWithTag(P, );
P = 0i64;
if ( v3 )
continue;
}
break;
}
if ( v2 >= )
{
result = P;
}
else
{
sub_199F0(P);
result = 0i64;
}
return result;
}

这是调用ZwQuerySystemInformation()函数的11号功能也就是SystemModuleInformation功能,这个函数经常在安全类程序中调用,作为一个常规的枚举模块的方法。用循环是为了让ZwQuerySystemInformation返回需要的合适的大小。这个函数返回的结构如下

 typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Count;
SYSTEM_MODULE_INFORMATION_ENTRY Module[];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

Count为个数,有多少Count就有多少的SYSTEM_MODULE_INFORMATION_ENTRY,其中这个数组中的项的结构如下:

typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
HANDLE Section;
PVOID MappedBase;
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[];
} SYSTEM_MODULE_INFORMATION_ENTRY,
*PSYSTEM_MODULE_INFORMATION_ENTRY;

注意这个调用返回的第一个模块一定是ntoskrnl.exe模块,很多人就是通过这个调用去获取内核模块的信息的。

 __int64 __fastcall sub_21DB0(const char *a1)
{
__int64 result; // rax@2
UNICODE_STRING String1; // [sp+20h] [bp-108h]@3
UNICODE_STRING String2; // [sp+30h] [bp-F8h]@12
NTSTATUS v4; // [sp+40h] [bp-E8h]@1
PCWSTR v5; // [sp+48h] [bp-E0h]@1
__int64 v6; // [sp+50h] [bp-D8h]@1
__int64 v7; // [sp+58h] [bp-D0h]@1
__int64 v8; // [sp+60h] [bp-C8h]@1
__int64 v9; // [sp+68h] [bp-C0h]@1
__int64 v10; // [sp+70h] [bp-B8h]@1
unsigned int i; // [sp+78h] [bp-B0h]@1
UNICODE_STRING v12; // [sp+80h] [bp-A8h]@1
UNICODE_STRING v13; // [sp+90h] [bp-98h]@19
STRING v14; // [sp+A0h] [bp-88h]@3
STRING v15; // [sp+B0h] [bp-78h]@8
PCWSTR v16; // [sp+C0h] [bp-68h]@1
__int64 v17; // [sp+C8h] [bp-60h]@1
__int64 v18; // [sp+D0h] [bp-58h]@1
__int64 v19; // [sp+D8h] [bp-50h]@1
UNICODE_STRING UnicodeString; // [sp+E0h] [bp-48h]@8
int j; // [sp+F0h] [bp-38h]@1
PVOID v22; // [sp+F8h] [bp-30h]@1
UNICODE_STRING DestinationString; // [sp+100h] [bp-28h]@1
__int64 v24; // [sp+110h] [bp-18h]@1
PCSZ SourceString; // [sp+130h] [bp+8h]@1 SourceString = a1;
v24 = 0i64;
v4 = ;
i = ;
j = ;
v5 = L"hal.dll";
v6 = (__int64)L"halacpi.dll";
v7 = (__int64)L"halapic.dll";
v8 = (__int64)L"halmps.dll";
v9 = (__int64)L"halaacpi.dll";
v10 = (__int64)L"halmacpi.dll";
v16 = L"ntoskrnl.exe";
v17 = (__int64)L"ntkrnlpa.exe";
v18 = (__int64)L"ntkrnlmp.exe";
v19 = (__int64)L"ntkrpamp.exe";
v22 = 0i64;
RtlInitUnicodeString(&DestinationString, L"hal.dll");
RtlInitUnicodeString(&v12, L"ntoskrnl.exe");
v22 = sub_260D0(11u);
if ( v22 )
{
RtlInitAnsiString(&v14, SourceString);
v4 = RtlAnsiStringToUnicodeString(&String1, &v14, 1u);
if ( v4 >= )
{
for ( i = ; ; ++i )
{
if ( i < *(_DWORD *)v22 )
{
RtlInitAnsiString(&v15, (PCSZ)v22 + * i + *((_WORD *)v22 + * i + ) + );
v4 = RtlAnsiStringToUnicodeString(&UnicodeString, &v15, 1u);
if ( v4 < )
continue;
if ( RtlEqualUnicodeString(&String1, &DestinationString, ) )
{
for ( j = ; j < ; ++j )
{
RtlInitUnicodeString(&String2, (&v5)[ * j]);
if ( RtlEqualUnicodeString(&UnicodeString, &String2, ) )
{
v24 = *((_QWORD *)v22 + * i + );
break;
}
}
}
else if ( RtlEqualUnicodeString(&String1, &v12, ) )
{
for ( j = ; j < ; ++j )
{
RtlInitUnicodeString(&v13, (&v16)[ * j]);
if ( RtlEqualUnicodeString(&UnicodeString, &v13, ) )
{
v24 = *((_QWORD *)v22 + * i + );
break;
}
}
}
else if ( RtlEqualUnicodeString(&String1, &UnicodeString, ) )
{
v24 = *((_QWORD *)v22 + * i + );
}
RtlFreeUnicodeString(&UnicodeString);
if ( !v24 )
continue;
}
break;
}
RtlFreeUnicodeString(&String1);
sub_199F0(v22);
result = v24;
}
else
{
result = 0i64;
}
}
else
{
result = 0i64;
}
return result;
}

这个是遍历刚才得到的结果,就是刚才得到的SYSTEM_MODULE_INFORMATION结构。如果要得到的目标模块是nt内核模块或是hal.dll的话就特殊处理

0x1

接下来就是进入正题了,来看看PT的分发例程,在看分发例程之前先总结下,如下图

图中的真正的功能函数就是我们要分析的重点,PT的大部分功能都在这里完成。

0x2

我们来看switch语句,这个语句由最后的一个 DbgPrint("[kEvP64] Unknown IOCTL: 0x%X (%04X,%04X)\r\n", v37, (v37 & 0xFFFF0000) >> 16, (v37 >> 2) & 0xFFF);就可以看出是DeviceIoControl函数来发送的一些自定义的IOCTL。但是我们没有办法知道具体的含义,因为这些都是自定义的,在C中定义IOCTL也只是用一个宏来完成。

来看下这里

 //IDA伪代码
Irp = a2;
v35 = -;
v27 = 0i64;
v28 = sub_11100((__int64)a2);

注意第5行的sub_11100,参数a2是Irp指针,它的反汇编如下图

只是一个简单的移位操作是吧。我猜这个应该就是IoGetCurrentIrpStackLocation()这个函数,可见IRP中是存有当前IRP栈的指针的。首先是对比Irp栈的总层数是不是大于当前层数,然后就是取出当前栈的指针(这个指针在Irp结构中)返回了。

而我们常用的操作就是

PIO_STACK_LOCATION irpSp;
IoControlCode=irpSp->Parameters.DeviceIoControl.IoControlCode;
switch(IoControlCode)
{
……
}

PowerTool x64驱动模块逆向分析(持续更新)的更多相关文章

  1. Beta 讨论分析——持续更新ing

    wonderland Beta 讨论分析 标签(空格分隔): 软工实践 wonderland 主要工作: info信息: 1.关联账号界面:hbb 2.标签检索界面:hbb 3.近期活跃度(cf.hd ...

  2. BAT 前端开发面经 —— 吐血总结 前端相关片段整理——持续更新 前端基础精简总结 Web Storage You don't know js

    BAT 前端开发面经 —— 吐血总结   目录 1. Tencent 2. 阿里 3. 百度 更好阅读,请移步这里 聊之前 最近暑期实习招聘已经开始,个人目前参加了阿里的内推及腾讯和百度的实习生招聘, ...

  3. 2020/1/29 PHP代码审计之进一步学习XSS【持续更新】

    0x00 上午学习了XSS漏洞,中午吃饭想了想,还是思考的太浅层了,这种老生常谈的东西对于现在的我意义不大.现在我需要的是思考.于是就有了这个随笔.在本文中,我会持续更新一些XSS的深入思考,payl ...

  4. DuiLib逆向分析の按钮事件定位

    目录 DuiLib逆向分析の按钮事件定位 0x00 前言 DuiLib介绍 DuiLib安装 DuiLib Hello,World! Duilib逆向分析之定位按钮事件 碎碎念 第一步:获取xml布局 ...

  5. 我的敏捷、需求分析、UML、软件设计电子书 - 下载(持续更新中)

    我将所有我的电子书汇总在一起,方便大家下载!(持续更新) 文档保存在我的网站——软件知识原创基地上(www.umlonline.org),请放心下载. 1)软件设计是怎样炼成的?(2014-4-1 发 ...

  6. 干货!IT小伙伴们实用的网站及工具大集合!持续更新!

    1.Git 还在担心自己辛辛苦苦写的代码被误删了吗?还在担心自己改错了代码不能挽回吗?还在苦恼于多人开发合作找不到一个好的工具吗?那么用Git就对 了,Git是一个开源的分布式版本控制系统,用以有效. ...

  7. java视频教程 Java自学视频整理(持续更新中...)

    视频教程,马士兵java视频教程,java视频 1.Java基础视频 <张孝祥JAVA视频教程>完整版[RMVB](东西网) 历经5年锤炼(史上最适合初学者入门的Java基础视频)(传智播 ...

  8. BLE资料应用笔记 -- 持续更新

    BLE资料应用笔记 -- 持续更新 BLE 应用笔记 小书匠 简而言之,蓝牙无处不在,易于使用,低耗能和低使用成本.'让我们'更深入地探索这些方面吧. 蓝牙无处不在-,您可以在几乎每一台电话.笔记本电 ...

  9. ( 译、持续更新 ) JavaScript 上分小技巧(三)

    最近家里杂事较多,自学时间实在少的可怜,所以都在空闲时间看看老外写的内容,学习之外顺便翻译分享~等学习的时间充足些再写写自己的一些学习内容和知识点分析(最近有在接触的:复习(C#,SQL).(学习)T ...

随机推荐

  1. strut2以及路径的一些问题

    Struts2一个Action内包含多个请求处理方法的处理,method的使用方法,struts2中 struts2的关于method=“{1}"意思详解 <action   name ...

  2. 【转】基于R语言构建的电影评分预测模型

    一,前提准备         1.R语言包:ggplot2包(绘图),recommenderlab包,reshape包(数据处理)         2.获取数据:大家可以在明尼苏达州大学的社会化计算研 ...

  3. winscp以命令行方式同步服务器数据到PC机磁盘上

    目前服务器上每日会产生备份文件,需要使用winscp工具把备份同步到本地PC机硬盘上.平时都是图形界面用鼠标点击方式来同步的,效率低下,因此编写了winscp自动同步脚本,并加入到计划任务中定时自动运 ...

  4. Python【异常处理】

    def f(): first = input('请输入除数:') second = input('请输入被除数:') try: first = int(first) second = int(seco ...

  5. 手把手教你使用koa2

    简介 koa是由express的原班人马打造的web框架.但是相对于express,koa的性能要更高,因为koa通过使用aysnc函数,帮你丢弃回调函数,并有力的增强了错误处理.而且koa没有绑定任 ...

  6. bzoj千题计划166:bzoj2179: FFT快速傅立叶

    http://www.lydsy.com/JudgeOnline/problem.php?id=2179 FFT做高精乘 #include<cmath> #include<cstdi ...

  7. 流媒体技术学习笔记之(十六)H264编码profile & level控制

    H.264有四种画质级别,分别是baseline, extended, main, high: 1.Baseline Profile:基本画质.支持I/P 帧,只支持无交错(Progressive)和 ...

  8. python学习笔记3-函数的递归

    递归就是指自己函数的自我调用 #递归 #自己调用自己,函数的循环 def test1(): num = int(input('please enter a number:')) if num%2==0 ...

  9. [转载].net程序集自动生成版本号

    原文:http://hi.baidu.com/bcbgrand/item/a74a7ba71c3b0ea928ce9dce .net程序版本号的格式是4个十进制数字 比如 2.5.729.2 依次是 ...

  10. 把JS和CSS合并到1个文件

    合并JS文件和CSS文件很多人都知道,也用过,目的是为了减少请求数.但有时候我们觉的把JS合并到1个文件,CSS又合并到另外1个文件也是浪费,我们如何能把CSS和JS一起合并进1个文件了? 这里需要使 ...