目标
我正在学习漏洞开发,其中一个主题是编写shellcode。
通常情况下,msfvenom可以很好地完成shikata ga nai编码。生成的shellcode通常也包含FPU指令来获取EIP,使其成为PIC。
我提到的FPU指令是:
dadc fcmovu st, st(4)
d97424f4 fnstenv [esp-0Ch]
5d pop ebp
字符串
环境
Microsoft Windows Version 1709(Build 16299.2166)x86
使用WinDbg:10.0.22621.755 X86进行调试
预期结果
当我使用实验室的VM时,我能够获得FPULastInstructionOpcode,其中esp
将指向包含执行fcmovu
指令的EIP值的堆栈地址,因此pop ebp
将eip
值放置到ebp
。
接收问题
在执行fcmovu
指令之前,我的堆栈看起来是这样的:
01e0744c 41 41 41 41 41 41 41 41 83 0c 09 10 43 43 43 43 AAAAAAAA....CCCC
01e0745c 90 90 90 90 90 90 90 90 90 90 be 02 61 13 10 da ............a...
01e0746c dc d9 74 24 f4 5d 29 c9 b1 52 83 c5 04 31 75 0e ..t$.])..R...1u.
01e0747c 03 77 6f f1 e5 8b 87 77 05 73 58 18 8f 96 69 18 .wo....w.sX...i.
型
执行fnstenv
指令后:
01e0744c 41 41 41 41 7f 02 ff ff 41 00 ff ff fe ff ff ff AAAA....A.......
01e0745c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ................
01e0746c dc d9 74 24 f4 5d 29 c9 b1 52 83 c5 04 31 75 0e ..t$.])..R...1u.
01e0747c 03 77 6f f1 e5 8b 87 77 05 73 58 18 8f 96 69 18 .wo....w.sX...i.
型
我的ESP指向0x1e0745c
,EIP值应该在这里。但是,我收到的是NULL值而不是EIP值。
帮助
所以我想问社区的是,为什么我得到的是NULL值?我做错了什么?
我已经阅读了x86文档,知道fcmovu
不是这里的问题。
这与我在实验室中使用的shellcode完全相同,并且我能够按预期接收EIP值。
我也读过StackExchange here的另一篇文章,但回复并没有回答OP的问题。
缓解方案
在Peter Cordes的帮助下,我发现VMWare Guest OS下的WinDbg在单步执行x87 FPU指令时从FPULastInstructionOpcode
返回空值。这是一个意外的结果,通过在FPU指令后设置断点并运行shellcode来缓解。不知道为什么VMWare中的调试器会这样破坏结果,但有些事情真的不需要答案(或者更确切地说,可能是太多的工作,以调查的东西,可以微不足道地减轻)。
1条答案
按热度按时间0qx6xfy61#
**这是您的VM或调试器中的一个bug。**如果您能找出是哪个bug,请向他们报告。单步执行的结果应该与让指令运行直到您遇到断点(您确认它正在工作;感谢测试)的结果相同。
这在Linux上的GDB中工作正常(直接在我的i7- 6700 k CPU上,没有VM)。即使单步执行
fcmov
然后fnstenv
,它也会将fcmov
的地址存储为FP环境中的FPUInstructionPointer
,而不是0x00000000
。(这是pop ebp
加载的。)在我的系统上,写入堆栈的字节与你的FPU控制字1、状态字和标记字相匹配,所以你的FPU处于相同的状态。将
FPUInstructionPointer
设置为指向执行的最后一条非控制FP指令总是会发生,而不仅仅是在FPU异常时,根据Intel的x86手册第1卷(第8.1.8节x87 FPU指令和数据(操作数)指针)。我不认为有任何理由你的AMD CPU会清除x87
FPUInstructionPointer
字段,而采取单步调试异常,所以它很可能是一个软件错误,不是你的AMD和我的英特尔之间的硬件差异。它在fcmov
和fnstenv
之间不停止时工作的事实证实了AMD硬件确实按照英特尔文档的方式设置了这个字段。我猜这是 * 可能 *(但不太可能)AMD的frstor
或xrstor
无法正确恢复该字段,因此请确保在向VM或调试器开发人员报告此问题时包含硬件详细信息。脚注1:实际上有一个区别:你的控制字=
0x027f
(精度控制= 0 b10 = 53位尾数like 32-bit MSVC sets),而我的有0x037f
(精度控制= 0 b11 = 64位尾数,就像finit
状态。但这并不影响当所有x87寄存器都处于“未写”状态时,由
fcmov
引起的掩码x87堆栈下溢异常所发生的情况。http://www.ray.masmcode.com/tutorial/fpuchap1.htm标记字确认了这种情况,因此fcmov
确实出错并将NaN写入st0
,留下FP寄存器#0的标记字段= 0 b10,其余为空(标记= 0 b11)。状态字确认堆栈下溢时C1 = 0 asfcmov
sets。不过这并不重要
FPUInstructionPointer
被设置为最后一条非控制FPU指令,无论它是否发生故障;我在评论这个问题并建议非故障fcmov
可能解释空指针时犯了这个错误。