Chameleon

Chameleon Svn Source Tree

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

Source at commit 341 created 13 years 8 months ago.
By meklort, Updates module code, dependencies now work correctly. Added KernelPatcher module (currently doesn't hook in anywhere). I need to fix the module loader so that the kernel patcher module loads / starts correctly.
1/*
2 * Copyright (c) 2009 Evan Lojewski. All rights reserved.
3 *
4 */
5
6#include "libsaio.h"
7#include "kernel_patcher.h"
8#include "platform.h"
9
10//extern PlatformInfo_t Platform;
11
12
13#define SYMBOL_CPUID_SET_INFO0
14#define SYMBOL_PANIC1
15#define SYMBOL_PMCPUEXITHALTTOOFF2
16#define SYMBOL_LAPIC_INIT3
17#define SYMBOL_COMMPAGE_STUFF_ROUTINE4
18#define NUM_SYMBOLS5
19
20#define SYMBOL_CPUID_SET_INFO_STRING"_cpuid_set_info"
21#define SYMBOL_PANIC_STRING"_panic"
22#define SYMBOL_PMCPUEXITHALTTOOFF_STRING"_pmCPUExitHaltToOff"
23#define SYMBOL_LAPIC_INIT_STRING"_lapic_init"
24#define SYMBOL_COMMPAGE_STUFF_ROUTINE_STRING"_commpage_stuff_routine"
25
26char* kernelSymbols[NUM_SYMBOLS] = {
27SYMBOL_CPUID_SET_INFO_STRING,
28SYMBOL_PANIC_STRING,
29SYMBOL_PMCPUEXITHALTTOOFF_STRING,
30SYMBOL_LAPIC_INIT_STRING,
31SYMBOL_COMMPAGE_STUFF_ROUTINE_STRING
32};
33
34UInt32 kernelSymbolAddresses[NUM_SYMBOLS] = {
350,
360,
370,
380,
390
40};
41
42
43UInt32 textSection = 0;
44UInt32 textAddress = 0;
45
46
47void HelloWorld_start();
48
49void KernelPatcher_start()
50{
51printf("KernelPatcher(), about to call HelloWorld_start()\n");
52//getc();
53//HelloWorld_start();
54
55}
56
57
58
59
60void patch_kernel(void* kernelData)
61{
62switch (locate_symbols((void*)kernelData)) {
63case KERNEL_32:
64patch_kernel_32((void*)kernelData);
65break;
66
67case KERNEL_64:
68default:
69patch_kernel_64((void*)kernelData);
70break;
71}
72}
73
74// patches a 64bit kernel.
75void patch_kernel_64(void* kernelData)
76{
77// At the moment, the kernel patching code fails when used
78// in 64bit mode, so we don't patch it. This is due to 32bit vs 64bit
79// pointers as well as changes in structure sizes
80printf("Unable to patch 64bit kernel. Please use arch=i386.\n");
81}
82
83
84/**
85 ** patch_kernel_32
86 **patches kernel based on cpu info determined earlier in the boot process.
87 **It the machine is vmware, remove the artificial lapic panic
88 **If the CPU is not supported, remove the cpuid_set_info panic
89 **If the CPU is and Intel Atom, inject the penryn cpuid info.
90 **/
91void patch_kernel_32(void* kernelData)
92{
93// Remove panic in commpage
94patch_commpage_stuff_routine(kernelData);
95
96//patch_pmCPUExitHaltToOff(kernelData);// Not working as intended, disabled for now
97
98//if(vmware_detected)
99{
100patch_lapic_init(kernelData);
101}
102
103switch(13)//Platform.CPU.Model)
104{
105// Known good CPU's, no reason to patch kernel
106case 13:
107case CPUID_MODEL_YONAH:
108case CPUID_MODEL_MEROM:
109case CPUID_MODEL_PENRYN:
110case CPUID_MODEL_NEHALEM:
111case CPUID_MODEL_FIELDS:
112case CPUID_MODEL_DALES:
113case CPUID_MODEL_NEHALEM_EX:
114break;
115
116// Known unsuported CPU's
117case CPUID_MODEL_ATOM:
118// TODO: Impersonate CPU based on user selection
119patch_cpuid_set_info(kernelData, CPUFAMILY_INTEL_PENRYN, CPUID_MODEL_PENRYN);// Impersonate Penryn CPU
120break;
121
122// Unknown CPU's
123default:
124// TODO: Impersonate CPU based on user selection
125patch_cpuid_set_info(kernelData, 0, 0);// Remove Panic Call
126
127break;
128}
129}
130
131
132/**
133 **This functions located the kernelSymbols[i] symbols in the mach-o header.
134 **as well as determines the start of the __TEXT segment and __TEXT,__text sections
135 **/
136int locate_symbols(void* kernelData)
137{
138UInt16 symbolIndexes[NUM_SYMBOLS];
139
140struct load_command *loadCommand;
141struct symtab_command *symtableData;
142struct nlist *symbolEntry;
143
144char* symbolString;
145
146UInt32 kernelIndex = 0;
147kernelIndex += sizeof(struct mach_header);
148
149if(((struct mach_header*)kernelData)->magic != MH_MAGIC) return KERNEL_64;
150
151
152//printf("%d load commands beginning at 0x%X\n", (unsigned int)header->ncmds, (unsigned int)kernelIndex);
153//printf("Commands take up %d bytes\n", header->sizeofcmds);
154
155
156int cmd = 0;
157while(cmd < ((struct mach_header*)kernelData)->ncmds)// TODO: for loop instead
158{
159cmd++;
160
161loadCommand = kernelData + kernelIndex;
162
163UInt cmdSize = loadCommand->cmdsize;
164
165
166// Locate start of _panic and _cpuid_set_info in the symbol tabe.
167// Load commands should be anded with 0x7FFFFFFF to ignore theLC_REQ_DYLD flag
168if((loadCommand->cmd & 0x7FFFFFFF) == LC_SYMTAB)// We only care about the symtab segment
169{
170//printf("Located symtable, length is 0x%X, 0x%X\n", (unsigned int)loadCommand->cmdsize, (unsigned int)sizeof(symtableData));
171
172symtableData = kernelData + kernelIndex;
173kernelIndex += sizeof(struct symtab_command);
174
175cmdSize -= sizeof(struct symtab_command);
176
177// Loop through symbol table untill all of the symbols have been found
178
179symbolString = kernelData + symtableData->stroff;
180
181
182UInt16 symbolIndex = 0;
183UInt8 numSymbolsFound = 0;
184
185while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS)// TODO: for loop
186{
187int i = 0;
188while(i < NUM_SYMBOLS)
189{
190if(strcmp(symbolString, kernelSymbols[i]) == 0)
191{
192symbolIndexes[i] = symbolIndex;
193numSymbolsFound++;
194}
195i++;
196
197}
198symbolString += strlen(symbolString) + 1;
199symbolIndex++;
200}
201
202// loop again
203symbolIndex = 0;
204numSymbolsFound = 0;
205while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS)// TODO: for loop
206{
207
208symbolEntry = kernelData + symtableData->symoff + (symbolIndex * sizeof(struct nlist));
209
210int i = 0;
211while(i < NUM_SYMBOLS)
212{
213if(symbolIndex == (symbolIndexes[i] - 4))
214{
215kernelSymbolAddresses[i] = (UInt32)symbolEntry->n_value;
216numSymbolsFound++;
217}
218i++;
219
220}
221
222symbolIndex ++;
223}
224// Load commands should be anded with 0x7FFFFFFF to ignore theLC_REQ_DYLD flag
225} else if((loadCommand->cmd & 0x7FFFFFFF) == LC_SEGMENT)// We only care about the __TEXT segment, any other load command can be ignored
226{
227
228struct segment_command *segCommand;
229
230segCommand = kernelData + kernelIndex;
231
232//printf("Segment name is %s\n", segCommand->segname);
233
234if(strcmp("__TEXT", segCommand->segname) == 0)
235{
236UInt32 sectionIndex;
237
238sectionIndex = sizeof(struct segment_command);
239
240struct section *sect;
241
242while(sectionIndex < segCommand->cmdsize)
243{
244sect = kernelData + kernelIndex + sectionIndex;
245
246sectionIndex += sizeof(struct section);
247
248
249if(strcmp("__text", sect->sectname) == 0)
250{
251// __TEXT,__text found, save the offset and address for when looking for the calls.
252textSection = sect->offset;
253textAddress = sect->addr;
254break;
255}
256}
257}
258
259
260kernelIndex += cmdSize;
261} else {
262kernelIndex += cmdSize;
263}
264}
265
266return KERNEL_32;
267}
268
269
270/**
271 ** Locate the fisrt instance of _panic inside of _cpuid_set_info, and either remove it
272 ** Or replace it so that the cpuid is set to a valid value.
273 **/
274void patch_cpuid_set_info(void* kernelData, UInt32 impersonateFamily, UInt8 impersonateModel)
275{
276UInt8* bytes = (UInt8*)kernelData;
277UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] - textAddress + textSection);
278UInt32 jumpLocation = 0;
279UInt32 panicAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;
280if(kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] == 0)
281{
282printf("Unable to locate _cpuid_set_info\n");
283return;
284
285}
286if(kernelSymbolAddresses[SYMBOL_PANIC] == 0)
287{
288printf("Unable to locate _panic\n");
289return;
290}
291
292//TODO: don't assume it'll always work (Look for *next* function address in symtab and fail once it's been reached)
293while(
294 (bytes[patchLocation -1] != 0xE8) ||
295 ( ( (UInt32)(panicAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
296bytes[patchLocation + 1] << 8 |
297bytes[patchLocation + 2] << 16 |
298bytes[patchLocation + 3] << 24)))
299 )
300{
301patchLocation++;
302}
303patchLocation--;
304
305
306// Remove panic call, just in case the following patch routines fail
307bytes[patchLocation + 0] = 0x90;
308bytes[patchLocation + 1] = 0x90;
309bytes[patchLocation + 2] = 0x90;
310bytes[patchLocation + 3] = 0x90;
311bytes[patchLocation + 4] = 0x90;
312
313
314// Locate the jump call, so that 10 bytes can be reclamed.
315// NOTE: This will *NOT* be located on pre 10.6.2 kernels
316jumpLocation = patchLocation - 15;
317while((bytes[jumpLocation - 1] != 0x77 ||
318 bytes[jumpLocation] != (patchLocation - jumpLocation - -8)) &&
319 (patchLocation - jumpLocation) < 0xF0)
320{
321jumpLocation--;
322}
323
324// If found... AND we want to impersonate a specific cpumodel / family...
325if(impersonateFamily &&
326 impersonateModel &&
327 ((patchLocation - jumpLocation) < 0xF0))
328{
329
330bytes[jumpLocation] -= 10;// sizeof(movl$0x6b5a4cd2,0x00872eb4) = 10bytes
331
332/*
333 * Inpersonate the specified CPU FAMILY and CPU Model
334 */
335
336// bytes[patchLocation - 17] = 0xC7;// already here... not needed to be done
337// bytes[patchLocation - 16] = 0x05;// see above
338UInt32 cpuid_cpufamily_addr =bytes[patchLocation - 15] << 0 |
339bytes[patchLocation - 14] << 8 |
340bytes[patchLocation - 13] << 16 |
341bytes[patchLocation - 12] << 24;
342
343// NOTE: may change, determined based on cpuid_info struct
344UInt32 cpuid_model_addr = cpuid_cpufamily_addr - 299;
345
346
347// cpufamily = CPUFAMILY_INTEL_PENRYN
348bytes[patchLocation - 11] = (impersonateFamily & 0x000000FF) >> 0;
349bytes[patchLocation - 10] = (impersonateFamily & 0x0000FF00) >> 8;
350bytes[patchLocation - 9] = (impersonateFamily & 0x00FF0000) >> 16;
351bytes[patchLocation - 8] = (impersonateFamily & 0xFF000000) >> 24;
352
353// NOPS, just in case if the jmp call wasn't patched, we'll jump to a
354// nop and continue with the rest of the patch
355// Yay two free bytes :), 10 more can be reclamed if needed, as well as a few
356// from the above code (only cpuid_model needs to be set.
357bytes[patchLocation - 7] = 0x90;
358bytes[patchLocation - 6] = 0x90;
359
360bytes[patchLocation - 5] = 0xC7;
361bytes[patchLocation - 4] = 0x05;
362bytes[patchLocation - 3] = (cpuid_model_addr & 0x000000FF) >> 0;
363bytes[patchLocation - 2] = (cpuid_model_addr & 0x0000FF00) >> 8;
364bytes[patchLocation - 1] = (cpuid_model_addr & 0x00FF0000) >> 16;
365bytes[patchLocation - 0] = (cpuid_model_addr & 0xFF000000) >> 24;
366
367// Note: I could have just copied the 8bit cpuid_model in and saved about 4 bytes
368// so if this function need a different patch it's still possible. Also, about ten bytes previous can be freed.
369bytes[patchLocation + 1] = impersonateModel;// cpuid_model
370bytes[patchLocation + 2] = 0x01;// cpuid_extmodel
371bytes[patchLocation + 3] = 0x00;// cpuid_extfamily
372bytes[patchLocation + 4] = 0x02;// cpuid_stepping
373
374}
375else if(impersonateFamily && impersonateModel)
376{
377// pre 10.6.2 kernel
378// Locate the jump to directly *after* the panic call,
379jumpLocation = patchLocation - 4;
380while((bytes[jumpLocation - 1] != 0x77 ||
381 bytes[jumpLocation] != (patchLocation - jumpLocation + 4)) &&
382 (patchLocation - jumpLocation) < 0x20)
383{
384jumpLocation--;
385}
386// NOTE above isn't needed (I was going to use it, but I'm not, so instead,
387// I'll just leave it to verify the binary stucture.
388
389// NOTE: the cpumodel_familt data is not set in _cpuid_set_info
390// so we don't need to set it here, I'll get set later based on the model
391// we set now.
392
393if((patchLocation - jumpLocation) < 0x20)
394{
395UInt32 cpuid_model_addr =(bytes[patchLocation - 14] << 0 |
396bytes[patchLocation - 13] << 8 |
397bytes[patchLocation - 12] << 16 |
398bytes[patchLocation - 11] << 24);
399// Remove jump
400bytes[patchLocation - 9] = 0x90;/// Was a jump if supported cpu
401bytes[patchLocation - 8] = 0x90;// jumped past the panic call, we want to override the panic
402
403bytes[patchLocation - 7] = 0x90;
404bytes[patchLocation - 6] = 0x90;
405
406bytes[patchLocation - 5] = 0xC7;
407bytes[patchLocation - 4] = 0x05;
408bytes[patchLocation - 3] = (cpuid_model_addr & 0x000000FF) >> 0;
409bytes[patchLocation - 2] = (cpuid_model_addr & 0x0000FF00) >> 8;
410bytes[patchLocation - 1] = (cpuid_model_addr & 0x00FF0000) >> 16;
411bytes[patchLocation - 0] = (cpuid_model_addr & 0xFF000000) >> 24;
412
413// Note: I could have just copied the 8bit cpuid_model in and saved about 4 bytes
414// so if this function need a different patch it's still possible. Also, about ten bytes previous can be freed.
415bytes[patchLocation + 1] = impersonateModel;// cpuid_model
416bytes[patchLocation + 2] = 0x01;// cpuid_extmodel
417bytes[patchLocation + 3] = 0x00;// cpuid_extfamily
418bytes[patchLocation + 4] = 0x02;// cpuid_stepping
419
420
421
422patchLocation = jumpLocation;
423// We now have 14 bytes available for a patch
424
425}
426else
427{
428// Patching failed, using NOP replacement done initialy
429}
430}
431else
432{
433// Either We were unable to change the jump call due to the function's sctructure
434// changing, or the user did not request a patch. As such, resort to just
435// removing the panic call (using NOP replacement above). Note that the
436// IntelCPUPM kext may still panic due to the cpu's Model ID not being patched
437}
438}
439
440
441/**
442 ** SleepEnabler.kext replacement (for those that need it)
443 ** Located the KERN_INVALID_ARGUMENT return and replace it with KERN_SUCCESS
444 **/
445void patch_pmCPUExitHaltToOff(void* kernelData)
446{
447UInt8* bytes = (UInt8*)kernelData;
448UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_PMCPUEXITHALTTOOFF] - textAddress + textSection);
449
450if(kernelSymbolAddresses[SYMBOL_PMCPUEXITHALTTOOFF] == 0)
451{
452printf("Unable to locate _pmCPUExitHaltToOff\n");
453return;
454}
455
456while(bytes[patchLocation - 1]!= 0xB8 ||
457 bytes[patchLocation]!= 0x04 ||// KERN_INVALID_ARGUMENT (0x00000004)
458 bytes[patchLocation + 1]!= 0x00 ||// KERN_INVALID_ARGUMENT
459 bytes[patchLocation + 2]!= 0x00 ||// KERN_INVALID_ARGUMENT
460 bytes[patchLocation + 3]!= 0x00)// KERN_INVALID_ARGUMENT
461
462{
463patchLocation++;
464}
465bytes[patchLocation] = 0x00;// KERN_SUCCESS;
466}
467
468void patch_lapic_init(void* kernelData)
469{
470UInt8 panicIndex = 0;
471UInt8* bytes = (UInt8*)kernelData;
472UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_LAPIC_INIT] - textAddress + textSection);
473UInt32 panicAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;
474
475if(kernelSymbolAddresses[SYMBOL_LAPIC_INIT] == 0)
476{
477printf("Unable to locate %s\n", SYMBOL_LAPIC_INIT_STRING);
478return;
479
480}
481if(kernelSymbolAddresses[SYMBOL_PANIC] == 0)
482{
483printf("Unable to locate %s\n", SYMBOL_PANIC_STRING);
484return;
485}
486
487
488
489// Locate the (panicIndex + 1) panic call
490while(panicIndex < 3)// Find the third panic call
491{
492while(
493 (bytes[patchLocation -1] != 0xE8) ||
494 ( ( (UInt32)(panicAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
495bytes[patchLocation + 1] << 8 |
496bytes[patchLocation + 2] << 16 |
497bytes[patchLocation + 3] << 24)))
498 )
499{
500patchLocation++;
501}
502patchLocation++;
503panicIndex++;
504}
505patchLocation--;// Remove extra increment from the < 3 while loop
506
507bytes[--patchLocation] = 0x90;
508bytes[++patchLocation] = 0x90;
509bytes[++patchLocation] = 0x90;
510bytes[++patchLocation] = 0x90;
511bytes[++patchLocation] = 0x90;
512
513
514}
515
516
517void patch_commpage_stuff_routine(void* kernelData)
518{
519UInt8* bytes = (UInt8*)kernelData;
520UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_COMMPAGE_STUFF_ROUTINE] - textAddress + textSection);
521UInt32 panicAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;
522
523if(kernelSymbolAddresses[SYMBOL_COMMPAGE_STUFF_ROUTINE] == 0)
524{
525printf("Unable to locate %s\n", SYMBOL_COMMPAGE_STUFF_ROUTINE_STRING);
526return;
527
528}
529if(kernelSymbolAddresses[SYMBOL_PANIC] == 0)
530{
531printf("Unable to locate %s\n", SYMBOL_PANIC_STRING);
532return;
533}
534
535
536while(
537 (bytes[patchLocation -1] != 0xE8) ||
538 ( ( (UInt32)(panicAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
539bytes[patchLocation + 1] << 8 |
540bytes[patchLocation + 2] << 16 |
541bytes[patchLocation + 3] << 24)))
542 )
543{
544patchLocation++;
545}
546patchLocation--;
547
548
549// Remove panic call, just in case the following patch routines fail
550bytes[patchLocation + 0] = 0x90;
551bytes[patchLocation + 1] = 0x90;
552bytes[patchLocation + 2] = 0x90;
553bytes[patchLocation + 3] = 0x90;
554bytes[patchLocation + 4] = 0x90;
555
556
557}
558

Archive Download this file

Revision: 341