Chameleon

Chameleon Svn Source Tree

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

Source at commit 610 created 13 years 6 months ago.
By meklort, Added HDA patching capabilities. Currently disabled untill I add a way for either detection of a codec, or a way for users to specify the coedc
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);
33bool patch_hda_kext(TagPtr plist, char* plistbuffer, void* start);
34bool patch_hda_controller(TagPtr plist, char* plistbuffer, void* start);
35
36static void * z_alloc(void *, u_int items, u_int size);
37static void z_free(void *, void *ptr);
38
39uint16_t patch_gma_deviceid = 0;
40uint16_t patch_bcm_deviceid = 0;
41// TODO: add detection code / a method for users to enter the id
42uint16_t patch_hda_codec = 0;
43
44#define NEEDS_PATCHING(patch_bcm_deviceid || patch_gma_deviceid | patch_hda_codec)
45
46typedef struct z_mem {
47 uint32_t alloc_size;
48 uint8_t data[0];
49} z_mem;
50
51/*
52 * Space allocation and freeing routines for use by zlib routines.
53 */
54void *
55z_alloc(void * notused __unused, u_int num_items, u_int size)
56{
57 void * result = NULL;
58 z_mem * zmem = NULL;
59 uint32_t total = num_items * size;
60 uint32_t allocSize = total + sizeof(zmem);
61
62 zmem = (z_mem *)malloc(allocSize);
63 if (!zmem) {
64 goto finish;
65 }
66 zmem->alloc_size = allocSize;
67 result = (void *)&(zmem->data);
68finish:
69 return result;
70}
71
72void
73z_free(void * notused __unused, void * ptr)
74{
75 uint32_t * skipper = (uint32_t *)ptr - 1;
76 z_mem * zmem = (z_mem *)skipper;
77 free((void *)zmem);
78 return;
79}
80
81
82unsigned long Mkext_Alder32( unsigned char * buffer, long length );
83
84void KextPatcher_hook(void* current, void* arg2, void* arg3, void* arg4);
85
86/**
87 ** KextPatcher_start -> module start
88 **Notified the module system that this module will hook into the
89 **LoadMatchedModules and LoadDriverMKext functions
90 **/
91void KextPatcher_start()
92{
93// Hooks into the following:
94//execute_hook("LoadDriverMKext", (void*)package, (void*) length, NULL, NULL);
95// execute_hook("LoadMatchedModules", module, &length, executableAddr, NULL);
96
97register_hook_callback("PCIDevice", &KextPatcher_hook);
98//register_hook_callback("LoadMatchedModules", &kext_loaded);
99register_hook_callback("LoadDriverMKext", &mkext_loaded);
100
101}
102
103/**
104 ** kext_loaded -> Called whenever a kext is in read into memory
105 **This function will be used to patch kexts ( eg AppleInteIntegratedFramebuffer)
106 **and their plists when they are loaded into memmory
107 **/
108void kext_loaded(void* moduletmp, void* lengthprt, void* executableAddr, void* arg3)
109{
110
111//ModulePtr module = moduletmp;
112//long length = *(long*)lengthprt;
113//long length2 = strlen(module->plistAddr);
114// *(long*)lengthprt = length2 + 5 * 1024 * 1024;
115
116//printf("Loading %s, lenght is %d, executable is 0x%X\n", module->plistAddr, length, executableAddr);
117//getc();
118}
119
120/**
121 ** mkext_loaded -> Called whenever an mkext is in read into memory
122 **This function will be used to patch mkext. Matching kexts will be
123 **Extracted, modified, and then compressed again. Note: I need to determine
124 **what sort of slowdown this will cause and if it's worth implimenting.
125 **/
126
127void mkext_loaded(void* filespec, void* packagetmp, void* lengthtmp, void* arg3)
128{
129if(!NEEDS_PATCHING) return;// No need to apply a patch, hardware doesn't need it
130
131int version = 0;
132//int length = *((int*)lengthtmp);
133mkext_basic_header* package = packagetmp;
134
135// Verify the MKext.
136 if (( MKEXT_GET_MAGIC(package)!= MKEXT_MAGIC ) ||
137 ( MKEXT_GET_SIGNATURE(package)!= MKEXT_SIGN ) ||
138 ( MKEXT_GET_LENGTH(package)> kLoadSize ) ||
139 ( MKEXT_GET_CHECKSUM(package) !=
140 Mkext_Alder32((unsigned char *)&package->version, MKEXT_GET_LENGTH(package) - 0x10) ) )
141 {
142 return;
143// Don't try to patch a b
144 }
145
146/*
147if(strcmp(filespec, "/System/Library/Caches/com.apple.kext.caches/Startup/Extensions.mkext") == 0)
148{
149printf("Invalidating mkext %s\n", filespec);
150// 10.6 cache folder. Doesn't contain certain extensions we need, so invalidate it.
151//package->adler32++;
152// NOTE: double check that this is needed
153package->magic = 0x00;
154return;
155}*/
156
157
158version = MKEXT_GET_VERSION(package);
159
160if(version == 0x01008000) // mkext1
161{
162// mkext1 uses lzss
163mkext1_header* package = packagetmp;
164int i;
165for(i = 0; i < MKEXT_GET_COUNT(package); i++)
166{
167DBG("Parsing kext %d\n", i);
168//mkext_kext* kext = MKEXT1_GET_KEXT(package, i);
169// uses decompress_lzss
170// TODO: handle kext
171
172}
173}
174else if((version & 0xFFFF0000) == 0x02000000) // mkext2
175{
176DBG("Mkext2 package located at 0x%X\n", package);
177
178// mkext2 uses zlib
179mkext2_header* package = packagetmp;
180z_stream zstream;
181bool zstream_inited = false;
182int zlib_result;
183int plist_offset = MKEXT2_GET_PLIST(package);
184
185char* plist = malloc(MKEXT2_GET_PLIST_FULLSIZE(package));
186
187bzero(&zstream, sizeof(zstream));
188zstream.next_in = (UInt8*)((char*)package + plist_offset);
189zstream.avail_in = MKEXT2_GET_PLIST_COMPSIZE(package);
190
191zstream.next_out = (UInt8*)plist;
192zstream.avail_out = MKEXT2_GET_PLIST_FULLSIZE(package);
193
194zstream.zalloc = z_alloc;
195zstream.zfree = z_free;
196
197zlib_result = inflateInit(&zstream);
198if (Z_OK != zlib_result)
199{
200printf("ZLIB Error: %s\n", zstream.msg);
201getc();
202}
203else
204{
205zstream_inited = true;
206}
207
208
209zlib_result = inflate(&zstream, Z_FINISH);
210if (zstream_inited) inflateEnd(&zstream);
211
212DBG("Inflated result is %d, in: %d bytes, out: %d bytes\n", zlib_result, zstream.total_in, zstream.total_out);
213if (zlib_result == Z_STREAM_END || zlib_result == Z_OK)
214{
215config_file_t plistData;
216config_file_t allDicts;
217bzero(&plistData, sizeof(plistData));
218bzero(&allDicts, sizeof(allDicts));
219
220XMLParseFile( plist, &plistData.dictionary );
221
222int count = 0;
223
224allDicts.dictionary = XMLGetProperty(plistData.dictionary, kMKEXTInfoDictionariesKey);
225count = XMLTagCount(allDicts.dictionary);
226
227DBG("Plist contains %d kexts\n", count);
228
229
230bool patched = false;
231for(; count--; count > 0)
232{
233TagPtr kextEntry = XMLGetElement(allDicts.dictionary, count);
234patched |= patch_kext(kextEntry, plist, package);
235}
236
237
238if(patched)
239{
240zstream_inited = false;
241// Recompress the plist
242bzero(&zstream, sizeof(zstream));
243zstream.next_in = (UInt8*)plist;
244zstream.next_out = (UInt8*)package + plist_offset;
245zstream.avail_in = MKEXT2_GET_PLIST_FULLSIZE(package);
246zstream.avail_out = MKEXT2_GET_PLIST_FULLSIZE(package)<<2;// Give us some extra free space, just in case
247zstream.zalloc = Z_NULL;
248zstream.zfree = Z_NULL;
249zstream.opaque = Z_NULL;
250
251
252zlib_result = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,15, 8 /* memLevel */, Z_DEFAULT_STRATEGY);
253if (Z_OK != zlib_result) {
254printf("ZLIB Deflate Error: %s\n", zstream.msg);
255getc();
256}
257else
258{
259zstream_inited = true;
260}
261
262zlib_result = deflate(&zstream, Z_FINISH);
263
264if (zlib_result == Z_STREAM_END)
265{
266DBG("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));
267}
268else if (zlib_result == Z_OK)
269{
270/* deflate filled output buffer, meaning the data doesn't compress.
271 */
272DBG("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));
273
274}
275else if (zlib_result != Z_STREAM_ERROR)
276{
277printf("ZLIB Deflate Error: %s\n", zstream.msg);
278getc();
279}
280
281if(zstream.total_out != MKEXT2_GET_PLIST_COMPSIZE(package))
282{
283// Update the mkext length
284MKEXT2_HDR_CAST(package)->length = MKEXT_SWAP(MKEXT_GET_LENGTH(package) - MKEXT2_GET_PLIST_COMPSIZE(package) + zstream.total_out);
285MKEXT2_HDR_CAST(package)->plist_compressed_size = MKEXT_SWAP(zstream.total_out);
286*((int*)lengthtmp) -= MKEXT2_GET_PLIST_COMPSIZE(package);
287*((int*)lengthtmp) += zstream.total_out;
288}
289
290if (zstream_inited) deflateEnd(&zstream);
291
292
293
294// re alder32 the new mkext2 package
295MKEXT_HDR_CAST(package)->adler32 =
296MKEXT_SWAP(Mkext_Alder32((unsigned char *)&package->version,
297 MKEXT_GET_LENGTH(package) - 0x10));
298}
299}
300else
301{
302printf("ZLIB Error: %s\n", zstream.msg);
303getc();
304}
305
306//config_file_t mkextPlist;
307//ParseXMLFile((char*) plist, &mkextPlist.dictionary);
308
309
310
311
312
313/*int i;
314for(i = 0; i < MKEXT_GET_COUNT(package); i++)
315{
316printf("Parsing kext %d\n", i);
317}
318*/
319
320
321}
322
323
324DBG("Loading %s, length %d, version 0x%x\n", filespec, length, version);
325//getc();
326}
327
328// FIXME: only handles mkext2 entries
329bool patch_kext(TagPtr plist, char* plistbuffer, void* start)
330{
331char* bundleID;
332
333if(XMLGetProperty(plist, kMKEXTExecutableKey) == NULL) return false;// Kext is a plist only kext, don't patch
334
335bundleID = XMLCastString(XMLGetProperty(plist, kPropCFBundleIdentifier));
336
337
338if(patch_gma_deviceid &&
339 (
340(strcmp(bundleID, "com.apple.driver.AppleIntelGMA950") == 0) ||
341(strcmp(bundleID, "com.apple.driver.AppleIntelIntegratedFramebuffer") == 0)
342 )
343 )
344{
345return patch_gma_kexts(plist, plistbuffer, start);
346}
347else if(patch_bcm_deviceid && (strcmp(bundleID, "com.apple.driver.AirPortBrcm43xx") == 0))
348{
349return patch_bcm_kext(plist, plistbuffer, start);
350
351}
352else if(patch_hda_codec && strcmp(bundleID, "com.apple.driver.AppleHDA") == 0)
353{
354return patch_hda_kext(plist, plistbuffer, start);
355
356}
357/*
358else if(patch_hda_codec && strcmp(bundleID, "com.apple.driver.AppleHDAController") == 0)
359{
360return patch_hda_controller(plist, plistbuffer, start);
361
362}
363*/
364return false;
365}
366
367void KextPatcher_hook(void* arg1, void* arg2, void* arg3, void* arg4)
368{
369pci_dt_t* current = arg1;
370if(current)
371{
372if(current->class_id == PCI_CLASS_DISPLAY_VGA)
373{
374if(current->vendor_id == 0x8086 && current->device_id == 0x27AE)
375{
376// TODO: patche based on dev id.
377patch_gma_deviceid = current->device_id;
378}
379}
380else if(current->class_id == PCI_CLASS_NETWORK_OTHER)
381{
382// Patch BCM43xx
383if(current->vendor_id == 0x14E4 && ((current->device_id & 0xFF00) == 0x4300))
384{
385patch_bcm_deviceid = current->device_id;
386}
387}
388}
389}
390
391
392bool patch_hda_controller(TagPtr plist, char* plistbuffer, void* start)
393{
394return false;
395// change the PCI class code to match to. Note: A LegacyHDA plist should do this on it's own
396// As such, it's disabled
397
398// TODO: read class code
399TagPtr personality;
400personality =XMLCastDict(XMLGetProperty(plist, kPropIOKitPersonalities));
401personality =XMLGetProperty(personality, (const char*)"BuiltInHDA");
402TagPtr match_class =XMLCastArray(XMLGetProperty(personality, (const char*)"IOPCIClassMatch"));
403
404
405char* new_str = malloc(strlen("0xXXXX000&0xFFFE0000")+1);
406sprintf(new_str, "0x04030000&amp;0xFFFE0000"); // todo, pass in actual class id
407
408
409char* orig_string = "0x04020000&amp;0xFFFE0000"; //XMLCastString(match_class);
410
411DBG("Attemting to replace '%s' with '%s'\n", orig_string, new_str);
412
413// TODO: verify string doesn't exist first.
414
415replace_string(orig_string, new_str, plistbuffer + XMLCastStringOffset(match_class), 1024);
416
417return true;
418
419}
420
421
422bool patch_hda_kext(TagPtr plist, char* plistbuffer, void* start)
423{
424uint16_t find_codec = 0;
425int full_size, compressed_size, executable_offset;
426void* compressed_data;
427mkext2_file_entry* kext;
428int zlib_result;
429z_stream zstream;
430bool zstream_inited = false;
431
432switch(0xFF00 & patch_hda_codec)
433{
434case 0x0200:
435find_codec = 0x0262;
436break;
437
438case 0x0800:
439find_codec = 0x0885;
440break;
441
442case 0x0600:// specificaly the 662
443find_codec = 0x0885;
444break;
445}
446
447if(!find_codec) return false;// notify caller that we aren't patching the kext
448
449
450executable_offset = XMLCastInteger(XMLGetProperty(plist, kMKEXTExecutableKey));
451kext = (void*)((char*)start + executable_offset);
452
453full_size = MKEXT2_GET_ENTRY_FULLSIZE(kext);
454compressed_size = MKEXT2_GET_ENTRY_COMPSIZE(kext);
455compressed_data = MKEXT2_GET_ENTRY_DATA(kext);
456executable_offset = XMLCastInteger(XMLGetProperty(plist, kMKEXTExecutableKey));
457
458
459char* executable = malloc(full_size);
460
461bzero(&zstream, sizeof(zstream));
462zstream.next_in = (UInt8*)compressed_data;
463zstream.avail_in = compressed_size;
464
465zstream.next_out = (UInt8*)executable;
466zstream.avail_out = full_size;
467
468zstream.zalloc = z_alloc;
469zstream.zfree = z_free;
470
471zlib_result = inflateInit(&zstream);
472if (Z_OK != zlib_result)
473{
474printf("ZLIB Inflate Error: %s\n", zstream.msg);
475getc();
476}
477else
478{
479zstream_inited = true;
480}
481
482
483zlib_result = inflate(&zstream, Z_FINISH);
484
485DBG("Inflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
486
487replace_word(0x10EC | (find_codec << 8), 0xE10EC | (patch_hda_codec << 8), executable, zstream.total_out);
488
489if (zstream_inited) inflateEnd(&zstream);
490
491
492zstream.next_in = (UInt8*)executable;
493zstream.next_out = (UInt8*)compressed_data;
494
495zstream.avail_in = full_size;
496zstream.avail_out = compressed_size;
497zstream.zalloc = Z_NULL;
498zstream.zfree = Z_NULL;
499zstream.opaque = Z_NULL;
500
501
502
503// Recompress the eecutable
504zlib_result = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,15, 8 /* memLevel */, Z_DEFAULT_STRATEGY);
505if (Z_OK != zlib_result) {
506printf("ZLIB Deflate Error: %s\n", zstream.msg);
507getc();
508}
509else
510{
511zstream_inited = true;
512}
513
514zlib_result = deflate(&zstream, Z_FINISH);
515
516if (zlib_result == Z_STREAM_END)
517{
518DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
519}
520else if (zlib_result == Z_OK)
521{
522/* deflate filled output buffer, meaning the data doesn't compress.
523 */
524DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
525
526}
527else if (zlib_result != Z_STREAM_ERROR)
528{
529printf("ZLIB Deflate Error: %s\n", zstream.msg);
530getc();
531}
532
533if (zstream_inited) deflateEnd(&zstream);
534
535free(executable);
536
537return true;
538
539}
540
541bool patch_bcm_kext(TagPtr plist, char* plistbuffer, void* start)
542{
543TagPtr personality;
544personality =XMLCastDict(XMLGetProperty(plist, kPropIOKitPersonalities));
545personality =XMLGetProperty(personality, (const char*)"Broadcom 802.11 PCI");
546TagPtr match_names =XMLCastArray(XMLGetProperty(personality, (const char*)"IONameMatch"));
547
548
549char* new_str = malloc(strlen("pci14e4,xxxx")+1);
550sprintf(new_str, "pci14e4,%02x", patch_bcm_deviceid);
551
552// Check to see if we *really* need to modify the plist, if not, return false
553// so that *if* this were going ot be the only modified kext, the repacking code
554// won't need to be executed.
555int count = XMLTagCount(match_names);
556while(count)
557{
558count--;
559TagPtr replace =XMLGetElement(match_names, count);// Modify the second entry
560char* orig_string = XMLCastString(replace);
561if(strcmp(orig_string, new_str) == 0) return false;
562}
563
564
565TagPtr replace =XMLGetElement(match_names, 1);// Modify the second entry
566char* orig_string = XMLCastString(replace);
567
568DBG("Attemting to replace '%s' with '%s'\n", orig_string, new_str);
569
570// TODO: verify string doesn't exist first.
571
572replace_string(orig_string, new_str, plistbuffer + XMLCastStringOffset(replace), 1024);
573
574return true;
575}
576
577bool patch_gma_kexts(TagPtr plist, char* plistbuffer, void* start)
578{
579int exeutable_offset, full_size, compressed_size;
580TagPtr personality;
581long offset;
582int zlib_result;
583z_stream zstream;
584bool zstream_inited = false;
585mkext2_file_entry* kext;
586void* compressed_data;
587
588exeutable_offset = XMLCastInteger(XMLGetProperty(plist, kMKEXTExecutableKey));
589kext = (void*)((char*)start + exeutable_offset);
590
591full_size = MKEXT2_GET_ENTRY_FULLSIZE(kext);
592compressed_size = MKEXT2_GET_ENTRY_COMPSIZE(kext);
593compressed_data = MKEXT2_GET_ENTRY_DATA(kext);
594
595personality =XMLCastDict(XMLGetProperty(plist, kPropIOKitPersonalities));
596if(XMLGetProperty(personality, (const char*)"Intel915"))
597{
598personality =XMLGetProperty(personality, (const char*)"Intel915");
599}
600else
601{
602personality =XMLGetProperty(personality, (const char*)"AppleIntelIntegratedFramebuffer");
603}
604#if DEBUG_KEXT_PATCHER
605char* pcimatch =XMLCastString(XMLGetProperty(personality, (const char*)"IOPCIPrimaryMatch"));
606#endif
607offset =XMLCastStringOffset(XMLGetProperty(personality, (const char*)"IOPCIPrimaryMatch"));
608
609replace_string("0x27A28086", "0x27AE8086", plistbuffer + offset, 1024);
610
611DBG("Located kext %s\n", bundleID);
612DBG("PCI Match offset = %d, string = %s\n", offset, pcimatch);
613char* executable = malloc(full_size);
614
615bzero(&zstream, sizeof(zstream));
616zstream.next_in = (UInt8*)compressed_data;
617zstream.avail_in = compressed_size;
618
619zstream.next_out = (UInt8*)executable;
620zstream.avail_out = full_size;
621
622zstream.zalloc = z_alloc;
623zstream.zfree = z_free;
624
625zlib_result = inflateInit(&zstream);
626if (Z_OK != zlib_result)
627{
628printf("ZLIB Inflate Error: %s\n", zstream.msg);
629getc();
630}
631else
632{
633zstream_inited = true;
634}
635
636
637zlib_result = inflate(&zstream, Z_FINISH);
638
639DBG("Inflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
640
641replace_word(0x27A28086, 0x27AE8086, executable, zstream.total_out);
642if (zstream_inited) inflateEnd(&zstream);
643
644
645zstream.next_in = (UInt8*)executable;
646//zstream.next_out = (UInt8*)((int)compressed_data<<1);
647zstream.next_out = (UInt8*)compressed_data;
648
649zstream.avail_in = full_size;
650zstream.avail_out = compressed_size;
651zstream.zalloc = Z_NULL;
652zstream.zfree = Z_NULL;
653zstream.opaque = Z_NULL;
654
655
656
657// Recompress the eecutable
658zlib_result = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,15, 8 /* memLevel */, Z_DEFAULT_STRATEGY);
659if (Z_OK != zlib_result) {
660printf("ZLIB Deflate Error: %s\n", zstream.msg);
661getc();
662}
663else
664{
665zstream_inited = true;
666}
667
668zlib_result = deflate(&zstream, Z_FINISH);
669
670if (zlib_result == Z_STREAM_END)
671{
672DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
673}
674else if (zlib_result == Z_OK)
675{
676/* deflate filled output buffer, meaning the data doesn't compress.
677 */
678DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
679
680}
681else if (zlib_result != Z_STREAM_ERROR)
682{
683printf("ZLIB Deflate Error: %s\n", zstream.msg);
684getc();
685}
686
687if (zstream_inited) deflateEnd(&zstream);
688
689free(executable);
690
691return true;
692}

Archive Download this file

Revision: 610