Techniques23-Jan-26|11 min read

The Short Binary Problem

Distinguishing Decoded Shellcode from Encrypted Payload

Definition:

The short binary problem refers to the classification challenge automated deobfuscation tools face when processing produces non-printable output. The tool must determine whether this binary data represents successfully decoded shellcode (requiring no further processing) or still-encrypted payload (requiring continued decryption). Misclassification in either direction causes analysis failures: stopping too early misses encrypted layers, while continuing too long corrupts successfully decoded output.

Deobfuscation is inherently iterative. Malware authors stack encoding layers, and analysts must peel them back one at a time. Base64 reveals XOR-encrypted data. XOR decryption reveals compressed payload. Decompression reveals... what? This is where the classification problem emerges. When a deobfuscation step produces binary output, the tool faces a decision with no middle ground. If the binary is successfully decoded shellcode, processing must stop immediately. If the binary is still-encrypted payload, processing must continue. There's no "maybe" option. Every sample demands a definitive classification. Get this wrong in one direction, and you've stopped too early. The encrypted payload remains hidden, the IOCs stay buried, the detection opportunity is lost. Get it wrong in the other direction, and you've just destroyed your own work. The successfully decoded shellcode gets mangled by unnecessary decoding operations, producing garbage that looks like failed analysis. Human analysts make this judgement intuitively. They look at output, recognise patterns, and know when to stop. Automated tools don't have that luxury. They need algorithmic classification that works reliably across thousands of samples without human review. This article explains the signals that make that classification possible.

The Two Paths to Binary Output

Two fundamentally different processes can produce visually identical results. Understanding these divergent paths is essential for accurate classification.

Path 1: Successfully Decoded ShellcodeShellcode is position-independent machine code designed for execution in memory. It appears as binary output because it is binary: raw x86 or x64 opcodes that a CPU can execute directly. Common deobfuscation paths that produce shellcode include compression unpacking (LZMA, DEFLATE, Gzip), XOR decryption with correctly identified keys, direct Base64 decoding of raw shellcode, and custom encoding reversal. This output represents the END of the deobfuscation chain. The shellcode is ready for static analysis, emulation, or execution tracing. Further processing would corrupt it.
Path 2: Still-Encrypted PayloadEncrypted payloads also appear as binary because encryption transforms readable text into pseudo-random byte sequences. The output is non-printable, high-entropy, and visually indistinguishable from shellcode. Common scenarios producing encrypted binary include partial decryption (outer layer removed but inner encryption remains), XOR decryption with incorrect key, multi-stage encryption requiring sequential removal, and encrypted-then-compressed payloads. This output requires CONTINUED processing. The actual payload remains hidden inside.

The fundamental problem is that both outputs look identical to naive inspection. Both contain non-printable characters. Both fail text validation. Both appear as "binary garbage" without deeper analysis. The classification challenge is distinguishing between success (Path 1) and incomplete work (Path 2).

Length as Diagnostic Signal

Length is the most reliable first-pass classifier. This insight emerges from understanding the constraints that shellcode authors face versus the constraints on encrypted payloads.

Shellcode authors face constraints that script authors don't. Every byte in shellcode costs something: it increases payload size, complicates delivery, and raises detection probability. Decades of shellcode development have produced a culture of extreme optimisation. Common shellcode patterns reflect this pressure.

NOP sleds provide landing zones but the functional shellcode they precede is compact. Syscall stubs invoke system calls in a few dozen bytes. Egghunters search memory for larger payloads in minimal footprint. Staged loaders that download larger payloads are intentionally minimal. Jump trampolines redirect execution in single-digit bytes. When decompression or decryption produces a small binary blob, the probability that it's successfully decoded shellcode is high. Shellcode doesn't need to be large because it doesn't contain the logic that scripts contain. It's just enough machine code to achieve a specific objective: spawn a shell, download a file, inject into a process.

Encrypted scripts tell a different story. Encrypted scripts maintain roughly their original length. XOR encryption doesn't compress data. AES and other block ciphers may add padding, but they don't shrink content. A PowerShell script encrypted with XOR produces roughly the same byte count as the original. When deobfuscation produces a large binary blob, the probability that it's still-encrypted payload is high. The length alone signals that something substantial is hidden inside, waiting for the correct decryption key or algorithm.

Short binary output suggests shellcode (stop processing). Long binary output suggests encrypted payload (continue processing). The exact threshold is empirically determined through testing against known samples, but the principle is universal.

This isn't a perfect classifier. Some shellcode is larger (multi-function payloads). Some encrypted payloads are smaller (short commands). But as a first-pass heuristic that's correct the vast majority of the time, length provides crucial guidance for automated decision-making.

NOP Sled Detection: The Unambiguous Signal

