“Weaning” WinFXNet from greed (part 1)

In the first part of this article, we will quickly go through the process of how I looked for functions that prevent the program from starting.

For research we will need the following utilities:

  • Detect It Easy (DiE) (github) – file type detector.

  • Ghidra (github) or IDA/Binary Ninja – a disassembler of your choice.

  • x64dbg (github) or any debugger you like.

  • Interactive Delphi Reconstructor (IDR) (github) – interactive decompiler for Delphi.

  • Dhrake (github) – a set of scripts for Ghidr, tailored for Delphi after IDR.

  • The program itself – there is no installer anywhere on the Internet, so I uploaded it to github – I hope the file will live for some time.

We start by determining what the program is written in (from the tags and list of utilities, I think you already guessed):

Delphi 2010

Delphi 2010

Great, the old version of Delphi is from 2010 – that means IDR will decipher the forms freely. DiE also tells us that protection with NetHASP/Hardlock dongle is used.

Download IDR, unpack archives with binary stamps and analyze our exe file. We wait for the analysis to complete and select “Tools -> IDC generator” in the menu item:

IDC generator

IDC generator

The resulting file will have the following structure:

Generated idc file

Generated idc file

This file needs to be slightly edited – IDR generates long lines through the line separator, which is why IDA and other scripts will swear. Therefore, the resulting spaces and line breaks must be removed and everything turned into one line

Examples of lines in idc where you need to correct

Examples of lines in idc where you need to correct

Then we apply the generated IDC script: in IDA Pro, click File → Script File…, select the script and wait for application:

IDA
Or through View -> Recent scripts we select previously launched scripts” title=”Or through View -> Recent scripts we select previously launched scripts” width=”1705″ height=”1064″ data-src=”https://habrastorage.org/getpro/habr/upload_files/632/7f0/6cb/6327f06cbb9a46d662f424f8cfcf2c51.png”/></p><p><figcaption>Or through View -> Recent scripts we select previously launched scripts</figcaption></p></figure><figure class=Don’t forget to specify the Delphi compiler in IDA’s Options → Compiler menu (the default is C).

Don’t forget to specify the Delphi compiler in IDA’s Options → Compiler menu (the default is C).

In Ghidra we will execute scripts from the Dhrake set:

Ghidra
Before starting, you need to put it in the right place.  Places can be viewed through Script Directories

Before starting, you need to put it in the right place. Places can be viewed through Script Directories

I'll put it in USER_HOME/ghidra_scripts

I’ll put it in USER_HOME/ghidra_scripts

We do everything as written on Github – execute DhrakeInit.java, indicate where our idc file is located, and wait for the script to complete its work.

Great, now the disassembler understands our functions and we don’t have to search for or edit anything manually. Sometimes it happens that functions have incorrect boundaries, but you can correct this yourself.

Let’s return to IDR, which by the way indicated for us a starting function with a simple name EntryPoint. IDR can try to recreate the source code for this function for us by pressing the Src key:

The program will most likely swear, but an approximate description of the assembler functions has been translated into Delphi code:

Looks readable

Looks readable

So, when the program starts, the TStartUpForm form opens – an excellent name for the form, it directly conveys the essence of its purpose. In IDR, open the Forms tab, find our form and see what’s what:

We will need a function to open the OpenDialog dialog box, but that will come a little later.

We will need a function to open the OpenDialog dialog box, but that will come a little later.

For now, let’s return to the code above and see what the disassemblers generated for the EntryPoint function:

IDA
void __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 == '\0') 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;
}

Here you can choose as you like (I think Hydra gave it more clearly), but the essence is the same for everyone – we look at the execution of the function FUN_005966b8.

