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的范围内。