= Ph4nt0m Security Team =
Issue 0x03, Phile #0x03 of 0x07
| = --------------------------------------------------------------------------- = |
| = -------------- = [Advanced Linux Kernel Inline Hook technical analysis and implementation] = ------------- = |
| = --------------------------------------------------------------------------- = |
| = --------------------------------------------------------------------------- = |
| = -------------------------- = [By wzt] = ---------------------------- = |
| = ------------------------ = [<Wzt_at_xsec.org>] = ------------------------- = |
| = --------------------------------------------------------------------------- = |
[Directory]
1. Brief Introduction
2. Change the offset to redirect
3. Supplement
4. How to kill
5. Instance
I. Brief Introduction
Currently, the popular and mature kernel inline hook Technology is to modify the opcode of kernel functions by writing
Push ret and other commands to jump to the new kernel function to achieve the modification or filtering function. What these technologies have in common is
Will overwrite the original command, so it is easy to find out in the function by looking for jmp, push ret and other commands, so this
Inline hook method is not concealed. This article uses an advanced inline hook Technology to implement a more concealed inline
Hook Technology.
Ii. Change the offset to redirect
How can I jump to our new kernel function without adding or overwriting new commands to the function? We know that implementation 1
System Call functions cannot implement all functions in this function. It must call its lower-level function.
Number. If this lower-level function can also obtain the information we want to filter, we can put the lower-level function on
The offset in the layer function is replaced with the offset of our new function, so that when the upper function calls the lower function, it will jump
In new functions, we filter and hijack content in new functions. The principle is as follows. Let's take a look at how it works.
Implementation:
Linux-2.6.18/fs/read_write.c
Asmlinkage ssize_t sys_read (unsigned int fd, char _ user * buf, size_t count)
{
Struct file * file;
Ssize_t ret =-EBADF;
Int fput_needed;
File = fget_light (fd, & fput_needed );
If (file ){
Loff_t pos = file_pos_read (file );
Ret = vfs_read (file, buf, count, & pos );
File_pos_write (file, pos );
Fput_light (file, fput_needed );
}
Return ret;
}
EXPORT_SYMBOL_GPL (sys_read );
We can see that sys_read eventually calls the lower-layer function vfs_read to complete Data Reading operations, so we do not
You need to add or override commands to sys_read. Instead, you need to change the offset of vfs_read in sys_read code to skip
Go to our new new_vfs_read. How can I modify the offset of vfs_read? First, disassemble sys_read to see:
[Root @ xsec linux-2.6.18] # gdb-q vmlinux
Using host libthread_db library "/lib/libthread_db.so.1 ".
(Gdb) disass sys_read
Dump of worker er code for function sys_read:
0xc0000dc5a <sys_read + 0>: push % ebp
0xc0000dc5b <sys_read + 1>: mov % esp, % ebp
0xc0000dc5d <sys_read + 3>: push % esi
0xc0000dc5e <sys_read + 4>: mov $0xfffffff7, % esi
0xc0000dc63 <sys_read + 9>: push % ebx
0xc0000dc64 <sys_read + 10>: sub $ 0xc, % esp
0xc0000dc67 <sys_read + 13>: mov 0x8 (% ebp), % eax
0xc0000dc6a <sys_read + 16>: lea 0xfffffff4 (% ebp), % edx
0xc0000dc6d <sys_read + 19>: call 0xc0000e16c <fget_light>
0xc0000dc72 <sys_read + 24>: test % eax, % eax
0xc0000dc74 <sys_read + 26>: mov % eax, % ebx
0xc0000dc76 <sys_read + 28>: je 0xc0000dcb1 <sys_read + 87>
0xc0000dc78 <sys_read + 30>: mov 0x24 (% ebx), % edx
0xc0000dc7b <sys_read + 33>: mov 0x20 (% eax), % eax
0xc0000dc7e <sys_read + 36>: mov 0x10 (% ebp), % ecx
0xc0000dc81 <sys_read + 39>: mov % edx, 0xfffffff0 (% ebp)
0xc0000dc84 <sys_read + 42>: mov 0xc (% ebp), % edx
0xc0000dc87 <sys_read + 45>: mov % eax, 0 xffffffec (% ebp)
0xc0000dc8a <sys_read + 48>: lea 0 xffffffec (% ebp), % eax
0xc1_dc8d <sys_read + 51>: push % eax
0xc0000dc8e <sys_read + 52>: mov % ebx, % eax
0xc0000dc90 <sys_read + 54>: call 0xc0000d75c <vfs_read>
0xc0000dc95 <sys_read + 59>: mov 0xfffffff0 (% ebp), % edx
0xc0000dc98 <sys_read + 62>: mov % eax, % esi
0xc0000dc9a <sys_read + 64>: mov 0 xffffffec (% ebp), % eax
0xc0000dc9d <sys_read + 67>: mov % edx, 0x24 (% ebx)
0xc0000dca0 <sys_read + 70>: mov % eax, 0x20 (% ebx)
0xc0000da3 <sys_read + 73>: cmpl $0x0, 0xfffffff4 (% ebp)
0xc0000dca7 <sys_read + 77>: pop % eax
0xc0000dca8 <sys_read + 78>: je 0xc0000dcb1 <sys_read + 87>
0xc0000dcaa <sys_read + 80>: mov % ebx, % eax
0xc0000dcac <sys_read + 82>: call 0xc0000e107 <fput>
0xc0000dcb1 <sys_read + 87>: lea 0xfffffff8 (% ebp), % esp
0xc0000dcb4 <sys_read + 90>: mov % esi, % eax
0xc0000dcb6 <sys_read + 92>: pop % ebx
0xc0000dcb7 <sys_read + 93>: pop % esi
0xc0000dcb8 <sys_read + 94>: pop % ebp
0xc0000dcb9 <sys_read + 95>: ret
End of worker er dump.
(Gdb)
0xc0000dc90 <sys_read + 54>: call 0xc0000d75c <vfs_read>
Use the call command to jump to vfs_read. 0xc0000d75c is the memory address of vfs_read. So you just need
This address is replaced with our new function address. When sys_read executes this address, it will jump to our function.
The following shows a hook engine I wrote to complete the function of searching for and replacing offset. The principle is to search sys_read.