IDA
void __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;
}
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,0x28);
    }
  } 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 == '\0') {
        cVar3 = FileExists(unaff_ESI);
        if (cVar3 == '\0') {
          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 == '\0') {
            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 == '\0') {
            bVar1 = false;
          }
          else {
            cVar3 = DirectoryExists(unaff_EDI);
            if (cVar3 == '\0') {
              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 == '\0') {
            bVar1 = false;
          }
          else {
            cVar3 = DirectoryExists(unaff_EDI);
            if (cVar3 == '\0') {
              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;
}

We see a call to the function FUN_00590cdc, which, depending on the return value, will allow us to run the program further or not. Based on the loop condition, if we comment out the call to this function and change the condition to check equality, then everything should go further. Let’s try – open x32dbg, load the executable, go to address 005966f2 (we got this address from the same hydra):

x32dbg
Right-click in the CPU field and select Go -> Expression” title=”Right-click in the CPU field and select Go -> Expression” width=”1003″ height=”975″ data-src=”https://habrastorage.org/getpro/habr/upload_files/90f/a6d/892/90fa6d8929173fa1c74a97ed4b9819e8.png”/></p><p><figcaption>Right-click in the CPU field and select Go -> Expression</figcaption></p></figure><figure class=We enter our address and click OK.  Using F2 we set a breakpoint, but at a higher address.

We enter our address and click OK. Using F2 we set a breakpoint, but at a higher address.

I replace the call to this function with mov eax, 0x0 and I see that this comes out:

x32dbg
Right-click on the address and select Assemble

Right-click on the address and select Assemble

Great! We have reached the point of selecting a software license file. We have a valid license file (unlike a HASP key), so I specify it and it will appear in the open folder on the video (\AppData\Local\Schneider Electric\WinFXNet).

Let’s continue to clean the program from hidden key checks. Let’s return to IDR. Let’s open the main form and look at the elements:

TMainForm

TMainForm

The clever name of the timer catches your eye – LicTimer, which has a function call call 0061EFB8. Let’s see what’s inside:

Ghidra
void 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 == '\0') {
    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,0x28,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;
}

I think it’s immediately obvious that the license is being checked again. In IDR you can export the entire project via File -> Save Delphi Project, which is what we will do. Let’s open a file search in Notepad++ and look for all occurrences of this function:

This function is used 10 times in processing various buttons on the TMainForm form

This function is used 10 times in processing various buttons on the TMainForm form

We continue further in x32dbg – we go to the addresses, nop’em call the function and for the opening procedure we change the transition from jne to je (otherwise the application will close there according to the condition).

That’s all – we have a working version of the program without requiring a HASP key. All that remains is to figure out how to generate a license for the program, what the serial number affects, and how the program understands what functions are available under this license. I’ll leave this for the second part, if I finish it (or are allowed to finish it), I’ll write it. But for now (as a bonus) to understand license generation, let’s see how the license file is decrypted inside the program.

License file

First of all, let’s look at the file itself using the HEX editor:

HEX lic

The file is 512 bytes in size, of which the first 127 are normal text, the rest is an incomprehensible set of bytes. Remember, in the text above, I talked about the OpenDialog function – you can put a breakpoint on it, but I did it more cleverly. We run the cycle with opening the file for the first time, a window will appear that the license is available for another N days and will offer to continue or open another file. At this time, in x32dbg we look at the stack call and look at the lines where we read the file into memory. At this address in the dump we set a read/write breakpoint and return to the program. Select the file again, click open and get to our breakpoint. The function responsible for decrypting the file from memory is FUN_00595d28.

Assembler
 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 != '\0');
  return CONCAT31((int3)((uint)pcVar1 >> 8),1);
}
IDA
char __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;
}

To understand what is happening, it is better to simply step-by-step debugging to see what is happening with the registers and the memory area where the loaded license file is located:

x32dbg

We look at the value of the EDX register – it starts from 0000060, reaches 7E, resets to zero (after and dl,7F ) and further to 5D and the cycle exits. That is, the first 127 bytes in the license file are nothing more than a code word for encoding, just counting starts at the offset [esi+80] , reaches the end of the phrase, returns from the very beginning and to the penultimate character, where the counting began. Brilliant and simple. All you have to do is turn the stuffing backwards and you will get a license generator.

Bottom line

I’m very lucky that the program is not packaged with anything, there are almost no anti-debugging tools (I saw only one thing). In general, if you further understand the HASP structure, you can make a key emulator, but for this you physically need to have a key at least at the first stage. Well, we need to understand further about the license for the software and the rest, as the decryption algorithm described above is simple, you just need to transfer it to a simple programming language.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *