---
# System prepended metadata

title: Practical Binary Hardening with Control-flow Enforcement Technology

---

# Practical Binary Hardening with Control-flow Enforcement Technology
- CET internals
- ... 

### Intel Control-flow Enforcement Technology
- Hardware-based mitigation against control flow hjacking attack
- CET = Shadow Stack + Indirect Branch Trecking (IBT)
- Violations -> Control Protection fault (#CP)

### Why?
- Static analysis alone cannot enforce caller-callee return pairing at runtime
- CET provides hardware shadow stack + IBT with near-zero overhead
    - branch checking
    - ignore instructon after ret/call


### CET : The Concept
- Shadow Stack
    - Protected copy of return addr checked by hardware
    - Saves return addresses whe `call`
    - Validates it with the one in shadow stack when `ret`
- Indirect Branch Tracking

### CET Invariants
- Shadow Stack
    - on every `ret`, check `RSP`(actia; ret) = `SSP`  (shadow ret addr)

- Indirect Branch Tracking
    - on every indirect `call/jmp`
    - forward-edge defense : indirect `call/jmp` target validation

### CET supports
windows: user+kernel
linux: only kernl

### What Does CET Assume?
- W ^ X is intact no writable + executable pages
- Shadow stack is HW-protected oordinary stores can't write it
- OS has enabled CET CR4.CET + per-mode MSRs set

## IBT
### Implementation
- A `0x3E` "notrack"
![](https://s.secrss.com/anquanneican/bf5551e17832090076d2b5dc51b904e3.jpg)

### ENDBR32 / ENDBR64
- `ENDBR{64,32}` : `F3 0F 1E {FA,FB}`
    - FA : 64 bits
    - FB : 32 bits
- `F3 0F` = Multi-byte reserved NOP encoding
    - Old hardware w/o CET support -> no-op

### Edges
- Backwared Edge : Return-Oriented Programming (ROP)
    - Attacker overwrites saved return address on the stack
    - Chains small gadgets ending in `ret`
- Forwared Edge : JOP/COP
    - Attacker computes indirect jump/call targets (function pointers)

### Common gadget atttack

#### ROP
d
#### JOP
- JOP controls chains gadget w/ indirect branch, uses `jmp(reg)` insted of `ret`
- dont reuse `ret`


#### COP
uses indirect call, insted of `ret/jmp`

### tl;dr
- IBT -> prevent COP/JOP
- Shadow Stack -> prevent ROP

### CVEs
#### CVE-2025-32756
https://horizon3.ai/attack-research/attack-blogs/cve-2025-32756-low-rise-jeans-are-back-and-so-are-buffer-overflows/

- root cause: no bound check on b64(user_input) to a fixed stack


##### if CET enable
- raise CP fault, attack will fails

#### CVE-2025-0282
https://labs.watchtowr.com/exploitation-walkthrough-and-techniques-ivanti-connect-secure-rce-cve-2025-0282/

- attack path: fake `*this` pointer -> fake vtable redirect -> false deref -> stack pivot -> ROP -> RCE


### Exceptional Control Flow
- There are legitimate cases when control flow a transferred to opaque continuation targets
- Unwinding, `NtContinue`, `RtlRestoreContext` or `setjmp/longjmp`
- APC delivery


## System Calls
related talk: https://i.blackhat.com/asia-19/Thu-March-28/bh-asia-Sun-How-to-Survive-the-Hardware-Assisted-Control-Flow-Integrity-Enforcement.pdf

### NtContinue
- Introduced `NtContinueEx` system call
- Now `KCONTINUE_TYPE` = description

### KeVerifyContextXStateCetU
- First validation routine for `NtContinue`, `NtSetContextThread`, ...

### K{e,i}VerifyContextIpForUserCet
WHen context IP validation is enabled on a target process:
- The kernel validates given RIP
- The RIP must appear on the usr shadow stack
- Reference EM Continuation / LongJump Table for a predefined setr tof staticcally known continuation targets
- Relaxed behavior for backwards compatibility
    - If the executable does not have EH continuation table.


### EH Continuation Table
- Linker : `/GUARD:EHCONT`
- A data found in Load Config data directory in PE
- `IMAGE_GUARD_EH_CONTINUATION_TABLE_PRESENT` bit set

- `target_rva` = echo: valid continunation target


>在結構化異常處理 (SEH) 異常回溯期間，使用 RtlRestoreContext 和 NtContinue 回溯到包含 __except 程式碼區塊的目標訊框。 __ __except 程式碼區塊的指令指標不應位於影子堆疊中，因為這會導致指令指標驗證失敗。編譯器開關 /guard:ehcont 會產生一個「EH 延續表」。此表包含二進位檔案中所有有效異常處理延續目標 NtContinue RVA 排序清單。 NtContinue 首先檢查影子堆疊中是否存在使用者提供的指令指針，如果未找到，則會檢查包含該指令指針的二進位檔案中的 EH 延續表

ref: https://learn.microsoft.com/en-us/cpp/build/reference/guard-enable-eh-continuation-metadata?view=msvc-170

### LongJump Table
- Linker : `/GUARD:LONGJMP`
- a data found in Load Config data directory in PE
- `IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT` bit set
- An array of entries represented by `longjump_entry`
    - `target_rva` tells the kernel ...

### Unwinding
`RtlVerifyUserUnwindTarget`

### JIT Code
special handling for CET support


### Conclution
Windows handle wirh set-context ip validation w/ CET

### CET Support on Windows JIT codes


| Runtime         | SHSTCK |
| --------------- | ------ |
| V8              | X      |
| SpiderMonkery   | X      |
| JavaScriptCore  | X      |
| .NET 9+ CoreCLR    | V      |
| .NET native AOT | V      |

- only on .NET native & .NET 9+ core, impliment defaultly after .NET 9

### Problem 1 : GC Return Addr Hijacking
- GC needs to pause a managed thread
- Overwrites a return addr on the real stack with a GC ...

### Solution 1 : User-Mode APC Suspension
- GC Thread -> `QueueUserAPC2(SPECIAL_USER_APC)` -> Thread A -> APC fires at alartable point -> Cnters GC suspension

#### 3 types of APCs
- kernel mode APC -- kernel content
- User Mode APC -- QueueUserAPC, running thread APCs
- Special Kernel APC (aka Normal vs Special APC distinction)

| Type               | Runs In | Used By           | Example                              |
| ------------------ | ------- | ----------------- | ------------------------------------ |
| Kernel-mode APC    | Kernel  | OS                | I/O completion                       |
| User-mode APC      | User    | Applications      | `QueueUserAPC`                       |
| Special Kernel APC | Kernel  | OS (critical ops) | Thread termination, system internals |

### Prob 2. 
`RtlRestoreContex`: Restores the context of the caller to the specified context record.

### Sol 2.
- CoreCLR does not call `SetProcessDynamicEHContinuationTargets`
    - CoreCLR is the runtime for .NET Core. It includes the garbage collector(GC), JIT compiler, primitive data types and low-level classes.

### Prob 3 native runtime component

### Sol 3 CET Binary Merkers

### Wrapup

### Key Takeaway
- Broser engines still treat SHSTK + JIT renderer support as a hard integration area
- Bypass `rtlrestorecontext` w/ clrRestoreNonVolatileContext


### Indirect Branch Tracking
- CFG/XFG implements in software
    - CFG : Control Flow Guard 控制流防護
        - 主要在間接調用（如 call 或 jmp 暫存器）前檢查目標地址有效性
    - XFG : eXtended Flow Guard 擴展流防護
        - 針對間接調用，檢查 Function Prototype Hash，防止惡意利用函數原型不同的間接跳轉


## Undocumented CET Flags on Win!!
- related issue :https://github.com/llvm/llvm-project/pull/150761

`/CETCOMPATSTRICT`
- `KiFixupControlProtectionUserModeReturnMismatch`
- Remove the compatibility behavior (AppCompat)

`/cetipvalidationrelaxed[:no]`

`/cetdynamicapisinproc[:no]`

`/hotpatchcompatible[:no]`

### Singnal Handling with Shadow Stack

## linux Indirect Branch Tracking (IBT)
When the Linux kernel supports CET/IBT, it will ensure that all indirect jump targets have `ENDBR` during compilation, booting and dynamic probe insertion, and prevent probes from destroying these protection instructions.


### CET limitation: deploy

https://www.felixcloutier.com/x86/rstorssp


