Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #89, МАЙ 2006 г.

Дао универсальной распаковки

Крис Касперски

Хакер, номер #089, стр. 089-114-3


Возьмем, к примеру, тот же ASPack и посмотрим в его начало:

[точка входа в распаковщик ASPack]

:u eip

01010001 PUSHAD

01010002 CALL 0101000A

01010007 JMP 465E04F7

0101000C PUSH EBP

0101000D RET

Замечательно! Первая же команда сохраняет все регистры в стеке. Очевидно, что непосредственно перед передачей управления на OEP они будут восстановлены командой POPA, выполнение которой очень легко отследить, установив точку останова на двойное слово, лежащее выше верхушки стека: "bpm esp - 4".

Результат превосходит все ожидания:

[передача управления на OEP]

010103AF POPAD ; на этой команде отладчик всплывает

010103B0 JNZ 010103BA

010103B2 MOV EAX,00000001

010103B7 RET 000C

010103BA PUSH 1006420 ; передача управления на OEP

010103BF RET

Распаковав программу, ASPack заботливо выталкивает сохраненные регистры из стека, вызывая всплытие отладчика, и мы видим тривиальный код, передающий управление на OEP "классическим" способом через PUSH offset OEP/RET. Поиск исходной точки входа не затратил и десятка секунд! Ну разве не красота?

А теперь возьмем UPX и проверим, удастся ли нам провернуть этот трюк и над ним? Ведь мы же претендуем на универсальный пример!

[так начинается UPX]

01011710 PUSHAD ; <- упаковщик сохраняет регистры

01011711 MOV ESI,0100D000

01011716 LEA EDI,[ESI+FFFF4000]

0101171C PUSH EDI

Вот он, уже знакомый нам PUSHAD, сохраняющий все регистры в стеке и восстанавливающий их непосредственно перед передачей управления на OEP. Даем команду "bpm esp-4" и выходим из отладчика, пока он не всплывет.

[так UPX передает управление на OEP]

0101185E POPAD

0101185F JMP 01006420

А вот и отличия! Передача управления осуществляется командой JMP 1006420h, где 1006420h — исходная точка входа. Похоже, что все упаковщики работают по одному и тому же алгоритму и ломаются, как в ночь перед исходом.

Но не будем смешить. Возьмем PE-compact и проверим свою догадку на нем.

[точка входа в файл, упакованный PE-compact]

01001000 MOV EAX,01011974

01001005 PUSH EAX

01001006 PUSH DWORD PTR FS:[00000000]

0100100D MOV FS:[00000000],ESP

Плохо дело! PE-compact никаких регистров вообще не сохраняет, а PUSH EAX используется только затем, чтобы установить свой обработчик структурных исключений. Тем не менее, на момент завершения распаковки указатель стека должен быть восстановлен, следовательно, точка останова на "bpm esp-4" все-таки может сработать….

[первое срабатывание точки останова на esp-4]

77F8AF78 PUSH DWORD PTR [EBX+04]

77F8AF7B LEA EAX,[EBP-10]

77F8AF7E PUSH EAX

Так, ну это срабатывание явно левое (судя по EIP 77F8AF78h, мы находимся где-то внутри KERNEL32.DLL, использующим стек для нужд производственной необходимости), давим <Ctrl-D>, не желая здесь больше задерживаться.

[Кузьмич?! Где это я?]

010119A6 PUSH EBP

010119A7 PUSH EBX

010119A8 PUSH ECX

010119A9 PUSH EDI

Следующее всплытие отладчика также не проясняет ситуацию. Ясно только одно: в стек сохраняется регистр EBP вместе с другими регистрами. Давим <Ctrl-D> и ждем дальше.

Назад на стр. 089-114-2  Содержание  Вперед на стр. 089-114-4