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/types.h>
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UNINTERRUPTABLE_SLEEP = 'D',
|
UNINTERRUPTABLE_SLEEP = 'D',
|
||||||
|
|
@ -62,6 +63,9 @@ int process_attach_all(process_status_t* threads, size_t thread_count);
|
||||||
// detaches from all threads
|
// detaches from all threads
|
||||||
void process_detach_all(process_status_t* threads, size_t thread_count);
|
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
|
// read registers of thread. returns 0 on success, 1 on error
|
||||||
int process_read_registers(process_status_t* thread, struct user_regs_struct* regs);
|
int process_read_registers(process_status_t* thread, struct user_regs_struct* regs);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
.text
|
.text
|
||||||
hijack_destination:
|
hijack_destination:
|
||||||
leaq redirect_msg(%rip), %rdi
|
lea redirect_msg(%rip), %rdi
|
||||||
call puts
|
call puts
|
||||||
.sleep_loop:
|
.sleep_loop:
|
||||||
mov $0x1, %edi
|
mov $0x1, %edi
|
||||||
call sleep
|
call sleep
|
||||||
jmp .sleep_loop
|
jmp .sleep_loop
|
||||||
|
|
||||||
.section rodata
|
.section .rodata
|
||||||
redirect_msg: .string "thread has been redirected to this function! cool!"
|
redirect_msg: .asciz "thread has been redirected to this function! cool!"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
|
#define _DEFAULT_SOURCE
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
extern char *program_invocation_name;
|
extern char *program_invocation_name;
|
||||||
|
|
@ -51,8 +55,36 @@ __attribute__((noreturn)) void* slave3_job(void*)
|
||||||
|
|
||||||
extern void hijack_destination();
|
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()
|
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");
|
status("master");
|
||||||
printf("hijack_destination: %p\n", hijack_destination);
|
printf("hijack_destination: %p\n", hijack_destination);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ int main(int argc, char** argv)
|
||||||
if (process_read_registers(active, ®s))
|
if (process_read_registers(active, ®s))
|
||||||
fprintf(stderr, "failed to read registers: %s\n", strerror(errno));
|
fprintf(stderr, "failed to read registers: %s\n", strerror(errno));
|
||||||
// hijack instruction pointer to our destination
|
// 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))
|
if (process_write_registers(active, ®s))
|
||||||
fprintf(stderr, "failed to write registers: %s\n", strerror(errno));
|
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);
|
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)
|
int process_read_registers(process_status_t* thread, struct user_regs_struct* regs)
|
||||||
{
|
{
|
||||||
struct iovec data = {
|
struct iovec data = {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue