arrow_backUS Cyber Games 2026
Reverse Engineeringhard

WinHardPacked

by Pavel Knespl (capyplivl)

A 26 KB UPX-packed Windows console PE (WinHardPacked.exe). After unpacking, the password check is RC4 with a hardcoded 8-byte key comparing against a stack-string ciphertext; recover the password by decrypting the embedded blob.

Solve

  1. Confirm the packer. file reports PE32 ... UPX compressed, 3 sections. The version banner is stripped so strings | grep upx is empty, but the UPX0/UPX1/UPX2 section names and the UPX! magic at 0x3e0 are intact.
  2. Unpack with stock UPX (it keys off the magic, not the banner):
upx -d -o whp_unpack.exe WinHardPacked.exe
  1. Find the check in radare2 (aaa; pdf @ 0x4017d9). main is if (argc==2 && check(argv[1])==1) puts("You beat a packed Windows executable! Wow!");.
  2. Reverse check (fcn.0040153d). It reads a 41-byte expected ciphertext written as a stack string (mov byte [ebp+0x48+k], imm), then runs RC4. The KSA uses an 8-byte key from two dwords 0xa9d1f482, 0xde3057c6 (little-endian) = 82 f4 d1 a9 c6 57 30 de. PRGA generates 41 keystream bytes, XORs them into the input, and compares all 41 bytes. The IsDebuggerPresent bail, a PEB fs:[0x30] slot later reused as a counter, and a permutation loop writing to a dead ebp+0x3c buffer are all decoys.
  3. Pass condition is RC4_encrypt(input) == expected, so the password is the RC4 decryption of the embedded blob:
key = [0x82,0xf4,0xd1,0xa9,0xc6,0x57,0x30,0xde]
exp = [0x65,0x23,0xca,0x3d,0xc4,0xde,0xc6,0x21,0x98,0x4b,0xd6,0x9c,0x6d,0xf6,0x1a,0xb9,
       0xe5,0xfb,0xdb,0xc7,0x22,0xff,0x64,0x88,0xf3,0x5c,0x8c,0x07,0xcb,0xfd,0x3d,0xa6,
       0xd8,0xb3,0xdb,0xf7,0x5a,0xe9,0x85,0x22,0x05]
S=list(range(256)); j=0
for i in range(256): j=(j+S[i]+key[i%8])&255; S[i],S[j]=S[j],S[i]
i=j=0; out=[]
for n in range(len(exp)):
    i=(i+1)&255; j=(j+S[i])&255; S[i],S[j]=S[j],S[i]
    out.append(S[(S[i]+S[j])&255]^exp[n])
print(bytes(out))

Flag: SVIUSCG{NowYouCanDoPackedWindowsFiles!}