内核获取未导出函数

第一步:IDA查看这个函数的交叉引用,看到PspAlloCateThread 调用了该函数

 

 

 

 

 

 

 

 

 二. 继续查看有谁调用了PspAllocateThread 这个函数

 

 

 

看到了一个导出函数 NtCreateUserProcess ,思路就是   NtCreateUserProcess --> PspAllocateThread --> PspUserThreadStartup  这样子就能找到 PspUserThreadStartup  函数的地址

记录一下特征码 这里我在  NtCreateUserProcess 调用  PspAllocateThread 的call 附加寻找特征码 ,我寻找的特征码是  94 24 18 01   其实这种特征码不靠谱 但这个函数很小而且从函数头到调用的位置只出现一次

这里顺便记录一下  94这个字节  距离真正调用call 相差 9 个字节

 

 

 

接下来寻找 PspAllocateThread 调用 PspUserThreadStartup   附加的特征码,8B 86 10 06   这里距离 lea r8,PspUserThreadStartup   相差16个字节

 

 

 接下来编写一个函数暴力枚举出来

PVOID GetPspUserThreadStartup2(ULONG64 函数地址, 暴力扫描* 信息, UCHAR 特征码[])

{

if (!MmIsAddressValid(&函数地址))

{

return0;

}

INT code1 = NULL;

ULONG64 addr = NULL;

ULONG64 返回地址 = NULL;

for (size_t i = 0; i < 0x1BF8CA; i++)

{

if (memcmp((PVOID)(函数地址 + i), 特征码, 信息->特征码长度) == 0)

{

addr = 函数地址 + i + 信息->特征码距离函数地址偏移;

信息->偏移 = __insn_len_x86((PVOID)addr, __b64); //信息->偏移 可以理解为地址的汇编长度 比如 0x123456 E8 01 这个0x123456地址长度就是 2

for (int i = 信息->偏移; i >= 4; i--)

{

if (i == 4)

{

信息->偏移 = 信息->偏移 - i; //这里算法可以计算出函数调用位置的后四字节

break;

}

}

memcpy(&code1, (PVOID)(addr + 信息->偏移), 4); //这里拷贝 调用的位置后四个字节 比如上面看到的 call PspAllocateThread E8 0D 4E 0C 00 这里需要拿到后四个字节计算函数真正地址 计算公式 函数真正地址=当前地址+后四字节地址+地址长度

函数地址 = (addr + code1 + __insn_len_x86((PVOID)addr, __b64));

返回地址 = 函数地址;

break;

}

}

return (PVOID)返回地址;

}

使用方法,可以定义一个结构体

 

 

 

 

 上面GetFUnaddr  是 NtcreateUserProcess 在SSDT中的编号  获取它在SSDT中的地址获取

结果:

 

以上是 内核获取未导出函数 的全部内容, 来源链接: utcz.com/a/47973.html

回到顶部