Skip to content

Instantly share code, notes, and snippets.

@Cr4sh
Created September 3, 2014 19:55
Show Gist options
  • Save Cr4sh/fe910f0d1b0559efd43d to your computer and use it in GitHub Desktop.
Save Cr4sh/fe910f0d1b0559efd43d to your computer and use it in GitHub Desktop.
Dynamically finding sys_call_table on Linux x86_64 systems
void **find_sys_call_table(void *kernel_addr, int kernel_size)
{
/*
Check for the system_call_fastpath() signature, hand-written piece of
assembly code from arch/x86/kernel/entry_64.S:
ja badsys
mov rcx, r10
call sys_call_table[rax * 8]
mov [rsp + 20h], rax
ret_from_sys_call:
mov edi, 1000FEFFh
This instructions are unchanged for the last 7 years (and maybe even more, haven't
older kernels on my test machines), so, looks reliable enough.
*/
unsigned char *mask = "\xff\xff\x00\x00\x00\x00"
"\xff\xff\xff"
"\xff\xff\xff\x00\x00\x00\x00"
"\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff";
unsigned char *sign = "\x0f\x87\x00\x00\x00\x00"
"\x4c\x89\xd1"
"\xff\x14\xc5\x00\x00\x00\x00"
"\x48\x89\x44\x24\x20"
"\xbf\xff\xfe\x00\x10";
int i = 0, n = 0, sign_len = 26;
for (i = 0; i < kernel_size; i += 1)
{
unsigned char *p = (unsigned char *)kernel_addr + i;
char matched = 1;
for (n = 0; n < sign_len; n += 1)
{
// match signature byte
if ((*(p + n) & mask[n]) != sign[n])
{
matched = 0;
break;
}
}
if (matched > 0)
{
// get sys_call_table address
return (void **)(((unsigned long long)kernel_addr & 0xffffffff00000000) + *(unsigned long *)(p + 0x0c));
}
}
return NULL;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment