|
|
1.1 root 1: #import "RegionManager.h"
2: #import <stdlib.h>
3: #import <string.h>
4: #import <mach/mach.h>
5: #import <mach-o/loader.h>
6: #import <mach/vm_param.h>
7:
8: kern_return_t static inline vmRegion(task_t task,
9: vm_address_t address,
10: Region *region)
11: {
12: vm_offset_t offset;
13: vm_prot_t maxProtection;
14: vm_inherit_t inheritance;
15: boolean_t shared;
16: port_t objectName;
17: region->reloc.address = address;
18: return vm_region(task,
19: ®ion->reloc.address,
20: ®ion->reloc.size,
21: ®ion->protection,
22: &maxProtection,
23: &inheritance,
24: &shared,
25: &objectName,
26: &offset);
27: }
28:
29: @implementation RegionManager
30:
31: -initTask: (vm_task_t)theTask readInRegions: (BOOL)readInRegions
32: {
33: vm_statistics_data_t vm_stats;
34:
35: task = theTask;
36: vm_statistics(theTask, &vm_stats);
37: pageSize = vm_stats.pagesize;
38: relocSize = sizeof(Region);
39: rmFlags.shouldSortRelocs = NO;
40: if (readInRegions)
41: [self readInAllRelocs];
42: else
43: rmFlags.invalid = YES;
44: return self;
45: }
46:
47: -(BOOL)isTask
48: {
49: struct task_basic_info taskInfo;
50: unsigned int taskInfoCount;
51: BOOL ret;
52:
53: taskInfoCount = TASK_BASIC_INFO_COUNT;
54: ret = (task_info(task,
55: TASK_BASIC_INFO,
56: (task_info_t)&taskInfo,
57: &taskInfoCount) == KERN_SUCCESS) ? YES : NO;
58: if (!ret && taskGoneCallBack)
59: (*taskGoneCallBack)();
60: return ret;
61: }
62:
63: -(void)setTaskGoneCallBack: (TaskGoneCallBack)theCallBack
64: {
65: taskGoneCallBack = theCallBack;
66: }
67:
68: +newTask: (vm_task_t)theTask
69: {
70: return [[super new] initTask: theTask readInRegions: YES];
71: }
72:
73: +newTask: (vm_task_t)theTask readInRegions: (BOOL)readInRegions
74: {
75: return [[super new] initTask: theTask readInRegions: readInRegions];
76: }
77:
78: -invalidate
79: {
80: if (rmFlags.invalid)
81: return self;
82: else {
83: Region *region;
84: int count;
85: if (relocs) {
86: for (count = numRelocs, region = (Region *)relocs;
87: count;
88: count--, region++) {
89: if (region->reloc.rFlags.readIn)
90: vm_deallocate(task_self(),
91: region->reloc.data,
92: region->reloc.size);
93: }
94: }
95: if (pages) {
96: free(pages);
97: pages = NULL;
98: }
99: return [super invalidate];
100: }
101: }
102:
103: -(void)getStartPage: (void **)startPage andSize: (int *)sizePage
104: forPointer: (void *)start andSize: (int)numBytes
105: {
106: vm_address_t offset = ((vm_address_t)start % pageSize);
107: vm_address_t s = numBytes + offset;
108:
109: *startPage = start - offset;
110: *sizePage = (s - (s % pageSize)) + pageSize;
111: }
112:
113: -(void)protectDataAt: (const void *)start for: (int)numBytes
114: {
115: vm_address_t offset = ((vm_address_t)start % pageSize);
116: vm_address_t startPage = (vm_address_t)start - offset;
117: size_t sizePage = numBytes + offset;
118:
119: vm_protect(task, startPage, pageSize, NO, VM_PROT_READ);
120: }
121:
122: -(void)unProtectDataAt: (const void *)start for: (int)numBytes
123: {
124: vm_address_t offset = ((vm_address_t)start % pageSize);
125: vm_address_t startPage = (vm_address_t)start - offset;
126: size_t sizePage = numBytes + offset;
127:
128: vm_protect(task, startPage, pageSize, NO, VM_PROT_READ | VM_PROT_WRITE);
129: }
130:
131: -(int)writeDataAt: (const void *)start for: (int)numBytes reloc: (Region *)region markOnly: (BOOL)markOnly
132: {
133: vm_address_t offset = ((vm_address_t)start % pageSize);
134: vm_address_t startPage = (vm_address_t)start - offset;
135: size_t sizePage = numBytes + offset;
136: pointer_t startData;
137: kern_return_t ret = 0;
138: unsigned char *pPage;
139:
140: if (markOnly) {
141: if (!region->pagesInvalid)
142: regionsInvalid++;
143: }
144: for (sizePage += (pageSize - (sizePage % pageSize)),
145: startData = region->reloc.data
146: + ((pointer_t)startPage - region->reloc.address),
147: pPage = region->pages
148: + (((pointer_t)startPage - region->reloc.address) / pageSize);
149: sizePage && !ret;
150: sizePage -= pageSize, startData += pageSize, startPage += pageSize,
151: pPage++) {
152: if (markOnly) {
153: if (!(*pPage & PAGEINVALID)) {
154: *pPage |= PAGEINVALID;
155: region->pagesInvalid++;
156: }
157: } else {
158: *pPage &= ~PAGEINVALID;
159: if (*pPage & VM_PROT_WRITE)
160: ret = vm_write(task, startPage, startData, pageSize);
161: else {
162: vm_protect(task, startPage, pageSize, NO, VM_PROT_WRITE);
163: ret = vm_write(task, startPage, startData, pageSize);
164: vm_protect(task, startPage, pageSize, NO,
165: (vm_prot_t)(*pPage & 0x7));
166: }
167: }
168: }
169: if (ret == KERN_SUCCESS)
170: return numBytes;
171: else {
172: [self isTask];
173: return 0;
174: }
175: }
176:
177: -(int)writeDataAt: (const void *)start for: (int)numBytes reloc: (Region *)region
178: {
179: return [self writeDataAt: start for: numBytes reloc: region markOnly: NO];
180: }
181:
182: -(int)putDataAt: (void *)start for: (int)numBytes from: (const void *)data markOnly: (BOOL)markOnly
183: {
184: int numBytesInRegion;
185: Reloc *reloc = [self relocFor: start];
186: if (reloc) {
187: numBytesInRegion = reloc->maxAddress - (int)start;
188: if (numBytes > numBytesInRegion)
189: numBytes = numBytesInRegion;
190: if (numBytes == 1)
191: *(char *)(reloc->data + ((pointer_t)start - reloc->address))
192: = *(char *)data;
193: else
194: memcpy((void *)(reloc->data + ((pointer_t)start - reloc->address)),
195: data,
196: numBytes);
197: return [self writeDataAt: start for: numBytes reloc: (Region *)reloc markOnly: markOnly];
198: } else
199: return 0;
200: }
201:
202: -(int)putDataAt: (void *)start for: (int)numBytes from: (const void *)data
203: {
204: return [self putDataAt: start for: numBytes from: data markOnly: NO];
205: }
206:
207: -(void)flushMarkedPages
208: {
209: int ret = 0;
210: while (regionsInvalid) {
211: int i;
212: Region *region;
213:
214: for (i = 0, region = (Region *)relocs;
215: i < numRelocs;
216: i++, ((void *)region) += relocSize) {
217: if (region->pagesInvalid) {
218: unsigned char *p = region->pages;
219: while (region->pagesInvalid) {
220: if (*p & PAGEINVALID) {
221: int numPage = p - region->pages;
222: pointer_t startPage, startData;
223:
224: startPage
225: = region->reloc.address + (numPage * pageSize);
226: startData
227: = region->reloc.data + (numPage * pageSize);
228: *p &= ~PAGEINVALID;
229: region->pagesInvalid--;
230: if (*p & VM_PROT_WRITE)
231: ret = vm_write(task, startPage, startData, pageSize);
232: else {
233: vm_protect(task, startPage, pageSize, NO, VM_PROT_WRITE);
234: ret = vm_write(task, startPage, startData, pageSize);
235: vm_protect(task, startPage, pageSize, NO,
236: (vm_prot_t)(*p & 0x7));
237: }
238: }
239: p++;
240: }
241: regionsInvalid--;
242: }
243: }
244: }
245: if (ret)
246: [self isTask];
247: }
248:
249: -(int)writeDataAt: (const void *)start for: (int)numBytes;
250: {
251: Reloc *reloc = [self relocFor: start];
252: if (reloc)
253: return [self writeDataAt: start for: numBytes reloc: (Region *)reloc];
254: else
255: return NO;
256: }
257:
258: -(BOOL)readInReloc: (Reloc *)reloc
259: {
260: kern_return_t ret;
261: unsigned int nData;
262: if (reloc->rFlags.readIn) {
263: return YES;
264: } else {
265: ret = vm_read(task, reloc->address, reloc->size, &reloc->data, &nData);
266: if (ret == KERN_SUCCESS) {
267: reloc->maxData = reloc->data + reloc->size;
268: reloc->displacement = reloc->data - reloc->address;
269: reloc->rFlags.readIn = YES;
270: return YES;
271: } else {
272: [self isTask];
273: return NO;
274: }
275: }
276: }
277:
278: -(void)combineRegions: (BOOL)combineRegions
279: { dontCombineRegions = !combineRegions;}
280:
281: -(void)_readInAllRelocs
282: {
283: kern_return_t error = 0;
284: vm_address_t address = VM_MIN_ADDRESS;
285: Region *theRegion, *regions, *newRegion, *nextRegion, *lastRegion;
286: int count = 0, numPages = 0, numAlloced = 16, nPages;
287: unsigned char *thePage;
288:
289: if ([self isTask]) {
290: theRegion = regions = malloc(numAlloced * sizeof(Region));
291: bzero(regions, numAlloced * sizeof(Region));
292: while (!error) {
293: error = vmRegion(task, address, theRegion);
294: address = theRegion->reloc.address + theRegion->reloc.size;
295: if (!error) {
296: if (theRegion->protection & VM_PROT_READ) {
297: count++;
298: numPages += theRegion->reloc.size / pageSize;
299: if (count < numAlloced)
300: theRegion++;
301: else {
302: numAlloced *= 2;
303: regions = realloc(regions,
304: numAlloced * sizeof(Region));
305: theRegion = regions + count;
306: bzero(theRegion, count * sizeof(Region));
307: }
308: }
309: if (address < theRegion->reloc.address)
310: error = KERN_NO_SPACE;
311: }
312: }
313: if (error == KERN_NO_SPACE) {
314: lastRegion = theRegion;
315:
316: pages = malloc(numPages);
317: for (theRegion = regions, thePage = pages;
318: theRegion < lastRegion;
319: theRegion++) {
320: theRegion->pages = thePage;
321: nPages = theRegion->reloc.size / pageSize;
322: while(nPages--)
323: *(thePage++) = (unsigned char)theRegion->protection;
324: }
325:
326: if (dontCombineRegions) {
327: for (theRegion = regions; theRegion < lastRegion; theRegion++)
328: theRegion->reloc.maxAddress
329: = theRegion->reloc.address + theRegion->reloc.size;
330: relocs = regions;
331: numRelocs = count;
332: } else {
333: relocs = malloc(count * sizeof(Region));
334: bzero(relocs, count * sizeof(Region));
335: for (theRegion = regions, newRegion = relocs;
336: theRegion < lastRegion;
337: theRegion = nextRegion, newRegion++) {
338: for (nextRegion = theRegion + 1;
339: (nextRegion < lastRegion
340: && ((theRegion->reloc.address + theRegion->reloc.size)
341: == nextRegion->reloc.address));
342: nextRegion++) {
343: theRegion->reloc.size += nextRegion->reloc.size;
344: }
345: *newRegion = *theRegion;
346: newRegion->reloc.maxAddress
347: = newRegion->reloc.address + newRegion->reloc.size;
348: }
349: numRelocs = newRegion - (Region *)relocs;
350: relocs = realloc(relocs, numRelocs * sizeof(Region));
351: free(regions);
352: }
353: rmFlags.invalid = NO;
354: } else
355: free(regions);
356:
357: if (error != KERN_NO_SPACE)
358: [self isTask];
359: }
360: }
361:
362: -(struct mach_header *)getMachHeader
363: {
364: Reloc *reloc;
365: int count;
366: struct mach_header *header, *foundHeader;
367:
368: if (rmFlags.invalid)
369: [self readInAllRelocs];
370: reloc = relocs;
371: for (foundHeader = NULL, count = 0;
372: !foundHeader && count < numRelocs;
373: count++) {
374: [self readInReloc: reloc];
375: header = [self pointerFor: (void *)reloc->address
376: withSize: sizeof(*header)];
377: if (header
378: && (header->magic == MH_MAGIC)
379: && ([self pointerFor: (void *)reloc->address
380: withSize: header->sizeofcmds]))
381: foundHeader = header;
382: else
383: ((void *)reloc) += relocSize;
384: }
385: return foundHeader;
386: }
387:
388: -(int)getNumMachHeaders
389: {
390: struct mach_header *myHeader;
391: int numHeaders, i;
392: struct fvmlib_command *loadCmd;
393: if (myHeader = [self getMachHeader]) {
394: numHeaders = 1;
395: for (i = 0, loadCmd = (struct fvmlib_command *)(myHeader + 1);
396: i < myHeader->ncmds;
397: i++,
398: loadCmd = ((void *)loadCmd + loadCmd->cmdsize)) {
399: if (loadCmd->cmd == LC_LOADFVMLIB)
400: numHeaders++;
401: }
402: } else
403: numHeaders = 0;
404: return numHeaders;
405: }
406:
407: -(struct mach_header **)getMachHeadersWithNames: (char ***)names
408: {
409: struct mach_header *myHeader, **headers, *header;
410: char **theNames = NULL;
411: struct fvmlib_command *loadCmd;
412: int numHeaders, headerIndex;
413: numHeaders = [self getNumMachHeaders];
414: myHeader = [self getMachHeader];
415: headers = malloc((numHeaders + 1) * sizeof(*headers));
416: if (names) {
417: *names = theNames = malloc((numHeaders + 1) * sizeof(*theNames));
418: theNames[0] = NULL;
419: }
420: headers[0] = myHeader;
421: for (headerIndex = 1, loadCmd = (struct fvmlib_command *)(myHeader + 1);
422: headerIndex < numHeaders;
423: loadCmd = ((void *)loadCmd + loadCmd->cmdsize)) {
424: if (loadCmd->cmd == LC_LOADFVMLIB) {
425: header = [self pointerFor: (void *)(loadCmd->fvmlib.header_addr)
426: withSize: sizeof(*header)];
427: if (header)
428: headers[headerIndex]
429: = [self pointerFor: (void *)(loadCmd->fvmlib.header_addr)
430: withSize: header->sizeofcmds];
431: if (names)
432: theNames[headerIndex]
433: = (char *)loadCmd
434: + ((struct fvmlib_command *)loadCmd)
435: ->fvmlib.name.offset;
436: headerIndex++;
437: }
438: }
439: headers[numHeaders] = NULL;
440: if (names)
441: theNames[numHeaders] = NULL;
442: return headers;
443: }
444:
445: -(struct mach_header **)getMachHeaders
446: {
447: return [self getMachHeadersWithNames: NULL];
448: }
449:
450: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.