Haw*_*wke 3 x86 assembly exploit shellcode
我有一些来自shell代码有效负载的示例代码,显示了for循环并使用push / pop设置计数器:
push 9
pop ecx
Run Code Online (Sandbox Code Playgroud)
为什么不能只使用mov?
mov ecx, 9
Run Code Online (Sandbox Code Playgroud)
是的,mov ecx, 9出于性能原因,通常应始终使用。 它比push/ pop 更有效,因为它可以在任何端口上运行。(对于Agner Fog测试过的所有现有CPU都是这样:https://agner.org/optimize/ )
push imm8/ 的正常原因pop r32是机器代码没有零字节。这对于必须通过或其他任何方法将缓冲区溢出的shellcodestrcpy视为将其视为由0字节终止的隐式长度C字符串的一部分。
mov ecx, immediate仅可用于32位立即数,因此机器代码将如下所示B9 09 00 00 00。与6a 09推9; 59流行ecx。
(ECX寄存器是数1,这是在B9与59来自:低的指令的3位= 001)
另一个用例是纯粹的代码大小:mov r32, imm325个字节(使用无ModRM编码,将寄存器号放在操作码的低3位中),因为不幸的是x86缺少用于符号扩展的imm8操作码mov(没有mov r/m32, imm8) 。几乎所有可追溯到8086的ALU指令都存在这种情况。
在16位8086中,该编码将不会节省任何空间:对于几乎所有内容,3字节的简短格式mov r16, imm16都将与假设的一样好mov r/m16, imm8,除了将立即数移动到该mov r/m16, imm16格式(带有ModRM字节)的内存中是必需的。
由于386的32位模式没有添加新的操作码,只是更改了默认的操作数大小和立即宽度,因此ISA在32位模式下的这种“遗漏的优化”从386开始。全角立即数长了2个字节,add r32,imm32现在比更长add r/m32, imm8。请参阅x86汇编16位vs 8位立即操作数编码。但是我们没有这种选择,mov因为没有MOV操作码对其立即数进行符号扩展(或零扩展)。
有趣的事实:(clang -Oz即使以速度为代价进行大小优化)也可以编译 int foo(){return 9;}为push 9;pop rax。
另请参阅Codegolf.SE上有关在x86 / x64机器代码中打高尔夫球的技巧(该网站通常是出于娱乐目的而优化大小,而不是将代码放入小型ROM或引导扇区中。但是对于机器代码,进行大小优化确实具有实用性。有时甚至会牺牲性能。)
如果您已有另一个具有已知内容的寄存器,则可以使用3字节在另一个寄存器中创建9 lea ecx, [eax-0 + 9](如果EAX成立0)。只需操作码+ ModRM + disp8。因此,如果您已经将其他任何寄存器的异或为零,则可以避免push / pop hack。 lea的效率几乎不及mov,并且在优化速度时可以考虑使用它,因为较小的代码大小在大规模上具有较小的速度优势:L1i缓存命中,有时在uop缓存尚未很热时进行解码。
| 归档时间: |
|
| 查看次数: |
174 次 |
| 最近记录: |