1

这实际上是反汇编 Windows 7 D3D9.dll 的 DrawIndexedPrimitive 方法。

CPU Disasm
Address   Hex dump          Command                                  Comments
58EBB6B1   .  8BFF          MOV EDI,EDI
58EBB6B3  /.  55            PUSH EBP
58EBB6B4  |.  8BEC          MOV EBP,ESP
58EBB6B6  |.  6A FF         PUSH -1
58EBB6B8  |.  68 28BE0259   PUSH 5902BE28                            ; Entry point
58EBB6BD  |.  64:A1 0000000 MOV EAX,DWORD PTR FS:[0]
58EBB6C3  |.  50            PUSH EAX
58EBB6C4  |.  83EC 20       SUB ESP,20
58EBB6C7  |.  53            PUSH EBX
58EBB6C8  |.  56            PUSH ESI
58EBB6C9  |.  57            PUSH EDI
58EBB6CA  |.  A1 50920359   MOV EAX,DWORD PTR DS:[59039250]
58EBB6CF  |.  33C5          XOR EAX,EBP
58EBB6D1  |.  50            PUSH EAX
58EBB6D2  |.  8D45 F4       LEA EAX,[EBP-0C]
58EBB6D5  |.  64:A3 0000000 MOV DWORD PTR FS:[0],EAX
58EBB6DB  |.  8965 F0       MOV DWORD PTR SS:[EBP-10],ESP
58EBB6DE  |.  8B7D 08       MOV EDI,DWORD PTR SS:[EBP+8]
58EBB6E1  |.  33DB          XOR EBX,EBX
58EBB6E3  |.  3BFB          CMP EDI,EBX
58EBB6E5  |.- 0F84 BA030000 JE 58EBBAA5
58EBB6EB  |.  8D77 04       LEA ESI,[EDI+4]
58EBB6EE  |.  8975 EC       MOV DWORD PTR SS:[EBP-14],ESI
58EBB6F1  |>  8975 D4       MOV DWORD PTR SS:[EBP-2C],ESI
58EBB6F4  |.  895D D8       MOV DWORD PTR SS:[EBP-28],EBX
58EBB6F7  |.  395E 18       CMP DWORD PTR DS:[ESI+18],EBX
58EBB6FA  |.- 0F85 66DE0500 JNE 58F19566
58EBB700  |>  F647 2C 02    TEST BYTE PTR DS:[EDI+2C],02
58EBB704  |.  895D FC       MOV DWORD PTR SS:[EBP-4],EBX
58EBB707  |.- 0F85 65DE0500 JNE 58F19572
58EBB70D  |.  818F 0C2A0000 OR DWORD PTR DS:[EDI+2A0C],40000000
58EBB717  |.  F647 2C 08    TEST BYTE PTR DS:[EDI+2C],08
58EBB71B  |.  C645 FC 01    MOV BYTE PTR SS:[EBP-4],1
58EBB71F  |.- 0F85 54030000 JNE 58EBBA79
58EBB725  |>  8B8F F02C0000 MOV ECX,DWORD PTR DS:[EDI+2CF0]
58EBB72B  |.  8B55 10       MOV EDX,DWORD PTR SS:[EBP+10]
58EBB72E  |.  8DB7 3C2B0000 LEA ESI,[EDI+2B3C]
58EBB734  |.  8951 14       MOV DWORD PTR DS:[ECX+14],EDX
58EBB737  |.  399E 70010000 CMP DWORD PTR DS:[ESI+170],EBX
58EBB73D  |.- 0F85 54DE0500 JNE 58F19597
58EBB743  |>  F787 0C2A0000 TEST DWORD PTR DS:[EDI+2A0C],00000200
58EBB74D  |.- 0F85 AE020000 JNE 58EBBA01
58EBB753  |>  8B4D 20       MOV ECX,DWORD PTR SS:[EBP+20]
58EBB756  |.  8B55 1C       MOV EDX,DWORD PTR SS:[EBP+1C]
58EBB759  |.  8B45 18       MOV EAX,DWORD PTR SS:[EBP+18]
58EBB75C  |.  51            PUSH ECX
58EBB75D  |.  8B4D 14       MOV ECX,DWORD PTR SS:[EBP+14]
58EBB760  |.  52            PUSH EDX
58EBB761  |.  8B55 10       MOV EDX,DWORD PTR SS:[EBP+10]
58EBB764  |.  50            PUSH EAX
58EBB765  |.  8B45 0C       MOV EAX,DWORD PTR SS:[EBP+0C]
58EBB768  |.  51            PUSH ECX
58EBB769  |.  8B8F 0C2D0000 MOV ECX,DWORD PTR DS:[EDI+2D0C]
58EBB76F  |.  52            PUSH EDX
58EBB770  |.  50            PUSH EAX
58EBB771  |.  57            PUSH EDI
58EBB772  |.  FFD1          CALL ECX
58EBB774  |.  8B45 EC       MOV EAX,DWORD PTR SS:[EBP-14]
58EBB777  |.  81A7 0C2A0000 AND DWORD PTR DS:[EDI+2A0C],BFFFFFFF
58EBB781  |.  83C4 1C       ADD ESP,1C
58EBB784  |.  3958 18       CMP DWORD PTR DS:[EAX+18],EBX
58EBB787  |.- 0F85 6ADF0500 JNE 58F196F7
58EBB78D  |>  33C0          XOR EAX,EAX
58EBB78F  |.  8B4D F4       MOV ECX,DWORD PTR SS:[EBP-0C]
58EBB792  |.  64:890D 00000 MOV DWORD PTR FS:[0],ECX
58EBB799  |.  59            POP ECX
58EBB79A  |.  5F            POP EDI
58EBB79B  |.  5E            POP ESI
58EBB79C  |.  5B            POP EBX
58EBB79D  |.  8BE5          MOV ESP,EBP
58EBB79F  |.  5D            POP EBP
58EBB7A0  \.  C2 1C00       RETN 1C

比如说,我用我的跳转代码洞穴替换了 58EBB6DB(3 个字节)和 58EBB6DE(3 个字节)。这将替换 6 个字节的代码(跳转到我的代码洞穴函数地址 5 个字节,并跳过第 6 个字节)。

然后,我将替换后的原始 6 字节代码放回我的代码洞穴函数中。“MOV DWORD PTR SS:[EBP-10],ESP”和“MOV EDI,DWORD PTR SS:[EBP+8]”。然后我的代码洞穴开始做我的工作......

我的代码洞穴中有一个 If-Then-Else。

假设
1) 当结果为真时,我的代码洞穴返回 58EBB6E1 地址。
2)当结果为假时,这个DrawIndexedPrimitive方法将在我的代码洞穴编码处终止。

当我的代码洞穴返回到 58EBB6E1 地址的下一条指令行时,我对第一个没有问题。但是当我终止它时,游戏崩溃了。

这就是我终止该方法的方式。

TERMINATE:
        POPAD     // clear the previous PUSHAD
        POPFD     // clear the previous PUSHFD

            // restore what DrawIndexedPrimitive method called...
        POP EDI
        POP ESI
        POP EBX
        MOV ESP,EBP
        POP EBP
        RETN 1C    //CD3DBase::DrawIndexedPrimitive(enum  _D3DPRIMITIVETYPE, int, unsigned int, unsigned int, unsigned int, unsigned int)
4

1 回答 1

1

我不太确定你为什么要把你的跳转放到方法中,然后不得不担心将原始方法代码复制到目标代码中,并恢复原始方法已经进行的堆栈更改。也许你能启发我们?

轻松拦截方法调用的方法已经以以下形式存在mov edi, edi- 用于热补丁的 2 字节 NOP,允许您用短跳转到长跳转原子地替换它,然后将其放在 5 个空字节中到方法。参见:热补丁

明确地 - 如果您查看方法之前的字节,应该(至少)有 5nop条指令。应按如下方式执行补丁:

  1. 在要修补的方法之前的 5 个字节中,将 5 个字节的长跳转写入补丁代码。
  2. 将 2 字节的短跳转写入方法开始时在步骤 1 中写入的跳转(替换mov edi, edi)。这将只是0xEB 0xF9.
  3. 根据补丁中的处理,您可以:
    • 58EBB6B3通过跳转到(即跳过补丁的短跳转)继续该方法。
    • 通过执行一个跳过该方法ret 0x1c
于 2012-07-30T09:58:15.140 回答