Stealth Inline Hook Detection via LR Return Address

Published: (December 12, 2025 at 10:15 PM EST)
2 min read
Source: Dev.to

Source: Dev.to

Background: Why Traditional Inline Hook Detection Fails

Inline hook detection on Android traditionally relies on:

  • CRC or code‑hash verification
  • Comparing function prologue bytes (e.g., detecting LDR/BR trampolines)

These methods have major weaknesses:

  • They read code pages, making them easily traceable with memory breakpoints.
  • Attackers can hook the detection function itself.
  • Their “signatures” are well known and easy to bypass.

Consequently, they are visible and high‑risk in real offensive–defensive scenarios.

Stealth Inline Hook Detection via LR Return Address

The proposed method does not read any instructions, does not scan memory, and is extremely difficult for Frida (or similar frameworks) to bypass.

Inline‑hook frameworks (Frida, Dobby, xhook, etc.) typically:

  1. Overwrite the LR register.
  2. Redirect RET to a trampoline stored in a custom‑allocated memory page (outside the original module).

Key observation:
If a function’s LR points outside its module’s memory range, the function is inline‑hooked.

Advantages

  • No reads of the .text code section.
  • Cannot be traced via hardware breakpoints.
  • Works on ARM64 and x86_64 (Android and Windows).

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);
    }
}
__attribute__((always_inline))
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_end) {
        LOGD("[!] Inline‑hook detected. lr = %llx", lr);
    } else {
        LOGD("[+] Function not hooked.");
    }
}

Anti‑Debug Hardening (Optional)

To make debugging nearly impossible, the protection can corrupt the stack and jump to an invalid address:

void anti_debug_crash() {
    uint64_t fp;
    asm volatile("mov %0, x29" : "=r"(fp));

    memset((void*)fp, 0xCC, 2048);          // Overwrite stack memory
    ((void(*)())0x12345678)();              // Jump to an invalid address
}

This destroys stack traces and hinders reverse engineering of the protection logic.

Summary

  • LR‑based inline hook detection does not read code pages and is nearly breakpoint‑proof.
  • It reliably detects Frida, Dobby, xhook, and other trampoline mechanisms.
  • Works across Android and Windows, on both ARM64 and x86_64 architectures.

The technique opens a new direction for mobile security, anti‑cheat systems, and runtime protection.

Back to Blog

Related posts

Read more »

Still Learning, Still Showing Up

I’m still learning, and I’m okay with that. Writing regularly is slowly teaching me how to be more clear and confident. Some days feel easy, some don’t — but sh...

Daily Tech News Roundup - 2025-12-16

Silksong is getting a free expansion next year Source: The Vergehttps://www.theverge.com/news/845189/hollow-knight-silksong-sea-of-sorrow-dlc-expansion-switch-...