【问题标题】:ASM: code cave terminationASM:代码洞穴终止
【发布时间】:2012-07-27 21:47:52
【问题描述】:

这其实是反汇编的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)当结果为false时,这个DrawIndexedPrimitive方法会在我的code Cave编码处终止。

当我的代码洞穴返回到 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)

【问题讨论】:

  • 为什么会崩溃?我是否正确弹出它们?
  • 能否包含整个 DrawIndexedPrimitive 方法的转储?
  • 铱星:如上编辑。

标签: assembly x86 direct3d


【解决方案1】:

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

轻松拦截方法调用的方法已经以 mov edi, edi 的形式存在 - 一个 2 字节的 NOP 用于热补丁,允许您用短跳转原子替换它到您放置的长跳转紧接在该方法之前的 5 个空字节。见:hot patching

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

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

【讨论】:

  • 好吧,比如说,我有一个我不想渲染的对象。因此,通过 if-then-else 检查,它将确定是继续渲染还是立即停止渲染并返回给调用者。
  • @lannyboy 我的意思是 - 为什么在原始代码已经完成大量内容之后将您的跳转代码部分放在方法中,您的补丁必须正确清理这些内容才能跳过渲染(并且可能必须随着 D3D 库的每次更新而改变),而不是仅仅修补方法的开头,不需要特殊的清理来跳过方法并且更容易维护。
  • 补丁在开始?请告诉我钩码洞穴的最佳位置在哪里?
  • @lannyboy 我的回答准确地说明了如何做到这一点,但我已经对其进行了编辑以使其更加清晰。
  • 哦,是的!找到了解决方案!我需要将我的代码洞穴中的 eax 归零。 XOR EAX,EAX 已解决:)
猜你喜欢
  • 1970-01-01
  • 2011-03-01
  • 2010-10-21
  • 1970-01-01
  • 2012-08-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-16
  • 1970-01-01
相关资源
最近更新 更多