首页
社区
课程
招聘
[原创]重载内核实现
发表于: 2020-10-14 17:29 8545

[原创]重载内核实现

2020-10-14 17:29
8545

最近研究重载内核,把论坛里有关的帖子都看了个遍。
最后参考了这两位大佬的贴子:
重载内核全程分析笔记
sidyhe大牛

重载内核是为了过ssdt hook用的,因为ssdt hook太多了,与其跟人家对着干,不如想办法绕过去。

这个需要学习过PE文件结构

1、将内核文件加载到内存并对齐内存格式
2、修复重定位表
3、构造好一个新的SSDT
4、hook KiFastCallEntry

第一步比较简单就不说了,PE文件怎么加载就怎么做。

.

这个很多人都容易写出问题,所以代码我贴一下

这段代码是引用的 重载内核全程分析笔记
因为写的比较详细,我也没怎么改他,直接拿来就用了。
大概的操作就是 重新设置ssdt内的函数

.

hook这个函数的时候,在其内部有这么几行代码
我们要hook的地方就是sub esp, ecx 和 shr ecx, 2这个位置
这个地址是前人找出来的一个绝佳位置
但要注意的是杀毒软件也hook了这个地方,如果你电脑有装杀毒软件了,那么你可能不会顺利的hook
这个位置上edi = ssdt的第一个成员,eax = 函数索引

.
要hook这个函数首先要找到他在哪,大概有下面两种方法:
1、通过msr寄存器0x176位置找到他的地址
2、通过hook原来的ssdt里的函数,回溯查找
本人这里是通过了msr获取的

最后需要自己写一个处理函数
我这写的有点复杂,大概的流程就是判断下是不是hooktest.exe进程
如果是就用新内核,不是就用旧内核

到此也就差不多了,可以直接用了
从pchunter中可以看到已经被hook了,而且系统也没有崩溃,基本算是可以了

然后测试一下用指定名称hooktest.exe的进程来调用下api
我这里打开了一个计算器,然后用hooktest.exe去关闭它

关闭成功

好了差不多就是这样了,基本上已经完成了,需要hook什么函数就自由发挥吧
这个还有很多细节没有处理,就先说到这了。

