Root/
Source at commit 600 created 13 years 6 months ago. By meklort, Added zlib delfate code. Kext patcher can now successfuly patch the GMA950 and fb binaries for 27AE devices, plist not patched yet. | |
---|---|
1 | ␉/*␊ |
2 | * Copyright (c) 2010 Evan Lojewski. All rights reserved.␊ |
3 | *␉␊ |
4 | *␉KextPather␊ |
5 | *␉This is an experimental module that I'm looking into implimenting.␊ |
6 | *␉The main purpose is to replace the need for programs such as ␊ |
7 | * NetbookInstaller's kext patching routines. THis way, Apple's kexts can be␊ |
8 | * patched whe loaded instead. (eg: GMA950 kext, Bluetooth + Wifi kexts)␊ |
9 | */␊ |
10 | ␊ |
11 | #include "libsaio.h"␊ |
12 | #include "zlib.h"␊ |
13 | #include "kext_patcher.h"␊ |
14 | #include "pci.h"␊ |
15 | #include "drivers.h"␊ |
16 | #include "mkext.h"␊ |
17 | #include "modules.h"␊ |
18 | #include "hex_editor.h"␊ |
19 | ␊ |
20 | bool patch_kext(TagPtr plist, void* start);␊ |
21 | ␊ |
22 | static void * z_alloc(void *, u_int items, u_int size);␊ |
23 | static void z_free(void *, void *ptr);␊ |
24 | ␊ |
25 | typedef struct z_mem {␊ |
26 | uint32_t alloc_size;␊ |
27 | uint8_t data[0];␊ |
28 | } z_mem;␊ |
29 | ␊ |
30 | /*␊ |
31 | * Space allocation and freeing routines for use by zlib routines.␊ |
32 | */␊ |
33 | void *␊ |
34 | z_alloc(void * notused __unused, u_int num_items, u_int size)␊ |
35 | {␊ |
36 | void * result = NULL;␊ |
37 | z_mem * zmem = NULL;␊ |
38 | uint32_t total = num_items * size;␊ |
39 | uint32_t allocSize = total + sizeof(zmem);␊ |
40 | ␊ |
41 | zmem = (z_mem *)malloc(allocSize);␊ |
42 | if (!zmem) {␊ |
43 | goto finish;␊ |
44 | }␊ |
45 | zmem->alloc_size = allocSize;␊ |
46 | result = (void *)&(zmem->data);␊ |
47 | finish:␊ |
48 | return result;␊ |
49 | }␊ |
50 | ␊ |
51 | void␊ |
52 | z_free(void * notused __unused, void * ptr)␊ |
53 | {␊ |
54 | uint32_t * skipper = (uint32_t *)ptr - 1;␊ |
55 | z_mem * zmem = (z_mem *)skipper;␊ |
56 | free((void *)zmem);␊ |
57 | return;␊ |
58 | }␊ |
59 | ␊ |
60 | ␊ |
61 | unsigned long Mkext_Alder32( unsigned char * buffer, long length );␊ |
62 | ␊ |
63 | void KextPatcher_hook(void* current, void* arg2, void* arg3, void* arg4);␊ |
64 | ␊ |
65 | /**␊ |
66 | ** KextPatcher_start -> module start␊ |
67 | **␉␉Notified the module system that this module will hook into the ␊ |
68 | **␉␉LoadMatchedModules and LoadDriverMKext functions␊ |
69 | **/␊ |
70 | void KextPatcher_start()␊ |
71 | {␉␉␊ |
72 | ␉// Hooks into the following:␊ |
73 | ␉//␉execute_hook("LoadDriverMKext", (void*)package, (void*) length, NULL, NULL);␊ |
74 | ␉// execute_hook("LoadMatchedModules", module, &length, executableAddr, NULL);␊ |
75 | ␊ |
76 | ␉register_hook_callback("PCIDevice", &KextPatcher_hook);␊ |
77 | ␉//register_hook_callback("LoadMatchedModules", &kext_loaded); ␊ |
78 | ␉register_hook_callback("LoadDriverMKext", &mkext_loaded); ␊ |
79 | ␊ |
80 | }␊ |
81 | ␊ |
82 | /**␊ |
83 | ** kext_loaded -> Called whenever a kext is in read into memory␊ |
84 | **␉␉This function will be used to patch kexts ( eg AppleInteIntegratedFramebuffer)␊ |
85 | **␉␉and their plists when they are loaded into memmory␊ |
86 | **/␊ |
87 | void kext_loaded(void* moduletmp, void* lengthprt, void* executableAddr, void* arg3)␊ |
88 | {␊ |
89 | ␉␊ |
90 | ␉//ModulePtr module = moduletmp;␊ |
91 | ␉//long length = *(long*)lengthprt;␊ |
92 | ␉//long length2 = strlen(module->plistAddr);␊ |
93 | ␉// *(long*)lengthprt = length2 + 5 * 1024 * 1024;␊ |
94 | ␊ |
95 | ␉//printf("Loading %s, lenght is %d, executable is 0x%X\n", module->plistAddr, length, executableAddr);␊ |
96 | ␉//getc();␊ |
97 | }␊ |
98 | ␊ |
99 | /**␊ |
100 | ** mkext_loaded -> Called whenever an mkext is in read into memory␊ |
101 | **␉␉This function will be used to patch mkext. Matching kexts will be␊ |
102 | **␉␉Extracted, modified, and then compressed again. Note: I need to determine␊ |
103 | **␉␉what sort of slowdown this will cause and if it's worth implimenting.␊ |
104 | **/␊ |
105 | ␊ |
106 | void mkext_loaded(void* filespec, void* packagetmp, void* lengthtmp, void* arg3)␊ |
107 | {␊ |
108 | ␉int version = 0;␊ |
109 | ␉int length = (int) lengthtmp;␊ |
110 | ␉mkext_basic_header* package = packagetmp;␊ |
111 | ␊ |
112 | ␉// Verify the MKext.␊ |
113 | if (( MKEXT_GET_MAGIC(package)␉␉!= MKEXT_MAGIC ) ||␊ |
114 | ( MKEXT_GET_SIGNATURE(package)␉!= MKEXT_SIGN ) ||␊ |
115 | ( MKEXT_GET_LENGTH(package)␉␉> kLoadSize )␉ ||␊ |
116 | ( MKEXT_GET_CHECKSUM(package) !=␊ |
117 | ␉␉ Mkext_Alder32((unsigned char *)&package->version, MKEXT_GET_LENGTH(package) - 0x10) ) )␊ |
118 | {␊ |
119 | return;␊ |
120 | ␉␉// Don't try to patch a b␊ |
121 | }␉␊ |
122 | ␉␊ |
123 | ␉/*␊ |
124 | ␉if(strcmp(filespec, "/System/Library/Caches/com.apple.kext.caches/Startup/Extensions.mkext") == 0)␊ |
125 | ␉{␊ |
126 | ␉␉printf("Invalidating mkext %s\n", filespec);␊ |
127 | ␉␉// 10.6 cache folder. Doesn't contain certain extensions we need, so invalidate it.␊ |
128 | ␉␉//package->adler32++;␊ |
129 | ␉␉// NOTE: double check that this is needed␊ |
130 | ␉␉package->magic = 0x00;␊ |
131 | ␉␉return;␊ |
132 | ␉}*/␊ |
133 | ␉␊ |
134 | ␉␊ |
135 | ␉version = MKEXT_GET_VERSION(package);␊ |
136 | ␉␊ |
137 | ␉if(version == 0x01008000) // mkext1␊ |
138 | ␉{␊ |
139 | ␉␉// mkext1 uses lzss␊ |
140 | ␉␉mkext1_header* package = packagetmp;␊ |
141 | ␉␉int i;␊ |
142 | ␉␉for(i = 0; i < MKEXT_GET_COUNT(package); i++)␊ |
143 | ␉␉{␊ |
144 | ␉␉␉printf("Parsing kext %d\n", i);␊ |
145 | ␉␉␉//mkext_kext* kext = MKEXT1_GET_KEXT(package, i);␊ |
146 | ␉␉␉// uses decompress_lzss␊ |
147 | ␉␉␉// TODO: handle kext␊ |
148 | ␊ |
149 | ␉␉}␊ |
150 | ␉}␊ |
151 | ␉else if((version & 0xFFFF0000) == 0x02000000) // mkext2␊ |
152 | ␉{␊ |
153 | ␉␉printf("Mkext2 package located at 0x%X\n", package);␊ |
154 | ␊ |
155 | ␉␉// mkext2 uses zlib␉␉␊ |
156 | ␉␉mkext2_header* package = packagetmp;␊ |
157 | ␉␉z_stream zstream;␊ |
158 | ␉␉bool zstream_inited = false;␊ |
159 | ␉␉int zlib_result;␊ |
160 | ␉␉int plist_offset = MKEXT2_GET_PLIST(package);␊ |
161 | ␉␉␊ |
162 | ␉␉char* plist = malloc(MKEXT2_GET_PLIST_FULLSIZE(package));␊ |
163 | ␉␉␊ |
164 | ␉␉bzero(&zstream, sizeof(zstream));␉␉␊ |
165 | ␉␉zstream.next_in = (UInt8*)((char*)package + plist_offset);␊ |
166 | ␉␉zstream.avail_in = MKEXT2_GET_PLIST_COMPSIZE(package);␊ |
167 | ␉␉␊ |
168 | ␉␉zstream.next_out = (UInt8*)plist;␊ |
169 | ␉␉zstream.avail_out = MKEXT2_GET_PLIST_FULLSIZE(package);␊ |
170 | ␉␉␊ |
171 | ␉␉zstream.zalloc = z_alloc;␊ |
172 | ␉␉zstream.zfree = z_free;␊ |
173 | ␉␉␉␉␊ |
174 | ␉␉zlib_result = inflateInit(&zstream);␊ |
175 | ␉␉if (Z_OK != zlib_result)␊ |
176 | ␉␉{␊ |
177 | ␉␉␉printf("ZLIB Error: %s\n", zstream.msg);␊ |
178 | ␉␉␉getc();␊ |
179 | ␉␉}␊ |
180 | ␉␉else ␊ |
181 | ␉␉{␊ |
182 | ␉␉␉zstream_inited = true;␊ |
183 | ␉␉}␊ |
184 | ␊ |
185 | ␉␉␊ |
186 | ␉␉zlib_result = inflate(&zstream, Z_FINISH);␊ |
187 | ␉␉printf("Inflated result is %d, in: %d bytes, out: %d bytes\n", zlib_result, zstream.total_in, zstream.total_out);␊ |
188 | ␉␉if (zlib_result == Z_STREAM_END || zlib_result == Z_OK)␊ |
189 | ␉␉{␊ |
190 | ␉␉␉//printf("Plist contains %s\n", plist);␊ |
191 | ␉␉␉␊ |
192 | ␉␉␉config_file_t plistData;␊ |
193 | ␉␉␉config_file_t allDicts;␊ |
194 | ␉␉␉bzero(&plistData, sizeof(plistData));␊ |
195 | ␉␉␉bzero(&allDicts, sizeof(allDicts));␊ |
196 | ␉␉␉␊ |
197 | ␉␉␉//plist += strlen("<dict><key>_MKEXTInfoDictionaries</key><array>");␉// Skip kMKEXTInfoDictionariesKey. Causes issues␊ |
198 | ␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉// NOTE: there will be an extra </array></dict> at the end␊ |
199 | ␉␉␉/*int len =*/ XMLParseFile( plist, &plistData.dictionary );␊ |
200 | ␊ |
201 | ␉␉␉int count = 0;␊ |
202 | ␊ |
203 | ␉␉␉count = XMLTagCount(plistData.dictionary);␊ |
204 | ␉␉␉if(count != 1)␊ |
205 | ␉␉␉{␊ |
206 | ␉␉␉␉error("Mkext has more than one entry, unable to patch.");␊ |
207 | ␉␉␉␉getc();␊ |
208 | ␉␉␉␉return;␊ |
209 | ␉␉␉}␊ |
210 | ␉␉␉allDicts.dictionary = XMLGetProperty(plistData.dictionary, kMKEXTInfoDictionariesKey);␊ |
211 | ␉␉␉count = XMLTagCount(allDicts.dictionary);␊ |
212 | ␉␉␉/*printf("Element type: %d\n", allDicts.dictionary->type);␊ |
213 | ␉␉␉printf("Element tag: %d\n", allDicts.dictionary->tag);␊ |
214 | ␉␉␉printf("Element tagNext: %d\n", allDicts.dictionary->tagNext);␊ |
215 | ␉␉␉*/␊ |
216 | ␉␉␉printf("Plist contains %d kexts\n", count);␊ |
217 | ␉␉␉␊ |
218 | ␉␉␉␊ |
219 | ␉␉␉bool patched = false;␊ |
220 | ␉␉␉for(; count--; count > 0)␊ |
221 | ␉␉␉{␊ |
222 | ␉␉␉␉TagPtr kextEntry = XMLGetElement(allDicts.dictionary, count);␊ |
223 | ␉␉␉␉patched |= patch_kext(kextEntry, package);␊ |
224 | ␉␉␉}␊ |
225 | ␉␉␉␊ |
226 | ␉␉␉if(patched)␊ |
227 | ␉␉␉{␊ |
228 | ␉␉␉␉// re alder32 the new mkext2 package␊ |
229 | ␉␉␉␉MKEXT_HDR_CAST(package)->adler32 = ␊ |
230 | ␉␉␉␉␉MKEXT_SWAP(Mkext_Alder32((unsigned char *)&package->version,␊ |
231 | ␉␉␉␉␉␉␉␉␉␉␉ MKEXT_GET_LENGTH(package) - 0x10));␊ |
232 | ␊ |
233 | ␉␉␉}␊ |
234 | ␉␉␉␊ |
235 | ␉␉␉printf("kexts parsed\n");␊ |
236 | ␊ |
237 | ␉␉␉␊ |
238 | ␉␉}␊ |
239 | ␉␉else␊ |
240 | ␉␉{␊ |
241 | ␉␉␉printf("ZLIB Error: %s\n", zstream.msg);␊ |
242 | ␉␉␉getc();␊ |
243 | ␉␉}␊ |
244 | ␊ |
245 | ␉␉//config_file_t mkextPlist;␊ |
246 | ␉␉//ParseXMLFile((char*) plist, &mkextPlist.dictionary);␊ |
247 | ␉␉␊ |
248 | ␉␉␊ |
249 | ␉␉␊ |
250 | ␉␉␊ |
251 | ␉␉␊ |
252 | ␉␉/*␉␉int i;␊ |
253 | ␉␉for(i = 0; i < MKEXT_GET_COUNT(package); i++)␊ |
254 | ␉␉{␊ |
255 | ␉␉␉printf("Parsing kext %d\n", i);␊ |
256 | ␉␉}␊ |
257 | ␉␉*/␊ |
258 | ␉␉␊ |
259 | ␉␉if (zstream_inited) inflateEnd(&zstream);␊ |
260 | ␊ |
261 | ␉}␊ |
262 | ␊ |
263 | ␉␊ |
264 | ␉printf("Loading %s, length %d, version 0x%x\n", filespec, length, version);␊ |
265 | ␉getc();␊ |
266 | }␊ |
267 | ␊ |
268 | // TODO: only handles mkext2 entries␊ |
269 | bool patch_kext(TagPtr plist, void* start)␊ |
270 | {␊ |
271 | ␉int exeutable_offset;␊ |
272 | ␉mkext2_file_entry* kext;␊ |
273 | ␉char* bundleID;␊ |
274 | ␉int full_size, compressed_size;␊ |
275 | ␉void* compressed_data;␊ |
276 | ␉z_stream zstream;␊ |
277 | ␉bool zstream_inited = false;␊ |
278 | ␉int zlib_result;␊ |
279 | ␉␊ |
280 | ␉if(XMLGetProperty(plist, kMKEXTExecutableKey) == NULL) return false;␉// Kext is a plist only kext, don't patch␊ |
281 | ␉␊ |
282 | ␉bundleID = XMLCastString(XMLGetProperty(plist, kPropCFBundleIdentifier));␊ |
283 | ␉exeutable_offset = XMLCastInteger(XMLGetProperty(plist, kMKEXTExecutableKey));␊ |
284 | ␉kext = (void*)((char*)start + exeutable_offset);␊ |
285 | ␊ |
286 | ␉full_size = MKEXT2_GET_ENTRY_FULLSIZE(kext);␊ |
287 | ␉compressed_size = MKEXT2_GET_ENTRY_COMPSIZE(kext);␊ |
288 | ␉compressed_data = MKEXT2_GET_ENTRY_DATA(kext);␊ |
289 | ␉␊ |
290 | ␉if(␉(strcmp(bundleID, "com.apple.driver.AppleIntelGMA950") == 0) ||␊ |
291 | ␉␉(strcmp(bundleID, "com.apple.driver.AppleIntelIntegratedFramebuffer") == 0))␊ |
292 | ␉{␊ |
293 | ␉␉printf("Located kext %s\n", bundleID);␊ |
294 | ␉␉printf("offset is 0x%x\n", exeutable_offset);␊ |
295 | ␉␉␊ |
296 | ␉␉char* executable = malloc(full_size);␊ |
297 | ␉␉␊ |
298 | ␉␉bzero(&zstream, sizeof(zstream));␉␉␊ |
299 | ␉␉zstream.next_in = (UInt8*)compressed_data;␊ |
300 | ␉␉zstream.avail_in = compressed_size;␊ |
301 | ␉␉␊ |
302 | ␉␉zstream.next_out = (UInt8*)executable;␊ |
303 | ␉␉zstream.avail_out = full_size;␊ |
304 | ␉␉␊ |
305 | ␉␉zstream.zalloc = z_alloc;␊ |
306 | ␉␉zstream.zfree = z_free;␊ |
307 | ␉␉␊ |
308 | ␉␉zlib_result = inflateInit(&zstream);␊ |
309 | ␉␉if (Z_OK != zlib_result)␊ |
310 | ␉␉{␊ |
311 | ␉␉␉printf("ZLIB Inflate Error: %s\n", zstream.msg);␊ |
312 | ␉␉␉getc();␊ |
313 | ␉␉}␊ |
314 | ␉␉else ␊ |
315 | ␉␉{␊ |
316 | ␉␉␉zstream_inited = true;␊ |
317 | ␉␉}␊ |
318 | ␉␉␊ |
319 | ␉␉␊ |
320 | ␉␉zlib_result = inflate(&zstream, Z_FINISH);␊ |
321 | ␉␉␊ |
322 | ␉␉printf("Inflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);␊ |
323 | ␊ |
324 | ␉␉printf("Replaced 0x27A28086 %d times.\n", ␊ |
325 | ␉␉␉ replace_word(0x27A28086, 0x27AE8086, executable, zstream.total_out));␊ |
326 | ␉␉if (zstream_inited) inflateEnd(&zstream);␊ |
327 | ␊ |
328 | ␉␉␊ |
329 | ␉␉zstream.next_in = (UInt8*)executable;␊ |
330 | ␉␉zstream.next_out = (UInt8*)compressed_data;␊ |
331 | ␉␉zstream.avail_in = full_size;␊ |
332 | ␉␉zstream.avail_out = compressed_size;␊ |
333 | ␉␉zstream.zalloc = Z_NULL;␊ |
334 | ␉␉zstream.zfree = Z_NULL;␊ |
335 | ␉␉zstream.opaque = Z_NULL;␊ |
336 | ␉␉␊ |
337 | ␉␉␊ |
338 | ␉␉␊ |
339 | ␉␉// Recompress the eecutable␊ |
340 | ␉␉zlib_result = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,15, 8 /* memLevel */, Z_DEFAULT_STRATEGY);␊ |
341 | ␉␉if (Z_OK != zlib_result) {␊ |
342 | ␉␉␉printf("ZLIB Deflate Error: %s\n", zstream.msg);␊ |
343 | ␉␉␉getc();␊ |
344 | ␉␉}␊ |
345 | ␉␉else ␊ |
346 | ␉␉{␊ |
347 | ␉␉␉zstream_inited = true;␊ |
348 | ␉␉}␊ |
349 | ␉␉␊ |
350 | ␉␉zlib_result = deflate(&zstream, Z_FINISH);␊ |
351 | ␊ |
352 | ␉␉if (zlib_result == Z_STREAM_END)␊ |
353 | ␉␉{␊ |
354 | ␉␉␉printf("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);␊ |
355 | ␉␉} ␊ |
356 | ␉␉else if (zlib_result == Z_OK)␊ |
357 | ␉␉{␊ |
358 | ␉␉␉/* deflate filled output buffer, meaning the data doesn't compress.␊ |
359 | ␉␉␉ */␊ |
360 | ␉␉␉printf("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);␊ |
361 | ␊ |
362 | ␉␉} ␊ |
363 | ␉␉else if (zlib_result != Z_STREAM_ERROR)␊ |
364 | ␉␉{␊ |
365 | ␉␉␉printf("ZLIB Deflate Error: %s\n", zstream.msg);␊ |
366 | ␉␉␉getc();␊ |
367 | ␉␉}␊ |
368 | ␉␉␊ |
369 | ␉␉/* TODO: Only accept the compression if it actually shrinks the file.␊ |
370 | ␉␉ */␊ |
371 | ␊ |
372 | ␉␉if (zstream_inited) deflateEnd(&zstream);␊ |
373 | ␊ |
374 | ␊ |
375 | ␉␉␊ |
376 | ␉␉␊ |
377 | ␊ |
378 | ␉␉free(executable);␊ |
379 | ␉␉␊ |
380 | ␉␉//printf("\n");␊ |
381 | ␉␉␊ |
382 | ␉␉getc();␉␉␊ |
383 | ␉␉␊ |
384 | ␉␉return true;␊ |
385 | ␉}␊ |
386 | ␉return false;␊ |
387 | }␊ |
388 | ␊ |
389 | ␊ |
390 | void KextPatcher_hook(void* arg1, void* arg2, void* arg3, void* arg4)␊ |
391 | {␊ |
392 | ␉//pci_dt_t* current = arg1;␊ |
393 | } |