Among binary patterns, NOP sleds stand alone as near-certain shellcode indicators. The NOP instruction (0x90 on x86 architecture) tells the CPU to do nothing and advance to the next instruction. Attackers use sequences of NOPs to create "landing zones" for exploits where precise jump targeting is difficult.

If an exploit can only guarantee landing somewhere within a range of addresses, filling that range with NOPs means any landing point will "slide" execution down to the actual shellcode. This technique dates back to the earliest buffer overflow exploits and remains common today.

The diagnostic power of NOP sleds comes from probability. Encrypted data is pseudo-random. The probability of multiple consecutive 0x90 bytes appearing in encrypted output is vanishingly small. Finding them at significant density is statistically impossible in encrypted content. When deobfuscation output contains repeated 0x90 patterns at meaningful density, it's definitive: this is shellcode, not encrypted payload. No further processing should occur.

Robust NOP sled detection looks for minimum sequence length (several consecutive NOPs, not isolated bytes), density threshold (NOPs as a percentage of total output), and position (NOPs typically appear at the beginning of shellcode blobs). This pattern provides one of the few binary signatures that enables confident, automated classification without human review.

NOP sled techniques are extensively documented in exploit development resources. Metasploit's payload generation, SANS SEC760 course materials, and academic papers on buffer overflow exploitation all describe NOP sled mechanics.

Printable Character Ratios and Their Limits

ASCII defines printable characters from 0x20 (space) through 0x7E (tilde). Characters outside this range don't render as readable text. Successfully decoded scripts (PowerShell, JavaScript, VBScript, batch files) consist almost entirely of printable characters. They're text. High printable ratios strongly suggest textual content.

But printable ratio alone fails to distinguish shellcode from encrypted payload. Both produce low printable ratios. Shellcode is machine code, with opcodes spanning the full byte range with no bias toward printable ASCII. Encrypted data is pseudo-random, with byte values distributing roughly evenly across all possibilities. A low printable ratio tells you the output is binary. It doesn't tell you which kind of binary. You've identified what it isn't (text), not what it is.

Printable ratio becomes diagnostic when combined with length. Short binary with low printable ratio suggests shellcode. Long binary with low printable ratio suggests encrypted payload. Any length with high printable ratio indicates text output requiring quality validation. The multi-signal approach provides confidence that single metrics can't achieve.

Expansion Ratio Validation

Compression algorithms reduce data size. Decompression restores it. This means valid decompression always produces output larger than (or equal to) input. When processing potential DEFLATE, LZMA, or Gzip streams, expansion ratio provides validation.

Output significantly larger than input indicates likely valid decompression. Output smaller than or equal to input indicates likely false positive. Raw DEFLATE streams lack magic bytes, making them prone to false detection. Random binary data can sometimes be accepted by decompression libraries, producing garbage output. Expansion ratio catches these failures.

Valid malware compression typically achieves substantial expansion ratios. PowerShell scripts compress well. A small compressed payload expanding to several kilobytes is expected. A payload "expanding" to smaller size is invalid. After confirmed expansion, printable ratio validation ensures the decompressed content is actually textual (if text was expected) or confirms binary shellcode output. The combination of expansion validation plus output classification provides layered confidence.

The Encoding Preservation Problem

When chaining deobfuscation operations, intermediate results must be stored and passed between steps. The obvious choice for text-based tools is UTF-8 encoding. This choice is catastrophically wrong for binary data.

UTF-8 is a variable-width encoding. Byte values above 0x7F are interpreted as multi-byte sequence leaders. When binary shellcode containing bytes like 0x90, 0xC3, or 0xFF passes through UTF-8 encoding and decoding, those bytes are mangled into multi-byte sequences or replacement characters. The result: binary data that was successfully decoded is corrupted before the next processing step can occur. The corruption is invisible to logging. The analyst sees only garbage output and concludes deobfuscation failed.

Latin-1 (ISO-8859-1) is a single-byte encoding where every value from 0x00 through 0xFF maps to exactly one character and back. Binary data round-trips perfectly. This is why robust deobfuscation tools use Latin-1 for intermediate storage, even when final output is UTF-8 text. It's a subtle implementation detail that separates tools that work on diverse samples from tools that mysteriously fail on certain inputs.

Encoding errors produce symptoms that mimic failed deobfuscation: output appears corrupted or garbled, character sequences don't match expected patterns, downstream decoders fail on previously-working input. Analysts who see these symptoms often conclude the sample uses unknown encoding, when the real problem is encoding corruption in the tool's own processing chain.

Real-World Classification Scenarios

