原理:在 EXE 文件中寻找未使用的空白区域(或者新增一个节 Section),将你的机器码写入其中(这就是“Code Cave”)。
插入节区
寻找OEP(获取原程序入口点)
用 CFF Explorer 打开目标 .exe:
查看 NT Headers → Optional Header → AddressOfEntryPoint
记下该 RVA(例如 0x1500)

在节区界面右键添加空节,不要选择只有头部那个,因为我们需要将自己的代码放入。

输入虚拟内存大小,建议1000h

其他参数CFF会自动处理如下,可添加名称如.mine

选中自添加的节区选中修改节区标志

选择可读可写可执行,写一般没必要,最好加上,不要选择第一个可共享除非必要

导入表分析
查看导入表,发现导入了两个dll,没有导入 USER32.dll,所以无法直接调用 MessageBoxA,
实际上我的这个程序仅为输出字符串(纯控制台程序或无 GUI 程序)

Msvcrt.dll中的FTs(IAT)为0x82AC
获取printf函数入口地址的方法如下图

在下图中数得printf排在24索引处,从0开始,即第25行

计算偏移即msvcrt.dll的FTs(IAT)地址加上24*8

VA = ImageBase(加载到内存中的基址) + IAT RVA(导入表项的相对虚拟地址)
故printf的位置为0x400000 + 0x836c = 0x40836c
写入shellcode
为此在.mine区中写入自己的shellcode如下,有代码也有数据,通过偏移获取数据,调用printf函数输出后跳回原代码执行
完整shellcode(为获得换行效果,在数据最后添加一个\\n对应ASCII为10,对应hex为0A)

要得到机器码可用x64dbg汇编获得,如下

在64位程序中gs:[60]存放的是PEB(process environment block),其中的偏移10记录着imagebase内存基址
其中的lea指令目的是取得有效地址,其在汇编输入时使用rip+偏移指向数据处,需要注意的是当cpu执行到此lea指令时取出该指令后rip即指向下一条要指向的指令,这里如图为nop,故需要从nop的地址计算到数据的偏移。
此处的nop不重要,只是我在修改lea指令时使用剩余字节nop填充产生的

注入效果演示

通过遍历模块+dll偏移获取函数地址
shellcode如下

CFF中同步修改并保存

测试效果

需要注意的是以上代码是在win10下运行的,其printf的地址与msvcrt.dll入口的地址偏移为41440h,但是要在我自己机器上运行我的这个dll的偏移为45870h
Win11下修改偏移量同理成功

分析shellcode
其中gs:[0x60]为取得PEB地址
Rax+0x18是取得LDR地址
Rax+0x20是取得Inmemoryorderlist地址
之后4个mov rax,[rax]用于根据inmemoryorderlist链表向下找dll入口,针对我的测试程序,第一个mov rax,[rax]后是ntdll.dll,第二个是kernel32,之后是kernelbase和msvcrt,
当第四个mov rax,[rax]后其指向_LDR_DATA_TABLE_ENTRY的0x10处,即指向于Flink(forward link,指向下个LDR_DATA_TABLE_ENTRY的Flink,故减去10用于定位该结构的起始
mov rsi,[rax,+0x38]用于获得该LDR_DATA_TABLE_ENTRY对应的dll的入口地址
add rsi ,偏移到printf,该偏移可从x64dbg中的符号查看
PEB分析
为分析PEB等需要在微软商店下载windbg
Windbg中选择文件,运行程序

可用!peb查看PEB,结合调试和网上资料确定偏移,如下图可看到Ldr.Inmemoryordermodulist项
不知道能不能直接用peb偏移获取,而非用ldr间接获取

使用dt查看PEB结构,发现Ldr在0x18偏移处,貌似不能直接通过PEB获得模块地址

lm可查看导入的模块

Windbg中可用dq 地址+偏移 显示模式,查看内存值,如下命令可看到PEB在2CA000h,加上18h到Ldr结构

也可以使用$引用变量加偏移取得LDR地址7ffdd3c328e0,与peb对照相符

由LDR获取InMemoryOrderModuleList地址(此时也指向flink),由于其为双向链表
第一个756a80为Flink,第二个766cb0为Blink,使用第一个进行遍历

由于flink位于一个_LDR_DATA_TABLE_ENTRY的0x10处,
故我们可以减0x10偏移后查看特定地址的_LDR_DATA_TABLE_ENTRY的结构,
命令如下,可以看到第一个_LDR_DATA_TABLE_ENTRY是关于该运行程序exe的
按照这个flink一直向下即可定位到所要的Mscvrt.dll的入口地址




