Chameleon

Chameleon Svn Source Tree

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

1/*
2 * Copyright (c) 2009-2010 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"
10
11#ifndef DEBUG_KERNEL_PATCHER
12#define DEBUG_KERNEL_PATCHER 0
13#endif
14
15#if DEBUG_KERNEL_PATCHER
16#define DBG(x...)printf(x)
17#else
18#define DBG(x...)
19#endif
20
21long long symbol_handler(char* module, char* symbolName, long long addr, char is64);
22
23patchRoutine_t* patches = NULL;
24kernSymbols_t* kernelSymbols = NULL;
25static void register_kernel_patch(void* patch, int arch, int cpus);
26static void register_kernel_symbol(int kernelType, const char* name);
27static kernSymbols_t* lookup_kernel_symbol(const char* name);
28static int determineKernelArchitecture(void* kernelData);
29static int locate_symbols(void* kernelData);
30static unsigned int parse_mach_64(char *module, void* binary, long long(*symbol_handler)(char*, char*, long long, char));
31static unsigned int handle_symtable_64(char *module, UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, char*, long long, char), char is64);
32
33/*
34 * Internal patches provided by this module.
35 */
36static void patch_cpuid_set_info_all(void* kernelData);
37static void patch_cpuid_set_info_32(void* kernelData, UInt32 impersonateFamily, UInt8 impersonateModel);
38static void patch_cpuid_set_info_64(void* kernelData, UInt32 impersonateFamily, UInt8 impersonateModel);
39
40//static void patch_pmCPUExitHaltToOff(void* kernelData);
41static void patch_lapic_init(void* kernelData);
42static void patch_commpage_stuff_routine(void* kernelData);
43static void patch_lapic_configure(void* kernelData);
44//static void patch_lapic_interrupt(void* kernelData);
45
46void patch_kernel(void* kernelData, void* arg2, void* arg3, void *arg4, void* arg5, void* arg6);
47void kernel_patcher_ignore_cache(void* arg1, void* arg2, void* arg3, void *arg4, void* arg5, void* arg6);
48void kernel_patcher_ignore_cache(void* arg1, void* arg2, void* arg3, void *arg4, void* arg5, void* arg6){}
49
50void KernelPatcher_start(void);
51void KernelPatcher_start(void)
52{
53register_kernel_patch(patch_cpuid_set_info_all, KERNEL_ANY, CPUID_MODEL_UNKNOWN);
54
55register_kernel_patch(patch_commpage_stuff_routine, KERNEL_ANY, CPUID_MODEL_ANY);
56
57register_kernel_patch(patch_lapic_init, KERNEL_ANY, CPUID_MODEL_ANY);
58
59// NOTE: following is currently 32bit only
60register_kernel_patch(patch_lapic_configure, KERNEL_32, CPUID_MODEL_ANY);
61
62register_kernel_symbol(KERNEL_ANY, "_panic");
63register_kernel_symbol(KERNEL_ANY, "_cpuid_set_info");
64register_kernel_symbol(KERNEL_ANY, "_pmCPUExitHaltToOff");
65register_kernel_symbol(KERNEL_ANY, "_lapic_init");
66register_kernel_symbol(KERNEL_ANY, "_commpage_stuff_routine");
67
68// lapic_configure symbols
69register_kernel_symbol(KERNEL_ANY, "_lapic_configure");
70register_kernel_symbol(KERNEL_ANY, "_lapic_start");
71register_kernel_symbol(KERNEL_ANY, "_lapic_interrupt_base");
72
73// lapic_interrup symbols
74//register_kernel_patch(patch_lapic_interrupt, KERNEL_ANY, CPUID_MODEL_ANY);
75//register_kernel_symbol(KERNEL_ANY, "_lapic_interrupt");
76
77// TODO: register needed symbols
78
79register_hook_callback("ExecKernel", &patch_kernel);
80
81replace_system_function("_getKernelCachePath", &kernel_patcher_ignore_cache);
82}
83
84/*
85 * Register a kernel patch
86 */
87static void register_kernel_patch(void* patch, int arch, int cpus)
88{
89// TODO: only insert valid patches based on current cpuid and architecture
90// AKA, don't at 64bit patches if it's a 32bit only machine
91patchRoutine_t* entry;
92
93// Check to ensure that the patch is valid on this machine
94// If it is not, exit early form this function
95if(cpus != get_env(envModel))
96{
97if(cpus != CPUID_MODEL_ANY)
98{
99if(cpus == CPUID_MODEL_UNKNOWN)
100{
101switch(get_env(envModel))
102{
103case 13:
104case CPUID_MODEL_YONAH:
105case CPUID_MODEL_MEROM:
106case CPUID_MODEL_PENRYN:
107case CPUID_MODEL_NEHALEM:
108case CPUID_MODEL_FIELDS:
109case CPUID_MODEL_DALES:
110case CPUID_MODEL_NEHALEM_EX:
111// Known cpu's we don't want to add the patch
112return;
113break;
114
115default:
116// CPU not in supported list, so we are going to add
117// The patch will be applied
118break;
119}
120}
121else
122{
123// Invalid cpuid for current cpu. Ignoring patch
124return;
125}
126}
127}
128
129if(patches == NULL)
130{
131patches = entry = malloc(sizeof(patchRoutine_t));
132}
133else
134{
135entry = patches;
136while(entry->next)
137{
138entry = entry->next;
139}
140
141entry->next = malloc(sizeof(patchRoutine_t));
142entry = entry->next;
143}
144
145entry->next = NULL;
146entry->patchRoutine = patch;
147entry->validArchs = arch;
148entry->validCpu = cpus;
149}
150
151static void register_kernel_symbol(int kernelType, const char* name)
152{
153if(kernelSymbols == NULL)
154{
155kernelSymbols = malloc(sizeof(kernSymbols_t));
156kernelSymbols->next = NULL;
157kernelSymbols->symbol = (char*)name;
158kernelSymbols->addr = 0;
159}
160else
161{
162kernSymbols_t *symbol = kernelSymbols;
163while(symbol->next != NULL)
164{
165symbol = symbol->next;
166}
167
168symbol->next = malloc(sizeof(kernSymbols_t));
169symbol = symbol->next;
170
171symbol->next = NULL;
172symbol->symbol = (char*)name;
173symbol->addr = 0;
174}
175}
176
177static kernSymbols_t* lookup_kernel_symbol(const char* name)
178{
179kernSymbols_t *symbol = kernelSymbols;
180
181while(symbol && strcmp(symbol->symbol, name) !=0)
182{
183symbol = symbol->next;
184}
185
186if(!symbol)
187{
188return NULL;
189}
190else
191{
192return symbol;
193}
194}
195
196void patch_kernel(void* kernelData, void* arg2, void* arg3, void *arg4, void* arg5, void* arg6)
197{
198patchRoutine_t* entry = patches;
199
200int arch = determineKernelArchitecture(kernelData);
201
202locate_symbols(kernelData);
203
204if(patches != NULL)
205{
206while(entry)
207{
208if(entry->validArchs == KERNEL_ANY || arch == entry->validArchs)
209{
210if(entry->patchRoutine) entry->patchRoutine(kernelData);
211}
212entry = entry->next;
213}
214}
215}
216
217static int determineKernelArchitecture(void* kernelData)
218{
219if(((struct mach_header*)kernelData)->magic == MH_MAGIC)
220{
221return KERNEL_32;
222}
223
224if(((struct mach_header*)kernelData)->magic == MH_MAGIC_64)
225{
226return KERNEL_64;
227}
228else
229{
230return KERNEL_ERR;
231}
232}
233
234static unsigned int parse_mach_64(char *module, void* binary, long long(*symbol_handler)(char*, char*, long long, char))// TODO: add param to specify valid archs
235{
236char is64 = false;
237unsigned int module_start = 0xFFFFFFFF;
238EFI_STATUS bind_status = EFI_SUCCESS;
239
240// TODO convert all of the structs to a union
241struct dyld_info_command* dyldInfoCommand = NULL;
242struct symtab_command* symtabCommand = NULL;
243
244{
245struct segment_command *segCommand = NULL;
246struct segment_command_64 *segCommand64 = NULL;
247struct load_command *loadCommand = NULL;
248UInt32 binaryIndex = 0;
249UInt16 cmd = 0;
250
251// Parse through the load commands
252if(((struct mach_header*)binary)->magic == MH_MAGIC)
253{
254is64 = false;
255binaryIndex += sizeof(struct mach_header);
256}
257else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)
258{
259// NOTE: modules cannot be 64bit...
260is64 = true;
261binaryIndex += sizeof(struct mach_header_64);
262}
263else
264{
265printf("Modules: Invalid mach magic\n");
266getc();
267return 0xFFFFFFFF;
268}
269
270
271
272/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)
273 {
274 printf("Module is not a dylib. Unable to load.\n");
275 getc();
276 return NULL; // Module is in the incorrect format
277 }*/
278
279while(cmd < ((struct mach_header*)binary)->ncmds)
280{
281cmd++;
282
283loadCommand = binary + binaryIndex;
284UInt32 cmdSize = loadCommand->cmdsize;
285
286
287switch ((loadCommand->cmd & 0x7FFFFFFF))
288{
289case LC_SYMTAB:
290symtabCommand = binary + binaryIndex;
291break;
292
293case LC_SEGMENT: // 32bit macho
294{
295segCommand = binary + binaryIndex;
296
297//printf("Segment name is %s\n", segCommand->segname);
298
299if(strncmp("__TEXT", segCommand->segname, sizeof("__TEXT")) == 0)
300{
301UInt32 sectionIndex;
302
303#if DEBUG_KERNEL_PATCHER
304unsigned long fileaddr;
305long filesize;
306vmaddr = (segCommand->vmaddr & 0x3fffffff);
307vmsize = segCommand->vmsize;
308fileaddr = ((unsigned long)(binary + binaryIndex) + segCommand->fileoff);
309filesize = segCommand->filesize;
310
311printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
312 segCommand->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
313 (unsigned) segCommand->nsects, (unsigned)segCommand->flags);
314#if DEBUG_KERNEL_PATCHER==2
315
316getc();
317#endif
318#endif
319
320sectionIndex = sizeof(struct segment_command);
321
322struct section *sect;
323
324while(sectionIndex < segCommand->cmdsize)
325{
326sect = binary + binaryIndex + sectionIndex;
327
328sectionIndex += sizeof(struct section);
329
330
331if(strncmp("__text", sect->sectname,sizeof("__text")) == 0)
332{
333// __TEXT,__text found, save the offset and address for when looking for the calls.
334textSection = sect->offset;
335textAddress = sect->addr;
336break;
337}
338}
339}
340break;
341}
342case LC_SEGMENT_64:// 64bit macho's
343{
344segCommand64 = binary + binaryIndex;
345
346//printf("Segment name is %s\n", segCommand->segname);
347
348if(strncmp("__TEXT", segCommand64->segname, sizeof("__TEXT")) == 0)
349{
350UInt32 sectionIndex;
351
352#if DEBUG_KERNEL_PATCHER
353unsigned long fileaddr;
354long filesize;
355vmaddr = (segCommand64->vmaddr & 0x3fffffff);
356vmsize = segCommand64->vmsize;
357fileaddr = ((unsigned long)(binary + binaryIndex) + segCommand64->fileoff);
358filesize = segCommand64->filesize;
359
360printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
361 segCommand64->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
362 (unsigned) segCommand64->nsects, (unsigned)segCommand64->flags);
363#if DEBUG_KERNEL_PATCHER==2
364
365getc();
366#endif
367#endif
368
369sectionIndex = sizeof(struct segment_command_64);
370
371struct section_64 *sect;
372
373while(sectionIndex < segCommand64->cmdsize)
374{
375sect = binary + binaryIndex + sectionIndex;
376
377sectionIndex += sizeof(struct section_64);
378
379
380if(strncmp("__text", sect->sectname, sizeof("__text")) == 0)
381{
382// __TEXT,__text found, save the offset and address for when looking for the calls.
383textSection = sect->offset;
384textAddress = sect->addr;
385
386break;
387}
388}
389}
390
391break;
392}
393case LC_DYSYMTAB:
394break;
395
396case LC_LOAD_DYLIB:
397case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
398 break;
399
400case LC_ID_DYLIB:
401 break;
402
403
404case LC_DYLD_INFO:
405// Bind and rebase info is stored here
406dyldInfoCommand = binary + binaryIndex;
407break;
408
409case LC_UUID:
410break;
411
412case LC_UNIXTHREAD:
413break;
414
415default:
416DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
417break;
418
419}
420
421binaryIndex += cmdSize;
422}
423//if(!moduleName) return NULL;
424}
425
426// bind_macho uses the symbols.
427module_start = handle_symtable_64(module, (UInt32)binary, symtabCommand, symbol_handler, is64);
428
429// Rebase the module before binding it.
430if(dyldInfoCommand && dyldInfoCommand->rebase_off)
431{
432rebase_macho(binary, (char*)dyldInfoCommand->rebase_off, dyldInfoCommand->rebase_size);
433}
434
435if(dyldInfoCommand && dyldInfoCommand->bind_off)
436{
437bind_status = bind_macho(module, binary, (char*)dyldInfoCommand->bind_off, dyldInfoCommand->bind_size);
438}
439
440if(dyldInfoCommand && dyldInfoCommand->weak_bind_off && (bind_status == EFI_SUCCESS))
441{
442// NOTE: this currently should never happen.
443bind_status = bind_macho(module, binary, (char*)dyldInfoCommand->weak_bind_off, dyldInfoCommand->weak_bind_size);
444}
445
446if(dyldInfoCommand && dyldInfoCommand->lazy_bind_off && (bind_status == EFI_SUCCESS))
447{
448// NOTE: we are binding the lazy pointers as a module is laoded,
449// This should be changed to bind when a symbol is referened at runtime instead.
450bind_status = bind_macho(module, binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size);
451}
452
453 if (bind_status != EFI_SUCCESS) {
454 module_start = 0xFFFFFFFF;
455 }
456
457return module_start;
458
459}
460
461static unsigned int handle_symtable_64(char *module, UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, char*, long long, char), char is64)
462{
463unsigned int module_start = 0xFFFFFFFF;
464
465UInt32 symbolIndex = 0;
466 if (!symtabCommand) {
467 return 0xFFFFFFFF;
468 }
469char* symbolString = base + (char*)symtabCommand->stroff;
470if(!is64)
471{
472struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
473while(symbolIndex < symtabCommand->nsyms)
474{
475if(symbolEntry->n_value)
476{
477if(strstr(symbolString + symbolEntry->n_un.n_strx, "module_start") || (strncmp(symbolString + symbolEntry->n_un.n_strx, "start", sizeof("start")) == 0))
478{
479module_start = base + symbolEntry->n_value;
480DBG("n_value %x module_start %x\n", (unsigned)symbolEntry->n_value, (unsigned)module_start);
481}
482else
483{
484symbol_handler(module, symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64);
485
486
487}
488#if DEBUG_KERNEL_PATCHER
489bool isTexT = (((unsigned)symbolEntry->n_value > (unsigned)vmaddr) && ((unsigned)(vmaddr + vmsize) > (unsigned)symbolEntry->n_value ));
490printf("%s %s\n", isTexT ? "__TEXT :" : "__DATA(OR ANY) :", symbolString + symbolEntry->n_un.n_strx);
491#if DEBUG_KERNEL_PATCHER==2
492
493if(strcmp(symbolString + symbolEntry->n_un.n_strx, "_BootHelp_txt") == 0)
494{
495long long addr = (long long)base + symbolEntry->n_value;
496unsigned char *BootHelp = NULL;
497BootHelp = (unsigned char*)(UInt32)addr;
498printf("method 1: __DATA : BootHelp_txt[0] %x\n", BootHelp[0]);
499
500long long addr2 = symbolEntry->n_value;
501unsigned char *BootHelp2 = NULL;
502BootHelp2 = (unsigned char*)(UInt32)addr2;
503printf("method 2: __DATA : BootHelp_txt[0] %x\n", BootHelp2[0]);
504}
505#endif
506#endif
507
508}
509
510symbolEntry++;
511symbolIndex++;// TODO remove
512}
513}
514else
515{
516struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
517// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now)
518while(symbolIndex < symtabCommand->nsyms)
519{
520
521if(strstr(symbolString + symbolEntry->n_un.n_strx, "module_start") || (strncmp(symbolString + symbolEntry->n_un.n_strx, "start",sizeof("start")) == 0))
522{
523module_start = (unsigned int)(base + symbolEntry->n_value);
524}
525else
526{
527symbol_handler(module, symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64);
528}
529
530symbolEntry++;
531symbolIndex++;// TODO remove
532}
533}
534return module_start;
535
536}
537
538/**
539 **This functions located the requested symbols in the mach-o file.
540 **as well as determines the start of the __TEXT segment and __TEXT,__text sections
541 **/
542static int locate_symbols(void* kernelData)
543{
544char is64 = 1;
545parse_mach_64("VirtualXnuSyms",kernelData, symbol_handler);
546//handle_symtable((UInt32)kernelData, symtableData, &symbol_handler, determineKernelArchitecture(kernelData) == KERNEL_64);
547return 1 << is64;
548}
549
550long long symbol_handler(char* module, char* symbolName, long long addr, char is64)
551{
552// Locate the symbol in the list, if it exists, update it's address
553kernSymbols_t *symbol = lookup_kernel_symbol(symbolName);
554
555if(symbol)
556{
557symbol->addr = addr;
558}
559
560return 0xFFFFFFFF; // fixme
561}
562
563/**
564 ** Locate the fisrt instance of _panic inside of _cpuid_set_info, and either remove it
565 ** Or replace it so that the cpuid is set to a valid value.
566 **/
567static void patch_cpuid_set_info_all(void* kernelData)
568{
569switch(get_env(envModel))
570{
571case CPUID_MODEL_ATOM:
572if(determineKernelArchitecture(kernelData) == KERNEL_32)
573{
574patch_cpuid_set_info_32(kernelData, CPUFAMILY_INTEL_PENRYN, CPUID_MODEL_PENRYN);
575}
576else
577{
578patch_cpuid_set_info_64(kernelData, CPUFAMILY_INTEL_PENRYN, CPUID_MODEL_PENRYN);
579}
580
581break;
582
583default:
584{
585// AnV: Extra cpuid fix for spoofing Nehalem CPU for i5/i9
586switch(get_env(envFamily))
587{
588case 0x1E: /* Intel i5 */
589case 0x2C: /* Intel i9 */
590if(determineKernelArchitecture(kernelData) == KERNEL_32)
591{
592patch_cpuid_set_info_32(kernelData, CPUFAMILY_INTEL_NEHALEM, CPUID_MODEL_NEHALEM);
593}
594else
595{
596patch_cpuid_set_info_64(kernelData, CPUFAMILY_INTEL_NEHALEM, CPUID_MODEL_NEHALEM);
597}
598
599break;
600
601default:
602if(determineKernelArchitecture(kernelData) == KERNEL_32)
603{
604patch_cpuid_set_info_32(kernelData, 0, 0);
605}
606else
607{
608patch_cpuid_set_info_64(kernelData, 0, 0);
609}
610break;
611}
612break;
613}
614}
615}
616
617static void patch_cpuid_set_info_64(void* kernelData, UInt32 impersonateFamily, UInt8 impersonateModel)
618{
619UInt8* bytes = (UInt8*)kernelData;
620
621kernSymbols_t *symbol = lookup_kernel_symbol("_cpuid_set_info");
622
623UInt32 patchLocation = symbol ? symbol->addr - textAddress + textSection: 0; //(kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] - textAddress + textSection);
624patchLocation -= (UInt32)kernelData;// Remove offset
625
626//UInt32 jumpLocation = 0;
627
628if(symbol == 0 || symbol->addr == 0)
629{
630verbose("Unable to locate _cpuid_set_info\n");
631return;
632}
633
634symbol = lookup_kernel_symbol("_panic");
635UInt32 panicAddr = symbol ? symbol->addr - textAddress: 0; //kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;
636if(symbol == 0 || symbol->addr == 0)
637{
638printf("Unable to locate _panic\n");
639return;
640}
641panicAddr -= (UInt32)kernelData;
642
643//TODO: don't assume it'll always work (Look for *next* function address in symtab and fail once it's been reached)
644while(
645 (bytes[patchLocation -1] != 0xE8) ||
646 ( ( (UInt32)(panicAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
647bytes[patchLocation + 1] << 8 |
648bytes[patchLocation + 2] << 16 |
649bytes[patchLocation + 3] << 24)))
650 )
651{
652patchLocation++;
653}
654patchLocation--;
655
656// Remove panic just in ca se
657// The panic instruction is exactly 5 bytes long.
658bytes[patchLocation + 0] = 0x90;
659bytes[patchLocation + 1] = 0x90;
660bytes[patchLocation + 2] = 0x90;
661bytes[patchLocation + 3] = 0x90;
662bytes[patchLocation + 4] = 0x90;
663
664// Check for a 10.2.0+ kernel
665if(bytes[patchLocation - 19] == 0xC7 && bytes[patchLocation - 18] == 0x05)
666{
667UInt32 cpuid_cpufamily_addr =bytes[patchLocation - 17] << 0 |
668bytes[patchLocation - 16] << 8 |
669bytes[patchLocation - 15] << 16 |
670bytes[patchLocation - 14] << 24;
671
672// NOTE: may change, determined based on cpuid_info struct
673UInt32 cpuid_model_addr = cpuid_cpufamily_addr - 310;
674
675//ffffff8000228b3b -> 0x00490e8b
676//ffffff8000228c28 -> -237 -> 0x490D9E -> -310
677
678// The mov is 10 bytes
679/*
680 bytes[patchLocation - 19] = 0x90;// c7
681 bytes[patchLocation - 18] = 0x90;// 05
682 bytes[patchLocation - 17] = 0x90;// family location
683 bytes[patchLocation - 16] = 0x90;// family location
684 bytes[patchLocation - 15] = 0x90;// family location
685 bytes[patchLocation - 14] = 0x90;// family location
686 */
687bytes[patchLocation - 13] = (impersonateFamily & 0x000000FF) >> 0;
688bytes[patchLocation - 12] = (impersonateFamily & 0x0000FF00) >> 8;
689bytes[patchLocation - 11] = (impersonateFamily & 0x00FF0000) >> 16;
690bytes[patchLocation - 10] = (impersonateFamily & 0xFF000000) >> 24;
691
692// The lea (%rip),%rip is 7 bytes
693bytes[patchLocation - 9] = 0xC7;
694bytes[patchLocation - 8] = 0x05;
695bytes[patchLocation - 7] = ((cpuid_model_addr -10) & 0x000000FF) >> 0;// NOTE: this opcode is relative in 64bit mode, subtract offset
696bytes[patchLocation - 6] = ((cpuid_model_addr -10) & 0x0000FF00) >> 8;
697bytes[patchLocation - 5] = ((cpuid_model_addr -10) & 0x00FF0000) >> 16;
698bytes[patchLocation - 4] = ((cpuid_model_addr -10) & 0xFF000000) >> 24;
699bytes[patchLocation - 3] = impersonateModel;// cpuid_model
700
701// The xor eax eax is 2 bytes
702bytes[patchLocation - 2] = 0x01;// cpuid_extmodel
703bytes[patchLocation - 1] = 0x00;// cpuid_extfamily
704
705// The panic instruction is exactly 5 bytes long.
706bytes[patchLocation - 0] = 0x02;// cpuid_stepping
707/*bytes[patchLocation + 1] = 0x90;
708bytes[patchLocation + 2] = 0x90;
709bytes[patchLocation + 3] = 0x90;
710bytes[patchLocation + 4] = 0x90;
711*/
712
713// Panic call has been removed.
714// Override the CPUID now. This requires ~ 10 bytes on 10.0.0 kernels
715// On 10.2.0+ kernels, this requires ~16 bytes
716
717// Total: 24 bytes
718printf("Running on a 10.2.0+ kernel\n");
719getc();
720}
721else {
722printf("Running on a 10.0.0 kernel, patch unsupported\n");
723getc();
724}
725}
726
727static void patch_cpuid_set_info_32(void* kernelData, UInt32 impersonateFamily, UInt8 impersonateModel)
728{
729UInt8* bytes = (UInt8*)kernelData;
730
731kernSymbols_t *symbol = lookup_kernel_symbol("_cpuid_set_info");
732
733UInt32 patchLocation = symbol ? symbol->addr - textAddress + textSection: 0; //(kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] - textAddress + textSection);
734patchLocation -= (UInt32)kernelData;// Remove offset
735
736UInt32 jumpLocation = 0;
737
738if(symbol == 0 || symbol->addr == 0)
739{
740verbose("Unable to locate _cpuid_set_info\n");
741return;
742}
743
744symbol = lookup_kernel_symbol("_panic");
745UInt32 panicAddr = symbol ? symbol->addr - textAddress: 0; //kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;
746if(symbol == 0 || symbol->addr == 0)
747{
748printf("Unable to locate _panic\n");
749return;
750}
751panicAddr -= (UInt32)kernelData;
752
753//TODO: don't assume it'll always work (Look for *next* function address in symtab and fail once it's been reached)
754while(
755 (bytes[patchLocation -1] != 0xE8) ||
756 ( ( (UInt32)(panicAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
757bytes[patchLocation + 1] << 8 |
758bytes[patchLocation + 2] << 16 |
759bytes[patchLocation + 3] << 24)))
760 )
761{
762patchLocation++;
763}
764patchLocation--;
765
766// Remove panic call, just in case the following patch routines fail
767bytes[patchLocation + 0] = 0x90;
768bytes[patchLocation + 1] = 0x90;
769bytes[patchLocation + 2] = 0x90;
770bytes[patchLocation + 3] = 0x90;
771bytes[patchLocation + 4] = 0x90;
772
773// Locate the jump call, so that 10 bytes can be reclamed.
774// NOTE: This will *NOT* be located on pre 10.6.2 kernels
775jumpLocation = patchLocation - 15;
776while((bytes[jumpLocation - 1] != 0x77 ||
777 bytes[jumpLocation] != (patchLocation - jumpLocation - -8)) &&
778 (patchLocation - jumpLocation) < 0xF0)
779{
780jumpLocation--;
781}
782
783// If found... AND we want to impersonate a specific cpumodel / family...
784if(impersonateFamily &&
785 impersonateModel &&
786 ((patchLocation - jumpLocation) < 0xF0))
787{
788
789bytes[jumpLocation] -= 10;// sizeof(movl$0x6b5a4cd2,0x00872eb4) = 10bytes
790
791/*
792 * Inpersonate the specified CPU FAMILY and CPU Model
793 */
794
795// bytes[patchLocation - 17] = 0xC7;// already here... not needed to be done
796// bytes[patchLocation - 16] = 0x05;// see above
797UInt32 cpuid_cpufamily_addr =bytes[patchLocation - 15] << 0 |
798bytes[patchLocation - 14] << 8 |
799bytes[patchLocation - 13] << 16 |
800bytes[patchLocation - 12] << 24;
801
802// NOTE: may change, determined based on cpuid_info struct
803UInt32 cpuid_model_addr = cpuid_cpufamily_addr - 299;
804
805// cpufamily
806bytes[patchLocation - 11] = (impersonateFamily & 0x000000FF) >> 0;
807bytes[patchLocation - 10] = (impersonateFamily & 0x0000FF00) >> 8;
808bytes[patchLocation - 9] = (impersonateFamily & 0x00FF0000) >> 16;
809bytes[patchLocation - 8] = (impersonateFamily & 0xFF000000) >> 24;
810
811// NOPS, just in case if the jmp call wasn't patched, we'll jump to a
812// nop and continue with the rest of the patch
813// Yay two free bytes :), 10 more can be reclamed if needed, as well as a few
814// from the above code (only cpuid_model needs to be set.
815bytes[patchLocation - 7] = 0x90;
816bytes[patchLocation - 6] = 0x90;
817
818bytes[patchLocation - 5] = 0xC7;
819bytes[patchLocation - 4] = 0x05;
820bytes[patchLocation - 3] = (cpuid_model_addr & 0x000000FF) >> 0;
821bytes[patchLocation - 2] = (cpuid_model_addr & 0x0000FF00) >> 8;
822bytes[patchLocation - 1] = (cpuid_model_addr & 0x00FF0000) >> 16;
823bytes[patchLocation - 0] = (cpuid_model_addr & 0xFF000000) >> 24;
824
825// Note: I could have just copied the 8bit cpuid_model in and saved about 4 bytes
826// so if this function need a different patch it's still possible. Also, about ten bytes previous can be freed.
827bytes[patchLocation + 1] = impersonateModel;// cpuid_model
828bytes[patchLocation + 2] = 0x01;// cpuid_extmodel
829bytes[patchLocation + 3] = 0x00;// cpuid_extfamily
830bytes[patchLocation + 4] = 0x02;// cpuid_stepping
831}
832else if(impersonateFamily && impersonateModel)
833{
834// pre 10.6.2 kernel
835// Locate the jump to directly *after* the panic call,
836jumpLocation = patchLocation - 4;
837while((bytes[jumpLocation - 1] != 0x77 ||
838 bytes[jumpLocation] != (patchLocation - jumpLocation + 4)) &&
839 (patchLocation - jumpLocation) < 0x20)
840{
841jumpLocation--;
842}
843// NOTE above isn't needed (I was going to use it, but I'm not, so instead,
844// I'll just leave it to verify the binary stucture.
845
846// NOTE: the cpumodel_familt data is not set in _cpuid_set_info
847// so we don't need to set it here, I'll get set later based on the model
848// we set now.
849
850if((patchLocation - jumpLocation) < 0x20)
851{
852UInt32 cpuid_model_addr =(bytes[patchLocation - 14] << 0 |
853 bytes[patchLocation - 13] << 8 |
854 bytes[patchLocation - 12] << 16 |
855 bytes[patchLocation - 11] << 24);
856// Remove jump
857bytes[patchLocation - 9] = 0x90;/// Was a jump if supported cpu
858bytes[patchLocation - 8] = 0x90;// jumped past the panic call, we want to override the panic
859
860bytes[patchLocation - 7] = 0x90;
861bytes[patchLocation - 6] = 0x90;
862
863bytes[patchLocation - 5] = 0xC7;
864bytes[patchLocation - 4] = 0x05;
865bytes[patchLocation - 3] = (cpuid_model_addr & 0x000000FF) >> 0;
866bytes[patchLocation - 2] = (cpuid_model_addr & 0x0000FF00) >> 8;
867bytes[patchLocation - 1] = (cpuid_model_addr & 0x00FF0000) >> 16;
868bytes[patchLocation - 0] = (cpuid_model_addr & 0xFF000000) >> 24;
869
870// Note: I could have just copied the 8bit cpuid_model in and saved about 4 bytes
871// so if this function need a different patch it's still possible. Also, about ten bytes previous can be freed.
872bytes[patchLocation + 1] = impersonateModel;// cpuid_model
873bytes[patchLocation + 2] = 0x01;// cpuid_extmodel
874bytes[patchLocation + 3] = 0x00;// cpuid_extfamily
875bytes[patchLocation + 4] = 0x02;// cpuid_stepping
876
877#if 0
878patchLocation = jumpLocation;
879#endif
880// We now have 14 bytes available for a patch
881}
882else
883{
884// Patching failed, using NOP replacement done initialy
885}
886}
887else
888{
889// Either We were unable to change the jump call due to the function's sctructure
890// changing, or the user did not request a patch. As such, resort to just
891// removing the panic call (using NOP replacement above). Note that the
892// IntelCPUPM kext may still panic due to the cpu's Model ID not being patched
893}
894}
895
896/**
897 ** SleepEnabler.kext replacement (for those that need it)
898 ** Located the KERN_INVALID_ARGUMENT return and replace it with KERN_SUCCESS
899 **/
900#if 0
901static void patch_pmCPUExitHaltToOff(void* kernelData)
902{
903UInt8* bytes = (UInt8*)kernelData;
904
905kernSymbols_t *symbol = lookup_kernel_symbol("_PmCpuExitHaltToOff");
906UInt32 patchLocation = symbol ? symbol->addr - textAddress + textSection: 0;
907
908if(symbol == 0 || symbol->addr == 0)
909{
910printf("Unable to locate _pmCPUExitHaltToOff\n");
911return;
912}
913
914patchLocation -= (UInt32)kernelData;// Remove offset
915
916while(bytes[patchLocation - 1]!= 0xB8 ||
917 bytes[patchLocation]!= 0x04 ||// KERN_INVALID_ARGUMENT (0x00000004)
918 bytes[patchLocation + 1]!= 0x00 ||// KERN_INVALID_ARGUMENT
919 bytes[patchLocation + 2]!= 0x00 ||// KERN_INVALID_ARGUMENT
920 bytes[patchLocation + 3]!= 0x00)// KERN_INVALID_ARGUMENT
921
922{
923patchLocation++;
924}
925bytes[patchLocation] = 0x00;// KERN_SUCCESS;
926}
927#endif
928
929static void patch_lapic_init(void* kernelData)
930{
931UInt8 panicIndex = 0;
932UInt8* bytes = (UInt8*)kernelData;
933
934kernSymbols_t *symbol = lookup_kernel_symbol("_lapic_init");
935UInt32 patchLocation = symbol ? symbol->addr - textAddress + textSection: 0;
936if(symbol == 0 || symbol->addr == 0)
937{
938printf("Unable to locate %s\n", "_lapic_init");
939return;
940}
941
942symbol = lookup_kernel_symbol("_panic");
943UInt32 panicAddr = symbol ? symbol->addr - textAddress: 0;
944if(symbol == 0 || symbol->addr == 0)
945{
946printf("Unable to locate %s\n", "_panic");
947return;
948}
949
950patchLocation -= (UInt32)kernelData;// Remove offset
951panicAddr -= (UInt32)kernelData;// Remove offset
952
953// Locate the (panicIndex + 1) panic call
954while(panicIndex < 3)// Find the third panic call
955{
956while(
957 (bytes[patchLocation -1] != 0xE8) ||
958 ( ( (UInt32)(panicAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
959bytes[patchLocation + 1] << 8 |
960bytes[patchLocation + 2] << 16 |
961bytes[patchLocation + 3] << 24)))
962 )
963{
964patchLocation++;
965}
966patchLocation++;
967panicIndex++;
968}
969patchLocation--;// Remove extra increment from the < 3 while loop
970
971bytes[--patchLocation] = 0x90;
972bytes[++patchLocation] = 0x90;
973bytes[++patchLocation] = 0x90;
974bytes[++patchLocation] = 0x90;
975bytes[++patchLocation] = 0x90;
976}
977
978static void patch_commpage_stuff_routine(void* kernelData)
979{
980UInt8* bytes = (UInt8*)kernelData;
981
982kernSymbols_t *symbol = lookup_kernel_symbol("_commpage_stuff_routine");
983if(symbol == 0 || symbol->addr == 0)
984{
985//printf("Unable to locate %s\n", "_commpage_stuff_routine");
986return;
987
988}
989
990UInt32 patchLocation = symbol->addr - textAddress + textSection;
991
992symbol = lookup_kernel_symbol("_panic");
993if(symbol == 0 || symbol->addr == 0)
994{
995printf("Unable to locate %s\n", "_panic");
996return;
997}
998UInt32 panicAddr = symbol->addr - textAddress;
999
1000patchLocation -= (UInt32)kernelData;
1001panicAddr -= (UInt32)kernelData;
1002
1003while(
1004 (bytes[patchLocation -1] != 0xE8) ||
1005 ( ( (UInt32)(panicAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
1006bytes[patchLocation + 1] << 8 |
1007bytes[patchLocation + 2] << 16 |
1008bytes[patchLocation + 3] << 24)))
1009 )
1010{
1011patchLocation++;
1012}
1013patchLocation--;
1014
1015// Replace panic with nops
1016bytes[patchLocation + 0] = 0x90;
1017bytes[patchLocation + 1] = 0x90;
1018bytes[patchLocation + 2] = 0x90;
1019bytes[patchLocation + 3] = 0x90;
1020bytes[patchLocation + 4] = 0x90;
1021}
1022#if 0
1023static void patch_lapic_interrupt(void* kernelData)
1024{
1025// NOTE: this is a hack untill I finish patch_lapic_configure
1026UInt8* bytes = (UInt8*)kernelData;
1027
1028kernSymbols_t *symbol = lookup_kernel_symbol("_lapic_interrupt");
1029if(symbol == 0 || symbol->addr == 0)
1030{
1031printf("Unable to locate %s\n", "_lapic_interrupt");
1032return;
1033}
1034
1035UInt32 patchLocation = symbol->addr - textAddress + textSection;
1036
1037symbol = lookup_kernel_symbol("_panic");
1038if(symbol == 0 || symbol->addr == 0)
1039{
1040printf("Unable to locate %s\n", "_panic");
1041return;
1042}
1043UInt32 panicAddr = symbol->addr - textAddress;
1044
1045patchLocation -= (UInt32)kernelData;
1046panicAddr -= (UInt32)kernelData;
1047
1048while(
1049 (bytes[patchLocation -1] != 0xE8) ||
1050 ( ( (UInt32)(panicAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
1051bytes[patchLocation + 1] << 8 |
1052bytes[patchLocation + 2] << 16 |
1053bytes[patchLocation + 3] << 24)))
1054 )
1055{
1056patchLocation++;
1057}
1058patchLocation--;
1059
1060// Replace panic with nops
1061bytes[patchLocation + 0] = 0x90;
1062bytes[patchLocation + 1] = 0x90;
1063bytes[patchLocation + 2] = 0x90;
1064bytes[patchLocation + 3] = 0x90;
1065bytes[patchLocation + 4] = 0x90;
1066}
1067#endif
1068static void patch_lapic_configure(void* kernelData)
1069{
1070UInt8* bytes = (UInt8*)kernelData;
1071
1072UInt32 patchLocation;
1073UInt32 lapicStart;
1074UInt32 lapicInterruptBase;
1075
1076kernSymbols_t *symbol = lookup_kernel_symbol("_lapic_configure");
1077if(symbol == 0 || symbol->addr == 0)
1078{
1079printf("Unable to locate %s\n", "_lapic_configure");
1080return;
1081}
1082patchLocation = symbol->addr - textAddress + textSection;
1083
1084symbol = lookup_kernel_symbol("_lapic_start");
1085if(symbol == 0 || symbol->addr == 0)
1086{
1087printf("Unable to locate %s\n", "_lapic_start");
1088return;
1089}
1090lapicStart = symbol->addr;
1091
1092symbol = lookup_kernel_symbol("_lapic_interrupt_base");
1093if(symbol == 0 || symbol->addr == 0)
1094{
1095printf("Unable to locate %s\n", "_lapic_interrupt_base");
1096return;
1097}
1098lapicInterruptBase = symbol->addr;
1099patchLocation -= (UInt32)kernelData;
1100lapicStart -= (UInt32)kernelData;
1101lapicInterruptBase -= (UInt32)kernelData;
1102
1103// Looking for the following:
1104//movl _lapic_start,%e_x
1105//addl $0x00000320,%e_x
1106// 8b 15 __ __ __ __ 81 c2 20 03 00 00
1107while(
1108 (bytes[patchLocation - 2] != 0x8b) ||
1109 //bytes[patchLocation -1] != 0x15) ||// Register, we don't care what it is
1110 ( lapicStart != (UInt32)(
1111(bytes[patchLocation + 0] << 0 |
1112 bytes[patchLocation + 1] << 8 |
1113 bytes[patchLocation + 2] << 16 |
1114 bytes[patchLocation + 3] << 24
1115)
1116 )
1117 ) ||
1118 (bytes[patchLocation + 4 ] != 0x81) ||
1119 //(bytes[patchLocation + 5 ] != 0Cx2) ||// register
1120 (bytes[patchLocation + 6 ] != 0x20) ||
1121 (bytes[patchLocation + 7 ] != 0x03) ||
1122 (bytes[patchLocation + 8 ] != 0x00) ||
1123 (bytes[patchLocation + 9] != 0x00)
1124
1125 )
1126{
1127patchLocation++;
1128}
1129patchLocation-=2;
1130
1131// NOTE: this is currently hardcoded, change it to be more resilient to changes
1132// At a minimum, I should have this do a cheksup first and if not matching, remove the panic instead.
1133
1134// 8b 15 __ __ __ __ -> movl _lapic_start,%edx (NOTE: this should already be here)
1135/*
1136bytes[patchLocation++] = 0x8B;
1137bytes[patchLocation++] = 0x15;
1138bytes[patchLocation++] = (lapicStart & 0x000000FF) >> 0;
1139bytes[patchLocation++] = (lapicStart & 0x0000FF00) >> 8;
1140bytes[patchLocation++] = (lapicStart & 0x00FF0000) >> 16;
1141bytes[patchLocation++] = (lapicStart & 0xFF000000) >> 24;
1142*/
1143patchLocation += 6;
1144
1145// 81 c2 60 03 00 00 -> addl $0x00000320,%edx
1146/*
1147bytes[patchLocation++] = 0x81;
1148bytes[patchLocation++] = 0xC2;
1149*/
1150patchLocation += 2;
1151bytes[patchLocation++] = 0x60;
1152/*
1153bytes[patchLocation++];// = 0x03;
1154bytes[patchLocation++];// = 0x00;
1155bytes[patchLocation++];// = 0x00;
1156*/
1157patchLocation += 3;
1158
1159// c7 02 00 04 00 00 -> movl $0x00000400,(%edx)
1160bytes[patchLocation++] = 0xC7;
1161bytes[patchLocation++] = 0x02;
1162bytes[patchLocation++] = 0x00;
1163bytes[patchLocation++] = 0x04;
1164bytes[patchLocation++] = 0x00;
1165bytes[patchLocation++] = 0x00;
1166
1167// 83 ea 40 -> subl $0x40,edx
1168bytes[patchLocation++] = 0x83;
1169bytes[patchLocation++] = 0xEA;
1170bytes[patchLocation++] = 0x40;
1171
1172// a1 __ __ __ __ -> movl _lapic_interrupt_base,%eax
1173bytes[patchLocation++] = 0xA1;
1174bytes[patchLocation++] = (lapicInterruptBase & 0x000000FF) >> 0;
1175bytes[patchLocation++] = (lapicInterruptBase & 0x0000FF00) >> 8;
1176bytes[patchLocation++] = (lapicInterruptBase & 0x00FF0000) >> 16;
1177bytes[patchLocation++] = (lapicInterruptBase & 0xFF000000) >> 24;
1178
1179// 83 c0 0e -> addl $0x0e,%eax
1180bytes[patchLocation++] = 0x83;
1181bytes[patchLocation++] = 0xC0;
1182bytes[patchLocation++] = 0x0E;
1183
1184// 89 02 -> movl %eax,(%edx)
1185bytes[patchLocation++] = 0x89;
1186bytes[patchLocation++] = 0x02;
1187
1188// 81c230030000 addl $0x00000330,%edx
1189bytes[patchLocation++] = 0x81;
1190bytes[patchLocation++] = 0xC2;
1191bytes[patchLocation++] = 0x30;
1192bytes[patchLocation++] = 0x03;
1193bytes[patchLocation++] = 0x00;
1194bytes[patchLocation++] = 0x00;
1195
1196// a1 __ __ __ __ -> movl _lapic_interrupt_base,%eax
1197bytes[patchLocation++] = 0xA1;
1198bytes[patchLocation++] = (lapicInterruptBase & 0x000000FF) >> 0;
1199bytes[patchLocation++] = (lapicInterruptBase & 0x0000FF00) >> 8;
1200bytes[patchLocation++] = (lapicInterruptBase & 0x00FF0000) >> 16;
1201bytes[patchLocation++] = (lapicInterruptBase & 0xFF000000) >> 24;
1202
1203// 83 c0 0f -> addl $0x0f,%eax
1204bytes[patchLocation++] = 0x83;
1205bytes[patchLocation++] = 0xC0;
1206bytes[patchLocation++] = 0x0F;
1207
1208// 89 02 -> movl %eax,(%edx)
1209bytes[patchLocation++] = 0x89;
1210bytes[patchLocation++] = 0x02;
1211
1212// 83 ea 10 -> subl $0x10,edx
1213bytes[patchLocation++] = 0x83;
1214bytes[patchLocation++] = 0xEA;
1215bytes[patchLocation++] = 0x10;
1216
1217// a1 __ __ __ __ -> movl _lapic_interrupt_base,%eax
1218bytes[patchLocation++] = 0xA1;
1219bytes[patchLocation++] = (lapicInterruptBase & 0x000000FF) >> 0;
1220bytes[patchLocation++] = (lapicInterruptBase & 0x0000FF00) >> 8;
1221bytes[patchLocation++] = (lapicInterruptBase & 0x00FF0000) >> 16;
1222bytes[patchLocation++] = (lapicInterruptBase & 0xFF000000) >> 24;
1223
1224// 83 c0 0c -> addl $0x0c,%eax
1225bytes[patchLocation++] = 0x83;
1226bytes[patchLocation++] = 0xC0;
1227bytes[patchLocation++] = 0x0C;
1228
1229// 89 02 -> movl %eax,(%edx)
1230bytes[patchLocation++] = 0x89;
1231bytes[patchLocation++] = 0x02;
1232
1233// Replace remaining with nops
1234
1235bytes[patchLocation++] = 0x90;
1236bytes[patchLocation++] = 0x90;
1237bytes[patchLocation++] = 0x90;
1238bytes[patchLocation++] = 0x90;
1239//bytes[patchLocation++] = 0x90; // double check the lenght of the patch...
1240//bytes[patchLocation++] = 0x90;
1241}
1242

Archive Download this file

Revision: 2118