// Allocate a new handler struct Handler* get_handler(pid_t pid, unsigned ip, struct Option* opt){ HANDLER_ID hid; struct Handler *handler_p; unsigned buff, backup; hid = GETID(ip); handler_p = (struct Handler*)malloc(sizeof(struct Handler)); handler_p -> global_flag = FALSE; handler_p -> option = opt; // If already exists a breakpoint at this instruction if (handlers[hid]){ backup = handlers[hid] -> backup; }else{ // Else, place a new breakpoint // Read the address of bp, making backup backup = Ptrace(PTRACE_PEEKTEXT, pid, (void*)ip, NULL); buff = (backup&0xffffff00) | 0xcc; Ptrace(PTRACE_POKETEXT, pid, (void*)ip, (void*)buff); } // IP is not breakpoint, just additional information handler_p -> ip = ip; handler_p -> backup = backup; handler_p -> life = opt->life; if (handlers[hid]) handlers[hid]->prev_handler = handler_p; handler_p -> next_handler = handlers[hid]; handler_p -> prev_handler = NULL; handlers[hid] = handler_p; return handler_p; }
// ????????????????????STRANGE void bp_show(pid_t pid, struct Handler* handler_p){ unsigned backup, ip, buff; ip = handler_p -> ip; backup = Ptrace(PTRACE_PEEKDATA, pid, (void*)ip, NULL); buff = (backup&0xffffff00)|0xcc; Ptrace(PTRACE_POKETEXT, pid, (void*)ip, (void*)buff); }
void bp_hide(pid_t pid, struct Handler* handler_p){ unsigned backup, ip; backup = handler_p -> backup; ip = handler_p -> ip; Ptrace(PTRACE_POKETEXT, pid, (void*)ip, (void*)backup); char inst_str[128]; unsigned data; data = Ptrace(PTRACE_PEEKTEXT, pid, (void*)ip, NULL); get_single_instruction_word(data, inst_str, 128); }
enum __ptrace_request trace(pid_t pid, struct Handler* handler){ unsigned ip, esp, ret; struct user_regs_struct regs; char inst_str[128]; int len; Ptrace(PTRACE_GETREGS, pid, NULL, ®s); ip = regs.eip; // if ip is within a visible module. Output and trace on if (visible(ip, handler->option->trace_option.whitelist)){ fprintf(handler->option->trace_option.file, "0x%x\n", ip); fflush(handler->option->trace_option.file); len = get_single_instruction_at(pid, ip, inst_str, 128); if (!strncmp(inst_str, "call", 4)){ // If 'call', record the latest 'ret' addr get_global_handler(pid, ip + len, handler->option); }else{ // If not 'call', hand on the latest 'ret' addr get_global_handler(pid, handler->ip, handler->option); } return PTRACE_SINGLESTEP; }else{ // If not, run until the latest 'ret' addr get_handler(pid, handler->ip, handler->option); return PTRACE_CONT; } }
struct Handler* get_global_handler(pid_t pid, unsigned ip, struct Option* opt){ struct Handler *handler_p; unsigned backup; unsigned hid; hid = GETID(ip); handler_p = (struct Handler*)malloc(sizeof(struct Handler)); handler_p -> global_flag = TRUE; handler_p -> option = opt; // If already a breakpoint exists at this instruction // Then just copy the backup if (handlers[hid]) backup = handlers[hid] -> backup; else backup = Ptrace(PTRACE_PEEKTEXT, pid, (void*)ip, NULL); // Not a breakpoint, just additional information handler_p -> ip = ip; handler_p -> backup = backup; handler_p -> life = opt -> life; if (global_handler) global_handler -> prev_handler = handler_p; handler_p -> next_handler = global_handler; handler_p -> prev_handler = NULL; global_handler = handler_p; return handler_p; }
int get_single_instruction_at(pid_t pid, unsigned ip, char* str, size_t bufsize){ unsigned data; int len; data = Ptrace(PTRACE_PEEKTEXT, pid, (void*)ip, NULL); len = get_single_instruction_word(data, str, bufsize); return len; }
enum __ptrace_request disable(pid_t pid, struct Handler* handler_p){ unsigned ip; struct user_regs_struct regs; char inst_str[128]; int len = 0; Ptrace(PTRACE_GETREGS, pid, NULL, ®s); ip = regs.eip; switch(handler_p->option->disable_option.api_type){ case API_TYPE_NORMAL: // SHOULT DETECT ELAPPED HERE. do{ ip += len; len = get_single_instruction_at(pid, ip, inst_str, 128); }while (!strncmp(inst_str, "ret", 3)); regs.eip = ip; Ptrace(PTRACE_SETREGS, pid, NULL, ®s); return PTRACE_CONT; case API_TYPE_PLT: ip = Ptrace(PTRACE_PEEKTEXT, pid, (void*)regs.esp, NULL); regs.eip = ip; Ptrace(PTRACE_SETREGS, pid, NULL, ®s); return PTRACE_CONT; } }
int __ptrace (int request, pid_t pid, caddr_t addr, int data) { int retval; long tmp; if ((request == PT_READ_I) || (request == PT_READ_D)) data = (int) &tmp; retval = Ptrace (request, pid, addr, data); if (retval < 0) { __set_errno (-retval); retval = -1; if (errno == ENOSYS) { fputs ("This system does not support the Ptrace() syscall!", stderr); } } else if (retval == 0) { if ((request == PT_READ_I) || (request == PT_READ_D)) { __set_errno (0); retval = tmp; } } return retval; }
int main(){ struct Handler *handler_p, *next_handler; unsigned hid; unsigned oep; // This is NOT THE PROPER WAY!!! unsigned siginfo[512]; unsigned baseaddr, memsize; enum __ptrace_request pr, pr2; //struct user_regs_struct regs; //char inst_str[128]; // Test const char *prog = "./try"; //char indirect = 0; //char manual = 0; //char plt = 1; //int pop = 0; //ban = 0x0804841b; int wait_status; struct user_regs_struct regs; init(); pid_t pid = fork(); if (pid == 0){ Ptrace(PTRACE_TRACEME, 0, NULL, NULL); execl(prog, prog, NULL); }else if (pid > 0){ oep = get_entry_point(prog); // On loaded wait(&wait_status); if (WIFSTOPPED(wait_status)){ // Test, wrong memsize = get_memsize(prog); baseaddr = get_baseaddr(prog); add_module(&whitelist, baseaddr, memsize); get_handler(pid, oep, get_trace_option(fopen("/tmp/trace","w"), whitelist)); get_handler(pid, 0x8048380, get_disable_option(API_TYPE_PLT)); Ptrace(PTRACE_CONT, pid, NULL, NULL); } wait(&wait_status); // Withdraw control from plugins while (WIFSTOPPED(wait_status)){ Ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo); // Caused by breakpoint if (siginfo[2] == 0x80){ // Discard the 0xcc int 3 instruction // So move the eip upper by 1 Ptrace(PTRACE_GETREGS, pid, NULL, ®s); regs.eip --; Ptrace(PTRACE_SETREGS, pid ,NULL, ®s); } // PTRACE_CONT by default because it has the lowest priority pr = PTRACE_CONT; hid = GETID(regs.eip); for (handler_p=global_handler;handler_p;handler_p=next_handler){ next_handler = handler_p->next_handler; pr2 = dispatch(pid, handler_p); pr = PRIORITY(pr, pr2); pr2 = global_expire(pid, handler_p, &next_handler); pr = PRIORITY(pr, pr2); } for (handler_p=handlers[hid];handler_p;handler_p=next_handler){ next_handler = handler_p->next_handler; pr2 = dispatch(pid, handler_p); pr = PRIORITY(pr, pr2); pr2 = expire(pid, handler_p, hid, &next_handler); pr = PRIORITY(pr, pr2); } Ptrace(pr, pid, NULL, NULL); wait(&wait_status); } }else{ perror("Folk failed: "); exit(-1); } finalize(); return 0; }