自定义跳转函数的通用unhook方法

0x00 前言

本文介绍一种比较有意思的unhook手法,来源于小伙伴发的一个GitHub的POC:<https://github.com/trickster0/LdrLoadDll-
Unhooking>,本文讲参照此POC来一步步解读这个方法。

目前大家常用的经典手法大都是直接系统调用(Syscall)或是找到ntdll的地址并重新映射磁盘中的.text段,去获得一个干净的dll去寻找函数地址的方式。

下面介绍这种方式相当于我们自己去组装一个“跳转函数”,巧妙地规避了一些Hook,具有一定的参考以及学习价值。

0x01 流程分析

  1. 首先,构造Nt函数参数的结构体
UNICODE_STRING ldrldll;
    OBJECT_ATTRIBUTES objectAttributes = { 0 };
    wchar_t ldrstring[] = L"Wininet.dll";
    RtlInitUnicodeString(&ldrldll, ldrstring);
    InitializeObjectAttributes(&objectAttributes, &ldrldll, OBJ_CASE_INSENSITIVE, NULL, NULL);
  1. 接着定义和初始化要修补的指令的头部、地址、尾部
unsigned char jumpPrelude[] = { 0x49, 0xBB }; 
    unsigned char jumpAddress[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF };
    unsigned char jumpEpilogue[] = { 0x41, 0xFF, 0xE3, 0xC3 }; 
  1. 新建一块内存页,属性为可读可写(opsec),这块内存页是为了保存最终要使用的LdrLoadDll的地址。
LPVOID trampoline = VirtualAlloc(NULL,19, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  1. 获取ntdll内导出函数LdrLoadDll,原始的地址
LPVOID origLdrLoadDll = GetProcAddress(GetModuleHandleA("ntdll.dll"),"LdrLoadDll");

许多EDR去Hook API的方式就是去修改Windows
DLL中的函数,通过在函数开头插入JMP指令来跳转到自己的检测函数;如果API被Hook了的话,一般前5个字节会变为JMP xxxxh,跳转到检测函数的地址,下方图片说明了这个流程。

image-20220117134946650

上述获取到的原始函数地址,放在内存窗口查看。

image-20220117132815195

为了更方便查看,使用Windbg反汇编LdrLoadDll查看其结构,记录前五个字节,也就是\x48\x89\x5c\x24\x10

image-20220117005918587

5.将原始的前5个字节,放入我们开始申请的地址中。

CCopyMemory(trampoline,(PVOID)"\x48\x89\x5c\x24\x10", 5);

这一步比较巧妙,即使是EDR修改了前5个字节为跳转指令,我们也不用在意,因为我们不会去使用原始的前5个字节,而是自己放进去。

  1. 获取原始地址前5个字节后的地址,放入第2步申请的jumpAddress
LPVOID jmpAddr = (void*)((char*)origLdrLoadDll + 0x5);
    *(void**)(jumpAddress) = jmpAddr; //jmpaddr的地址

image-20220117133552397

查看jumpAddress的内存,发现也就是地址7ff8d8ae6a15

image-20220117133636639

  1. 接着是3个拷贝操作
CCopyMemory((PBYTE)trampoline+5, jumpPrelude, 2);
    CCopyMemory((PBYTE)trampoline + 5 + 2, jumpAddress, sizeof(jumpAddress)); 
    CCopyMemory((PBYTE)trampoline + 5 + 2 + 8, jumpEpilogue, 4);

首先将jumpPrelude拷贝到前5个字节后,然后拷贝原始函数5个字节后的地址,最后拷贝jumpEpilogue指令尾部

在第5步的时候trampoline事先写入了前5个字节,内存看起来是这样的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PP0igkG3-1691746017571)(https://image.3001.net/images/20220506/1651830645_6274ef75e58f980f1909b.png!small)]

经过3次内容的拷贝,最终指令为:

image-20220117134431236

  1. 修改这个最终要使用的“自定义跳转函数”的内存空间为可执行
VirtualProtect(trampoline,30,PAGE_EXECUTE_READ,&oldProtect);
  1. 最后,将地址赋给事先定义的函数结构,并且调用
LdrLoadrDll = (pNewLdrLoadDll)trampoline;
    HANDLE wininetmodule = NULL;
    LdrLoadrDll(NULL, 0 , &ldrldll, &wininetmodule);

开启VS的汇编窗口,到了函数调用时,步入进去即可更清晰的看到最终trampoline中所做的操作,右边蓝框。image-20220117005309923

0x02 总结

这样就构建了一个完整的自定义的跳转函数,这个函数实际上的功能还是跳转回原始的LdrLoadDll的前5个字节后的地址去执行,相当于避免了修改前5个字节JMP到检测函数的这种Hook方法。

我们自定义的跳转函数不受其影响,并且调用也是从NTDLL发出的,以一张图来说明流程:

image-20220117143938358

于避免了修改前5个字节JMP到检测函数的这种Hook方法。

我们自定义的跳转函数不受其影响,并且调用也是从NTDLL发出的,以一张图来说明流程:

[外链图片转存中…(img-5wzi1KrA-1691746017573)]

学习计划安排


我一共划分了六个阶段,但并不是说你得学完全部才能上手工作,对于一些初级岗位,学到第三四个阶段就足矣~

这里我整合并且整理成了一份【282G】的网络安全从零基础入门到进阶资料包,需要的小伙伴可以扫描下方优快云官方合作二维码免费领取哦,无偿分享!!!

如果你对网络安全入门感兴趣,那么你需要的话可以

点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

①网络安全学习路线
②上百份渗透测试电子书
③安全攻防357页笔记
④50份安全攻防面试指南
⑤安全红队渗透工具包
⑥HW护网行动经验总结
⑦100个漏洞实战案例
⑧安全大厂内部视频资源
⑨历年CTF夺旗赛题解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值