Created
June 27, 2013 14:55
-
-
Save 0x75/5877105 to your computer and use it in GitHub Desktop.
code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <string> | |
#include <grp.h> | |
#include <sys/user.h> | |
#include <assert.h> | |
// mach | |
#include <mach/mach.h> | |
#include <mach/mach_init.h> | |
#include <mach/mach_traps.h> | |
#include <mach/mach_types.h> | |
#include <mach/mach_vm.h> | |
#include <mach/vm_map.h> | |
#include <mach/task.h> | |
#include <mach/task_info.h> | |
#include <mach/thread_status.h> | |
#include <mach/thread_info.h> | |
#include <mach/exception.h> | |
#include <mach/exception_types.h> | |
//spawn | |
#include <spawn.h> | |
//#include <posix.h> | |
// ptrace | |
#include <signal.h> | |
#include <sys/wait.h> | |
#include <sys/ptrace.h> | |
#include "NdbgDefs.h" | |
#include "Breakpoint.h" | |
class Ndbg { | |
public: | |
std::string Name; // Process Name | |
std::string File; // Path to Binary File | |
std::string Args; // Args for File | |
pid_t pid; | |
task_t targetTask; | |
task_t our_port; | |
mach_port_t exception_port; | |
// List of Breakpoints | |
int BPID; // Number of active breakpoints | |
// std::list<Breakpoint> BL; | |
Ndbg(std::string NAME) { | |
Name = NAME; | |
our_port = -1; | |
BPID = 0; | |
} | |
Ndbg(int PID) { | |
Name = ""; | |
our_port = -1; | |
pid = (pid_t)PID; | |
BPID = 0; | |
} | |
// FIX ME constructor only needs string argument, but conflicts with Ndbg(std::string NAME) | |
Ndbg(std::string FILE, std::string ARGS) { | |
File = FILE; | |
Args = ARGS; | |
our_port = -1; | |
BPID = 0; | |
//launch_process(); | |
} | |
void check_privileges(void) { | |
struct group *mygroup; | |
mygroup = getgrnam("procmod"); | |
int permissionstatus = 0; | |
if (getuid() != 0) | |
permissionstatus = 1; | |
if (getegid() == mygroup->gr_gid) | |
permissionstatus = 0; | |
if (permissionstatus) { | |
fprintf(stderr, "[ERROR]: This program must be run as root or with procmod group permission\n"); | |
exit(1); | |
} | |
} | |
// PROCESS HANDLING | |
void launch_process(void) { | |
int PID, status; | |
mach_port_t port; | |
#ifdef DEBUG | |
printf("[DEBUG] Forking and executing %s %s\n", File.c_str(), Args.c_str()); | |
#endif | |
if((PID = fork()) == 0) { | |
ptrace(PT_TRACE_ME, 0, 0, 0); | |
execl(File.c_str(), "", 0); | |
} | |
else { | |
// get the task for the child process | |
task_for_pid(mach_task_self(), PID, &port); | |
pid = PID; | |
targetTask = port; | |
wait(&status); | |
#ifdef DEBUG | |
if(WIFSTOPPED(status)) | |
fprintf(stderr, "Process has stopped...\n"); | |
#endif | |
} | |
} | |
void continue_process() { | |
ptrace(PT_CONTINUE, pid, 0, 0); | |
} | |
void kill_process(int sig) { | |
if (kill(pid, sig) != 0) | |
printf("killfail\n"); | |
} | |
void kill_task(void) { | |
task_terminate(targetTask); | |
} | |
void kill_thread(int hthread) { | |
/* DANGEROUS DANGEROUS */ | |
// thread_terminate(getact_thread(hthread)); | |
} | |
void CreateProcess(void) { | |
printf("[DEBUG] Creating process %s %s\n", Name.c_str(), Args.c_str()); | |
posix_spawnattr_t attr; | |
int retval = 0; | |
size_t copied = 0; | |
short flags = 0; | |
cpu_type_t cpu = 0; | |
// default target is 64bits | |
cpu = CPU_TYPE_X86_64; | |
retval = posix_spawnattr_init (&attr); | |
// set process flags | |
// the new process will start in a suspended state and permissions reset to real uid/gid | |
flags = POSIX_SPAWN_RESETIDS | POSIX_SPAWN_START_SUSPENDED; | |
// disable ASLR, Snow Leopard will just ignore this flag | |
flags |= _POSIX_SPAWN_DISABLE_ASLR; | |
retval = posix_spawnattr_setflags(&attr, flags); | |
// reset signals | |
sigset_t no_signals; | |
sigset_t all_signals; | |
sigemptyset (&no_signals); | |
sigfillset (&all_signals); | |
posix_spawnattr_setsigmask(&attr, &no_signals); | |
posix_spawnattr_setsigdefault(&attr, &all_signals); | |
// set the target cpu to be used, due to fat binaries | |
retval = posix_spawnattr_setbinpref_np(&attr, 1, &cpu, &copied); | |
char *spawnedEnv[] = { NULL }; | |
int cmd_line_len = (int) strlen(Args.c_str()); | |
if (cmd_line_len >= ARG_MAX) { | |
fprintf(stderr, "[ERROR] arg list too long\n"); | |
exit(1); | |
} | |
if (cmd_line_len) { | |
// parse command line; | |
int i = 0; | |
char *p = strchr(Args.c_str(), ' '); | |
char *q = (char *)Args.c_str(); | |
char **argv = (char **)malloc(sizeof(char*) * 256); | |
while (p && i < 253) { | |
*p = '\0'; | |
argv[i++] = q; | |
q = p + 1; | |
p = strchr(q, ' '); | |
} | |
errno = 0; | |
argv[i] = q; | |
argv[i+1] = NULL; | |
printf("[DEBUG] Spawning %s %s %s\n", argv[0], argv[1], argv[2]); | |
fflush(stdout); | |
retval = posix_spawn(&pid, argv[0], NULL, &attr, argv, spawnedEnv); | |
if(retval) { | |
fprintf(stderr, "[ERROR] Could not spawn debuggee: %s\n", strerror(retval)); | |
exit(1); | |
} | |
free(argv); | |
} | |
else { | |
fflush(stdout); | |
// execute with no arguments | |
char *argv[] = {(char *)Name.c_str(), NULL}; | |
printf("[DEBUG] Spawning %s (no arguments)...\n", Name.c_str()); | |
retval = posix_spawnp(&pid, argv[0], NULL, &attr, argv, spawnedEnv); | |
if (retval) { | |
fprintf(stderr, "[ERROR] Could not spawn debuggee: %s\n", strerror(retval)); | |
exit(1); | |
} | |
} | |
// parent: initialize the mach port into the debugee | |
retval = attach(); | |
// failed to attach | |
if (retval == 0) { | |
kill(pid, SIGCONT); // leave no zombies behind! | |
kill(pid, SIGKILL); | |
} | |
assert(task_for_pid(mach_task_self(), pid, &targetTask) == KERN_SUCCESS); | |
suspend_all_threads(); | |
// and now we can continue the process, threads are still suspended! | |
kill(pid, SIGCONT); | |
fflush(stdout); | |
} | |
void kill_process(pid_t pid, int sig) { | |
kill(pid, sig); | |
} | |
pid_t get_pid(void) { | |
struct kinfo_proc *procs = NULL, *newprocs; | |
char thiscmd[MAXCOMLEN + 1]; | |
pid_t thispid; | |
int mib[4]; | |
size_t miblen; | |
int i, st, nprocs; | |
size_t size; | |
size = 0; | |
mib[0] = CTL_KERN; | |
mib[1] = KERN_PROC; | |
mib[2] = KERN_PROC_ALL; | |
mib[3] = 0; | |
miblen = 3; | |
sysctl(mib, (unsigned int)miblen, NULL, &size, NULL, 0); | |
do { | |
size += size / 10; | |
newprocs = (kinfo_proc *) realloc(procs, size); | |
if (newprocs == 0) { | |
if (procs) | |
free(procs); | |
printf("could not reallocate memory"); | |
} | |
procs = newprocs; | |
st = (int)sysctl(mib, (unsigned int)miblen, procs, &size, NULL, 0); | |
} | |
while (st == -1 && errno == ENOMEM); | |
nprocs = (int)size /sizeof(struct kinfo_proc); | |
/* Now print out the data */ | |
for (i = 0; i < nprocs; i++) { | |
thispid = procs[i].kp_proc.p_pid; | |
strncpy(thiscmd, procs[i].kp_proc.p_comm, MAXCOMLEN); | |
thiscmd[MAXCOMLEN] = '\0'; | |
if (strcmp(Name.c_str(), thiscmd) == 0) { | |
//printf("%d\t%s\n", thispid, thiscmd); | |
return(thispid); | |
pid = thispid; | |
} | |
} | |
/* Clean up */ | |
free(procs); | |
return(-1); | |
} | |
task_t getport() { | |
if(our_port == -1) { | |
task_t port; | |
assert(task_for_pid(mach_task_self(), pid, &port) == KERN_SUCCESS); | |
our_port = port; | |
} | |
return our_port; | |
} | |
int attach(void) { | |
our_port = -1; // each time we attach, get a new port | |
getport(); // make sure port gets set | |
exception_port = install_debug_port(); | |
if (exception_port == 0) | |
return 0; | |
return 1; | |
} | |
int detach(void) { | |
//fprintf(stderr, "detatch %x\n", pid); | |
mach_port_t me = mach_task_self(); | |
kern_return_t err = mach_port_deallocate(me, exception_port); | |
if(err != KERN_SUCCESS) { | |
printf("Failed to deallocate port!\n"); | |
if (err == KERN_INVALID_TASK){ | |
fprintf(stderr, "Invalid task\n"); | |
} | |
else if (err == KERN_INVALID_NAME) { | |
fprintf(stderr, "Invalid name\n"); | |
} | |
else if (err == KERN_INVALID_RIGHT) { | |
fprintf(stderr, "Invalid right\n"); | |
} | |
} | |
return 0; | |
} | |
// INFO OUTPUT | |
void print_host_info(void) { | |
host_name_port_t host; | |
kernel_version_t kv; | |
host_basic_info_data_t hinfo; | |
mach_msg_type_number_t count; | |
char *cpu_type, *cpu_type_name, *cpu_subtype_name; | |
vm_size_t page_size; | |
host = mach_host_self(); | |
assert(host_kernel_version(host, kv) == KERN_SUCCESS); | |
// EXIT ON MACH ERROR | |
count = HOST_BASIC_INFO_COUNT; | |
assert(host_info(host, HOST_BASIC_INFO, (host_info_t) &hinfo, &count) == KERN_SUCCESS); | |
// EXIT ON MACH ERR | |
assert(host_page_size(host, &page_size) == KERN_SUCCESS); | |
// EXIT ... | |
printf("\n\n\n[DEBUG] HOST INFO\n\n"); | |
printf("%s\n", kv); | |
slot_name(hinfo.cpu_type, hinfo.cpu_subtype, &cpu_type_name, &cpu_subtype_name); | |
printf("cpu %s (%s, type=0x%x subtype=0x%x, threadtype = 0x%x)\n", cpu_type_name, cpu_subtype_name,hinfo.cpu_type, hinfo.cpu_subtype, hinfo.cpu_threadtype); | |
printf("max_cpus\t\t%d\n", hinfo.max_cpus); | |
printf("available cpus\t\t%d\n", hinfo.avail_cpus); | |
printf("physical_cpu\t\t%d\n", hinfo.physical_cpu); | |
printf("physical_cpu_max\t%d\n", hinfo.physical_cpu_max); | |
printf("logical_cpu\t\t%d\n", hinfo.logical_cpu); | |
printf("logical_cpu_max\t\t%d\n", hinfo.logical_cpu_max); | |
printf("memory size\t%u MB\n", (hinfo.memory_size >> 20)); | |
printf("max mem\t\t%u MB\n", (unsigned int)(hinfo.max_mem >> 20)); | |
printf("page size\t%u bytes\n\n",(unsigned int) page_size); | |
//hinfo.cpu_type; | |
} | |
void print_process_info() { | |
thread_act_port_array_t thread_list; | |
mach_msg_type_number_t thread_count; | |
task_threads(targetTask, &thread_list, &thread_count); | |
printf("[DEBUG] Process runs %d threads\n\n", thread_count); | |
} | |
int print_task_info () { | |
/* | |
task_basic_info_t taskinfo; | |
mach_msg_type_number_t count; | |
if (task_info(targetTask, TASK_BASIC_INFO, taskinfo, &count) != KERN_SUCCESS) | |
fprintf(stderr, "[ERROR] print_task_info() failed while trying to print task info!\n"); | |
else { | |
printf ("----> %i\n", taskinfo->suspend_count); | |
} | |
*/ | |
return(0); | |
} | |
void print_thread_info(unsigned int thread, int thread_num) { | |
unsigned int size = THREAD_BASIC_INFO_COUNT; | |
struct thread_basic_info info; | |
assert(thread_info(thread, THREAD_BASIC_INFO, (thread_info_t) &info, &size) == KERN_SUCCESS); | |
printf ("[DEBUG] THREAD INFO THREAD %i\n", thread_num); | |
// RUN STATE | |
switch (info.run_state) { | |
case TH_STATE_RUNNING: | |
printf("Thread is running normally\n"); | |
break; | |
case TH_STATE_STOPPED: | |
printf("Thread is stopped\n"); | |
break; | |
case TH_STATE_WAITING: | |
printf("Thread is waiting normally\n"); | |
break; | |
case TH_STATE_UNINTERRUPTIBLE: | |
printf("Thread is in an uninterruptible wait state\n"); | |
break; | |
case TH_STATE_HALTED: | |
printf("Thread is halted\n"); | |
break; | |
default: | |
break; | |
} | |
// FLAGS | |
if (info.flags & TH_FLAGS_IDLE) | |
printf("Thread %i is idle\n", thread_num); | |
else if (info.flags & TH_FLAGS_SWAPPED) | |
printf("Thread %i is swapped out\n", thread_num); | |
printf("CPU usage %i\n", (int)info.cpu_usage); | |
printf("Suspend count %i\n", (int)info.suspend_count); | |
printf("Sleep time %i\n", (int)info.sleep_time); | |
printf("\n"); | |
} | |
int print_all_threads_info(void) { | |
#if DEBUG | |
printf("[DEBUG] Printing basic info for all threads...\n"); | |
#endif | |
thread_act_port_array_t thread_list; | |
mach_msg_type_number_t thread_count,i; | |
assert(task_threads(targetTask, &thread_list, &thread_count) == KERN_SUCCESS); | |
if (thread_count > 0) { | |
i = 0; | |
while (i < thread_count) { | |
print_thread_info(thread_list[i], i); | |
i++; | |
} | |
} | |
return(0); | |
} | |
// THREAD HANDLING | |
int suspend_thread(unsigned int thread) { | |
assert(thread_suspend(thread) == KERN_SUCCESS); | |
return(0); | |
} | |
void suspend_all_threads(void) { | |
#if DEBUG | |
printf("[DEBUG] Suspending all threads...\n"); | |
#endif | |
thread_act_port_array_t thread_list; | |
mach_msg_type_number_t thread_count,i; | |
assert(task_threads(targetTask, &thread_list, &thread_count) == KERN_SUCCESS); | |
if (thread_count > 0) { | |
i = thread_count; | |
while (i--) { | |
suspend_thread(thread_list[i]); | |
} | |
} | |
} | |
bool check_thread_state(unsigned thread, int state) { | |
unsigned int size = THREAD_BASIC_INFO_COUNT; | |
struct thread_basic_info info; | |
assert(thread_info(thread, THREAD_BASIC_INFO, (thread_info_t) &info, &size) == KERN_SUCCESS); | |
if (info.run_state != state) | |
return(false); | |
return (true); | |
} | |
bool check_all_thread_states(int state) { | |
#if DEBUG | |
printf("[DEBUG] Checking run_state of all threads...\n"); | |
#endif | |
thread_act_port_array_t thread_list; | |
mach_msg_type_number_t thread_count, i; | |
assert(task_threads(targetTask, &thread_list, &thread_count) == KERN_SUCCESS); | |
if (thread_count > 0) { | |
i = thread_count; | |
while (i--) { | |
if (check_thread_state((thread_list[i]), state) == false) | |
return (false); | |
} | |
} | |
return (true); | |
} | |
int resume_thread(unsigned int thread) { | |
unsigned int size = THREAD_BASIC_INFO_COUNT; | |
struct thread_basic_info info; | |
assert(thread_info(thread, THREAD_BASIC_INFO, (thread_info_t) &info, &size) == KERN_SUCCESS); | |
int i; | |
for(i = 0; i < info.suspend_count; i++) { | |
assert(thread_resume(thread) == KERN_SUCCESS); | |
} | |
return 0; | |
} | |
void resume_all_threads(void) { | |
#if DEBUG | |
printf("[DEBUG] Resuming all threads...\n"); | |
#endif | |
thread_act_port_array_t thread_list; | |
mach_msg_type_number_t thread_count,i; | |
assert(task_threads(targetTask, &thread_list, &thread_count) == KERN_SUCCESS); | |
if (thread_count > 0) { | |
i = thread_count; | |
while (i--) { | |
resume_thread(thread_list[i]); | |
} | |
} | |
} | |
void startDBG(void) { | |
mach_msg_server(exception_port); | |
} | |
// MACH EXCEPTION HANDLING | |
private: | |
void mach_msg_server(mach_port_t exception_port) { | |
mach_msg_return_t r; | |
r = mach_msg(&msg.head, MACH_RCV_MSG|MACH_RCV_LARGE|MACH_RCV_TIMEOUT, 0, sizeof(msg), exception_port, 0, MACH_PORT_NULL); | |
assert(r != MACH_RCV_TIMED_OUT); | |
assert (r == MACH_MSG_SUCCESS); | |
mach_exc_server(&msg.head, &reply.head); | |
r = mach_msg(&reply.head, MACH_SEND_MSG|MACH_SEND_TIMEOUT, reply.head.msgh_size, 0, MACH_PORT_NULL, 0 ,MACH_PORT_NULL); | |
assert(r != MACH_SEND_TIMED_OUT); | |
assert(r == MACH_MSG_SUCCESS); | |
} | |
mach_port_t install_debug_port(void) { | |
mach_port_t *exceptionPort = (mach_port_t *) malloc(sizeof(mach_port_t)); | |
mach_port_t me; | |
exception_mask_t mask = EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT | EXC_MASK_SYSCALL; | |
// Create a port by allocating a receive right, and then create a send right | |
// accessible under the same name. | |
me = mach_task_self(); | |
mach_assert("mach_port_allocate()", mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, exceptionPort)); | |
mach_assert("mach_port_insert_right()", mach_port_insert_right(me, *exceptionPort, *exceptionPort, MACH_MSG_TYPE_MAKE_SEND)); | |
/* get the old exception ports */ | |
mach_assert("mach_get_exception_ports()", task_get_exception_ports(targetTask, mask, old_exc_ports.masks, &old_exc_ports.count, old_exc_ports.ports, old_exc_ports.behaviors, old_exc_ports.flavors)); | |
/* set the new exception port */ | |
mach_assert("task_set_exception_ports()", task_set_exception_ports(targetTask, mask, *exceptionPort, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE)); | |
return *exceptionPort; | |
} | |
public: | |
// DEBUGGER FUNCTIONALITY | |
int GetThreadRegs(int hThread, REGISTERS *REG) { | |
mach_msg_type_number_t count; | |
#if defined (__arm__) | |
arm_thread_state_t state; | |
count = ARM_THREAD_STATE_COUNT; | |
thread_get_state(hThread, ARM_THREAD_STATE, (thread_state_t) &state, &count); | |
REG->R0 = state.__r[0]; | |
REG->R1 = state.__r[1]; | |
REG->R2 = state.__r[2]; | |
REG->R3 = state.__r[3]; | |
REG->R4 = state.__r[4]; | |
REG->R5 = state.__r[5]; | |
REG->R6 = state.__r[6]; | |
REG->R7 = state.__r[7]; | |
REG->R8 = state.__r[8]; | |
REG->R9 = state.__r[9]; | |
REG->R10 = state.__r[10]; | |
REG->R11 = state.__r[11]; | |
REG->R12 = state.__r[12]; | |
REG->SP = state.__sp; | |
REG->LR = state.__lr; | |
REG->PC = state.__pc; | |
REG->CPSR = state.__cpsr; | |
// FIXMEARM: add debug registers ? | |
#elif defined (__x86_64__) | |
x86_thread_state64_t state; | |
count = x86_THREAD_STATE64_COUNT; | |
thread_get_state(hThread, x86_THREAD_STATE64, (thread_state_t) &state, &count); | |
REG->Rax = state.__rax; | |
REG->Rbx = state.__rbx; | |
REG->Rcx = state.__rcx; | |
REG->Rdx = state.__rdx; | |
REG->Rdi = state.__rdi; | |
REG->Rsi = state.__rsi; | |
REG->Rbp = state.__rbp; | |
REG->Rsp = state.__rsp; | |
REG->Rip = state.__rip; | |
REG->R8 = state.__r8; | |
REG->R9 = state.__r9; | |
REG->R10 = state.__r10; | |
REG->R11 = state.__r11; | |
REG->R12 = state.__r12; | |
REG->R13 = state.__r13; | |
REG->R14 = state.__r14; | |
REG->R15 = state.__r15; | |
REG->SegCs = state.__cs; | |
REG->SegFs = state.__fs; | |
REG->SegGs = state.__gs; | |
REG->RFlags = state.__rflags; | |
x86_debug_state64_t debug; | |
count = x86_DEBUG_STATE64_COUNT; | |
thread_get_state(hThread, x86_DEBUG_STATE64, (thread_state_t) &debug, &count); | |
REG->Dr0 = debug.__dr0; | |
REG->Dr1 = debug.__dr1; | |
REG->Dr2 = debug.__dr2; | |
REG->Dr3 = debug.__dr3; | |
REG->Dr6 = debug.__dr6; | |
REG->Dr7 = debug.__dr7; | |
#elif defined (__i386__) | |
i386_thread_state_t state; | |
count = i386_THREAD_STATE_COUNT; | |
thread_get_state(hThread, i386_THREAD_STATE, (thread_state_t) &state, &count); | |
REG->Eax = state.__eax; | |
REG->Ebx = state.__ebx; | |
REG->Ecx = state.__ecx; | |
REG->Edx = state.__edx; | |
REG->Edi = state.__edi; | |
REG->Esi = state.__esi; | |
REG->Ebp = state.__ebp; | |
REG->Esp = state.__esp; | |
REG->Eip = state.__eip; | |
REG->SegSs = state.__ss; | |
REG->SegCs = state.__cs; | |
REG->SegDs = state.__ds; | |
REG->SegEs = state.__es; | |
REG->SegFs = state.__fs; | |
REG->SegGs = state.__gs; | |
REG->EFlags = state.__eflags; | |
x86_debug_state32_t debug; | |
count = x86_DEBUG_STATE32_COUNT; | |
thread_get_state(hThread, x86_DEBUG_STATE32, (thread_state_t) &debug, &count); | |
REG->Dr0 = debug.__dr0; | |
REG->Dr1 = debug.__dr1; | |
REG->Dr2 = debug.__dr2; | |
REG->Dr3 = debug.__dr3; | |
REG->Dr6 = debug.__dr6; | |
REG->Dr7 = debug.__dr7; | |
#endif | |
return 1; | |
} | |
int SetThreadRegs(int hThread, const REGISTERS* REG) { | |
mach_msg_type_number_t count; | |
#if defined (__x86_64__) | |
x86_thread_state64_t state; | |
state.__rax = REG->Rax; | |
state.__rbx = REG->Rbx; | |
state.__rcx = REG->Rcx; | |
state.__rdx = REG->Rdx; | |
state.__rdi = REG->Rdi; | |
state.__rsi = REG->Rsi; | |
state.__rbp = REG->Rbp; | |
state.__rsp = REG->Rsp; | |
state.__rip = REG->Rip; | |
state.__r8 = REG->R8; | |
state.__r9 = REG->R9; | |
state.__r10 = REG->R10; | |
state.__r11 = REG->R11; | |
state.__r12 = REG->R12; | |
state.__r13 = REG->R13; | |
state.__r14 = REG->R14; | |
state.__r15 = REG->R15; | |
state.__cs = REG->SegCs; | |
state.__fs = REG->SegFs; | |
state.__gs = REG->SegGs; | |
state.__rflags = REG->RFlags; | |
count = x86_THREAD_STATE64_COUNT; | |
if (thread_set_state(hThread, x86_THREAD_STATE64, (thread_state_t) &state, count) != KERN_SUCCESS) { | |
fprintf(stderr, "[ERROR] 64bits thread set state failed!\n"); | |
return 0; | |
} | |
x86_debug_state64_t debug; | |
debug.__dr0 = REG->Dr0; | |
debug.__dr1 = REG->Dr1; | |
debug.__dr2 = REG->Dr2; | |
debug.__dr3 = REG->Dr3; | |
debug.__dr6 = REG->Dr6; | |
debug.__dr7 = REG->Dr7; | |
count = x86_DEBUG_STATE64_COUNT; | |
if (thread_set_state(hThread, x86_DEBUG_STATE64, (thread_state_t) &debug, count) != KERN_SUCCESS) { | |
fprintf(stderr, "[ERROR] 64bits thread set state debug failed!\n"); | |
return -1; | |
} | |
#elif defined (__i386__) | |
i386_thread_state_t state; | |
count = i386_THREAD_STATE_COUNT; | |
thread_get_state(hThread, i386_THREAD_STATE, (thread_state_t) &state, &count); | |
REG->Eax = state.__eax; | |
REG->Ebx = state.__ebx; | |
REG->Ecx = state.__ecx; | |
REG->Edx = state.__edx; | |
REG->Edi = state.__edi; | |
REG->Esi = state.__esi; | |
REG->Ebp = state.__ebp; | |
REG->Esp = state.__esp; | |
REG->Eip = state.__eip; | |
REG->SegSs = state.__ss; | |
REG->SegCs = state.__cs; | |
REG->SegDs = state.__ds; | |
REG->SegEs = state.__es; | |
REG->SegFs = state.__fs; | |
REG->SegGs = state.__gs; | |
REG->EFlags = state.__eflags; | |
x86_debug_state32_t debug; | |
count = x86_DEBUG_STATE32_COUNT; | |
thread_get_state(hThread, x86_DEBUG_STATE32, (thread_state_t) &debug, &count); | |
REG->Dr0 = debug.__dr0; | |
REG->Dr1 = debug.__dr1; | |
REG->Dr2 = debug.__dr2; | |
REG->Dr3 = debug.__dr3; | |
REG->Dr6 = debug.__dr6; | |
REG->Dr7 = debug.__dr7; | |
#endif | |
return 1; | |
} | |
Breakpoint SetBreakPoint(uint64_t Address) { | |
BPID++; | |
Breakpoint B; | |
B.ID = BPID; | |
B.address = Address; | |
B.active = true; | |
B.max_hits = -1; | |
B.description = ""; | |
B.Orig_Inst = 0; | |
B.hitcount = 0; | |
mach_assert("mach_vm_protect()", mach_vm_protect(targetTask, B.address, 1, false, VM_PROT_READ | VM_PROT_WRITE)); | |
mach_vm_size_t nread; | |
mach_assert("mach_vm_read_overwrite()", mach_vm_read_overwrite(targetTask, B.address, 1, (mach_vm_address_t) &B.Orig_Inst, &nread)); | |
unsigned char BP = {0xCC}; | |
mach_assert("mach_vm_write()", mach_vm_write(targetTask, B.address, (vm_offset_t) &BP, 1)); | |
mach_assert("mach_vm_protect()", mach_vm_protect(targetTask, B.address, 1, false, VM_PROT_READ | VM_PROT_EXECUTE)); | |
return B; | |
} | |
Breakpoint SetBreakPoint(uint64_t Address, int mHits, std::string Description) { | |
BPID++; | |
Breakpoint B; | |
B.ID = BPID; | |
B.address = Address; | |
B.active = true; | |
B.max_hits = mHits; | |
B.description = Description; | |
mach_assert("mach_vm_protect()", mach_vm_protect(targetTask, B.address, 1, false, VM_PROT_READ | VM_PROT_WRITE)); | |
mach_vm_size_t nread; | |
mach_assert("mach_vm_read_overwrite()", mach_vm_read_overwrite(targetTask, B.address, 1, (mach_vm_address_t) &B.Orig_Inst, &nread)); | |
unsigned char BP = {0xCC}; | |
mach_assert("mach_vm_write()", mach_vm_write(targetTask, B.address, (vm_offset_t) &BP, 1)); | |
mach_assert("mach_vm_protect()", mach_vm_protect(targetTask, B.address, 1, false, VM_PROT_READ | VM_PROT_EXECUTE)); | |
return B; | |
} | |
void DelBreakPoint(Breakpoint B) { | |
BPID--; | |
mach_assert("mach_vm_protect()", mach_vm_protect(targetTask, B.address, 1, false, VM_PROT_READ | VM_PROT_WRITE)); | |
mach_assert("mach_vm_write()", mach_vm_write(targetTask, B.address, (vm_offset_t) &B.Orig_Inst, 1)); | |
mach_assert("mach_vm_protect()", mach_vm_protect(targetTask, B.address, 1, false, VM_PROT_READ | VM_PROT_EXECUTE)); | |
} | |
// Gets base address for Task //ugly work | |
vm_map_offset_t get_task_base_address() { | |
vm_map_offset_t vmoffset; | |
vm_map_size_t vmsize; | |
uint32_t nesting_depth = 0; | |
struct vm_region_submap_info_64 vbr; | |
mach_msg_type_number_t vbrcount = 16; | |
assert((mach_vm_region_recurse(targetTask, &vmoffset, &vmsize, &nesting_depth, (vm_region_recurse_info_t)&vbr, &vbrcount)) == KERN_SUCCESS); | |
return(vmoffset); | |
} | |
// int SetSingleStepping(void) {} | |
// int ContinueProcess(void) {} | |
// int Set_hardware_Breakpoint(int hthread, long address) {} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment