WinAntiDbg0x100

Published: April 3, 2024

Description

A Windows console binary detects debuggers via IsDebuggerPresent and refuses to show the flag if a debugger is attached. By intercepting the anti-debug check in x64dbg and skipping the alert path, you can read the embedded flag string.

This is a gentle intro to anti-debug bypass: find the check, break on it, and set EIP past the failure branch so execution continues as if no debugger was detected.

Windows & x64dbg

Download WinAntiDbg0x100.zip (password: picoctf) and extract the executable.

Open WinAntiDbg0x100.exe inside x64dbg (32-bit).

wget https://artifacts.picoctf.net/c_titan/84/WinAntiDbg0x100.zip && \
unzip WinAntiDbg0x100.zip

Solution

This is the first challenge in the WinAntiDbg series. WinAntiDbg0x200 and WinAntiDbg0x300 introduce progressively more advanced anti-debug techniques.
  1. Step 1Locate IsDebuggerPresent
    In x64dbg, use View → Symbol Info → search for IsDebuggerPresent. Double-click it and set a breakpoint so execution halts at the anti-debug call.
    Learn more

    IsDebuggerPresent is a Windows API function (in kernel32.dll) that returns non-zero if the calling process has a debugger attached. It works by reading a flag in the Process Environment Block (PEB) - a kernel data structure describing the process - specifically the BeingDebugged byte at offset 0x2.

    This is the most basic and most well-known anti-debug technique. Malware uses it to detect analysis environments and either crash, behave differently, or decrypt themselves only when no debugger is present. Hundreds of documented anti-debug tricks exist, ranging from simple API calls to timing attacks, exception handling abuse, and hardware register manipulation.

    • x64dbg is a free, open-source Windows debugger for 32-bit and 64-bit executables - the modern replacement for OllyDbg.
    • Symbol resolution lets you set breakpoints by API name rather than memory address, which is crucial since addresses change between runs (ASLR).
    • The 32-bit version (x32dbg) is required for 32-bit binaries like this one.
  2. Step 2Step past the check
    Run until the breakpoint hits, then Step Into to reach the ret instruction. Set EIP to the branch that executes when no debugger is present (address FA161B in the provided build).
    Learn more

    EIP(Extended Instruction Pointer) is the x86 register that holds the address of the next instruction to execute. By directly setting EIP to a different address in x64dbg (right-click the address in the disassembly view and choose "Set EIP here"), you force execution to skip the conditional branch that would otherwise terminate the program.

    This technique - manually redirecting execution past an anti-debug check - is called an EIP redirect or jump patch. A more permanent approach is to NOP out the conditional jump instruction (replace it with 90 bytes), which makes the bypass survive multiple runs without needing to reset EIP each time.

    The ret instruction returns from the current function by popping the return address from the stack into EIP. Setting EIP just after the ret of IsDebuggerPresent means the check runs but its result is never used - execution flows directly to the non-debugger code path.

  3. Step 3Continue to the flag
    Step over the subsequent instructions. The MOV eax, dword ptr ds:[FA5408] line reveals the flag string; copy it from memory to retrieve picoCTF{...}.
    Learn more

    Once the anti-debug check is bypassed, the program executes its "no debugger" code path, which reads and displays the flag. The MOV eax, dword ptr ds:[FA5408] instruction loads the flag's memory address into the eax register. In x64dbg, you can right-click this instruction and follow the address in the memory dump or string dump to see the flag content.

    Embedded strings in executables are stored in the binary's data segment (.data or .rdata section). Even without running the program, strings on the executable often reveals flag-like content - though anti-debug challenges sometimes encrypt the flag and decrypt it only at runtime, making dynamic analysis (actually running with a debugger) the only viable approach.

    The WinAntiDbg series progressively introduces more sophisticated techniques: this level uses the simple API call; later levels use timing-based detection, exception handler checks, and parent process inspection - techniques that require more creative bypasses than a simple EIP redirect.

Flag

picoCTF{d3bug_f0r_th3_Win_0x100_e7...}

Skipping the failure branch reveals the stored flag string immediately.

Want more picoCTF 2024 writeups?

Useful tools for Reverse Engineering

Related reading

What to try next