// Read/write from a Mach data segment. static int machsegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr) { mach_port_t task; int r; task = idtotask(map->pid); if(task == -1) return -1; if(isr){ vm_size_t nn; nn = n; if(me(vm_read_overwrite(task, addr, n, (uintptr)v, &nn)) < 0) return -1; return nn; }else{ r = vm_write(task, addr, (uintptr)v, n); if(r == KERN_INVALID_ADDRESS){ // Happens when writing to text segment. // Change protections. if(me(vm_protect(task, addr, n, 0, VM_PROT_WRITE|VM_PROT_READ|VM_PROT_EXECUTE)) < 0){ fprint(2, "vm_protect: %s\n", r); return -1; } r = vm_write(task, addr, (uintptr)v, n); } if(r != 0){ me(r); return -1; } return n; } }
/** * (Safely) read len bytes from @a source, storing in @a dest. * * @param task The task from which data from address @a source will be read. * @param source The address within @a task from which the data will be read. * @param dest The destination address to which copied data will be written. * @param len The number of bytes to be read. * * @return On success, returns KERN_SUCCESS. If the pages containing @a source + len are unmapped, KERN_INVALID_ADDRESS * will be returned. If the pages can not be read due to access restrictions, KERN_PROTECTION_FAILURE will be returned. * * @warning Unlike all other plcrash_* functions, plcrash_async_read_addr returns a kern_return_t value. * @todo Modify plcrash_async_read_addr and all API clients to use plcrash_error_t values. */ kern_return_t plcrash_async_read_addr (mach_port_t task, pl_vm_address_t source, void *dest, pl_vm_size_t len) { #ifdef PL_HAVE_MACH_VM pl_vm_size_t read_size = len; return mach_vm_read_overwrite(task, source, len, (pointer_t) dest, &read_size); #else vm_size_t read_size = len; return vm_read_overwrite(task, source, len, (pointer_t) dest, &read_size); #endif }
kern_return_t ksmach_copyMem(const void* const src, void* const dst, const int numBytes) { vm_size_t bytesCopied = 0; return vm_read_overwrite(mach_task_self(), (vm_address_t)src, (vm_size_t)numBytes, (vm_address_t)dst, &bytesCopied); }
static int __read(RIO *io, RIODesc *fd, ut8 *buf, int len) { vm_size_t size = 0; int err = vm_read_overwrite (RIOMACH_TASK (fd->data), (vm_offset_t)io->off, len, (pointer_t)buf, &size); if (err == -1) { eprintf ("Cannot read\n"); return -1; } return (int)size; }
static int __read(RIO *io, RIODesc *fd, ut8 *buf, int len) { vm_size_t size = 0; int blen, err, copied = 0; int blocksize = 32; RIOMach *riom = (RIOMach *)fd->data; if (task_is_dead (riom->pid)) { return -1; } memset (buf, 0xff, len); if (RIOMACH_PID (fd->data) == 0) { if (io->off < 4096) { return len; } } copied = getNextValid (io, fd, io->off) - io->off; if (copied < 0) copied = 0; while (copied < len) { blen = R_MIN ((len - copied), blocksize); //blen = len; err = vm_read_overwrite (RIOMACH_TASK (fd->data), (ut64)io->off + copied, blen, (pointer_t)buf + copied, &size); switch (err) { case KERN_PROTECTION_FAILURE: //eprintf ("r_io_mach_read: kern protection failure.\n"); break; case KERN_INVALID_ADDRESS: if (blocksize == 1) { memset (buf+copied, 0xff, len-copied); return size+copied; } blocksize = 1; blen = 1; buf[copied] = 0xff; break; } if (err == -1 || size < 1) { return -1; } if (size == 0) { if (blocksize == 1) { memset (buf+copied, 0xff, len-copied); return len; } blocksize = 1; blen = 1; buf[copied] = 0xff; } copied += blen; } return len; }
kern_return_t Task_readMemory(Task* self, VMAddr addr, void* data, vm_size_t length) { kern_return_t retVal = KERN_INVALID_ARGUMENT; if (self == NULL || data == NULL) { Log_invalidArgument("self: %p, data: %p", self, data); } else { vm_size_t count = length; retVal = vm_read_overwrite(self->task, addr, length, (vm_address_t) data, &count); if (retVal != KERN_SUCCESS || length != count) { Log_errorMach(retVal, "vm_read_overwrite"); } } return retVal; }
static bool readProcessMemory(const mach_port_t &task, const vm_address_t &from, const vm_size_t &size, vm_address_t to) { vm_size_t bytes; auto status = vm_read_overwrite(task, from, size, to, &bytes); if (status != KERN_SUCCESS) { return false; } if (bytes != size) { return false; } return true; }
static int __read(RIO *io, RIODesc *fd, ut8 *buf, int len) { vm_size_t size = 0; int blen, err, copied = 0; int blocksize = 32; if (RIOMACH_PID (fd->data) == 0) { if (io->off<4096) return len; } memset (buf, 0xff, len); while (copied<len) { blen = R_MIN ((len-copied), blocksize); //blen = len; err = vm_read_overwrite (RIOMACH_TASK (fd->data), (ut64)io->off+copied, blen, (pointer_t)buf+copied, &size); switch (err) { case KERN_PROTECTION_FAILURE: //eprintf ("r_io_mach_read: kern protection failure.\n"); break; case KERN_INVALID_ADDRESS: if (blocksize == 1) { memset (buf+copied, 0xff, len-copied); return size+copied; } blocksize = 1; blen = 1; buf[copied] = 0xff; //eprintf("invaddr %d\n",len); break; } if (err == -1) { //eprintf ("Cannot read\n"); return -1; } if (size==0) { if (blocksize == 1) { memset (buf+copied, 0xff, len-copied); return len; //size+copied; } blocksize = 1; blen = 1; buf[copied] = 0xff; } //if (size != blen) { return size+copied; } copied += blen; } return len; //(int)size; }
uint8_t* _yr_fetch_block_data( YR_MEMORY_BLOCK* block) { YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) block->context; vm_size_t size = block->size; if (context->buffer_size < block->size) { if (context->buffer != NULL) yr_free(context->buffer); context->buffer = yr_malloc(block->size); if (context->buffer != NULL) { context->buffer_size = block->size; } else { context->buffer_size = 0; return NULL; } } if (vm_read_overwrite( context->task, block->base, block->size, (vm_address_t) context->buffer, &size) != KERN_SUCCESS) { return NULL; } return context->buffer; }
int yr_process_get_memory( pid_t pid, YR_MEMORY_BLOCK** first_block) { task_t task; kern_return_t kr; vm_size_t size = 0; vm_address_t address = 0; vm_region_basic_info_data_64_t info; mach_msg_type_number_t info_count; mach_port_t object; unsigned char* data; YR_MEMORY_BLOCK* new_block; YR_MEMORY_BLOCK* current_block = NULL; *first_block = NULL; if ((kr = task_for_pid(mach_task_self(), pid, &task)) != KERN_SUCCESS) return ERROR_COULD_NOT_ATTACH_TO_PROCESS; do { info_count = VM_REGION_BASIC_INFO_COUNT_64; kr = vm_region_64( task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t) &info, &info_count, &object); if (kr == KERN_SUCCESS) { data = (unsigned char*) yr_malloc(size); if (data == NULL) return ERROR_INSUFICIENT_MEMORY; if (vm_read_overwrite( task, address, size, (vm_address_t) data, &size) == KERN_SUCCESS) { new_block = (YR_MEMORY_BLOCK*) yr_malloc(sizeof(YR_MEMORY_BLOCK)); if (new_block == NULL) { yr_free(data); return ERROR_INSUFICIENT_MEMORY; } if (*first_block == NULL) *first_block = new_block; new_block->base = address; new_block->size = size; new_block->data = data; new_block->next = NULL; if (current_block != NULL) current_block->next = new_block; current_block = new_block; } else { yr_free(data); } address += size; } } while (kr != KERN_INVALID_ADDRESS); if (task != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), task); return ERROR_SUCCESS; }
/** * (Safely) read len bytes from addr, storing in dest. Uses mach vm_read_overwrite to * avoid dereferencing a bad pointer. */ kern_return_t plframe_read_addr (const void *source, void *dest, size_t len) { vm_size_t read_size = len; return vm_read_overwrite(mach_task_self(), (vm_address_t) source, len, (pointer_t) dest, &read_size); }
static OSStatus DoLoadMemory( AuthorizationRef auth, const void * userData, CFDictionaryRef request, CFMutableDictionaryRef response, aslclient asl, aslmsg aslMsg ) // Implements the kGetUIDsCommand. Gets the process's three UIDs and // adds them to the response dictionary. { //asl_log(asl, aslMsg, ASL_LEVEL_DEBUG, "DoLoadMemory()"); // Pre-conditions if(auth == NULL || request == NULL || response == NULL) return kMemToolBadParameter; // CFShow(request); // load in the WoW ProcessID pid_t wowPID = 0; CFNumberRef cfPID = CFDictionaryGetValue(request, CFSTR(kWarcraftPID)); if(!CFNumberGetValue(cfPID, kCFNumberIntType, &wowPID) || wowPID <= 0) { return kMemToolBadPID; } // load in the memory address unsigned int address = 0; CFNumberRef cfAddress = CFDictionaryGetValue(request, CFSTR(kMemoryAddress)); if(!CFNumberGetValue(cfAddress, kCFNumberIntType, &address) || address == 0) { return kMemToolBadAddress; } // load in memory length vm_size_t length = 0; CFNumberRef cfLength = CFDictionaryGetValue(request, CFSTR(kMemoryLength)); if(!CFNumberGetValue(cfLength, kCFNumberIntType, &length) || length == 0) { return kMemToolBadLength; } bool memSuccess = false; if(wowPID && address && length) { //asl_log(asl, aslMsg, ASL_LEVEL_DEBUG, "Reading pid %d at address 0x%X for length %d", wowPID, address, length); // create buffer for our data Byte buffer[length]; int i; for(i=0; i<length; i++) buffer[i] = 0; // get a handle on the WoW task mach_port_t wowTask; task_for_pid(current_task(), wowPID, &wowTask); vm_size_t bytesRead = length; memSuccess = ((KERN_SUCCESS == vm_read_overwrite(wowTask, address, length, (vm_address_t)&buffer, &bytesRead)) && (bytesRead == length) ); //(KERN_SUCCESS == vm_write(wowTask, address, (vm_offset_t)&buffer, length)); if(memSuccess) { CFDataRef memoryContents = CFDataCreate(NULL, buffer, length); if(memoryContents != NULL) { // we got our memory! add it to the return dictionary CFDictionaryAddValue(response, CFSTR(kMemoryContents), memoryContents); CFRelease(memoryContents); return kMemToolNoError; } } } else { return kMemToolBadParameter; } return kMemToolUnknown; }
static int __read(RIO *io, RIODesc *desc, ut8 *buf, int len) { vm_size_t size = 0; int blen, err, copied = 0; int blocksize = 32; RIODescData *dd = (RIODescData *)desc->data; if (!io || !desc || !buf || !dd) { return -1; } if (dd ->magic != r_str_hash ("mach")) { return -1; } memset (buf, 0xff, len); int pid = __get_pid (desc); task_t task = pid_to_task (desc, pid); if (task_is_dead (desc, pid)) { return -1; } if (pid == 0) { if (io->off < 4096) { return len; } } copied = getNextValid (io, desc, io->off) - io->off; if (copied < 0) { copied = 0; } while (copied < len) { blen = R_MIN ((len - copied), blocksize); //blen = len; err = vm_read_overwrite (task, (ut64)io->off + copied, blen, (pointer_t)buf + copied, &size); switch (err) { case KERN_PROTECTION_FAILURE: //eprintf ("r_io_mach_read: kern protection failure.\n"); break; case KERN_INVALID_ADDRESS: if (blocksize == 1) { memset (buf+copied, 0xff, len-copied); return size+copied; } blocksize = 1; blen = 1; buf[copied] = 0xff; break; } if (err == -1 || size < 1) { return -1; } if (size == 0) { if (blocksize == 1) { memset (buf + copied, 0xff, len - copied); return len; } blocksize = 1; blen = 1; buf[copied] = 0xff; } copied += blen; } return len; }
int dump_kernel_task(int argc, char *argv[]) { task_t task; kern_return_t error; pid_t pid = 0; int fd; error = task_for_pid(mach_task_self(), pid, &task); if (error != KERN_SUCCESS) { printf("task for pid failed for pid=%d error=%d\n", pid, error); return 0; } vm_address_t address=0; char *buf = malloc(4096); vm_address_t start = strtoul(argv[1],0,0); vm_address_t end = strtoul(argv[2], 0, 0); int ret; printf("Reading from %x to %x\n", start, end); fd = -1; for (address = start; address < end; address += 0x1000) { memset(buf, 0, 4096); mach_msg_type_number_t count = 0; // // Region is mapped 0,0. but there's a bug where // reading < 4096 will work :-) // ret = vm_read_overwrite (task, address, PAGE_SIZE/2, buf, &count); if (ret == 0) { ret = vm_read_overwrite (task, address + PAGE_SIZE/2, PAGE_SIZE/2, buf + PAGE_SIZE/2, &count); } if (ret == 0) { if (fd == -1) { char namebuf[40]; sprintf(namebuf, "kmem/%.8x.mem", address); fd = open(namebuf, O_CREAT|O_WRONLY); if (fd == -1){ printf("unable to open file %s for writing\n", namebuf); break; } } write(fd, buf, 4096); } else { printf("Failed to read: ret=%d address= %x", ret, address); break; } } close(fd); printf("Finished\n"); mach_port_deallocate(mach_task_self(), task); return 0; }
#include "KSMemory.h" //#define KSLogger_LocalLevel TRACE #include "KSLogger.h" #include <mach/mach.h> static inline int copySafely(const void* restrict const src, void* restrict const dst, const int byteCount) { vm_size_t bytesCopied = 0; kern_return_t result = vm_read_overwrite(mach_task_self(), (vm_address_t)src, (vm_size_t)byteCount, (vm_address_t)dst, &bytesCopied); if(result != KERN_SUCCESS) { return 0; } return (int)bytesCopied; } static inline int copyMaxPossible(const void* restrict const src, void* restrict const dst, const int byteCount) { const uint8_t* pSrc = src; const uint8_t* pSrcMax = (uint8_t*)src + byteCount; const uint8_t* pSrcEnd = (uint8_t*)src + byteCount; uint8_t* pDst = dst;