简体   繁体   English

Windbg/cdb - 将慢速条件断点替换为 memory 补丁(32 位)

[英]Windbg/cdb - Replace a slow conditional breakpoint with an in memory patch (32-bit)

Using cdb, I have following conditional breakpoint使用 cdb,我有以下条件断点

bp 004bf9f8 ".if (@eax = 0) {.echotime;.echo Breakpoint 004bf9f8;r};gc"

As this is to investigate an intermittent issue, it has to stay attached for quite some time but the conditional breakpoint slows down the overall performance of the application far more than I can afford.由于这是为了调查一个间歇性问题,它必须保持连接相当长的一段时间,但条件断点会降低应用程序的整体性能,远远超出我的承受能力。

  • Anyone any idea how to optimize the conditional breakpoint?有人知道如何优化条件断点吗? All it does is checking eax=0 .它所做的只是检查eax=0 I have read some posts explaining why conditional breakpoints slow down so much and those make perfect sense so I assume this is a dead end.我已经阅读了一些帖子,解释了为什么条件断点会这么慢,而且这些帖子非常有意义,所以我认为这是一个死胡同。
  • I can pretty much do what I want with the in memory image.我几乎可以用 memory 图像做我想做的事。 Would it be possible to patch some instructions as to insert something like if eax = 0 { <whatever>} so I could add an unconditional breakpoint on <whatever> ?是否可以修补一些指令以插入类似if eax = 0 { <whatever>}这样我可以在<whatever>上添加无条件断点?

Edit编辑

from the comments, the plan of action is to script as follows从评论来看,行动计划是编写如下脚本

.dvalloc <bytes> and store the result in a variable called patch .dvalloc <bytes>并将结果存储在名为patch的变量中

a 004bfa08 JMP patch
a patch MOV eax,esi
a patch+x CMP eax,0
a patch+y JNE 004bfa0a
a patch+z JMP 004bfa0a

and now I should be able to add an unconditional breakpoint on patch+z to dump the information I need without halting the application.现在我应该能够在patch+z上添加一个无条件断点来转储我需要的信息,而无需停止应用程序。

bp patch+z ".echotime;.echo Breakpoint patch+z;~.;r;!dpx;gc"

Edit 2编辑 2

Following POC works in a live debugging session but this still has to be converted to a script that doesn't halt the application, waiting for keypresses or anything.以下 POC 在实时调试 session 中工作,但这仍然必须转换为不会停止应用程序、等待按键或任何东西的脚本。

Commands executed执行的命令

.dvalloc 1000

a 004bfa00
JMP 0x0c570000
NOP

a 0xc570000
mov edi,edx
mov esi,eax
mov ebp,edi
cmp eax,0
jne 0x004bfa06
jmp 0x004bfa06

bp 0c570011 ".echo Hello World"

Commands executed including output/context执行的命令,包括输出/上下文

0:010> .dvalloc 1000
Allocated 1000 bytes starting at 0c570000

0:010> u 004bf9f8 LD
application+0xbf9f8:
004bf9f8 53              push    ebx
004bf9f9 56              push    esi
004bf9fa 57              push    edi
004bf9fb 55              push    ebp
004bf9fc 51              push    ecx
004bf9fd 890c24          mov     dword ptr [esp],ecx
004bfa00 8bfa            mov     edi,edx |
004bfa02 8bf0            mov     esi,eax |-> these get overwritten so repeat in patch
004bfa04 8bef            mov     ebp,edi |
004bfa06 8bd5            mov     edx,ebp
004bfa08 8bc6            mov     eax,esi
004bfa0a e8e5feffff      call    application+0xbf8f4 (004bf8f4)

0:010> a 004bfa00
JMP 0x0c570000
NOP

