Root/
Source at commit 143 created 13 years 10 months ago. By meklort, Updated kernel patcher. Removed CPUID panic as well as removes the need for SleepEnabler.kext | |
---|---|
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;␊ |
33 | UInt32 textAddress;␊ |
34 | ␊ |
35 | ␊ |
36 | extern unsigned long gBinaryAddress;␊ |
37 | ␊ |
38 | ␊ |
39 | void patch_kernel()␊ |
40 | {␊ |
41 | ␉switch (locate_symbols((void*)gBinaryAddress)) {␊ |
42 | ␉␉case KERNEL_32:␊ |
43 | ␉␉␉patch_kernel_32((void*)gBinaryAddress);␊ |
44 | ␉␉␉break;␊ |
45 | ␉␉case KERNEL_64:␊ |
46 | ␉␉default:␊ |
47 | ␉␉␉patch_kernel_64((void*)gBinaryAddress);␊ |
48 | ␉␉␉break;␊ |
49 | ␉}␊ |
50 | }␊ |
51 | ␊ |
52 | // patches a 64bit kernel.␊ |
53 | void patch_kernel_64(void* kernelData)␊ |
54 | {␊ |
55 | ␉// At the moment, the kernel patching code fails when used␊ |
56 | ␉// in 64bit mode, so we don't patch it. This is due to 32bit vs 64bit␊ |
57 | ␉// pointers as well as changes in structure sizes␊ |
58 | ␉verbose("Unable to patch 64bit kernel. Please use arch=i386.\n");␊ |
59 | }␊ |
60 | ␊ |
61 | /**␊ |
62 | ** patch_kernel_32␊ |
63 | **␉␉Due to the way the _cpuid_set_info function is writtin, the first instance of _panic is called␊ |
64 | **␉␉␉when an unsupported (read: non apple used cpu) is found. This routine locates that first _panic call␊ |
65 | **␉␉␉and replaces the jump call (0xe8) with no ops (0x90).␊ |
66 | **/␊ |
67 | ␊ |
68 | void patch_kernel_32(void* kernelData)␊ |
69 | {␊ |
70 | ␉patch_pmCPUExitHaltToOff(kernelData);␊ |
71 | ␉patch_cpuid_set_info(kernelData);␊ |
72 | ␊ |
73 | }␊ |
74 | ␊ |
75 | /**␊ |
76 | **␉␉This functions located the following in the mach_kernel symbol table␊ |
77 | **␉␉␉_panic␊ |
78 | **␉␉␉_cpuid_set_info␊ |
79 | **/␊ |
80 | int locate_symbols(void* kernelData)␊ |
81 | {␊ |
82 | ␉UInt16 symbolIndexes[NUM_SYMBOLS];␊ |
83 | ␊ |
84 | ␉struct load_command *loadCommand;␊ |
85 | ␉struct symtab_command *symtableData;␊ |
86 | ␉struct nlist *symbolEntry;␊ |
87 | ␉␊ |
88 | ␉char* symbolString;␊ |
89 | ␊ |
90 | ␉UInt32 kernelIndex = 0;␊ |
91 | ␉kernelIndex += sizeof(struct mach_header);␊ |
92 | ␉␊ |
93 | ␉if(((struct mach_header*)kernelData)->magic != MH_MAGIC) return KERNEL_64;␊ |
94 | ␉␊ |
95 | ␉//printf("%d load commands beginning at 0x%X\n", (unsigned int)header->ncmds, (unsigned int)kernelIndex);␊ |
96 | ␉//printf("Commands take up %d bytes\n", header->sizeofcmds);␊ |
97 | ␉␊ |
98 | ␉␊ |
99 | ␉int cmd = 0;␊ |
100 | ␉while(cmd < ((struct mach_header*)kernelData)->ncmds)␉// TODO: for loop instead␊ |
101 | ␉{␊ |
102 | ␉␉cmd++;␊ |
103 | ␉␉␊ |
104 | ␉␉loadCommand = kernelData + kernelIndex;␊ |
105 | ␉␉␊ |
106 | ␉␉UInt cmdSize = loadCommand->cmdsize;␊ |
107 | ␉␉␊ |
108 | ␉␉␊ |
109 | ␉␉// Locate start of _panic and _cpuid_set_info in the symbol tabe.␊ |
110 | ␉␉// Load commands should be anded with 0x7FFFFFFF to ignore the␉LC_REQ_DYLD flag␊ |
111 | ␉␉if((loadCommand->cmd & 0x7FFFFFFF) == LC_SYMTAB)␉␉// We only care about the symtab segment␊ |
112 | ␉␉{␊ |
113 | ␉␉␉//printf("Located symtable, length is 0x%X, 0x%X\n", (unsigned int)loadCommand->cmdsize, (unsigned int)sizeof(symtableData));␊ |
114 | ␉␉␉␊ |
115 | ␉␉␉symtableData = kernelData + kernelIndex;␊ |
116 | ␉␉␉kernelIndex += sizeof(struct symtab_command);␊ |
117 | ␉␉␉␊ |
118 | ␉␉␉cmdSize -= sizeof(struct symtab_command);␊ |
119 | ␊ |
120 | ␉␉␉// Loop through symbol table untill all of the symbols have been found␊ |
121 | ␉␉␉␊ |
122 | ␉␉␉symbolString = kernelData + symtableData->stroff; ␊ |
123 | ␉␉␉␊ |
124 | ␉␉␉␊ |
125 | ␉␉␉UInt16 symbolIndex = 0;␊ |
126 | ␉␉␉UInt8 numSymbolsFound = 0;␊ |
127 | ␊ |
128 | ␉␉␉while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS)␉// TODO: for loop␊ |
129 | ␉␉␉{␊ |
130 | ␉␉␉␉int i = 0;␊ |
131 | ␉␉␉␉while(i < NUM_SYMBOLS)␊ |
132 | ␉␉␉␉{␊ |
133 | ␉␉␉␉␉if(strcmp(symbolString, kernelSymbols[i]) == 0)␊ |
134 | ␉␉␉␉␉{␊ |
135 | ␉␉␉␉␉␉symbolIndexes[i] = symbolIndex;␊ |
136 | ␉␉␉␉␉␉numSymbolsFound++;␉␉␉␉␊ |
137 | ␉␉␉␉␉} ␊ |
138 | ␉␉␉␉␉␊ |
139 | ␉␉␉␉}␊ |
140 | ␉␉␉␉symbolString += strlen(symbolString) + 1;␊ |
141 | ␉␉␉␉symbolIndex++;␊ |
142 | ␉␉␉}␊ |
143 | ␉␉␉␊ |
144 | ␉␉␉// loop again␊ |
145 | ␉␉␉symbolIndex = 0;␊ |
146 | ␉␉␉numSymbolsFound = 0;␊ |
147 | ␉␉␉while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS)␉// TODO: for loop␊ |
148 | ␉␉␉{␊ |
149 | ␉␉␉␉␊ |
150 | ␉␉␉␉symbolEntry = kernelData + symtableData->symoff + (symbolIndex * sizeof(struct nlist));␊ |
151 | ␉␉␉␉␊ |
152 | ␉␉␉␉int i = 0;␊ |
153 | ␉␉␉␉while(i < NUM_SYMBOLS)␊ |
154 | ␉␉␉␉{␊ |
155 | ␉␉␉␉␉if(symbolIndex == (symbolIndexes[i] - 4))␊ |
156 | ␉␉␉␉␉{␊ |
157 | ␉␉␉␉␉␉kernelSymbolAddresses[i] = (UInt32)symbolEntry->n_value;␊ |
158 | ␉␉␉␉␉␉numSymbolsFound++;␉␉␉␉␊ |
159 | ␉␉␉␉␉} ␊ |
160 | ␉␉␉␉␉␊ |
161 | ␉␉␉␉}␊ |
162 | ␉␉␉␉␊ |
163 | ␉␉␉␉symbolIndex ++;␊ |
164 | ␉␉␉}␉␉␉␊ |
165 | ␉␉// Load commands should be anded with 0x7FFFFFFF to ignore the␉LC_REQ_DYLD flag␊ |
166 | ␉␉} else if((loadCommand->cmd & 0x7FFFFFFF) == LC_SEGMENT)␉␉// We only care about the __TEXT segment, any other load command can be ignored␊ |
167 | ␉␉{␊ |
168 | ␉␉␉␊ |
169 | ␉␉␉struct segment_command *segCommand;␊ |
170 | ␉␉␉␊ |
171 | ␉␉␉segCommand = kernelData + kernelIndex;␊ |
172 | ␉␉␉␊ |
173 | ␉␉␉//printf("Segment name is %s\n", segCommand->segname);␊ |
174 | ␉␉␉␊ |
175 | ␉␉␉if(strcmp("__TEXT", segCommand->segname) == 0)␊ |
176 | ␉␉␉{␊ |
177 | ␉␉␉␉UInt32 sectionIndex;␊ |
178 | ␉␉␉␉␊ |
179 | ␉␉␉␉sectionIndex = sizeof(struct segment_command);␊ |
180 | ␉␉␉␉␊ |
181 | ␉␉␉␉struct section *sect;␊ |
182 | ␉␉␉␉␊ |
183 | ␉␉␉␉while(sectionIndex < segCommand->cmdsize)␊ |
184 | ␉␉␉␉{␊ |
185 | ␉␉␉␉␉sect = kernelData + kernelIndex + sectionIndex;␊ |
186 | ␉␉␉␉␉␊ |
187 | ␉␉␉␉␉sectionIndex += sizeof(struct section);␊ |
188 | ␉␉␉␉␉␊ |
189 | ␉␉␉␉␉␊ |
190 | ␉␉␉␉␉if(strcmp("__text", sect->sectname) == 0)␊ |
191 | ␉␉␉␉␉{␊ |
192 | ␉␉␉␉␉␉// __TEXT,__text found, save the offset and address for when looking for the panic call.␊ |
193 | ␉␉␉␉␉␉textSection = sect->offset;␊ |
194 | ␉␉␉␉␉␉textAddress = sect->addr;␊ |
195 | ␉␉␉␉␉␉break;␊ |
196 | ␉␉␉␉␉}␉␉␉␉␉␊ |
197 | ␉␉␉␉}␊ |
198 | ␉␉␉}␊ |
199 | ␉␉␉␊ |
200 | ␉␉␉␊ |
201 | ␉␉␉kernelIndex += cmdSize;␊ |
202 | ␉␉} else {␊ |
203 | ␉␉␉kernelIndex += cmdSize;␊ |
204 | ␉␉}␊ |
205 | ␉}␊ |
206 | ␉␊ |
207 | ␉return KERNEL_32;␊ |
208 | }␊ |
209 | ␊ |
210 | /**␊ |
211 | ** Locate the fisrt instance of _panic inside of _cpuid_set_info, and remove it␊ |
212 | **/␊ |
213 | void patch_cpuid_set_info(void* kernelData)␊ |
214 | {␊ |
215 | ␉UInt8* bytes = (void*)kernelData;␊ |
216 | ␉UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] - textAddress + textSection);␊ |
217 | ␉UInt32 panidAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;␊ |
218 | ␉␊ |
219 | ␉␊ |
220 | ␉//TODO: don't assume it'll always work (Look for *next* function address in symtab and fail once it's been reached)␊ |
221 | ␉while( ␊ |
222 | ␉␉ (bytes[patchLocation -1] != 0xE8) ||␊ |
223 | ␉␉ ( ( (UInt32)(panidAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation] | ␊ |
224 | ␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉bytes[patchLocation + 1] << 8 | ␊ |
225 | ␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉bytes[patchLocation + 2] << 16 |␊ |
226 | ␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉bytes[patchLocation + 3] << 24))) //&&␊ |
227 | ␉␉ ␊ |
228 | ␉␉ // (patchLocation < maxLocation)␉// max location is not known... assuming there is a panic call somewhere after cpuid_set_info␊ |
229 | ␉␉ )␊ |
230 | ␉{␊ |
231 | ␉␉patchLocation++;␊ |
232 | ␉}␊ |
233 | ␉␊ |
234 | ␉// repace with nops␊ |
235 | ␉bytes[patchLocation - 1] = 0x90;␊ |
236 | ␉bytes[patchLocation ] = 0x90;␊ |
237 | ␉bytes[patchLocation + 1] = 0x90;␊ |
238 | ␉bytes[patchLocation + 2] = 0x90;␊ |
239 | ␉bytes[patchLocation + 3] = 0x90;␊ |
240 | ␉␊ |
241 | ␉// Patching finished␊ |
242 | }␊ |
243 | ␊ |
244 | /**␊ |
245 | ** SleepEnabler.kext replacement (for those that need it)␊ |
246 | ** Located the KERN_INVALID_ARGUMENT return and replace it with KERN_SUCCESS␊ |
247 | **/␊ |
248 | void patch_pmCPUExitHaltToOff(void* kernelData)␊ |
249 | {␊ |
250 | ␉UInt8* bytes = (void*)kernelData;␊ |
251 | ␉UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_PMCPUEXITHALTTOOFF] - textAddress + textSection);␊ |
252 | ␊ |
253 | ␉while(bytes[patchLocation - 1]␉!= 0xB8 ||␊ |
254 | ␉␉ bytes[patchLocation]␉␉!= 0x04 ||␉// KERN_INVALID_ARGUMENT (0x00000004)␊ |
255 | ␉␉ bytes[patchLocation + 1]␉!= 0x00 ||␉// KERN_INVALID_ARGUMENT␊ |
256 | ␉␉ bytes[patchLocation + 2]␉!= 0x00 ||␉// KERN_INVALID_ARGUMENT␊ |
257 | ␉␉ bytes[patchLocation + 3]␉!= 0x00)␉// KERN_INVALID_ARGUMENT␊ |
258 | ␊ |
259 | ␉{␊ |
260 | ␉␉patchLocation++;␊ |
261 | ␉}␊ |
262 | ␉bytes[patchLocation] = 0x00;␉// KERN_SUCCESS;␊ |
263 | ␊ |
264 | }␊ |
265 |