#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#ifndef __WALL #define __WALL 0 #endif
void enable_core_dump(void);
int inject(pid_t pid, const char *shellcode, int size)
{
long ptr;
int i;
struct user_regs_struct data;
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) {
perror("Attach");
return -1;
}
/* wait for the stopping of the target process */
if (waitpid(pid, NULL, __WALL) == -1) {
perror("waitpid");
return -1;
}
if (ptrace(PTRACE_GETREGS, pid, NULL, &data) == -1) {
perror("Getregs");
return -1;
}
/* save the return address, since we use jmp to call the
* function instead of call instruction */
data.esp -= sizeof(long);
if (ptrace(PTRACE_POKETEXT, pid, data.esp, data.eip) == -1) {
perror("Poketext");
return -1;
}
/* transfer the shellcode to the target process */
if (size < 0)
size = strlen(shellcode);
ptr = data.eip = data.esp - size - 1024;
for (i = 0; i < size; i += sizeof(long)) {
if (ptrace(PTRACE_POKETEXT, pid, ptr, *((long*)(shellcode + i))) == -1) {
perror("Poktext");
return -1;
}
ptr += sizeof(long);
}
/* set the instruction counter */
data.eip += 2; /* skip the two instructions: nop */
if (ptrace(PTRACE_SETREGS, pid, NULL, &data) == -1) {
perror("Setregs");
return -1;
}
/* detach the target process and let it run... */
if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1) {
perror("Detach");
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
pid_t pid;
if (argc < 2) {
printf("Usage: %s pid [-k]\n", argv[0]);
return -1;
}
pid = atoi(argv[1]);
printf("Start injecting(%d)...", pid);
if (inject(pid, (const char *)enable_core_dump, 0x2c) != 0) {
printf("Failed\n");
return -1;
}
printf("OK\n");
/* sleep for a moment. When waken up, the core dump of the target
* process should be enabled. */
if (argc > 2 && strcmp(argv[2], "-k") == 0) {
sleep(3);
kill(pid, SIGSEGV);
}
return 0;
}
|