让我们把它分开一点。我会跳过一些你可能已经理解的东西,但如果有些东西不清楚,我们可能需要扩展它。
MOV DWORD PTR SS:[EBP-30],400400
MOV DWORD PTR SS:[EBP-30],DWORD PTR DS:[400400]
语法有点奇怪,但我们可以理解您想MOV
用两个内存操作数对 a 进行编码。我们来看看一些文档
参考:https : //www.felixcloutier.com/x86/MOV.html
没有可能的编码来MOV
接受m32,m32
。随着m32
理解为是一个32位的指针。
这种情况并不明显,但不幸的是。
参考:https : //stackoverflow.com/a/33799523/10279341
如果您关心为什么,这是一个很好的答案,但它只是补充阅读,对这种情况并不重要。
因此,如果我们想使用 x86 将内存复制到内存中:
参考:https : //stackoverflow.com/a/1299094/10279341
普遍接受的解决方案是使用寄存器作为临时值存储。
请注意,我们需要保存正在使用的寄存器的状态,否则我们可能会意外更改程序状态。
MOV ECX,DWORD PTR DS:[400400]
MOV DWORD PTR SS:[EBP-30],ECX
所以这是在正确的轨道上。但是我们需要ECX
事先保存以防其他人正在使用它。
0x00000000: 51 push ecx
0x00000001: 8b 0d 00 04 40 00 mov ecx, dword ptr [0x400400]
0x00000007: 89 4d e2 mov dword ptr [ebp - 0x1e], ecx
0x0000000a: 59 pop ecx
这应该做你想要的。我们ECX
通过将其压入堆栈来保存。将地址处的值加载0x400400
到ECX
. 然后将 的值写入ECX
内存中[EBP-0x1E]
,然后恢复ECX
到之前的值。
那么我们如何将其修补到二进制图像中呢?
上面的程序集长度为 11 个字节,我们的目标是更改指令
0: c7 45 e2 4c 00 00 00 mov DWORD PTR [ebp-0x1e],0x4c
我们可以看到有 7 个字节长。
我们可以通过使用“代码洞穴”来获得这些额外的 4 个字节。我们将执行重定向到未使用的内存位,执行我们的代码,然后跳回。
参考:https : //www.codeproject.com/Articles/20240/The-Beginners-Guide-to-Codecaves
简而言之,我们正在寻找在 exe 映像中分配/映射的“空白空间”,最好在 .text 部分,但在任何情况下都不会被程序使用。由于默认情况下 Windows PE 中的 SectionAlignment 为 4096,这几乎会出现在每个可执行映像中。
实现这一点的最简单方法是在我们试图修改的同一内存区域中找到未使用的字节。
使用 ollydbg 查找/应用代码洞的基本方法如下所示:
https://medium.com/@vysec.private/backdoor-101-f318110e1fcb
在为我们的洞穴找到合适的内存后,在 shellcode 中打补丁:
0x00000000: 51 push ecx
0x00000001: 8b 0d 00 04 40 00 mov ecx, dword ptr [0x400400]
0x00000007: 89 4d e2 mov dword ptr [ebp - 0x1e], ecx
0x0000000a: 59 pop ecx
使用 ollydbg 的汇编程序。
然后改变的原始指令mov DWORD PTR [ebp-0x1e],0x4c
到JMP x
哪里x
是你的shellcode地址,同一模块/形象。
如果需要,用 0x90 (NOP) 覆盖其余的指令字节。所以我们最终得到:
c7 45 e2 4c 00 00 00
- 原始说明
e9 xx xx xx xx 90 90
- JMP rel32 加 2 个 NOP
x86 JMP 参考:https : //c9x.me/x86/html/file_module_x86_id_147.html
之后,pop ecx
在我们的代码洞穴回来组装:JMP y
其中y
是紧跟在 之后的指令地址mov DWORD PTR [ebp-0x1e],0x4c
。当你跳出代码洞时,你最终应该跳过 NOP 指令,这就是为什么我说它们是可选的。
概括,
组装我们的 shellcode,记录正确的 x86 ASM 并保留程序状态。
如果没有足够的空间来修补内嵌指令,请识别代码洞穴。
应用代码洞并组装两条JMP
指令以将执行 (1) 重定向到代码洞,(2) 返回到原始代码的下一条指令。