新浪博客

JMP后面的值也就是E9XXXX怎样计算的

2018-06-08 12:41阅读:
1.32位汇编,000000x的值转换成汇编编码的规律:
jmp 0002H
IP1=004ED879H
IP2=00000002H
IP2-(IP1+本句指令字节数)=2-(4ED879H+5)=0FFB12784H
Jmp 0040H
IP1=004ED879H
IP2=40H
IP2-(IP1+本句指令)=40-(4ED879H+5)=FFB127C2H
汇编里的数次序要反过来:
E9 C227B1FF
以上只是远跳转,近跳转'本句指令字节数'会缩短。
2.几种跳转指令和对应的机器码

0xE8 CALL 后面的四个字节是地址
0xE9 JMP 后面的四个字节是偏移
0xEB JMP
后面的二个字节是偏移
0xFF15 CALL 后面的四个字节是存放地址的地址
0xFF25 JMP 后面的四个字节是存放地址的地址
0x68 PUSH 后面的四个字节入栈
0x6A PUSH 后面的一个字节入栈
shellcode跳转回原始OEP方法一
大部分人比较喜欢直接jmp跳转到原始oep,这时候一般都用e9跳转,e9后面的四个字节是一个偏移地址。
计算公式: 偏移地址 = 目的地址 - 跳转基地址(jmp的下一条指令的地址)
也就是 原始OEP - jmp的下一条指令的地址
db 0e9h ;这是jmp
OEPOffs:
dd ? ;这里是4个字节 未初始化
偏移地址 = 原始OEP - (offset OEPOffs + 4) 为什么+4 因为OEPOffs标号向后偏移4个字节 才是jmp的下一条指令地址 也就是跳转基地址
shellcode跳转回原始OEP方法二
有些人用 push oep然后jmp dword ptr [esp]的方法跳回原始oep,这时候shellcode要这样写:
db 68h
OEP:
dd ?
jmp dword ptr [esp]
68h是 push后面四个字节的意思 dd ? 声明了四个字节,然后通过OEP标号,定位到这个位置,然后把原始OEP写进去就可以了

64位 jmp:
方法一:
48 B8 0000EA4B50000000 - mov rax,000000504BEA0000
FF E0 - jmp rax
指令和机器码:
mov rax, 64位地址 的机器码就是 “48 B8 64位地址的little-endian(需要64位即8个字节)”
jmp rax 的机器码 FF E0
这个方法会占用12个字节。如果你还要保存rax寄存器内容和还原寄存器,你还需要额外的2两个字节,即14个字节。
方法二:
如果跳转前后的地址都是32位的,就如我前面截图上的那个,那么地址的换算和32位没有什么区别,都是用的相对偏移。
方法三:
如果你用我前面提到的另外一种64位跳转方法,如
504BEA0006 - FF 25 00000000 - jmp qword ptr [504BEA000C]
504BEA000C - 00 00 - add [rax],al
504BEA000E - EA 4B500000 0000 - jmp 0000:0000504B
我是把64位的跳转地址000000504BEA0000作为数据直接写到跳转语句504BEA0006的下面504BEA000C处。那么跳转语句永远都是FF 25 00000000, 它会读取接下来的8个字节作为跳转地址来使用的。而这个地址就是你申请到的内存地址。可以看到这种方法需要14个连续字节,且不改变寄存器的内容。
当然你也可以把跳转地址的数据写到其他的地方如: 04BEA000D处。 那么跳转语句的FF 25 00000000就变成FF 25 01000000, 其中01000000 little-endian读下来就是00000001=1 即关于504BEA000C的相对地址是1。这后面4个字节其实就是数据地址关于504BEA000C的偏移量。和32位的原理是相同的。
总之,以上三种方法各有特色也各有利弊。方法一和三对于32和64位地址是通用的。方法二适用当地址是32位的情况下。而对于第一种方法需要修改寄存器,但是不需要计算跳转地址,而且寻址范围包括整个64位可用地址空间。第三种方法不修改寄存器,但需要计算偏移地址,而且和32位一样寻址空间限制在32位即前后2GB的范围内。

我的更多文章

下载客户端阅读体验更佳

APP专享