Chameleon

Chameleon Svn Source Tree

Root/branches/meklort/i386/boot2/kernel_patcher.c

Source at commit 429 created 13 years 8 months ago.
By meklort, Updated module system. Hooks can now be used within modules when cetaion functions are called in chameleon. Note that onle two hooks currently exist, more need to be added. I also updated the HelloWorld module to use a hook instead of print out right away.
1/*
2 * Copyright (c) 2009 Evan Lojewski. All rights reserved.
3 *
4 */
5
6#include "libsaio.h"
7#include "kernel_patcher.h"
8#include "platform.h"
9
10extern PlatformInfo_t Platform;
11
12
13#define SYMBOL_CPUID_SET_INFO0
14#define SYMBOL_PANIC1
15#define SYMBOL_PMCPUEXITHALTTOOFF2
16#define SYMBOL_LAPIC_INIT3
17#define SYMBOL_COMMPAGE_STUFF_ROUTINE4
18#define NUM_SYMBOLS5
19
20#define SYMBOL_CPUID_SET_INFO_STRING"_cpuid_set_info"
21#define SYMBOL_PANIC_STRING"_panic"
22#define SYMBOL_PMCPUEXITHALTTOOFF_STRING"_pmCPUExitHaltToOff"
23#define SYMBOL_LAPIC_INIT_STRING"_lapic_init"
24#define SYMBOL_COMMPAGE_STUFF_ROUTINE_STRING"_commpage_stuff_routine"
25
26char* kernelSymbols[NUM_SYMBOLS] = {
27SYMBOL_CPUID_SET_INFO_STRING,
28SYMBOL_PANIC_STRING,
29SYMBOL_PMCPUEXITHALTTOOFF_STRING,
30SYMBOL_LAPIC_INIT_STRING,
31SYMBOL_COMMPAGE_STUFF_ROUTINE_STRING
32};
33
34UInt32 kernelSymbolAddresses[NUM_SYMBOLS] = {
350,
360,
370,
380,
390
40};
41
42
43UInt32 textSection = 0;
44UInt32 textAddress = 0;
45
46
47void patch_kernel(void* kernelData)
48{
49switch (locate_symbols((void*)kernelData)) {
50case KERNEL_32:
51patch_kernel_32((void*)kernelData);
52break;
53
54case KERNEL_64:
55default:
56patch_kernel_64((void*)kernelData);
57break;
58}
59}
60
61// patches a 64bit kernel.
62void patch_kernel_64(void* kernelData)
63{
64// At the moment, the kernel patching code fails when used
65// in 64bit mode, so we don't patch it. This is due to 32bit vs 64bit
66// pointers as well as changes in structure sizes
67printf("Unable to patch 64bit kernel. Please use arch=i386.\n");
68}
69
70
71/**
72 ** patch_kernel_32
73 **patches kernel based on cpu info determined earlier in the boot process.
74 **It the machine is vmware, remove the artificial lapic panic
75 **If the CPU is not supported, remove the cpuid_set_info panic
76 **If the CPU is and Intel Atom, inject the penryn cpuid info.
77 **/
78void patch_kernel_32(void* kernelData)
79{
80// Remove panic in commpage
81patch_commpage_stuff_routine(kernelData);
82
83//patch_pmCPUExitHaltToOff(kernelData);// Not working as intended, disabled for now
84
85//if(vmware_detected)
86{
87patch_lapic_init(kernelData);
88}
89
90switch(Platform.CPU.Model)
91{
92// Known good CPU's, no reason to patch kernel
93case 13:
94case CPUID_MODEL_YONAH:
95case CPUID_MODEL_MEROM:
96case CPUID_MODEL_PENRYN:
97case CPUID_MODEL_NEHALEM:
98case CPUID_MODEL_FIELDS:
99case CPUID_MODEL_DALES:
100case CPUID_MODEL_NEHALEM_EX:
101break;
102
103// Known unsuported CPU's
104case CPUID_MODEL_ATOM:
105// TODO: Impersonate CPU based on user selection
106patch_cpuid_set_info(kernelData, CPUFAMILY_INTEL_PENRYN, CPUID_MODEL_PENRYN);// Impersonate Penryn CPU
107break;
108
109// Unknown CPU's
110default:
111// TODO: Impersonate CPU based on user selection
112patch_cpuid_set_info(kernelData, 0, 0);// Remove Panic Call
113
114break;
115}
116}
117
118
119/**
120 **This functions located the kernelSymbols[i] symbols in the mach-o header.
121 **as well as determines the start of the __TEXT segment and __TEXT,__text sections
122 **/
123int locate_symbols(void* kernelData)
124{
125UInt16 symbolIndexes[NUM_SYMBOLS];
126
127struct load_command *loadCommand;
128struct symtab_command *symtableData;
129struct nlist *symbolEntry;
130
131char* symbolString;
132
133UInt32 kernelIndex = 0;
134kernelIndex += sizeof(struct mach_header);
135
136if(((struct mach_header*)kernelData)->magic != MH_MAGIC) return KERNEL_64;
137
138
139//printf("%d load commands beginning at 0x%X\n", (unsigned int)header->ncmds, (unsigned int)kernelIndex);
140//printf("Commands take up %d bytes\n", header->sizeofcmds);
141
142
143int cmd = 0;
144while(cmd < ((struct mach_header*)kernelData)->ncmds)// TODO: for loop instead
145{
146cmd++;
147
148loadCommand = kernelData + kernelIndex;
149
150UInt cmdSize = loadCommand->cmdsize;
151
152
153// Locate start of _panic and _cpuid_set_info in the symbol tabe.
154// Load commands should be anded with 0x7FFFFFFF to ignore theLC_REQ_DYLD flag
155if((loadCommand->cmd & 0x7FFFFFFF) == LC_SYMTAB)// We only care about the symtab segment
156{
157//printf("Located symtable, length is 0x%X, 0x%X\n", (unsigned int)loadCommand->cmdsize, (unsigned int)sizeof(symtableData));
158
159symtableData = kernelData + kernelIndex;
160kernelIndex += sizeof(struct symtab_command);
161
162cmdSize -= sizeof(struct symtab_command);
163
164// Loop through symbol table untill all of the symbols have been found
165
166symbolString = kernelData + symtableData->stroff;
167
168
169UInt16 symbolIndex = 0;
170UInt8 numSymbolsFound = 0;
171
172while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS)// TODO: for loop
173{
174int i = 0;
175while(i < NUM_SYMBOLS)
176{
177if(strcmp(symbolString, kernelSymbols[i]) == 0)
178{
179symbolIndexes[i] = symbolIndex;
180numSymbolsFound++;
181}
182i++;
183
184}
185symbolString += strlen(symbolString) + 1;
186symbolIndex++;
187}
188
189// loop again
190symbolIndex = 0;
191numSymbolsFound = 0;
192while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS)// TODO: for loop
193{
194
195symbolEntry = kernelData + symtableData->symoff + (symbolIndex * sizeof(struct nlist));
196
197int i = 0;
198while(i < NUM_SYMBOLS)
199{
200if(symbolIndex == (symbolIndexes[i] - 4))
201{
202kernelSymbolAddresses[i] = (UInt32)symbolEntry->n_value;
203numSymbolsFound++;
204}
205i++;
206
207}
208
209symbolIndex ++;
210}
211// Load commands should be anded with 0x7FFFFFFF to ignore theLC_REQ_DYLD flag
212} else if((loadCommand->cmd & 0x7FFFFFFF) == LC_SEGMENT)// We only care about the __TEXT segment, any other load command can be ignored
213{
214
215struct segment_command *segCommand;
216
217segCommand = kernelData + kernelIndex;
218
219//printf("Segment name is %s\n", segCommand->segname);
220
221if(strcmp("__TEXT", segCommand->segname) == 0)
222{
223UInt32 sectionIndex;
224
225sectionIndex = sizeof(struct segment_command);
226
227struct section *sect;
228
229while(sectionIndex < segCommand->cmdsize)
230{
231sect = kernelData + kernelIndex + sectionIndex;
232
233sectionIndex += sizeof(struct section);
234
235
236if(strcmp("__text", sect->sectname) == 0)
237{
238// __TEXT,__text found, save the offset and address for when looking for the calls.
239textSection = sect->offset;
240textAddress = sect->addr;
241break;
242}
243}
244}
245
246
247kernelIndex += cmdSize;
248} else {
249kernelIndex += cmdSize;
250}
251}
252
253return KERNEL_32;
254}
255
256
257/**
258 ** Locate the fisrt instance of _panic inside of _cpuid_set_info, and either remove it
259 ** Or replace it so that the cpuid is set to a valid value.
260 **/
261void patch_cpuid_set_info(void* kernelData, UInt32 impersonateFamily, UInt8 impersonateModel)
262{
263UInt8* bytes = (UInt8*)kernelData;
264UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] - textAddress + textSection);
265UInt32 jumpLocation = 0;
266UInt32 panicAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;
267if(kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] == 0)
268{
269printf("Unable to locate _cpuid_set_info\n");
270return;
271
272}
273if(kernelSymbolAddresses[SYMBOL_PANIC] == 0)
274{
275printf("Unable to locate _panic\n");
276return;
277}
278
279//TODO: don't assume it'll always work (Look for *next* function address in symtab and fail once it's been reached)
280while(
281 (bytes[patchLocation -1] != 0xE8) ||
282 ( ( (UInt32)(panicAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
283bytes[patchLocation + 1] << 8 |
284bytes[patchLocation + 2] << 16 |
285bytes[patchLocation + 3] << 24)))
286 )
287{
288patchLocation++;
289}
290patchLocation--;
291
292
293// Remove panic call, just in case the following patch routines fail
294bytes[patchLocation + 0] = 0x90;
295bytes[patchLocation + 1] = 0x90;
296bytes[patchLocation + 2] = 0x90;
297bytes[patchLocation + 3] = 0x90;
298bytes[patchLocation + 4] = 0x90;
299
300
301// Locate the jump call, so that 10 bytes can be reclamed.
302// NOTE: This will *NOT* be located on pre 10.6.2 kernels
303jumpLocation = patchLocation - 15;
304while((bytes[jumpLocation - 1] != 0x77 ||
305 bytes[jumpLocation] != (patchLocation - jumpLocation - -8)) &&
306 (patchLocation - jumpLocation) < 0xF0)
307{
308jumpLocation--;
309}
310
311// If found... AND we want to impersonate a specific cpumodel / family...
312if(impersonateFamily &&
313 impersonateModel &&
314 ((patchLocation - jumpLocation) < 0xF0))
315{
316
317bytes[jumpLocation] -= 10;// sizeof(movl$0x6b5a4cd2,0x00872eb4) = 10bytes
318
319/*
320 * Inpersonate the specified CPU FAMILY and CPU Model
321 */
322
323// bytes[patchLocation - 17] = 0xC7;// already here... not needed to be done
324// bytes[patchLocation - 16] = 0x05;// see above
325UInt32 cpuid_cpufamily_addr =bytes[patchLocation - 15] << 0 |
326bytes[patchLocation - 14] << 8 |
327bytes[patchLocation - 13] << 16 |
328bytes[patchLocation - 12] << 24;
329
330// NOTE: may change, determined based on cpuid_info struct
331UInt32 cpuid_model_addr = cpuid_cpufamily_addr - 299;
332
333
334// cpufamily = CPUFAMILY_INTEL_PENRYN
335bytes[patchLocation - 11] = (impersonateFamily & 0x000000FF) >> 0;
336bytes[patchLocation - 10] = (impersonateFamily & 0x0000FF00) >> 8;
337bytes[patchLocation - 9] = (impersonateFamily & 0x00FF0000) >> 16;
338bytes[patchLocation - 8] = (impersonateFamily & 0xFF000000) >> 24;
339
340// NOPS, just in case if the jmp call wasn't patched, we'll jump to a
341// nop and continue with the rest of the patch
342// Yay two free bytes :), 10 more can be reclamed if needed, as well as a few
343// from the above code (only cpuid_model needs to be set.
344bytes[patchLocation - 7] = 0x90;
345bytes[patchLocation - 6] = 0x90;
346
347bytes[patchLocation - 5] = 0xC7;
348bytes[patchLocation - 4] = 0x05;
349bytes[patchLocation - 3] = (cpuid_model_addr & 0x000000FF) >> 0;
350bytes[patchLocation - 2] = (cpuid_model_addr & 0x0000FF00) >> 8;
351bytes[patchLocation - 1] = (cpuid_model_addr & 0x00FF0000) >> 16;
352bytes[patchLocation - 0] = (cpuid_model_addr & 0xFF000000) >> 24;
353
354// Note: I could have just copied the 8bit cpuid_model in and saved about 4 bytes
355// so if this function need a different patch it's still possible. Also, about ten bytes previous can be freed.
356bytes[patchLocation + 1] = impersonateModel;// cpuid_model
357bytes[patchLocation + 2] = 0x01;// cpuid_extmodel
358bytes[patchLocation + 3] = 0x00;// cpuid_extfamily
359bytes[patchLocation + 4] = 0x02;// cpuid_stepping
360
361}
362else if(impersonateFamily && impersonateModel)
363{
364// pre 10.6.2 kernel
365// Locate the jump to directly *after* the panic call,
366jumpLocation = patchLocation - 4;
367while((bytes[jumpLocation - 1] != 0x77 ||
368 bytes[jumpLocation] != (patchLocation - jumpLocation + 4)) &&
369 (patchLocation - jumpLocation) < 0x20)
370{
371jumpLocation--;
372}
373// NOTE above isn't needed (I was going to use it, but I'm not, so instead,
374// I'll just leave it to verify the binary stucture.
375
376// NOTE: the cpumodel_familt data is not set in _cpuid_set_info
377// so we don't need to set it here, I'll get set later based on the model
378// we set now.
379
380if((patchLocation - jumpLocation) < 0x20)
381{
382UInt32 cpuid_model_addr =(bytes[patchLocation - 14] << 0 |
383bytes[patchLocation - 13] << 8 |
384bytes[patchLocation - 12] << 16 |
385bytes[patchLocation - 11] << 24);
386// Remove jump
387bytes[patchLocation - 9] = 0x90;/// Was a jump if supported cpu
388bytes[patchLocation - 8] = 0x90;// jumped past the panic call, we want to override the panic
389
390bytes[patchLocation - 7] = 0x90;
391bytes[patchLocation - 6] = 0x90;
392
393bytes[patchLocation - 5] = 0xC7;
394bytes[patchLocation - 4] = 0x05;
395bytes[patchLocation - 3] = (cpuid_model_addr & 0x000000FF) >> 0;
396bytes[patchLocation - 2] = (cpuid_model_addr & 0x0000FF00) >> 8;
397bytes[patchLocation - 1] = (cpuid_model_addr & 0x00FF0000) >> 16;
398bytes[patchLocation - 0] = (cpuid_model_addr & 0xFF000000) >> 24;
399
400// Note: I could have just copied the 8bit cpuid_model in and saved about 4 bytes
401// so if this function need a different patch it's still possible. Also, about ten bytes previous can be freed.
402bytes[patchLocation + 1] = impersonateModel;// cpuid_model
403bytes[patchLocation + 2] = 0x01;// cpuid_extmodel
404bytes[patchLocation + 3] = 0x00;// cpuid_extfamily
405bytes[patchLocation + 4] = 0x02;// cpuid_stepping
406
407
408
409patchLocation = jumpLocation;
410// We now have 14 bytes available for a patch
411
412}
413else
414{
415// Patching failed, using NOP replacement done initialy
416}
417}
418else
419{
420// Either We were unable to change the jump call due to the function's sctructure
421// changing, or the user did not request a patch. As such, resort to just
422// removing the panic call (using NOP replacement above). Note that the
423// IntelCPUPM kext may still panic due to the cpu's Model ID not being patched
424}
425}
426
427
428/**
429 ** SleepEnabler.kext replacement (for those that need it)
430 ** Located the KERN_INVALID_ARGUMENT return and replace it with KERN_SUCCESS
431 **/
432void patch_pmCPUExitHaltToOff(void* kernelData)
433{
434UInt8* bytes = (UInt8*)kernelData;
435UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_PMCPUEXITHALTTOOFF] - textAddress + textSection);
436
437if(kernelSymbolAddresses[SYMBOL_PMCPUEXITHALTTOOFF] == 0)
438{
439printf("Unable to locate _pmCPUExitHaltToOff\n");
440return;
441}
442
443while(bytes[patchLocation - 1]!= 0xB8 ||
444 bytes[patchLocation]!= 0x04 ||// KERN_INVALID_ARGUMENT (0x00000004)
445 bytes[patchLocation + 1]!= 0x00 ||// KERN_INVALID_ARGUMENT
446 bytes[patchLocation + 2]!= 0x00 ||// KERN_INVALID_ARGUMENT
447 bytes[patchLocation + 3]!= 0x00)// KERN_INVALID_ARGUMENT
448
449{
450patchLocation++;
451}
452bytes[patchLocation] = 0x00;// KERN_SUCCESS;
453}
454
455void patch_lapic_init(void* kernelData)
456{
457UInt8 panicIndex = 0;
458UInt8* bytes = (UInt8*)kernelData;
459UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_LAPIC_INIT] - textAddress + textSection);
460UInt32 panicAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;
461
462if(kernelSymbolAddresses[SYMBOL_LAPIC_INIT] == 0)
463{
464printf("Unable to locate %s\n", SYMBOL_LAPIC_INIT_STRING);
465return;
466
467}
468if(kernelSymbolAddresses[SYMBOL_PANIC] == 0)
469{
470printf("Unable to locate %s\n", SYMBOL_PANIC_STRING);
471return;
472}
473
474
475
476// Locate the (panicIndex + 1) panic call
477while(panicIndex < 3)// Find the third panic call
478{
479while(
480 (bytes[patchLocation -1] != 0xE8) ||
481 ( ( (UInt32)(panicAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
482bytes[patchLocation + 1] << 8 |
483bytes[patchLocation + 2] << 16 |
484bytes[patchLocation + 3] << 24)))
485 )
486{
487patchLocation++;
488}
489patchLocation++;
490panicIndex++;
491}
492patchLocation--;// Remove extra increment from the < 3 while loop
493
494bytes[--patchLocation] = 0x90;
495bytes[++patchLocation] = 0x90;
496bytes[++patchLocation] = 0x90;
497bytes[++patchLocation] = 0x90;
498bytes[++patchLocation] = 0x90;
499
500
501}
502
503
504void patch_commpage_stuff_routine(void* kernelData)
505{
506UInt8* bytes = (UInt8*)kernelData;
507UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_COMMPAGE_STUFF_ROUTINE] - textAddress + textSection);
508UInt32 panicAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;
509
510if(kernelSymbolAddresses[SYMBOL_COMMPAGE_STUFF_ROUTINE] == 0)
511{
512printf("Unable to locate %s\n", SYMBOL_COMMPAGE_STUFF_ROUTINE_STRING);
513return;
514
515}
516if(kernelSymbolAddresses[SYMBOL_PANIC] == 0)
517{
518printf("Unable to locate %s\n", SYMBOL_PANIC_STRING);
519return;
520}
521
522
523while(
524 (bytes[patchLocation -1] != 0xE8) ||
525 ( ( (UInt32)(panicAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
526bytes[patchLocation + 1] << 8 |
527bytes[patchLocation + 2] << 16 |
528bytes[patchLocation + 3] << 24)))
529 )
530{
531patchLocation++;
532}
533patchLocation--;
534
535
536// Remove panic call, just in case the following patch routines fail
537bytes[patchLocation + 0] = 0x90;
538bytes[patchLocation + 1] = 0x90;
539bytes[patchLocation + 2] = 0x90;
540bytes[patchLocation + 3] = 0x90;
541bytes[patchLocation + 4] = 0x90;
542
543
544}
545

Archive Download this file

Revision: 429