Chameleon

Chameleon Svn Source Tree

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

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
20bool patch_kext(TagPtr plist, void* start);
21
22static void * z_alloc(void *, u_int items, u_int size);
23static void z_free(void *, void *ptr);
24
25typedef 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 */
33void *
34z_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);
47finish:
48 return result;
49}
50
51void
52z_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
61unsigned long Mkext_Alder32( unsigned char * buffer, long length );
62
63void 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 **/
70void 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
76register_hook_callback("PCIDevice", &KextPatcher_hook);
77//register_hook_callback("LoadMatchedModules", &kext_loaded);
78register_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 **/
87void 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
106void mkext_loaded(void* filespec, void* packagetmp, void* lengthtmp, void* arg3)
107{
108int version = 0;
109int length = (int) lengthtmp;
110mkext_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/*
124if(strcmp(filespec, "/System/Library/Caches/com.apple.kext.caches/Startup/Extensions.mkext") == 0)
125{
126printf("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
130package->magic = 0x00;
131return;
132}*/
133
134
135version = MKEXT_GET_VERSION(package);
136
137if(version == 0x01008000) // mkext1
138{
139// mkext1 uses lzss
140mkext1_header* package = packagetmp;
141int i;
142for(i = 0; i < MKEXT_GET_COUNT(package); i++)
143{
144printf("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}
151else if((version & 0xFFFF0000) == 0x02000000) // mkext2
152{
153printf("Mkext2 package located at 0x%X\n", package);
154
155// mkext2 uses zlib
156mkext2_header* package = packagetmp;
157z_stream zstream;
158bool zstream_inited = false;
159int zlib_result;
160int plist_offset = MKEXT2_GET_PLIST(package);
161
162char* plist = malloc(MKEXT2_GET_PLIST_FULLSIZE(package));
163
164bzero(&zstream, sizeof(zstream));
165zstream.next_in = (UInt8*)((char*)package + plist_offset);
166zstream.avail_in = MKEXT2_GET_PLIST_COMPSIZE(package);
167
168zstream.next_out = (UInt8*)plist;
169zstream.avail_out = MKEXT2_GET_PLIST_FULLSIZE(package);
170
171zstream.zalloc = z_alloc;
172zstream.zfree = z_free;
173
174zlib_result = inflateInit(&zstream);
175if (Z_OK != zlib_result)
176{
177printf("ZLIB Error: %s\n", zstream.msg);
178getc();
179}
180else
181{
182zstream_inited = true;
183}
184
185
186zlib_result = inflate(&zstream, Z_FINISH);
187printf("Inflated result is %d, in: %d bytes, out: %d bytes\n", zlib_result, zstream.total_in, zstream.total_out);
188if (zlib_result == Z_STREAM_END || zlib_result == Z_OK)
189{
190//printf("Plist contains %s\n", plist);
191
192config_file_t plistData;
193config_file_t allDicts;
194bzero(&plistData, sizeof(plistData));
195bzero(&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
201int count = 0;
202
203count = XMLTagCount(plistData.dictionary);
204if(count != 1)
205{
206error("Mkext has more than one entry, unable to patch.");
207getc();
208return;
209}
210allDicts.dictionary = XMLGetProperty(plistData.dictionary, kMKEXTInfoDictionariesKey);
211count = XMLTagCount(allDicts.dictionary);
212/*printf("Element type: %d\n", allDicts.dictionary->type);
213printf("Element tag: %d\n", allDicts.dictionary->tag);
214printf("Element tagNext: %d\n", allDicts.dictionary->tagNext);
215*/
216printf("Plist contains %d kexts\n", count);
217
218
219bool patched = false;
220for(; count--; count > 0)
221{
222TagPtr kextEntry = XMLGetElement(allDicts.dictionary, count);
223patched |= patch_kext(kextEntry, package);
224}
225
226if(patched)
227{
228// re alder32 the new mkext2 package
229MKEXT_HDR_CAST(package)->adler32 =
230MKEXT_SWAP(Mkext_Alder32((unsigned char *)&package->version,
231 MKEXT_GET_LENGTH(package) - 0x10));
232
233}
234
235printf("kexts parsed\n");
236
237
238}
239else
240{
241printf("ZLIB Error: %s\n", zstream.msg);
242getc();
243}
244
245//config_file_t mkextPlist;
246//ParseXMLFile((char*) plist, &mkextPlist.dictionary);
247
248
249
250
251
252/*int i;
253for(i = 0; i < MKEXT_GET_COUNT(package); i++)
254{
255printf("Parsing kext %d\n", i);
256}
257*/
258
259if (zstream_inited) inflateEnd(&zstream);
260
261}
262
263
264printf("Loading %s, length %d, version 0x%x\n", filespec, length, version);
265getc();
266}
267
268// TODO: only handles mkext2 entries
269bool patch_kext(TagPtr plist, void* start)
270{
271int exeutable_offset;
272mkext2_file_entry* kext;
273char* bundleID;
274int full_size, compressed_size;
275void* compressed_data;
276z_stream zstream;
277bool zstream_inited = false;
278int zlib_result;
279
280if(XMLGetProperty(plist, kMKEXTExecutableKey) == NULL) return false;// Kext is a plist only kext, don't patch
281
282bundleID = XMLCastString(XMLGetProperty(plist, kPropCFBundleIdentifier));
283exeutable_offset = XMLCastInteger(XMLGetProperty(plist, kMKEXTExecutableKey));
284kext = (void*)((char*)start + exeutable_offset);
285
286full_size = MKEXT2_GET_ENTRY_FULLSIZE(kext);
287compressed_size = MKEXT2_GET_ENTRY_COMPSIZE(kext);
288compressed_data = MKEXT2_GET_ENTRY_DATA(kext);
289
290if((strcmp(bundleID, "com.apple.driver.AppleIntelGMA950") == 0) ||
291(strcmp(bundleID, "com.apple.driver.AppleIntelIntegratedFramebuffer") == 0))
292{
293printf("Located kext %s\n", bundleID);
294printf("offset is 0x%x\n", exeutable_offset);
295
296char* executable = malloc(full_size);
297
298bzero(&zstream, sizeof(zstream));
299zstream.next_in = (UInt8*)compressed_data;
300zstream.avail_in = compressed_size;
301
302zstream.next_out = (UInt8*)executable;
303zstream.avail_out = full_size;
304
305zstream.zalloc = z_alloc;
306zstream.zfree = z_free;
307
308zlib_result = inflateInit(&zstream);
309if (Z_OK != zlib_result)
310{
311printf("ZLIB Inflate Error: %s\n", zstream.msg);
312getc();
313}
314else
315{
316zstream_inited = true;
317}
318
319
320zlib_result = inflate(&zstream, Z_FINISH);
321
322printf("Inflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
323
324printf("Replaced 0x27A28086 %d times.\n",
325 replace_word(0x27A28086, 0x27AE8086, executable, zstream.total_out));
326if (zstream_inited) inflateEnd(&zstream);
327
328
329zstream.next_in = (UInt8*)executable;
330zstream.next_out = (UInt8*)compressed_data;
331zstream.avail_in = full_size;
332zstream.avail_out = compressed_size;
333zstream.zalloc = Z_NULL;
334zstream.zfree = Z_NULL;
335zstream.opaque = Z_NULL;
336
337
338
339// Recompress the eecutable
340zlib_result = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,15, 8 /* memLevel */, Z_DEFAULT_STRATEGY);
341if (Z_OK != zlib_result) {
342printf("ZLIB Deflate Error: %s\n", zstream.msg);
343getc();
344}
345else
346{
347zstream_inited = true;
348}
349
350zlib_result = deflate(&zstream, Z_FINISH);
351
352if (zlib_result == Z_STREAM_END)
353{
354printf("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
355}
356else if (zlib_result == Z_OK)
357{
358/* deflate filled output buffer, meaning the data doesn't compress.
359 */
360printf("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}
363else if (zlib_result != Z_STREAM_ERROR)
364{
365printf("ZLIB Deflate Error: %s\n", zstream.msg);
366getc();
367}
368
369/* TODO: Only accept the compression if it actually shrinks the file.
370 */
371
372if (zstream_inited) deflateEnd(&zstream);
373
374
375
376
377
378free(executable);
379
380//printf("\n");
381
382getc();
383
384return true;
385}
386return false;
387}
388
389
390void KextPatcher_hook(void* arg1, void* arg2, void* arg3, void* arg4)
391{
392//pci_dt_t* current = arg1;
393}

Archive Download this file

Revision: 600