Skip to content

2.22 在GDB里如何查看GS:0x10的内容

https://scz.617.cn/unix/201205081619.txt

Q:

逻辑地址

段选择子(16-bits):段内偏移(32-bits)

也叫远指针。程序中寻址时只能使用逻辑地址。没有办法禁用段机制,但有办法
禁用分页机制。

线性地址

逻辑地址经GDT、LDT转换后得到线性地址。

我想在GDB里查看逻辑地址"GS:0x10"的内容。

A:

在GDB里没有通用办法查看逻辑地址的内容,也没有通用办法进行逻辑地址到线性地 址的转换。

就这个具体的"GS:0x10"而言,有变通办法达到原始目的。

检查glibc-2.11.2的源码:

nptl/sysdeps/i386/tls.h

从TLS_INIT_TP()宏的实现可以看出,GS的段基址对应系统调用set_thread_area()的 形参u_info->base_addr:


int set_thread_area ( struct user_desc *u_info );

struct user_desc { unsigned int entry_number; unsigned long int base_addr; unsigned int limit; unsigned int seg_32bit:1; unsigned int contents:2; unsigned int read_exec_only:1; unsigned int limit_in_pages:1; unsigned int seg_not_present:1; unsigned int useable:1; unsigned int empty:25; };


GS用于访问GLIBC TLS (thread-local storage),GS段的起始地址对应tcbhead_t结 构:


/ * nptl/sysdeps/i386/tls.h / typedef struct { / * Pointer to the TCB. Not necessarily the thread descriptor used by * libpthread. / void tcb; dtv_t dtv; / * Pointer to the thread descriptor. * * 指向所属结构的起始地址 / void self; int multiple_threads; / * GS:0x10 */ uintptr_t sysinfo; uintptr_t stack_guard; uintptr_t pointer_guard; int gscope_flag;

ifndef __ASSUME_PRIVATE_FUTEX

int         private_futex;

else

int         __unused1;

endif

/*
 * Reservation of some values for the TM ABI.
 */
void       *__private_tm[5];

} tcbhead_t;

$ gdb /usr/bin/col (gdb) catch syscall set_thread_area Catchpoint 1 (syscall 'set_thread_area' [243]) (gdb) r Starting program: /usr/bin/col

Catchpoint 1 (call to syscall 'set_thread_area'), 0xb7fe6cff in ?? () from /lib/ld-linux.so.2 (gdb) x/i $eip-2 0xb7fe6cfd: int $0x80 (gdb) i r ebx ebx 0xbffffaa0 -1073743200 (gdb) x/1wx $ebx+4 0xbffffaa4: 0xb7e8a8d0 (gdb) x/1wx (unsigned int )($ebx+4)+0x10 0xb7e8a8e0: 0xb7fe4400 (gdb) x/17i (unsigned int )((unsigned int )($ebx+4)+0x10) 0xb7fe4400: push %ecx 0xb7fe4401: push %edx 0xb7fe4402: push %ebp 0xb7fe4403: mov %esp,%ebp 0xb7fe4405: sysenter 0xb7fe4407: nop 0xb7fe4408: nop 0xb7fe4409: nop 0xb7fe440a: nop 0xb7fe440b: nop 0xb7fe440c: nop 0xb7fe440d: nop 0xb7fe440e: jmp 0xb7fe4403 0xb7fe4410: pop %ebp 0xb7fe4411: pop %edx 0xb7fe4412: pop %ecx 0xb7fe4413: ret (gdb)


拦截系统调用set_thread_area(),检查形参,获得GS段的线性地址(base_addr),将 base_addr(0xb7e8a8d0)加0x10,得到GS:0x10对应的线性地址(0xb7e8a8e0),检查该 地址内容为0xb7fe4400。

顺便说一句,0xb7fe4400即__kernel_vsyscall()。在没有ASLR机制的年代,后者对 应0xffffe400。