4 // Virtual Memory Wrapper
6 // Copyright (c) 2004, Chaz McGarvey
7 // All rights reserved.
9 // Redistribution and use in source and binary forms, with or without modification, are
10 // permitted provided that the following conditions are met:
12 // 1. Redistributions of source code must retain the above copyright notice, this list
13 // of conditions and the following disclaimer.
15 // 2. Redistributions in binary form must reproduce the above copyright notice, this
16 // list of conditions and the following disclaimer in the documentation and/or other
17 // materials provided with the distribution.
19 // 3. Neither the name of the BrokenZipper nor the names of its contributors may be
20 // used to endorse or promote products derived from this software without specific
21 // prior written permission.
23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
24 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
26 // SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29 // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
34 // Web: http://www.brokenzipper.com/
35 // Email: chaz@brokenzipper.com
40 #include <mach/mach_traps.h> // for task_for_pid(3)
41 #include <signal.h> // for stop(2)
44 static __inline__ vm_map_t
_VMTaskFromPID( pid_t process
)
48 if ( task_for_pid( current_task(), process
, &task
) == KERN_SUCCESS
) {
54 static __inline__ VMRegion
_VMMakeRegionWithAttributes( pid_t process
, vm_address_t address
, vm_size_t size
, unsigned attribs
)
57 region._process
= process
;
58 region._address
= address
;
60 region._attributes
= attribs
;
64 unsigned _VMAttributesFromAddress( pid_t process
, vm_address_t address
);
67 const VMRegion VMNullRegion
= { 0, 0, 0, 0 };
71 #pragma mark VMRegion Functions
72 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
74 VMRegion
VMMakeRegion( pid_t process
, vm_address_t address
, vm_size_t size
)
77 region._process
= process
;
78 region._address
= address
;
80 region._attributes
= _VMAttributesFromAddress( process
, address
);
84 BOOL VMRegionSetData( VMRegion region
, NSData
*data
)
86 // get the size that should be used (to prevent from writing past the region)
87 vm_size_t size
= (vm_size_t
)[data length
];
88 size
= (size
> region._size
)? region._size
: size
;
90 return VMWriteBytes( region._process
, region._address
, [data bytes
], size
);
93 NSString
*VMStringFromRegion( VMRegion region
)
95 return [NSString stringWithFormat
:@
"{pid:%i,%p,%u,}", region._process
, region._address
, region._size
];
100 #pragma mark Utility VM Functions
101 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
103 unsigned VMCountRegions( pid_t process
)
106 VMRegion prev
= VMNullRegion
;
109 while ( VMRegionIsNotNull( region
= VMNextRegion( process
, prev
) ) )
118 unsigned VMCountRegionsWithAttributes( pid_t process
, unsigned attribs
)
121 VMRegion prev
= VMNullRegion
;
124 while ( VMRegionIsNotNull( region
= VMNextRegionWithAttributes( process
, prev
, attribs
) ) )
134 VMRegion
VMNextRegion( pid_t process
, VMRegion previous
)
136 vm_map_t task
= _VMTaskFromPID( process
);
137 unsigned attribs
= 0;
139 kern_return_t result
;
141 vm_address_t address
= 0x0;
143 vm_region_basic_info_data_t info
;
144 mach_msg_type_number_t infoCnt
= VM_REGION_BASIC_INFO_COUNT
;
145 mach_port_t object_name
= 0;
147 if ( !VMEqualRegions( previous
, VMNullRegion
) ) {
148 address
= previous._address
+ previous._size
;
151 // get the next region
152 result
= vm_region( task
, &address
, &size
, VM_REGION_BASIC_INFO
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
);
154 if ( result
== KERN_SUCCESS
) {
155 // get the attributes
156 if ( info.protection
& VM_PROT_READ
) {
157 attribs |
= VMREGION_READABLE
;
159 if ( info.protection
& VM_PROT_WRITE
) {
160 attribs |
= VMREGION_WRITABLE
;
162 if ( info.protection
& VM_PROT_EXECUTE
) {
163 attribs |
= VMREGION_EXECUTABLE
;
166 return _VMMakeRegionWithAttributes( process
, address
, size
, attribs
);
172 VMRegion
VMNextRegionWithAttributes( pid_t process
, VMRegion previous
, unsigned attribs
)
176 while ( VMRegionIsNotNull( region
= VMNextRegion( process
, previous
) ) )
178 if ( (attribs
& region._attributes
) == attribs
) {
179 // pass back this region if the attributes match
189 NSData
*VMReadData( pid_t process
, vm_address_t address
, vm_size_t size
)
191 vm_map_t task
= _VMTaskFromPID( process
);
192 kern_return_t result
;
195 vm_size_t actualSize
;
197 // create a local block to hold the incoming data
198 buffer
= (void *)malloc( (size_t)size
);
205 result
= vm_read_overwrite( task
, address
, size
, (vm_address_t
)buffer
, &actualSize
);
206 if ( result
!= KERN_SUCCESS
) {
212 // everything seems to be peachy, so return the data
213 return [[[NSData alloc
] initWithBytesNoCopy
:buffer length
:actualSize freeWhenDone
:YES
] autorelease
];
216 BOOL VMReadBytes( pid_t process
, vm_address_t address
, void *bytes
, vm_size_t
*size
)
218 vm_map_t task
= _VMTaskFromPID( process
);
219 kern_return_t result
;
220 vm_size_t staticsize
= *size
;
223 result
= vm_read_overwrite( task
, address
, staticsize
, (vm_address_t
)bytes
, size
);
224 if ( result
!= KERN_SUCCESS
) {
231 BOOL VMWriteData( pid_t process
, vm_address_t address
, NSData
*data
)
233 return VMWriteBytes( process
, address
, [data bytes
], [data length
] );
236 BOOL VMWriteBytes( pid_t process
, vm_address_t address
, const void *bytes
, vm_size_t size
)
238 vm_map_t task
= _VMTaskFromPID( process
);
239 kern_return_t result
;
241 // attempt to write the bytes and return success/failure
242 result
= vm_write( task
, address
, (vm_address_t
)bytes
, size
);
243 return (result
== KERN_SUCCESS
);
247 unsigned _VMAttributesFromAddress( pid_t process
, vm_address_t address
)
249 vm_map_t task
= _VMTaskFromPID( process
);
250 unsigned attribs
= 0;
252 kern_return_t result
;
255 vm_region_basic_info_data_t info
;
256 mach_msg_type_number_t infoCnt
= 8;
257 mach_port_t object_name
= 0;
259 // get the next region
260 result
= vm_region( task
, &address
, &size
, VM_REGION_BASIC_INFO
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
);
262 if ( result
== KERN_SUCCESS
) {
263 // get the attributes
264 if ( info.protection
& VM_PROT_READ
) {
265 attribs |
= VMREGION_READABLE
;
267 if ( info.protection
& VM_PROT_WRITE
) {
268 attribs |
= VMREGION_WRITABLE
;
270 if ( info.protection
& VM_PROT_EXECUTE
) {
271 attribs |
= VMREGION_EXECUTABLE
;
273 // return the region attributes