Root/
Source at commit 598 created 13 years 6 months ago. By meklort, Kext Patcher initial implimentation, incomplete. Mkexts v2 are partialy handled (need to be recompressed), all others are not handled. Added the zlib library, I may change this into a module in the future. | |
---|---|
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 | ␊ |
19 | void patch_kext(TagPtr plist, void* start);␊ |
20 | ␊ |
21 | static void * z_alloc(void *, u_int items, u_int size);␊ |
22 | static void z_free(void *, void *ptr);␊ |
23 | ␊ |
24 | typedef struct z_mem {␊ |
25 | uint32_t alloc_size;␊ |
26 | uint8_t data[0];␊ |
27 | } z_mem;␊ |
28 | ␊ |
29 | /*␊ |
30 | * Space allocation and freeing routines for use by zlib routines.␊ |
31 | */␊ |
32 | void *␊ |
33 | z_alloc(void * notused __unused, u_int num_items, u_int size)␊ |
34 | {␊ |
35 | void * result = NULL;␊ |
36 | z_mem * zmem = NULL;␊ |
37 | uint32_t total = num_items * size;␊ |
38 | uint32_t allocSize = total + sizeof(zmem);␊ |
39 | ␊ |
40 | zmem = (z_mem *)malloc(allocSize);␊ |
41 | if (!zmem) {␊ |
42 | goto finish;␊ |
43 | }␊ |
44 | zmem->alloc_size = allocSize;␊ |
45 | result = (void *)&(zmem->data);␊ |
46 | finish:␊ |
47 | return result;␊ |
48 | }␊ |
49 | ␊ |
50 | void␊ |
51 | z_free(void * notused __unused, void * ptr)␊ |
52 | {␊ |
53 | uint32_t * skipper = (uint32_t *)ptr - 1;␊ |
54 | z_mem * zmem = (z_mem *)skipper;␊ |
55 | free((void *)zmem);␊ |
56 | return;␊ |
57 | }␊ |
58 | ␊ |
59 | ␊ |
60 | unsigned long Mkext_Alder32( unsigned char * buffer, long length );␊ |
61 | ␊ |
62 | void KextPatcher_hook(void* current, void* arg2, void* arg3, void* arg4);␊ |
63 | ␊ |
64 | /**␊ |
65 | ** KextPatcher_start -> module start␊ |
66 | **␉␉Notified the module system that this module will hook into the ␊ |
67 | **␉␉LoadMatchedModules and LoadDriverMKext functions␊ |
68 | **/␊ |
69 | void KextPatcher_start()␊ |
70 | {␉␉␊ |
71 | ␉// Hooks into the following:␊ |
72 | ␉//␉execute_hook("LoadDriverMKext", (void*)package, (void*) length, NULL, NULL);␊ |
73 | ␉// execute_hook("LoadMatchedModules", module, &length, executableAddr, NULL);␊ |
74 | ␊ |
75 | ␉register_hook_callback("PCIDevice", &KextPatcher_hook);␊ |
76 | ␉register_hook_callback("LoadMatchedModules", &kext_loaded); ␊ |
77 | ␉register_hook_callback("LoadDriverMKext", &mkext_loaded); ␊ |
78 | ␊ |
79 | }␊ |
80 | ␊ |
81 | /**␊ |
82 | ** kext_loaded -> Called whenever a kext is in read into memory␊ |
83 | **␉␉This function will be used to patch kexts ( eg AppleInteIntegratedFramebuffer)␊ |
84 | **␉␉and their plists when they are loaded into memmory␊ |
85 | **/␊ |
86 | void kext_loaded(void* moduletmp, void* lengthprt, void* executableAddr, void* arg3)␊ |
87 | {␊ |
88 | ␉␊ |
89 | ␉//ModulePtr module = moduletmp;␊ |
90 | ␉//long length = *(long*)lengthprt;␊ |
91 | ␉//long length2 = strlen(module->plistAddr);␊ |
92 | ␉// *(long*)lengthprt = length2 + 5 * 1024 * 1024;␊ |
93 | ␊ |
94 | ␉//printf("Loading %s, lenght is %d, executable is 0x%X\n", module->plistAddr, length, executableAddr);␊ |
95 | ␉//getc();␊ |
96 | }␊ |
97 | ␊ |
98 | /**␊ |
99 | ** mkext_loaded -> Called whenever an mkext is in read into memory␊ |
100 | **␉␉This function will be used to patch mkext. Matching kexts will be␊ |
101 | **␉␉Extracted, modified, and then compressed again. Note: I need to determine␊ |
102 | **␉␉what sort of slowdown this will cause and if it's worth implimenting.␊ |
103 | **/␊ |
104 | ␊ |
105 | void mkext_loaded(void* filespec, void* packagetmp, void* lengthtmp, void* arg3)␊ |
106 | {␊ |
107 | ␉int version = 0;␊ |
108 | ␉int length = (int) lengthtmp;␊ |
109 | ␉mkext_basic_header* package = packagetmp;␊ |
110 | ␊ |
111 | ␉// Verify the MKext.␊ |
112 | if (( MKEXT_GET_MAGIC(package)␉␉!= MKEXT_MAGIC ) ||␊ |
113 | ( MKEXT_GET_SIGNATURE(package)␉!= MKEXT_SIGN ) ||␊ |
114 | ( MKEXT_GET_LENGTH(package)␉␉> kLoadSize )␉ ||␊ |
115 | ( MKEXT_GET_CHECKSUM(package) !=␊ |
116 | ␉␉ Mkext_Alder32((unsigned char *)&package->version, MKEXT_GET_LENGTH(package) - 0x10) ) )␊ |
117 | {␊ |
118 | return;␊ |
119 | ␉␉// Don't try to patch a b␊ |
120 | }␉␊ |
121 | ␉␊ |
122 | ␉␊ |
123 | ␉if(strcmp(filespec, "/System/Library/Caches/com.apple.kext.caches/Startup/Extensions.mkext") == 0)␊ |
124 | ␉{␊ |
125 | ␉␉printf("Invalidating mkext %s\n", filespec);␊ |
126 | ␉␉// 10.6 cache folder. Doesn't contain certain extensions we need, so invalidate it.␊ |
127 | ␉␉//package->adler32++;␊ |
128 | ␉␉// NOTE: double check that this is needed␊ |
129 | ␉␉package->magic = 0x00;␊ |
130 | ␉␉return;␊ |
131 | ␉}␊ |
132 | ␉␊ |
133 | ␉␊ |
134 | ␉version = MKEXT_GET_VERSION(package);␊ |
135 | ␉␊ |
136 | ␉if(version == 0x01008000) // mkext1␊ |
137 | ␉{␊ |
138 | ␉␉// mkext1 uses lzss␊ |
139 | ␉␉mkext1_header* package = packagetmp;␊ |
140 | ␉␉int i;␊ |
141 | ␉␉for(i = 0; i < MKEXT_GET_COUNT(package); i++)␊ |
142 | ␉␉{␊ |
143 | ␉␉␉printf("Parsing kext %d\n", i);␊ |
144 | ␉␉␉//mkext_kext* kext = MKEXT1_GET_KEXT(package, i);␊ |
145 | ␉␉␉// uses decompress_lzss␊ |
146 | ␉␉␉// TODO: handle kext␊ |
147 | ␊ |
148 | ␉␉}␊ |
149 | ␉}␊ |
150 | ␉else if((version & 0xFFFF0000) == 0x02000000) // mkext2␊ |
151 | ␉{␊ |
152 | ␉␉printf("Mkext2 package located at 0x%X\n", package);␊ |
153 | ␊ |
154 | ␉␉// mkext2 uses zlib␉␉␊ |
155 | ␉␉mkext2_header* package = packagetmp;␊ |
156 | ␉␉z_stream zstream;␊ |
157 | ␉␉bool zstream_inited = false;␊ |
158 | ␉␉int zlib_result;␊ |
159 | ␉␉int plist_offset = MKEXT2_GET_PLIST(package);␊ |
160 | ␉␉␊ |
161 | ␉␉char* plist = malloc(MKEXT2_GET_PLIST_FULLSIZE(package));␊ |
162 | ␉␉␊ |
163 | ␉␉bzero(&zstream, sizeof(zstream));␉␉␊ |
164 | ␉␉zstream.next_in = (UInt8*)((char*)package + plist_offset);␊ |
165 | ␉␉zstream.avail_in = MKEXT2_GET_PLIST_COMPSIZE(package);␊ |
166 | ␉␉␊ |
167 | ␉␉zstream.next_out = (UInt8*)plist;␊ |
168 | ␉␉zstream.avail_out = MKEXT2_GET_PLIST_FULLSIZE(package);␊ |
169 | ␉␉␊ |
170 | ␉␉zstream.zalloc = z_alloc;␊ |
171 | ␉␉zstream.zfree = z_free;␊ |
172 | ␉␉␉␉␊ |
173 | ␉␉zlib_result = inflateInit(&zstream);␊ |
174 | ␉␉if (Z_OK != zlib_result)␊ |
175 | ␉␉{␊ |
176 | ␉␉␉printf("ZLIB Error: %s\n", zstream.msg);␊ |
177 | ␉␉␉getc();␊ |
178 | ␉␉}␊ |
179 | ␉␉else ␊ |
180 | ␉␉{␊ |
181 | ␉␉␉zstream_inited = true;␊ |
182 | ␉␉}␊ |
183 | ␊ |
184 | ␉␉␊ |
185 | ␉␉zlib_result = inflate(&zstream, Z_FINISH);␊ |
186 | ␉␉printf("Inflated result is %d, in: %d bytes, out: %d bytes\n", zlib_result, zstream.total_in, zstream.total_out);␊ |
187 | ␉␉if (zlib_result == Z_STREAM_END || zlib_result == Z_OK)␊ |
188 | ␉␉{␊ |
189 | ␉␉␉//printf("Plist contains %s\n", plist);␊ |
190 | ␉␉␉␊ |
191 | ␉␉␉config_file_t plistData;␊ |
192 | ␉␉␉config_file_t allDicts;␊ |
193 | ␉␉␉bzero(&plistData, sizeof(plistData));␊ |
194 | ␉␉␉bzero(&allDicts, sizeof(allDicts));␊ |
195 | ␉␉␉␊ |
196 | ␉␉␉//plist += strlen("<dict><key>_MKEXTInfoDictionaries</key><array>");␉// Skip kMKEXTInfoDictionariesKey. Causes issues␊ |
197 | ␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉// NOTE: there will be an extra </array></dict> at the end␊ |
198 | ␉␉␉/*int len =*/ XMLParseFile( plist, &plistData.dictionary );␊ |
199 | ␊ |
200 | ␉␉␉int count = 0;␊ |
201 | ␊ |
202 | ␉␉␉count = XMLTagCount(plistData.dictionary);␊ |
203 | ␉␉␉if(count != 1)␊ |
204 | ␉␉␉{␊ |
205 | ␉␉␉␉error("Mkext has more than one entry, unable to patch.");␊ |
206 | ␉␉␉␉getc();␊ |
207 | ␉␉␉␉return;␊ |
208 | ␉␉␉}␊ |
209 | ␉␉␉allDicts.dictionary = XMLGetProperty(plistData.dictionary, kMKEXTInfoDictionariesKey);␊ |
210 | ␉␉␉count = XMLTagCount(allDicts.dictionary);␊ |
211 | ␉␉␉printf("Element type: %d\n", allDicts.dictionary->type);␊ |
212 | ␉␉␉printf("Element tag: %d\n", allDicts.dictionary->tag);␊ |
213 | ␉␉␉printf("Element tagNext: %d\n", allDicts.dictionary->tagNext);␊ |
214 | ␊ |
215 | ␉␉␉printf("Plist contains %d kexts\n", count);␊ |
216 | ␉␉␉␊ |
217 | ␉␉␉for(; count--; count > 0)␊ |
218 | ␉␉␉{␊ |
219 | ␉␉␉␉TagPtr kextEntry = XMLGetElement(allDicts.dictionary, count);␊ |
220 | ␉␉␉␉patch_kext(kextEntry, package);␊ |
221 | ␉␉␉}␊ |
222 | ␉␉␉␊ |
223 | ␉␉␉printf("kexts parsed\n");␊ |
224 | ␊ |
225 | ␉␉␉␊ |
226 | ␉␉}␊ |
227 | ␉␉else␊ |
228 | ␉␉{␊ |
229 | ␉␉␉printf("ZLIB Error: %s\n", zstream.msg);␊ |
230 | ␉␉␉getc();␊ |
231 | ␉␉}␊ |
232 | ␊ |
233 | ␉␉//config_file_t mkextPlist;␊ |
234 | ␉␉//ParseXMLFile((char*) plist, &mkextPlist.dictionary);␊ |
235 | ␉␉␊ |
236 | ␉␉␊ |
237 | ␉␉␊ |
238 | ␉␉␊ |
239 | ␉␉␊ |
240 | ␉␉/*␉␉int i;␊ |
241 | ␉␉for(i = 0; i < MKEXT_GET_COUNT(package); i++)␊ |
242 | ␉␉{␊ |
243 | ␉␉␉printf("Parsing kext %d\n", i);␊ |
244 | ␉␉}␊ |
245 | ␉␉*/␊ |
246 | ␉␉␊ |
247 | ␉␉if (zstream_inited) inflateEnd(&zstream);␊ |
248 | ␊ |
249 | ␉}␊ |
250 | ␊ |
251 | ␉␊ |
252 | ␉printf("Loading %s, length %d, version 0x%x\n", filespec, length, version);␊ |
253 | ␉getc();␊ |
254 | }␊ |
255 | ␊ |
256 | // TODO: only handles mkext2 entries␊ |
257 | void patch_kext(TagPtr plist, void* start)␊ |
258 | {␊ |
259 | ␉int exeutable_offset;␊ |
260 | ␉mkext2_file_entry* kext;␊ |
261 | ␉char* bundleID;␊ |
262 | ␉int full_size, compressed_size;␊ |
263 | ␉void* compressed_data;␊ |
264 | ␉z_stream zstream;␊ |
265 | ␉bool zstream_inited = false;␊ |
266 | ␉int zlib_result;␊ |
267 | ␉␊ |
268 | ␉if(XMLGetProperty(plist, kMKEXTExecutableKey) == NULL) return;␉// Kext is a plist only kext, don't patch␊ |
269 | ␉␊ |
270 | ␉bundleID = XMLCastString(XMLGetProperty(plist, kPropCFBundleIdentifier));␊ |
271 | ␉exeutable_offset = XMLCastInteger(XMLGetProperty(plist, kMKEXTExecutableKey));␊ |
272 | ␉kext = (void*)((char*)start + exeutable_offset);␊ |
273 | ␊ |
274 | ␉full_size = MKEXT2_GET_ENTRY_FULLSIZE(kext);␊ |
275 | ␉compressed_size = MKEXT2_GET_ENTRY_COMPSIZE(kext);␊ |
276 | ␉compressed_data = MKEXT2_GET_ENTRY_DATA(kext);␊ |
277 | ␉␊ |
278 | ␉if(strcmp(bundleID, "com.apple.driver.AppleIntelGMA950") == 0)␊ |
279 | ␉//if(strcmp(bundleID, "com.apple.driver.AppleACPIBatteryManager") == 0)␊ |
280 | ␉{␊ |
281 | ␉␉printf("offset is 0x%x\n", exeutable_offset);␊ |
282 | ␉␉␊ |
283 | ␉␉char* executable = malloc(full_size);␊ |
284 | ␉␉␊ |
285 | ␉␉bzero(&zstream, sizeof(zstream));␉␉␊ |
286 | ␉␉zstream.next_in = (UInt8*)compressed_data;␊ |
287 | ␉␉zstream.avail_in = compressed_size;␊ |
288 | ␉␉␊ |
289 | ␉␉zstream.next_out = (UInt8*)executable;␊ |
290 | ␉␉zstream.avail_out = full_size;␊ |
291 | ␉␉␊ |
292 | ␉␉zstream.zalloc = z_alloc;␊ |
293 | ␉␉zstream.zfree = z_free;␊ |
294 | ␉␉␊ |
295 | ␉␉zlib_result = inflateInit(&zstream);␊ |
296 | ␉␉if (Z_OK != zlib_result)␊ |
297 | ␉␉{␊ |
298 | ␉␉␉printf("ZLIB Error: %s\n", zstream.msg);␊ |
299 | ␉␉␉getc();␊ |
300 | ␉␉}␊ |
301 | ␉␉else ␊ |
302 | ␉␉{␊ |
303 | ␉␉␉zstream_inited = true;␊ |
304 | ␉␉}␊ |
305 | ␉␉␊ |
306 | ␉␉␊ |
307 | ␉␉zlib_result = inflate(&zstream, Z_FINISH);␊ |
308 | ␉␉␊ |
309 | ␉␉printf("Inflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);␊ |
310 | ␊ |
311 | ␉␉if (zstream_inited) inflateEnd(&zstream);␊ |
312 | ␊ |
313 | ␉␉free(executable);␊ |
314 | ␉␉␊ |
315 | ␉␉printf("\n");␊ |
316 | ␉␉␊ |
317 | ␉␉getc();␉␉␊ |
318 | ␉}␊ |
319 | }␊ |
320 | ␊ |
321 | ␊ |
322 | void KextPatcher_hook(void* arg1, void* arg2, void* arg3, void* arg4)␊ |
323 | {␊ |
324 | ␉//pci_dt_t* current = arg1;␊ |
325 | } |