代码是vs2013 + wdk8.1编译通过

 
 
 
DWORD32 CkRepairRelactionTable(IN OUT PVOID pImageBuffer, IN DWORD32 dwImageBase)
{
 
    //DOS头
    IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pImageBuffer;
    //NT头
    IMAGE_NT_HEADERS* pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD32)pImageBuffer + pDosHeader->e_lfanew);
    //PE头
    IMAGE_FILE_HEADER* pFileHeader = (IMAGE_FILE_HEADER*)((DWORD32)pNtHeaders + sizeof(pNtHeaders->Signature));
    //可选头
    IMAGE_OPTIONAL_HEADER* pOpHeader = (IMAGE_OPTIONAL_HEADER*)((DWORD32)pFileHeader + sizeof(IMAGE_FILE_HEADER));
 
 
    //获取重定位表
    IMAGE_BASE_RELOCATION* pRelocationTable = (IMAGE_BASE_RELOCATION*)((DWORD32)pImageBuffer + pOpHeader->DataDirectory[5].VirtualAddress);
    IMAGE_BASE_RELOCATION* pCurrentRelocationTable = pRelocationTable;
 
    //遍历所有页
    while (pCurrentRelocationTable->VirtualAddress != 0 || pCurrentRelocationTable->SizeOfBlock != 0)
    {
        //当前页需要修改的个数
        DWORD32 dwCnt = (pCurrentRelocationTable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(UINT16);
        //地址位置
        DWORD32 dwAddr = ((DWORD32)pCurrentRelocationTable) + sizeof(IMAGE_BASE_RELOCATION);
 
        for (int i = 0; i < dwCnt; i++)
        {
 
            if ((*(DWORD32*)(dwAddr + i * sizeof(UINT16)) & 0x0000F000) != 0x00003000)
            {
                continue;
            }
 
            //获取要修改的地址
            DWORD32* pRepairAddr = (DWORD32*)((DWORD32)pImageBuffer + pCurrentRelocationTable->VirtualAddress + (*((UINT16*)dwAddr + i) & 0x0FFF));
            //修正重定位表值
            *pRepairAddr += dwImageBase - pOpHeader->ImageBase;
        }
 
        pCurrentRelocationTable = (IMAGE_BASE_RELOCATION*)((DWORD32)&pCurrentRelocationTable->VirtualAddress + pCurrentRelocationTable->SizeOfBlock);
    }
 
    //修改imagebase
    pOpHeader->ImageBase = dwImageBase;
 
 
    return pOpHeader->SizeOfImage;
 
}
DWORD32 CkRepairRelactionTable(IN OUT PVOID pImageBuffer, IN DWORD32 dwImageBase)
{
 
    //DOS头
    IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pImageBuffer;
    //NT头
    IMAGE_NT_HEADERS* pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD32)pImageBuffer + pDosHeader->e_lfanew);
    //PE头
    IMAGE_FILE_HEADER* pFileHeader = (IMAGE_FILE_HEADER*)((DWORD32)pNtHeaders + sizeof(pNtHeaders->Signature));
    //可选头
    IMAGE_OPTIONAL_HEADER* pOpHeader = (IMAGE_OPTIONAL_HEADER*)((DWORD32)pFileHeader + sizeof(IMAGE_FILE_HEADER));
 
 
    //获取重定位表
    IMAGE_BASE_RELOCATION* pRelocationTable = (IMAGE_BASE_RELOCATION*)((DWORD32)pImageBuffer + pOpHeader->DataDirectory[5].VirtualAddress);
    IMAGE_BASE_RELOCATION* pCurrentRelocationTable = pRelocationTable;
 
    //遍历所有页
    while (pCurrentRelocationTable->VirtualAddress != 0 || pCurrentRelocationTable->SizeOfBlock != 0)
    {
        //当前页需要修改的个数
        DWORD32 dwCnt = (pCurrentRelocationTable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(UINT16);
        //地址位置
        DWORD32 dwAddr = ((DWORD32)pCurrentRelocationTable) + sizeof(IMAGE_BASE_RELOCATION);
 
        for (int i = 0; i < dwCnt; i++)
        {
 
            if ((*(DWORD32*)(dwAddr + i * sizeof(UINT16)) & 0x0000F000) != 0x00003000)
            {
                continue;
            }
 
            //获取要修改的地址
            DWORD32* pRepairAddr = (DWORD32*)((DWORD32)pImageBuffer + pCurrentRelocationTable->VirtualAddress + (*((UINT16*)dwAddr + i) & 0x0FFF));
            //修正重定位表值
            *pRepairAddr += dwImageBase - pOpHeader->ImageBase;
        }
 
        pCurrentRelocationTable = (IMAGE_BASE_RELOCATION*)((DWORD32)&pCurrentRelocationTable->VirtualAddress + pCurrentRelocationTable->SizeOfBlock);
    }
 
    //修改imagebase
    pOpHeader->ImageBase = dwImageBase;
 
 
    return pOpHeader->SizeOfImage;
 
}
VOID SetNewSSDT(PVOID pNewImage)
{
    //新内核地址-老内核地址,得到相对偏移
    ULONG uNewKernelInc = (ULONG)pNewImage - OrigImage;
 
    //老内核的ssdt指针加上相对偏移,得到新内核的ssdt指针
    pNewSSDT = (PKSYSTEM_SERVICE_TABLE)((ULONG)KeServiceDescriptorTable + uNewKernelInc);
 
    if (!MmIsAddressValid(pNewSSDT))
    {
        DbgPrint("pNewSSDT is unaviable!\r\n");
        return;
    }
 
    //由于数量是一个数值,因此不必作相对偏移
    pNewSSDT->NumberOfServices = KeServiceDescriptorTable->NumberOfServices;
 
    //计算相对函数地址
    ULONG uOffset = (ULONG)KeServiceDescriptorTable->ServiceTableBase - OrigImage;
 
    //得到新的ssdt函数表地址
    pNewSSDT->ServiceTableBase = (PULONG)((ULONG)pNewImage + uOffset);
 
    if (!MmIsAddressValid(pNewSSDT->ServiceTableBase))
    {
        DbgPrint("pNewSSDT->ServiceTableBase: %X\r\n", pNewSSDT->ServiceTableBase);
        return;
    }
 
    //依次遍历
    for (ULONG uIndex = 0; uIndex<pNewSSDT->NumberOfServices; uIndex++)
    {//新的函数地址再加上相对加载地址,得到现在的ssdt函数地址
        pNewSSDT->ServiceTableBase[uIndex] += uNewKernelInc;
    }
}
VOID SetNewSSDT(PVOID pNewImage)
{
    //新内核地址-老内核地址,得到相对偏移
    ULONG uNewKernelInc = (ULONG)pNewImage - OrigImage;
 
    //老内核的ssdt指针加上相对偏移,得到新内核的ssdt指针
    pNewSSDT = (PKSYSTEM_SERVICE_TABLE)((ULONG)KeServiceDescriptorTable + uNewKernelInc);
 
    if (!MmIsAddressValid(pNewSSDT))
    {
        DbgPrint("pNewSSDT is unaviable!\r\n");
        return;
    }
 
    //由于数量是一个数值,因此不必作相对偏移
    pNewSSDT->NumberOfServices = KeServiceDescriptorTable->NumberOfServices;
 
    //计算相对函数地址
    ULONG uOffset = (ULONG)KeServiceDescriptorTable->ServiceTableBase - OrigImage;
 
    //得到新的ssdt函数表地址
    pNewSSDT->ServiceTableBase = (PULONG)((ULONG)pNewImage + uOffset);
 
    if (!MmIsAddressValid(pNewSSDT->ServiceTableBase))
    {
        DbgPrint("pNewSSDT->ServiceTableBase: %X\r\n", pNewSSDT->ServiceTableBase);
        return;
    }
 
    //依次遍历
    for (ULONG uIndex = 0; uIndex<pNewSSDT->NumberOfServices; uIndex++)
    {//新的函数地址再加上相对加载地址,得到现在的ssdt函数地址
        pNewSSDT->ServiceTableBase[uIndex] += uNewKernelInc;
    }
}
.text:00466621 2B E1                                         sub     esp, ecx
.text:00466623 C1 E9 02                                      shr     ecx, 2
.text:00466626 8B FC                                         mov     edi, esp
.text:00466628 3B 35 D4 19 48 00                             cmp     esi, ds:_MmUserProbeAddress
.text:0046662E 0F 83 A8 01 00 00                             jnb     loc_4667DC
.text:00466634
.text:00466634                               loc_466634:                             ; CODE XREF: _KiSystemService+35Fj
.text:00466634 F3 A5                                         rep movsd
.text:00466636 FF D3                                         call    ebx
.text:00466621 2B E1                                         sub     esp, ecx
.text:00466623 C1 E9 02                                      shr     ecx, 2
.text:00466626 8B FC                                         mov     edi, esp
.text:00466628 3B 35 D4 19 48 00                             cmp     esi, ds:_MmUserProbeAddress
.text:0046662E 0F 83 A8 01 00 00                             jnb     loc_4667DC
.text:00466634
.text:00466634                               loc_466634:                             ; CODE XREF: _KiSystemService+35Fj
.text:00466634 F3 A5                                         rep movsd
.text:00466636 FF D3                                         call    ebx
DWORD32 GetKiFastCallEntry()
{
    DWORD32 dwAddr = 0;
    _asm
    {
        pushad
            mov ecx, 0x176;
        rdmsr
            mov dwAddr, eax
            popad
    }
 
    return dwAddr;
}
 
