Chameleon

Chameleon Commit Details

Date:2017-03-25 18:58:21 (2 years 2 months ago)
Author:ErmaC
Commit:2870
Parents: 2869
Message:Port and adapt and improve binaryPatcher from Clover Project (Micky1979)
Changes:
A/branches/ErmaC/Enoch/i386/libsaio/binaryPatcher.h
A/branches/ErmaC/Enoch/i386/libsaio/binaryPatcher.c
M/branches/ErmaC/Enoch/i386/libsaio/Makefile
M/branches/ErmaC/Enoch/i386/boot2/boot.c

File differences

branches/ErmaC/Enoch/i386/libsaio/Makefile
2828
2929
3030
31
31
3232
3333
3434
INC = -I. -I$(SRCROOT) -I$(SYMROOT) -I$(LIBSADIR) -I$(BOOT2DIR) -I${SRCROOT}/i386/include
SAIO_OBJS = table.o asm.o bios.o biosfn.o \
disk.o sys.o cache.o bootstruct.o \
binaryPatcher.o disk.o sys.o cache.o bootstruct.o \
stringTable.o load.o pci.o allocate.o misc.o \
befs.o freebsd.o openbsd.o \
vbe.o nbp.o hfs.o hfs_compare.o \
branches/ErmaC/Enoch/i386/libsaio/binaryPatcher.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
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
//
// binaryPatcher.c
//
// binary patcher of any kinds (kexts, kernel, ACPI tables etc..)
//
//
#include "binaryPatcher.h"
#include "boot.h" /* to expose gDarwinBuildVerStr */
// Clover
// Searches Source for Search pattern of size SearchSize and return number of occurrences
//
unsigned int FindAndCount(void *sourceData,
UInt32 SourceSize,
UInt32 StartLocation,
UInt8 *Search,
unsigned int SearchSize)
{
UInt8 *Source = ( UInt8 *)sourceData;
SourceSize += StartLocation;
unsigned int NumFounds = 0;
UInt8 *End = Source + SourceSize;
while (Source < End) {
if (memcmp(Source, Search, SearchSize) == 0) {
NumFounds++;
Source += SearchSize;
} else {
Source++;
}
}
return NumFounds;
}
// Clover
//
// Searches Source for Search pattern of size SearchSize
// and replaces it with Replace up to MaxReplaces times.
// If MaxReplaces <= 0, then there is no restriction on number of replaces.
// Replace should have the same size as Search.
// Returns number of replaces done.
//
unsigned int FindAndReplace(void *sourceData,
UInt32 SourceSize,
UInt32 StartLocation,
UInt8 *Search,
unsigned int SearchSize,
UInt8 *Replace,
int MaxReplaces)
{
UInt8 *Source = ( UInt8 *)sourceData;
Source += StartLocation;
unsigned int NumReplaces = 0;
bool NoReplacesRestriction = MaxReplaces <= 0;
UInt8 *End = Source + SourceSize;
if (!Source || !Search || !Replace || !SearchSize) {
return 0;
}
while ((Source < End) && (NoReplacesRestriction || (MaxReplaces > 0))) {
if (memcmp(Source, Search, SearchSize) == 0) {
memcpy(Source, Replace, SearchSize);
NumReplaces++;
MaxReplaces--;
Source += SearchSize;
} else {
Source++;
}
}
return NumReplaces;
}
bool IsPatchEnabled (char *MatchOSEntry, char *CurrOS)
{
int i;
bool ret = false;
struct MatchOSes *mos; // = malloc(sizeof(struct MatchOSes));
if (!MatchOSEntry || !CurrOS) {
return true; //undefined matched corresponds to old behavior
}
mos = GetStrArraySeparatedByChar(MatchOSEntry, ',');
if (!mos) {
return true; //memory fails -> anyway the patch enabled
}
for (i = 0; i < mos->count; ++i) {
// dot represent MatchOS
if (
((strstr(mos->array[i], ".") != NULL) && IsOSValid(mos->array[i], CurrOS)) || // MatchOS
(strstr(mos->array[i], CurrOS) != NULL) // MatchBuild
) {
ret = true;
break;
}
}
deallocMatchOSes(mos);
return ret;
}
// FIXME
// the following is an improved versione of what Clover have
// but malloc in Enoch fails to allocate memory (also using the same code in Clover ).
// For now we use a buffer and for this reason deallocMatchOSes() does nothing..
struct MatchOSes *GetStrArraySeparatedByChar(char *str, char sep)
{
char buffer[strlen(str) +1];
struct MatchOSes *mo;
int len = 0, i = 0, inc = 1;
char doubleSep[2];
mo = malloc(sizeof(struct MatchOSes));
if (!mo) {
return NULL;
}
mo->count = countOccurrences( str, sep ) + 1;
len = (int)strlen(str);
doubleSep[0] = sep; doubleSep[1] = sep;
if(strstr(str, doubleSep) || !len || str[0] == sep || str[len -1] == sep) {
mo->count = 0;
mo->array[0] = NULL;
return mo;
}
if (mo->count > 1) {
int *indexes = (int *) malloc(mo->count + 1);
for (i = 0; i < len; ++i) {
char c = str[i];
if (c == sep) {
indexes[inc]=i;
inc++;
}
}
indexes[0] = 0; // manually add first index
indexes[mo->count] = len; // manually add last index
int startLocation = 0, endLocation = 0;
for (i = 0; i < mo->count; ++i) {
unsigned int newLen = 0;
startLocation = i ? indexes[i] + 1 : indexes[0];
endLocation = (i == mo->count - 1) ? len : indexes[i + 1];
newLen = (endLocation - startLocation);
//char *lastStr = (char *) malloc(newLen+1);
//strncpy(lastStr, str + startLocation, newLen);
strncpy(buffer, str + startLocation, newLen);
buffer[newLen /*strlen(lastStr)*/] = '\0';
mo->array[i] = buffer;
//printf("%s [len = %lu]\n", mo->array[i], strlen(mo->array[i]));
if (endLocation == len) break;
}
free(indexes);
}
else {
//char *lastStr = (char *) malloc(strlen(str)+1);
//strncpy(lastStr, str, strlen(str));
strncpy(buffer, str, strlen(str));
buffer[strlen(str)] = '\0';
mo->array[0] = buffer;
//printf("%s [len = %lu]\n", mo->array[0], strlen(mo->array[0]));
}
//printf("------------\n");
return mo;
}
void deallocMatchOSes(struct MatchOSes *s)
{
/*
int i;
if (!s) {
return;
}
for (i = 0; i < s->count; i++) {
if (s->array[i]) {
free(s->array[i]);
}
}
free(s);
*/
}
bool IsOSValid(char *MatchOS, char *CurrOS)
{
/* example for valid matches are:
10.7, only 10.7 (10.7.1 will be skipped)
10.10.2 only 10.10.2 (10.10.1 or 10.10.5 will be skipped)
10.10.x (or 10.10.X), in this case is valid for all minor version of 10.10 (10.10.(0-9))
*/
bool ret = false;
struct MatchOSes *osToc;
struct MatchOSes *currOStoc;
if (!MatchOS || !CurrOS) {
return true; //undefined matched corresponds to old behavior
}
osToc = GetStrArraySeparatedByChar(MatchOS, '.');
currOStoc = GetStrArraySeparatedByChar(CurrOS, '.');
if (osToc->count == 2) {
if (strcmp(osToc->array[0], currOStoc->array[0]) == 0
&& strcmp(osToc->array[1], currOStoc->array[1]) == 0) {
ret = true;
}
} else if (osToc->count == 3) {
if (currOStoc->count == 3) {
if (strcmp(osToc->array[0], currOStoc->array[0]) == 0
&& strcmp(osToc->array[1], currOStoc->array[1]) == 0
&& strcmp(osToc->array[2], currOStoc->array[2]) == 0) {
ret = true;
} else if (strcmp(osToc->array[0], currOStoc->array[0]) == 0
&& strcmp(osToc->array[1], currOStoc->array[1]) == 0
&& (strcmp(osToc->array[2], "x") == 0 || strcmp(osToc->array[2], "X") == 0)) {
ret = true;
}
} else if (currOStoc->count == 2) {
if (strcmp(osToc->array[0], currOStoc->array[0]) == 0
&& strcmp(osToc->array[1], currOStoc->array[1]) == 0) {
ret = true;
} else if (strcmp(osToc->array[0], currOStoc->array[0]) == 0
&& strcmp(osToc->array[1], currOStoc->array[1]) == 0
&& (strcmp(osToc->array[2], "x") == 0 || strcmp(osToc->array[2], "X") == 0)) {
ret = true;
}
}
}
deallocMatchOSes(osToc);
deallocMatchOSes(currOStoc);
return ret;
}
int countOccurrences( char *s, char c )
{
return *s == '\0'
? 0
: countOccurrences( s + 1, c ) + (*s == c);
}
// End of MatchOS
//
// Micky1979
//
// Function to iterate the kernel.plist/kexts.plist (Acpi.plist?) and apply patches
//
void pach_binaryUsingDictionary(void *data,
UInt32 dataLen,
UInt32 StartLocation,
char *reason,
TagPtr config)
{
bool canPatch = false;
UInt8 *bytes = (UInt8 *)data;
intnumPatch, count;
numPatch = -1;
count = 0;
char * realReason;
TagPtrPatchTag = NULL;
if (!config) return;
/* coming soon..
if (!strcmp(reason, "AcpiPatches")) {
// on all the acpi tables
realReason = "Acpi";
}
else
if (!strcmp(reason, "DsdtPatches")) {
// only on dsdt
realReason = "Dsdt";
}
else
*/
if (!strcmp(reason, "KernelPatches")) {
realReason = "kernel";
}
else
{
realReason = reason;
}
if ((PatchTag = XMLCastArray(XMLGetProperty(config, (const char *)reason))))
{
count = XMLTagCount(PatchTag);
/* for (i=0; i<count; i++) normal */
for (unsigned i = count ; i-- > 0 ;) /* reversed iteration since xml.c add it reversed */
{
numPatch ++;
if (!bytes) {
verbose("\t Skipping patch for %s because no bytes to patch..\n", realReason);
return;
}
TagPtr index = XMLGetElement( PatchTag, i );
if (index)
{
char *Comment = NULL;
char *MatchOS = NULL;
char *MatchBuild = NULL;
char *MatchUUID = NULL;
int numPatches = 0;
TagPtr FindPtr = XMLGetProperty(index, (const char*)"Find");
TagPtr ReplacePtr = XMLGetProperty(index, (const char*)"Replace");
Comment = XMLCastString(XMLGetProperty(index, (const char*)"Comment"));
MatchOS = XMLCastString(XMLGetProperty(index, (const char*)"MatchOS"));
MatchBuild = XMLCastString(XMLGetProperty(index, (const char*)"MatchBuild"));
MatchUUID = XMLCastString(XMLGetProperty(index, (const char*)"MatchUUID"));
Comment = (Comment != NULL && strlen(Comment) >0) ? Comment : "untitled";
MatchOS = (MatchOS != NULL && strlen(MatchOS) >0) ? MatchOS : ""; // if lenght is 0 IsPatchEnabled() will not be called!
MatchBuild = (MatchBuild != NULL && strlen(MatchBuild) >0) ? MatchBuild : "";
MatchUUID = (MatchUUID != NULL && strlen(MatchUUID) >0) ? MatchUUID : "";
canPatch = true;
// the order is important to skip patches
if (strlen(MatchUUID))
{
// to be implemented
// check MatchUUID and disable this patch if does not match. Usefull to load or skip patches for certain volumes
// canPatch = IsPatchEnabled(MatchUUID, (char *)uuid_to_be_taken_somewhere);
}
else
{
MatchUUID = "not implemented";
}
if (strlen(MatchOS))
{
// check MatchOS and disable this patch if does not match
canPatch = IsPatchEnabled(MatchOS, (char *)gMacOSVersion);
}
else
{
MatchOS = "not set";
}
if (strlen(MatchBuild))
{
// check MatchBuild and disable this patch if does not match
canPatch = IsPatchEnabled(MatchBuild, (char *)gMacOSVersion);
}
else
{
MatchBuild = "not set";
}
char buf[1024];
sprintf(buf, "\tPatching %s [Item %d] (%s) MatchOS[ %s ] MatchBuild[ %s ]: ",
realReason, numPatch, Comment, MatchOS, MatchBuild);
verbose("%s", buf);
if (canPatch)
{
if (FindPtr && ReplacePtr)
{
if (!XMLIsData(FindPtr))
{
verbose("\n\t\t\tUser Error, Find not in data tag, patch skipped\n");
return;
}
if (!XMLIsData(ReplacePtr))
{
verbose("\n\t\t\tUser Error, Replace not in data tag, patch skipped\n");
return;
}
// don't allow patches with less than 2 bytes (it's ridiculous)
if (sizeof(FindPtr->data) <= 2)
{
verbose("\n\t\t\tUser Error, Find is less than 2 bytes (or less), patch skipped\n");
return;
}
if (sizeof(FindPtr->data) != sizeof(ReplacePtr->data))
{
verbose("\n\t\t\tUser Error, Find and Replace does not have the same length, patch skipped\n");
return;
}
if (sizeof(FindPtr->data) > (dataLen - StartLocation))
{
verbose("\n\t\t\tUser Error, Find is bigger than the hole data, patch skipped\n");
return;
}
}
else
{
verbose("\n\t\t\tUser Error, Find or Replace (or both) are missing, patch skipped\n");
return;
}
}
// patch it
if (canPatch) {
numPatches = FindAndReplace(data,
(UInt32)dataLen,
StartLocation,
FindPtr->data,
sizeof(FindPtr->data),
ReplacePtr->data,
0);
verbose("%d substitutions made!\n", numPatches);
}
else
{
verbose("disabled!\n");
}
}
}
}
}
branches/ErmaC/Enoch/i386/libsaio/binaryPatcher.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
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
//
// binaryPatcher.h
//
// binary patcher of any kinds (kexts, kernel, ACPI tables etc..)
//
//
#ifndef binaryPatcher_h
#define binaryPatcher_h
#include <string.h>
#include <stdbool.h>
#include <libkern/OSTypes.h>
#include "saio_types.h"
#include "libsaio.h"
#include "xml.h"
#include "bootargs.h"
#include "saio_types.h"
#include "bios.h"
#include "device_tree.h"
// Micky1979: Next five functions (+ needed struct) are to split a string like "10.10.5,10.7,10.11.6,10.8.x"
// in their components separated by comma (in this case)
struct MatchOSes {
int count;
char* array[100];
};
/** Returns a boolean and then enable disable the patch if MachOSEntry have a match for the booted OS. */
bool IsPatchEnabled(char *MatchOSEntry, char *CurrOS);
/** return true if a given os contains '.' as separator,
and then match components of the current booted OS. Also allow 10.10.x format meaning all revisions
of the 10.10 OS */
bool IsOSValid(char *MatchOS, char *CurrOS);
/** return MatchOSes struct (count+array) with the components of str that contains the given char sep as separator. */
struct MatchOSes *GetStrArraySeparatedByChar(char *str, char sep);
/** free MatchOSes struct and its array. */
void deallocMatchOSes(struct MatchOSes *s);
/** count occurrences of a given char in a char* string. */
int countOccurrences( char *s, char c );
unsigned int FindAndReplace(void *sourceData,
UInt32 SourceSize,
UInt32 StartLocation,
UInt8 *Search,
unsigned int SearchSize,
UInt8 *Replace,
int MaxReplaces);
unsigned int FindAndReplace(void *sourceData,
UInt32 SourceSize,
UInt32 StartLocation,
UInt8 *Search,
unsigned int SearchSize,
UInt8 *Replace,
int MaxReplaces);
/*
unsigned int FindAndCount(void *sourceData,
UInt32 SourceSize,
UInt8 *Search,
unsigned int SearchSize);
*/
void pach_binaryUsingDictionary(void *data,
UInt32 dataLen,
UInt32 StartLocation,
char *reason,
TagPtr config);
#endif /* binaryPatcher_h */
branches/ErmaC/Enoch/i386/boot2/boot.c
5656
5757
5858
59
5960
60
6161
6262
6363
#include "platform.h"
#include "modules.h"
#include "device_tree.h"
#include "xml.h"
#if DEBUG_BOOT2
#define DBG(x...)printf(x)
#else

Archive Download the corresponding diff file

Revision: 2870