x86架构32位模式切换64位模式不能正常切换. 这是多款调试器都有的BUG.
od1.x本身就不支持64位就不用测了, x64dbg虽然支持32位和64位, 但都是独立分析的, 即64位调试器只能分析64位,32位也只能分析32位.
测试了yzdbg 是没有办法切换的. 如果给yzdbg设置了 加载DLL中断事件,在64位系统上加载32位进程, 第一个会暂停在 wow64.dll,
这个时候 yzdbg 能识别出64位模式, 我猜应该是和我写的ollydbg x64上个版本一样, 是中断后判断当前IP,所处的模块是32位还是64位.
通过读取IP命中模块PE结构的 Machine位来设置当前是32还是64位无疑是可行的. 但是有一种情况会失败.
那就是在当前段,直接使用段间跳,如下代码:
[Asm] 纯文本查看 复制代码 0019526C > 51 PUSH ECX ; 32位切换.<ModuleEntryPoint>
0019526D 68 00701900 PUSH 32位切换.00197000 ; ASCII "Input your flag here:"
00195272 FF15 0C601900 CALL DWORD PTR [<&msvcrt.printf>] ; msvcrt.printf
00195278 83C4 04 ADD ESP,4
0019527B 68 1D701900 PUSH 32位切换.0019701D
00195280 68 18701900 PUSH 32位切换.00197018 ; ASCII "%46s"
00195285 FF15 08601900 CALL DWORD PTR [<&msvcrt.scanf>] ; msvcrt.scanf
0019528B 83C4 08 ADD ESP,8
0019528E 33C0 XOR EAX,EAX
00195290 B3 2D MOV BL,2D
00195292 803D 1D701900 5>CMP BYTE PTR [19701D],53
00195299 75 49 JNZ SHORT 32位切换.001952E4
0019529B 803D 1E701900 6>CMP BYTE PTR [19701E],61
001952A2 75 40 JNZ SHORT 32位切换.001952E4
001952A4 803D 1F701900 6>CMP BYTE PTR [19701F],6E
001952AB 75 37 JNZ SHORT 32位切换.001952E4
001952AD 803D 20701900 6>CMP BYTE PTR [197020],67
001952B4 75 2E JNZ SHORT 32位切换.001952E4
001952B6 803D 21701900 4>CMP BYTE PTR [197021],46
001952BD 75 25 JNZ SHORT 32位切换.001952E4
001952BF 803D 22701900 6>CMP BYTE PTR [197022],6F
001952C6 75 1C JNZ SHORT 32位切换.001952E4
001952C8 803D 23701900 7>CMP BYTE PTR [197023],72
001952CF 75 13 JNZ SHORT 32位切换.001952E4
001952D1 803D 24701900 7>CMP BYTE PTR [197024],7B
001952D8 75 0A JNZ SHORT 32位切换.001952E4
001952DA 803D 45701900 7>CMP BYTE PTR [197045],7D
001952E1 75 01 JNZ SHORT 32位切换.001952E4
001952E3 40 INC EAX
001952E4 0BC0 OR EAX,EAX
001952E6 75 15 JNZ SHORT 32位切换.001952FD
001952E8 68 56701900 PUSH 32位切换.00197056 ; ASCII "Fail."
001952ED FF15 0C601900 CALL DWORD PTR [<&msvcrt.printf>] ; msvcrt.printf
001952F3 83C4 04 ADD ESP,4
001952F6 6A 00 PUSH 0
001952F8 E8 03BDFFFF CALL <JMP.&kernel32.ExitProcess>
001952FD 8D3D 5C701900 LEA EDI,DWORD PTR [19705C]
00195303 8D35 1D701900 LEA ESI,DWORD PTR [19701D]
00195309 EA 10531900 330>JMP FAR 0033:00195310 ; Far jump
00195310 E8 FBBCFFFF CALL 32位切换.00191010
00195315 E8 00000000 CALL 32位切换.0019531A
0019531A C74424 04 23000>MOV DWORD PTR [ESP+4],23
00195322 812C24 1A43D9FF SUB DWORD PTR [ESP],FFD9431A
00195329 810424 3143D9FF ADD DWORD PTR [ESP],FFD94331
00195330 CB RETF ; Far return
其中地址 00195309 使用的就是段间跳, 而跳向的正是下一行地址 00195310.
可以看到跳转CS填写的是33表示已经进入64位模式了. 就是这一跳, yzdbg 没有识别出来.
而windbg测试了能识别出来,模式也能自动切换自如.
还不清楚windbg是如何识别的, 回头空了分析一下, 并将自动切换的方法加入我们调试器中.
(盲猜 windbg 应该不是单纯的判断 context.cs 来实现模式切换的, 因为本人之前好像测试过64位调试器中调用 GetThreadContext 和 Wow64GetThreadContext 获取的cs结果是不一样的.
比如当前cs是33 通过 GetThreadContext 获取的是33 通过 Wow64GetThreadContext 获取的就是23. 你说, 尴尬不? -_-#
回头再进一步确认一下.)
至于ida我没测, 我感觉ida动态调试方面本身就有点鸡肋,支持自适应切换模式,应该够呛~
--------------------------------------------------------------------
2022.12.06
前面猜测应该都错了, 并不是通过cs来判断当前是32还是64模式.
而是 debug event 中, 自己就能区分当前是什么模式了.
比如 int 3 事件, 32位模式 是 STATUS_WX86_BREAKPOINT 64位模式是 EXCEPTION_BREAKPOINT.
但要注意, 仅限64位调试器, 如果是32位调试器, 那就都是 走 EXCEPTION_BREAKPOINT 事件.
其它 single step 等事件也是同理. yzdbg 也不晓得是怎样实现的, 因为我实际测试中发现, yzdbg 遇到这种自己程序代码切换架构模式的, yzdbg并不能自动切换自如.
而我写的调用用了这种方法之后, 遇到这种自身代码切换模式的,调试器也是能识别出来, 并自动切换模式的.只要自己的能实现自动切换就行了,至于yzdbg是怎样实现的,也不用关心了.
--------------------------------------------------------------------
to be continued...
|