Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 606