Чтобы испытать новое средство для реверса, созданное в стенах АНБ США, я решил поломать замечательную и несложную крэкми MalwareTech. Выбрал ее неслучайно. В одной из своих статей я рассказывал о том, как устроена виртуализация кода, и мы даже написали простенькую виртуалку. А теперь давай посмотрим, как ломать такую защиту.
Скачать крэкми можно с сайта MalwareTech, пароль к архиву — тоже MalwareTech.
Итак, для начала посмотрим, что в архиве. Видим исполняемый файл vm1.exe, файл дампа ram.bin и readme.txt, в котором написано, что мы имеем дело с восьмибитной виртуальной машиной. Файл дампа — не что иное, как кусок памяти, в котором вперемешку расположены рандомные данные и флаг, который мы должны найти. Оставим пока в покое файл дампа и посмотрим на vm1.exe через программу DiE.
DiE не показывает ничего интересного, с энтропией все в порядке. Значит, никакой навесной защиты нет, но проверить все равно стоило. Давай загрузим этот файл в Ghidra и посмотрим, что она выдаст. Я приведу полный листинг приложения без функций (он совсем небольшой) — чтобы ты понял, с чем мы имеем дело.
PUSH EBP MOV EBP ,ESP SUB ESP ,0x94 LEA ECX =>local_94 ,[0xffffff70 + EBP ] CALL MD5::MD5 PUSH 0x1fb PUSH 0x0 CALL dword ptr [->KERNEL32.DLL::GetProcessHeap ] PUSH EAX CALL dword ptr [->KERNEL32.DLL::HeapAlloc ] MOV [DAT_0040423c ],EAX PUSH 0x1fb PUSH DAT_00404040 MOV EAX ,[DAT_0040423c ] PUSH EAX CALL memcpy ADD ESP ,0xc CALL FUN_004022e0 MOV ECX ,dword ptr [DAT_0040423c ] PUSH ECX LEA ECX =>local_94 ,[0xffffff70 + EBP ] CALL MD5::digestString MOV dword ptr [local_98 + EBP ],EAX PUSH 0x30 PUSH s_We've_been_compromised!_0040302c MOV EDX ,dword ptr [local_98 + EBP ] PUSH EDX PUSH 0x0 CALL dword ptr [->USER32.DLL::MessageBoxA ] PUSH 0x0 CALL dword ptr [->KERNEL32.DLL::ExitProcess ] XOR EAX ,EAX MOV ESP ,EBP POP EBP RET
Как видишь, код простой и легко читается. Давай воспользуемся декомпилятором Ghidra и посмотрим, что он выдаст.
undefined4 entry(void) { HANDLE hHeap; char *lpText; DWORD dwFlags; SIZE_T dwBytes; MD5 local_94 [144]; MD5(local_94); dwBytes = 0x1fb; dwFlags = 0; hHeap = GetProcessHeap(); DAT_0040423c = (char *)HeapAlloc(hHeap,dwFlags,dwBytes); memcpy(DAT_0040423c,&DAT_00404040,0x1fb); FUN_004022e0(); lpText = digestString(local_94,DAT_0040423c); MessageBoxA((HWND)0x0,lpText,"We've been compromised!",0x30); ExitProcess(0); return 0; }
Я добавил отступы для удобочитаемости — отделил объявления переменных от остального кода. Код весьма простой: сначала выделяется память в куче GetProcessHeap -> HeapAlloc, далее в нее копируется 0x1fb(507) байт из DAT_00404040. Но у нас нет ничего интересного в 00404040! Вспоминаем, что в инструкции к крэкми говорилось, что ram.bin — это кусок памяти. Разумеется, если посмотреть размер файла, он оказывается равным 507 байт.
Загружаем ram.bin в HxD или любой другой шестнадцатеричный редактор и смотрим.

Увы, ничего внятного там не обнаруживаем. Но логика работы немного проясняется: DAT_0040423c — это ram.bin (наши выделенные 507 байт в куче). Давай переименуем DAT_0040423c в RAM, чтобы было удобнее ориентироваться в коде. Далее заходим в функцию FUN_004022e0.
Продолжение доступно только подписчикам
Материалы из последних выпусков можно покупать отдельно только через два месяца после публикации. Чтобы продолжить чтение, необходимо купить подписку.
Подпишись на «Хакер» по выгодной цене!
Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке
1 год7390 р. Экономия 1400 рублей! |
1 месяц720 р. 25-30 статей в месяц |
Уже подписан?