X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fthecheat;a=blobdiff_plain;f=VMRegion.m;fp=VMRegion.m;h=612327a39336b3c6d55d7b7d4619f7da77e3bfbd;hp=0000000000000000000000000000000000000000;hb=d27548f80fe411fda2ee69c74a24eab4292267e9;hpb=e8d51183acdd2410a38dcf8f0efbf7c30cd6c581 diff --git a/VMRegion.m b/VMRegion.m new file mode 100644 index 0000000..612327a --- /dev/null +++ b/VMRegion.m @@ -0,0 +1,279 @@ + +// +// VMRegion 0.1 +// Virtual Memory Wrapper +// +// Copyright (c) 2004, Chaz McGarvey +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the BrokenZipper nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +// SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// Web: http://www.brokenzipper.com/ +// Email: chaz@brokenzipper.com +// + +#import "VMRegion.h" + +#include // for task_for_pid(3) +#include // for stop(2) + + +static __inline__ vm_map_t _VMTaskFromPID( pid_t process ) +{ + vm_map_t task; + + if ( task_for_pid( current_task(), process, &task ) == KERN_SUCCESS ) { + return task; + } + return 0; +} + +static __inline__ VMRegion _VMMakeRegionWithAttributes( pid_t process, vm_address_t address, vm_size_t size, unsigned attribs ) +{ + VMRegion region; + region._process = process; + region._address = address; + region._size = size; + region._attributes = attribs; + return region; +} + +unsigned _VMAttributesFromAddress( pid_t process, vm_address_t address ); + + +const VMRegion VMNullRegion = { 0, 0, 0, 0 }; + + +#pragma mark - +#pragma mark VMRegion Functions +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + +VMRegion VMMakeRegion( pid_t process, vm_address_t address, vm_size_t size ) +{ + VMRegion region; + region._process = process; + region._address = address; + region._size = size; + region._attributes = _VMAttributesFromAddress( process, address ); + return region; +} + +BOOL VMRegionSetData( VMRegion region, NSData *data ) +{ + // get the size that should be used (to prevent from writing past the region) + vm_size_t size = (vm_size_t)[data length]; + size = (size > region._size)? region._size : size; + + return VMWriteBytes( region._process, region._address, [data bytes], size ); +} + +NSString *VMStringFromRegion( VMRegion region ) +{ + return [NSString stringWithFormat:@"{pid:%i,%p,%u,}", region._process, region._address, region._size]; +} + + +#pragma mark - +#pragma mark Utility VM Functions +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + +unsigned VMCountRegions( pid_t process ) +{ + VMRegion region; + VMRegion prev = VMNullRegion; + unsigned count = 0; + + while ( VMRegionIsNotNull( region = VMNextRegion( process, prev ) ) ) + { + count++; + prev = region; + } + + return count; +} + +unsigned VMCountRegionsWithAttributes( pid_t process, unsigned attribs ) +{ + VMRegion region; + VMRegion prev = VMNullRegion; + unsigned count = 0; + + while ( VMRegionIsNotNull( region = VMNextRegionWithAttributes( process, prev, attribs ) ) ) + { + count++; + prev = region; + } + + return count; +} + + +VMRegion VMNextRegion( pid_t process, VMRegion previous ) +{ + vm_map_t task = _VMTaskFromPID( process ); + unsigned attribs = 0; + + kern_return_t result; + + vm_address_t address = 0x0; + vm_size_t size = 0; + vm_region_basic_info_data_t info; + mach_msg_type_number_t infoCnt = VM_REGION_BASIC_INFO_COUNT; + mach_port_t object_name = 0; + + if ( !VMEqualRegions( previous, VMNullRegion ) ) { + address = previous._address + previous._size; + } + + // get the next region + result = vm_region( task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)(&info), &infoCnt, &object_name ); + + if ( result == KERN_SUCCESS ) { + // get the attributes + if ( info.protection & VM_PROT_READ ) { + attribs |= VMREGION_READABLE; + } + if ( info.protection & VM_PROT_WRITE ) { + attribs |= VMREGION_WRITABLE; + } + if ( info.protection & VM_PROT_EXECUTE ) { + attribs |= VMREGION_EXECUTABLE; + } + // return the region + return _VMMakeRegionWithAttributes( process, address, size, attribs ); + } + + return VMNullRegion; +} + +VMRegion VMNextRegionWithAttributes( pid_t process, VMRegion previous, unsigned attribs ) +{ + VMRegion region; + + while ( VMRegionIsNotNull( region = VMNextRegion( process, previous ) ) ) + { + if ( (attribs & region._attributes) == attribs ) { + // pass back this region if the attributes match + return region; + } + previous = region; + } + + return VMNullRegion; +} + + +NSData *VMReadData( pid_t process, vm_address_t address, vm_size_t size ) +{ + vm_map_t task = _VMTaskFromPID( process ); + kern_return_t result; + + void *buffer; + vm_size_t actualSize; + + // create a local block to hold the incoming data + buffer = (void *)malloc( (size_t)size ); + if ( !buffer ) { + // no buffer, abort + return nil; + } + + // perform the read + result = vm_read_overwrite( task, address, size, (vm_address_t)buffer, &actualSize ); + if ( result != KERN_SUCCESS ) { + // read error, abort + free( buffer ); + return nil; + } + + // everything seems to be peachy, so return the data + return [[[NSData alloc] initWithBytesNoCopy:buffer length:actualSize freeWhenDone:YES] autorelease]; +} + +BOOL VMReadBytes( pid_t process, vm_address_t address, void *bytes, vm_size_t *size ) +{ + vm_map_t task = _VMTaskFromPID( process ); + kern_return_t result; + vm_size_t staticsize = *size; + + // perform the read + result = vm_read_overwrite( task, address, staticsize, (vm_address_t)bytes, size ); + if ( result != KERN_SUCCESS ) { + return NO; + } + + return YES; +} + +BOOL VMWriteData( pid_t process, vm_address_t address, NSData *data ) +{ + return VMWriteBytes( process, address, [data bytes], [data length] ); +} + +BOOL VMWriteBytes( pid_t process, vm_address_t address, const void *bytes, vm_size_t size ) +{ + vm_map_t task = _VMTaskFromPID( process ); + kern_return_t result; + + // attempt to write the bytes and return success/failure + result = vm_write( task, address, (vm_address_t)bytes, size ); + return (result == KERN_SUCCESS); +} + + +unsigned _VMAttributesFromAddress( pid_t process, vm_address_t address ) +{ + vm_map_t task = _VMTaskFromPID( process ); + unsigned attribs = 0; + + kern_return_t result; + + vm_size_t size = 0; + vm_region_basic_info_data_t info; + mach_msg_type_number_t infoCnt = 8; + mach_port_t object_name = 0; + + // get the next region + result = vm_region( task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)(&info), &infoCnt, &object_name ); + + if ( result == KERN_SUCCESS ) { + // get the attributes + if ( info.protection & VM_PROT_READ ) { + attribs |= VMREGION_READABLE; + } + if ( info.protection & VM_PROT_WRITE ) { + attribs |= VMREGION_WRITABLE; + } + if ( info.protection & VM_PROT_EXECUTE ) { + attribs |= VMREGION_EXECUTABLE; + } + // return the region attributes + return attribs; + } + return 0; +} + +