Scenario 1: The LZMA Shellcode ChainA malicious document contains a Base64 blob. Decoding reveals LZMA-compressed data. Decompression produces a small binary blob with a clear NOP sled pattern. A naive tool applies XOR brute-forcing to the decompressed output, producing corrupted garbage across dozens of "candidate" results. Correct behaviour recognises short binary with NOP indicators, marks decompression as complete, and preserves shellcode for analysis. The naive tool's output looks like failed analysis. The correct tool's output is byte-perfect shellcode ready for disassembly.
Scenario 2: The Encrypted PowerShell ChainA script contains a Base64 blob. Decoding reveals several kilobytes of binary data with low printable ratio and no NOP patterns. A naive tool sees binary output, assumes decoding complete, and stops processing. The encrypted PowerShell remains hidden. Correct behaviour recognises long binary without shellcode indicators, continues XOR key analysis, discovers the key, and decrypts to reveal the PowerShell payload. The naive tool misses the actual payload entirely. The correct tool extracts actionable IOCs from the decrypted script.
Scenario 3: The Multi-Layer TrapA sample uses Base64 followed by XOR followed by DEFLATE compression wrapping shellcode. The XOR-decrypted output is still compressed DEFLATE data, which appears as binary. A naive tool sees binary after XOR decryption, applies ROT13 (which "always works"), corrupts the compressed stream so DEFLATE decompression fails. Correct behaviour recognises that medium-length binary after XOR might be compressed data, attempts DEFLATE decompression before other transforms, and successfully recovers shellcode. Decoder ordering and binary classification interact. Getting either wrong cascades into total analysis failure.
Scenario 4: The False Positive CascadeAn analyst processes a sample where Base64 decoding produces short binary output. The tool correctly identifies this as potential shellcode. But the sample is actually Base64-encoded XOR-encrypted text with a short encryption key. Overly aggressive classification marks output as shellcode, stops processing. The encrypted text payload is missed. Correct behaviour uses length as initial signal, but validates with additional checks (entropy analysis, key detection heuristics). Discovers XOR key, decrypts to reveal text. Classification heuristics must balance false positive prevention against false negative risk. No single signal is definitive.

Known Malware Family Patterns

Key Examples
Cobalt Strike
CompressionLZMA, DEFLATE, XOR
Typical Shellcode SizeCompact stager
Payload TypePosition-independent shellcode
Public SourceMandiant APT1, CISA AA21-148A
Metasploit
CompressionShikata Ga Nai, XOR
Typical Shellcode SizeConfigurable, typically compact
Payload TypeTemplate-based shellcode
Public SourceRapid7 Documentation
Qakbot
CompressionCustom XOR, LZMA
Typical Shellcode SizeSmall loader
Payload TypeMulti-stage with shellcode loader
Public SourceCISA Alert AA23-242A
IcedID
CompressionLZMA, Gzip
Typical Shellcode SizeCompact initial loader
Payload TypeShellcode transitions to DLL
Public SourceProofpoint Research
Emotet
CompressionXOR + custom
Typical Shellcode SizeEvolved across campaigns
Payload TypePowerShell to shellcode to DLL
Public SourceTrend Micro, CISA AA20-280A
BazarLoader
CompressionXOR, custom encoding
Typical Shellcode SizeSmall initial beacon
Payload TypeShellcode loader for Cobalt Strike
Public SourceCybereason Research
Bumblebee
CompressionRC4, custom
Typical Shellcode SizeVariable loader size
Payload TypeDLL with embedded shellcode
Public SourceGoogle TAG Research

Advanced Classification Patterns

Entropy AnalysisShannon entropy measures randomness in data. Encrypted data has high entropy (approaching maximum for strong encryption). Compressed data also has high entropy. Shellcode has variable entropy depending on instruction patterns. Entropy alone doesn't distinguish encrypted from compressed from shellcode. But entropy changes during processing provide signals: successful decryption typically reduces entropy, successful decompression typically reduces entropy, processing shellcode as encrypted data may increase apparent entropy (introducing corruption). Entropy trends across processing steps can validate classification decisions. The same entropy principles apply when detecting hidden payloads in images, where high-entropy regions inside otherwise normal-entropy image data flag concealed content.
Magic Byte DetectionCertain binary formats have identifying headers. MZ (0x4D5A) indicates PE executables. PK (0x504B) indicates ZIP archives. LZMA streams have characteristic initial bytes. Gzip has its distinctive header. When deobfuscation output contains recognised magic bytes, it provides strong classification signal. PE headers in short output suggest shellcode that unpacks an executable. ZIP magic suggests archive-based payload delivery.
Behavioural PatternsSome shellcode has recognisable instruction patterns beyond NOP sleds: call-pop sequences for position-independent addressing, XOR-based decoder loops at shellcode entry points, syscall number loading patterns for direct system calls. These patterns require deeper binary analysis but provide additional classification confidence when available.

Implications for Automated Analysis

Robust deobfuscation requires binary classification at every processing step. This isn't optional sophistication. It's fundamental to producing reliable results. Tools that skip classification either stop too early (missing encrypted layers) or process too aggressively (destroying decoded shellcode).

