多亏了 blabb 和 Jonathon Reinhart 的提示,我才能够编写一个get_thread_start_address()
函数。它读取用于pthread_start_thread()
调用启动例程的相同地址。在内核 3.2.0-4-686-pae 中,这个地址是GS+0x234
. 我ptrace
用来获取GS register
和实际的GS segment address
. 这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <asm/ldt.h>
#include <asm/ptrace.h>
int attach(int tid);
int detach(int tid);
void print_error(char* func_name, int errnumber);
int get_gs_register(int tid){
struct user_regs_struct regs;
int ret = ptrace(PTRACE_GETREGS, tid, NULL, ®s);
if(ret == -1){
print_error("PTRACE_GETREGS", errno);
return -1;
}
return regs.xgs;
}
// This is needed to get the actual GS segment address from the GS register value
int get_thread_area_base(tid, gs){
struct user_desc desc;
memset(&desc, 0, sizeof(desc));
int ret = ptrace(PTRACE_GET_THREAD_AREA, tid, gs / LDT_ENTRY_SIZE, &desc);
if(ret == -1){
print_error("PTRACE_GET_THREAD_AREA", errno);
return -1;
}
return desc.base_addr;
}
void* get_start_address(tid, start_address_pointer){
char start_addr_str[4];
int mem_file;
char mem_file_path[255];
snprintf(mem_file_path, sizeof(mem_file_path), "/proc/%i/mem", tid);
mem_file = open(mem_file_path, O_RDONLY);
if(mem_file == -1){
print_error("open()", errno);
return (void*) -4;
}
int ret = lseek(mem_file, start_address_pointer, SEEK_SET);
if(ret == -1){
print_error("lseek()", errno);
return (void*) -5;
}
ret = read(mem_file, start_addr_str, 4);
if(ret == -1){
print_error("read()", errno);
return (void*) -6;
}
return (void*) *((int*)start_addr_str);
}
int main(int argc, char* argv[]){
if(argc <= 1){
printf("Usage: %s TID\n", argv[0]);
return -1;
}
int tid = atoi(argv[1]);
int gs;
int thread_area_base;
int start_address_offset = 0x234;
void* start_address;
int ret = attach(tid);
if(ret == -1) return -1;
gs = get_gs_register(tid);
if(gs == -1){
detach(tid);
return -2;
}
thread_area_base = get_thread_area_base(tid, gs);
if(thread_area_base == -1){
detach(tid);
return -3;
}
printf("thread_area_base: %p\n", (void*) thread_area_base);
unsigned int start_address_pointer = thread_area_base + start_address_offset;
printf("start_address_pointer: %p\n", (void*) start_address_pointer);
start_address = get_start_address(tid, start_address_pointer);
printf("start_address: %p\n", start_address);
detach(tid);
return 0;
}
int attach(int tid){
int status;
int ret = ptrace(PTRACE_ATTACH, tid, NULL, NULL);
if(ret == -1){
print_error("PTRACE_ATTACH", errno);
}
ret = waitpid(-1, &status, __WALL);
if(ret == -1){
print_error("waitpid()", errno);
}
return ret;
}
int detach(int tid){
int ret = ptrace(PTRACE_DETACH, tid, NULL, NULL);
if(ret == -1){
print_error("PTRACE_DETACH", errno);
}
return ret;
}
void print_error(char* func_name, int errnumber){
printf("%s failed. %i, %s\n", func_name, errnumber, strerror(errnumber));
}