Chameleon

Chameleon Svn Source Tree

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

Source at commit 429 created 13 years 9 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"
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: 429