Files
Mergen/scripts/rewrite/themida_samples.json
Claude 4114bb61f7 diag: add Unicorn-based external-call tracer; document Themida transform
Adds scripts/dev/trace_external_calls.py: loads a PE into Unicorn,
patches every IAT slot with a unique unmapped-address sentinel, then
emulates from the chosen entry. When any call/jmp/ret resolves its
target to a sentinel, logs the call-site address, the mnemonic, and
the addressing form. One-shot diagnostic for answering 'what x86
instruction issues this external call at runtime.'

Using it on example2-virt.bin shows the Themida transform precisely:
- guest imports (GetStdHandle etc) remain in the IAT
- every guest call site is rewritten from 'call [rip+IAT]' to a
  VM-staged 'push target; ret' where target was loaded from the
  IAT upstream
- for example2, the first external call happens at VA 0x14017fa77
  via 'ret 0', popping the GetStdHandle IAT value off the stack
- Themida strips its own SDK markers (VirtualizerSDK64.dll#103/#503)
  from the IAT; our ignore_imports filter already accounts for this

The lifter's current recognition handles direct call-through-IAT
and register-indirect IAT calls (the non-virt binary resolves 5
imports cleanly). It does not recognize the ret-pops-IAT-loaded-
pointer pattern, which is why the virt lift surfaces zero imports.

Also annotates themida_samples.json with these properties inline
so the transform semantics live next to the test that exercises
them.
2026-04-24 07:31:39 +03:00

32 lines
1.2 KiB
JSON

{
"_comment": [
"Themida preserves the guest binary's own imports (Win32 APIs) in the IAT,",
"but rewrites each call site from `call [rip+IAT]` to a VM-staged",
"`push target; ret` where `target` was loaded from the IAT by an upstream",
"VM handler. The lifter currently does not recognize this transfer pattern",
"as an import call, so the guest's externals do not surface in the IR.",
"See scripts/dev/trace_external_calls.py for a Unicorn-based tracer that",
"shows the real call mechanism at runtime.",
"",
"Themida strips its own SDK markers (VirtualizerSDK64.dll#103/#503,",
"VirtualizerStart/End) from the protected binary's IAT, so those",
"appear in the non-virt reference but not in the virt binary. The",
"ignore_imports pattern filters them out before update / compare."
],
"samples": [
{
"name": "example2",
"reference_binary": "../testthemida/example2.bin",
"virt_binary": "../testthemida/example2-virt.bin",
"entry": "0x140001000",
"ignore_imports": ["^VirtualizerSDK64\\.dll#"],
"required_imports": [
"CharUpperA",
"GetStdHandle",
"ReadConsoleA",
"WriteConsoleA"
]
}
]
}