内核获取未导出函数
第一步: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地址长度就是 2for (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