0:010> u 004bf9f8 LD
application+0xbf9f8:
004bf9f8 53              push    ebx
004bf9f9 56              push    esi
004bf9fa 57              push    edi
004bf9fb 55              push    ebp
004bf9fc 51              push    ecx
004bf9fd 890c24          mov     dword ptr [esp],ecx
004bfa00 e9fb050b0c      jmp     0c570000
004bfa05 90              nop
004bfa06 8bd5            mov     edx,ebp
004bfa08 8bc6            mov     eax,esi
004bfa0a e8e5feffff      call    application+0xbf8f4 (004bf8f4)

0:010> a 0xc570000
0c570000 mov edi,edx
mov edi,edx
0c570002 mov esi,eax
mov esi,eax
0c570004 mov ebp,edi
mov ebp,edi
0c570006 cmp eax,0
cmp eax,0
0c57000b jne 0x004bfa06
jne 0x004bfa06
0c570011 jmp 0x004bfa06
jmp 0x004bfa06
0c570016 

0:010> u 0x0c570000 L6
0c570000 8bfa            mov     edi,edx
0c570002 8bf0            mov     esi,eax
0c570004 8bef            mov     ebp,edi
0c570006 3d00000000      cmp     eax,0
0c57000b 0f85f5f9f4f3    jne     application+0xbfa06 (004bfa06)
0c570011 e9f0f9f4f3      jmp     application+0xbfa06 (004bfa06)

0:010> bp 0c570011 ".echo Hello World"

Edit 3编辑 3

manually patching 7 running executables was successful but depending on the address returned by .dvalloc , the assembled JMP instruction contains a different instruction.手动修补 7 个正在运行的可执行文件是成功的,但根据.dvalloc返回的地址,汇编的JMP指令包含不同的指令。 I assumed it would be as simple as subtracting the address we jump to from the address obtained from .dvalloc but that does not seem to be the case.我认为这就像从从.dvalloc获得的地址中减去我们跳转到的地址一样简单,但情况似乎并非如此。

   -------------------------------------------------------------
   .dvalloc+0x11 |a jmp 004bfa06 |opcode |cd       |LE
   --------------|---------------|-------|---------|------------
1. 00df0011      |e9f0f96cff     |e9     |f0f96cff |ff 6c f9 f0
2. 00e30011      |e9f0f968ff     |e9     |f0f968ff |ff 68 f9 f0
3. 00f00011      |e9f0f95bff     |e9     |f0f95bff |ff 5b f9 f0
4. 00ff0011      |e9f0f94cff     |e9     |f0f94cff |ff 4c f9 f0
5. 093a0011      |e9f0f911f7     |e9     |f0f911f7 |f7 11 f9 f0
6. 0c570011      |e9f0f9f4f3     |e9     |f0f9f4f3 |f3 f4 f9 f0
7. 0ce70011      |e9f0f964f3     |e9     |f0f964f3 |f3 64 f9 f0
   -------------------------------------------------------------

The first f is a sign bit perhaps?第一个f可能是一个符号位?

Edit 4编辑 4

The calculation is straightforward after all, took me long enough though.毕竟,计算很简单,尽管我花了足够长的时间。 The first f indeed is the sign.第一个f确实是符号。

  • Take the address to jump to.取要跳转的地址。 In my case 004bfa06在我的情况下004bfa06
  • Subtract the end of the memory location of the jmp 004bfa06 instruction.减去jmp 004bfa06指令的 memory 位置的末尾。 In my case, that is always .dvalloc+0x16 ( .dvalloc+0x11 is the start of the instruction)在我的情况下,那总是.dvalloc+0x16.dvalloc+0x11是指令的开始)

Applied to my last attempt (7), that gives应用于我的最后一次尝试(7),这给出了

004fba01 - 0ce70016 = f3 64 f9 f0. 
The instruction to edit the memory at 0ce70011 then becomes e9f0f964f3.

