WinAntiDbg0x300

Deskripsi

Walkthrough

Diberikan sebuah file zip yang berisi 3 file berikut:

Ketika file WinAntiDbg0x300.exe dijalankan, maka akan menghasilkan output berikut:

Dari deskripsi tersebut bisa diketahui bahwa flag bisa diperoleh dengan menjalankan program ini di debugger.

Seperti biasanya, sebelum melakukan analisis lebih dalam, saya mengecek terlebih dahulu kumpulan string yang ada di program ini dengan perintah: strings WinAntiDbg0x300.exe untuk menemukan flagnya.

Setelah mencari menggunakan grep dan ekplorasi manual dengan ltrace, strace, dan strings, saya tetap tidak menemukan flagnya. Tetapi, saya menemukan bahwa program ini dikompresi dengan UPX, sebuah packer yang digunakan untuk memperkecil ukuran program atau “menyembunyikan” bagian kode aplikasi dari analisis awal di reverse engineering.

Dekompresi Program

Untuk melakukan dekompresi UPX ini sangatlah mudah, saya hanya perlu mendownload UPX dari GitHub dan menjalankan perintah:

upx -d WinAntiDbg0x300.exe -o WinAntiDbg0x300_unpacked.exe

Setelah melakukan dekompresi, saya kemudian mengecek kembali kumpulan string yang ada di program ini dengan strings, strace, dan ltrace. Namun, tetap saja tidak menemukan flagnya dengan cara ini.

Analisis Statik

Setelah langkah awal tidak memberikan hasil, saya kemudian melakukan analisis statik lanjutan dengan Ghidra.

Jika kalian ingin mempelajari cara menggunakan Ghidra, bisa lihat tutorial ini.

Di bawah ini adalah tampilan awal ketika program hasil dekompresi dibuka di Ghidra.

Di window sebelah kiri paling atas berisi struktur segmentasi dari program yang sedang dianalisis. Ini merepresentasikan layout memori dari file binari. Di window dengan garis warna hijau berisi daftar dependensi yang digunakan oleh file binari. Sedangkan di kotak warna biru adalah daftar fungsi internal yang ditemukan dalam file binari.

Karena ada terlalu banyak fungsi lokal dan saya malas untuk mengecek isi dari setiap fungsi satu persatu :), jadi saya langsung mencoba untuk mencari flagnya melalui fitur Program Text.

Saya tidak menemukan flag aslinya dari hasil search text ini. Namun, saya menemukan sejumlah string berisi pesan untuk menampilkan flagnya.

Saya kemudian langsung mengecek lokasi di mana string flag ini pertama kali ditemukan, ternyata berada di lokasi 0040392b. Dan setelah menuju ke lokasi tersebut, muncul hasil dekompilasi kode berikut:


/* WARNING: Removing unreachable block (ram,0x004038e0) */
/* WARNING: Removing unreachable block (ram,0x00403911) */
/* WARNING: Removing unreachable block (ram,0x00403929) */

undefined4 FUN_00403740(void)

{
  WCHAR local_384 [260];
  CHAR local_17c [272];
  _STARTUPINFOA local_6c;
  BOOL local_24;
  DWORD local_20;
  _PROCESS_INFORMATION local_1c;
  DWORD local_8;
  
  memset(&local_6c,0,0x44);
  local_6c.cb = 0x44;
  local_1c.hProcess = (HANDLE)0x0;
  local_1c.hThread = (HANDLE)0x0;
  local_1c.dwProcessId = 0;
  local_1c.dwThreadId = 0;
  local_8 = 0;
  local_20 = GetCurrentProcessId();
  GetModuleFileNameW((HMODULE)0x0,local_384,0x104);
  thunk_FUN_00403e50(local_17c,0x110,"%ws %d",(char)local_384);
  thunk_FUN_00402bc0(2);
  do {
    local_24 = CreateProcessA((LPCSTR)0x0,local_17c,(LPSECURITY_ATTRIBUTES)0x0,
                              (LPSECURITY_ATTRIBUTES)0x0,0,0,(LPVOID)0x0,(LPCSTR)0x0,&local_6c,
                              &local_1c);
    if (local_24 == 0) {
      MessageBoxW(DAT_0040c704,
                  L"[FATAL ERROR]  Unable to create the child process. Challenge aborted.",
                  (LPCWSTR)&lpWindowName_0040c3e0,0x10);
      thunk_FUN_00402e00(0xff);
    }
    WaitForSingleObject(local_1c.hProcess,0xffffffff);
    GetExitCodeProcess(local_1c.hProcess,&local_8);
    if (local_8 == 0xff) {
      MessageBoxW(DAT_0040c704,L"Something went wrong. Challenge aborted.",
                  (LPCWSTR)&lpWindowName_0040c3e0,0x10);
      thunk_FUN_00402e00(0xff);
    }
    else if (local_8 == 0xfe) {
      MessageBoxW(DAT_0040c704,
                  L"The debugger was detected but our process wasn\'t able to fight it. Challenge ab orted."
                  ,(LPCWSTR)&lpWindowName_0040c3e0,0x10);
      thunk_FUN_00402e00(0xff);
    }
    else if (local_8 == 0xfd) {
      MessageBoxW(DAT_0040c704,
                  L"Our process detected the debugger and was able to fight it. Don\'t be surprised if the debugger crashed."
                  ,(LPCWSTR)&lpWindowName_0040c3e0,0x10);
    }
    CloseHandle(local_1c.hProcess);
    CloseHandle(local_1c.hThread);
    Sleep(5000);
  } while( true );
}

Setelah mengecek kode hasil dekompilasi tersebut, ternyata di sana tidak berisi fungsi untuk men-trigger flagnya. Namun, jika dilihat kembali, terdapat dua fungsi yang dieksekusi di awal sebelum perintah looping Do While, yaitu thunk_FUN_00403e50 dan thunk_FUN_00402bc0

Namun, setelah mengecek kedua fungsi tersebut dan tidak menemukan clue yang jelas untuk mendapatkan flagnya, saya kemudian melihat flow fungsi FUN_00403740 melalui graph.

Dan jika mengikuti flow graph di sebelah kiri, yaitu fungsi LAB_004038e0 dan melihat isinya, bisa dilihat bahwa fungsi inilah yang sebenarnya akan menampilkan flagnya.

Patching

Setelah mengetahui flow untuk mendapatkan flag, kemudian langkah selanjutnya adalah saya perlu memanipulasi flow program ini untuk mendapatkan flagnya.

Supaya fungsi LAB_004038e0 dieksekusi dan selanjutnya akan mengeksekusi LAB_00403929 (flag), maka saya perlu memanipulasi hasil dari instruksi TEST EAX, EAX di fungsi LAB_004037c0 supaya instruksi JZ LAB_004038e0 dieksekusi dan melompat ke arah flow sebelah kiri yang menuju ke fungsi yang men-trigger flag (LAB_00403929).

Di sini, terdapat instruksi TEST EAX, EAX yang melakukan operasi bitwise AND pada EAX, dan dilanjutkan eksekusi instruksi JZ LAB_004038e0 yang akan melakukan lompatan ke fungsi LAB_004038e0 jika hasil TEST EAX, EAX adalah 0.

Karena TEST EAX, EAX akan selalu menghasilkan output 1, maka instruksi JZ LAB_004038e0 tidak akan pernah dieksekusi, dan program akan melanjutkan ke instruksi di flow graph sebelah kanan (looping do while), yang artinya fungsi untuk men-trigger flag (flow sebelah kiri) tidak akan pernah dieksekusi.

Supaya flow di sebelah kiri dieksekui, maka saya perlu memanipulai flow instruksi di fungsi ini supaya instruksi JZ LAB_004038e0 dieksekusi. Dan untuk melakukan ini sangatlah mudah, saya hanya perlu mengubah instruksi JZ (Jump Zero) dengan JNZ (Jump Not Zero) melalui Patch Instruction:

Dan setelah berhasil melakukan patching instruksi dari JZ ke JNZ, maka hasil dekompilasi dari fungsi yang men-trigger flag akan tampil secara otomatis di window dekompilasi kode:

Kemudian langkah selanjutnya adalah mengeksport hasil patching dan menjalankan programnya.

Dan saat program hasil patching dijalankan, maka flag akan secara otomatis muncul dalam bentuk pop up alert window.

Last updated

Was this helpful?