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
- Confirm the packer.
filereportsPE32 ... UPX compressed, 3 sections. The version banner is stripped sostrings | grep upxis empty, but theUPX0/UPX1/UPX2section names and theUPX!magic at0x3e0are intact. - Unpack with stock UPX (it keys off the magic, not the banner):
upx -d -o whp_unpack.exe WinHardPacked.exe
- Find the check in radare2 (
aaa; pdf @ 0x4017d9).mainisif (argc==2 && check(argv[1])==1) puts("You beat a packed Windows executable! Wow!");. - 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 dwords0xa9d1f482,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. TheIsDebuggerPresentbail, a PEBfs:[0x30]slot later reused as a counter, and a permutation loop writing to a deadebp+0x3cbuffer are all decoys. - 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!}