Skip to content

anti analysis

1-3-7 edited this page Jun 17, 2026 · 1 revision

Anti-analysis defeat

disrobe is a static, deterministic analyzer that never runs the sample on the default path. It recognizes the standard anti-static-analysis arsenal and recovers what is statically recoverable, stating a wall where the data is genuinely absent rather than fabricating past it.

Signature defeat

Identification never trusts a single magic byte. A zeroed or flipped magic, renamed UPX0/UPX1 sections, or a corrupt UPX! marker is re-identified from internal self-consistency:

  • PE through e_lfanew to the COFF and optional headers.
  • ELF / Mach-O by header offsets that close against the file length.
  • ZIP by its end-of-central-directory anchor.
  • DEX by section-offset consistency.
  • Classfile by a constant-pool walk.
  • wasm by the LEB section stream.

A real UPX executable with a flipped MZ and renamed sections still unpacks byte-identically, because the structural PackHeader (method id, self-consistent compressed and uncompressed lengths, plausible version) is the signal a scrambler cannot remove without breaking the stub's own ability to self-extract.

String and data encryption

Scheme What disrobe does
Single-byte XOR stack strings Recovers them with English-likeness key detection, on native via the in-house x86 emulator driving each decoder-shaped function.
Per-family keyed strings Mirai, Dridex, and Trickbot keyed-string schemes decoded from their known transforms.
JVM string encryption Emulates the in-class decrypt(String) / decrypt(int, String) method over the encrypted constants, running <clinit> for a static key or constructing the receiver for an instance key.
.NET constant decryption ConfuserEx2 constants reversed on a real committed sample by emulating the in-assembly decryptor.
JS string-array rotation The rotated string array is rebuilt and call sites inlined.
Python exec/eval/compile payloads Unwrapped through base64/85/16/32 and zlib/lzma decode chains.

Runtime-keyed schemes (a key from a system property, the environment, the clock, a secure random, or a live cross-class table) are flagged as walls, not guessed.

Control-flow obfuscation

  • BlackObfuscator DEX flattening is deflattened: the String.hashCode()-keyed dispatcher is recognized, each block's const-string name is matched to its switch case, and the original linear block order is recovered and annotated in the output.
  • OLLVM-style control-flow flattening, bogus control flow, and instruction substitution are reversed on native.
  • Obfuscator-planted out-of-range exception entries that poison the JVM control-flow graph are dropped before structuring.
  • Flattened JS dispatchers are collapsed back to structured control flow.

Anti-disassembly and MBA

The JVM, Dalvik, and CIL decoders tolerate broken StackMapTable, fake exception ranges, and illegal-but-verifiable bytecode. On native, jump-into-the-middle desync, overlapping instructions, and opaque predicates are resolved in-tree. A mixed-boolean-arithmetic simplifier, wired through the JS and WebAssembly decoders as well, collapses MBA expressions back to their algebraic form.

Bytecode virtualization

Target Status
Lua (IronBrew2 2.7.0) Devirtualized in standard and MAX mode, graded by a real-lua execution differential.
Native generic VM disrobe native devirt locates the interpreter, fingerprints each handler's micro-op behaviorally through the in-tree x86 emulator, and lifts to a re-executable IR plus pseudo-code, validated end-to-end on a self-authored Tigress-shape VM (the recovered IR re-executes byte-identically from machine code alone).
VMProtect / Themida / Enigma front-ends Extended from published RE write-ups, not a running commercial sample. A per-machine-keyed handler stream is the residual wall.

Overlay inflation

The PE overlay carve computes the true end of the executable image and isolates any trailing archive (gzip, xz, zstd, bzip2, tar, 7z, cab, rar) into its own segment, so padding cannot mask an appended payload.

Symbol stripping

ProGuard/R8 names are restored from mapping.txt (overload-correct), Go type and stdlib names are recovered from pclntab/moduledata on stripped binaries, Rust/C++/Swift/Itanium symbols are demangled, and structure is recovered from DWARF. garble name-hashing (HMAC-SHA256 over an absent build seed) is a wall, but structure, types, and control flow recover regardless.

Runtime-keyed protection

PyArmor v6-v9 static decryption succeeds when the pyarmor_runtime is supplied. With no runtime, the verdict routes to the dynamic-capture path (opt-in, sandboxed) rather than emitting fabricated plaintext. ionCube, SourceGuardian, Zend Guard, ILProtector, and MaxToCode derive their key in a native loader or live process absent from the artifact, so they are walled and reported absent.

See the forensics and malware-safety posture for how the default static path stays safe on untrusted input.

Clone this wiki locally