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

Archive Download this file

Revision: 2121