Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 439