Chameleon

Chameleon Commit Details

Date:2010-05-07 07:13:17 (13 years 11 months ago)
Author:Evan Lojewski
Commit:143
Parents: 142
Message:Updated kernel patcher. Removed CPUID panic as well as removes the need for SleepEnabler.kext
Changes:
A/branches/meklort/i386/boot2/kernel_patcher.c
A/branches/meklort/i386/boot2/kernel_patcher.h

File differences

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

Archive Download the corresponding diff file

Revision: 143