反汇编程序如何从内存中提取操作码?

时间:2014-03-23 19:00:33

标签: assembly pykd

我正试图弄清楚反汇编程序是如何工作的。具体来说,内存中的内容如何映射到相应的汇编语言操作码。

以下是内存中的内容,第一列地址:

773eed5c  50 ff 15 0c 17 3a 77 90-90 90 90 90 8b ff 55 8b  P....:w.......U.
773eed6c  ec 51 51 83 7d 10 00 74-38 ff 75 10 8d 45 f8 50  .QQ.}..t8.u..E.P
773eed7c  e8 14 d7 ff ff 85 c0 74-24 56 ff 75 fc ff 75 0c  .......t$V.u..u.
773eed8c  ff 75 08 e8 ab ff ff ff-83 7d 10 00 8b f0 74 0a  .u.......}....t.
773eed9c  8d 45 f8 50 ff 15 9c 15-3a 77 8b c6 5e c9 c2 0c  .E.P....:w..^...
773eedac  00 83 65 fc 00 eb d2 90-90 90 90 90 8b ff 55 8b  ..e...........U.
773eedbc  ec 57 e8 c7 d6 ff ff 8b-4d 0c 6a 34 5f 03 c7 0f  .W......M.j4_...
773eedcc  b7 00 40 40 03 c9 3b c8-0f 82 07 e5 00 00 56 e8  ..@@..;.......V.

和相应的反汇编结果,第一列内存地址,第二列操作码指令,其余列汇编指令:

0x773eed5c 50 push    eax
0x773eed63 90 nop
0x773eed65 90 nop
0x773eed67 90 nop
0x773eed6a 55 push    ebp
0x773eed6d 51 push    ecx
0x773eed6f 837d1000 cmp     dword ptr [ebp+10h],0 ss:0023:056cfa8c=778237eb
0x773eed7c e814d7ffff call    kernel32!Basep8BitStringToDynamicUnicodeString (773ec495)

现在我可以看到操作码e814d7ffff在内存上(e8 14 d7 ff ff

但是如何解释内存地址0x773eed5c中的内容? push eax和连续nop的操作码如何映射到内存内容0c15ff50 90773a17 90909090 8b55ff8b

更新:

我上面给出的反汇编结果不正确。如下所示,正确的结果非常适合内存中的内容:

0x773eed5c 50 push    eax
0x773eed5d ff150c173a77 call    dword ptr [kernel32+0x170c (773a170c)] ds:0023:773a170c={ntdll!RtlExitUserThread (777ef608)}
0x773eed63 90 nop
0x773eed64 90 nop
0x773eed65 90 nop
0x773eed66 90 nop
0x773eed67 90 nop
0x773eed68 8bff mov     edi,edi
0x773eed6a 55 push    ebp
0x773eed6b 8bec mov     ebp,esp
0x773eed6d 51 push    ecx
0x773eed6e 51 push    ecx
0x773eed6f 837d1000 cmp     dword ptr [ebp+10h],0 ss:0023:0447fc24=778237eb
0x773eed73 7438 je      kernel32!OpenFileMappingA+0x45 (773eedad) [br=1]
0x773eed75 ff7510 push    dword ptr [ebp+10h]  ss:0023:0447fc24=778237eb
0x773eed78 8d45f8 lea     eax,[ebp-8]
0x773eed7b 50 push    eax
0x773eed7c e814d7ffff call    kernel32!Basep8BitStringToDynamicUnicodeString (773ec495)

有关我的错误的详细信息:我正在使用pykd围绕WinDbg开发工具。有关其disasm模块的文档未涵盖详细信息,因此我对disasm.jumprel函数使用了错误的参数,这导致了不完整的反汇编结果。

2 个答案:

答案 0 :(得分:2)

实际上非常简单。

请注意:http://www.mathemainzel.info/files/x86asmref.html

这是一个x86指令集参考。

如果您查找“PUSH AX”,您会看到操作码为50。如果您查找“NOP”,您会看到其操作码为90

那么,您会收到每个操作码的样子(50 == PUSH AX90 == NOP等等。某些操作码需要比其他操作码更多的参数。 CALL操作码有4种模式,第一种是E8,用于“近指针”。

现在,x86具有不同的操作模式(16b,32b,64b),因此它重用相同的操作码,但调整了不同模式的参数。这是反汇编者需要事先知道的事情。因为“近指针”在16b,32b和64b模式下是不同的(它们占用更多空间,等等)。

但最后,一个简单的反汇编程序查找其当前的操作码,消耗基于操作码所需的字节数,然后为该段内存创建适当的汇编指令。

更复杂的反汇编程序可以理解更高级别的语言,可以指出代码无法访问的区域(例如,它可以跟踪跳转,调用和分支,并知道它不会反汇编的代码)。

反汇编程序可以变得非常复杂,但简单的一个很简单。

答案 1 :(得分:2)

似乎确实缺少一些东西。

50                push eax
ff 15 0c 17 3a 77 call [0x0c173a77] ; where did this thing go?
90                nop
90                nop
90                nop
90                nop
90                nop
8b ff             mov edi, edi  ; wut?
55                push ebp      ; this looks like the beginning of a function
8b ec             mov ebp, esp
51                push ecx
51                push ecx
83 7d 10 00       cmp [ebp + 10], 0

我手动拆卸了这个,我可能犯了错误。这段代码很奇怪。你拆卸它甚至更奇怪,我不知道它是如何发生的。