Skip to content

Obfuscation Tricks

Lander Brandt edited this page Aug 12, 2021 · 6 revisions

gabe_k's deep-dive into Python obfuscation at NolaCon 2016 can be found here: https://www.youtube.com/watch?v=kLf8zrPUu8c

The same module obfuscated and deobfuscated:

Obfuscated vs Deobfuscated

Here's a rough overview of some of the common tricks:

  1. Some decompilers such as uncompyle rely on lifting the bytecode to its assembly/IL. uncompyle in particular uses AST matching to reconstruct the pattern that could have been responsible for generating that code. For example, the following pattern is used to construct an import statement:
# Load the name of the module we're about to import
IMPORT_NAME 3
# Import the module
IMPORT_FROM
# Store the module in one of our slots
STORE_NAME 3

An obfuscator may insert additional code inbetween any of these instructions that alters the stack state in a way that is a no-op, but throws off the pattern matching of the decompiler.

  1. The obfuscators may do complex arithmetic that is split in an abnormal way. See the above point for more info, but this will also throw off reconstructing of expressions. Here is an example where a sequence is spilled to the stack, selectively rebuilt into a set, and AND'd with another set:

Opaque predicates

  1. Building off of point #2, complex arithmetic may be a constant expression that always evaluates to true/false, but determining this constant value requires evaluating all dependencies of the boolean (what we call an opaque predicate). The obfuscators can use this to inject false code paths that will never actually be executed, but either jumps to a completely garbage jump target (i.e. the offset does not exist, or is at a weird location) or jumps to invalid/garbage bytecode.
  2. Variable/function names may become obfuscated into non-valid Python identifiers. e.g. cache may become something like for u global set :.
  3. The marshalled code object may have a marshalled code object that is decrypted/decoded at runtime, unmarshalled, and exec'd. This nested payload may also be obfuscated in the same ways.
Clone this wiki locally