Access to kernel state by user state via library function
In order to coordinate with the kernel to use the new system call way, glibc must make certain modification. This change has already been included in the new glibc-2.3.2 (and later versions), and in the Sysdeps/unix/sysv/linux/i386/sysdep.h file of the glibc source code, the macro that handles the system call Internal_ Syscall has different results under different compilation options. Under I386_use_sysenter of the option to support sysenter/sysexit directives, system calls can be made in two ways, using the "call *_dl_sysinfo" instruction in the case of static links (compile-time plus-static options) , in the case of dynamic linking, the "call *%gs:0x10" instruction is used. Both cases are linked by the GLIBC library, which in fact ultimately corresponds to the code that calls a fixed address. Below we use a small program, with GDB to verify.
The first is a statically compiled program, the code is simple:
main()
{
getuid();
}
Statically compile the code with the static option in GCC, and then load and decompile the main function with GDB.
[root@test opt]# gcc test.c -o ./static -static
[root@test opt]# gdb ./static
(gdb) disassemble main
0x08048204 <main+0>: push %ebp
0x08048205 <main+1>: mov %esp,%ebp
0x08048207 <main+3>: sub $0x8,%esp
0x0804820a <main+6>: and $0xfffffff0,%esp
0x0804820d <main+9>: mov $0x0,%eax
0x08048212 <main+14>: sub %eax,%esp
0x08048214 <main+16>: call 0x804cb20 <__getuid>
0x08048219 <main+21>: leave
0x0804821a <main+22>: ret
As you can see, the __getuid function is called in the main function, and then the __getuid function is recompiled.
(gdb) disassemble 0x804cb20
0x0804cb20 <__getuid+0>: push %ebp
0x0804cb21 <__getuid+1>: mov 0x80aa028,%eax
0x0804cb26 <__getuid+6>: mov %esp,%ebp
0x0804cb28 <__getuid+8>: test %eax,%eax
0x0804cb2a <__getuid+10>: jle 0x804cb40 <__getuid+32>
0x0804cb2c <__getuid+12>: mov $0x18,%eax
0x0804cb31 <__getuid+17>: call *0x80aa054
0x0804cb37 <__getuid+23>: pop %ebp
0x0804cb38 <__getuid+24>: ret
The above is just part of the __getuid function. You can see that __getuid the EAX register to the function number of GETUID system call 0x18 then calls another function, where is the entrance to the function? Next, look at the value at address 0x80aa054.
(GDB) X 0x80aa054
0x80aa054 <_dl_sysinfo>: 0x0804d7f6
It doesn't look like the code that points to the kernel map page, but you can confirm that the __dl_sysinfo pointer's address is 0x80aa054. Below, we try to start the program, then stop in the first statement of the program, and then look at the value of this place.
(gdb) b main
Breakpoint 1 at 0x804820a
(gdb) r
Starting program: /opt/static
Breakpoint 1, 0x0804820a in main ()
(gdb) X 0x80aa054
0x80aa054 <_dl_sysinfo>: 0xffffe400
As you can see, the value that the _dl_sysinfo pointer is pointing to has changed, pointing to 0xffffe400, and if we continue to run the program, the __GETUID function will call the code at the address 0xffffe400.
Next, we will compile the above code into a dynamic link, that is, by default, load and decompile the main function with GDB
[root@test opt]# gcc test.c -o ./dynamic
[root@test opt]# gdb ./dynamic
(gdb) disassemble main
0x08048204 <main+0>: push %ebp
0x08048205 <main+1>: mov %esp,%ebp
0x08048207 <main+3>: sub $0x8,%esp
0x0804820a <main+6>: and $0xfffffff0,%esp
0x0804820d <main+9>: mov $0x0,%eax
0x08048212 <main+14>: sub %eax,%esp
0x08048214 <main+16>: call 0x8048288
0x08048219 <main+21>: leave
0x0804821a <main+22>: ret