0x00 前言

在shellcode开发和研究中,定位EIP是一个重要的问题。

0x01 利用x86汇编查找EIP

使用FPU指令

该方法首次利用是由Aaron Adams发表在https://seclists.org/vuln-dev/2003/Nov/44
实现原理就是利用x87浮点运算单元(FPU)来获取EIP的值

先大概介绍一下FPU:
FPU是专用于浮点运算的处理器,以前FPU是一种单独的芯片,从486开始集成在了CPU中,所以基于x86的处理器是继承了FPU处理器的。
此时可以通过如下的汇编代码来获取EIP:
section .text
BITS 32
global CMAIN
CMAIN:
fldz
fnstenv [esp-0xc]
pop eax
add al,0x09
xor eax, eax
ret
image.png

使用的编辑器是https://github.com/Dman95/SASM

上面的汇编指令中,fldz用于激活FPU寄存器,fldz功能是把+0.0 压入压入堆栈中。这里指的就是FPU寄存器.
在因特尔手册中可以找到关于FPU寄存器的结构描述:
image.png
这里调用了fldz指令之后,便会初始化FPU寄存器,并将当前EIP的内容存放到FIP中。

第二条指令fnstenv [esp - 0xc]
image.png
所以该指令的功能是将FPU保存到指定地址,esp-0xc的位置
这里为什么是0xc,我们再回过头来看FPU的定义:
image.png

可以看到FIP相对FPU的偏移刚好是12,也就是0xc
这里将FPU保存到exp-0xc,也就是将esp保存在FIP中。

接下来通过pop eax指令,将FIP(esp)的值弹出保存到eax
image.png

这个时候我们就可以通过这个esp去找到EIP,因为现在eax已经指向esp了,所以直接将eax加上已经执行过的命令的字节数,就可以得到EIP。这里本来应该是+7,但由于本身add al,7这条命令还要占2个字节,所以直接写add al,9。

将汇编代码编译生成exe
在调试器中断在fldz指令处:
image.png
目前fldz还未执行
往后执行两步,初始化FPU寄存器,并将FPU保存到esp-0xc
image.png
这里可以看到ESP(FIP)的值就是00401390

执行pop eax 将这个值弹出
image.png
现在eax指向00401390处
接下来将执行过的代码字节给加上,就可以使eax指向当前的EIP了
image.png
这里需要注意
原本的命令应该是7个字节,但是这里还要往后执行语句,所以加起来应该是9个字节所以是al+9

通过jmp

先上代码:
%include “io.inc”
section .text
BITS 32
global CMAIN
CMAIN:
jmp labe12
labe11:
jmp getEIP
labe12:
call labe11
getEIP:
pop eax

image.png

调试器中:
image.png
这里pop eax执行之后,eax直接就指向了eip的前一条指令,即成功获取到EIP了。

0x02 在x64下查找RIP

FPU

查了一下,x64处理器下FPU还是可以使用的,所以直接参照之前x86的方法尝试,直接在一个64位的进程中输入代码:
image.png

pop rax之后,RAX成功指到RSP
同样的方法add rax ,7 是的RAX指向RIP前一个位置image.png

通过跳转

同样的,构建一个同x86的跳转代码:
image.png

image.png
pop rax之后,RAX指向的RIP的前一个指令

**