Windbg / cdb - заменить медленную условную точку останова на исправление в памяти (32-разрядное) - PullRequest
1 голос
/ 06 апреля 2020

Используя cdb, у меня есть следующая условная точка останова

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

Поскольку это делается для исследования прерывистой проблемы, она должна оставаться подключенной в течение некоторого времени, но условная точка останова замедляется общая производительность приложения намного больше, чем я могу себе позволить.

  • Кто-нибудь знает, как оптимизировать условную точку останова? Все, что он делает, это проверяет eax=0. Я прочитал некоторые записи , объясняющие , почему условные точки останова так сильно тормозят, и они имеют смысл, поэтому я предполагаю, что это тупик.
  • Я могу в значительной степени делать то, что я хочу с изображением в памяти. Можно ли пропатчить некоторые инструкции, чтобы вставить что-то вроде if eax = 0 { <whatever>}, чтобы я мог добавить безусловную точку останова на <whatever>?

Edit

из комментариев план действий состоит в следующем:

.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

и теперь я смогу добавить безусловную точку останова на patch+z, чтобы выгружать нужную мне информацию без остановки приложения.

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

Редактировать 2

После PO C работает в сеансе отладки в режиме реального времени, но его все равно необходимо преобразовать в сценарий, который не останавливает приложение, ожидает нажатия клавиш или что-либо еще.

Выполненные команды

.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"

Выполненные команды, включая вывод / контекст

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"

Редактировать 3

ручное исправление 7 запущенных исполняемых файлов прошло успешно, но в зависимости от адреса, возвращаемого .dvalloc, Собранная JMP инструкция содержит другую инструкцию. Я предполагал, что это будет так же просто, как вычитать адрес, к которому мы переходим, из адреса, полученного из .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
   -------------------------------------------------------------

Первый f является знаковым битом возможно?

Редактировать 4

В конце концов, расчет прост, хотя и занял у меня достаточно много времени. Первый f действительно является знаком.

  • Возьмите адрес, чтобы перейти к. В моем случае 004bfa06
  • Вычтите конец ячейки памяти инструкции jmp 004bfa06. В моем случае это всегда .dvalloc+0x16 (.dvalloc+0x11 - начало инструкции)

Применительно к моей последней попытке (7), что дает

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

Ниже приведен пролог функции, в котором я устанавливаю точку останова. Инструкция на 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

Ответы [ 4 ]

2 голосов
/ 08 апреля 2020

Добавление другого ответа

источник, который мы собираемся использовать скомпилированный в сообществе vs2017 как x64
наша задача - разрывать только когда eax = 0x1337 без каких-либо условных бит / с

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);
    }
}

дизассемблирование функции somefun c () выглядит следующим образом

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:

Я собираюсь редактировать байты в трех местах, используя эту 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")
}

байты для исправления были взяты из этого 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")

загрузили исполняемый файл в исправленный windbg и выполнили его для сбоя в 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
1 голос
/ 08 апреля 2020

Благодарность

БОЛЬШОЙ крик Блабу и Томасу за помощь, терпение и примеры (1) (2) (3) они предоставили. Если кто-то наткнется на этот вопрос и ему поможет, пожалуйста, дайте ему свои голоса!

Specifi c в моей ситуации, это были ручные действия, необходимые для исправления функции на 0x004bf9f8, чтобы перейти к Недавно созданный патч, в котором я мог проверить eax на ноль и установить безусловную точку останова.

Ручные действия

Это сработало, но все еще громоздко. Родительское приложение порождает дочерних элементов приложения, которое мне нужно было исправить, поэтому для этого потребовалось немало усилий и риск опечатки или пропуска приложения.

* 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

Сценарии ручных действий

Опять же, я бы не знал, с чего начать без помощи. Следующие проблемы с попыткой написать сценарий ручного действия

  • Команда a в Windbg / cdb не может быть использована в сценарии (отказ от ответственности: уверен в этом)

  • Без команды a мне пришлось прибегнуть к редактированию памяти и найти необходимые коды операций

  • Расчет относительных скачков

Скрипт с минимальным комментарием

* 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

Скрипт с немного чрезмерным комментарием

***** 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
1 голос
/ 08 апреля 2020

E9 код операции может прыгать только + - 2 ГБ, поэтому он немного поврежден в x64
, вам может понадобиться загрузить регистр нуля и перейти туда

.dvallo c имеет переключатель / b, с которым Вы можете указать адрес, чтобы вам не приходилось иметь дело с .parsing .dvallo c

x64 Команда сборки не будет работать в windbg, вам может понадобиться внешний инструмент, такой как keystone

keystone равен c, но доступны python привязки ( устанавливается из msi )

при условии, что у вас есть 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")

выведет эти 12 байтов (вы будете повреждать 12 байтов, поэтому вам нужно их сохранить)

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

теперь это полная разборка произвольной функции, которую я отклоняю

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

Я обращаюсь по адресу 14000100a. Я выделил память размером 0x1000 в 0x200000000, используя .dvallo c, и снова повторно собираю

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

сборка твой лог c в 0х 200000000 восстанавливать поврежденные байты и возвращать их обратно в поток, если адрес возврата находится в середине инструкции, вам может потребоваться использовать правильный адрес

для кода, показанного выше, вам может потребоваться вернуться к 14000101b, так как он поврежден только 12 байты будут повреждать первый байт по инструкции 140001015

1 голос
/ 08 апреля 2020

Это, наверное, очень непрофессионально. Шутки в сторону. Мои знания ассемблера x86 близки к нулю. Мне действительно нравится видеть ответ @blabb или кого-то еще, кто действительно понимает, что он делает. Во всяком случае, вот что я достиг, используя 32-битный блокнот (C:\Windows\SysWow64\notepad.exe).

Адрес новой памяти в $ t8

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

Адрес метода, который должен быть исправлен в $ 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: переход в новую память. Дополните это 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

Подготовить пункт назначения: добавить код 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

Добавить код из 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 является относительным JNE.

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

Давайте исправим это:

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]

И 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

Давайте разберемся, чтобы увидеть, как это происходит

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 message displayed by Notepad

После некоторых окон сообщений я получаю

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

, и я действительно не знаю почему.

...