Teaching programme
Twelve weeks
One argument in four blocks. Each week takes the same small C program a step further from its source and asks what is left of its meaning.
The course runs a two-hour studio every week, and a spine lecture at the start of each block. Weeks are cumulative: week 10 is only legible because week 9 built the dispatcher, and week 9 is only legible because week 6 separated a genuine branch from an injected one. If you are dipping in, read the block claim first.
The question the twelve weeks answer together: How much program meaning survives a change of representation, and which deobfuscation methods generalise beyond one implementation?
Four words we keep apart
Almost every wrong conclusion in this field is one of these four being mistaken for another. They are the vocabulary of every week, every ledger and every marking rubric here.
- Analysis success
- A tool ran, produced output, and did not error.
- Semantic proof
- A property holds — under a stated model, state and path prefix.
- Binary rewriting
- Bytes changed and a file still loads.
- Runtime correctness
- The program answered correctly, on the inputs that were actually run.
Block IRepresentation
One computation has several truthful descriptions, and obfuscation is a change of description before it is anything else.
Opens with the spine lecture Same program, four stories.
Week 1. From C to machine code
If the source, the IR and the machine code disagree about how complicated a program is, which one is wrong?
24 February 2027
Week 2. What is obfuscation?
An obfuscator ran and exited zero. What has it actually done, and what would show that?
3 March 2027
Week 3. Instruction substitution
If the obfuscator expanded every single addition, why can I still see additions in the machine code?
10 March 2027
Block IISimplification
Something usually simplifies the obfuscation for you — the algebra, the compiler backend, or your own reading — and each of the three proves a different thing.
Opens with the spine lecture Something always simplifies it for you.
Week 4. MBA and semantic simplification
A simplifier returned a shorter expression. What exactly has been proved, and by what?
17 March 2027
Week 5. Optimization versus obfuscation
Is this result about the obfuscator, or about the optimisation flag that came after it?
24 March 2027
Week 6. Bogus control flow and opaque predicates
Which of these twenty-six conditional branches did the programmer actually write?
31 March 2027
Block IIIProof
A solver can prove a branch impossible and that proof can be turned into changed bytes; neither step covers what flattening hides.
Opens with the spine lecture What a proof is worth.
Week 7. Symbolic execution and SMT
What exactly has a solver established when it returns UNSAT for one direction of a branch?
21 April 2027
Week 8. From proof to a working binary
A solver proved an edge impossible. What has to happen next, and who has to do it?
28 April 2027
Week 9. Control-flow flattening
If every block returns to the same dispatcher, where did the program's structure go?
5 May 2027
Block IVLimits
The methods that generalise are the ones that carry their assumptions with them, and every output still needs validating at the level of its claim.
Opens with the spine lecture The smaller graph problem.
Week 10. Unflattening and hidden assumptions
The tool exited zero and the graph got smaller. How would you find out whether it worked?
12 May 2027
Week 11. Lifting machine code back to LLVM IR
The lifted IR verifies, recompiles and is smaller than the machine code. Is it right?
19 May 2027
Week 12. How generic can deobfuscation be?
Given an unfamiliar obfuscated function, what would you do first, and what would you have to check?
26 May 2027