Advertisement
Thun0

Untitled

Aug 5th, 2016
502
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.25 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <sys/ptrace.h>
  4. #include <stdlib.h>
  5. #include <elf.h>
  6. #include <string.h>
  7. #include <sys/wait.h>
  8. #include <sys/user.h>
  9. #include <errno.h>
  10.  
  11. #define BKPT   0xCC
  12. #define BKPT_MASK   0xFFFFFFFFFFFFFF00
  13.  
  14. #define FILEPATH_LEN 100
  15. #define SYMBOL_NAME_LEN 30
  16. #define BUF_LEN 200
  17.  
  18. char filename[FILEPATH_LEN+1];
  19. FILE* fp;
  20. int child_pid;
  21.  
  22. typedef struct
  23. {
  24.     long addr;
  25.     long original_code;
  26.     char name[SYMBOL_NAME_LEN+1];
  27. } Breakpoint;
  28.  
  29. Breakpoint* breakpoints;
  30. int bp_count;
  31.  
  32. void parse_elf_file()
  33. {
  34.     Elf64_Ehdr elf_header;
  35.     Elf64_Shdr section_header;
  36.     fp = fopen(filename, "r");
  37.     if(!fp)
  38.     {
  39.         printf("Failed to open ELF file!\n");
  40.         exit(-1);
  41.     }
  42.    
  43.     fread(&elf_header, 1, sizeof(elf_header), fp);  // read elf header
  44.  
  45.     fseek(fp, elf_header.e_shoff, SEEK_SET);    // skip to section headers
  46.  
  47.     for(int i = 0; i < elf_header.e_shnum; ++i) // iterate through headers
  48.     {
  49.         fread(&section_header, 1, sizeof(section_header), fp);  // read section header
  50.         if(section_header.sh_type == SHT_SYMTAB)    // check if this section is symbol table
  51.         {
  52.            
  53.             Elf64_Shdr strtab_header;   // we need to get strtab associated with this symtab to get functions names
  54.             long strtab_hdr_offset = elf_header.e_shoff+section_header.sh_link*sizeof(section_header); // calculate offset to strtab header
  55.             fseek(fp, strtab_hdr_offset, SEEK_SET);
  56.             fread(&strtab_header, 1, sizeof(strtab_header), fp);    // read strtab header
  57.             fseek(fp, section_header.sh_offset, SEEK_SET);
  58.  
  59.             int entries = section_header.sh_size / section_header.sh_entsize;
  60.             //printf("Found symtab with %d entries\n", entries);
  61.             breakpoints = malloc(entries*sizeof(Breakpoint));   // there are more entries than just functions
  62.  
  63.             for(i = 0; i < entries; ++i)
  64.             {
  65.                 Elf64_Sym symbol;
  66.                 fread(&symbol, 1, sizeof(symbol), fp);          // read symbol
  67.                 if(ELF64_ST_TYPE(symbol.st_info) == STT_FUNC    // symbol is a function
  68.                     && symbol.st_name != 0                      // symbol has name
  69.                     && symbol.st_value != 0)                    // symbol has address within binary
  70.                 {
  71.                     //printf("Found function at offset %lx", symbol.st_value);
  72.                    
  73.                     long pos = ftell(fp);
  74.                     fseek(fp, strtab_header.sh_offset+symbol.st_name, SEEK_SET);
  75.                     //char symbol_name[SYMBOL_NAME_LEN+1];
  76.                     //fread(symbol_name, SYMBOL_NAME_LEN, sizeof(char), fp);
  77.                     //printf(" %s", symbol_name);
  78.  
  79.                     breakpoints[bp_count].addr = symbol.st_value;   // get address to beginning of function
  80.                     fread(breakpoints[bp_count].name, SYMBOL_NAME_LEN, sizeof(char), fp);   // get function name
  81.                     //printf("BP at %lx\n", breakpoints[bp_count].addr);
  82.  
  83.                     fseek(fp, pos, SEEK_SET);
  84.                     bp_count++;
  85.    
  86.                     //printf("\n");
  87.                 }
  88.             }
  89.         }
  90.     }
  91. }
  92.  
  93. void insert_brakepoints()
  94. {
  95.     for(int i = 0; i < bp_count; ++i)
  96.     {
  97.         breakpoints[i].original_code = ptrace(PTRACE_PEEKTEXT, child_pid, (void*)breakpoints[i].addr, 0);
  98.         ptrace(PTRACE_POKETEXT, child_pid, (void*)breakpoints[i].addr, (breakpoints[i].original_code & BKPT_MASK) | BKPT); // insert breakpoint
  99.     }
  100. }
  101.  
  102. void prepare_breakpoints()
  103. {
  104.     parse_elf_file();
  105.     insert_brakepoints();
  106. }
  107.  
  108. int get_bp_id(long addr)
  109. {
  110.     for(int i = 0; i < bp_count; ++i)
  111.     {
  112.         if(breakpoints[i].addr == addr)
  113.             return i;
  114.     }
  115.     return -1;
  116. }
  117.  
  118. void trace()
  119. {
  120.     int status;
  121.     ptrace(PTRACE_CONT, child_pid, 0, 0);   // start child process
  122.     printf("Tracing started\n===\n\n");
  123.     while(1)
  124.     {
  125.         waitpid(child_pid, &status, 0);     // wait for change of status
  126.  
  127.         if(WIFEXITED(status))
  128.         {
  129.             printf("Child finished\n");
  130.             return;
  131.         }
  132.  
  133.         if(WIFSTOPPED(status))  // child stopped
  134.         {
  135.             if(WSTOPSIG(status) == SIGTRAP) // child stopped on sigtrap
  136.             {
  137.                 struct user_regs_struct regs;
  138.                 ptrace(PTRACE_GETREGS, child_pid, 0, &regs);
  139.                 int id = get_bp_id(regs.rip-1); // -1 because rip is now set to next inst and BP is 1 byte
  140.                 if(id == -1)
  141.                 {
  142.                     printf("Unexpected SIGTRAP %llx\n", regs.rip);
  143.                     return;
  144.                 }
  145.                 else
  146.                 {
  147.                     printf("%s();\n", breakpoints[id].name);
  148.                     regs.rip = breakpoints[id].addr;
  149.                     ptrace(PTRACE_SETREGS, child_pid, 0, &regs);    // set rip back to good position
  150.                     ptrace(PTRACE_POKETEXT, child_pid, (void*)breakpoints[id].addr, breakpoints[id].original_code); // return original instruction
  151.                     ptrace(PTRACE_SINGLESTEP, child_pid, 0, 0);     // step instruction
  152.                     wait(NULL); // wait for singlestep
  153.                     ptrace(PTRACE_POKETEXT, child_pid, (void*)breakpoints[id].addr, (breakpoints[id].original_code & BKPT_MASK) | BKPT); // insert breakpoint again
  154.                 }
  155.             }
  156.             if(((status >> 16) & 0xffff) == PTRACE_EVENT_EXIT)
  157.             {
  158.                 printf("Child finished\n");
  159.                 return;
  160.             }
  161.         }
  162.         ptrace(PTRACE_CONT, child_pid, 0, 0);   // continue child process
  163.     }
  164. }
  165.  
  166. int main(int argc, char** argv)
  167. {
  168.     if(argc < 2)
  169.     {
  170.         printf("Usage: tracer path\n");
  171.         return -1;
  172.     }
  173.     strncpy(filename, argv[1], FILEPATH_LEN);
  174.     child_pid = fork();
  175.     if(child_pid == 0)  // child process - tracee
  176.     {
  177.         ptrace(PTRACE_TRACEME, 0, NULL, NULL);
  178.         execl(argv[1], argv[1], NULL);
  179.         printf("Failed to execl!!\n");
  180.         exit(-1);
  181.     }
  182.     else    // parent - tracer
  183.     {
  184.         printf("PID %d\n", child_pid);
  185.         wait(NULL);
  186.         prepare_breakpoints();
  187.         trace();
  188.         free(breakpoints);
  189.     }
  190.     return 0;
  191. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement