Chameleon

Chameleon Svn Source Tree

Root/branches/meklort/i386/boot2/kernel_patcher.c

Source at commit 148 created 13 years 11 months ago.
By meklort, 915resolution code
1/*
2 * Copyright (c) 2009 Evan Lojewski. All rights reserved.
3 *
4 */
5
6#include "libsaio.h"
7#include "kernel_patcher.h"
8
9#define NUM_SYMBOLS3
10
11#define SYMBOL_CPUID_SET_INFO0
12#define SYMBOL_PANIC1
13#define SYMBOL_PMCPUEXITHALTTOOFF2
14
15#define SYMBOL_CPUID_SET_INFO_STRING"_cpuid_set_info"
16#define SYMBOL_PANIC_STRING"_panic"
17#define SYMBOL_PMCPUEXITHALTTOOFF_STRING"_pmCPUExitHaltToOff"
18
19char* kernelSymbols[NUM_SYMBOLS] = {
20SYMBOL_CPUID_SET_INFO_STRING,
21SYMBOL_PANIC_STRING,
22SYMBOL_PMCPUEXITHALTTOOFF_STRING
23};
24
25UInt32 kernelSymbolAddresses[NUM_SYMBOLS] = {
260,
270,
280
29};
30
31
32UInt32 textSection = 0;
33UInt32 textAddress = 0;
34
35
36extern unsigned long gBinaryAddress;
37
38
39void patch_kernel(void* kernelData)
40{
41switch (locate_symbols((void*)kernelData)) {
42case KERNEL_32:
43patch_kernel_32((void*)kernelData);
44break;
45
46case KERNEL_64:
47default:
48patch_kernel_64((void*)kernelData);
49break;
50}
51}
52
53// patches a 64bit kernel.
54void patch_kernel_64(void* kernelData)
55{
56// At the moment, the kernel patching code fails when used
57// in 64bit mode, so we don't patch it. This is due to 32bit vs 64bit
58// pointers as well as changes in structure sizes
59printf("Unable to patch 64bit kernel. Please use arch=i386.\n");
60}
61
62
63/**
64 ** patch_kernel_32
65 **Due to the way the _cpuid_set_info function is writtin, the first instance of _panic is called
66 **when an unsupported (read: non apple used cpu) is found. This routine locates that first _panic call
67 **and replaces the jump call (0xe8) with no ops (0x90).
68 **/
69void patch_kernel_32(void* kernelData)
70{
71//patch_pmCPUExitHaltToOff(kernelData);// Not working as intended, disabled for now
72patch_cpuid_set_info(kernelData);
73
74}
75
76
77/**
78 **This functions located the following in the mach_kernel symbol table
79 **_panic
80 **_cpuid_set_info
81 **/
82int locate_symbols(void* kernelData)
83{
84UInt16 symbolIndexes[NUM_SYMBOLS];
85
86struct load_command *loadCommand;
87struct symtab_command *symtableData;
88struct nlist *symbolEntry;
89
90char* symbolString;
91
92UInt32 kernelIndex = 0;
93kernelIndex += sizeof(struct mach_header);
94
95if(((struct mach_header*)kernelData)->magic != MH_MAGIC) return KERNEL_64;
96
97
98//printf("%d load commands beginning at 0x%X\n", (unsigned int)header->ncmds, (unsigned int)kernelIndex);
99//printf("Commands take up %d bytes\n", header->sizeofcmds);
100
101
102int cmd = 0;
103while(cmd < ((struct mach_header*)kernelData)->ncmds)// TODO: for loop instead
104{
105cmd++;
106
107loadCommand = kernelData + kernelIndex;
108
109UInt cmdSize = loadCommand->cmdsize;
110
111
112// Locate start of _panic and _cpuid_set_info in the symbol tabe.
113// Load commands should be anded with 0x7FFFFFFF to ignore theLC_REQ_DYLD flag
114if((loadCommand->cmd & 0x7FFFFFFF) == LC_SYMTAB)// We only care about the symtab segment
115{
116//printf("Located symtable, length is 0x%X, 0x%X\n", (unsigned int)loadCommand->cmdsize, (unsigned int)sizeof(symtableData));
117
118symtableData = kernelData + kernelIndex;
119kernelIndex += sizeof(struct symtab_command);
120
121cmdSize -= sizeof(struct symtab_command);
122
123// Loop through symbol table untill all of the symbols have been found
124
125symbolString = kernelData + symtableData->stroff;
126
127
128UInt16 symbolIndex = 0;
129UInt8 numSymbolsFound = 0;
130
131while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS)// TODO: for loop
132{
133int i = 0;
134while(i < NUM_SYMBOLS)
135{
136if(strcmp(symbolString, kernelSymbols[i]) == 0)
137{
138symbolIndexes[i] = symbolIndex;
139numSymbolsFound++;
140}
141i++;
142
143}
144symbolString += strlen(symbolString) + 1;
145symbolIndex++;
146}
147
148// loop again
149symbolIndex = 0;
150numSymbolsFound = 0;
151while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS)// TODO: for loop
152{
153
154symbolEntry = kernelData + symtableData->symoff + (symbolIndex * sizeof(struct nlist));
155
156int i = 0;
157while(i < NUM_SYMBOLS)
158{
159if(symbolIndex == (symbolIndexes[i] - 4))
160{
161kernelSymbolAddresses[i] = (UInt32)symbolEntry->n_value;
162numSymbolsFound++;
163}
164i++;
165
166}
167
168symbolIndex ++;
169}
170// Load commands should be anded with 0x7FFFFFFF to ignore theLC_REQ_DYLD flag
171} else if((loadCommand->cmd & 0x7FFFFFFF) == LC_SEGMENT)// We only care about the __TEXT segment, any other load command can be ignored
172{
173
174struct segment_command *segCommand;
175
176segCommand = kernelData + kernelIndex;
177
178//printf("Segment name is %s\n", segCommand->segname);
179
180if(strcmp("__TEXT", segCommand->segname) == 0)
181{
182UInt32 sectionIndex;
183
184sectionIndex = sizeof(struct segment_command);
185
186struct section *sect;
187
188while(sectionIndex < segCommand->cmdsize)
189{
190sect = kernelData + kernelIndex + sectionIndex;
191
192sectionIndex += sizeof(struct section);
193
194
195if(strcmp("__text", sect->sectname) == 0)
196{
197// __TEXT,__text found, save the offset and address for when looking for the calls.
198textSection = sect->offset;
199textAddress = sect->addr;
200break;
201}
202}
203}
204
205
206kernelIndex += cmdSize;
207} else {
208kernelIndex += cmdSize;
209}
210}
211
212return KERNEL_32;
213}
214
215
216/**
217 ** Locate the fisrt instance of _panic inside of _cpuid_set_info, and remove it
218 **/
219void patch_cpuid_set_info(void* kernelData)
220{
221UInt8* bytes = (UInt8*)kernelData;
222UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] - textAddress + textSection);
223UInt32 jumpLocation = 0;
224UInt32 panidAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;
225if(kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] == 0)
226{
227printf("Unable to locate _cpuid_set_info\n");
228return;
229
230}
231if(kernelSymbolAddresses[SYMBOL_PANIC] == 0)
232{
233printf("Unable to locate _panic\n");
234return;
235}
236
237//TODO: don't assume it'll always work (Look for *next* function address in symtab and fail once it's been reached)
238while(
239 (bytes[patchLocation -1] != 0xE8) ||
240 ( ( (UInt32)(panidAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 |
241bytes[patchLocation + 1] << 8 |
242bytes[patchLocation + 2] << 16 |
243bytes[patchLocation + 3] << 24)))
244 )
245{
246patchLocation++;
247}
248patchLocation--;
249
250/*
251 // repace with nops to disable the panic call
252Old patch, nolonger used. This is a safer patch than before, however
253the new patch allows the native pm kext to load without any extra kexts
254bytes[patchLocation] = 0x90;
255bytes[patchLocation + 1] = 0x90;
256bytes[patchLocation + 2] = 0x90;
257bytes[patchLocation + 3] = 0x90;
258bytes[patchLocation + 4] = 0x90;
259*/
260
261// Locate a JMP to patchLocation - sizeof(mov) + 2 (aka 8)
262// ... NOTE: can *ONLY* be up to 0xFF - 8 bytes aways
263jumpLocation = patchLocation - 15;
264while((bytes[jumpLocation - 1] != 0x77 ||
265 bytes[jumpLocation] != (patchLocation - jumpLocation - -8)) &&
266 (patchLocation - jumpLocation) < 0xEF)
267{
268jumpLocation--;
269}
270
271// If found... (not the end of the world if it isn't found, the panic is removed either way.
272// But if it isn't found, then IntelCPUPM.kext might panic if an unknown cpu (atom)
273// Jump to patchLocation - 17
274if((patchLocation - jumpLocation) < 0xEF) bytes[jumpLocation] -= 10; // sizeof(movl$0x6b5a4cd2,0x00872eb4)
275
276
277// bytes[patchLocation - 17] = 0xC7;// already here... not needed to be done
278// bytes[patchLocation - 16] = 0x05;// see above
279UInt32 cpuid_cpufamily_addr =bytes[patchLocation - 15] << 0 |
280bytes[patchLocation - 14] << 8 |
281bytes[patchLocation - 13] << 16 |
282bytes[patchLocation - 12] << 24;
283
284// NOTE: may change, determined based on cpuid_info struct
285UInt32 cpuid_model_addr = cpuid_cpufamily_addr - 299;
286
287
288// cpufamily = CPUFAMILY_INTEL_PENRYN
289bytes[patchLocation - 11] = (CPUFAMILY_INTEL_PENRYN & 0x000000FF) >> 0;
290bytes[patchLocation - 10] = (CPUFAMILY_INTEL_PENRYN & 0x0000FF00) >> 8;
291bytes[patchLocation - 9] = (CPUFAMILY_INTEL_PENRYN & 0x00FF0000) >> 16;
292bytes[patchLocation - 8] = (CPUFAMILY_INTEL_PENRYN & 0xFF000000) >> 24;
293
294// NOPS, just in case if the jmp call wasn't patched, we'll jump to a
295// nop and continue with the rest of the patch
296// Yay two free bytes :), 10 more can be reclamed if needed, as well as a few
297// from the above code (only cpuid_model needs to be set.
298bytes[patchLocation - 7] = 0x90;
299bytes[patchLocation - 6] = 0x90;
300
301bytes[patchLocation - 5] = 0xC7;
302bytes[patchLocation - 4] = 0x05;
303bytes[patchLocation - 3] = (cpuid_model_addr & 0x000000FF) >> 0;
304bytes[patchLocation - 2] = (cpuid_model_addr & 0x0000FF00) >> 8;
305bytes[patchLocation - 1] = (cpuid_model_addr & 0x00FF0000) >> 16;
306bytes[patchLocation - 0] = (cpuid_model_addr & 0xFF000000) >> 24;
307
308// Note: I could have just copied the 8bit cpuid_model in and saved about 4 bytes
309// so if this function need a different patch it's still possible. Also, about ten bytes previous can be freed.
310bytes[patchLocation + 1] = 0x17;// cpuid_model
311bytes[patchLocation + 2] = 0x01;// cpuid_extmodel
312bytes[patchLocation + 3] = 0x00;// cpuid_extfamily
313bytes[patchLocation + 4] = 0x02;// cpuid_stepping
314
315}
316
317
318/**
319 ** SleepEnabler.kext replacement (for those that need it)
320 ** Located the KERN_INVALID_ARGUMENT return and replace it with KERN_SUCCESS
321 **/
322void patch_pmCPUExitHaltToOff(void* kernelData)
323{
324UInt8* bytes = (UInt8*)kernelData;
325UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_PMCPUEXITHALTTOOFF] - textAddress + textSection);
326
327if(kernelSymbolAddresses[SYMBOL_PMCPUEXITHALTTOOFF] == 0)
328{
329printf("Unable to locate _pmCPUExitHaltToOff\n");
330return;
331}
332
333while(bytes[patchLocation - 1]!= 0xB8 ||
334 bytes[patchLocation]!= 0x04 ||// KERN_INVALID_ARGUMENT (0x00000004)
335 bytes[patchLocation + 1]!= 0x00 ||// KERN_INVALID_ARGUMENT
336 bytes[patchLocation + 2]!= 0x00 ||// KERN_INVALID_ARGUMENT
337 bytes[patchLocation + 3]!= 0x00)// KERN_INVALID_ARGUMENT
338
339{
340patchLocation++;
341}
342bytes[patchLocation] = 0x00;// KERN_SUCCESS;
343}
344

Archive Download this file

Revision: 148