Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 440