#define _GNU_SOURCE #include #include #include #include #include #include #include void help(char* p) { printf("usage: %s pid cmd\n", p); exit(1); } void err(char* m) { perror(m); exit(1); } int main(int argc, char* argv[]) { if (argc < 3) help(argv[0]); int pid = atoi(argv[1]); if (!pid) help(argv[0]); char* cmd = argv[2]; int cmdlen = (strlen(cmd) / 4 + 1) * 4; char* ncmd = (char*)malloc(cmdlen); strcpy(ncmd, cmd); if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) err("attach"); wait(NULL); struct user_regs_struct regs; if (ptrace(PTRACE_GETREGS, pid, NULL, ®s) < 0) err("getregs"); regs.eip = regs.esp; regs.eax = SYS_execve; regs.ebx = regs.esp - 8 - cmdlen; regs.ecx = regs.esp - 8; /* insert syscall code */ char code[] = {0xcd, 0x80, 0x00, 0x00}; long lv; memcpy(&lv, code, 4); if (ptrace(PTRACE_POKEDATA, pid, regs.eip, lv) < 0) err("pokedata"); long esp = regs.esp - 8; /* insert pathname */ if (ptrace(PTRACE_POKEDATA, pid, esp, esp-cmdlen) < 0) err("pokedata"); if (ptrace(PTRACE_POKEDATA, pid, esp+4, 0) < 0) err("pokedata"); int i; esp -= cmdlen; for (i = 0; i < cmdlen/4; i++) { memcpy(&lv, ncmd+i*4, 4); if (ptrace(PTRACE_POKEDATA, pid, esp+4*i, lv) < 0) err("pokedata"); } #if 0 /* environ is NULL */ regs.edx = 0; #else { regs.edx = esp = regs.eip + 4; char buf[1024*1024]; sprintf(buf, "/proc/%d/environ", pid); FILE* fp = fopen(buf, "r"); int c, len = 0, strnum = 0; for (; (c = getc(fp)) != EOF; buf[len++] = c) strnum += !c; int ss = esp + strnum * 4 + 4; int i; char* p = buf; for (i = 0; i < strnum; i++) { if (ptrace(PTRACE_POKEDATA, pid, esp, ss+(p-buf)) < 0) err("pokedata"); p = index(p+1, 0) + 1; esp += 4; } if (ptrace(PTRACE_POKEDATA, pid, esp, 0) < 0) err("pokedata"); for (i = 0; i < len+4; i += 4) { esp += 4; memcpy(&lv, buf+i, 4); if (ptrace(PTRACE_POKEDATA, pid, esp, lv) < 0) err("pokedata"); } } #endif printf("eax = %x\n", regs.eax); printf("ebx = %x\n", regs.ebx); printf("ecx = %x\n", regs.ecx); printf("edx = %x\n", regs.edx); printf("eip = %x\n", regs.eip); /* for (i = esp; i <= regs.eip; i += 4) { printf("%x %x\n", i, ptrace(PTRACE_PEEKDATA, pid, i, 0)); } */ if (ptrace(PTRACE_SETREGS, pid, NULL, ®s) < 0) err("setregs"); if (ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) err("detach"); return 0; }