Modern technology gives us many things.

«Отучаем» WinFXNet от жадности (часть 1)

51

Уровень сложности Простой Время на прочтение 18 мин Количество просмотров 3.2K 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 — надеюсь файл проживет какое-то время.

Начинаем с определения, на чем же написана программа (из тегов и списка утилит я думаю вы уже догадались):

«Отучаем» WinFXNet от жадности (часть 1)

Delphi 2010

Прекрасно, старая версия Delphi 2010 года — значит IDR свободно расшифрует формы. Так же DiE нам подсказывает, что используется защита с NetHASP/Hardlock dongle.

Скачиваем IDR, распаковываем архивы с бинарными штампами и анализируем наш exe файл. Ждем, когда пройдет анализ и выбираем в пункте меню «Tools -> IDC generator»:

«Отучаем» WinFXNet от жадности (часть 1)

IDC generator

Полученный файл будет иметь следующую структуру:

«Отучаем» WinFXNet от жадности (часть 1)

Сгенерированный idc файл

Данный файл необходимо чутка подредактировать — IDR генерирует длинные строки через разделитель строк, из-за чего IDA и другие скрипты будут ругаться. Поэтому полученные пробелы и переходы строк необходимо убрать и превратить всё в одну строку:

«Отучаем» WinFXNet от жадности (часть 1)

Примеры строк в idc, где нужно подправить

Затем применим сгенеренный IDC-скрипт: в IDA Pro жмем File → Script File…, выбираем скрипт и ждем применения:

IDA

«Отучаем» WinFXNet от жадности (часть 1)

Либо через View -> Recent scripts выбираем уже запущенные ранее скрипты

«Отучаем» WinFXNet от жадности (часть 1)

Не забываем у IDA в меню Options → Compiler указать компилятор Delphi (по умолчанию стоит C).

В Ghidra выполним скрипты из набора Dhrake:

Ghidra

«Отучаем» WinFXNet от жадности (часть 1)

«Отучаем» WinFXNet от жадности (часть 1)

Перед запуском надо положить в правильное место. Места можно посмотреть через Script Directories

«Отучаем» WinFXNet от жадности (часть 1)

Я положу в USER_HOME/ghidra_scripts

Делаем всё, как написано на гитхабе — DhrakeInit.java выполняем, указываем, где находится наш idc файл, ждем выполнение работы скрипта.

Отлично, теперь дизассемблер понимает наши функции и руками ничего не приходится искать и править. Иногда бывает, что функции имеют неверные границы, но это можете поправить руками самостоятельно.

Вернемся к IDR, который кстати указал для нас стартовую функцию с незамысловатым название EntryPoint. IDR может попытаться воссоздать нам исходный код данной функции, через нажатие клавишы Src:

«Отучаем» WinFXNet от жадности (часть 1)

Программа скорее всего ругнется, но примерное описание ассемблерных функций переведёт в код на Delphi:

«Отучаем» WinFXNet от жадности (часть 1)

Выглядит читаемо

Итак, при старте программы открывается форма TStartUpForm — отличное название формы, прям передаёт суть своего назначения. В IDR открываем вкладку Forms, находим нашу форму и смотрим что к чему:

«Отучаем» WinFXNet от жадности (часть 1)

