Chameleon

Chameleon Svn Source Tree

Root/branches/meklort/i386/boot2/kernel_patcher.c

Source at commit 143 created 13 years 11 months ago.
By meklort, Updated kernel patcher. Removed CPUID panic as well as removes the need for SleepEnabler.kext
1/*
2 * Copyright (c) 2009 Evan Lojewski. All rights reserved.
3 *
4 */
5
6#include "libsaio.h"
7#include "kernel_patcher.h"
8
9#define NUM_SYMBOLS3
10
11#define SYMBOL_CPUID_SET_INFO0
12#define SYMBOL_PANIC1
13#define SYMBOL_PMCPUEXITHALTTOOFF2
14
15#define SYMBOL_CPUID_SET_INFO_STRING"_cpuid_set_info"
16#define SYMBOL_PANIC_STRING"_panic"
17#define SYMBOL_PMCPUEXITHALTTOOFF_STRING"_pmCPUExitHaltToOff"
18
19char* kernelSymbols[NUM_SYMBOLS] = {
20SYMBOL_CPUID_SET_INFO_STRING,
21SYMBOL_PANIC_STRING,
22SYMBOL_PMCPUEXITHALTTOOFF_STRING
23};
24
25UInt32 kernelSymbolAddresses[NUM_SYMBOLS] = {
260,
270,
280
29};
30
31
32UInt32 textSection;
33UInt32 textAddress;
34
35
36extern unsigned long gBinaryAddress;
37
38
39void patch_kernel()
40{
41switch (locate_symbols((void*)gBinaryAddress)) {
42case KERNEL_32:
43patch_kernel_32((void*)gBinaryAddress);
44break;
45case KERNEL_64:
46default:
47patch_kernel_64((void*)gBinaryAddress);
48break;
49}
50}
51
52// patches a 64bit kernel.
53void patch_kernel_64(void* kernelData)
54{
55// At the moment, the kernel patching code fails when used
56// in 64bit mode, so we don't patch it. This is due to 32bit vs 64bit
57// pointers as well as changes in structure sizes
58verbose("Unable to patch 64bit kernel. Please use arch=i386.\n");
59}
60
61/**
62 ** patch_kernel_32
63 **Due to the way the _cpuid_set_info function is writtin, the first instance of _panic is called
64 **when an unsupported (read: non apple used cpu) is found. This routine locates that first _panic call
65 **and replaces the jump call (0xe8) with no ops (0x90).
66 **/
67
68void patch_kernel_32(void* kernelData)
69{
70patch_pmCPUExitHaltToOff(kernelData);
71patch_cpuid_set_info(kernelData);
72
73}
74
75/**
76 **This functions located the following in the mach_kernel symbol table
77 **_panic
78 **_cpuid_set_info
79 **/
80int locate_symbols(void* kernelData)
81{
82UInt16 symbolIndexes[NUM_SYMBOLS];
83
84struct load_command *loadCommand;
85struct symtab_command *symtableData;
86struct nlist *symbolEntry;
87
88char* symbolString;
89
90UInt32 kernelIndex = 0;
91kernelIndex += sizeof(struct mach_header);
92
93if(((struct mach_header*)kernelData)->magic != MH_MAGIC) return KERNEL_64;
94
95//printf("%d load commands beginning at 0x%X\n", (unsigned int)header->ncmds, (unsigned int)kernelIndex);
96//printf("Commands take up %d bytes\n", header->sizeofcmds);
97
98
99int cmd = 0;
100while(cmd < ((struct mach_header*)kernelData)->ncmds)// TODO: for loop instead
101{
102cmd++;
103
104loadCommand = kernelData + kernelIndex;
105
106UInt cmdSize = loadCommand->cmdsize;
107
108
109// Locate start of _panic and _cpuid_set_info in the symbol tabe.
110// Load commands should be anded with 0x7FFFFFFF to ignore theLC_REQ_DYLD flag
111if((loadCommand->cmd & 0x7FFFFFFF) == LC_SYMTAB)// We only care about the symtab segment
112{
113//printf("Located symtable, length is 0x%X, 0x%X\n", (unsigned int)loadCommand->cmdsize, (unsigned int)sizeof(symtableData));
114
115symtableData = kernelData + kernelIndex;
116kernelIndex += sizeof(struct symtab_command);
117
118cmdSize -= sizeof(struct symtab_command);
119
120// Loop through symbol table untill all of the symbols have been found
121
122symbolString = kernelData + symtableData->stroff;
123
124
125UInt16 symbolIndex = 0;
126UInt8 numSymbolsFound = 0;
127
128while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS)// TODO: for loop
129{
130int i = 0;
131while(i < NUM_SYMBOLS)
132{
133if(strcmp(symbolString, kernelSymbols[i]) == 0)
134{
135symbolIndexes[i] = symbolIndex;
136numSymbolsFound++;
137}
138
139}
140symbolString += strlen(symbolString) + 1;
141symbolIndex++;
142}
143
144// loop again
145symbolIndex = 0;
146numSymbolsFound = 0;
147while(symbolIndex < symtableData->nsyms && numSymbolsFound < NUM_SYMBOLS)// TODO: for loop
148{
149
150symbolEntry = kernelData + symtableData->symoff + (symbolIndex * sizeof(struct nlist));
151
152int i = 0;
153while(i < NUM_SYMBOLS)
154{
155if(symbolIndex == (symbolIndexes[i] - 4))
156{
157kernelSymbolAddresses[i] = (UInt32)symbolEntry->n_value;
158numSymbolsFound++;
159}
160
161}
162
163symbolIndex ++;
164}
165// Load commands should be anded with 0x7FFFFFFF to ignore theLC_REQ_DYLD flag
166} else if((loadCommand->cmd & 0x7FFFFFFF) == LC_SEGMENT)// We only care about the __TEXT segment, any other load command can be ignored
167{
168
169struct segment_command *segCommand;
170
171segCommand = kernelData + kernelIndex;
172
173//printf("Segment name is %s\n", segCommand->segname);
174
175if(strcmp("__TEXT", segCommand->segname) == 0)
176{
177UInt32 sectionIndex;
178
179sectionIndex = sizeof(struct segment_command);
180
181struct section *sect;
182
183while(sectionIndex < segCommand->cmdsize)
184{
185sect = kernelData + kernelIndex + sectionIndex;
186
187sectionIndex += sizeof(struct section);
188
189
190if(strcmp("__text", sect->sectname) == 0)
191{
192// __TEXT,__text found, save the offset and address for when looking for the panic call.
193textSection = sect->offset;
194textAddress = sect->addr;
195break;
196}
197}
198}
199
200
201kernelIndex += cmdSize;
202} else {
203kernelIndex += cmdSize;
204}
205}
206
207return KERNEL_32;
208}
209
210/**
211 ** Locate the fisrt instance of _panic inside of _cpuid_set_info, and remove it
212 **/
213void patch_cpuid_set_info(void* kernelData)
214{
215UInt8* bytes = (void*)kernelData;
216UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_CPUID_SET_INFO] - textAddress + textSection);
217UInt32 panidAddr = kernelSymbolAddresses[SYMBOL_PANIC] - textAddress;
218
219
220//TODO: don't assume it'll always work (Look for *next* function address in symtab and fail once it's been reached)
221while(
222 (bytes[patchLocation -1] != 0xE8) ||
223 ( ( (UInt32)(panidAddr - patchLocation - 4) + textSection ) != (UInt32)((bytes[patchLocation] |
224bytes[patchLocation + 1] << 8 |
225bytes[patchLocation + 2] << 16 |
226bytes[patchLocation + 3] << 24))) //&&
227
228 // (patchLocation < maxLocation)// max location is not known... assuming there is a panic call somewhere after cpuid_set_info
229 )
230{
231patchLocation++;
232}
233
234// repace with nops
235bytes[patchLocation - 1] = 0x90;
236bytes[patchLocation ] = 0x90;
237bytes[patchLocation + 1] = 0x90;
238bytes[patchLocation + 2] = 0x90;
239bytes[patchLocation + 3] = 0x90;
240
241// Patching finished
242}
243
244/**
245 ** SleepEnabler.kext replacement (for those that need it)
246 ** Located the KERN_INVALID_ARGUMENT return and replace it with KERN_SUCCESS
247 **/
248void patch_pmCPUExitHaltToOff(void* kernelData)
249{
250UInt8* bytes = (void*)kernelData;
251UInt32 patchLocation = (kernelSymbolAddresses[SYMBOL_PMCPUEXITHALTTOOFF] - textAddress + textSection);
252
253while(bytes[patchLocation - 1]!= 0xB8 ||
254 bytes[patchLocation]!= 0x04 ||// KERN_INVALID_ARGUMENT (0x00000004)
255 bytes[patchLocation + 1]!= 0x00 ||// KERN_INVALID_ARGUMENT
256 bytes[patchLocation + 2]!= 0x00 ||// KERN_INVALID_ARGUMENT
257 bytes[patchLocation + 3]!= 0x00)// KERN_INVALID_ARGUMENT
258
259{
260patchLocation++;
261}
262bytes[patchLocation] = 0x00;// KERN_SUCCESS;
263
264}
265

Archive Download this file

Revision: 143