Following is the function prologue where I am setting the breakpoint.以下是我设置断点的 function 序言。 The instruction at 004bfa08 (MOV param_1,ESI) is redundant because of the previous instruction at 004bfa02 (MOV ESI,param_1) so that might be usefull but I lack the knowledge on how to proceed from here. 004bfa08 (MOV param_1,ESI)处的指令是多余的,因为004bfa02 (MOV ESI,param_1)处的前一条指令可能有用,但我缺乏关于如何从这里开始的知识。

                     **************************************************************
                     *                          FUNCTION                          *
                     **************************************************************
                     int * __register FUN_004bf9f8(int param_1, int param_2, 
     int *             EAX:4          <RETURN>
     int               EAX:4          param_1
     int               EDX:4          param_2
     int               ECX:4          param_3
     undefined4        Stack[-0x14]:4 local_14

004bf9f8 53              PUSH       EBX
004bf9f9 56              PUSH       ESI
004bf9fa 57              PUSH       EDI
004bf9fb 55              PUSH       EBP
004bf9fc 51              PUSH       param_3
004bf9fd 89 0c 24        MOV        dword ptr [ESP]=>local_14,param_3
004bfa00 8b fa           MOV        EDI,param_2
004bfa02 8b f0           MOV        ESI,param_1
004bfa04 8b ef           MOV        EBP,EDI
004bfa06 8b d5           MOV        param_2,EBP
004bfa08 8b c6           MOV        param_1,ESI
004bfa0a e8 e5 fe        CALL       FUN_004bf8f4
         ff ff
004bfa0f 8b d8           MOV        EBX,param_1

Adding Another Answer添加另一个答案

source we are going to use compiled with in vs2017 community as x64我们将在 vs2017 社区中使用编译为 x64 的源
our task is to break only when eax = 0x1337 without any conditional bps我们的任务是仅在 eax = 0x1337 且没有任何条件 bps 时才中断

cl /Zi /W4 /analyze /EHsc /Od /nologo  patch.cpp /link /release /entry:main  /subsystem:windows

Source资源

#include <windows.h>
#pragma comment(lib,"kernel32.lib")
int count = 0;
int somefunc()
{
    return count++;
}
int main(void)
{
    for (;;)
    {
        somefunc();
        Sleep(2);
    }
}

the disassembly of function somefunc() is as follows function somefunc()的反汇编如下

F:\src\deto>cdb -c "uf deto!somefunc;q" deto.exe | f:\git\usr\bin\awk.exe "/Reading/,/quit/"
0:000> cdb: Reading initial command 'uf deto!somefunc;q'
deto!somefunc:
00000001`40001000 4883ec18        sub     rsp,18h
00000001`40001004 8b05f61f0000    mov     eax,dword ptr [deto!count (00000001`40003000)]
00000001`4000100a 890424          mov     dword ptr [rsp],eax
00000001`4000100d 8b05ed1f0000    mov     eax,dword ptr [deto!count (00000001`40003000)]
00000001`40001013 ffc0            inc     eax
00000001`40001015 8905e51f0000    mov     dword ptr [deto!count (00000001`40003000)],eax
00000001`4000101b 8b0424          mov     eax,dword ptr [rsp]
00000001`4000101e 4883c418        add     rsp,18h
00000001`40001022 c3              ret
quit:

I am going to edit bytes in three places using this JavaScript我将使用这个 JavaScript 在三个地方编辑字节

function log(a)
{
    host.diagnostics.debugLog( a + '\n');
}

function exec (cmdstr)
{
    return host.namespace.Debugger.Utility.Control.ExecuteCommand(cmdstr);
}

function patch()
{
log("hi")
exec(".dvalloc /b 0x200000000 1000")
exec("eb 0x14000100a 0x49 0xbf 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x41 0xff 0xe7")
exec("eb 0x200000000 0x3d 0x37 0x13 0x0 0x0 0x49 0xbf 0x0 0x8 0x0 0x0 0x2 0x0 0x0 0x0 0x74 0x25 0x36 0x89 0x4 0x24 0xa1 0x0 0x30 0x0 0x40 0x1 0x0 0x0 0x0 0xff 0xc0 0xa3 0x0 0x30 0x0 0x40 0x1 0x0 0x0 0x0 0x49 0xbf 0x1b 0x10 0x0 0x40 0x1 0x0 0x0 0x0 0x41 0xff 0xe7 0x41 0xff 0xe7")
exec("eb 0x200000800 0xcc")
}

the bytes to patch were taken from this python script要修补的字节取自此 python 脚本

from keystone import *
print ("assemble at 0x14000100a\n")
CODE = b"mov r15,0x200000000;jmp r15"
ks = Ks(KS_ARCH_X86,KS_MODE_64)
encoding,count = ks.asm(CODE)
for i in encoding:
    print(hex(i),end = " ")
print("\n")
print ("Assemble at 0x200000000\n")
CODE = b"cmp eax,0x1337;\
        mov r15,0x200000800;\
        je here;\
        mov dword ptr ss:[rsp],eax;\
        mov eax,dword ptr ds:[0x140003000];\
        inc eax;\
        mov dword ptr ds:[0x140003000],eax;\
        mov r15, 0x14000101b;\
        jmp r15;\
        here:;\
        jmp r15;"
encoding,count = ks.asm(CODE)
for i in encoding:
    print(hex(i),end = " ")
print("\n")
print ("Assemble at 0x200000800 an int 3 aka 0xcc")

loaded the exe in windbg patched and executed to break in 0x200000800加载windbg中的exe补丁并执行以中断0x200000800

Microsoft (R) Windows Debugger Version 10.0.17763.132 AMD64

ntdll!LdrpDoDebuggerBreak+0x30:
00007ff9`b33f121c cc              int     3

0:000> .scriptload f:\wdscr\patch.js

JavaScript script successfully loaded from 'f:\wdscr\patch.js'

0:000> dx @$scriptContents.patch()
hi
@$scriptContents.patch()

0:000> uf deto!somefunc
Flow analysis was incomplete, some code may be missing
deto!somefunc [f:\src\deto\deto.cpp @ 5]:
    5 00000001`40001000 4883ec18        sub     rsp,18h
    6 00000001`40001004 8b05f61f0000    mov     eax,dword ptr [deto!count (00000001`40003000)]
    6 00000001`4000100a 49bf0000000002000000 mov r15,200000000h <<<<<<<<<<<
    6 00000001`40001014 41ffe7          jmp     r15 <<<<<<<<<<<<<<<<<<<

0:000> g
(3aec.405c): Break instruction exception - code 80000003 (first chance)
00000002`00000800 cc              int     3 <<<<<<<<<<<<<<
0:000> r eax
eax=1337

This is probably very unprofessional.这可能是非常不专业的。 Seriously.严重地。 My x86 assembler knowledge is close to zero.我的 x86 汇编知识接近于零。 I really like to see an answer of @blabb or someone else who really understands what he does.我真的很想看到@blabb 或其他真正了解他的工作的人的回答。 Anyway, here's what I've achieved using 32 Bit Notepad ( C:\Windows\SysWow64\notepad.exe ).无论如何,这是我使用 32 位记事本 ( C:\Windows\SysWow64\notepad.exe ) 所取得的成果。

Address of new memory in $t8 $t8 中新 memory 的地址

0:007> ~0s
0:000> .foreach /pS 5 (addr {.dvalloc 100000}) {r $t8=${addr}}; ? $t8
Evaluate expression: 179699712 = 0ab60000

Address of method to be patched in $t7 $t7 中要修补的方法的地址

0:000> .foreach /pS 3 (addr {.frame 2}) {r $t7=${addr}}; ? $t7
0:000> .writemem winmain.mem $t7 L200
0:000> u $t7 L7
notepad!WinMain+0x1a3:
007ec4a6 85c0            test    eax,eax
007ec4a8 0f8567ffffff    jne     notepad!WinMain+0x112 (007ec415)
007ec4ae 8d442438        lea     eax,[esp+38h]
007ec4b2 50              push    eax
007ec4b3 6a00            push    0
007ec4b5 ff3500288000    push    dword ptr [notepad!szFileName (00802800)]
007ec4bb ff150c328000    call    dword ptr [notepad!_imp__GetFileAttributesExW (0080320c)]

Patch: jump to new memory.补丁:跳转到新的 memory。 Pad this with NOPs until we end up on the next statement用 NOP 填充它,直到我们结束下一个语句

0:000> eb $t7+0 50 B8
0:000> ed $t7+2 $t8+20
0:000> eb $t7+6 FF E0 58 90 90 90 
0:000> u $t7 L7
notepad!WinMain+0x1a3:
007ec4a6 50              push    eax            // because we need it for the jump
007ec4a7 b80000b60a      mov     eax,0AB60000h
007ec4ac ffe0            jmp     eax
007ec4ae 58              pop     eax
007ec4af 90              nop
007ec4b0 90              nop
007ec4b1 90              nop

Prepare destination: add hello world code准备目的地:添加hello world代码

0:000> eu $t8 "Hello world!"
0:000> eb $t8+20 B8 00 00 00 00 50 B8
0:000> ed $t8+27 $t8
0:000> eb $t8+2b 50 50 B8 00 00 00 00 50 B8
0:000> ed $t8+34 USER32!MessageBoxW
0:000> eb $t8+38 FF D0 58 58 58 58 58

0:000> u $t8+20 LE
0ab60020 b800000000      mov     eax,0           // MB_OK
0ab60025 50              push    eax             
0ab60026 b80000b60a      mov     eax,0AB60000h   // "Hello world!"
0ab6002b 50              push    eax             // Text
0ab6002c 50              push    eax             // Caption
0ab6002d b800000000      mov     eax,0           // Desktop HWND
0ab60032 50              push    eax
0ab60033 b87013b077      mov     eax,offset USER32!MessageBoxW (77b01370)
0ab60038 ffd0            call    eax
0ab6003a 58              pop     eax  // Desktop HWND
0ab6003b 58              pop     eax  // Caption
0ab6003c 58              pop     eax  // Text
0ab6003d 58              pop     eax  // MB_OK
0ab6003e 58              pop     eax  // EAX which was rescued before jumping here

Add code from WinMain:从 WinMain 添加代码:

0:000> .readmem winmain.mem $t8+3f L200
Reading 200 bytes.

0:000> u $t8+3f L3
0ab6003f 85c0            test    eax,eax
0ab60041 0f8567ffffff    jne     0ab5ffae
0ab60047 8d442438        lea     eax,[esp+38h]

0F85 is a relative JNE. 0F85 是一个相对的 JNE。

007ec4a8 0f8567ffffff    jne     notepad!WinMain+0x112 (007ec415)
0:000> ? dwo($t8+43)
Evaluate expression: -153 = ffffff67

Let's fix that:让我们解决这个问题:

0:000> ed $t8+43 ($t7+2)-($t8+41)+dwo($t8+43)
0:000> u $t8+3f L3
0ab6003f 85c0            test    eax,eax
0ab60041 0f85cec3c8f5    jne     notepad!WinMain+0x112 (007ec415)
0ab60047 8d442438        lea     eax,[esp+38h]

And go back和 go 背

0:000> eb $t8+4b 50 B8
0:000> ed $t8+4d $t7+8
0:000> eb $t8+51 ff e0
0:000> u $t8+4b L3
0ab6004b 50              push    eax  // Because we need it for the jump
0ab6004c b8aec47e00      mov     eax,offset notepad!WinMain+0x1ab (007ec4ae)
0ab60051 ffe0            jmp     eax

Let's break to see it happen让我们休息看看它发生

0:000> bp $t8+20
0:000> bp $t7
0:000> bl
     0 e Disable Clear  0aea0020     0001 (0001)  0:**** 
     1 e Disable Clear  007ec4a6     0001 (0001)  0:**** notepad!WinMain+0x1a3

0:000> g
Breakpoint 1 hit
007ec4a6 50              push    eax
0:000> p
007ec4a7 b82000ea0a      mov     eax,0AEA0020h
0:000> p
007ec4ac ffe0            jmp     eax {0aea0020}
0:000> p
Breakpoint 0 hit
0aea0020 b800000000      mov     eax,0
0:000> g
Breakpoint 1 hit
007ec4a6 50              push    eax
0:000> bd 0
0:000> bd 1

记事本显示的 Hello world 消息

After some message boxes, I get在一些消息框之后,我得到

STATUS_STACK_BUFFER_OVERRUN encountered
(2f28.4008): Break instruction exception - code 80000003 (first chance)

and I don't really know why.我真的不知道为什么。

E9 opcode can jump only +- 2GB so it is kinda crippled in x64 E9 操作码只能跳转 +- 2GB 所以它在 x64 中有点残缺
you may need to load a scratch register and jump there你可能需要加载一个暂存器并跳转到那里

.dvalloc has a switch /b with which you can specify an address so you don't have to deal with.parsing.dvalloc .dvalloc 有一个开关 /b ,您可以使用它指定一个地址,因此您不必处理.parsing.dvalloc

x64 assemble command wont work in windbg you may need an external tool like keystone x64 assemble 命令在 windbg 中不起作用,您可能需要像 keystone 这样的外部工具

keystone is c but python bindings are available ( installable from msi ) keystone是 c 但 python 绑定可用( 可从 msi 安装

assuming you have python and keystone假设你有 python 和 keystone

from keystone import *
CODE = b"mov r15,0x200000000;jmp r15"
ks = Ks(KS_ARCH_X86,KS_MODE_64)
encoding,count = ks.asm(CODE)
for i in encoding:
    print(hex(i),end = " ")
print("\n")

will output these 12 bytes (you will be damaging 12 bytes so you need to save them)将 output 这 12 个字节(您将损坏 12 个字节,因此您需要保存它们)

0x49 0xbf 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x41 0xff 0xe7 0x49 0xbf 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x41 0xff 0xe7

now this is the complete disassembly of an arbitrary function which I am detouring现在这是我绕道而行的任意 function 的完整反汇编

0:000> uf .
deto!somefunc [f:\src\deto\deto.cpp @ 5]:
    5 00000001`40001000 4883ec18        sub     rsp,18h
    6 00000001`40001004 8b05f61f0000    mov     eax,dword ptr [deto!count (00000001`40003000)]
    6 00000001`4000100a 890424          mov     dword ptr [rsp],eax
    6 00000001`4000100d 8b05ed1f0000    mov     eax,dword ptr [deto!count (00000001`40003000)]
    6 00000001`40001013 ffc0            inc     eax
    6 00000001`40001015 8905e51f0000    mov     dword ptr [deto!count (00000001`40003000)],eax
    6 00000001`4000101b 8b0424          mov     eax,dword ptr [rsp]
    7 00000001`4000101e 4883c418        add     rsp,18h
    7 00000001`40001022 c3              ret

I am detouring at address 14000100a I have allocated 0x1000 sized memory at 0x200000000 using.dvalloc and redisassembling again我在地址 14000100a 绕道我已经使用.dvalloc 在 0x200000000 分配了 0x1000 大小的 memory 并再次重新反汇编

0:000> .dvalloc /b 200000000 1000
Allocated 1000 bytes starting at 00000002`00000000
0:000> eb 14000100a 0x49 0xbf 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x41 0xff 0xe7
0:000> uf .
Flow analysis was incomplete, some code may be missing
deto!somefunc [f:\src\deto\deto.cpp @ 5]:
    5 00000001`40001000 4883ec18        sub     rsp,18h
    6 00000001`40001004 8b05f61f0000    mov     eax,dword ptr [deto!count (00000001`40003000)]
    6 00000001`4000100a 49bf0000000002000000 mov r15,200000000h
    6 00000001`40001014 41ffe7          jmp     r15

assemble your logic in 0x200000000 restore damaged bytes and return back to flow if the return address is in middle of an instruction you may need to use a proper address在 0x200000000 中组装您的逻辑,如果返回地址在指令中间,则恢复损坏的字节并返回流程,您可能需要使用正确的地址

for the code shown above you may have to return back to 14000101b as damaging just 12 bytes will be damaging the first byte at instruction 140001015对于上面显示的代码,您可能必须返回到 14000101b,因为仅损坏 12 个字节将损坏指令 140001015 处的第一个字节

Acknowledgment致谢

A BIG shout out to blabb and Thomas for the help, patience and examples (1) (2) (3) they have provided.向 blabb 和 Thomas 大声疾呼,感谢他们提供的帮助、耐心和示例(1) (2) (3) If anyone stumbles on this question and is helped by it, please give them your votes!如果有人偶然发现这个问题并得到了帮助,请给他们投票!

Specific to my situation, these were the manual actions needed to patch up the function at 0x004bf9f8 to jump to a newly created patch where I could test eax for nil and set an unconditional breakpoint.具体到我的情况,这些是在 0x004bf9f8 处修补0x004bf9f8以跳转到新创建的补丁所需的手动操作,我可以在其中测试 eax 是否为 nil 并设置无条件断点。

Manual actions手动操作

This worked but it's still cumbersome.这有效,但仍然很麻烦。 The parent application spawns children of the application I needed to patch so this required quite a bit of effort and a risk of mistyping or missing an application.父应用程序产生了我需要修补的应用程序的子应用程序,因此这需要相当多的努力,并且存在输入错误或丢失应用程序的风险。

* Make a note of the address returned (pe. 0x00df0000)
.dvalloc 100

* Replace all <patch> by previous returned address. Copy/past following 3 lines (+enter)
a 004bfa00
JMP <patch>
NOP

* Copy/paste following 7 lines (+enter)
a <patch>
mov edi,edx
mov esi,eax
mov ebp,edi
cmp eax,0
jne 0x004bfa06
jmp 0x004bfa06

* Copy/paste following line 1 in cdb
bp <patch>+0x11 ".echo Breakpoint 004bf9f8 Nil Pointer Unconditional Check;r!dpx};gc"

* Verify
u 004bf9f8 LD
u <patch> LD

Scripting of the manual actions手动操作的脚本

Again, I wouldn't have know where to begin without the help provided.同样,如果没有提供的帮助,我将不知道从哪里开始。 Following issues with trying to script the manual actions尝试编写手动操作脚本的问题

  • The a command in Windbg/cdb can't be used in a script (disclaimer: pretty sure of it) Windbg/cdb 中的a命令不能在脚本中使用(免责声明:非常确定)

  • Without the a command, I had to resort to editing memory and look up the required opcodes如果没有a命令,我不得不求助于编辑 memory 并查找所需的操作码

  • Calculating relative jumps计算相对跳跃

Script with minimal comment带有最少注释的脚本

* Make note of returned address and store in $t8
.foreach /pS 5 (patch {.dvalloc 100}) {r $t8=${patch}}; ? $t8

* Patch the function to jump to $t8
r $t9=$t8-(0x004bfa00+0x05)
eb 0x004bfa00 e9
ed 0x004bfa01 $t9
eb 0x004bfa05 90

* Create the patch at $t8
ew $t8+0x00 fa8b
ew $t8+0x02 f08b
ew $t8+0x04 ef8b
eb $t8+0x06 3d
ed $t8+0x07 00000000
r $t9=0x004bfa06-($t8+0x11)
ew $t8+0x0b 850f
ed $t8+0x0d $t9
r $t9=0x004bfa06-($t8+0x16)
eb $t8+0x11 e9
ed $t8+0x12 $t9

* Set the unconditional breakpoint
bp $t8 ".echo Breakpoint 004bf9f8 Nil Pointer Unconditional Check;r;!dpx};gc"

* Verify
u 004bf9f8 LD
u $t8 LD

Script with a bit excessive comment注释有点过多的脚本

***** Allocate 100 bytes of memory to hold our patch
*     Remember the start adress in the $t8 pseudo register
.foreach /pS 5 (patch {.dvalloc 100}) {r $t8=${patch}}; ? $t8

***** Patch the function to jump to $t8
*     Jump to our patch when entering function 0x004bf948 to test for nil pointer
* 1 0x004bfa00 e9<offset>      jmp     <patch> ($t8 LE)
* 2 0x004bfa05 90              nop

        ***** 1 0x004bfa00 e9<offset> jmp <patch> ($t8 LE)
        * r $t9   the size of the jump from 0x004bfa00+0x05 to $t8
        * eb      e9 is the opcode for JMP
        * ed      append with offset where to jump to
        r $t9=$t8-(0x004bfa00+0x05)
        eb 0x004bfa00 e9
        ed 0x004bfa01 $t9

        ***** 2 0x004bfa05 90 nop
        * eb      90 is the opcode for NOP
        eb 0x004bfa05 90

***** Create the patch at $t8
*     Repeat the replaced code at 0x004bfa00 used to jump to our new address
*     Add a compare with nil
*     Jump back to where we left off (0x004bfa06)
* 1 0x00000000 8bfa            mov     edi,edx
* 2 0x00000002 8bf0            mov     esi,eax
* 3 0x00000004 8bef            mov     ebp,edi
* 4 0x00000006 3d00000000      cmp     eax,0
* 5 0x0000000b 0f85<offset>    jne     app+0xbfa06 (004bfa06)
* 6 0x00000011 e9<offset>      jmp     app+0xbfa06 (004bfa06)

        ***** 1 0x0000000 mov edi,edx
        * ew      8b is the opcode for MOV
        *         fa is the opcode for ebp,edi
        ew $t8+0x00 fa8b

        ***** 2 0x0000002 mov esi,eax
        * ew      8b is the opcode for MOV
        *         f0 is the opcode for esi,eax
        ew $t8+0x02 f08b

        ***** 3 0x0000004 mov ebp,edi
        * ew      8b is the opcode for MOV
        *         ef is the opcode for ebp,edi
        ew $t8+0x04 ef8b

        ***** 4 0x0000006 cmp eax,0
        * eb      3d is the opcode for JNE
        * ed      append with what to compare with
        eb $t8+0x06 3d
        ed $t8+0x07 00000000

        ***** 5 0x000000b jne app+0xbfa06 (004bfa06)
        * r $t9   the size of the jump from $t8+11 to 0x004bfa06
        * ew      0f 85 is the opcode for JNE
        * ed      append with offset where to jump to
        r $t9=0x004bfa06-($t8+0x11)
        ew $t8+0x0b 850f
        ed $t8+0x0d $t9

        ***** 6 jmp app+0xbfa06 (004bfa06)
        * r $t9   the size of the jump from $t8+16 to 0x004bfa06
        * eb      e9 is the opcode for JMP
        * ed      append with offset where to jump to
        r $t9=0x004bfa06-($t8+0x16)
        eb $t8+0x11 e9
        ed $t8+0x12 $t9

***** Conditional Breakpoint/Log on address $t8
bp $t8+0x11 ".echo Breakpoint 004bf9f8 Nil Pointer Unconditional Check;r;!dpx};gc"

***** Verify
u 004bf9f8 LD
u $t8 LD

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM