Simple Reverse 0x30(2023 HW - Baby Ransom 1)

Simple Reverse 0x30(2023 HW - Baby Ransom 1)

Background

Source code

  • IDA Main Function
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
    
      StackBase = NtCurrentTeb()->NtTib.StackBase;
      while ( 1 )
      {
        DestInitValue = _InterlockedCompareExchange64(&qword_140017050, StackBase, 0i64);
        if ( !DestInitValue )
        {
          v5 = 0;
          goto LABEL_7;
        }
        if ( StackBase == DestInitValue )
          break;
        Sleep(1000u);
      }
      v5 = 1;
    LABEL_7:
      if ( unk_140017058 == 1 )
      {
        amsg_exit(31i64);
      }
      else if ( unk_140017058 )
      {
        dword_140017008 = 1;
      }
      else
      {
        unk_140017058 = 1;
        initterm(&qword_140019018, qword_140019028);
      }
      if ( unk_140017058 == 1 )
      {
        initterm(&qword_140019000, &qword_140019010);
        unk_140017058 = 2;
      }
      if ( !v5 )
        _InterlockedExchange64(&qword_140017050, 0i64);
      if ( TlsCallback_0 )
        TlsCallback_0(0i64, 2);
      sub_14000226B();
      v6 = 0i64;
      qword_1400170E0 = SetUnhandledExceptionFilter(&loc_140002530);
      (InterlockedExchange64)(nullsub_1);
      InitFloatUnit();
      v7 = dword_140017028;
      space = malloc(8i64 * (dword_140017028 + 1));
      v9 = qword_140017020;
      space_cp = space;
      while ( v7 > v6 )
      {
        size = strlen(*(v9 + 8 * v6)) + 1;
        dest = malloc(size);
        *(space_cp + 8 * v6) = dest;
        src = *(v9 + 8 * v6++);
        qmemcpy(dest, src, size);
      }
      qword_140017020 = space_cp;
      if ( v7 < 0 )
        v7 = 0i64;
      *(space_cp + 8 * v7) = 0i64;
      sub_140001F1E();
      _initenv = qword_140017018;
      dword_140017010 = (NetworkConfig_1DBB)(dword_140017028, qword_140017020);// 0x140017020 => 0x254CA9C1580
      if ( !dword_14001700C )
        exit(dword_140017010);
      if ( !dword_140017008 )
        cexit();
      return dword_140017010;
    }
    
  • IDA NetworkConfig_1DBB
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    __int64 NetworkConfig_1DBB()
    {
      void *hInternet; // [rsp+38h] [rbp-18h]
    
      sub_140001F1E();
      hInternet = InternetOpenA(0i64, 1u, 0i64, 0i64, 0);
      if ( InternetOpenUrlA(hInternet, (LPCSTR)szUrl, 0i64, 0, 0x84000000, 0i64) )// INTERNET_FLAG_RELOAD + INTERNET_FLAG_NO_CACHE_WRITE
                                                    // => retrieve the orginal item
                                                    // => don't write this item to the cache
        return 0i64;
      else
        return Reverse_URL_Part1();
    }
    
  • IDA Reverse_URL_Part1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    __int64 Reverse_URL_Part1()
    {
      PWSTR ppszPathOut; // [rsp+38h] [rbp-38h] BYREF
      int char_1; // [rsp+44h] [rbp-2Ch]
      PWSTR ppszPath; // [rsp+48h] [rbp-28h] BYREF
      LPWSTR lpFilename; // [rsp+50h] [rbp-20h]
      LPWSTR lpWideCharStr; // [rsp+58h] [rbp-18h]
      int cchWideChar; // [rsp+64h] [rbp-Ch]
      int j; // [rsp+68h] [rbp-8h]
      int i; // [rsp+6Ch] [rbp-4h]
    
      if ( SHGetKnownFolderPath((const KNOWNFOLDERID *const)&unk_14000AA80, KF_FLAG_DEFAULT, 0i64, &ppszPath) )
        return 0i64;
      for ( i = 7; i <= 22; i += 4 )
      {
        char_1 = *(_DWORD *)((char *)szUrl + i);
        for ( j = 0; j <= 3; ++j )
        {
          LOBYTE(char_1) = char_1 - 43;
          char_1 = __ROR4__(char_1, 8);
        }
        char_1 ^= 0x6F6F6F6Fu;
        *(_DWORD *)((char *)szUrl + i) = char_1;
      }
      HIBYTE(szUrl[2]) = 0;
      cchWideChar = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)szUrl + 7, -1, 0i64, 0);
      if ( !cchWideChar )
        return 0i64;
      lpWideCharStr = (LPWSTR)malloc(2i64 * cchWideChar);
      if ( !lpWideCharStr )
        return 0i64;
      MultiByteToWideChar(CP_UTF8, 0, (LPCCH)szUrl + 7, -1, lpWideCharStr, cchWideChar);
      if ( PathAllocCombine(ppszPath, lpWideCharStr, PATHCCH_NONE, &ppszPathOut) )
      {
        free(lpWideCharStr);
        return 0i64;
      }
      else
      {
        CreateDirectoryW(ppszPathOut, 0i64);
        SetFileAttributesW(ppszPathOut, 0x26u);     // FILE_ATTRIBUTE_ARCHIVE + FILE_ATTRIBUTE_SYSTEM + FILE_ATTRIBUTE_HIDDEN
        lpFilename = (LPWSTR)malloc(0x208ui64);
        GetModuleFileNameW(0i64, lpFilename, 0x104u);
        if ( PathAllocCombine(ppszPathOut, lpWideCharStr, 0, &ppszPathOut) )
        {
          free(lpWideCharStr);
          free(lpFilename);
          return 0i64;
        }
        else if ( MoveFileW(lpFilename, ppszPathOut) )
        {
          SetFileAttributesW(ppszPathOut, 0x26u);   // FILE_ATTRIBUTE_ARCHIVE + FILE_ATTRIBUTE_SYSTEM + FILE_ATTRIBUTE_HIDDEN
          free(lpWideCharStr);
          free(lpFilename);
          return Reverse_URL_Part2(ppszPathOut);
        }
        else
        {
          free(lpWideCharStr);
          free(lpFilename);
          ImportatntPart();
          return 0i64;
        }
      }
    }
    
  • IDA NextStagePayload
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void __stdcall NextStagePayload()
    {
      if ( !(unsigned int)off_140007088()           // isDebuggerPresent
        || !*(_QWORD *)(qword_140017030 + 8)
        || strcmp((const char *)(*(_QWORD *)(qword_140017030 + 8) + 9i64), "start!!") )
      {
        Reverse_URL_Part3_getEmbeddedPeFile_();
      }
    }
    
  • IDA Reverse_URL_Part3_getEmbeddedPeFile_
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    void __stdcall Reverse_URL_Part3_getEmbeddedPeFile_()
    {
      __int64 v0; // [rsp+58h] [rbp-28h] BYREF
      __int64 Buffer; // [rsp+60h] [rbp-20h] BYREF
      int v2; // [rsp+6Ch] [rbp-14h]
      struct _PROCESS_INFORMATION ProcessInformation; // [rsp+70h] [rbp-10h] BYREF
      struct _STARTUPINFOA StartupInfo; // [rsp+90h] [rbp+10h] BYREF
      DWORD v5; // [rsp+104h] [rbp+84h] BYREF
      int *v6; // [rsp+108h] [rbp+88h] BYREF
      LPCONTEXT lpContext; // [rsp+110h] [rbp+90h]
      int j; // [rsp+118h] [rbp+98h]
      int i; // [rsp+11Ch] [rbp+9Ch]
    
      getEmbeddedPE_File((LPVOID *)&v6, &v5);
      memset(&StartupInfo, 0, sizeof(StartupInfo));
      StartupInfo.cb = 104;
      memset(&ProcessInformation, 0, sizeof(ProcessInformation));
      for ( i = 121; i <= 124; i += 4 )
      {
        v2 = *(_DWORD *)&szUrl[i];
        for ( j = 0; j <= 3; ++j )
        {
          LOBYTE(v2) = v2 - 80;
          v2 = __ROR4__(v2, 8);
        }
        v2 ^= 0x7E7E7E7Eu;
        *(_DWORD *)&szUrl[i] = v2;
      }
      szUrl[125] = 0;
      CreateProcessA(0i64, &szUrl[121], 0i64, 0i64, 0, 4u, 0i64, 0i64, &StartupInfo, &ProcessInformation);
      lpContext = (LPCONTEXT)VirtualAlloc(0i64, 0x4D0ui64, 0x1000u, 4u);
      lpContext->ContextFlags = 0x10000B;
      if ( GetThreadContext(ProcessInformation.hThread, lpContext) )
      {
        sub_1400013B4(v6, v5, ProcessInformation.hProcess, &Buffer, &v0);
        WriteProcessMemory(ProcessInformation.hProcess, (LPVOID)(lpContext->Rdx + 16), &Buffer, 8ui64, 0i64);
        lpContext->Rcx = v0 + Buffer;
        SetThreadContext(ProcessInformation.hThread, lpContext);
        ResumeThread(ProcessInformation.hThread);
        CloseHandle(ProcessInformation.hProcess);
        CloseHandle(ProcessInformation.hThread);
      }
    }
    
  • IDA getEmbeddedPE_File
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    HRSRC __fastcall getEmbeddedPE_File(LPVOID *pe_file, DWORD *ResourceSize)
    {
      HRSRC result; // rax
      HRSRC hResInfo; // [rsp+30h] [rbp-10h]
      unsigned int i; // [rsp+3Ch] [rbp-4h]
    
      result = FindResourceA(0i64, (LPCSTR)'D', (LPCSTR)0x84);
      hResInfo = result;
      if ( result )
      {
        result = (HRSRC)LoadResource(0i64, result);
        if ( result )
        {
          *pe_file = LockResource(result);
          result = (HRSRC)*pe_file;
          if ( *pe_file )
          {
            *ResourceSize = SizeofResource(0i64, hResInfo);
            result = (HRSRC)*ResourceSize;          // 0x1ca00
            if ( (_DWORD)result )
            {
              for ( i = 0; ; i += 2 )
              {
                result = (HRSRC)*ResourceSize;
                if ( i >= (unsigned int)result )
                  break;
                *(_WORD *)((char *)*pe_file + (int)i) ^= 0x8711u;
              }
            }
          }
        }
      }
      return result;
    }
    

