Skip to main content

Kernel Hooks using the Debugger

Overview

Let's say the function at 0xfffffff001234570 is a memory allocator, with the interface of malloc, and we want to tag every allocation with the calling address. This can be done with kernel hooks with fairly low effort.

First, we need to enlarge the allocation by 8 bytes to leave space for the tag, and save the size for later:

mon patch 0xfffffff001234570 global[0] = cpu.x[0]; cpu.x[0] += 8;

Then, we find the RET opcode the allocator function uses - let's say it's at 0xfffffff0012346e4. We can patch this opcode to write LR (return address) before actually returning:

mon patch 0xfffffff0012346e4 if(cpu.x[0]) { *(u64 *)(cpu.x[0] + global[0]) = cpu.x[30]; }

This is however not fully reentrant. The issue could be solved by adding a stack frame (remember that AArch64 SP must be 16-byte aligned) and not using global[0]:

mon patch 0xfffffff001234570 cpu.sp -= 16; *(u64 *)cpu.sp = cpu.x[0]; cpu.x[0] += 8;
mon patch 0xfffffff0012346e4 size = *(u64 *)cpu.sp; if(cpu.x[0]) { *(u64 *)(cpu.x[0] + size) = cpu.x[30]; } cpu.sp += 16;

Other Notes

The monitor command form shown here is appropriate for GDB. In IDA, you can enter monitor commands without the leading mon. In LLDB, the command must be in the form of a process plugin packet monitor patch command.