Last active
October 8, 2015 13:53
-
-
Save ytlvy/f54550d45c90f723b2aa to your computer and use it in GitHub Desktop.
xnu 内存读写模块
This file contains hidden or 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 <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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment