Chameleon

Chameleon Svn Source Tree

Root/branches/meklort/i386/modules/KextPatcher/kext_patcher.c

Source at commit 607 created 13 years 6 months ago.
By meklort, Kext patcher can now add BCM43xx devices to the wifi kext. Only patches the kexts if associated devices exist, otherwise doesn't touch the mkext.
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
21#ifndef DEBUG_KEXT_PATCHER
22#define DEBUG_KEXT_PATCHER 0
23#endif
24
25#if DEBUG_KEXT_PATCHER
26#define DBG(x...)printf(x)
27#else
28#define DBG(x...)
29#endif
30bool patch_kext(TagPtr plist, char* plistbuffer, void* start);
31bool patch_gma_kexts(TagPtr plist, char* plistbuffer, void* start);
32bool patch_bcm_kext(TagPtr plist, char* plistbuffer, void* start);
33
34static void * z_alloc(void *, u_int items, u_int size);
35static void z_free(void *, void *ptr);
36
37uint16_t patch_gma_deviceid = 0;
38uint16_t patch_bcm_deviceid = 0;
39
40#define NEEDS_PATCHING(patch_bcm_deviceid || patch_gma_deviceid)
41
42typedef struct z_mem {
43 uint32_t alloc_size;
44 uint8_t data[0];
45} z_mem;
46
47/*
48 * Space allocation and freeing routines for use by zlib routines.
49 */
50void *
51z_alloc(void * notused __unused, u_int num_items, u_int size)
52{
53 void * result = NULL;
54 z_mem * zmem = NULL;
55 uint32_t total = num_items * size;
56 uint32_t allocSize = total + sizeof(zmem);
57
58 zmem = (z_mem *)malloc(allocSize);
59 if (!zmem) {
60 goto finish;
61 }
62 zmem->alloc_size = allocSize;
63 result = (void *)&(zmem->data);
64finish:
65 return result;
66}
67
68void
69z_free(void * notused __unused, void * ptr)
70{
71 uint32_t * skipper = (uint32_t *)ptr - 1;
72 z_mem * zmem = (z_mem *)skipper;
73 free((void *)zmem);
74 return;
75}
76
77
78unsigned long Mkext_Alder32( unsigned char * buffer, long length );
79
80void KextPatcher_hook(void* current, void* arg2, void* arg3, void* arg4);
81
82/**
83 ** KextPatcher_start -> module start
84 **Notified the module system that this module will hook into the
85 **LoadMatchedModules and LoadDriverMKext functions
86 **/
87void KextPatcher_start()
88{
89// Hooks into the following:
90//execute_hook("LoadDriverMKext", (void*)package, (void*) length, NULL, NULL);
91// execute_hook("LoadMatchedModules", module, &length, executableAddr, NULL);
92
93register_hook_callback("PCIDevice", &KextPatcher_hook);
94//register_hook_callback("LoadMatchedModules", &kext_loaded);
95register_hook_callback("LoadDriverMKext", &mkext_loaded);
96
97}
98
99/**
100 ** kext_loaded -> Called whenever a kext is in read into memory
101 **This function will be used to patch kexts ( eg AppleInteIntegratedFramebuffer)
102 **and their plists when they are loaded into memmory
103 **/
104void kext_loaded(void* moduletmp, void* lengthprt, void* executableAddr, void* arg3)
105{
106
107//ModulePtr module = moduletmp;
108//long length = *(long*)lengthprt;
109//long length2 = strlen(module->plistAddr);
110// *(long*)lengthprt = length2 + 5 * 1024 * 1024;
111
112//printf("Loading %s, lenght is %d, executable is 0x%X\n", module->plistAddr, length, executableAddr);
113//getc();
114}
115
116/**
117 ** mkext_loaded -> Called whenever an mkext is in read into memory
118 **This function will be used to patch mkext. Matching kexts will be
119 **Extracted, modified, and then compressed again. Note: I need to determine
120 **what sort of slowdown this will cause and if it's worth implimenting.
121 **/
122
123void mkext_loaded(void* filespec, void* packagetmp, void* lengthtmp, void* arg3)
124{
125if(!NEEDS_PATCHING) return;// No need to apply a patch, hardware doesn't need it
126
127int version = 0;
128//int length = *((int*)lengthtmp);
129mkext_basic_header* package = packagetmp;
130
131// Verify the MKext.
132 if (( MKEXT_GET_MAGIC(package)!= MKEXT_MAGIC ) ||
133 ( MKEXT_GET_SIGNATURE(package)!= MKEXT_SIGN ) ||
134 ( MKEXT_GET_LENGTH(package)> kLoadSize ) ||
135 ( MKEXT_GET_CHECKSUM(package) !=
136 Mkext_Alder32((unsigned char *)&package->version, MKEXT_GET_LENGTH(package) - 0x10) ) )
137 {
138 return;
139// Don't try to patch a b
140 }
141
142/*
143if(strcmp(filespec, "/System/Library/Caches/com.apple.kext.caches/Startup/Extensions.mkext") == 0)
144{
145printf("Invalidating mkext %s\n", filespec);
146// 10.6 cache folder. Doesn't contain certain extensions we need, so invalidate it.
147//package->adler32++;
148// NOTE: double check that this is needed
149package->magic = 0x00;
150return;
151}*/
152
153
154version = MKEXT_GET_VERSION(package);
155
156if(version == 0x01008000) // mkext1
157{
158// mkext1 uses lzss
159mkext1_header* package = packagetmp;
160int i;
161for(i = 0; i < MKEXT_GET_COUNT(package); i++)
162{
163DBG("Parsing kext %d\n", i);
164//mkext_kext* kext = MKEXT1_GET_KEXT(package, i);
165// uses decompress_lzss
166// TODO: handle kext
167
168}
169}
170else if((version & 0xFFFF0000) == 0x02000000) // mkext2
171{
172DBG("Mkext2 package located at 0x%X\n", package);
173
174// mkext2 uses zlib
175mkext2_header* package = packagetmp;
176z_stream zstream;
177bool zstream_inited = false;
178int zlib_result;
179int plist_offset = MKEXT2_GET_PLIST(package);
180
181char* plist = malloc(MKEXT2_GET_PLIST_FULLSIZE(package));
182
183bzero(&zstream, sizeof(zstream));
184zstream.next_in = (UInt8*)((char*)package + plist_offset);
185zstream.avail_in = MKEXT2_GET_PLIST_COMPSIZE(package);
186
187zstream.next_out = (UInt8*)plist;
188zstream.avail_out = MKEXT2_GET_PLIST_FULLSIZE(package);
189
190zstream.zalloc = z_alloc;
191zstream.zfree = z_free;
192
193zlib_result = inflateInit(&zstream);
194if (Z_OK != zlib_result)
195{
196printf("ZLIB Error: %s\n", zstream.msg);
197getc();
198}
199else
200{
201zstream_inited = true;
202}
203
204
205zlib_result = inflate(&zstream, Z_FINISH);
206if (zstream_inited) inflateEnd(&zstream);
207
208DBG("Inflated result is %d, in: %d bytes, out: %d bytes\n", zlib_result, zstream.total_in, zstream.total_out);
209if (zlib_result == Z_STREAM_END || zlib_result == Z_OK)
210{
211config_file_t plistData;
212config_file_t allDicts;
213bzero(&plistData, sizeof(plistData));
214bzero(&allDicts, sizeof(allDicts));
215
216XMLParseFile( plist, &plistData.dictionary );
217
218int count = 0;
219
220allDicts.dictionary = XMLGetProperty(plistData.dictionary, kMKEXTInfoDictionariesKey);
221count = XMLTagCount(allDicts.dictionary);
222
223DBG("Plist contains %d kexts\n", count);
224
225
226bool patched = false;
227for(; count--; count > 0)
228{
229TagPtr kextEntry = XMLGetElement(allDicts.dictionary, count);
230patched |= patch_kext(kextEntry, plist, package);
231}
232
233
234if(patched)
235{
236zstream_inited = false;
237// Recompress the plist
238bzero(&zstream, sizeof(zstream));
239zstream.next_in = (UInt8*)plist;
240zstream.next_out = (UInt8*)package + plist_offset;
241zstream.avail_in = MKEXT2_GET_PLIST_FULLSIZE(package);
242zstream.avail_out = MKEXT2_GET_PLIST_FULLSIZE(package)<<2;// Give us some extra free space, just in case
243zstream.zalloc = Z_NULL;
244zstream.zfree = Z_NULL;
245zstream.opaque = Z_NULL;
246
247
248zlib_result = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,15, 8 /* memLevel */, Z_DEFAULT_STRATEGY);
249if (Z_OK != zlib_result) {
250printf("ZLIB Deflate Error: %s\n", zstream.msg);
251getc();
252}
253else
254{
255zstream_inited = true;
256}
257
258zlib_result = deflate(&zstream, Z_FINISH);
259
260if (zlib_result == Z_STREAM_END)
261{
262DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, MKEXT2_GET_PLIST_FULLSIZE(package));
263}
264else if (zlib_result == Z_OK)
265{
266/* deflate filled output buffer, meaning the data doesn't compress.
267 */
268DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, MKEXT2_GET_PLIST_FULLSIZE(package));
269
270}
271else if (zlib_result != Z_STREAM_ERROR)
272{
273printf("ZLIB Deflate Error: %s\n", zstream.msg);
274getc();
275}
276
277if(zstream.total_out != MKEXT2_GET_PLIST_COMPSIZE(package))
278{
279// Update the mkext length
280MKEXT2_HDR_CAST(package)->length = MKEXT_SWAP(MKEXT_GET_LENGTH(package) - MKEXT2_GET_PLIST_COMPSIZE(package) + zstream.total_out);
281MKEXT2_HDR_CAST(package)->plist_compressed_size = MKEXT_SWAP(zstream.total_out);
282*((int*)lengthtmp) -= MKEXT2_GET_PLIST_COMPSIZE(package);
283*((int*)lengthtmp) += zstream.total_out;
284}
285
286if (zstream_inited) deflateEnd(&zstream);
287
288
289
290// re alder32 the new mkext2 package
291MKEXT_HDR_CAST(package)->adler32 =
292MKEXT_SWAP(Mkext_Alder32((unsigned char *)&package->version,
293 MKEXT_GET_LENGTH(package) - 0x10));
294}
295}
296else
297{
298printf("ZLIB Error: %s\n", zstream.msg);
299getc();
300}
301
302//config_file_t mkextPlist;
303//ParseXMLFile((char*) plist, &mkextPlist.dictionary);
304
305
306
307
308
309/*int i;
310for(i = 0; i < MKEXT_GET_COUNT(package); i++)
311{
312printf("Parsing kext %d\n", i);
313}
314*/
315
316
317}
318
319
320DBG("Loading %s, length %d, version 0x%x\n", filespec, length, version);
321//getc();
322}
323
324// FIXME: only handles mkext2 entries
325bool patch_kext(TagPtr plist, char* plistbuffer, void* start)
326{
327char* bundleID;
328
329if(XMLGetProperty(plist, kMKEXTExecutableKey) == NULL) return false;// Kext is a plist only kext, don't patch
330
331bundleID = XMLCastString(XMLGetProperty(plist, kPropCFBundleIdentifier));
332
333
334if(patch_gma_deviceid &&
335 (
336(strcmp(bundleID, "com.apple.driver.AppleIntelGMA950") == 0) ||
337(strcmp(bundleID, "com.apple.driver.AppleIntelIntegratedFramebuffer") == 0)
338 )
339 )
340{
341return patch_gma_kexts(plist, plistbuffer, start);
342}
343else if(patch_bcm_deviceid && (strcmp(bundleID, "com.apple.driver.AirPortBrcm43xx") == 0))
344{
345return patch_bcm_kext(plist, plistbuffer, start);
346
347}
348return false;
349}
350
351void KextPatcher_hook(void* arg1, void* arg2, void* arg3, void* arg4)
352{
353pci_dt_t* current = arg1;
354if(current)
355{
356if(current->class_id == PCI_CLASS_DISPLAY_VGA)
357{
358if(current->vendor_id == 0x8086 && current->device_id == 0x27AE)
359{
360// TODO: patche based on dev id.
361patch_gma_deviceid = current->device_id;
362}
363}
364else if(current->class_id == PCI_CLASS_NETWORK_OTHER)
365{
366// Patch BCM43xx
367if(current->vendor_id == 0x14E4 && ((current->device_id & 0xFF00) == 0x4300))
368{
369patch_bcm_deviceid = current->device_id;
370}
371}
372}
373}
374
375bool patch_bcm_kext(TagPtr plist, char* plistbuffer, void* start)
376{
377TagPtr personality;
378personality =XMLCastDict(XMLGetProperty(plist, kPropIOKitPersonalities));
379personality =XMLGetProperty(personality, (const char*)"Broadcom 802.11 PCI");
380TagPtr match_names =XMLCastArray(XMLGetProperty(personality, (const char*)"IONameMatch"));
381
382
383char* new_str = malloc(strlen("pci14e4,xxxx")+1);
384sprintf(new_str, "pci14e4,%02x", patch_bcm_deviceid);
385
386// Check to see if we *really* need to modify the plist, if not, return false
387// so that *if* this were going ot be the only modified kext, the repacking code
388// won't need to be executed.
389int count = XMLTagCount(match_names);
390while(count)
391{
392count--;
393TagPtr replace =XMLGetElement(match_names, count);// Modify the second entry
394char* orig_string = XMLCastString(replace);
395if(strcmp(orig_string, new_str) == 0) return false;
396}
397
398
399TagPtr replace =XMLGetElement(match_names, 1);// Modify the second entry
400char* orig_string = XMLCastString(replace);
401
402DBG("Attemting to replace '%s' with '%s'\n", orig_string, new_str);
403
404// TODO: verify string doesn't exist first.
405
406replace_string(orig_string, new_str, plistbuffer + XMLCastStringOffset(replace));
407
408return true;
409}
410
411bool patch_gma_kexts(TagPtr plist, char* plistbuffer, void* start)
412{
413int exeutable_offset, full_size, compressed_size;
414TagPtr personality;
415long offset;
416int zlib_result;
417z_stream zstream;
418bool zstream_inited = false;
419mkext2_file_entry* kext;
420void* compressed_data;
421
422exeutable_offset = XMLCastInteger(XMLGetProperty(plist, kMKEXTExecutableKey));
423kext = (void*)((char*)start + exeutable_offset);
424
425full_size = MKEXT2_GET_ENTRY_FULLSIZE(kext);
426compressed_size = MKEXT2_GET_ENTRY_COMPSIZE(kext);
427compressed_data = MKEXT2_GET_ENTRY_DATA(kext);
428
429personality =XMLCastDict(XMLGetProperty(plist, kPropIOKitPersonalities));
430if(XMLGetProperty(personality, (const char*)"Intel915"))
431{
432personality =XMLGetProperty(personality, (const char*)"Intel915");
433}
434else
435{
436personality =XMLGetProperty(personality, (const char*)"AppleIntelIntegratedFramebuffer");
437}
438#if DEBUG_KEXT_PATCHER
439char* pcimatch =XMLCastString(XMLGetProperty(personality, (const char*)"IOPCIPrimaryMatch"));
440#endif
441offset =XMLCastStringOffset(XMLGetProperty(personality, (const char*)"IOPCIPrimaryMatch"));
442
443replace_string("0x27A28086", "0x27AE8086", plistbuffer + offset);
444
445DBG("Located kext %s\n", bundleID);
446DBG("PCI Match offset = %d, string = %s\n", offset, pcimatch);
447char* executable = malloc(full_size);
448
449bzero(&zstream, sizeof(zstream));
450zstream.next_in = (UInt8*)compressed_data;
451zstream.avail_in = compressed_size;
452
453zstream.next_out = (UInt8*)executable;
454zstream.avail_out = full_size;
455
456zstream.zalloc = z_alloc;
457zstream.zfree = z_free;
458
459zlib_result = inflateInit(&zstream);
460if (Z_OK != zlib_result)
461{
462printf("ZLIB Inflate Error: %s\n", zstream.msg);
463getc();
464}
465else
466{
467zstream_inited = true;
468}
469
470
471zlib_result = inflate(&zstream, Z_FINISH);
472
473DBG("Inflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
474
475replace_word(0x27A28086, 0x27AE8086, executable, zstream.total_out);
476if (zstream_inited) inflateEnd(&zstream);
477
478
479zstream.next_in = (UInt8*)executable;
480//zstream.next_out = (UInt8*)((int)compressed_data<<1);
481zstream.next_out = (UInt8*)compressed_data;
482
483zstream.avail_in = full_size;
484zstream.avail_out = compressed_size;
485zstream.zalloc = Z_NULL;
486zstream.zfree = Z_NULL;
487zstream.opaque = Z_NULL;
488
489
490
491// Recompress the eecutable
492zlib_result = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,15, 8 /* memLevel */, Z_DEFAULT_STRATEGY);
493if (Z_OK != zlib_result) {
494printf("ZLIB Deflate Error: %s\n", zstream.msg);
495getc();
496}
497else
498{
499zstream_inited = true;
500}
501
502zlib_result = deflate(&zstream, Z_FINISH);
503
504if (zlib_result == Z_STREAM_END)
505{
506DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
507}
508else if (zlib_result == Z_OK)
509{
510/* deflate filled output buffer, meaning the data doesn't compress.
511 */
512DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
513
514}
515else if (zlib_result != Z_STREAM_ERROR)
516{
517printf("ZLIB Deflate Error: %s\n", zstream.msg);
518getc();
519}
520
521if (zstream_inited) deflateEnd(&zstream);
522
523free(executable);
524
525return true;
526}

Archive Download this file

Revision: 607