int main (int argc, char *argv[]) { int pid; struct link_map *map; char sym_name[256]; unsigned long sym_addr; unsigned long new_addr, old_addr, rel_addr; pid = atoi (argv[1]); ptrace_attach (pid); map = get_linkmap (pid); sym_addr = find_symbol (pid, map, "_dl_open"); printf ("found _dl_open at addr %p\n", sym_addr); call_dl_open (pid, sym_addr, "/home/joker/JustForFun/Injectso/passwd/so.so"); /* 找到我们的新函数newread的地址 */ strcpy (sym_name, "newread"); /* intercept */ sym_addr = find_symbol (pid, map, sym_name); printf ("%s addr\t %p\n", sym_name, sym_addr); /* 找到read的RELOCATION地址 */ strcpy (sym_name, "read"); rel_addr = find_sym_in_rel (pid, sym_name); printf ("%s rel addr\t %p\n", sym_name, rel_addr); /* 找到用于保存read地址的指针 */ strcpy (sym_name, "oldread"); old_addr = find_symbol (pid, map, sym_name); printf ("%s addr\t %p\n", sym_name, old_addr); /* 函数重定向 */ puts ("intercept..."); /* intercept */ ptrace_read (pid, rel_addr, &new_addr, sizeof (new_addr)); ptrace_write (pid, old_addr, &new_addr, sizeof (new_addr)); ptrace_write (pid, rel_addr, &sym_addr, sizeof (sym_addr)); puts ("injectso ok"); /* 脱离进程 */ ptrace_detach (pid); exit (0); }
unsigned long ptrace_push(int pid, regs_t *regs, void *paddr, int size) { #ifdef ANDROID unsigned long arm_sp; arm_sp = regs->ARM_sp; arm_sp -= size; arm_sp = arm_sp - arm_sp % 8; regs->ARM_sp= arm_sp; ptrace_write(pid, arm_sp, paddr, size); return arm_sp; #else unsigned long esp; regs_t regs; ptrace_readreg(pid, ®s); esp = regs.esp; esp -= size; esp = esp - esp % 8; regs.esp = esp; ptrace_writereg(pid, ®s); ptrace_write(pid, esp, paddr, size); return esp; #endif }
void inject_restore_socketcall(struct tracedump *td, struct pid *sp) { /* int 0x80, int3 */ unsigned char code[4] = { 0xcd, 0x80, 0xcc, 0 }; char backup[4]; struct user_regs_struct regs2; /* backup */ ptrace_read(sp, sp->regs.eip, backup, 4); /* exec */ sp->regs.eax = sp->regs.orig_eax; ptrace_setregs(sp, &sp->regs); ptrace_write(sp, sp->regs.eip, code, 4); ptrace_cont(sp, 0, true); /* read the return code */ ptrace_getregs(sp, ®s2); sp->regs.eax = regs2.eax; /* restore */ ptrace_setregs(sp, &sp->regs); ptrace_write(sp, sp->regs.eip, backup, 4); }
static void _prepare(struct pid *sp) { FILE *fp; char buf[128]; unsigned char code[4] = { 0xcd, 0x80, 0, 0 }; // int 0x80 if (sp->vdso_addr) return; /* find VDSO address */ snprintf(buf, sizeof buf, "/proc/%d/maps", sp->pid); fp = fopen(buf, "r"); while (fgets(buf, sizeof buf, fp)) { if (strlen(buf) < 49 + 6) continue; /* found it? */ if (strncmp(buf + 49, "[vdso]", 6) == 0) { /* parse address */ buf[8] = 0; sp->vdso_addr = strtoul(buf, NULL, 16); break; } } fclose(fp); if (!sp->vdso_addr) dbg(0, "pid %d: no [vdso] memory region\n", sp->pid); #ifdef VDSO_PIGGYBACK /* on x86-32 the INT 0x80 is already there :) */ sp->vdso_addr += 0x406; #else /* inject our code */ dbg(3, "pid %d: installing code at 0x%x\n", sp->pid, sp->vdso_addr); ptrace_write(sp, sp->vdso_addr, code, sizeof code); #endif }
int32_t inject_socketcall(struct tracedump *td, struct pid *sp, uint32_t sc_code, ...) { /* int 0x80, int3 */ unsigned char code[4] = { 0xcd, 0x80, 0xcc, 0 }; char backup[4]; struct user_regs_struct regs, regs2; int ss_vals, ss_mem, ss; va_list vl; enum arg_type type; uint32_t sv; void *ptr; uint8_t *stack, *stack_mem; uint32_t *stack32; int i, j; /* * get the required amount of stack space */ ss_vals = 0; ss_mem = 0; va_start(vl, sc_code); do { type = va_arg(vl, enum arg_type); if (type == AT_LAST) break; sv = va_arg(vl, uint32_t); /* each socketcall argument takes 4 bytes */ ss_vals += 4; /* if its memory, it takes additional sv bytes */ if (type == AT_MEM_IN || type == AT_MEM_INOUT) { ss_mem += sv; ptr = va_arg(vl, void *); } } while (true); va_end(vl); ss = ss_vals + ss_mem; /* * backup */ ptrace_getregs(sp, ®s); memcpy(®s2, ®s, sizeof regs); ptrace_read(sp, regs.eip, backup, sizeof backup); /* * write the stack */ stack = mmatic_zalloc(td->mm, ss); stack32 = (uint32_t *) stack; stack_mem = stack + ss_vals; va_start(vl, sc_code); i = 0; j = 0; do { type = va_arg(vl, enum arg_type); if (type == AT_LAST) break; sv = va_arg(vl, uint32_t); if (type == AT_VALUE) { stack32[i++] = sv; } else { /* i.e. its a memory arg */ stack32[i++] = regs.esp - ss_mem + j; /* copy the memory */ ptr = va_arg(vl, void *); memcpy(stack_mem + j, ptr, sv); j += sv; } } while (true); va_end(vl); ptrace_write(sp, regs.esp - ss, stack, ss); /* * write the code and run */ regs2.eax = 102; // socketcall regs2.ebx = sc_code; regs2.ecx = regs.esp - ss; ptrace_write(sp, regs.eip, code, sizeof code); ptrace_setregs(sp, ®s2); ptrace_cont(sp, 0, true); /* * read back */ ptrace_getregs(sp, ®s2); ptrace_read(sp, regs.esp - ss_mem, stack_mem, ss_mem); va_start(vl, sc_code); do { type = va_arg(vl, enum arg_type); if (type == AT_LAST) break; sv = va_arg(vl, uint32_t); if (type == AT_VALUE) continue; ptr = va_arg(vl, void *); if (type == AT_MEM_IN) continue; memcpy(ptr, stack_mem, sv); stack_mem += sv; } while (true); va_end(vl); /* restore */ ptrace_write(sp, regs.eip, backup, sizeof backup); ptrace_setregs(sp, ®s); mmatic_free(stack); return regs2.eax; }
int32_t inject_socketcall(struct tracedump *td, struct pid *sp, uint32_t sc_code, ...) { struct user_regs_struct regs, regs2; int ss_vals, ss_mem, ss; va_list vl; enum arg_type type; uint32_t sv; void *ptr; uint8_t *stack, *stack_mem; uint32_t *stack32; int i, j; /* * get the required amount of stack space */ ss_vals = 0; // stack space for immediate values ss_mem = 0; // stack space for pointer values va_start(vl, sc_code); do { type = va_arg(vl, enum arg_type); if (type == AT_LAST) break; sv = va_arg(vl, uint32_t); /* each socketcall argument takes 4 bytes */ ss_vals += 4; /* if its memory, it takes additional sv bytes */ if (type == AT_MEM_IN || type == AT_MEM_INOUT) { ss_mem += sv; ptr = va_arg(vl, void *); } } while (true); va_end(vl); ss = ss_vals + ss_mem; /* * backup */ ptrace_getregs(sp, ®s); memcpy(®s2, ®s, sizeof regs); /* * write the stack */ stack = mmatic_zalloc(td->mm, ss); // stack area for immediate values stack32 = (uint32_t *) stack; stack_mem = stack + ss_vals; // stack area for pointer values va_start(vl, sc_code); i = 0; j = 0; do { type = va_arg(vl, enum arg_type); if (type == AT_LAST) break; sv = va_arg(vl, uint32_t); if (type == AT_VALUE) { stack32[i++] = sv; } else { /* i.e. its a memory arg */ stack32[i++] = regs.esp - ss_mem + j; /* copy the memory */ ptr = va_arg(vl, void *); memcpy(stack_mem + j, ptr, sv); j += sv; } } while (true); va_end(vl); ptrace_write(sp, regs.esp - ss, stack, ss); /* * write the code and run */ _prepare(sp); regs2.eax = 102; // socketcall regs2.ebx = sc_code; regs2.ecx = regs.esp - ss; regs2.eip = sp->vdso_addr; // gateway to int3 ptrace_setregs(sp, ®s2); ptrace_cont_syscall(sp, 0, true); // enter... ptrace_cont_syscall(sp, 0, true); // ...and exit /* * read back */ ptrace_getregs(sp, ®s2); ptrace_read(sp, regs.esp - ss_mem, stack_mem, ss_mem); va_start(vl, sc_code); do { type = va_arg(vl, enum arg_type); if (type == AT_LAST) break; sv = va_arg(vl, uint32_t); if (type == AT_VALUE) continue; ptr = va_arg(vl, void *); if (type == AT_MEM_IN) continue; memcpy(ptr, stack_mem, sv); stack_mem += sv; } while (true); va_end(vl); /* restore */ ptrace_setregs(sp, ®s); mmatic_free(stack); return regs2.eax; }
void interact( const char *const argv_0) { EditLine *const el = el_init(argv_0, stdin, stdout, stderr); el_set(el, EL_PROMPT, &prompt); el_set(el, EL_EDITOR, "emacs"); History *const hist = history_init(); if (!hist) { fprintf(stderr, "Could not initalize history\n"); exit(EXIT_FAILURE); } HistEvent ev; history(hist, &ev, H_SETSIZE, 100); el_set(el, EL_HIST, history, hist); const pid_t child_pid = _gen_child(); verbose_printf("child process is %d\n", child_pid); if (options.verbose) help(); char buf[PAGE_SIZE]; size_t buf_sz = 0; int end = 0; struct proc_info_t info = {}; ARCH_INIT_PROC_INFO(info); ptrace_launch(child_pid); ptrace_cont(child_pid, &info); ptrace_reap(child_pid, &info); display(&info); for (;;) { int count; const char *const line = el_gets(el, &count); if (count == -1) { perror("el_gets"); exit(EXIT_FAILURE); } // count is 0 == ^d if (!count || strcasestr(line, ".quit") || strcasestr(line, ".exit")) break; // We have input, add it to the our history history(hist, &ev, H_ENTER, line); // If we start with a ., we have a command if (line[0] == '.') { if (strcasestr(line, "help")) { help(); continue; } if (strcasestr(line, "info")) { display(&info); continue; } if (strcasestr(line, "showmap")) { char cmd[PATH_MAX] = { 0 }; snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", child_pid); if (system(cmd)) fprintf(stderr, "sh: %s failed\n", cmd); continue; } if (strcasestr(line, "read")) { ui_read(child_pid, line); continue; } if (strcasestr(line, "write")) { continue; } if (strcasestr(line, "begin")) { in_block = 1; continue; } // Note the lack of continue. Need to fall through... if (strcasestr(line, "end")) { in_block = 0; end = 1; } } if (buf_sz + count > sizeof(buf)) { printf("Buffer full (max: 0x%lx), please use '.end'\n", sizeof(buf)); continue; } // Since we fell through, we want to avoid adding adding .end to our buffer if (!end) { memcpy(buf + buf_sz, line, count); buf_sz += count; } if (!in_block) { verbose_printf("Trying to assemble(%zu):\n%s", buf_sz, buf); uint8_t bytecode[PAGE_SIZE]; const size_t bytecode_sz = assemble(bytecode, sizeof(bytecode), buf, buf_sz); memset(buf, 0, sizeof(buf)); buf_sz = 0; end = 0; verbose_printf("Got asm(%zu):\n", bytecode_sz); verbose_dump(bytecode, bytecode_sz, -1); if (!bytecode_sz) { fprintf(stderr, "'%s' assembled to 0 length bytecode\n", buf); continue; } ptrace_write(child_pid, (void *)options.start, bytecode, bytecode_sz); ptrace_reset(child_pid, options.start); ptrace_cont(child_pid, &info); ptrace_reap(child_pid, &info); display(&info); } } ptrace_detatch(child_pid, &info); printf("\n"); history_end(hist); el_end(el); }