Нам будет нужна функция открытия диалогово окна 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 == ‘’) goto LAB_00660175; TCustomForm.Show(*(undefined4 *)gvar_00685650); TControl.Refresh(*(undefined4 *)gvar_00685650); TApplication.SetTitle(*(undefined4 *)puVar1,&DAT_006601b4); TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_00616150,gvar_00685784); TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_00601a94,gvar_006857E8); TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005e12a0,gvar_00685A24); TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005dfa58,gvar_006858D8); TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005e027c,gvar_006859A0); TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005e0aa8,gvar_00685928); TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_006038c0,gvar_00685A5C); TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_00604510,gvar_00685AEC); iVar4 = ParamCount(); if (iVar4 < 2) { LAB_00660052: uStack_30 = 0x660065; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005dc8b0,gvar_00685DC4); uStack_30 = 0x660078; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005d07e0,gvar_006859C0); uStack_30 = 0x66008b; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005ec000,gvar_006858DC); uStack_30 = 0x66009e; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_00627940,gvar_006855B8); uStack_30 = 0x6600b1; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005fd944,gvar_00685E28); uStack_30 = 0x6600c4; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005fefd4,gvar_00685B94); uStack_30 = 0x6600d7; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005e7820,gvar_00685DDC); uStack_30 = 0x6600ea; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005dee5c,gvar_00685918); uStack_30 = 0x6600fd; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005ba430,gvar_00685DC8); uStack_30 = 0x660110; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_0059ab9c,gvar_006855D0); uStack_30 = 0x660123; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005b3c7c,gvar_00685E08); uStack_30 = 0x660136; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005f2420,gvar_00685C48); uStack_30 = 0x660149; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005babf0,gvar_00685E50); uStack_30 = 0x66015c; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005b3ef4,gvar_006855D4); } else { ParamStr(2,&local_20); @WStrFromUStr(&local_1c,local_20); uStack_30 = 0x660005; LeftStr(local_1c,4,local_18); uStack_30 = 0x660012; bVar5 = @WStrEqual(local_18[0],L»auto»); if (!bVar5) goto LAB_00660052; uStack_30 = 0x660027; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005ec000,gvar_006858DC); uStack_30 = 0x66003a; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_006009cc,gvar_00685B90); uStack_30 = 0x66004d; TApplication.CreateForm(*(undefined4 *)puVar1,&LAB_005ba430,gvar_00685DC8); } uStack_30 = 0x660168; @UStrAsg(*(int *)puVar1 + 0x50,0); *(undefined *)(*(int *)puVar1 + 0x5b) = 0; uStack_30 = 0x660175; TApplication.Run(*(undefined4 *)puVar1); LAB_00660175: *in_FS_OFFSET = puStack_2c; puStack_28 = (undefined *)0x66018a; @UStrClr(&local_20,puStack_2c,unaff_EBX); puStack_28 = (undefined *)0x660197; @WStrArrayClr(&local_1c,2); return; }

Читать на TechLife:  В России резко подешевел Exeed TXL

Тут кому как нравится (мне кажется нагляднее Гидра выдала), но суть у всех одинаковая — смотрим на выполнение функции FUN_005966b8.

IDAvoid __fastcall sub_5966B8(int a1) { int v1; // esi int v2; // ebx double v3; // st7 double v4; // st7 char v5; // bl int v6; // esi char v7; // zf const WCHAR *v8; // eax const WCHAR *v9; // eax double v10; // st7 int v11; // ecx int v12; // ecx int v13; // ecx int v14; // ecx const WCHAR *v15; // [esp-14h] [ebp-390h] const WCHAR *v16; // [esp-14h] [ebp-390h] struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; // [esp-Ch] [ebp-388h] BYREF void *v18; // [esp-8h] [ebp-384h] int *v19; // [esp-4h] [ebp-380h] int v20; // [esp+Ch] [ebp-370h] BYREF int v21[2]; // [esp+10h] [ebp-36Ch] BYREF int v22; // [esp+18h] [ebp-364h] BYREF char v23[256]; // [esp+1Ch] [ebp-360h] BYREF int v24; // [esp+11Ch] [ebp-260h] BYREF int v25; // [esp+120h] [ebp-25Ch] BYREF int v26; // [esp+124h] [ebp-258h] BYREF int v27; // [esp+128h] [ebp-254h] BYREF __int64 v28; // [esp+12Ch] [ebp-250h] BYREF double v29; // [esp+134h] [ebp-248h] int v30; // [esp+13Ch] [ebp-240h] BYREF double v31; // [esp+140h] [ebp-23Ch] int v32; // [esp+148h] [ebp-234h] BYREF WCHAR pszPath[261]; // [esp+14Ch] [ebp-230h] BYREF char v34; // [esp+357h] [ebp-25h] int v35; // [esp+358h] [ebp-24h] int v36; // [esp+35Ch] [ebp-20h] BYREF int v37; // [esp+360h] [ebp-1Ch] BYREF int v38; // [esp+364h] [ebp-18h] BYREF int v39; // [esp+368h] [ebp-14h] BYREF int v40; // [esp+36Ch] [ebp-10h] BYREF int v41; // [esp+370h] [ebp-Ch] BYREF int v42; // [esp+374h] [ebp-8h] BYREF int v43; // [esp+378h] [ebp-4h] BYREF int savedregs; // [esp+37Ch] [ebp+0h] BYREF v35 = a1; v19 = &savedregs; v18 = &loc_596DE0; ExceptionList = NtCurrentTeb()->NtTib.ExceptionList; __writefsdword(0, (unsigned int)&ExceptionList); v34 = 0; do { v1 = 2; v2 = sub_590CDC(*(_DWORD *)(v35 + 932)); if ( v2 == 7 ) v1 = MessageDlgPosHelp(0, -1, -1, 0); } while ( v2 && v1 != 2 ); if ( v2 > 41 ) { if ( v2 != 8001 && v2 != 8002 ) { if ( v2 != 8003 ) { LABEL_20: LODWORD(v31) = v2; BYTE4(v31) = 0; Format(&v32); MessageDlgPosHelp(0, -1, -1, 0); } LABEL_21: if ( v2 ) { v34 = 0; goto LABEL_59; } v31 = sub_58FD08(*(_DWORD *)(v35 + 932)); v3 = ((double (__fastcall *)(_DWORD))loc_58FCA8)(*(_DWORD *)(v35 + 932)); if ( v31 — v3 < 60.0 ) { v29 = sub_58FD08(*(_DWORD *)(v35 + 932)); v4 = ((double (__fastcall *)(_DWORD))loc_58FCA8)(*(_DWORD *)(v35 + 932)); v28 = TRUNC(v29 — v4); LODWORD(v31) = &v28; BYTE4(v31) = 16; Format(&v30); MessageDlgPosHelp(0, -1, -1, 0); } shell32_SHGetSpecialFolderPathW(0, pszPath, 28, 0); UStrFromWArray(&v27, pszPath, 261); UStrCat3(&v43, v27, &off_596E0C); UStrCat3(&v42, v43, &loc_596E38); UStrFromWArray(&v26, pszPath, 261); UStrCat3(&v41, v26, &off_596E60); UStrCat3(&v40, v41, &loc_596E38); UStrFromWArray(&v25, pszPath, 261); UStrCat3(&v39, v25, aSchneider); UStrCat3(&v38, v39, &loc_596E38); while ( 1 ) { if ( (unsigned __int8)FileExists(v38) ) { UStrLAsg(&v37, v38); } else if ( (unsigned __int8)FileExists(v40) ) { UStrLAsg(&v37, v40); } else { UStrLAsg(&v37, v42); } v5 = 0; v6 = sub_595EF4(LODWORD(dbl_70911C) + 1032); if ( !v6 ) { v5 = 0; UStrEqual(v37, v40); if ( v7 || (UStrEqual(v37, v42), v7) ) { if ( !(unsigned __int8)DirectoryExists(v39) ) ForceDirectories(v39); v15 = (const WCHAR *)UStrToPWChar(v38); v8 = (const WCHAR *)UStrToPWChar(v37); kernel32_CopyFileW(v8, v15, 0); } goto LABEL_54; } if ( (unsigned int)(v6 — 1) < 4 ) { if ( MessageDlgPosHelp(0, -1, -1, 0) != 6 ) { v5 = 0; goto LABEL_54; } if ( !(unsigned __int8)sub_5960D8(LODWORD(dbl_70911C), &v36) ) { v5 = 0; goto LABEL_54; } if ( !(unsigned __int8)DirectoryExists(v39) ) ForceDirectories(v39); } else { if ( v6 != 5 ) goto LABEL_54; v10 = ((double (__fastcall *)(_DWORD))loc_58FCA8)(*(_DWORD *)(v35 + 932)); LODWORD(v31) = TRUNC(*(double *)(LODWORD(dbl_70911C) + 1032) — v10); BYTE4(v31) = 0; Format(&v24); if ( MessageDlgPosHelp(0, -1, -1, 0) != 6 ) { v5 = 0; goto LABEL_54; } if ( !(unsigned __int8)sub_5960D8(LODWORD(dbl_70911C), &v36) ) { v5 = 0; goto LABEL_54; } if ( !(unsigned __int8)DirectoryExists(v39) ) ForceDirectories(v39); } v16 = (const WCHAR *)UStrToPWChar(v38); v9 = (const WCHAR *)UStrToPWChar(v36); kernel32_CopyFileW(v9, v16, 0); v5 = 1; LABEL_54: if ( !v5 ) { if ( v6 == 5 ) v6 = 0; if ( !v6 ) { LStrFromString(ExceptionList); sub_5912B4(v21[1], &v22); LStrToString(v23, v22, 255); LOBYTE(v11) = 50; PStrNCpy(LODWORD(dbl_70911C) + 166, v23, v11); LStrFromString(v18); sub_5912B4(v20, v21); LStrToString(v23, v21[0], 255); LOBYTE(v12) = 25; PStrNCpy(LODWORD(dbl_70911C) + 140, v23, v12); *(_BYTE *)gvar_0068564C = (*(_BYTE *)(LODWORD(dbl_70911C) + 138) & 1) != 0; *(_BYTE *)gvar_00685670 = (*(_BYTE *)(LODWORD(dbl_70911C) + 138) & 2) != 0; *(_BYTE *)gvar_00685A88 = (*(_BYTE *)(LODWORD(dbl_70911C) + 138) & 4) != 0; *(_BYTE *)gvar_00685DE8 = (*(_BYTE *)(LODWORD(dbl_70911C) + 138) & 8) != 0; *(_BYTE *)gvar_00685800 = (*(_BYTE *)(LODWORD(dbl_70911C) + 138) & 0x10) != 0; *(_BYTE *)gvar_00685DFC = (*(_BYTE *)(LODWORD(dbl_70911C) + 138) & 0x20) != 0; *(_BYTE *)gvar_00685964 = (*(_BYTE *)(LODWORD(dbl_70911C) + 138) & 0x40) != 0; *(_BYTE *)gvar_00685C5C = *(char *)(LODWORD(dbl_70911C) + 138) < 0; v34 = 1; } LABEL_59: __writefsdword(0, (unsigned int)ExceptionList); v19 = (int *)&loc_596DE7; LStrArrayClr(&v20, 4); UStrArrayClr(&v24, 4, v13); UStrClr(v19); UStrClr(v19); UStrArrayClr(&v36, 8, v14); JUMPOUT(0x596DF1); } } } } else if ( v2 != 41 ) { if ( !v2 || v2 == 7 ) goto LABEL_21; if ( v2 != 12 && v2 != 25 ) goto LABEL_20; } MessageDlgPosHelp(0, -1, -1, 0); goto LABEL_21; }

Читать на TechLife:  30 лет DOOM: новый код — новые баги

Ghidra void FUN_005966b8(int param_1) { bool bVar1; wchar_t *pwVar2; char cVar3; uint uVar4; int iVar5; LPCWSTR pWVar6; LPCWSTR pWVar7; int iVar8; wchar_t *unaff_EBX; undefined4 unaff_ESI; wchar_t *unaff_EDI; int *in_FS_OFFSET; bool bVar9; float10 in_ST0; float10 in_ST1; float10 in_ST2; undefined4 param_11; undefined4 local_374; undefined4 local_370; undefined4 local_36c; undefined4 local_368; undefined local_364 [256]; undefined4 local_264; wchar_t *local_260; wchar_t *local_25c; wchar_t *local_258; undefined4 local_254 [2]; double local_24c; undefined4 local_244; undefined8 local_240; undefined4 local_238; WCHAR local_234 [252]; undefined4 uStackY_3c; undefined4 uStackY_38; BOOL BVar10; undefined4 *puVar11; int local_24; undefined *local_20; wchar_t *local_1c; wchar_t *local_c; wchar_t *local_8; local_1c = (wchar_t *)&stack0xfffffffc; iVar8 = 0x6e; do { local_8 = (wchar_t *)0x0; iVar8 = iVar8 + -1; } while (iVar8 != 0); local_20 = &LAB_00596de0; local_24 = *in_FS_OFFSET; *in_FS_OFFSET = (int)&local_24; do { iVar8 = 2; puVar11 = (undefined4 *)(param_1 + 0x3a4); param_1 = 0x5966f7; uVar4 = FUN_00590cdc(*puVar11); if (uVar4 == 0x70) { param_1 = 0; uStackY_38 = 0x59672d; iVar8 = MessageDlgPosHelp((&PTR_u_USB_License_key_could_not_be_fou_006829f0) [(uint)(byte)*gvar_00685658 * 0xe],1,0×28); } } while ((uVar4 != 0) && (iVar8 != 2)); if ((int)uVar4 < 0x2a) { if (uVar4 == 0x29) { param_1 = 0; uStackY_38 = 0x5967af; MessageDlgPosHelp((&PTR_u_The_USB_License_key_has_expired_00682a0c) [(uint)(byte)*gvar_00685658 * 0xe],1,4); goto LAB_005968a3; } if ((uVar4 == 0) || (uVar4 == 7)) goto LAB_005968a3; if ((uVar4 == 0xc) || (uVar4 == 0x19)) { param_1 = 0; uStackY_38 = 0x59684b; MessageDlgPosHelp((&PTR_u_USB_License_key_clock_failure_00682a04) [(uint)(byte)*gvar_00685658 * 0xe],1,4); goto LAB_005968a3; } } else { if (uVar4 == 0x1f41) { param_1 = 0; uStackY_38 = 0x5967e3; MessageDlgPosHelp((&PTR_u_USB_License_key_is_invalid_006829fc) [(uint)(byte)*gvar_00685658 * 0xe],1,4); goto LAB_005968a3; } if (uVar4 == 0x1f42) { param_1 = 0; uStackY_38 = 0x596817; MessageDlgPosHelp((&PTR_u_The_USB_License_key_has_expired_00682a0c) [(uint)(byte)*gvar_00685658 * 0xe],1,4); goto LAB_005968a3; } if (uVar4 == 0x1f43) goto LAB_005968a3; } local_240._0_5_ = (uint5)uVar4; Format((&PTR_u_USB_License_key_error:_%d_006829f8)[(uint)(byte)*gvar_00685658 * 0xe],&local_240 ,0) ; param_1 = 0; uStackY_38 = 0x5968a3; MessageDlgPosHelp(local_238,1,4); LAB_005968a3: if (uVar4 == 0) { iVar8 = 0x5968be; FUN_0058fd08(*(undefined4 *)(param_1 + 0x3a4)); local_240 = (double)in_ST0; FUN_0058fca8(*(undefined4 *)(iVar8 + 0x3a4)); if ((float10)local_240 — in_ST1 < (float10)60.0) { puVar11 = &local_244; FUN_0058fd08(param_11); local_24c = (double)in_ST2; FUN_0058fca8(puVar11[0xe9]); local_254[0] = @TRUNC(); local_240._0_5_ = CONCAT14(0x10,local_254); Format((&PTR_u_The_USB_License_key_for_this_sof_006829f4)[(uint)(byte)*gvar_00685658 * 0xe] , &local_240,0); uStackY_38 = 0x59697f; MessageDlgPosHelp(local_244,0,4); } uStackY_38 = 0x596991; shell32.SHGetSpecialFolderPathW((HWND)0x0,local_234,0x1c,0); @UStrFromWArray(&local_258,local_234,0x105); @UStrCat3(&local_8,local_258,L»\Esmi\WinFXNet\»); @UStrCat3(&local_c,local_8,L»winfxnet.lic»); @UStrFromWArray(&local_25c,local_234,0x105); @UStrCat3((wchar_t **)&stack0xfffffff0,local_25c,L»\Pelco\WinFXNet\»); @UStrCat3((wchar_t **)&stack0xffffffec,unaff_EBX,L»winfxnet.lic»); @UStrFromWArray(&local_260,local_234,0x105); @UStrCat3((wchar_t **)&stack0xffffffe8,local_260,L»\Schneider Electric\WinFXNet\»); @UStrCat3(&local_1c,unaff_EDI,L»winfxnet.lic»); do { cVar3 = FileExists(local_1c); if (cVar3 == ‘’) { cVar3 = FileExists(unaff_ESI); if (cVar3 == ‘’) { iVar8 = 0x596a79; @UStrLAsg(&local_20,local_c); } else { iVar8 = 0x596a6c; @UStrLAsg(&local_20,unaff_ESI); } } else { iVar8 = 0x596a53; @UStrLAsg(&local_20,local_1c); } bVar1 = false; local_24 = DAT_0070911c + 0x408; iVar5 = FUN_00595ef4(DAT_0070911c,local_20,DAT_0070911c + 4); if (iVar5 == 0) { bVar1 = false; bVar9 = true; @UStrEqual(local_20,unaff_ESI); if ((bVar9) || (@UStrEqual(local_20,local_c), bVar9)) { cVar3 = DirectoryExists(unaff_EDI); if (cVar3 == ‘’) { ForceDirectories(unaff_EDI); } BVar10 = 0; pWVar6 = (LPCWSTR)@UStrToPWChar(local_1c); pWVar7 = (LPCWSTR)@UStrToPWChar(local_20); uStackY_38 = 0x596af8; kernel32.CopyFileW(pWVar7,pWVar6,BVar10); } } else if (iVar5 — 1U < 4) { uStackY_38 = 0; uStackY_3c = 0x596b30; iVar8 = MessageDlgPosHelp(*(undefined4 *) ((uint)(byte)*gvar_00685658 * 0x38 + 0x6829d4 + iVar5 * 4),1,3) ; if (iVar8 == 6) { cVar3 = FUN_005960d8(DAT_0070911c,&local_24); if (cVar3 == ‘’) { bVar1 = false; } else { cVar3 = DirectoryExists(unaff_EDI); if (cVar3 == ‘’) { ForceDirectories(unaff_EDI); } BVar10 = 0; pWVar6 = (LPCWSTR)@UStrToPWChar(local_1c); pWVar7 = (LPCWSTR)@UStrToPWChar(local_24); uStackY_38 = 0x596b70; kernel32.CopyFileW(pWVar7,pWVar6,BVar10); bVar1 = true; } } else { bVar1 = false; } } else if (iVar5 == 5) { FUN_0058fca8(*(undefined4 *)(iVar8 + 0x3a4)); uVar4 = @TRUNC(); local_240._0_5_ = (uint5)uVar4; Format((&PTR_u_The_license_information_file_for_006829e8)[(uint)(byte)*gvar_00685658 * 0x e], &local_240,0); uStackY_38 = 0; uStackY_3c = 0x596bfc; iVar8 = MessageDlgPosHelp(local_264,0,3); if (iVar8 == 6) { cVar3 = FUN_005960d8(DAT_0070911c,&local_24); if (cVar3 == ‘’) { bVar1 = false; } else { cVar3 = DirectoryExists(unaff_EDI); if (cVar3 == ‘’) { ForceDirectories(unaff_EDI); } BVar10 = 0; pWVar6 = (LPCWSTR)@UStrToPWChar(local_1c); pWVar7 = (LPCWSTR)@UStrToPWChar(local_24); uStackY_38 = 0x596c3c; kernel32.CopyFileW(pWVar7,pWVar6,BVar10); bVar1 = true; } } else { bVar1 = false; } } } while (bVar1); if (iVar5 == 5) { iVar5 = 0; } if (iVar5 == 0) { @LStrFromString(&local_36c,DAT_0070911c + 0xa6,0); local_24 = 0x596c86; FUN_005912b4(local_36c,&local_368); local_24 = 0x596c9c; @LStrToString(local_364,local_368,0xff); local_24 = 0x596cb0; @PStrNCpy(DAT_0070911c + 0xa6,local_364,0x32); local_24 = 0x596cc8; @LStrFromString(&local_374,DAT_0070911c + 0x8c,0); local_24 = 0x596cd9; FUN_005912b4(local_374,&local_370); local_24 = 0x596cef; @LStrToString(local_364,local_370,0xff); local_24 = 0x596d03; @PStrNCpy(DAT_0070911c + 0x8c,local_364,0x19); *gvar_0068564C = (*(byte *)(DAT_0070911c + 0x8a) & 1) != 0; *gvar_00685670 = (*(byte *)(DAT_0070911c + 0x8a) & 2) != 0; *gvar_00685A88 = (*(byte *)(DAT_0070911c + 0x8a) & 4) != 0; *gvar_00685DE8 = (*(byte *)(DAT_0070911c + 0x8a) & 8) != 0; *gvar_00685800 = (*(byte *)(DAT_0070911c + 0x8a) & 0x10) != 0; *gvar_00685DFC = (*(byte *)(DAT_0070911c + 0x8a) & 0x20) != 0; *gvar_00685964 = (*(byte *)(DAT_0070911c + 0x8a) & 0x40) != 0; *gvar_00685C5C = (*(byte *)(DAT_0070911c + 0x8a) & 0x80) != 0; } } pwVar2 = local_1c; *in_FS_OFFSET = local_24; local_1c = (wchar_t *)&LAB_00596de7; local_20 = (undefined *)0x596dac; @LStrArrayClr(&local_374,4,pwVar2); local_20 = (undefined *)0x596dbc; @UStrArrayClr(&local_264,4); local_20 = (undefined *)0x596dc7; @UStrClr(&local_244); local_20 = (undefined *)0x596dd2; @UStrClr(&local_238); local_20 = (undefined *)0x596ddf; @UStrArrayClr(&local_24,8); return; }

Нам на глаза падает вызов функции FUN_00590cdc, которая взависимости от возвращаемого значения позволит нам запустить программу дальше или нет. Исходя из условия цикла, если мы закоментируем вызов данной функции и изменим условие на проверку равенства, то всё должно пройти дальше. Пробуем — открываем x32dbg, загружаем exeшник, переходим по адресу 005966f2 (этот адрес мы получили из той же гидры):

«Отучаем» WinFXNet от жадности (часть 1)

x32dbg

«Отучаем» WinFXNet от жадности (часть 1)

Щелкаем правой кнопкой мыши в поле CPU, выбираем Перейти -> Выражение

«Отучаем» WinFXNet от жадности (часть 1)

Вбиваем наш адрес и жмем окей. По F2 выставляем точку останова, но на адрес выше.

Вызов данной функции я заменяю на mov eax, 0x0 и смотрю, что и этого выходит:

x32dbg

«Отучаем» WinFXNet от жадности (часть 1)

Правой кнопкой по адресу выбираем Ассемблировать

Отлично! Мы дошли до выбора файла лицензии уже ПО. Файл действующей лицензии у нас есть (в отличии от HASP ключа), поэтому я указываю его и он появится в открытой папке на видео (AppDataLocalSchneider ElectricWinFXNet).

Продолжим дальше вычищать программу от скрытых проверок ключа. Вернёмся к IDR. Откроем основную форму и посмотрим на элементы:

«Отучаем» WinFXNet от жадности (часть 1)

TMainForm

В глаза бросается хитрое название таймера — LicTimer, который имеет вызов функции call 0061EFB8. Посмотрим, что там внутри такого:

Читать на TechLife:  Первые подробности о кросс-универсале Dacia C-Neo 2026: крутой дизайн, платформа как у Lada Iskra и практичность на уровне Skoda Octavia

Ghidravoid FUN_0061efb8(void) { undefined *puVar1; int iVar2; int iVar3; undefined4 *in_FS_OFFSET; undefined4 uStack_2c; undefined *puStack_28; undefined *puStack_24; int local_14; undefined local_10; undefined4 local_c [2]; puStack_24 = &stack0xfffffffc; local_c[0] = 0; puStack_28 = &LAB_0061f0de; uStack_2c = *in_FS_OFFSET; *in_FS_OFFSET = &uStack_2c; if (*gvar_00685734 == ‘’) { iVar3 = 0; puStack_24 = &stack0xfffffffc; do { iVar2 = FUN_005054a9(); if (iVar2 != 0) { iVar2 = FUN_005054a9(); } if (iVar2 != 0) { if (iVar2 == 7) { iVar3 = MessageDlgPosHelp(*(undefined4 *) (PTR_PTR_u_The_license_information_file_cou_0068570c + (uint)(byte)*gvar_00685658 * 0x38 + 0x18),1,0×28,0,0xffffffff , 0xffffffff,0); } else { local_10 = 0; local_14 = iVar2; Format(*(undefined4 *) (PTR_PTR_u_The_license_information_file_cou_0068570c + (uint)(byte)*gvar_00685658 * 0x38 + 0x20),&local_14,0,local_c); iVar3 = MessageDlgPosHelp(local_c[0],1,4,0,0xffffffff,0xffffffff,0); } } } while (((iVar2 != 0) && (iVar3 != 2)) && (iVar3 != 1)); FUN_005055e9(); } puVar1 = puStack_24; *in_FS_OFFSET = uStack_2c; puStack_24 = &LAB_0061f0e5; puStack_28 = (undefined *)0x61f0dd; @UStrClr(local_c,uStack_2c,puVar1); return; }

Думаю, уже сразу видно, что идет вновь проверка на лицензию. В IDR можно экспортировать весь проект через File -> Save Delphi Project, что мы и сделаем. Откроем поиск по файлам в Notepad++ и поищем все вхождения данной функции:

«Отучаем» WinFXNet от жадности (часть 1)

10 раз используется данная функция в обработках различных кнопок на форме TMainForm

Продолжаем дальше в x32dbg — переходим по адресам, nop’им вызов функции и для процедуры открытия меняем переход с jne на je (иначе там по условию закроется приложение).

На этом всё — рабочий вариант программы без требования HASP ключа у нас есть. Осталось только разобраться с генерацией лицензии на программу, на что влиияет серийный номер, как программа понимает, какие функции по этой лицензии доступны. Это оставлю на вторую часть, если доделаю (или дадут доделать), то напишу. Но а пока (в виде бонуса) для понимания генерации лицензии посмотрим, как идет расшифровка файла лицензии внутри программы.

Файл лицензии

Первым делом посмотрим через HEX редактор сам файл:

HEX lic

«Отучаем» WinFXNet от жадности (часть 1)

Файл размером 512 байт, из которых первые 127 — это нормальный текст, остальное — непонятный набор байт. Помните, текстом выше, я говорил про функцию OpenDialog — вот на неё можно поставить брейкпоинт, но я сделал хитрее. Прогоняем первый раз цикл с открыванием файла, выйдет окно, что лицензия доступна ещё N дней и предложит продолжить, либо открыть другой файл. В это время мы в x32dbg смотрим вызов стека и смотрим по строкам, где у нас считался файл в память. По этому адресу в дампе ставим брейкпоинт на чтение/запись и возвращаемся к программе. Вновь выбираем файл, жмем открыть и попадаем на наш брейкпоинт. Функция, отвечающая за расшифровку файла из памяти, является FUN_00595d28.

Assambler 00595D28 push ebx 00595D29 push esi 00595D2A mov esi,edx 00595D2C movzx edx,byte ptr [esi+80] 00595D33 mov cl,7E 00595D35 lea eax,[esi+82] 00595D3B movzx ebx,dl 00595D3E movzx ebx,byte ptr [esi+ebx] 00595D42 not bl 00595D44 sub byte ptr [eax],bl 00595D46 inc edx 00595D47 and dl,7F 00595D4A inc eax 00595D4B dec cl >00595D4D jne 00595D3B 00595D4F mov al,1 00595D51 pop esi 00595D52 pop ebx 00595D53 ret

Ghidra undefined4 FUN_00595d28(undefined4 param_1,int param_2) { char *pcVar1; char cVar2; byte bVar3; bVar3 = *(byte *)(param_2 + 0x80); cVar2 = ‘~’; pcVar1 = (char *)(param_2 + 0x82); do { *pcVar1 = *pcVar1 — ~*(byte *)(param_2 + (uint)bVar3); bVar3 = bVar3 + 1 & 0x7f; pcVar1 = pcVar1 + 1; cVar2 = cVar2 + -1; } while (cVar2 != ‘’); return CONCAT31((int3)((uint)pcVar1 >> 8),1); }

IDAchar __fastcall sub_595D28(int a1, int a2) { int v3; // edx char v4; // cl _BYTE *v5; // eax v3 = *(unsigned __int8 *)(a2 + 128); v4 = 126; v5 = (_BYTE *)(a2 + 130); do { *v5 += *(_BYTE *)(a2 + (unsigned __int8)v3++) + 1; LOBYTE(v3) = v3 & 0x7F; ++v5; —v4; } while ( v4 ); return 1; }

Чтобы понять, что происходит, лучше просто в пошаговой отладке посмотреть, что происходит с регистрами и областью памяти, где находится загруженный файл лицензии:

x32dbg

Смотрим за значением регистра EDX — начинается с 0000060, доходит до 7E, обнуляется (после and dl,7F ) и дальше до 5D и происходит выход из цикла. То есть первые 127 байт в файле лицензии не что иное, как кодовое слово для кодирования, просто счет начинается со смещения [esi+80] , доходит до конца фразы, возвращается с самого начала и до предпоследнего символа, откуда начинался счет. Гениально и просто. Осталось только провернуть фарш назад и получится генератор лицензии.

Итог

Очень везёт, что программа ничем не запакована, средств антиотладки почти нет (я увидел только один момент). В целом, если дальше разобраться со структурой HASP, то можно сделать эмулятор ключа, но для этого физически нужно иметь ключ на первом этапе хотя бы. Ну а про лицензию для ПО и остальное нужно разбираться дальше, как описал выше алгоритм расшифровки несложный, надо только перенести его на простой язык программирования.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста. Выпускать вторую часть? 93.94% Да 93 5.05% Нет 5 1.01% На данном этапе функционала программы хватает 1 Проголосовали 99 пользователей. Воздержались 7 пользователей. Теги:

  • реверсинг
  • реверс-инжиниринг для новичков
  • реверс-инжиниринг
  • x32dbg
  • x64dbg
  • ghidra
  • idr
  • ida pro
  • импортозамещение

Хабы:

  • Assembler
  • Delphi
  • Отладка
  • Реверс-инжиниринг

Источник

Каталог товаров с купонами и промокодами онлайн

Оставьте ответ

Ваш электронный адрес не будет опубликован.

©Купоно-Мания.ру