逆向入門筆記之分析TraceMe.exe

TraceMe.exe是一個示例程序,用於逆向的學習,簡單地模擬了註冊機制。

我們把它拖進IDA中無腦F5一波:

雙擊DialogFunc進入這個函數:

BOOL __stdcall DialogFunc(HWND hWnd, UINT a2, WPARAM a3, LPARAM a4)
{
  int v5; // ebx
  HWND v6; // eax
  HWND v7; // eax
  HWND v8; // eax
  HICON v9; // eax
  CHAR String2[4]; // [esp+8h] [ebp-F4h]
  int v11; // [esp+Ch] [ebp-F0h]
  int v12; // [esp+10h] [ebp-ECh]
  __int16 v13; // [esp+14h] [ebp-E8h]
  char v14; // [esp+16h] [ebp-E6h]
  CHAR v15; // [esp+18h] [ebp-E4h]
  char v16; // [esp+2Eh] [ebp-CEh]
  CHAR v17; // [esp+30h] [ebp-CCh]
  __int16 v18; // [esp+44h] [ebp-B8h]
  char v19; // [esp+46h] [ebp-B6h]
  CHAR String; // [esp+48h] [ebp-B4h]
  CHAR String1; // [esp+98h] [ebp-64h]

  qmemcpy(&v15, byte_405060, 0x16u);
  v11 = dword_405054;
  v16 = byte_405060[22];
  v14 = byte_40505E;
  qmemcpy(&v17, &unk_405038, 0x14u);
  *(_DWORD *)String2 = dword_405050;
  v18 = *((_WORD *)&unk_405038 + 10);
  v13 = word_40505C;
  v12 = dword_405058;
  v19 = *((_BYTE *)&unk_405038 + 22);
  if ( a2 == 16 )
  {
    DestroyWindow(hWnd);
    return 1;
  }
  if ( a2 == 272 )
  {
    v9 = LoadIconA(hInstance, (LPCSTR)0x70);
    SendMessageA(hWnd, 0x80u, 1u, (LPARAM)v9);
    SendDlgItemMessageA(hWnd, 110, 0xC5u, 0x50u, 0);
    return 1;
  }
  if ( a2 != 273 )
    return 0;
  if ( (signed int)(unsigned __int16)a3 > 1013 )
  {
    if ( (unsigned __int16)a3 == 1014 || (unsigned __int16)a3 == 40002 )
      DialogBoxParamA(hInstance, (LPCSTR)0x67, hWnd, sub_401020, 0);
    return 0;
  }
  if ( (unsigned __int16)a3 != 1013 )
  {
    if ( (unsigned __int16)a3 == 2 || (unsigned __int16)a3 == 1002 )
    {
      SendMessageA(hWnd, 0x10u, 0, 0);
      return 0;
    }
    return 0;
  }
  v5 = GetDlgItemTextA(hWnd, 110, &String, 81);
  GetDlgItemTextA(hWnd, 1000, &String1, 101);
  if ( String && v5 >= 5 )
  {
    if ( sub_401340(&String1, &String, v5) )
    {
      lstrcpyA(::String1, String2);
      v6 = GetDlgItem(hWnd, 110);
      EnableWindow(v6, 0);
      v7 = GetDlgItem(hWnd, 1000);
      EnableWindow(v7, 0);
      v8 = GetDlgItem(hWnd, 1000);
    }
    else
    {
      lstrcpyA(::String1, &v17);
      v8 = GetDlgItem(hWnd, 1000);
    }
  }
  else
  {
    lstrcpyA(::String1, &v15);
    v8 = GetDlgItem(hWnd, 110);
  }
  SetFocus(v8);
  MessageBeep(0);
  DialogBoxParamA(hInstance, (LPCSTR)0x79, hWnd, sub_401060, 0);
  return 0;
}

看到第60行:

 v5 = GetDlgItemTextA(hWnd, 110, &String, 81);
  GetDlgItemTextA(hWnd, 1000, &String1, 101);
  if ( String && v5 >= 5 )
  {
    if ( sub_401340(&String1, &String, v5) )
    {
      lstrcpyA(::String1, String2);
      v6 = GetDlgItem(hWnd, 110);
      EnableWindow(v6, 0);
      v7 = GetDlgItem(hWnd, 1000);
      EnableWindow(v7, 0);
      v8 = GetDlgItem(hWnd, 1000);
    }
    else
    {
      lstrcpyA(::String1, &v17);
      v8 = GetDlgItem(hWnd, 1000);
    }
  }

這裏就是程序主要的邏輯:

使用函數GetDlgItemTextA讀取輸入的用戶名和序列號,如果用戶名超長則截取前100位。

然後送入函數sub_401340計算,計算結果是true則驗證通過。

進入sub_401340這個函數看下:

BOOL __cdecl sub_401340(LPCSTR lpString1, LPSTR a2, int a3)
{
  int v3; // ecx
  int v4; // esi
  signed int i; // eax

  v3 = 3;
  v4 = 0;
  for ( i = 0; v3 < a3; ++i )
  {
    if ( i > 7 )
      i = 0;
    v4 += (unsigned __int8)byte_405030[i] * (unsigned __int8)a2[v3++];
  }
  wsprintfA(a2, aLd, v4);
  return lstrcmpA(lpString1, a2) == 0;
}

這就是具體的算法。邏輯大概就是根據傳入的變量lpstring、a2、a3計算序列號,並與用戶輸入的序列號比對。

針對該邏輯,給出python3寫的根據用戶名計算序列號的代碼:

f=[0x0C, 0x0A, 0x13, 0x09, 0x0C, 0x0B, 0x0A, 0x08]
inputs="asdfg"
f2=list(inputs)
a2=[]
for c in f2:
    a2.append(ord(c))
v3=3
v4=0
a3=len(inputs)
i=0
while v3<a3:
 if(i>7): i=0
 fi = f[i]
 a2v3=a2[v3]
 v4+=fi*a2v3
 v3+=1
 i+=1
print(hex(v4))

變量inputs就是輸入的用戶名,這裏我們輸入asdfg,運行這段python代碼,看到輸出註冊碼爲2254:

 

把用戶名和註冊碼輸入進去,看到驗證通過:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章