Lab 02 — Anti-Tamper Integrity Self-Check + Attestation Model
Phase: 11 — Security & Licensing | Difficulty: ⭐⭐⭐⭐⭐ | Time: 5–8 hours Language: C (self-check) + Python (tamper tool + attestation model) | Hardware: none
Concept primer:
../WARMUP.mdCh. 6–8. Defensive scope; every technique stated with its defeat condition.
Run
make && ./protected # runs + self-verifies its own code section
python3 tamper.py protected # flips one byte in the code section -> protected_tampered
./protected_tampered # self-check fires: tamper detected, refuses
python3 attestation.py # models measure -> quote -> verify (the STRONG answer)
0. The mission
Two halves of the protection story (WARMUP Ch. 6, 8):
- Integrity self-check (
protected.c): the program hashes its own.text(code) region at runtime and compares to an embedded expected digest; if a byte's been patched (e.g., to skip a license check), the hash differs and it refuses to run. This raises the cost of casual patching — and you'll state its defeat condition. - Attestation model (
attestation.py): models the qualitatively stronger approach — a hardware root of trust measures code, produces a hardware-signed quote, and an external verifier checks it. The point: the verifier is external and the key is in hardware, so it isn't defeated by patching software.
1. What the output shows
$ ./protected
[self-check] code digest matches embedded value — integrity OK
protected workload running: result = 1240
$ python3 tamper.py protected
patched 1 byte in the code region -> protected_tampered
$ ./protected_tampered
[self-check] code digest MISMATCH — binary has been tampered. Refusing to run.
$ python3 attestation.py
== self-check vs attestation ==
self-check : the checker is IN the binary the attacker controls -> patchable
attestation: measure -> quote (signed by a HARDWARE key) -> external verify
known-good measurement -> verifier ACCEPTS
tampered measurement -> verifier REJECTS
forged quote (no hw key)-> verifier REJECTS (can't sign without the TPM/GPU key)
why stronger: the verifier is EXTERNAL and the signing key is in HARDWARE,
so patching the software can't fake a valid quote.
2. Reading order
protected.c—self_check()hashes a marked code region and compares toEXPECTED_DIGEST; note the honest comment on how it's defeated (WARMUP Ch. 6).tamper.py— flips a byte in the code region to simulate a patch (the attacker's move against the Lab 01 license check).attestation.py— the measure/quote/verify flow and the side-by-side with the self-check (WARMUP Ch. 8).
3. The honest threat model (write it — the real deliverable)
In THREAT-MODEL.md, for each technique state what it raises the cost of and
how it's defeated:
| Technique | Raises cost of | Defeated by |
|---|---|---|
| integrity self-check | casual binary patching | patching the checker / the expected digest |
| obfuscation (Ch. 7) | locating/understanding the check | a debugger + attacker-hours |
| anti-tamper response | automated tampering | calibration errors (false positives hurt honest users) |
| attestation | faking the software state | a sound trust root is required; proves what loaded, not bug-freeness |
| confidential computing | reading weights/data on host | TEE + attestation must gate decryption |
The lesson (WARMUP Ch. 1): everything self-contained raises cost, never achieves impossibility; only a hardware root of trust (attestation, confidential computing) gives a real guarantee.
4. Extensions
- Redundant + obfuscated checks (WARMUP Ch. 6–7): add multiple self-checks in different functions; measure how much harder tampering gets (attacker must find them all).
- String/control-flow obfuscation experiment: obfuscate the check logic; reflect on the RE-cost increase vs the maintenance cost.
- Real attestation design doc: design a TPM measured-boot or NVIDIA H100
Confidential Computing attestation flow for gating model-weight decryption
(WARMUP Ch. 8–9) — the production version of
attestation.py. - Encrypted weights at rest: weights decrypt only after a valid attestation (model the gate).
5. Common pitfalls
- Believing the self-check is "secure" — it's a cost-raiser; the checker is in the attacker's binary (WARMUP Ch. 1, 6). Always pair the claim with the defeat condition.
- Aggressive tamper response — self-destruction/false positives punish honest users (a hardware change, a debugger attached for support). Calibrate.
- Confusing self-attestation with attestation — software vouching for itself is not attestation; the verifier and key must be external/hardware.
- Over-obfuscating — kills performance/debuggability for marginal, bounded gain; target only high-value code.
6. What this lab proves about you
You can implement protection and threat-model it honestly — the rare combination that makes a security architecture credible to a regulated customer. You know where the line is between cost-raising (self-check, obfuscation) and real guarantees (attestation, confidential computing), which is exactly the judgment a Head of Engineering needs to architect — and to not oversell — a sovereign-deployment security story.