In this post we are going to discuss two Volatility plugins that are specific to the ARM platform. Both of these plugins were contributed by Joe Sylve.
linux_check_syscall_arm
The first, linux_check_syscall_arm, enumerates each entry of the system call table to see if it is defined by the debug symbols for the kernel. This ensures that the function pointed to by the entry is valid. If the function is valid, the symbol name is printed, if is not then "HOOKED" is printed to alert the user. This is the same as how the Linux Intel plugin works as well as the Mac system call and trap table plugins.
The linux_check_syscall_arm plugin differs from the Intel version in that it requires an ARM specific method to obtain the size of the system call table. The size of the system call table changes, sometimes drastically, between kernel versions and Linux distributions, so a hardcoded value cannot be used. To gather the size, the vector_swi function is statically disassembled until the compare instruction that checks the requested system call number against the number of system calls is found. Once found, the size is then extracted. The people brave enough to read ARM disassembly may notice this size is compared to the NR_syscalls variable and wonder why we cannot read this variable directly. Unfortunately, this variable is not available on many kernel versions so we cannot generically rely on it to tell us the size of the table.
Partial output on a clean system can be seen below:
# python vol.py --profile=LinuxEvo4GARM -f ~/rodeo/Evo4GRodeo.lime linux_check_syscall_arm
Volatile Systems Volatility Framework 2.3_beta
Index Address Symbol
---------- ---------- ------------------------------
0x0 0xc0092458 sys_restart_syscall
0x1 0xc008a038 sys_exit
0x2 0xc003982c sys_fork_wrapper
0x3 0xc00f66d8 sys_read
0x4 0xc00f6488 sys_write
0x5 0xc00f4314 sys_open
0x6 0xc00f4038 sys_close
[snip]
Partial output on a clean system can be seen below:
# python vol.py --profile=LinuxEvo4GARM -f ~/rodeo/Evo4GRodeo.lime linux_check_syscall_arm
Volatile Systems Volatility Framework 2.3_beta
Index Address Symbol
---------- ---------- ------------------------------
0x0 0xc0092458 sys_restart_syscall
0x1 0xc008a038 sys_exit
0x2 0xc003982c sys_fork_wrapper
0x3 0xc00f66d8 sys_read
0x4 0xc00f6488 sys_write
0x5 0xc00f4314 sys_open
0x6 0xc00f4038 sys_close
[snip]
linux_check_evt_arm
The second plugin, linux_check_evt_arm, verifies the ARM exception vector table, which is very similar in purpose to Intel's interrupt descriptor table (IDT). This plugin works in three phases. It first verifies that the interrupt handling code has not been modified. It then verifies that the vector_swi slot in the table is not hooked (direct system call hooking of the entire table). It finishes by checking for the pointer to system call table within the code and that it has not been hooked. For each valid check, "PASS" is printed, while a failed check will print FAIL and stop processing since the subsequent data cannot be trusted. Sample output of from a clean system can be seen below:
# python vol.py --profile=LinuxEvo4GARM -f ~/rodeo/Evo4GRodeo.lime linux_check_evt_arm
Volatile Systems Volatility Framework 2.3_beta
Check PASS/FAIL Info
------------------------------ --------- ------------------------------
SWI Offset Instruction PASS Offset: 1048
vector_swi address PASS 0xC0039180
vector_swi code modification PASS E28F8080
[snip]
# python vol.py --profile=LinuxEvo4GARM -f ~/rodeo/Evo4GRodeo.lime linux_check_evt_arm
Volatile Systems Volatility Framework 2.3_beta
Check PASS/FAIL Info
------------------------------ --------- ------------------------------
SWI Offset Instruction PASS Offset: 1048
vector_swi address PASS 0xC0039180
vector_swi code modification PASS E28F8080
[snip]
Effects of Both Plugins
Combined, the two plugins make it very difficult to hook system call table entries on ARM systems. The EVT checking ensures that an attacker has not replaced the actively used system call table by either modifying the hardware handler arrays or the instructions that reference the system call table itself. Once these checks pass, we know that the system call table defined by the kernel is used, and the check system call table plugin verifies that each entry of this table is what it should be.
Conclusion
In this blog post we have shown new plugins that are able to leverage ARM specific features in order to detect kernel level rootkits. We are also glad that members of the forensics community are contributing back very useful functionality to the project. If you are a researcher who would like to contribute something substantial to the project, consider submitting to our plugin contest, where you can win cash prizes and industry recognition.
No comments:
Post a Comment