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)
43 static __inline__ vm_map_t
_VMTaskFromPID( pid_t process
)
47 if ( task_for_pid( current_task(), process
, &task
) == KERN_SUCCESS
) {
53 static __inline__ VMRegion
_VMMakeRegionWithAttributes( pid_t process
, vm_address_t address
, vm_size_t size
, unsigned attribs
)
56 region._process
= process
;
57 region._address
= address
;
59 region._attributes
= attribs
;
63 unsigned _VMAttributesFromAddress( pid_t process
, vm_address_t address
);
66 const VMRegion VMNullRegion
= { 0, 0, 0, 0 };
70 #pragma mark VMRegion Functions
71 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
73 VMRegion
VMMakeRegion( pid_t process
, vm_address_t address
, vm_size_t size
)
76 region._process
= process
;
77 region._address
= address
;
79 region._attributes
= _VMAttributesFromAddress( process
, address
);
83 BOOL VMRegionSetData( VMRegion region
, NSData
*data
)
85 // get the size that should be used (to prevent from writing past the region)
86 vm_size_t size
= (vm_size_t
)[data length
];
87 size
= (size
> region._size
)? region._size
: size
;
89 return VMWriteBytes( region._process
, region._address
, [data bytes
], size
);
92 NSString
*VMStringFromRegion( VMRegion region
)
94 return [NSString stringWithFormat
:@
"{pid:%i,%p,%u,}", region._process
, region._address
, region._size
];
99 #pragma mark Utility VM Functions
100 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
102 unsigned VMCountRegions( pid_t process
)
105 VMRegion prev
= VMNullRegion
;
108 while ( VMRegionIsNotNull( region
= VMNextRegion( process
, prev
) ) )
117 unsigned VMCountRegionsWithAttributes( pid_t process
, unsigned attribs
)
120 VMRegion prev
= VMNullRegion
;
123 while ( VMRegionIsNotNull( region
= VMNextRegionWithAttributes( process
, prev
, attribs
) ) )
133 VMRegion
VMNextRegion( pid_t process
, VMRegion previous
)
135 vm_map_t task
= _VMTaskFromPID( process
);
136 unsigned attribs
= 0;
138 kern_return_t result
;
140 vm_address_t address
= 0x0;
142 vm_region_basic_info_data_t info
;
143 mach_msg_type_number_t infoCnt
= VM_REGION_BASIC_INFO_COUNT
;
144 mach_port_t object_name
= 0;
146 if ( !VMEqualRegions( previous
, VMNullRegion
) ) {
147 address
= previous._address
+ previous._size
;
150 // get the next region
151 result
= vm_region( task
, &address
, &size
, VM_REGION_BASIC_INFO
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
);
153 if ( result
== KERN_SUCCESS
) {
154 // get the attributes
155 if ( info.protection
& VM_PROT_READ
) {
156 attribs |
= VMREGION_READABLE
;
158 if ( info.protection
& VM_PROT_WRITE
) {
159 attribs |
= VMREGION_WRITABLE
;
161 if ( info.protection
& VM_PROT_EXECUTE
) {
162 attribs |
= VMREGION_EXECUTABLE
;
165 return _VMMakeRegionWithAttributes( process
, address
, size
, attribs
);
171 VMRegion
VMNextRegionWithAttributes( pid_t process
, VMRegion previous
, unsigned attribs
)
175 while ( VMRegionIsNotNull( region
= VMNextRegion( process
, previous
) ) )
177 if ( (attribs
& region._attributes
) == attribs
) {
178 // pass back this region if the attributes match
188 NSData
*VMReadData( pid_t process
, vm_address_t address
, vm_size_t size
)
190 vm_map_t task
= _VMTaskFromPID( process
);
191 kern_return_t result
;
194 vm_size_t actualSize
;
196 // create a local block to hold the incoming data
197 buffer
= (void *)malloc( (size_t)size
);
204 result
= vm_read_overwrite( task
, address
, size
, (vm_address_t
)buffer
, &actualSize
);
205 if ( result
!= KERN_SUCCESS
) {
211 // everything seems to be peachy, so return the data
212 return [[[NSData alloc
] initWithBytesNoCopy
:buffer length
:actualSize freeWhenDone
:YES
] autorelease
];
215 BOOL VMReadBytes( pid_t process
, vm_address_t address
, void *bytes
, vm_size_t
*size
)
217 vm_map_t task
= _VMTaskFromPID( process
);
218 kern_return_t result
;
219 vm_size_t staticsize
= *size
;
222 result
= vm_read_overwrite( task
, address
, staticsize
, (vm_address_t
)bytes
, size
);
223 if ( result
!= KERN_SUCCESS
) {
230 BOOL VMWriteData( pid_t process
, vm_address_t address
, NSData
*data
)
232 return VMWriteBytes( process
, address
, [data bytes
], [data length
] );
235 BOOL VMWriteBytes( pid_t process
, vm_address_t address
, const void *bytes
, vm_size_t size
)
237 vm_map_t task
= _VMTaskFromPID( process
);
238 kern_return_t result
;
240 // attempt to write the bytes and return success/failure
241 result
= vm_write( task
, address
, (vm_address_t
)bytes
, size
);
242 return (result
== KERN_SUCCESS
);
246 unsigned _VMAttributesFromAddress( pid_t process
, vm_address_t address
)
248 vm_map_t task
= _VMTaskFromPID( process
);
249 unsigned attribs
= 0;
251 kern_return_t result
;
254 vm_region_basic_info_data_t info
;
255 mach_msg_type_number_t infoCnt
= 8;
256 mach_port_t object_name
= 0;
258 // get the next region
259 result
= vm_region( task
, &address
, &size
, VM_REGION_BASIC_INFO
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
);
261 if ( result
== KERN_SUCCESS
) {
262 // get the attributes
263 if ( info.protection
& VM_PROT_READ
) {
264 attribs |
= VMREGION_READABLE
;
266 if ( info.protection
& VM_PROT_WRITE
) {
267 attribs |
= VMREGION_WRITABLE
;
269 if ( info.protection
& VM_PROT_EXECUTE
) {
270 attribs |
= VMREGION_EXECUTABLE
;
272 // return the region attributes