Skip to content

Instantly share code, notes, and snippets.

@0x75
Created June 27, 2013 14:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 0x75/5877105 to your computer and use it in GitHub Desktop.
Save 0x75/5877105 to your computer and use it in GitHub Desktop.
code
#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