Chameleon

Chameleon Svn Source Tree

Root/branches/meklort/i386/modules/KernelPatcher/kernel_patcher.c

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

Archive Download this file

Revision: 364