RCE.SU - реверсинг, кодинг, выделенные сервера, ICQ, proxy

Пишем плагин к Imprec 1.42

Imprec 1.42 это великая вещь, тока к сожалению иногда не может восстановить некоторые функции, которые, если глянуть в айсе, имеют весьма приличный вид. В imprec есть возможность писать свои плагины чтоб решать такие проблемы. Вот ща напишем плагин, чтоб восстанавливать функции, которые Imprec 1.42 после asprotect восстановить не может.

Непонятно почему, но imprec иногда не восстанавливает функции вида:

:012373C4 55          PUSH      EBP  
:012373C5 8B EC	      MOV       EBP,ESP
:012373C7 56          PUSH      ESI
:012373C8 E9 xxxxxxxx JMP       BFBABB63

Первые три команды - это кусок из вызываемой функции. Т.е. реально функция выглядит так:
:BFBABB5F  PUSH      EBP
:BFBABB60  MOV       EBP,ESP
:BFBABB62  PUSH      ESI
:BFBABB63  MOV       ESI,[EBP+08]
:BFBABB66  PUSH      ESI
:BFBABB67  CALL      BFB74A08
:BFBABB6C  TEST      EAX,EAX
и т.д.
Т.е. происходит "эмуляция" вызова, т.к. вызов апи происходит не с первой команды, а как мы тут видим, с четвертой.

Такие вызовы могут производится через 2 типа джампов: относительный и прямой. Если был бы прямой jmp то вот те xxxxxxxx = 63 BB BA BF. При относительном jmp эти xxxxxxxx содержат смещение относительно команды jmp. При таком вызове xxxxxxxx = BFBABB63-012373C8-5 (5 - длина команды jmp) т.е. xxxxxxxx = 96 47 97 BE. Еще может быть не jmp, а push - ret. Ну тут тоже самое просто опкод у push другой.

Так вот в Imprec 1.42 есть исходник ихнего ASProtect 1.2x Emul.dll. Лежит он в \Plugin\Src\ASProtect\Delphi\ и называется aspr.dpr

Возьмем его за основу и напишем свой плагин. Находим в aspr.dpr цикл который идет после movememory (addr(to_trace),pointer(g_pointer),15);
//all different types of redirection code, a common one is mov eax,[xxxxxx].
//check for this and the value at xxxxxx and try to guess it ;)
found := false;

Там идет
For i:=0 to 9 do
begin
...
и длинное тело цикла.
Выкидываем этот цикл нафиг и пишем туда свой :) Вот такой

for i := 0 to 27 do
  begin
        if (to_trace[i] = $e9) or (to_trace[i] = $68) then
        Begin
         val:=to_trace[4+i] shl 24 + to_trace[3+i] shl 16 +
         to_trace[2+i] shl 8 + to_trace[1+i];
         if val<$400000 then continue;
         if IsBadReadPtr(pointer(val), 4) then
          val:=to_trace[4+i] shl 24 + to_trace[3+i] shl 16 +
          to_trace[2+i] shl 8 + to_trace[1+i]+g_pointer+5
         else
          val:=to_trace[4+i] shl 24 + to_trace[3+i] shl 16 +
          to_trace[2+i] shl 8 + to_trace[1+i]-i;

         found := true;
         break;
        end;
  end;
И еще надо поправить буфер в Var:
to_trace :array[0..32] of BYTE; а то 16 байтов это маловато.
Ну и естественно
movememory (addr(to_trace),pointer(g_pointer),32);

Теперь поясню. Плагин читает в массив to_trace 32 байта от адреса, который горит в Imprec. Дальше ищем байт $e9. Когда нашли - читаем четыре байта после него. Сначала делаю проверку, чтоб оно не схватило какой-нить push 00100000 (val<$400000). И этим же 4 байтам определяем какой это тип джампа: прямой или относительный. Определяю я это через по IsBadReadPtr. Еcли вернет true то это относительный джамп, иначе - прямой. g_pointer - это адрес который imprec увидел в IAT, т.е. тот, от которого мы начали анализ. Дальше нужно вернуть адрес в переменную val и сказать что мы успешно нашли, что искали (found:=true;).

Компилим и скидываем скомпиленную dll в каталог Plugins. Вот и все. Можно юзать.

P.S. Вероятный глюк. Может не определить функцию если смещение в относительном джампе попадет = адресу какой-нить области занятной левой dll и т.д. Т.е. IsBadReadPtr cкажет, что все нормально и будет возвращен неправильный адрес.


<= Вернуться к статьям


Rambler's Top100