turns out you have to offset the syscall instruction to rip, because PTRACE_CONT continue process by "returning" from syscall
This commit is contained in:
parent
0ae068762f
commit
635cf023c7
5 changed files with 48 additions and 4 deletions
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
UNINTERRUPTABLE_SLEEP = 'D',
|
||||
|
|
@ -62,6 +63,9 @@ int process_attach_all(process_status_t* threads, size_t thread_count);
|
|||
// detaches from all threads
|
||||
void process_detach_all(process_status_t* threads, size_t thread_count);
|
||||
|
||||
// calculate correct instruction pointer address for hijacking
|
||||
uintptr_t process_calculate_ip(process_status_t* thread, uintptr_t addr);
|
||||
|
||||
// read registers of thread. returns 0 on success, 1 on error
|
||||
int process_read_registers(process_status_t* thread, struct user_regs_struct* regs);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
.text
|
||||
hijack_destination:
|
||||
leaq redirect_msg(%rip), %rdi
|
||||
lea redirect_msg(%rip), %rdi
|
||||
call puts
|
||||
.sleep_loop:
|
||||
mov $0x1, %edi
|
||||
call sleep
|
||||
jmp .sleep_loop
|
||||
|
||||
.section rodata
|
||||
redirect_msg: .string "thread has been redirected to this function! cool!"
|
||||
.section .rodata
|
||||
redirect_msg: .asciz "thread has been redirected to this function! cool!"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
#define _DEFAULT_SOURCE
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern char *program_invocation_name;
|
||||
|
|
@ -51,8 +55,36 @@ __attribute__((noreturn)) void* slave3_job(void*)
|
|||
|
||||
extern void hijack_destination();
|
||||
|
||||
static struct sigaction sigill_old;
|
||||
static struct sigaction sigsegv_old;
|
||||
static void sigaction_handler(int signum, siginfo_t* info, void*)
|
||||
{
|
||||
fprintf(stderr, "got signal %d\n", signum);
|
||||
fprintf(stderr, "rip %p\n", info->si_addr);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// lets install some signal handlers
|
||||
// for sigsegv and sig illegal instruction
|
||||
struct sigaction sa;
|
||||
|
||||
// sigill
|
||||
memset(&sa, '\0', sizeof(sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = sigaction_handler;
|
||||
sigaction(SIGILL, &sa, &sigill_old);
|
||||
|
||||
// sigsegv
|
||||
memset(&sa, '\0', sizeof(sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = sigaction_handler;
|
||||
sigaction(SIGSEGV, &sa, &sigsegv_old);
|
||||
|
||||
status("master");
|
||||
printf("hijack_destination: %p\n", hijack_destination);
|
||||
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ int main(int argc, char** argv)
|
|||
if (process_read_registers(active, ®s))
|
||||
fprintf(stderr, "failed to read registers: %s\n", strerror(errno));
|
||||
// hijack instruction pointer to our destination
|
||||
regs.rip = (uintptr_t)destination;
|
||||
regs.rip = process_calculate_ip(active, (uintptr_t)destination);
|
||||
if (process_write_registers(active, ®s))
|
||||
fprintf(stderr, "failed to write registers: %s\n", strerror(errno));
|
||||
|
||||
|
|
|
|||
|
|
@ -283,6 +283,14 @@ void process_detach_all(process_status_t* threads, size_t thread_count)
|
|||
while (thread_count--) ptrace(PTRACE_DETACH, threads[thread_count].pid, NULL, NULL);
|
||||
}
|
||||
|
||||
// hardcoded syscall instruction size
|
||||
#define BJ_PTRACE_CONT_OFFSET 2
|
||||
|
||||
uintptr_t process_calculate_ip(process_status_t* thread, uintptr_t addr)
|
||||
{
|
||||
return addr + BJ_PTRACE_CONT_OFFSET;
|
||||
}
|
||||
|
||||
int process_read_registers(process_status_t* thread, struct user_regs_struct* regs)
|
||||
{
|
||||
struct iovec data = {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue