reversefreemedium

Partial Encryption

HackTheBox

PE32+ executable (console) x86-64 Windows binary `partialencryption.exe` (13312 bytes). Static analysis reveals neither the flag nor meaningful strings — only Windows API imports. The task uses **runtime code decryption** via hardware AES-NI instructions.

$ ls tags/ techniques/
runtime_code_decryptionaes_ni_manual_analysisencrypted_code_blobsoffline_decryptiondynamic_analysis

$ cat /etc/rate-limit

Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.

Partial Encryption — HackTheBox

Description

Static-Analysis on this program didn't reveal much. There must be a better way to approach this...

PE32+ executable (console) x86-64 Windows binary partialencryption.exe (13312 bytes). Static analysis reveals neither the flag nor meaningful strings — only Windows API imports. The task uses runtime code decryption via hardware AES-NI instructions.

Analysis

Initial Reconnaissance

$ file partialencryption.exe PE32+ executable (console) x86-64, for MS Windows $ strings partialencryption.exe # Only Windows API imports: # VirtualAlloc, VirtualProtect, VirtualFree, putchar # Standard CRT functions # No flag, no "correct/wrong" messages

The imports VirtualAlloc / VirtualProtect / VirtualFree are a classic sign of self-modifying code: the program allocates memory, decrypts code, makes it executable, calls it, and frees the memory.

Architecture — Self-Modifying Code with AES Decryption

The binary uses the following scheme:

.data section (VA 0x140004000–0x140004830)
    │
    │  Encrypted code blobs
    │
    ▼
Decryption function (0x140001000)
    │  AES-NI: AESKEYGENASSIST + AESDECLAST
    │
    ▼
VirtualAlloc → copy decrypted code
    │
    ▼
VirtualProtect(PAGE_EXECUTE) → code becomes executable
    │
    ▼
CALL → execute decrypted code
    │
    ▼
VirtualFree(MEM_RELEASE) → free memory

Decryption Algorithm (function 0x140001000)

For each 16-byte block i of encrypted data:

  1. Key = byte i, broadcast to all 16 positions: [i, i, i, ..., i]
  2. kg0 = AESKEYGENASSIST(key, 0x00) — subkey generation with rcon=0x00
  3. kg1 = AESKEYGENASSIST(key, 0x10) — subkey generation with rcon=0x10
  4. xmm2 = data_block XOR kg1 — XOR data block with subkey
  5. result = AESDECLAST(xmm2, kg0) — final AES decryption round:
    • InvSubBytes(InvShiftRows(xmm2)) XOR kg0

Key observation: the key for each block is simply the block index, which makes the scheme weak and allows offline decryption of the blobs.

Decrypted Code Blobs

...

$ grep --similar

Similar writeups