?? trace.c
字號:
/** * file:trace.c * author:XXX * date:2/3/08 * * note: Although we define a subfunction named "getMainEntryPoint", actually, the address * it gets is not the main() function entry point, but some virtul address prior to * main() function. Futhermore, there are still some bugs to be fixed. However, my free * is so limited, yet, I really want some reader to fix bugs for me. And you are quarl- * -ified to modify any lines of code below. If you do, please send email to notify me. * My email address is zhucj041070075@gmail.com, I'm looking forward to your letters. */#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<fcntl.h>#include<errno.h>#include<signal.h>#include<elf.h>#include<sys/types.h>#include<sys/stat.h>#include<sys/wait.h>#include<sys/ptrace.h>#include<asm/user.h>#define INPUTLINE 64void usage();void command();void ptraceErrCheck(int res, enum __ptrace_request req);int getUserRegs(pid_t pid, struct user_regs_struct * regs, int verbose);void setUserRegs(pid_t pid, struct user_regs_struct * regs);char ** CreateExecArgv(int argc, char ** argv);void FreeExecArgv(int argc, char ** argv);void calAddress(char * comm, unsigned long * bpAddr);int getMainEntryPoint(FILE * Elf_fp, unsigned long * bpAddr);int main(int argc, char ** argv){ if(argc < 2) { usage(); return 0; } FILE * fp; int stat_loc; long res; char comm[INPUTLINE]; pid_t pid; long oldInstruct, newInstruct; int IsInterrupted = 0; unsigned long bpAddr;//main entrypoint struct user_regs_struct regs; memset(®s, 0, sizeof(struct user_regs_struct)); if((fp = fopen(argv[1], "r")) < 0) { fprintf(stderr, "File not exist!\n"); return -1; } else { int ret = getMainEntryPoint(fp, &bpAddr);//get Main EntryPoint switch(ret) { case 0: fclose(fp); break; case -1://file read error fprintf(stdout, "file read error!\n"); fclose(fp); return -1; case -2://data format error fprintf(stdout, "data format error!\n"); fclose(fp); return -1; } } char ** ExecArgv = CreateExecArgv(argc, argv); if(!ExecArgv) { fprintf(stderr, "Failed to allocate memowy!\n"); return -1; }TRACEHERE: pid = fork(); if(pid < 0) { fprintf(stderr, "Fork error!\n"); return -1; } else if( pid == 0) { //child int ret = ptrace(PTRACE_TRACEME, 0, NULL, NULL); ptraceErrCheck(ret, PTRACE_TRACEME); execvp(ExecArgv[0] , ExecArgv); } else { //parent res = waitpid(pid, &stat_loc, 0); fprintf(stdout, "Begin to trace program %s!\n", ExecArgv[0]); while(1) { fprintf(stdout, "Command: "); fgets(comm, INPUTLINE, stdin); if(comm[0] == 'h') {//help command(); } else if(comm[0] == 'b') {//break IsInterrupted = 1; calAddress(comm, &bpAddr); oldInstruct = ptrace(PTRACE_PEEKTEXT, pid, bpAddr, NULL); ptraceErrCheck(oldInstruct, PTRACE_PEEKTEXT); /** *here I'm not sure whether it's always successful to midify the *instructure code like this, maybe we will be signaled with SIGILL, *so this is a subtle bug. */ newInstruct = 0xcccccccc; res = ptrace(PTRACE_POKETEXT, pid, bpAddr, newInstruct); ptraceErrCheck(res, PTRACE_POKETEXT); res = ptrace(PTRACE_CONT, pid, NULL, NULL); ptraceErrCheck(res, PTRACE_CONT); waitpid(pid, &stat_loc, 0); if(WIFSTOPPED(stat_loc)) { int signal = WSTOPSIG(stat_loc); if(signal == SIGTRAP) fprintf(stdout, "breakpoint at 0x%x \n", bpAddr); else fprintf(stdout, "Program %s interrupted by signal %d\n", ExecArgv[0], signal); getUserRegs(pid, ®s, 1); } } else if(comm[0] == 'r') {//run res = ptrace(PTRACE_CONT, pid, NULL, NULL); ptraceErrCheck(res, PTRACE_CONT); res = waitpid(pid, &stat_loc, 0); fprintf(stdout, "Program %s exit with code %d\n", ExecArgv[0], WEXITSTATUS(stat_loc)); goto TRACEHERE; } else if(comm[0] == 'c') {//continue if(!IsInterrupted) { fprintf(stdout, "program %s is not being running!\n", ExecArgv[0]); continue; } IsInterrupted = 0; res = getUserRegs(pid, ®s, 0);//Get the context of being ptraced process /** *x86 instructioin CC(INT 3) cause a TRAP,then eip is increased to *point to the next instruction.So, here we must decrease eip to *ensure it points to the trap-caused instruction. */ if(res) { continue; } regs.eip--; setUserRegs(pid, ®s);//set back context to the being ptraced process res = ptrace(PTRACE_POKETEXT, pid, bpAddr, oldInstruct); ptraceErrCheck(res, PTRACE_POKETEXT); res = ptrace(PTRACE_CONT, pid, NULL, NULL); ptraceErrCheck(res, PTRACE_CONT); waitpid(pid, &stat_loc, 0); if(WIFEXITED(stat_loc)) { fprintf(stdout, "Program %s exit with code %d\n", ExecArgv[0], WEXITSTATUS(stat_loc)); } else if(WIFSTOPPED(stat_loc)) { fprintf(stdout, "Program %s interrupted by signal %d\n", ExecArgv[0], WSTOPSIG(stat_loc)); } goto TRACEHERE; } else if(comm[0] == 'k') {//kill res = ptrace(PTRACE_KILL, pid, NULL, NULL); ptraceErrCheck(res, PTRACE_KILL); fprintf(stdout, "program %s terminated!\n", ExecArgv[0]); goto TRACEHERE; } else if(comm[0] == 'q') {//quit res = ptrace(PTRACE_KILL, pid, NULL, NULL); ptraceErrCheck(res, PTRACE_KILL); fprintf(stdout, "Tracer quit!\n"); break; } else { fprintf(stderr, "Unknown Command!\n"); } } } FreeExecArgv(argc, ExecArgv); return 0;}void usage(){ fprintf(stdout, " usage: trace [filename] [parameters]\n");}void command(){ fprintf(stdout, " command usage: b(break) *addr\n" " : c(continue) \n" " : r(run) \n" " : h(help) \n" " : k(kill) \n" " : q(quit) \n");}void ptraceErrCheck(int res, enum __ptrace_request req){ if(res < 0 && errno != 0) { perror("PTRACE error:"); switch(req) { case PTRACE_KILL: return; default: exit(-1); } }}int getUserRegs(pid_t pid, struct user_regs_struct * regs, int verbose){ long res = ptrace(PTRACE_GETREGS, pid, NULL, (void *)regs); if(res < 0 && errno != 0) { perror("PTRACE error:"); return -1; } if(verbose) { fprintf(stdout, "registers infomation:\n"); fprintf(stdout, " eax: 0x%x\n", regs->eax); fprintf(stdout, " ecx: 0x%x\n", regs->ecx); fprintf(stdout, " edx: 0x%x\n", regs->edx); fprintf(stdout, " ebx: 0x%x\n", regs->ebx); fprintf(stdout, " esp: 0x%x\n", regs->esp); fprintf(stdout, " ebp: 0x%x\n", regs->ebp); fprintf(stdout, " esi: 0x%x\n", regs->esi); fprintf(stdout, " edi: 0x%x\n", regs->edi); fprintf(stdout, " eip: 0x%x" "<--Here eip points to the next instruction\n", regs->eip); fprintf(stdout, " eflags: 0x%x\n", regs->eflags); fprintf(stdout, " cs: 0x%x\n", regs->cs); fprintf(stdout, " ss: 0x%x\n", regs->ss); fprintf(stdout, " ds: 0x%x\n", regs->ds); fprintf(stdout, " es: 0x%x\n", regs->es); fprintf(stdout, " fs: 0x%x\n", regs->fs); fprintf(stdout, " gs: 0x%x\n", regs->gs); } return 0;}void setUserRegs(pid_t pid, struct user_regs_struct * regs){ long res = ptrace(PTRACE_SETREGS, pid, NULL, (void *)regs); if(res < 0 && errno != 0) { perror("PTRACE error:"); exit(-1); }}void calAddress(char * comm, unsigned long * bpAddr){ //example:comm = b 0xffffffff //we must strip all the prefix //here we do not check the validity of Address char * index = comm; while(*index != '\0') { if(!strncmp(index, "0x", 2)){ *bpAddr = (unsigned long)strtol(index + 2, NULL, 16); printf("%x\n", *bpAddr); return; } index++; }}int getMainEntryPoint(FILE * Elf_fp, unsigned long * bpAddr){ Elf32_Ehdr elf_header; if(fread(&elf_header, sizeof(Elf32_Ehdr), 1, Elf_fp) != 1) return -1;//file read error unsigned char * field = (unsigned char *)&elf_header.e_entry; switch(elf_header.e_ident[EI_DATA]) { case ELFDATA2LSB: * bpAddr = ((unsigned long)(field[0])) | (((unsigned long)(field[1])) << 8) | (((unsigned long)(field[2])) << 16) | (((unsigned long)(field[3])) << 24); return 0;//success case ELFDATA2MSB: * bpAddr = ((unsigned long)(field[3])) | (((unsigned long)(field[2])) << 8) | (((unsigned long)(field[1])) << 16) | (((unsigned long)(field[0])) << 24); return 0;//success default: fprintf(stderr, "Unknown data format!\n"); return -2;//data format error }}char ** CreateExecArgv(int argc, char ** argv){ char ** execArgv = (char **)malloc(sizeof(char *) * argc); if(!execArgv) { return NULL; } int i, size;char * index; for(i = 1; i < argc; ++i) { size = sizeof(argv[i]) + 1; if(i == 1) size += 2; execArgv[i - 1] = (char *)malloc(sizeof(char) * size); if(!execArgv[i - 1]) { return NULL; } index = execArgv[i - 1]; if(i == 1) { if(argv[i][0] != '/' && argv[i][0] != '.') { strcpy(execArgv[i - 1], "./"); index = execArgv[i - 1] + 2; } } strcpy(index, argv[i]); } execArgv[argc - 1] = (char *)0; return execArgv;}void FreeExecArgv(int argc, char ** argv){ int i; for(i = 0; i < argc; ++i) { if(!argv[i]) free(argv[i]); } free(argv);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -