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

Archive Download this file

Revision: 2182