返回顶部

内核获取未导出函数:PspAlloCateThread

第一步: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(&函数地址))
    {
        return 0;
    }
    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中的地址获取

结果:

 

posted @ 2020-09-16 00:16  一身白_粉条  阅读(587)  评论(0编辑  收藏  举报