|
|
|
@ -1,3 +1,97 @@
@@ -1,3 +1,97 @@
|
|
|
|
|
|
|
|
|
|
static struct mi_registers |
|
|
|
|
get_process_registers(struct mi_process proc) |
|
|
|
|
{ |
|
|
|
|
struct user_regs_struct regs = { 0 }; |
|
|
|
|
struct iovec iov = { ®s, sizeof(regs) }; |
|
|
|
|
struct mi_registers result = { 0 }; |
|
|
|
|
|
|
|
|
|
ptrace(PTRACE_GETREGSET, proc.pid, NT_PRSTATUS, &iov); |
|
|
|
|
|
|
|
|
|
result.rax = regs.rax; |
|
|
|
|
result.rip = regs.rip; |
|
|
|
|
result.rbp = regs.rbp; |
|
|
|
|
result.rbx = regs.rbx; |
|
|
|
|
result.rcx = regs.rcx; |
|
|
|
|
result.rdx = regs.rdx; |
|
|
|
|
result.rsi = regs.rsi; |
|
|
|
|
result.rdi = regs.rdi; |
|
|
|
|
result.rsp = regs.rsp; |
|
|
|
|
|
|
|
|
|
result._sys = regs; |
|
|
|
|
|
|
|
|
|
return(result); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
set_process_registers(struct mi_process proc, struct mi_registers regs) |
|
|
|
|
{ |
|
|
|
|
regs._sys.rax = regs.rax; |
|
|
|
|
regs._sys.rip = regs.rip; |
|
|
|
|
regs._sys.rbp = regs.rbp; |
|
|
|
|
regs._sys.rbx = regs.rbx; |
|
|
|
|
regs._sys.rcx = regs.rcx; |
|
|
|
|
regs._sys.rdx = regs.rdx; |
|
|
|
|
regs._sys.rsi = regs.rsi; |
|
|
|
|
regs._sys.rdi = regs.rdi; |
|
|
|
|
regs._sys.rsp = regs.rsp; |
|
|
|
|
|
|
|
|
|
struct iovec iov = { ®s._sys, sizeof(regs._sys) }; |
|
|
|
|
ptrace(PTRACE_SETREGSET, proc.pid, NT_PRSTATUS, &iov); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
is_call_instruction(long word) |
|
|
|
|
{ |
|
|
|
|
// It's a call if:
|
|
|
|
|
// first byte == 0xe8
|
|
|
|
|
// first byte == 0xff AND "reg field" (bit 3-5 in next byte) == 2 or 3
|
|
|
|
|
// REX.W + 0xff/3 ????? TODO TODO TODO
|
|
|
|
|
|
|
|
|
|
u8 first_byte = word & 0xFF; |
|
|
|
|
if (first_byte == 0xE8) { |
|
|
|
|
return 1; |
|
|
|
|
} else if (first_byte == 0xFF) { |
|
|
|
|
u8 second_byte = word & 0xFF00UL; |
|
|
|
|
u8 reg = second_byte & 0x38; // 111000 (to extract bits 3-5)
|
|
|
|
|
if (reg == 2 || reg == 3) { |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static long |
|
|
|
|
place_breakpoint_at(struct mi_process proc, u64 address) |
|
|
|
|
{ |
|
|
|
|
long saved_instruction = ptrace(PTRACE_PEEKDATA, proc.pid, address, NULL); |
|
|
|
|
long int3_byte = 0x000000000000CC; |
|
|
|
|
long int3_word = (saved_instruction & 0xFFFFFFFFFFFFFF00) | int3_byte; |
|
|
|
|
|
|
|
|
|
/* write 0xcc */ |
|
|
|
|
ptrace(PTRACE_POKEDATA, proc.pid, address, int3_word); |
|
|
|
|
|
|
|
|
|
return(saved_instruction); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
run_until_breakpoint_and_restore(struct mi_process proc, u64 address, long saved_instruction) |
|
|
|
|
{ |
|
|
|
|
/* wait till child hits the interrupt */ |
|
|
|
|
ptrace(PTRACE_CONT, proc.pid, 0, 0); |
|
|
|
|
waitpid(proc.pid, 0, 0); |
|
|
|
|
|
|
|
|
|
/* restore original instrucion */ |
|
|
|
|
ptrace(PTRACE_POKEDATA, proc.pid, address, saved_instruction); |
|
|
|
|
|
|
|
|
|
/* step back to original instruction */ |
|
|
|
|
struct mi_registers regs = get_process_registers(proc); |
|
|
|
|
regs.rip -= 1; |
|
|
|
|
set_process_registers(proc, regs); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static u64 |
|
|
|
|
get_address_of_subroutine(struct mi_process proc, char *sr) |
|
|
|
|
{ |
|
|
|
@ -42,7 +136,12 @@ read_file_mmap(char *path)
@@ -42,7 +136,12 @@ read_file_mmap(char *path)
|
|
|
|
|
|
|
|
|
|
struct stat s; |
|
|
|
|
int fd = open(path, O_RDONLY); |
|
|
|
|
assert(fd != -1); |
|
|
|
|
|
|
|
|
|
if (fd == -1) { |
|
|
|
|
printf("File not found: %s\n", path); |
|
|
|
|
DIE("open() failed\n"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fstat(fd, &s); |
|
|
|
|
|
|
|
|
|
result.data = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0); |
|
|
|
@ -146,47 +245,6 @@ process_create(char *path)
@@ -146,47 +245,6 @@ process_create(char *path)
|
|
|
|
|
return(result); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static struct mi_registers |
|
|
|
|
get_process_registers(struct mi_process proc) |
|
|
|
|
{ |
|
|
|
|
struct user_regs_struct regs = { 0 }; |
|
|
|
|
struct iovec iov = { ®s, sizeof(regs) }; |
|
|
|
|
struct mi_registers result = { 0 }; |
|
|
|
|
|
|
|
|
|
ptrace(PTRACE_GETREGSET, proc.pid, NT_PRSTATUS, &iov); |
|
|
|
|
|
|
|
|
|
result.rax = regs.rax; |
|
|
|
|
result.rip = regs.rip; |
|
|
|
|
result.rbp = regs.rbp; |
|
|
|
|
result.rbx = regs.rbx; |
|
|
|
|
result.rcx = regs.rcx; |
|
|
|
|
result.rdx = regs.rdx; |
|
|
|
|
result.rsi = regs.rsi; |
|
|
|
|
result.rdi = regs.rdi; |
|
|
|
|
result.rsp = regs.rsp; |
|
|
|
|
|
|
|
|
|
result._sys = regs; |
|
|
|
|
|
|
|
|
|
return(result); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
set_process_registers(struct mi_process proc, struct mi_registers regs) |
|
|
|
|
{ |
|
|
|
|
regs._sys.rax = regs.rax; |
|
|
|
|
regs._sys.rip = regs.rip; |
|
|
|
|
regs._sys.rbp = regs.rbp; |
|
|
|
|
regs._sys.rbx = regs.rbx; |
|
|
|
|
regs._sys.rcx = regs.rcx; |
|
|
|
|
regs._sys.rdx = regs.rdx; |
|
|
|
|
regs._sys.rsi = regs.rsi; |
|
|
|
|
regs._sys.rdi = regs.rdi; |
|
|
|
|
regs._sys.rsp = regs.rsp; |
|
|
|
|
|
|
|
|
|
struct iovec iov = { ®s._sys, sizeof(regs._sys) }; |
|
|
|
|
ptrace(PTRACE_SETREGSET, proc.pid, NT_PRSTATUS, &iov); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
print_current_instruction(struct mi_process proc) |
|
|
|
|
{ |
|
|
|
|