Recon

從source code上到下慢慢解析,這一題很難的地方在於很多東西都是runtime才決定的,包含embedded pe file,或者是一些function pointer,所以只能慢慢跟著動態去猜他的行為

  1. main function中可以直接看到下面一點的地方,上面只是一些初始化,不用管他,真正在import embedded payload或是進行攻擊的地方在下面的NetworkConfig_1DBB
  2. 說是network config其實和網路操作沒啥屁毛關係,只是前期分析的時候看到有InternetOpen相關的API就先這樣寫,再加上他給了一個https開頭的strings,但看了一圈其實只是scramble過後的payload再加上https,所以其實也和連線沒關係。簡單說一下這一段,詳細可以看一下前面MSDN的background,InternetOpenUrlA中帶的0x84000000,我看csdn分析WannaCry的文章表示,是INTERNET_FLAG_RELOAD + INTERNET_FLAG_NO_CACHE_WRITE的結果,也就是從server端拉資料下來,然後不會把結果存到cache中,但這一切我認為都是為了混淆reverse的人,因為InternetOpenUrl會對給予的szUrl進行連線,有成功的話才會進到if-statement,但他永遠不會成功,因為仔細看szUrl其實是http://M17H+G+4FzeJ69F5.*f)vfquhvnv)*fwdhud)*vf)lpktud)*lj)4)*uk)',27h,'Lpfwjvjcu)Rpkejrv)Tyehu',所以直接分析下面的部分就好
  3. 進到part 1的地方先看到一個for loop,那個就是在還原scramble url的部分,還原的結果是Microsoft Update,接著下面會把path combine在一起,並且創一個folder,並設定屬性為FILE_ATTRIBUTE_ARCHIVE + FILE_ATTRIBUTE_SYSTEM + FILE_ATTRIBUTE_HIDDEN,所以必須把file explorer的隱藏系統檔案的選項取消,才看得到 圖片.png 接著下面的nested if statement有點迷,基本上第一次執行一定會直接進到最後的else,因為基本上lpFilename剛創好空間,本身應該沒東西,所以MoveFile當然不會成功,接著就進到最後的ImportantPart
  4. 持續跟進會先進到NextStatePayload,這一段有個小地方可以注意,也就是(unsigned int)off_140007088(),這是個function pointer,主要做的事情就是isDebuggerPresent,所以如果有使用x64dbg的話要記得開Scylla Hide的Anti Anti Debugger,這樣才會進到if statement去取得embedded pe file(雖然就算不設定,第二個判斷式也應該會是true才對) 圖片.png
  5. 終於進到最關鍵的部分了,首先一開始遇到的function其實就是在還原embedded pe file,主要的操作是先取得resource → 00007ff7f219b048 圖片.png 再藉由LoadResource取得真正的resource → 00007ff7f219b058 然後取得該resource的大小 → 0x1ca00

    • 最重要的部分就是每兩個byte都進行XOR 0x8711的動作,直到0x1ca00都做完,這一部分就是解密embedded pe file,解密完可以很明顯看到MD這個magic signature 圖片.png
    • 因此只要利用Scylla把這一部分的memory dump出來再拿去md5 file取得hash就可以了 圖片.png 圖片.png

Flag: FLAG{e6b77096375bcff4c8bc765e599fbbc0}