İnek Şaban Crackme

DATE: 2026-05-14TARGET: İnek Şaban Crackme

1. Initial Inspection and Static Analysis

I began by dumping readable strings from the file with the standard strings command.

strings crackme1


Figure 1: strings output

The output openly contained the string FLAG{Tebrikler_Dogru_Flag}. I also found no success or failure messages such as congratulations or an incorrect-flag warning. A flag this conspicuous suggested a possible rabbit hole.

2. Dynamic Analysis and Anti-Debugging Findings

To test that suspicion, I ran the file under GDB (GNU Debugger) and also attempted to trace its dynamic-library calls with ltrace.


Figure 2: Fake flag

When launched in GDB, the program requested a flag. Entering FLAG{Tebrikler_Dogru_Flag} from the strings output produced the message Tunelin ucu :) https://www.youtube.com/watch?v=3ksNL9uJssw. The linked Kemal Sunal film scene mockingly confirmed that this was indeed a trap. In addition, the SIGTRAP interrupt raised while the program was running in GDB demonstrated the presence of an intentional anti-debugging mechanism and showed that debugger detection had redirected execution into a fake path. I moved to Ghidra to recover the actual flag.


Figure 3: The tunnel led somewhere unpleasant

3. Ghidra and Algorithm Analysis

After loading and decompiling the file in Ghidra, the protection mechanisms became clear. I located the entry point and followed it into the next function, where the welcome message and related logic identified the body of main.

  signal(5,FUN_001011bc);
  FUN_00101159("=== Trackbook Crackme 1 ===\n");
  FUN_00101159("Lutfen flag giriniz: ");
  FUN_00101199(local_98,0x3f);
  local_fc = 0;
  do {
    if (0x3f < local_fc) {
LAB_001015c8:
      pcVar1 = (code *)swi(3);
      (*pcVar1)();
      return;
// Ghidra decompile işlemini burada kesti!

Protection 1: Exception-Based Control Flow

The program registered a SIGTRAP handler with signal(5, ...), then immediately invoked swi(3), whose assembly equivalent is the INT 3 interrupt.

Repairing the Decompiler with NOP Patching

When Ghidra encountered the INT 3 instruction, it assumed that control flow ended there and did not decompile the actual validation blocks. I patched the assembly to expose the remaining code.

Original Assembly Flow:

        001015bd 7e 09           jle        LAB_001015c8
        001015bf 8b 45 fc        mov        eax,dword ptr [rbp + local_fc]
        ...
                             LAB_001015c8
        001015c8 cc              INT        3  ; Breakpoint

I replaced the CC opcode with 90:

Patched Assembly Flow:

                             LAB_001015c8
        001015c8 90              NOP        ; Ghidra artık buraan sonra devam edicek

Ghidra then reanalyzed the function and revealed the real validation block after the interrupt. The updated decompilation showed that the application branched on the state variable. Following the hidden function call in the legitimate path led to FUN_001012fe and FUN_001011d0.

    if (0x3f < local_fc) {
code_r0x001015c9:
      if (_DAT_0010402c == 1) {
        iVar1 = FUN_001012fe(local_98);
        if (iVar1 == 0) {
          FUN_001011d0(&local_f8,0x13);
        }
        else {
          FUN_001011d0(&local_58,0x42);
        }
      }
      else {
        iVar1 = strcmp(local_98,"FLAG{Tebrikler_Dogru_Flag}");
        if (iVar1 == 0) {
          FUN_001011d0(&local_d8,0x3d);
        }
        else {
          FUN_001011d0(&local_f8,0x13);
        }
      }

4. String Obfuscation (XOR) and Flag Recovery

Inside the real validation function (FUN_001012fe), which executes when no debugger is detected, the actual flag was not stored in plaintext.

Protection 2: In-Memory XOR Obfuscation

The decompiled C code was as follows:

  local_28[0] = 0x7c;
  local_28[1] = 0x6b;
  //diğer byte lar
  local_28[0xf] = 0x4c;
  local_30 = 0;
  
  do {
    //uzunluk ve güvenlik kontrolü
    if ((int)(char)(*(byte *)(param_1 + local_30) ^ 0x31) != (uint)local_28[local_30]) {
      uVar1 = 0;
      goto LAB_0010139f; //hatalı flag
    }
    local_30 = local_30 + 1;
  } while( true );

The program XORed each character of the user’s input with the 0x31 key and compared the result against a statically embedded encrypted hexadecimal array. I also determined that displayed messages were decrypted at runtime with the 0x55 key before being printed.

void FUN_001011d0(long param_1,int param_2)
{
  long in_FS_OFFSET;
  int local_9c;
  byte local_98 [136];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  
  //local_98 buffer'ının 0 ile doldurulduğu kısımlar]
  
  for (local_9c = 0; local_9c < param_2; local_9c = local_9c + 1) {
    local_98[local_9c] = *(byte *)(param_1 + local_9c) ^ 0x55;
  }
  local_98[param_2] = 0;
  FUN_00101159(local_98); //Şifresi çözülen metnin ekrana basılması
  
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
    __stack_chk_fail();
  }
  return;
}

I recovered the real flag by applying XOR with the 0x31 key to the extracted static hexadecimal array in CyberChef:


Figure 3: Real flag

Decrypted Real Flag: MZVY{Inek_Saban}

5. Verification

To verify the recovered flag, I ran the program through the normal terminal flow without a debugger.


Figure 5: Verification of the real flag

I accept the creator’s approval and take my seat. :)


Figure 6: Well done, Şaban