Home > Writeups > DEADROP Rev 3 - asset_tracker

DEADROP Rev 3 - asset_tracker

A Windows PE with two anti-debug gates, IsDebuggerPresent and PEB NtGlobalFlag, protecting XOR-encoded flag fragments in .rodata. Patch or bypass the checks, then decode the three fragments with their respective keys.

asset_tracker

Overview

A Windows asset tracking binary with two gates: an anti-debug check that exits immediately if a debugger is detected, and a serial comparison that triggers flag assembly if the correct serial is supplied. The flag is stored as three separate XOR-encoded byte arrays, strings finds nothing useful. The solve is to identify and bypass the anti-debug check, then read the XOR constants from the decompiler.

Step 1: Triage with strings

strings asset_tracker.exe | grep -i deadrop
# DEADROP Asset Tracking System v2.0

One hit, just the title, no flag fragments, no readable ciphertext. The flag is encoded with keys above 0x7F so all bytes are non-printable.

Step 2: Load in Ghidra, find main

Navigate to main. The structure is:

  1. Print banner
  2. Check argument count
  3. Call is_debugged(), exit if true
  4. strcmp(argv[1], "UNIT7-ALPHA-1337")
  5. If serial matches: call decode_frag three times, print flag

Step 3: Identify the anti-debug checks

is_debugged() contains two checks:

Check 1: IsDebuggerPresent

if (IsDebuggerPresent()) return 1;

The Win32 API call that returns nonzero if a debugger is attached.

Check 2: PEB NtGlobalFlag

uint8_t *peb = (uint8_t *)__readgsqword(0x60);
uint32_t nt_global = *(uint32_t *)(peb + 0xBC);
if (nt_global & 0x70) return 1;

Reads the NtGlobalFlag field from the Process Environment Block. A debugger sets bits 0x70 here, so even if you patch IsDebuggerPresent, this catches you.

Bypass options

Option A: Patch the binary

In Ghidra or a hex editor, find the JNZ (or JE) that jumps to the INTEGRITY ERROR exit path and flip it to JMP (unconditional), or NOP out the call is_debugged entirely. Run the patched binary normally.

Option B: ScyllaHide / anti-anti-debug plugin

x64dbg with ScyllaHide hides the debugger from both IsDebuggerPresent and the PEB NtGlobalFlag check. Attach and run normally.

Option C: Static only (no execution needed)

Skip the anti-debug entirely, just read the XOR constants from the decompiler and decode offline.

Step 4: Read the XOR constants from Ghidra

With the anti-debug gated code visible, Ghidra shows:

_Memory = decode_frag(&frag_a, 0x19, 0xc3);
_Memory_00 = decode_frag(&frag_b, 0x0e, 0xd5);
_Memory_01 = decode_frag(&frag_c, 0x07, 0xe7);

Each call: encoded bytes, length, XOR key. Double-click each frag_X symbol to see the byte arrays in .rodata.

Decode all three:

frag_a = bytes([
    0x87,0x86,0x82,0x87,0x91,0x8c,0x93,0xb8,
    0xa2,0xad,0xb7,0xaa,0x9c,0xa7,0xa6,0xa1,
    0xb6,0xa4,0x9c,0xa0,0xab,0xa6,0xa0,0xa8,0x9c
])
frag_b = bytes([
    0xa6,0xa5,0xb0,0xb0,0xb1,0xb7,0xa0,0xb8,
    0xa5,0x8a,0xbb,0xba,0xa1,0x8a
])
frag_c = bytes([
    0x86,0xb8,0x90,0x86,0x8b,0x8b,0x9a
])

a = bytes(b ^ 0xc3 for b in frag_a).decode()
b = bytes(b ^ 0xd5 for b in frag_b).decode()
c = bytes(b ^ 0xe7 for b in frag_c).decode()
print(a + b + c)

Flag: DEADROP{anti_debug_check_speedbump_not_a_wall}

Key Takeaway

Anti-debug checks are speedbumps not walls, the flag says so explicitly. IsDebuggerPresent and PEB NtGlobalFlag are the two most common Windows anti-debug techniques and both have well-known bypasses. More importantly, they don't protect against static analysis at all: the XOR keys are visible constants in the decompiler output regardless of whether you ever run the binary.

< Back to All Writeups