No single metric provides sufficient confidence. Length alone has edge cases (large shellcode, small encrypted payloads). Printable ratio alone can't distinguish shellcode from encrypted data. NOP detection alone misses shellcode without NOP sleds. Expansion ratio alone only applies to decompression scenarios. Combining signals creates robust classification. Short length plus low printable ratio plus NOP patterns equals high-confidence shellcode identification. Long length plus low printable ratio plus no shellcode signatures equals high-confidence encrypted payload identification.

Manual analysts handle classification intuitively. They look at hexdumps, recognise patterns, and make judgement calls. This doesn't scale. Automated analysis at scale requires algorithmic classification that works without human review. The signals described in this article provide that algorithmic foundation.

In deobfuscation, false positives aren't merely inconvenient. They're destructive. A false positive classification that triggers unnecessary decoding operations corrupts the very data the tool was meant to extract. This asymmetry makes conservative classification strategies appropriate. When uncertain, tools should err toward "potentially shellcode, preserve output" rather than "probably encrypted, continue processing."

Related Articles

What is Script Obfuscation? — Understanding why attackers encode malicious scripts and the techniques they employ. The Multi-Layer Problem — How malware chains multiple encoding techniques and why layer order matters. Malware Encryption Keys as Threat Intelligence — Extracting IOCs from deobfuscation and tracking threat actor patterns.

KlaroSkope automatically classifies binary output at every deobfuscation step, distinguishing decoded shellcode from encrypted payloads using length heuristics, NOP sled detection, and multi-signal validation. This prevents false positives and ensures complete analysis without human review.

Try it now --> klaroskope.com/submit - submit a sample whose deobfuscation produces binary output, and see the shellcode-vs-encrypted classification reported alongside the decoded layers. Length heuristics, NOP detection, entropy, and printable-ratio signals are combined and surfaced per layer rather than collapsed into a single guess.

Frequently Asked Questions

Q

How do you tell if binary output is shellcode or encrypted payload?

Length is the primary indicator. Short binary blobs are usually successfully decoded shellcode because shellcode authors optimise ruthlessly for minimal size. Longer binary sequences often indicate still-encrypted payload that requires further decryption. Secondary signals include NOP sled patterns (repeated 0x90 bytes) which definitively identify shellcode, and printable character ratios which distinguish text from binary but can't differentiate shellcode from encrypted data alone.
Q

What is a NOP sled and why does it indicate shellcode?

A NOP sled is a sequence of no-operation instructions (0x90 in x86 architecture) that attackers use to create a "landing zone" for exploits. When precise jump targeting is difficult, filling memory with NOPs allows execution to "slide" down to the actual shellcode regardless of exact landing position. NOP patterns at high density are statistically impossible in encrypted or random data, making them definitive shellcode indicators.
Q

Why does automated deobfuscation sometimes corrupt binary output?

Corruption typically occurs through two mechanisms. First, tools may continue processing after successful decoding, applying transforms like ROT13 or XOR to already-decoded shellcode, which destroys the output. Second, improper character encoding (using UTF-8 instead of single-byte Latin-1) corrupts binary data during intermediate storage between processing steps. Both problems stem from failure to recognise when binary output represents completed analysis versus data requiring further processing.
Q

Can encrypted malware payloads be distinguished from random data?

Yes, through several signals. Encrypted payloads maintain structural properties: consistent length relative to original content, no magic byte corruption, and statistical patterns from the encryption algorithm. Truly random data lacks these properties. Length heuristics help classification because encrypted scripts maintain roughly their original size, while shellcode is optimised for minimal footprint. Entropy analysis and byte distribution statistics provide additional differentiation signals.
Q

What happens if a deobfuscation tool misclassifies shellcode as encrypted payload?

The tool applies additional decoding operations (XOR key brute-forcing, ROT13, character transforms) to already-decoded shellcode. This destroys the output, producing corrupted binary that appears as failed deobfuscation. The analyst sees only garbage and incorrectly concludes the sample couldn't be decoded, when the shellcode was actually successfully extracted before being corrupted by over-processing. This is why binary classification is critical for automated deobfuscation reliability.
Q

Why do deobfuscation tools need Latin-1 encoding instead of UTF-8 for binary data?

UTF-8 is a variable-width encoding that interprets byte values above 0x7F as multi-byte sequence leaders. Binary data (shellcode, encrypted payloads) contains arbitrary byte values across the full 0x00-0xFF range. When binary passes through UTF-8 encoding, bytes like 0x90, 0xC3, or 0xFF are corrupted into multi-byte sequences or replacement characters. Latin-1 (ISO-8859-1) maps every byte value to exactly one character, allowing binary data to round-trip without corruption between processing steps.

Found this useful? Sharing is caring!

Ready to decode?

See KlaroSkope transform obfuscated scripts into actionable intelligence.

Try It Free