diff options
Diffstat (limited to 'evilize.c')
-rw-r--r-- | evilize.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/evilize.c b/evilize.c new file mode 100644 index 0000000..e3b13aa --- /dev/null +++ b/evilize.c @@ -0,0 +1,65 @@ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <signal.h> +#include <sys/ptrace.h> + +#define ERRCHECK(E)\ + if ((E) == -1) {perror(argv[0]); kill(pid, SIGHUP); return -1;} + +int main(int argc, char *argv[]) { + if (argc < 2) { + fprintf(stderr, "usage: %s COMMAND [ARGS]...\n" , argv[0]); + return -1; + } + pid_t pid = fork(); + if (pid == -1) { + perror(argv[0]); + return -1; + } + if (pid == 0) { + ptrace(PTRACE_TRACEME, 0, NULL, NULL); + raise(SIGSTOP); + if (execvp(argv[1], argv + 1) == -1) { + perror(argv[0]); + return -1; + } + } else { + ERRCHECK(ptrace(PTRACE_ATTACH, pid, NULL, NULL)); + int status; + pid_t w = waitpid(pid, &status, __WALL); + ERRCHECK(w); + ERRCHECK(ptrace(PTRACE_CONT, pid, NULL, NULL)); + while (1) { + pid_t w = waitpid(pid, &status, __WALL); + ERRCHECK(w); + if (WIFEXITED(status)) + return WEXITSTATUS(status); + if (WIFSTOPPED(status)) { + if (WIFSIGNALED(status)) { + errno = 0; + switch (WSTOPSIG(status)) { + case SIGABRT: + case SIGBUS: + case SIGFPE: + case SIGILL: + case SIGSEGV: + ptrace(PTRACE_CONT, pid, NULL, NULL); + break; + default: + ptrace(PTRACE_CONT, pid, NULL, WSTOPSIG(status)); + break; + } + if (errno && errno != ESRCH) { + perror("ptrace"); + kill(pid, SIGHUP); + return -1; + } + } else ptrace(PTRACE_CONT, pid, NULL, NULL); + } + } + } +} |