Хотел в начале в халяву выложить,т.к. по запросу в поисковой системе эта статья нигде не высветилась и посчитал,что,наверное,редкая.Но выложил для всех.Начинающим крякерам будет полезной.
Код:
Патчинг EXECryptor 2.x
Автор: sanniassin
Жертва: execrypt.exe из дистрибутива EXECryptor 2.1.21.
Инструменты (к-рые использовал я): SoftICE 4.32+IceExt 0.66 (олли не катит, потому что EXECryptor её очень не любит), WinHex 12.05 SR9, IDA 4.8.0.847
Попробуем изменить что-нибудь в коде жертвы (например, первый байт на EP (всё-равно он не выполняется)). Получим “File corrupted!”, значит execryptor проверяет CRC файла (кто бы сомневался :)). Посмотрим, как именно он его проверяет. bpx MapViewOfFile ничего интересного не дал, а вот если брякнуться на ReadFile и посмотреть в его (ReadFile) буфер после выхода из ReadFile, то видно, что читаются именно части execrypt.exe :)
Однако при выходе из ReadFile мы попадём не в код протектора, а в функцию _lread, которую использует EXECryptor для чтения защищённого файла. Попробуем поискать в памяти зацикленной проги (например: bpx _lread, !suspend) адрес _lread (у меня это 7С839418). Запускаем WinHex, открываем в нем процесс execrypt->execrypt.exe (Alt+F9) и ищем (Ctrl+Alt+F) адрес _lread (т.е. у меня 7С839418 (пишем в окне поиска ессно в обратном порядке, т.е. 1894837C)). Должно найтись по адресу 7172F4. Нам нужно поменять этот адрес на что-то своё, чтобы можно было корректировать прочитанную часть файла.
Поставим “bpm 7172F4 w” и посмотрим, где по этому адресу будет писаться адрес _lread. Видно, что запись происходит по адресу 7608B7, однако, при запуске проги по этому адресу ничего нет, поэтому будем патчить нешифрованный код протектора в момент, когда код проверки CRC будет расшифрован, но, попытавшись пропатчить код сразу после rep movs, выяснилось, что EXECryptor до проверки CRC файла проверяет ещё и память (не всю и, возможно, не всегда, но для удобства (потому что процедура проверки памяти (сигнатура:
“565189C689D183E904FCACD0E880F874750E8B060FC801C8890683C60483E904497FE7595EC3”) не извращается EXECryptor-ом и находится сразу после TlsCallbacks, поэтому её легко найти) лучше использовать этот метод), поэтому будем патчить процедуру проверки памяти (её начало - 783118 ) (сама эта процедура почему то не проверяется :))
Поставим вместо “jg 783122” jmp 400078 (команды с jg 783122 по ret занимают как-раз 5 байт), т.к. EXECryptor не проверяет CRC до “PE header-20h байт”. По адресу 400078 восстановим команду “jg 783122”, а после неё
HEADER:0040007E cmp esi,78299C | 78299C взято из esi при последнем
| срабатывании бряка на 78313B (сразу после
| jg) в оригинальном exe
HEADER:00400084 jnz short loc_400097
HEADER:00400086 mov dword ptr ds:7608B8h, 0FFC9F7DEh | вместо записи
HEADER:00400090 mov byte ptr ds:7608B7h, 0E8h | _lread, поставим
| переход на наш
| код
HEADER:00400097
HEADER:00400097 loc_400097: ; CODE XREF: HEADER:00400084j
HEADER:00400097 pop ecx | восстанавливаем
HEADER:00400098 pop esi | затертые
HEADER:00400099 retn | команды
По адресу 7608B7 теперь стоит “call 40009A”, а по адресу 40009A напишем такой код
HEADER:0040009A mov ds:478FFCh, eax | сохраним адрес _lread
HEADER:0040009F mov dword ptr ds:7172F4h, 4000AAh | вместо _lread
| сделаем переход на
| наш код
HEADER:004000A9 retn
Вместо _lread мы будем попадать на адрес 4000AA
HEADER:004000AA push dword ptr [esp+0Ch] | восстанавливаем параметры для
HEADER:004000AE push dword ptr [esp+0Ch] | _lread
HEADER:004000B2 push dword ptr [esp+0Ch] |
HEADER:004000B6 call dword ptr ds:478FFCh | и вызываем его
Теперь нужно поймать момент, когда будет читаться измененная нами часть файла (там, где мы поставили jmp 400078). Я сделал так
HEADER:004000BC push eax
HEADER:004000BD mov eax, [esp-4] | пишем в eax адрес буфера для чтения
HEADER:004000C1 cmp dword ptr [eax+34h], 32D7B98Bh | проверяем, нужная
| ли нам часть прочитана
HEADER:004000C8 jnz short loc_4000F6
HEADER:004000CA mov dword ptr [eax+0D69h], 5E59E77Fh | восстанавливаем
HEADER:004000D4 mov byte ptr [eax+0D6Dh], 0C3h | измененный код
HEADER:004000DB mov eax, ds:478FFCh | восстанавливаем переход
HEADER:004000E0 mov ds:7172F4h, eax | на _lread
HEADER:004000E5 mov byte ptr ds:45E674h, 0C3h | делаем с прогой что хотим
А теперь обратим вниманию на фичу “Patch protection”, к-рая должна помешать всяким лоадерам и инлайнам :) Вот только обходится она легко. Поставим bpm 45E674 и когда брякнемся по адресу 74AFBE, то немного потрейсим (F8 - step into) до адреса 77B2F6.
Как видно это какой-то цикл (правда при трейсе встречается ещё и js, но я сначала воспринял его, как мусорный джамп и слава богу, а то начал бы копать не туда :)). Поставим бряк на 77B2FC и отпустим прогу. Когда брякнемся, опять также потрейсим до адреса 716320. Это опять какой-то цикл, поставим бряк на выход из него (т.е. на 716326).
Опять потрейсив заметим, что по адресу 74E1A6 происходит сравнение, похожее на сравнение CRC (используются те же переменные). Если заменить jz на jmp, то никакой “Patch protection” нам не страшен :)
HEADER:004000EC mov word ptr ds:74E1A9h, 0E990h | пресекаем “Patch
| protection”
HEADER:004000F5 nop | nop лишний, просто лень было убрать :)
HEADER:004000F6 loc_4000F6: ; CODE XREF: HEADER:004000C8j
HEADER:004000F6 pop eax
HEADER:004000F7 retn
На этом первая часть закончена.