/* * siringe -- non-destructive ptrace() injector * see http://www.secdev.org/ * for more informations * * Copyright (C) 2004 Philippe Biondi * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ #include #include #include #include #include #include #include #include #include #define __KERNEL__ /* macros ERESTART... */ #include #undef __KERNEL__ /* $Id$ */ #define STACKSIZE 512 #define ERROR(msg) do{ perror(msg); exit(-1); }while(0) #define USAGE do { fprintf(stderr, "Usage: siringe [-f \n"); exit(-2); }while(0) int main(int argc, char *argv[]) { int res, i, pid=0, shlen; long start, old_eip; struct user_regs_struct regs; char shcode[32768]; int fd = 1; char c; while (1) { c = getopt(argc, argv, "p:f:"); if (c == -1) break; switch (c) { case 'p': pid = atoi(optarg); break; case 'f': fd = open(optarg, O_RDONLY); if (fd == -1) ERROR("open"); break; } } if (!pid) USAGE; shlen = read(fd, shcode, sizeof(shcode)); if (!shlen) USAGE; /**** let's attach ****/ res = ptrace(PTRACE_ATTACH, pid, NULL, NULL); if (res == -1) ERROR("ptrace attach"); res = waitpid(pid, NULL, WUNTRACED); if (res != pid) ERROR("waitpid"); /**** We gather the registers ****/ res = ptrace(PTRACE_GETREGS, pid, NULL, ®s); if (res == -1) ERROR("ptrace getregs"); /**** We inject the code ****/ start = regs.esp-STACKSIZE-shlen; for (i=0; i < shlen; i+=4) { res = ptrace(PTRACE_POKEDATA, pid, start+i, *(int *)(shcode+i)); if (res == -1) ERROR("ptrace pokedata"); } /**** We hijack the exection flow ****/ old_eip = regs.eip; regs.eip = start; if ( (regs.orig_eax >= 0) && (regs.eax == -ERESTARTNOHAND || regs.eax == -ERESTARTSYS || regs.eax == -ERESTARTNOINTR) ) { regs.eip += 2; old_eip -= 2; } /**** We simulate a call (push eip) ****/ regs.esp -= 4; res = ptrace(PTRACE_POKEDATA, pid, regs.esp, old_eip); if (res == -1) ERROR("ptrace pokedata old_eip"); /**** We update the registers ****/ res = ptrace(PTRACE_SETREGS, pid, NULL, ®s); if (res == -1) ERROR("ptrace setregs"); /**** We detach and begin to run ****/ res = ptrace(PTRACE_DETACH, pid, NULL, NULL); if (res == -1) ERROR("ptrace detach"); return 0; }