Я намерен искать коды операций в определенной области памяти в дампе процесса.

Я хочу, чтобы при поиске были некоторые условия.

Например: $$> <<> script.wds #call 00400000 L? 01000000

for(00400000 ~ 01000000)
{
    // this condition is if argument's opcode which is address is not in this area 
   .if(arg1's opcode !in 00400000 ~ 01000000)
      .print arg1
}
0
Steven Beck 18 Фев 2016 в 05:45

3 ответа

Лучший ответ

Вы можете использовать комбинацию #, .foreach и $spat.

Допустим, вы хотите найти несколько первых кодов операций call в notepad!WinMain. Вы можете сделать что-то вроде этого:

0:000> .foreach (addr {# call notepad!WinMain L20}) { .if ($spat("addr", "notepad!*:")) {.echo addr} }
notepad!WinMain+0xa:
notepad!WinMain+0x19:
notepad!WinMain+0x20:
notepad!WinMain+0x33:
notepad!WinMain+0x39:
notepad!WinMain+0x45:

А теперь объяснение.

# call notepad!WinMain L20 ищет строку "call" в дизассемблировании в указанном диапазоне. Это результат:

0:000> # call notepad!WinMain L20
notepad!WinMain+0xa:
01002940 ff1514110001    call    dword ptr [notepad!_imp__GetCommandLineW (01001114)]
notepad!WinMain+0x19:
0100294f ff151c120001    call    dword ptr [notepad!_imp__GetSystemMetrics (0100121c)]
notepad!WinMain+0x20:
01002956 ff1510110001    call    dword ptr [notepad!_imp__GetProcAddress (01001110)]
notepad!WinMain+0x33:
01002969 ffd0            call    eax
notepad!WinMain+0x39:
0100296f e874f2ffff      call    notepad!SkipProgramName (01001be8)
notepad!WinMain+0x45:
0100297b e8e51b0000      call    notepad!NPInit (01004565)

.foreach (var {cmd}) {commands} выполняет cmd , разделяет вывод на пробелы и выполняет {commands} один раз для каждого токена, полученного с помощью " var "заменяется этим токеном.

Без .if мы получили бы что-то вроде:

0:000> .foreach (addr {# call notepad!WinMain L20}) {.echo addr}
notepad!WinMain+0xa:
01002940
ff1514110001
call
dword
ptr
[notepad!_imp__GetCommandLineW
(01001114)]
notepad!WinMain+0x19:
0100294f
ff151c120001
call
dword
ptr
[notepad!_imp__GetSystemMetrics
 .
 .
 .

Наконец, мы добавляем .if, чтобы проверить, начинается ли наш токен с « блокнот! » и заканчивается ли «: ». Обратите внимание, что мы должны проверить наличие двоеточия в конце. В противном случае мы могли бы получить « блокнот! SkipProgramName » и « блокнот! NPInit ». Даже тестирования для « notepad! WinMain * » недостаточно, так как он может быть целью локальных прыжков.


Теперь, если вы хотите передать этот адрес какой-либо команде, вам нужно избавиться от двоеточия в конце псевдонима addr созданной команды .foreach. Я не уверен, что есть способ сделать это, поэтому сделаем последний трюк. Каждый раз, когда мы находим addr , который соответствует шаблону, мы устанавливаем флаг, и на каждой итерации мы проверяем флаг. Если флаг поднят, мы используем текущий токен. Поскольку выход # имеет вид

Symbol:
address opcode_byte opcode_mnemonic argument ...

Токен, следующий за символом, который соответствует нашему шаблону, является чистым адресом.

Например, следующая команда разбирает два кода операции для каждого найденного call:

0:000> .foreach (addr {# call notepad!WinMain L20}) { .if (@$t0==1) { u addr L2; r @$t0=0;}; .if ($spat("addr", "notepad!*:")) { r @$t0 = 1} }
notepad!WinMain+0xa:
01002940 ff1514110001    call    dword ptr [notepad!_imp__GetCommandLineW (01001114)]
01002946 68d8130001      push    offset notepad!`string' (010013d8)
notepad!WinMain+0x19:
0100294f ff151c120001    call    dword ptr [notepad!_imp__GetSystemMetrics (0100121c)]
01002955 50              push    eax
notepad!WinMain+0x20:
01002956 ff1510110001    call    dword ptr [notepad!_imp__GetProcAddress (01001110)]
0100295c 33f6            xor     esi,esi
notepad!WinMain+0x33:
01002969 ffd0            call    eax
0100296b ff7514          push    dword ptr [ebp+14h]
notepad!WinMain+0x39:
0100296f e874f2ffff      call    notepad!SkipProgramName (01001be8)
01002974 50              push    eax
notepad!WinMain+0x45:
0100297b e8e51b0000      call    notepad!NPInit (01004565)
01002980 85c0            test    eax,eax

(Псевдо-регистр $t0 - это флаг.)

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

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

4
Community 23 Май 2017 в 12:09

Ваш запрос неясен, вы хотите сделать что-то подобное

0:000> .shell -ci ".echo"  type c:\foo.txt
# ${$arg1} ${$arg2} ${$arg3}.shell: Process exited

Запустив приведенный выше скрипт, предоставив три аргумента, вы можете найти любую инструкцию в указанном вами диапазоне, аргумент 1 - это вызов, поэтому я хочу найти инструкции по вызову. arg 2 - это выражение, поэтому windbg снова будет оцениваться по адресу, например 0x12340000 arg 3 это выражение, вычисленное как результат размера следующим образом

0:000> $$>a< c:\foo.txt call windbg L900
windbg+0x1009:
01341009 e8340170e8      call    e9a41142
windbg+0x10b5:
013410b5 e834010000      call    windbg+0x11ee (013411ee)
windbg+0x1171:
01341171 e8000060e8      call    e9941176
0
blabb 18 Фев 2016 в 19:20

Я не совсем уверен, понял ли я, что вам нужно, но я думаю, что это похоже на следующее.

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

.for(r @$t2=@$t0; @$t2<@$t1; r @$t2=@$t2+1) {.printf "%d, ", @$t2}

Настроить "параметры" в псевдо-регистрах

0:000> r @$t0 = 0x4
0:000> r @$t1 = 0x10

Затем запускаем скрипт:

0:000> $$>< script.wds
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,

Учитывая всю задачу, я бы не рекомендовал делать это в простом WinDbg и использовать абстракцию более высокого уровня, такую как PyKD, так как

0
Thomas Weller 18 Фев 2016 в 11:41