1. Background: Why Traditional Inline Hook Detection Fails
Inline hook detection on Android commonly relies on:
CRC or code hash verification
Comparing function prologue bytes (e.g., detecting LDR/BR trampolines)
However, these methods have major weaknesses:
They read code pages, which makes them easily traceable with memory breakpoints.
Attackers can hook the detection function itself.
Their “signatures” are well known and easy to bypass.
Thus they are visible and high-risk in real offensive–defensive scenarios.
2. Core Idea: Detecting Hooks via the LR (Return Address)
This article introduces a stealth and cross-platform method that doesn't read any instructions, doesn't scan memory, and is extremely difficult for Frida to bypass.
✔ Why LR works
Inline hook frameworks (Frida, Dobby, xhook, etc.) must:
overwrite the LR register
redirect
RETto a trampoline stored in a custom allocated memory page (not inside the original module)
Thus:
➜ If a function’s LR is outside its module’s memory range → it is inline-hooked.
This approach:
Does not read
.textcode sectionCannot be traced via hardware breakpoints
Works on ARM64 and x86_64
3. Detection Pipeline
Step 1 — Retrieve current module range
static uint64_t g_begin = 0;
static uint64_t g_end = 0;
__attribute__((constructor))
static void init_module_range() {
Dl_info info;
if (dladdr((void*)init_module_range, &info)) {
g_begin = (uint64_t)info.dli_fbase;
g_end = g_begin + get_module_size(info.dli_fname);
}
}
Step 2 — Read LR via ARM64 inline assembly
__attribute__((alwaysinline))
uint64_t get_lr() {
uint64_t lr;
asm volatile(
"mov x10, x29 \n"
"ldr %0, [x10, #8]\n"
: "=r"(lr)
:
: "x10"
);
return lr;
}
Step 3 — Detect inline hook
void check_inline_hook() {
uint64_t lr = get_lr();
if (lr < g_begin || lr > g_end) {
LOGD("[!] Inline-hook detected. lr = %llx", lr);
} else {
LOGD("[+] Function not hooked.");
}
}
4. Advanced Protection: Stack Corruption & Anti-Analysis
To make debugging nearly impossible:
detect hook
overwrite stack (FP → FP+2048)
jump to an invalid address
void anti_debug_crash() {
uint64_t fp;
asm volatile("mov %0, x29" : "=r"(fp));
memset((void*)fp, 0xCC, 2048);
((void(*)())0x12345678)();
}
This destroys stack traces and prevents reverse engineering of your protection logic.
5. Conclusion
This LR-based inline hook detection method:
does not read code pages
is nearly breakpoint-proof
detects Frida, Dobby, xhook, and other trampoline mechanisms
works on Android and Windows
It offers a new direction for mobile security, anti-cheat systems, and runtime protection.
I’m H.
Six years deep in Android reversing.
Is this sword sharp today?
— H

Top comments (0)