$ cat writeup.md…
$ cat writeup.md…
HackTheBox
Task: PE32 Windows binary with anti-debug protections. Solution: Bypassed PEB and RDTSC anti-debug checks, analyzed XOR self-modifying code to statically extract the flag.
A developer is experimenting with different ways to protect their software. They have sent in a windows binary that is supposed to be super secure and really hard to debug. Debug and see if you can find the flag.
Files:
debugme.exe - PE32 executable (console) Intel 80386, for MS Windows (MinGW compiled, 81377 bytes)file debugme.exe # PE32 executable (console) Intel 80386, for MS Windows strings debugme.exe | grep -i flag # "I heard you like bugs so I put bugs in your debugger so you can have bugs while you debug!!!" # "Seriously though try and find the flag, you will find it in your debugger!!!"
The binary contains DWARF debug sections (.debug_info, .debug_line, .debug_aranges, .debug_abbrev, .debug_frame, .debug_loc, .debug_ranges), compiled with GNU C 4.7.0 (MinGW).
Disassembly with objdump -d debugme.exe revealed a critical feature:
_main (0x401620) contains garbage/encoded data — many 0x5c (\) bytes, int3 instructions, unreadable code_mainCRTStartup (0x4010f9) starts with jmp 0x408904 — jump to __DTOR_LIST__+0x1c sectionThis means the real entry point is 0x408904, not the standard CRT startup.
The code in __DTOR_LIST__ performs three checks:
fs:[0x30]+0x02 (debugger flag)fs:[0x30]+0x68 (debug heap flags)rdtsc calls, if difference > 1000 cycles — debugger detectedIf all checks pass:
0x5C_main function from what appeared to be garbage0x5C (\) bytes in encoded data is the XOR key visible in encrypted formThe decoded _main:
Flag construction:
0x4B#!/usr/bin/env python3 """ Debugme - HackTheBox Reverse Engineering Static extraction of XOR-encoded flag """ # Step 1: Decode _main function (XOR with 0x5C) # The code at 0x408973 XORs bytes from 0x401620 to 0x401791 with 0x5C # Step 2: Analyze decoded main - it pushes 9 DWORDs and XORs with 0x4B # The DWORDs are constructed via mov/sub/add operations # Reconstructed DWORD values pushed to stack (from static analysis): dwords = [ 0x7b245f24, # After arithmetic operations 0x3a7f7f24, 0x3a3a7a24, 0x18787824, 0x2c2c7824, 0x2c2c2c24, 0x2d2d2d24, 0x3b3b3b24, 0x00000024, ] # Convert to bytes (little-endian) data = b''.join(d.to_bytes(4, 'little') for d in dwords) # XOR with 0x4B to get flag flag_content = bytes(b ^ 0x4B for b in data) flag = flag_content.rstrip(b'\x00').rstrip(b'o').decode('ascii') print(f"HTB{{{flag}}}") # HTB{Tr0lling_Ant1_D3buGGeR_trickz_R_fun!}
You can patch the checks in a debugger:
PEB.BeingDebugged = 0PEB.NtGlobalFlag = 0Use this technique when:
jmp to a non-standard section (__DTOR_LIST__, .data, etc.)main function contains unreadable code or repeating bytes (XOR key)fs:[0x30] (PEB) — sign of anti-debugrdtsc instructions — timing-based anti-debug$ cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ cat pricing.md$ grep --similar