DWORD32 GetHookAddr()
{
    //获取快速调用地址
    DWORD32 dwFastCallAddr = GetKiFastCallEntry();
 
    //获取快速调用获取地址
    DWORD32 dwHookAddr = 0;
    //遍历
    for (int i = 0; i < 1000; i++)
    {
        if (*(UCHAR*)(dwFastCallAddr + i + 0) == 0x2B &&
            *(UCHAR*)(dwFastCallAddr + i + 1) == 0xE1 &&
            *(UCHAR*)(dwFastCallAddr + i + 2) == 0xC1 &&
            *(UCHAR*)(dwFastCallAddr + i + 3) == 0xE9 &&
            *(UCHAR*)(dwFastCallAddr + i + 4) == 0x02)
        {
            dwHookAddr = dwFastCallAddr + i;
            break;
        }
    }
 
    //判断是否找到
    if (dwHookAddr == 0)
    {
        //没找到
        return 0;
    }
 
    return dwHookAddr;
}
 
void HookKiFastCallEntry()
{
    UCHAR buf[5] = { 0 };
    buf[0] = 0xE8;
 
 
    g_dwHookAddr = GetHookAddr();
 
    *(DWORD32*)&buf[1] = (DWORD32)((DWORD32)MyKiFastCallEntry - g_dwHookAddr - 5);
 
    //写入
    for (int i = 0; i < 5; i++)
    {
        *(UCHAR*)(g_dwHookAddr + i) = buf[i];
    }
 
}
DWORD32 GetKiFastCallEntry()
{
    DWORD32 dwAddr = 0;
    _asm
    {
        pushad
            mov ecx, 0x176;
        rdmsr
            mov dwAddr, eax
            popad
    }
 
    return dwAddr;
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 3
支持
分享
最新回复 (5)
雪    币: 12356
活跃值: (5879)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
2
都0202年了,还有人玩x86吗
2020-10-14 17:52
0
雪    币: 8764
活跃值: (5240)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
hhkqqs 都0202年了,还有人玩x86吗[em_13]
值得借鉴学习。
2020-10-14 21:47
0
雪    币: 2055
活跃值: (486)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
hhkqqs 都0202年了,还有人玩x86吗[em_13]
值得借鉴学习。
2020-10-14 22:41
0
雪    币: 6
活跃值: (1146)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
xp都可以源码编译了还玩这个
2020-10-14 23:41
0
雪    币: 3836
活跃值: (4142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
xp都可以源码编译了还玩这个
2020-10-28 10:59
0
游客
登录 | 注册 方可回帖
返回
//