比赛打完了,来继续搞了,因为那个主动防御正在写,所以想找找思路正好想到可以来逆向一下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. Java入门:基础算法之求数组元素的和

    本程序计算数组中所有元素的和. 代码1:数组元素由程序内部初始化 /** * @author: 理工云课堂 * @description: 求数组元素的和 */ class SumOfArray{ p ...

  2. python基础之collections模块

    Counter Counter是一个简单的计数器,可以统计一段字符串中各个元素出现的次数: import collections counter_1=collections.Counter('kjsd ...

  3. linq的语法和案例

    本篇逐一介绍linq各个关键字的用法(from,select,group,into等),本篇所有的案例都是用linqpad来完成的(官方地址:http://www.linqpad.net/),建议想学 ...

  4. newcoder Wannafly挑战赛4 树的距离

    https://www.nowcoder.com/acm/contest/35/D 假设要查询x的子树中,与x的距离>=y的距离和 那么如果有这么一个 由x的子树中的点到x的距离构成的序列,且按 ...

  5. nginx.conf 基础配置

    ### 全局块开始### #配置允许运行nginx服务器的用户和用户组 user nobody; #配置允许nginx进程生成的worker process 数 worker_processes 1; ...

  6. 你知道吗?什么是 Responsive JavaScript ?

    Responsive Javascript 是什么? 简单来说就是可以根据浏览器的状态做出响应.响应包括对视窗大小的反应,根据你设备是否支持触摸事件或地理定位功能来决定是否显示特定内容,不一而足. 什 ...

  7. jQuery精仿手机上的翻牌效果菜单

    代码简介: jQuery精仿手机上的翻牌效果菜单,很平滑的动画翻牌效果,每点击一下菜单,就会翻去一下,貌似很灵敏的动作.注意:如果预览时没看到效果,请刷新一下页面,让jquery载入就行了,在实际使用 ...

  8. Anaconda+django写出第一个web app(二)

    今天开始建立App中的第一个Model,命名为Tutorial. Model的定义在main文件夹下的models.py中通过类进行,我们希望Tutorial这个model包含三个属性:标题.内容和发 ...

  9. zzd 的割草机(Lawnmower)

    评测传送门 [题目描述] 已知花坛为一个 n * m 的矩形,草只会长在某些个格子上,zzd 有一个割草机,一开始,zzd 站在(1,1)处,面向(1,m)(面向右).每次 zzd 有两个选择(耗费一 ...

  10. D. Makoto and a Blackboard(积性函数+DP)

    题目链接:http://codeforces.com/contest/1097/problem/D 题目大意:给你n和k,每一次可以选取n的因子代替n,然后问你k次操作之后,每个因子的期望. 具体思路 ...