Root/
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_SYMBOLS␉␉3␊ |
10 | ␊ |
11 | #define SYMBOL_CPUID_SET_INFO␉␉␉␉0␊ |
12 | #define SYMBOL_PANIC␉␉␉␉␉␉1␊ |
13 | #define SYMBOL_PMCPUEXITHALTTOOFF␉␉␉2␊ |
14 | ␊ |
15 | #define SYMBOL_CPUID_SET_INFO_STRING␉␉"_cpuid_set_info"␊ |
16 | #define SYMBOL_PANIC_STRING␉␉␉␉␉"_panic"␊ |
17 | #define SYMBOL_PMCPUEXITHALTTOOFF_STRING␉"_pmCPUExitHaltToOff"␊ |
18 | ␊ |
19 | char* kernelSymbols[NUM_SYMBOLS] = {␊ |
20 | ␉SYMBOL_CPUID_SET_INFO_STRING,␊ |
21 | ␉SYMBOL_PANIC_STRING,␊ |
22 | ␉SYMBOL_PMCPUEXITHALTTOOFF_STRING␊ |
23 | };␊ |
24 | ␊ |
25 | UInt32 kernelSymbolAddresses[NUM_SYMBOLS] = {␊ |
26 | ␉0,␊ |
27 | ␉0,␊ |
28 | ␉0␊ |
29 | };␊ |
30 | ␊ |
31 | ␊ |
32 | UInt32 textSection = 0;␊ |
33 | UInt32 textAddress = 0;␊ |
34 | ␊ |
35 | ␊ |
36 | extern unsigned long gBinaryAddress;␊ |
37 | ␊ |
38 | ␊ |
39 | void patch_kernel(void* kernelData)␊ |
40 | {␊ |
41 | ␉switch (locate_symbols((void*)kernelData)) {␊ |
42 | ␉␉case KERNEL_32:␊ |
43 | ␉␉␉patch_kernel_32((void*)kernelData);␊ |
44 | ␉␉␉break;␊ |
45 | ␉␉␉␊ |
46 | ␉␉case KERNEL_64:␊ |
47 | ␉␉default:␊ |
48 | ␉␉␉patch_kernel_64((void*)kernelData);␊ |
49 | ␉␉␉break;␊ |
50 | ␉}␊ |
51 | }␊ |
52 | ␊ |
53 | // patches a 64bit kernel.␊ |
54 | void 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␊ |
59 | ␉printf("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 | **/␊ |
69 | void patch_kernel_32(void* kernelData)␊ |
70 | {␊ |
71 | ␉//patch_pmCPUExitHaltToOff(kernelData);␉// Not working as intended, disabled for now␊ |
72 | ␉patch_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 | **/␊ |
82 | int locate_symbols(void* kernelData)␊ |
83 | {␊ |
84 | ␉UInt16 symbolIndexes[NUM_SYMBOLS];␊ |
85 | ␊ |
86 | ␉struct load_command *loadCommand;␊ |
87 | ␉struct symtab_command *symtableData;␊ |
88 | ␉struct nlist *symbolEntry;␊ |
89 | ␉␊ |
90 | ␉char* symbolString;␊ |
91 | ␊ |
92 | ␉UInt32 kernelIndex = 0;␊ |
93 | ␉kernelIndex += sizeof(struct mach_header);␊ |
94 | ␉␊ |
95 | ␉if(((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 | ␉␊ |
102 | ␉int cmd = 0;␊ |
103 | ␉while(cmd < ((struct mach_header*)kernelData)->ncmds)␉// TODO: for loop instead␊ |
104 | ␉{␊ |
105 | ␉␉cmd++;␊ |
106 | ␉␉␊ |
107 | ␉␉loadCommand = kernelData + kernelIndex;␊ |
108 | ␉␉␊ |
109 | ␉␉UInt 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 the␉LC_REQ_DYLD flag␊ |
114 | ␉␉if((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 | ␉␉␉␊ |
118 | ␉␉␉symtableData = kernelData + kernelIndex;␊ |
119 | ␉␉␉kernelIndex += sizeof(struct symtab_command);␊ |
120 | ␉␉␉␊ |
121 | ␉␉␉cmdSize -= sizeof(struct symtab_command);␊ |
122 | ␊ |
123 | ␉␉␉// Loop through symbol table untill all of the symbols have been found␊ |
124 | ␉␉␉␊ |
125 | ␉␉␉symbolString = kernelData + symtableData->stroff; ␊ |
126 | ␉␉␉␊ |
127 | ␉␉␉␊ |
128 | ␉␉␉UInt16 symbolIndex = 0;␊ |
129 | ␉␉␉UInt8 numSymbolsFound = 0;␊ |
130 | ␊ |
131 | ␉␉␉while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS)␉// TODO: for loop␊ |
132 | ␉␉␉{␊ |
133 | ␉␉␉␉int i = 0;␊ |
134 | ␉␉␉␉while(i < NUM_SYMBOLS)␊ |
135 | ␉␉␉␉{␊ |
136 | ␉␉␉␉␉if(strcmp(symbolString, kernelSymbols[i]) == 0)␊ |
137 | ␉␉␉␉␉{␊ |
138 | ␉␉␉␉␉␉symbolIndexes[i] = symbolIndex;␊ |
139 | ␉␉␉␉␉␉numSymbolsFound++;␉␉␉␉␊ |
140 | ␉␉␉␉␉} ␊ |
141 | ␉␉␉␉␉i++;␊ |
142 | ␉␉␉␉␉␊ |
143 | ␉␉␉␉}␊ |
144 | ␉␉␉␉symbolString += strlen(symbolString) + 1;␊ |
145 | ␉␉␉␉symbolIndex++;␊ |
146 | ␉␉␉}␊ |
147 | ␉␉␉␊ |
148 | ␉␉␉// loop again␊ |
149 | ␉␉␉symbolIndex = 0;␊ |
150 | ␉␉␉numSymbolsFound = 0;␊ |
151 | ␉␉␉while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS)␉// TODO: for loop␊ |
152 | ␉␉␉{␊ |
153 | ␉␉␉␉␊ |
154 | ␉␉␉␉symbolEntry = kernelData + symtableData->symoff + (symbolIndex * sizeof(struct nlist));␊ |
155 | ␉␉␉␉␊ |
156 | ␉␉␉␉int i = 0;␊ |
157 | ␉␉␉␉while(i < NUM_SYMBOLS)␊ |
158 | ␉␉␉␉{␊ |
159 | ␉␉␉␉␉if(symbolIndex == (symbolIndexes[i] - 4))␊ |
160 | ␉␉␉␉␉{␊ |
161 | ␉␉␉␉␉␉kernelSymbolAddresses[i] = (UInt32)symbolEntry->n_value;␊ |
162 | ␉␉␉␉␉␉numSymbolsFound++;␉␉␉␉␊ |
163 | ␉␉␉␉␉} ␊ |
164 | ␉␉␉␉␉i++;␊ |
165 | ␉␉␉␉␉␊ |
166 | ␉␉␉␉}␊ |
167 | ␉␉␉␉␊ |
168 | ␉␉␉␉symbolIndex ++;␊ |
169 | ␉␉␉}␉␉␉␊ |
170 | ␉␉// Load commands should be anded with 0x7FFFFFFF to ignore the␉LC_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 | ␉␉␉␊ |
174 | ␉␉␉struct segment_command *segCommand;␊ |
175 | ␉␉␉␊ |
176 | ␉␉␉segCommand = kernelData + kernelIndex;␊ |
177 | ␉␉␉␊ |
178 | ␉␉␉//printf("Segment name is %s\n", segCommand->segname);␊ |
179 | ␉␉␉␊ |
180 | ␉␉␉if(strcmp("__TEXT", segCommand->segname) == 0)␊ |
181 | ␉␉␉{␊ |
182 | ␉␉␉␉UInt32 sectionIndex;␊ |
183 | ␉␉␉␉␊ |
184 | ␉␉␉␉sectionIndex = sizeof(struct segment_command);␊ |
185 | ␉␉␉␉␊ |
186 | ␉␉␉␉struct section *sect;␊ |
187 | ␉␉␉␉␊ |
188 | ␉␉␉␉while(sectionIndex < segCommand->cmdsize)␊ |
189 | ␉␉␉␉{␊ |
190 | ␉␉␉␉␉sect = kernelData + kernelIndex + sectionIndex;␊ |
191 | ␉␉␉␉␉␊ |
192 | ␉␉␉␉␉sectionIndex += sizeof(struct section);␊ |
193 | ␉␉␉␉␉␊ |
194 | ␉␉␉␉␉␊ |
195 | ␉␉␉␉␉if(strcmp("__text", sect->sectname) == 0)␊ |
196 | ␉␉␉␉␉{␊ |
197 | ␉␉␉␉␉␉// __TEXT,__text found, save the offset and address for when looking for the calls.␊ |
198 | ␉␉␉␉␉␉textSection = sect->offset;␊ |
199 | ␉␉␉␉␉␉textAddress = sect->addr;␊ |
200 | ␉␉␉␉␉␉break;␊ |
201 | ␉␉␉␉␉}␉␉␉␉␉␊ |
202 | ␉␉␉␉}␊ |
203 | ␉␉␉}␊ |
204 | ␉␉␉␊ |
205 | ␉␉␉␊ |
206 | ␉␉␉kernelIndex += cmdSize;␊ |
207 | ␉␉} else {␊ |
208 | ␉␉␉kernelIndex += cmdSize;␊ |
209 | ␉␉}␊ |
210 | ␉}␊ |
211 | ␉␊ |
212 | ␉return KERNEL_32;␊ |
213 | }␊ |
214 | ␊ |
215 | ␊ |
216 | /**␊ |
217 | ** Locate the fisrt instance of _panic inside of _cpuid_set_info, and remove it␊ |
218 | **/␊ |
219 | void patch_cpuid_set_info(void* kernelData)␊ |
220 | {␊ |
221 | ␉UInt8* bytes = (UInt8*)kernelData;␊ |
222 | ␉UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] - textAddress + textSection);␊ |
223 | ␉UInt32 jumpLocation = 0;␊ |
224 | ␉UInt32 panidAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;␊ |
225 | ␉if(kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] == 0)␊ |
226 | ␉{␊ |
227 | ␉␉printf("Unable to locate _cpuid_set_info\n");␊ |
228 | ␉␉return;␊ |
229 | ␉␉␊ |
230 | ␉}␊ |
231 | ␉if(kernelSymbolAddresses[SYMBOL_PANIC] == 0)␊ |
232 | ␉{␊ |
233 | ␉␉printf("Unable to locate _panic\n");␊ |
234 | ␉␉return;␊ |
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)␊ |
238 | ␉while( ␊ |
239 | ␉␉ (bytes[patchLocation -1] != 0xE8) ||␊ |
240 | ␉␉ ( ( (UInt32)(panidAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation + 0] << 0 | ␊ |
241 | ␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉bytes[patchLocation + 1] << 8 | ␊ |
242 | ␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉bytes[patchLocation + 2] << 16 |␊ |
243 | ␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉bytes[patchLocation + 3] << 24)))␊ |
244 | ␉␉ )␊ |
245 | ␉{␊ |
246 | ␉␉patchLocation++;␊ |
247 | ␉}␊ |
248 | ␉patchLocation--;␊ |
249 | ␉␊ |
250 | /*␊ |
251 | // repace with nops to disable the panic call␊ |
252 | ␉Old patch, nolonger used. This is a safer patch than before, however␊ |
253 | ␉the new patch allows the native pm kext to load without any extra kexts␊ |
254 | ␉bytes[patchLocation] = 0x90;␊ |
255 | ␉bytes[patchLocation + 1] = 0x90;␊ |
256 | ␉bytes[patchLocation + 2] = 0x90;␊ |
257 | ␉bytes[patchLocation + 3] = 0x90;␊ |
258 | ␉bytes[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␊ |
263 | ␉jumpLocation = patchLocation - 15;␊ |
264 | ␉while((bytes[jumpLocation - 1] != 0x77 ||␊ |
265 | ␉␉ bytes[jumpLocation] != (patchLocation - jumpLocation - -8)) &&␊ |
266 | ␉␉ (patchLocation - jumpLocation) < 0xEF)␊ |
267 | ␉{␊ |
268 | ␉␉jumpLocation--;␊ |
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␊ |
274 | ␉if((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␊ |
279 | ␉UInt32 cpuid_cpufamily_addr =␉bytes[patchLocation - 15] << 0 |␊ |
280 | ␉␉␉␉␉␉␉␉␉bytes[patchLocation - 14] << 8 |␊ |
281 | ␉␉␉␉␉␉␉␉␉bytes[patchLocation - 13] << 16 |␊ |
282 | ␉␉␉␉␉␉␉␉␉bytes[patchLocation - 12] << 24;␊ |
283 | ␉␊ |
284 | ␉// NOTE: may change, determined based on cpuid_info struct␊ |
285 | ␉UInt32 cpuid_model_addr = cpuid_cpufamily_addr - 299; ␊ |
286 | ␉␊ |
287 | ␉␊ |
288 | ␉// cpufamily = CPUFAMILY_INTEL_PENRYN␊ |
289 | ␉bytes[patchLocation - 11] = (CPUFAMILY_INTEL_PENRYN & 0x000000FF) >> 0;␊ |
290 | ␉bytes[patchLocation - 10] = (CPUFAMILY_INTEL_PENRYN & 0x0000FF00) >> 8;␊ |
291 | ␉bytes[patchLocation - 9] = (CPUFAMILY_INTEL_PENRYN & 0x00FF0000) >> 16;␉␊ |
292 | ␉bytes[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.␊ |
298 | ␉bytes[patchLocation - 7] = 0x90;␊ |
299 | ␉bytes[patchLocation - 6] = 0x90;␊ |
300 | ␊ |
301 | ␉bytes[patchLocation - 5] = 0xC7;␊ |
302 | ␉bytes[patchLocation - 4] = 0x05;␊ |
303 | ␉bytes[patchLocation - 3] = (cpuid_model_addr & 0x000000FF) >> 0;␊ |
304 | ␉bytes[patchLocation - 2] = (cpuid_model_addr & 0x0000FF00) >> 8;␉␊ |
305 | ␉bytes[patchLocation - 1] = (cpuid_model_addr & 0x00FF0000) >> 16;␊ |
306 | ␉bytes[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.␊ |
310 | ␉bytes[patchLocation + 1] = 0x17;␉// cpuid_model␊ |
311 | ␉bytes[patchLocation + 2] = 0x01;␉// cpuid_extmodel␊ |
312 | ␉bytes[patchLocation + 3] = 0x00;␉// cpuid_extfamily␊ |
313 | ␉bytes[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 | **/␊ |
322 | void patch_pmCPUExitHaltToOff(void* kernelData)␊ |
323 | {␊ |
324 | ␉UInt8* bytes = (UInt8*)kernelData;␊ |
325 | ␉UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_PMCPUEXITHALTTOOFF] - textAddress + textSection);␊ |
326 | ␊ |
327 | ␉if(kernelSymbolAddresses[SYMBOL_PMCPUEXITHALTTOOFF] == 0)␊ |
328 | ␉{␊ |
329 | ␉␉printf("Unable to locate _pmCPUExitHaltToOff\n");␊ |
330 | ␉␉return;␊ |
331 | ␉}␊ |
332 | ␉␊ |
333 | ␉while(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 | ␉{␊ |
340 | ␉␉patchLocation++;␊ |
341 | ␉}␊ |
342 | ␉bytes[patchLocation] = 0x00;␉// KERN_SUCCESS;␊ |
343 | }␊ |
344 |