«Отучаем» WinFXNet от жадности (часть 1)
Простой 18 мин Assembler *Delphi *Отладка *Реверс-инжиниринг * Туториал
В первой части данной статьи быстро пробежимся по процессу, как я искал функции, мешающие запуску программы.
Для иследования нам понадобятся следующие утилиты:
-
Detect It Easy (DiE) (github) — детектор типа файлов.
-
Ghidra (github) либо IDA/Binary Ninja — дизассемблер на ваше усмотрение.
-
x64dbg (github) либо любой любимый вами дебаггер.
-
Interactive Delphi Reconstructor (IDR) (github) — интерактивный декомпилятор под Delphi.
-
Dhrake (github) — комплект скриптов для Ghidr’ы, заточенные под Delphi после IDR.
-
Сама программа — в интернете установщика нигде нет, поэтому залил на github — надеюсь файл проживет какое-то время.
Начинаем с определения, на чем же написана программа (из тегов и списка утилит я думаю вы уже догадались):
Delphi 2010
Прекрасно, старая версия Delphi 2010 года — значит IDR свободно расшифрует формы. Так же DiE нам подсказывает, что используется защита с NetHASP/Hardlock dongle.
Скачиваем IDR, распаковываем архивы с бинарными штампами и анализируем наш exe файл. Ждем, когда пройдет анализ и выбираем в пункте меню «Tools -> IDC generator»:
IDC generator
Полученный файл будет иметь следующую структуру:
Сгенерированный idc файл
Данный файл необходимо чутка подредактировать — IDR генерирует длинные строки через разделитель строк, из-за чего IDA и другие скрипты будут ругаться. Поэтому полученные пробелы и переходы строк необходимо убрать и превратить всё в одну строку:
Примеры строк в idc, где нужно подправить
Затем применим сгенеренный IDC-скрипт: в IDA Pro жмем File → Script File…, выбираем скрипт и ждем применения:
IDA
Либо через View -> Recent scripts выбираем уже запущенные ранее скрипты
Не забываем у IDA в меню Options → Compiler указать компилятор Delphi (по умолчанию стоит C).
В Ghidra выполним скрипты из набора Dhrake:
Ghidra
Перед запуском надо положить в правильное место. Места можно посмотреть через Script Directories
Я положу в USER_HOME/ghidra_scripts
Делаем всё, как написано на гитхабе — DhrakeInit.java выполняем, указываем, где находится наш idc файл, ждем выполнение работы скрипта.
Отлично, теперь дизассемблер понимает наши функции и руками ничего не приходится искать и править. Иногда бывает, что функции имеют неверные границы, но это можете поправить руками самостоятельно.
Вернемся к IDR, который кстати указал для нас стартовую функцию с незамысловатым название EntryPoint. IDR может попытаться воссоздать нам исходный код данной функции, через нажатие клавишы Src:
Программа скорее всего ругнется, но примерное описание ассемблерных функций переведёт в код на Delphi:
Выглядит читаемо
Итак, при старте программы открывается форма TStartUpForm — отличное название формы, прям передаёт суть своего назначения. В IDR открываем вкладку Forms, находим нашу форму и смотрим что к чему:
Нам будет нужна функция открытия диалогово окна OpenDialog, но это чуть позже.
А пока вернемся к коду выше и посмотрим, что нам сгенерировали дизассамблеры для функции EntryPoint:
IDAvoid __noreturn EntryPoint() { int *v0; // ebx char v1; // zf struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; // [esp-Ch] [ebp-2Ch] BYREF void *v3; // [esp-8h] [ebp-28h] int *v4; // [esp-4h] [ebp-24h] int v5; // [esp+4h] [ebp-1Ch] int v6; // [esp+8h] [ebp-18h] int v7[5]; // [esp+Ch] [ebp-14h] BYREF int savedregs; // [esp+20h] [ebp+0h] BYREF v7[0] = 0; v6 = 0; v5 = 0; InitExe(); v0 = Application[0]; v4 = &savedregs; v3 = &loc_660198; ExceptionList = NtCurrentTeb()->NtTib.ExceptionList; __writefsdword(0, (unsigned int)&ExceptionList); TApplication_Initialize(ExceptionList); TCustomForm_Create(*v0, 1); *gvar_00685650 = (int)&loc_595777 + 1; if ( (unsigned __int8)((int (__stdcall *)(struct _EXCEPTION_REGISTRATION_RECORD *))sub_5966B8)(ExceptionList) ) { TCustomForm_Show(); TControl_Refresh(); TApplication_SetTitle(); TApplication_CreateForm(gvar_00685784, VMT_6160F8_TMainForm); TApplication_CreateForm(gvar_006857E8, VMT_601A3C_TSpecialSettingsFrm); TApplication_CreateForm(gvar_00685A24, VMT_5E1248_TAddressReport); TApplication_CreateForm(gvar_006858D8, VMT_5DFA00_TSelectPanelsDlg); TApplication_CreateForm(gvar_006859A0, VMT_5E0224_TSelectLoopsDlg); TApplication_CreateForm(gvar_00685928, VMT_5E0A50_TSelectZonesDlg); TApplication_CreateForm(gvar_00685A5C, VMT_603868_TDCRangeFrm); TApplication_CreateForm(gvar_00685AEC, VMT_6044B8_TDCErrorFrm); if ( ParamCount() > 1 && (ParamStr(), WStrFromUStr(v3), LeftStr(v7, 4), WStrEqual(), v1) ) { TApplication_CreateForm(gvar_006858DC, VMT_5EBFA8_TFXCommHandler); TApplication_CreateForm(gvar_00685B90, VMT_600974_TAutoConfigFrm); TApplication_CreateForm(gvar_00685DC8, &off_5BA430); } else { TApplication_CreateForm(gvar_00685DC4, VMT_5DC858_TFXColSelDlg); TApplication_CreateForm(gvar_006859C0, VMT_5D0788_TFXCGroupsDlg); TApplication_CreateForm(gvar_006858DC, VMT_5EBFA8_TFXCommHandler); TApplication_CreateForm(gvar_006855B8, VMT_6278E8_TAPFillDlg); TApplication_CreateForm(gvar_00685E28, VMT_5FD8EC_TFileImportDlg); TApplication_CreateForm(gvar_00685B94, VMT_5FEF7C_TFileExportDlg); TApplication_CreateForm(gvar_00685DDC, VMT_5E77C8_TConfigInfoDlg); TApplication_CreateForm(gvar_00685918, VMT_5DEE04_TSelectVisibleDlg); TApplication_CreateForm(gvar_00685DC8, &off_5BA430); TApplication_CreateForm(gvar_006855D0, &cls_FXDbgForm_TDbgFrm); TApplication_CreateForm(gvar_00685E08, (char *)&loc_5B3C7B + 1); TApplication_CreateForm(gvar_00685C48, VMT_5F23C8_TPreviewForm); TApplication_CreateForm(gvar_00685E50, &cls_FXEsaFileMerge_TMergeEsaForm); TApplication_CreateForm(gvar_006855D4, &cls_FXEsaFileMergeReport_TEsaReport); } UStrAsg(); *(_BYTE *)(*v0 + 91) = 0; TApplication_Run(); } __writefsdword(0, (unsigned int)v4); UStrClr(&loc_66019F); WStrArrayClr(); Halt0(); }
Ghidra void EntryPoint(void) { undefined *puVar1; char cVar2; undefined4 uVar3; int iVar4; undefined4 unaff_EBX; undefined4 *in_FS_OFFSET; bool bVar5; undefined4 uStack_30; undefined *puStack_2c; undefined *puStack_28; undefined4 local_20; undefined4 local_1c; wchar_t *local_18 [5]; local_18[0] = (wchar_t *)0x0; local_1c = 0; local_20 = 0; puStack_28 = (undefined *)0x65fed4; @InitExe(&DAT_00658424); puVar1 = Application; puStack_2c = &LAB_00660198; uStack_30 = *in_FS_OFFSET; *in_FS_OFFSET = &uStack_30; puStack_28 = &stack0xfffffffc; TApplication.Initialize(*(undefined4 *)puVar1); uVar3 = TCustomForm.Create(&LAB_00595778,1,*(undefined4 *)puVar1); *(undefined4 *)gvar_00685650 = uVar3; cVar2 = FUN_005966b8(*(undefined4 *)gvar_00685650); if (cVar2 == ‘