OR: WHY I HATE KERNELS LMAO
Turns out, the System.map file doesn’t accurately represent the kernel address space. Instead, KASLR shifts the kernel’s address space listed in System.map by a random constant. This has been the case since it was turned on by default in Linux 4.12.
https://marcograss.github.io/security/linux/2016/01/24/exploiting-infoleak-linux-kaslr-bypass.html
https://forums.grsecurity.net/viewtopic.php?f=7&t=3367
/Untitled-1100.png)
/Untitled-1101.png)
/Untitled-1102.png)
https://bneuburg.github.io/volatility/kaslr/2017/05/05/KASLR2.html
THE DRAVUF & LibVMI WORKAROUND:
drakvuf_init() →drakvuf_init_os() → _drakvuf_init_os() → vmi_init_os() → linux_init()
→ linux_filemode_init() or init_kaslr()
Antes, no drakvuf, os endereços dos simbolos de interesse eram obtidos através do system.map mas com KASLR, ele é quase inútil. Basicamente pq os endereços apresentados pelo system.map são os endereços dos simbolos antes do KASLR ser aplicado… Veja:
- linux_init()
- init_from_json_profile()
- linux_symbol_to_address()
- linux_filemode_init()
- init_kaslr()
struct linux_instance {
char *sysmap; /**< system map file for domain's running kernel */
addr_t tasks_offset; /**< task_struct->tasks */
addr_t mm_offset; /**< task_struct->mm */
addr_t pid_offset; /**< task_struct->pid */
addr_t pgd_offset; /**< mm_struct->pgd */
addr_t name_offset; /**< task_struct->comm */
addr_t kaslr_offset; /**< offset generated at boot time for KASLR */
addr_t init_task_fixed; /**< Rekall's location for init task, ignoring KASLR */
};status_t linux_init(vmi_instance_t vmi, GHashTable *config)
{
status_t rc;
os_interface_t os_interface = NULL;
if (!config) {
errprint("No config table found\n");
return VMI_FAILURE;
}
if (vmi->os_data != NULL) {
errprint("os data already initialized, reinitializing\n");
g_free(vmi->os_data);
}
vmi->os_data = g_try_malloc0(sizeof(struct linux_instance));
if ( !vmi->os_data )
return VMI_FAILURE;
linux_instance_t linux_instance = vmi->os_data;
g_hash_table_foreach(config, (GHFunc)linux_read_config_ghashtable_entries, vmi);
/*
Talvez seja necessário assumir que isso retorna "VMI_SUCCESS", só assim o offset
do KASLR será calculado antes de tentar resolver qualquer simbolo.
*/
rc = init_from_json_profile(vmi);
if ( VMI_FAILURE == rc && !vmi->init_task )
rc = linux_symbol_to_address(vmi, "init_task", NULL, &vmi->init_task);
else
rc = VMI_SUCCESS;
if ( VMI_FAILURE == rc ) {
errprint("Failed to determine init_task!\n");
goto _exit;
}
/* Save away the claimed init_task addr. It may be needed again for KASLR computation. */
vmi->init_task = canonical_addr(vmi->init_task);
linux_instance->init_task_fixed = vmi->init_task;
// KPGD = Kernel Page Global Directory e_e
if ( !vmi->kpgd ) {
#if defined(ARM32) || defined(ARM64)
rc = driver_get_vcpureg(vmi, &vmi->kpgd, TTBR1, 0);
#elif defined(I386) || defined(X86_64)
rc = driver_get_vcpureg(vmi, &vmi->kpgd, CR3, 0);
vmi->kpgd &= ~0x1fffull; // mask PCID and meltdown bits
#endif
}
/*
* The driver failed to get us a pagetable.
* As a fall-back, try to init using heuristics.
* This path is taken in FILE mode as well.
*/
if ( VMI_FAILURE == rc && VMI_FAILURE == linux_filemode_init(vmi) )
goto _exit;
if ( !linux_instance->kaslr_offset ) {
if ( VMI_FAILURE == init_kaslr(vmi) ) {
// try without masking Meltdown bit
vmi->kpgd |= 0x1000ull;
if ( VMI_FAILURE == init_kaslr(vmi) ) {
dbprint(VMI_DEBUG_MISC, "**failed to determine KASLR offset\n");
goto _exit;
}
}
}
dbprint(VMI_DEBUG_MISC, "**set vmi->kpgd (0x%.16"PRIx64").\n", vmi->kpgd);
dbprint(VMI_DEBUG_MISC, "**set vmi->init_task (0x%.16"PRIx64").\n", vmi->init_task);
os_interface = g_malloc(sizeof(struct os_interface));
if ( !os_interface )
goto _exit;
bzero(os_interface, sizeof(struct os_interface));
os_interface->os_get_offset = linux_get_offset;
os_interface->os_get_kernel_struct_offset = linux_get_kernel_struct_offset;
os_interface->os_pid_to_pgd = linux_pid_to_pgd;
os_interface->os_pgd_to_pid = linux_pgd_to_pid;
os_interface->os_ksym2v = linux_symbol_to_address;
os_interface->os_usym2rva = NULL;
os_interface->os_v2sym = NULL;
os_interface->os_v2ksym = linux_system_map_address_to_symbol;
os_interface->os_read_unicode_struct = NULL;
os_interface->os_teardown = linux_teardown;
vmi->os_interface = os_interface;
return VMI_SUCCESS;
_exit:
linux_teardown(vmi);
return VMI_FAILURE;
}