#include <mach/host_info.h>
#include <mach/mach_host.h>
#include <mach/shared_region.h>
#include <mach/mach.h>
#include <mach-o/dyld.h>
#include <stdlib.h>
#include <stdio.h>
#import <dlfcn.h>
#include <assert.h>
#include <errno.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#pragma mark read and write
/* Note : buffer must be free'd manually */
unsigned char * xnu_read (int pid, void* addr, size_t* size)
{
assert(*size != 0 || addr != 0);
*size = _word_align(*size);
unsigned char *rbuffer = (unsigned char*)malloc(*size);
if (rbuffer == 0)
printf("Allocation error : xnu_read \n");
mach_msg_type_number_t data_cnt;
mach_port_t task;
kern_return_t kernret = task_for_pid(mach_task_self(), pid, &task);
if (kernret != KERN_SUCCESS)
printf("Error : task_for_pid \n");
kernret = vm_read(task, (vm_address_t)addr, *size, (vm_offset_t*)&rbuffer, &data_cnt);
if(kernret != KERN_SUCCESS)
free(rbuffer);
return rbuffer;
}
int xnu_write (int pid, void* addr, unsigned char* data, size_t dsize)
{
assert(dsize != 0);
assert(addr != 0);
assert(data != 0);
dsize = _word_align(dsize);
unsigned char * ptxt = (unsigned char*)malloc(dsize);
assert(ptxt != 0);
memcpy(ptxt, data, dsize);
mach_port_t task;
//vm_info_region_t regbackup;
mach_msg_type_number_t dataCunt = dsize;
kern_return_t kret = task_for_pid(mach_task_self(), pid, &task);
//mach_vm_region_info(task, (vm_address_t)addr, ®backup,0 , 0);
/* retrieve write permision */
vm_protect(task, (vm_address_t)addr, (vm_size_t)dsize, 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_ALL);
kret = vm_write(task, (vm_address_t)addr, (pointer_t)ptxt, dataCunt);
return kret;
}
mach_error_t setpage_exec(void *address)
{
mach_error_t err = err_none;
vm_size_t pageSize;
host_page_size( mach_host_self(), &pageSize );
uintptr_t page = (uintptr_t)address & ~(uintptr_t)(pageSize-1);
int e = err_none;
e |= mprotect((void *)page, pageSize, PROT_EXEC | PROT_READ);
e |= msync((void *)page, pageSize, MS_INVALIDATE );
if (e) {
printf("Cannot create executable page\n");
}
return err;
}
size_t _word_align(size_t size)
{
size_t rsize = 0;
rsize = ((size % sizeof(long)) > 0) ? (sizeof(long) - (size % sizeof(long))) : 0;
rsize += size;
return rsize;
}
/* Mach-O format related functions */
#pragma mark macho
__uint64_t getAddressOfLibrary( char* libraryPath )
{
const struct mach_header* mh;
int n = _dyld_image_count();
int i = 0;
for( i = 0; i < n; i++ )
{
mh = _dyld_get_image_header(i);
if( mh->filetype != MH_DYLIB ){ continue; }
const char* imageName = _dyld_get_image_name(i);
printf("%s\n",imageName);
if( strcmp(imageName, libraryPath) == 0 )
{
struct segment_command_64* seg;
struct load_command* cmd;
cmd = (struct load_command*)((char*)mh + sizeof(struct mach_header_64));
int j = 0;
for( j = 0; j < mh->ncmds; j++ )
{
if( cmd->cmd == LC_SEGMENT_64 )
{
seg = (struct segment_command_64*)cmd;
if( strcmp(seg->segname, SEG_TEXT) == 0 )
{
return seg->vmaddr + (__uint64_t)_dyld_get_image_vmaddr_slide(i);
}
}
cmd = (struct load_command*)((char*)cmd + cmd->cmdsize);
}
return _dyld_get_image_vmaddr_slide(i);
}
}
return 0;
}
/* Retrieve symbol pointer at runtime */
__uint64_t getAddressOfSymbol(char* libpath, char * symbol)
{
void* hlib = dlopen(libpath, RTLD_NOW);
void* funcaddr64 = dlsym(hlib, symbol);
return (unsigned long long)funcaddr64;
}
#pragma mark processes
int32_t procpid (char* procname)
{
pid_t pid;
int j;
kinfo_proc * proclist;
size_t procCount;
getprocessList(&proclist, &procCount);
for (j = 0; j < procCount +1; j++) {
if (strcmp(proclist[j].kp_proc.p_comm, procname) == 0 )
pid = proclist[j].kp_proc.p_pid;
}
free(proclist);
return pid;
}
static int getprocessList(kinfo_proc **procList, size_t *procCount)
{
int err;
kinfo_proc * result;
int done;
static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
size_t length;
assert( procList != NULL);
//assert(*procList == NULL);
assert(procCount != NULL);
*procCount = 0;
result = NULL;
done = 0;
do {
assert(result == NULL);
length = 0;
err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1,
NULL, &length,
NULL, 0);
if (err == -1) {
err = errno;
}
if (err == 0) {
result = malloc(length);
if (result == NULL) {
err = ENOMEM;
}
}
if (err == 0) {
err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1,
result, &length,
NULL, 0);
if (err == -1) {
err = errno;
}
if (err == 0) {
done = 1;
} else if (err == ENOMEM) {
assert(result != NULL);
free(result);
result = NULL;
err = 0;
}
}
} while (err == 0 && ! done);
if (err != 0 && result != NULL) {
free(result);
result = NULL;
}
*procList = result;
if (err == 0) {
*procCount = length / sizeof(kinfo_proc);
}
assert( (err == 0) == (*procList != NULL) );
return err;
}