Bug Summary

File:TinyInst/macOS/debugger.cpp
Warning:line 1765, column 3
MIG callback fails with error after deallocating argument value. This is a use-after-free vulnerability because the caller will try to deallocate it again

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-macosx14.2.0 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name debugger.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=osx -analyzer-checker=security.insecureAPI.decodeValueOfObjCType -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -funwind-tables=1 -target-sdk-version=14.2 -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -target-cpu apple-m1 -target-feature +v8.5a -target-feature +aes -target-feature +crc -target-feature +dotprod -target-feature +fp-armv8 -target-feature +fp16fml -target-feature +lse -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sha2 -target-feature +sha3 -target-feature +neon -target-feature +zcm -target-feature +zcz -target-feature +fullfp16 -target-abi darwinpcs -debugger-tuning=lldb -target-linker-version 1022.1 -fcoverage-compilation-dir=/Users/xss/tmp/Jackalope-main -resource-dir /opt/homebrew/Cellar/llvm/17.0.6_1/lib/clang/17 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk -D CMAKE_INTDIR="Debug" -D ARM64 -I /Users/xss/tmp/Jackalope-main/TinyInst/Debug/include -I /Users/xss/tmp/Jackalope-main/TinyInst/third_party/obj/wkit/include -I /Users/xss/tmp/Jackalope-main/TinyInst -I /Users/xss/tmp/Jackalope-main/TinyInst/third_party/reil -I /Users/xss/tmp/Jackalope-main/build/tinyinst.build/Debug/DerivedSources-normal/arm64 -I /Users/xss/tmp/Jackalope-main/build/tinyinst.build/Debug/DerivedSources/arm64 -I /Users/xss/tmp/Jackalope-main/build/tinyinst.build/Debug/DerivedSources -F/Users/xss/tmp/Jackalope-main/TinyInst/Debug -internal-isystem /opt/homebrew/Cellar/llvm/17.0.6_1/bin/../include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk/usr/local/include -internal-isystem /opt/homebrew/Cellar/llvm/17.0.6_1/lib/clang/17/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk/usr/include -O0 -Wno-trigraphs -Wno-missing-field-initializers -Wno-missing-prototypes -Wno-return-type -Wno-non-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wno-unused-variable -Wno-empty-body -Wno-uninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-constant-conversion -Wno-int-conversion -Wno-bool-conversion -Wno-enum-conversion -Wno-float-conversion -Wno-non-literal-null-conversion -Wno-objc-literal-conversion -Wno-newline-eof -Wno-c++11-extensions -Wno-implicit-fallthrough -Wno-sign-conversion -Wno-infinite-recursion -Wno-move -Wno-comma -Wno-block-capture-autoreleasing -Wno-strict-prototypes -Wno-range-loop-analysis -Wno-semicolon-before-method-body -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/Users/xss/tmp/Jackalope-main -ferror-limit 19 -fmacro-backtrace-limit=0 -fmessage-length=260 -stack-protector 1 -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -fpascal-strings -fmax-type-align=16 -fdiagnostics-show-note-include-stack -fcolor-diagnostics -analyzer-output=html -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /Users/xss/tmp/Jackalope-main/report/2024-02-26-100845-33878-1 -x c++ /Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp
1/*
2Copyright 2020 Google LLC
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8https ://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#include <cstdio>
18#include <cstdlib>
19#include <string>
20#include <thread>
21#include <algorithm>
22
23#include <mach/mach.h>
24#include <mach/mach_vm.h>
25
26#include <mach-o/dyld.h>
27#include <mach-o/dyld_images.h>
28#include <mach-o/nlist.h>
29
30#include <dlfcn.h>
31
32#include <spawn.h>
33#include <sys/types.h>
34#include <sys/ptrace.h>
35#include <signal.h>
36#include <fcntl.h>
37
38#include "macOS/debugger.h"
39#include "common.h"
40
41#define BREAKPOINT_UNKNOWN0x0 0x0
42#define BREAKPOINT_ENTRYPOINT0x01 0x01
43#define BREAKPOINT_TARGET0x02 0x02
44#define BREAKPOINT_NOTIFICATION0x04 0x04
45#define BREAKPOINT_TARGET_END0x08 0x08
46
47#define PERSIST_END_EXCEPTION0x0F22 0x0F22
48
49#ifndef _POSIX_SPAWN_DISABLE_ASLR0x0100
50 #define _POSIX_SPAWN_DISABLE_ASLR0x0100 0x0100
51#endif
52
53extern char **environ;
54
55std::unordered_map<task_t, class Debugger*> Debugger::task_to_debugger_map;
56std::mutex Debugger::map_mutex;
57
58vm_prot_t Debugger::MacOSProtectionFlags(MemoryProtection memory_protection) {
59 switch (memory_protection) {
60 case READONLY:
61 return VM_PROT_READ((vm_prot_t) 0x01);
62
63 case READWRITE:
64 return VM_PROT_READ((vm_prot_t) 0x01) | VM_PROT_WRITE((vm_prot_t) 0x02);
65
66 case READEXECUTE:
67 return VM_PROT_READ((vm_prot_t) 0x01) | VM_PROT_EXECUTE((vm_prot_t) 0x04);
68
69 case READWRITEEXECUTE:
70 return VM_PROT_ALL(((vm_prot_t) 0x01)|((vm_prot_t) 0x02)|((vm_prot_t) 0x04));
71
72 default:
73 FATAL("Unimplemented memory protection")do { printf("[-] PROGRAM ABORT : " "Unimplemented memory protection"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 73); exit(1); } while (0)
;
74 }
75}
76
77void Debugger::ClearSharedMemory() {
78 for (auto iter = shared_memory.begin(); iter != shared_memory.end(); ) {
79 iter = FreeSharedMemory(iter);
80 }
81
82 shared_memory.clear();
83}
84
85std::list<SharedMemory>::iterator Debugger::FreeSharedMemory(std::list<SharedMemory>::iterator it) {
86 if (it->size == 0) {
87 WARN("FreeShare is called with size == 0\n")do { printf("[!] WARNING: " "FreeShare is called with size == 0\n"
); printf("\n"); } while (0)
;
88 return ++it;
89 }
90
91 kern_return_t krt = mach_port_destroy(mach_task_self()mach_task_self_, it->port);
92 if (krt != KERN_SUCCESS0) {
93 FATAL("Error (%s) destroy port for local shared memory @ 0x%llx\n", mach_error_string(krt), it->local_address)do { printf("[-] PROGRAM ABORT : " "Error (%s) destroy port for local shared memory @ 0x%llx\n"
, mach_error_string(krt), it->local_address); printf(" Location : %s(), %s:%u\n\n"
, __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 93); exit(1); } while (0)
;
94 }
95
96 krt = mach_vm_deallocate(mach_task_self()mach_task_self_, it->local_address, it->size);
97 if (krt != KERN_SUCCESS0) {
98 FATAL("Error (%s) freeing memory @ 0x%llx\n", mach_error_string(krt), it->remote_address)do { printf("[-] PROGRAM ABORT : " "Error (%s) freeing memory @ 0x%llx\n"
, mach_error_string(krt), it->remote_address); printf(" Location : %s(), %s:%u\n\n"
, __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 98); exit(1); } while (0)
;
99 }
100
101 return shared_memory.erase(it);
102}
103
104void Debugger::RemoteFree(void *address, size_t size) {
105 for (auto iter = shared_memory.begin(); iter != shared_memory.end(); iter++) {
106 if (iter->remote_address == (mach_vm_address_t)address) {
107 FreeSharedMemory(iter);
108 break;
109 }
110 }
111 mach_target->FreeMemory((uint64_t)address, size);
112}
113
114void Debugger::RemoteRead(void *address, void *buffer, size_t size) {
115 mach_vm_address_t shared_memory_address = 0;
116 for (auto iter = shared_memory.begin(); iter != shared_memory.end(); ++iter) {
117 if (((mach_vm_address_t)address >= iter->remote_address) &&
118 (((mach_vm_address_t)address + size) <= (iter->remote_address + iter->size)))
119 {
120 shared_memory_address = iter->local_address + ((mach_vm_address_t)address - iter->remote_address);
121 break;
122 }
123 }
124
125 if (shared_memory_address) {
126 memcpy(buffer, (void *)shared_memory_address, size);
127 } else {
128 mach_target->ReadMemory((uint64_t)address, size, buffer);
129 }
130}
131
132void Debugger::RemoteWrite(void *address, const void *buffer, size_t size) {
133 mach_target->WriteMemory((uint64_t)address, buffer, size);
134}
135
136void Debugger::RemoteProtect(void *address, size_t size, MemoryProtection protect) {
137 RemoteProtect(address, size, MacOSProtectionFlags(protect));
138}
139
140void Debugger::RemoteProtect(void *address, size_t size, vm_prot_t protect) {
141 mach_target->ProtectMemory((uint64_t)address, size, protect);
142}
143
144void Debugger::CreateException(MachException *mach_exception, Exception *exception) {
145 exception->ip = (void*)GetRegister(ARCH_PCPC);
146
147 switch (mach_exception->exception_type) {
148 case EXC_BREAKPOINT6:
149 exception->type = BREAKPOINT;
150#ifdef ARM641
151 SetRegister(ARCH_PCPC, GetRegister(ARCH_PCPC) + 4);
152 exception->ip = (void*)((uint64_t)exception->ip);
153#else
154 exception->ip = (void*)((uint64_t)exception->ip - 1);
155#endif
156 break;
157
158 case EXC_BAD_ACCESS1:
159 exception->type = ACCESS_VIOLATION;
160 break;
161
162 case EXC_BAD_INSTRUCTION2:
163 exception->type = ILLEGAL_INSTRUCTION;
164 break;
165
166 default:
167 exception->type = OTHER;
168 break;
169 }
170
171 exception->maybe_execute_violation = false;
172 exception->maybe_write_violation = false;
173 exception->access_address = 0;
174
175 if (mach_exception->exception_type == EXC_BAD_ACCESS1) {
176 if (mach_exception->code[0] == KERN_PROTECTION_FAILURE2) {
177 exception->maybe_write_violation = true;
178 exception->maybe_execute_violation = true;
179 }
180
181 exception->access_address = (void*)mach_exception->code[1];
182 }
183}
184
185uint64_t* Debugger::GetPointerToRegister(Register r) {
186 ARCH_THREAD_STATE_Tarm_thread_state64_t *state = (ARCH_THREAD_STATE_Tarm_thread_state64_t*)(mach_exception->new_state);
187#ifdef ARM641
188 switch(r) {
189 case X0:
190 case X1:
191 case X2:
192 case X3:
193 case X4:
194 case X5:
195 case X6:
196 case X7:
197 case X8:
198 case X9:
199 case X10:
200 case X11:
201 case X12:
202 case X13:
203 case X14:
204 case X15:
205 case X16:
206 case X17:
207 case X18:
208 case X19:
209 case X20:
210 case X21:
211 case X22:
212 case X23:
213 case X24:
214 case X25:
215 case X26:
216 case X27:
217 case X28:
218 case X29:
219 return &state->__x[r];
220 case PC:
221 return &state->__pc;
222 case CPSR:
223 return (uint64_t*)&state->__cpsr;
224 case LR:
225 return &state->__lr;
226 case SP:
227 return &state->__sp;
228
229 default:
230 FATAL("Unimplemented register")do { printf("[-] PROGRAM ABORT : " "Unimplemented register");
printf(" Location : %s(), %s:%u\n\n", __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 230); exit(1); } while (0)
;
231 }
232#else
233 switch (r) {
234 case RAX:
235 return &state->__rax;
236 case RCX:
237 return &state->__rcx;
238 case RDX:
239 return &state->__rdx;
240 case RBX:
241 return &state->__rbx;
242 case RSP:
243 return &state->__rsp;
244 case RBP:
245 return &state->__rbp;
246 case RSI:
247 return &state->__rsi;
248 case RDI:
249 return &state->__rdi;
250 case R8:
251 return &state->__r8;
252 case R9:
253 return &state->__r9;
254 case R10:
255 return &state->__r10;
256 case R11:
257 return &state->__r11;
258 case R12:
259 return &state->__r12;
260 case R13:
261 return &state->__r13;
262 case R14:
263 return &state->__r14;
264 case R15:
265 return &state->__r15;
266 case RIP:
267 return &state->__rip;
268
269 default:
270 FATAL("Unimplemented register")do { printf("[-] PROGRAM ABORT : " "Unimplemented register");
printf(" Location : %s(), %s:%u\n\n", __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 270); exit(1); } while (0)
;
271 }
272#endif
273}
274
275size_t Debugger::GetRegister(Register r) {
276#ifdef ARM641
277 if (r == CPSR) {
278 uint32_t *reg_pointer = (uint32_t *)GetPointerToRegister(r);
279 return *reg_pointer;
280 }
281#endif
282 uint64_t *reg_pointer = GetPointerToRegister(r);
283 return *reg_pointer;
284}
285
286void Debugger::SetRegister(Register r, size_t value) {
287#ifdef ARM641
288 if (r == CPSR) {
289 if(value & 0xFFFFFFFF00000000) FATAL("32 bit value required")do { printf("[-] PROGRAM ABORT : " "32 bit value required"); printf
(" Location : %s(), %s:%u\n\n", __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 289); exit(1); } while (0)
;
290 uint32_t *reg_pointer = (uint32_t *)GetPointerToRegister(r);
291 *reg_pointer = (uint32_t)(value & 0xFFFFFFFF);
292 }
293#endif
294 uint64_t *reg_pointer = GetPointerToRegister(r);
295 *reg_pointer = value;
296}
297
298#ifdef ARM641
299Register Debugger::ArgumentToRegister(int arg) {
300 switch (arg) {
301 case 0:
302 return X0;
303
304 case 1:
305 return X1;
306
307 case 2:
308 return X2;
309
310 case 3:
311 return X3;
312
313 case 4:
314 return X4;
315
316 case 5:
317 return X5;
318
319 case 6:
320 return X6;
321
322 case 7:
323 return X7;
324
325 default:
326 FATAL("Argument %d not valid\n", arg)do { printf("[-] PROGRAM ABORT : " "Argument %d not valid\n",
arg); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 326); exit(1); } while (0)
;
327 break;
328 }
329}
330#else
331Register Debugger::ArgumentToRegister(int arg) {
332 switch (arg) {
333 case 0:
334 return RDI;
335
336 case 1:
337 return RSI;
338
339 case 2:
340 return RDX;
341
342 case 3:
343 return RCX;
344
345 case 4:
346 return R8;
347
348 case 5:
349 return R9;
350
351 default:
352 FATAL("Argument %d not valid\n", arg)do { printf("[-] PROGRAM ABORT : " "Argument %d not valid\n",
arg); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 352); exit(1); } while (0)
;
353 break;
354 }
355}
356#endif
357
358void Debugger::SetReturnAddress(size_t value) {
359#ifdef ARM641
360 SetRegister(LR, value);
361#else
362 RemoteWrite((void*)GetRegister(RSP), &value, child_ptr_size);
363#endif
364}
365
366size_t Debugger::GetReturnAddress() {
367#ifdef ARM641
368 return GetRegister(LR);
369#else
370 void *ra;
371 RemoteRead((void*)GetRegister(RSP), &ra, child_ptr_size);
372 return (size_t)ra;
373#endif
374}
375
376void Debugger::GetMachHeader(void *mach_header_address, mach_header_64 *mach_header) {
377 RemoteRead(mach_header_address, (void*)mach_header, sizeof(mach_header_64));
378}
379
380void Debugger::GetLoadCommandsBuffer(void *mach_header_address,
381 const mach_header_64 *mach_header,
382 void **load_commands) {
383 *load_commands = (void*)malloc(mach_header->sizeofcmds);
384 RemoteRead((void*)((uint64_t)mach_header_address + sizeof(mach_header_64)),
385 *load_commands,
386 mach_header->sizeofcmds);
387}
388
389template <class TCMD>
390bool Debugger::GetLoadCommand(mach_header_64 mach_header,
391 void *load_commands_buffer,
392 uint32_t load_cmd_type,
393 const char *segname,
394 TCMD **ret_command) {
395 uint64_t load_cmd_addr = (uint64_t)load_commands_buffer;
396 for (uint32_t i = 0; i < mach_header.ncmds; ++i) {
397 load_command *load_cmd = (load_command *)load_cmd_addr;
398 if (load_cmd->cmd == load_cmd_type) {
399 TCMD *t_cmd = (TCMD*)load_cmd;
400 if (load_cmd_type != LC_SEGMENT_640x19
401 || !strcmp(((segment_command_64*)t_cmd)->segname, segname)) {
402 *ret_command = (TCMD*)load_cmd;
403 return true;
404 }
405 }
406
407 load_cmd_addr += load_cmd->cmdsize;
408 }
409
410 return false;
411}
412
413
414bool Debugger::GetSectionAndSlide(void *mach_header_address,
415 const char *segname,
416 const char *sectname,
417 section_64 *ret_section,
418 size_t *file_vm_slide) {
419 mach_header_64 mach_header;
420 GetMachHeader(mach_header_address, &mach_header);
421
422 void *load_commands_buffer = NULL__null;
423 GetLoadCommandsBuffer(mach_header_address, &mach_header, &load_commands_buffer);
424
425 segment_command_64 *text_cmd = NULL__null;
426 if (!GetLoadCommand(mach_header, load_commands_buffer, LC_SEGMENT_640x19, "__TEXT", &text_cmd)) {
427 FATAL("Unable to find __TEXT command in GetSectionAndSlide\n")do { printf("[-] PROGRAM ABORT : " "Unable to find __TEXT command in GetSectionAndSlide\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 427); exit(1); } while (0)
;
428 }
429 *file_vm_slide = (size_t)mach_header_address - text_cmd->vmaddr;
430
431 segment_command_64 *seg_cmd = NULL__null;
432 if (!GetLoadCommand(mach_header, load_commands_buffer, LC_SEGMENT_640x19, segname, &seg_cmd)) {
433 return false;
434 }
435
436 bool found_section = false;
437 size_t section_addr = (size_t)seg_cmd + sizeof(segment_command_64);
438 for (uint32_t i = 0; i < seg_cmd->nsects && !found_section; ++i) {
439 section_64 *section = (section_64*)section_addr;
440 if (!strcmp(section->sectname, sectname)) {
441 *ret_section = *section;
442 found_section = true;
443 }
444
445 section_addr += sizeof(section_64);
446 }
447
448 free(load_commands_buffer);
449 return found_section;
450}
451
452void *Debugger::MakeSharedMemory(mach_vm_address_t address, size_t size, MemoryProtection protection) {
453 mach_port_t shm_port;
454 if (address == 0)
455 return NULL__null;
456
457 memory_object_size_t memoryObjectSize = round_page(size)(((size) + (vm_page_size - 1)) & (~(vm_page_size - 1)));
458 vm_prot_t prot_flags = MacOSProtectionFlags(protection);
459 kern_return_t ret = mach_make_memory_entry_64(mach_target->Task(), &memoryObjectSize, address, prot_flags, &shm_port, MACH_PORT_NULL0);
460 if (ret != KERN_SUCCESS0) {
461 FATAL("Error (%s) remote allocate share memory\n", mach_error_string(ret))do { printf("[-] PROGRAM ABORT : " "Error (%s) remote allocate share memory\n"
, mach_error_string(ret)); printf(" Location : %s(), %s:%u\n\n"
, __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 461); exit(1); } while (0)
;
462 }
463
464 mach_vm_address_t map_address = 0;
465 ret = mach_vm_map(mach_task_self()mach_task_self_, &map_address, memoryObjectSize, 0, VM_FLAGS_ANYWHERE0x00000001, shm_port, 0, 0, prot_flags, prot_flags, VM_INHERIT_NONE((vm_inherit_t) 2));
466 if (ret != KERN_SUCCESS0) {
467 FATAL("Error (%s) map memory\n", mach_error_string(ret))do { printf("[-] PROGRAM ABORT : " "Error (%s) map memory\n",
mach_error_string(ret)); printf(" Location : %s(), %s:%u\n\n"
, __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 467); exit(1); } while (0)
;
468 }
469
470 SharedMemory sm(map_address, address, size, shm_port);
471 shared_memory.push_back(sm);
472
473 return (void *)map_address;
474}
475
476void *Debugger::RemoteAllocateNear(uint64_t region_min,
477 uint64_t region_max,
478 size_t size,
479 MemoryProtection protection,
480 bool use_shared_memory) {
481 uint64_t min_address, max_address;
482
483 //try after first
484 min_address = region_max;
485 max_address = (UINT64_MAX18446744073709551615ULL - region_min < 0x80000000) ? UINT64_MAX18446744073709551615ULL : region_min + 0x80000000;
486 void *ret_address = RemoteAllocateAfter(min_address, max_address, size, protection);
487 if (ret_address != NULL__null) {
488 if (use_shared_memory)
489 MakeSharedMemory((mach_vm_address_t)ret_address, size, protection);
490 return ret_address;
491 }
492
493 //try before second
494 min_address = (region_max < 0x80000000) ? 0 : region_max - 0x80000000;
495 max_address = (region_min < size) ? 0 : region_min - size;
496 ret_address = RemoteAllocateBefore(min_address, max_address, size, protection);
497 if (ret_address != NULL__null) {
498 if (use_shared_memory)
499 MakeSharedMemory((mach_vm_address_t)ret_address, size, protection);
500 return ret_address;
501 }
502
503 // if all else fails, try within
504 ret_address = RemoteAllocateAfter(region_min, region_max, size, protection);
505 if (use_shared_memory)
506 MakeSharedMemory((mach_vm_address_t)ret_address, size, protection);
507 return ret_address;
508}
509
510void *Debugger::RemoteAllocate(size_t size,
511 MemoryProtection protection,
512 bool use_shared_memory) {
513 mach_vm_address_t alloc_address = 0;
514 vm_prot_t protection_flags = MacOSProtectionFlags(protection);
515
516 kern_return_t krt = mach_vm_allocate(mach_target->Task(),
517 (mach_vm_address_t*)&alloc_address,
518 size,
519 VM_FLAGS_ANYWHERE0x00000001);
520
521 if (krt != KERN_SUCCESS0) {
522 FATAL("Unable to allocate memory, size 0x%lx\n", size)do { printf("[-] PROGRAM ABORT : " "Unable to allocate memory, size 0x%lx\n"
, size); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 522); exit(1); } while (0)
;
523 }
524 RemoteProtect((void *)alloc_address, size, protection_flags);
525
526 if (use_shared_memory) {
527 MakeSharedMemory(alloc_address, size, protection);
528 }
529
530 return (void *)alloc_address;
531}
532
533void *Debugger::RemoteAllocateBefore(uint64_t min_address,
534 uint64_t max_address,
535 size_t size,
536 MemoryProtection protection) {
537 vm_prot_t protection_flags = MacOSProtectionFlags(protection);
538
539 mach_vm_address_t cur_address = max_address;
540 while (cur_address > min_address) {
541 size_t step = size;
542
543 mach_vm_address_t region_address = cur_address;
544 mach_vm_size_t region_size = 0;
545 vm_region_submap_info_data_64_t info;
546 mach_target->GetRegionSubmapInfo(&region_address, &region_size, &info);
547
548 if (region_address <= cur_address) { /* cur_address references allocated memory */
549 cur_address = region_address;
550 } else { /* cur_address references unallocated memory */
551 uint64_t free_region_size = region_address - cur_address;
552 if (free_region_size >= size) {
553 void *ret_address = (void*)(cur_address + (free_region_size - size));
554 kern_return_t krt = RemoteAllocateAt(ret_address, size);
555
556 if (krt == KERN_SUCCESS0) {
557 if (!(min_address <= (uint64_t)ret_address && (uint64_t)ret_address <= max_address)) {
558 return NULL__null;
559 }
560
561 RemoteProtect(ret_address, size, protection_flags);
562 return ret_address;
563 }
564 } else {
565 step = size - free_region_size;
566 }
567 }
568
569 if (cur_address < step) break;
570 cur_address -= step;
571 }
572
573 return NULL__null;
574}
575
576void *Debugger::RemoteAllocateAfter(uint64_t min_address,
577 uint64_t max_address,
578 size_t size,
579 MemoryProtection protection) {
580 vm_prot_t protection_flags = MacOSProtectionFlags(protection);
581
582 mach_vm_address_t cur_address = min_address;
583 while (cur_address < max_address) {
584 mach_vm_address_t region_address = cur_address;
585 mach_vm_size_t region_size = 0;
586 vm_region_submap_info_data_64_t info;
587 mach_target->GetRegionSubmapInfo(&region_address, &region_size, &info);
588
589 if (region_address <= cur_address) { /* cur_address references allocated memory */
590 cur_address = region_address + region_size;
591 continue;
592 }
593
594 /* cur_address references unallocated memory */
595 if (region_address > max_address) {
596 region_address = max_address;
597 }
598
599 uint64_t free_region_size = region_address - cur_address;
600 if (free_region_size >= size) {
601 void *ret_address = (void*)cur_address;
602 kern_return_t krt = RemoteAllocateAt(ret_address, size);
603
604 if (krt == KERN_SUCCESS0) {
605 if (!(min_address <= (uint64_t)ret_address && (uint64_t)ret_address <= max_address)) {
606 return NULL__null;
607 }
608
609 RemoteProtect(ret_address, size, protection_flags);
610 return ret_address;
611 }
612 }
613
614 cur_address = region_address;
615 }
616
617 return NULL__null;
618}
619
620void *Debugger::RemoteAllocate(size_t size) {
621 kern_return_t krt;
622 void *alloc_address = 0;
623 krt = mach_vm_allocate(mach_target->Task(),
624 (mach_vm_address_t*)&alloc_address,
625 size,
626 VM_FLAGS_ANYWHERE0x00000001);
627
628 if (krt != KERN_SUCCESS0) {
629 return NULL__null;
630 }
631
632 return alloc_address;
633}
634
635kern_return_t Debugger::RemoteAllocateAt(void *ret_address, int size) {
636 kern_return_t krt;
637 bool retried = false;
638
639retry_label:
640 void *alloc_address = ret_address;
641 krt = mach_vm_allocate(mach_target->Task(),
642 (mach_vm_address_t*)&alloc_address,
643 size,
644 VM_FLAGS_FIXED0x00000000);
645
646 if (krt == KERN_NO_SPACE3 && !retried) {
647 krt = mach_vm_deallocate(mach_target->Task(),
648 (mach_vm_address_t)ret_address,
649 size);
650 if (krt != KERN_SUCCESS0) {
651 FATAL("Unable to deallocate memory region starting @ %p, size 0x%x\n",do { printf("[-] PROGRAM ABORT : " "Unable to deallocate memory region starting @ %p, size 0x%x\n"
, ret_address, size); printf(" Location : %s(), %s:%u\n\n"
, __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 652); exit(1); } while (0)
652 ret_address, size)do { printf("[-] PROGRAM ABORT : " "Unable to deallocate memory region starting @ %p, size 0x%x\n"
, ret_address, size); printf(" Location : %s(), %s:%u\n\n"
, __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 652); exit(1); } while (0)
;
653 }
654
655 retried = true;
656 goto retry_label;
657 }
658
659 return krt;
660}
661
662void Debugger::DeleteBreakpoints() {
663 for (auto iter = breakpoints.begin(); iter != breakpoints.end(); iter++) {
664 delete *iter;
665 }
666 breakpoints.clear();
667}
668
669
670void Debugger::AddBreakpoint(void *address, int type) {
671 for (auto it = breakpoints.rbegin(); it != breakpoints.rend(); ++it) {
672 if ((*it)->address == address) {
673 (*it)->type |= type;
674 if (((*it)->type & BREAKPOINT_NOTIFICATION0x04) && ((*it)->type & BREAKPOINT_TARGET0x02)) {
675 FATAL("Target method must not be the same as _dyld_debugger_notification")do { printf("[-] PROGRAM ABORT : " "Target method must not be the same as _dyld_debugger_notification"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 675); exit(1); } while (0)
;
676 }
677
678 return;
679 }
680 }
681
682 Breakpoint *new_breakpoint = new Breakpoint;
683#ifdef ARM641
684 uint32_t breakpoint_bytes = 0xd4200020;
685#else
686 unsigned char breakpoint_bytes = 0xcc;
687#endif
688 RemoteRead(address, &(new_breakpoint->original_opcode), sizeof(new_breakpoint->original_opcode));
689 RemoteWrite(address, (void*)&breakpoint_bytes, sizeof(breakpoint_bytes));
690
691 new_breakpoint->address = address;
692 new_breakpoint->type = type;
693 breakpoints.push_back(new_breakpoint);
694}
695
696void Debugger::GetFunctionArguments(uint64_t *arguments, size_t num_arguments, uint64_t sp, CallingConvention callconv) {
697 for (int arg_index = 0; arg_index < MAX_NUM_REG_ARGS8 && arg_index < num_arguments; ++arg_index) {
698 arguments[arg_index] = GetRegister(ArgumentToRegister(arg_index));
699 }
700
701 if (num_arguments > MAX_NUM_REG_ARGS8) {
702 RemoteRead((void*)((uint64_t)sp + child_ptr_size),
703 arguments + MAX_NUM_REG_ARGS8,
704 child_ptr_size * (num_arguments - MAX_NUM_REG_ARGS8));
705 }
706}
707
708void Debugger::SetFunctionArguments(uint64_t *arguments, size_t num_arguments, uint64_t sp, CallingConvention callconv) {
709 for (int arg_index = 0; arg_index < MAX_NUM_REG_ARGS8 && arg_index < num_arguments; ++arg_index) {
710 SetRegister(ArgumentToRegister(arg_index), arguments[arg_index]);
711 }
712
713 if (num_arguments > MAX_NUM_REG_ARGS8) {
714 RemoteWrite((void*)((uint64_t)sp + child_ptr_size),
715 arguments + MAX_NUM_REG_ARGS8,
716 child_ptr_size * (num_arguments - MAX_NUM_REG_ARGS8));
717 }
718}
719
720void Debugger::HandleTargetReachedInternal() {
721 saved_sp = (void*)GetRegister(ARCH_SPSP);
722 saved_return_address = (void*)GetReturnAddress();
723
724 if (loop_mode) {
725 GetFunctionArguments((uint64_t *)saved_args, target_num_args, (uint64_t)saved_sp, CALLCONV_DEFAULT);
726 }
727
728 if (!target_reached) {
729 target_reached = true;
730 OnTargetMethodReached();
731 }
732
733 if (target_end_detection == RETADDR_STACK_OVERWRITE) {
734 size_t return_address = PERSIST_END_EXCEPTION0x0F22;
735 RemoteWrite(saved_sp, &return_address, child_ptr_size);
736 } else if (target_end_detection == RETADDR_BREAKPOINT) {
737 AddBreakpoint((void*)GetTranslatedAddress((size_t)saved_return_address), BREAKPOINT_TARGET_END0x08);
738 }
739}
740
741
742void Debugger::HandleTargetEnded() {
743 target_return_value = (uint64_t)GetRegister(ARCH_RETURN_VALUE_REGISTERX0);
744
745 if (loop_mode) {
746 SetRegister(ARCH_PCPC, (size_t)target_address);
747 SetRegister(ARCH_SPSP, (size_t)saved_sp);
748
749 if (target_end_detection == RETADDR_STACK_OVERWRITE) {
750 size_t return_address = PERSIST_END_EXCEPTION0x0F22;
751 SetReturnAddress(return_address);
752 } else if (target_end_detection == RETADDR_BREAKPOINT) {
753 SetReturnAddress((size_t)saved_return_address);
754 AddBreakpoint((void*)GetTranslatedAddress((size_t)saved_return_address), BREAKPOINT_TARGET_END0x08);
755 }
756
757 SetFunctionArguments((uint64_t *)saved_args, target_num_args, (uint64_t)saved_sp, CALLCONV_DEFAULT);
758 } else {
759 SetRegister(ARCH_PCPC, (size_t)saved_return_address);
760 AddBreakpoint((void*)GetTranslatedAddress((size_t)target_address), BREAKPOINT_TARGET0x02);
761 }
762}
763
764void Debugger::OnEntrypoint() {
765 child_entrypoint_reached = true;
766 if (trace_debug_events) {
767 SAY("Debugger: Process entrypoint reached\n")printf("Debugger: Process entrypoint reached\n");
768 }
769}
770
771
772void Debugger::ExtractCodeRanges(void *base_address,
773 size_t min_address,
774 size_t max_address,
775 std::list<AddressRange> *executable_ranges,
776 size_t *code_size) {
777 mach_header_64 mach_header;
778 GetMachHeader(base_address, &mach_header);
779
780 void *load_commands_buffer = NULL__null;
781 GetLoadCommandsBuffer(base_address, &mach_header, &load_commands_buffer);
782
783 segment_command_64 *text_cmd = NULL__null;
784 if (!GetLoadCommand(mach_header, load_commands_buffer, LC_SEGMENT_640x19, "__TEXT", &text_cmd)) {
785 FATAL("Unable to find __TEXT command in ExtractCodeRanges\n")do { printf("[-] PROGRAM ABORT : " "Unable to find __TEXT command in ExtractCodeRanges\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 785); exit(1); } while (0)
;
786 }
787 uint64_t file_vm_slide = (uint64_t)base_address - text_cmd->vmaddr;
788
789 *code_size = 0;
790 for (auto &it: *executable_ranges) {
791 free(it.data);
792 }
793 executable_ranges->clear();
794
795 uint64_t load_cmd_addr = (uint64_t)load_commands_buffer;
796 for (uint32_t i = 0; i < mach_header.ncmds; ++i) {
797 load_command *load_cmd = (load_command *)load_cmd_addr;
798 if (load_cmd->cmd == LC_SEGMENT_640x19) {
799 segment_command_64 *segment_cmd = (segment_command_64*)load_cmd;
800
801 if (!strcmp(segment_cmd->segname, "__PAGEZERO")
802 || !strcmp(segment_cmd->segname, "__LINKEDIT")) {
803 load_cmd_addr += load_cmd->cmdsize;
804 continue;
805 }
806
807#ifdef ARM641
808 if (strcmp(segment_cmd->segname, "__TEXT") == 0) {
809 mach_vm_address_t segment_start_addr = (mach_vm_address_t)segment_cmd->vmaddr + file_vm_slide;
810 mach_vm_address_t segment_end_addr = (mach_vm_address_t)segment_cmd->vmaddr + file_vm_slide + segment_cmd->vmsize;
811 AddressRange arm_ar;
812 arm_ar.from = segment_start_addr;
813 arm_ar.to = segment_end_addr;
814 size_t range_size = arm_ar.to - arm_ar.from;
815 arm_ar.data = (char *)malloc(range_size);
816 RemoteRead((void*)arm_ar.from, arm_ar.data, range_size);
817
818 ExtractSegmentCodeRanges(segment_start_addr, segment_end_addr, executable_ranges, code_size);
819 for(const auto& er: *executable_ranges) {
820 free(er.data);
821 }
822 executable_ranges->clear();
823 executable_ranges->push_back(arm_ar);
824 *code_size = range_size;
825 break;
826 }
827#else
828 mach_vm_address_t segment_start_addr = (mach_vm_address_t)segment_cmd->vmaddr + file_vm_slide;
829 mach_vm_address_t segment_end_addr = (mach_vm_address_t)segment_cmd->vmaddr + file_vm_slide + segment_cmd->vmsize;
830
831 ExtractSegmentCodeRanges(segment_start_addr, segment_end_addr, executable_ranges, code_size);
832#endif
833 }
834
835 load_cmd_addr += load_cmd->cmdsize;
836 }
837
838 free(load_commands_buffer);
839}
840
841void Debugger::ExtractSegmentCodeRanges(mach_vm_address_t segment_start_addr,
842 mach_vm_address_t segment_end_addr,
843 std::list<AddressRange> *executable_ranges,
844 size_t *code_size) {
845 mach_vm_address_t cur_address = segment_start_addr;
846 while (cur_address < segment_end_addr) {
847 mach_vm_size_t region_size = 0;
848 vm_region_submap_info_data_64_t info;
849 mach_target->GetRegionSubmapInfo(&cur_address, &region_size, &info);
850 if (segment_end_addr <= cur_address) {
851 break;
852 }
853
854 AddressRange new_range;
855 new_range.from = cur_address;
856 new_range.to = cur_address + region_size;
857 if (new_range.from < segment_start_addr) {
858 new_range.from = segment_start_addr;
859 }
860 if (segment_end_addr < new_range.to) {
861 new_range.to = segment_end_addr;
862 }
863
864 if (info.protection & VM_PROT_EXECUTE((vm_prot_t) 0x04)) {
865 int retried = false;
866
867 size_t range_size = new_range.to - new_range.from;
868 new_range.data = (char *)malloc(range_size);
869 RemoteRead((void*)new_range.from, new_range.data, range_size);
870
871 retry_label:
872 RemoteProtect((void*)new_range.from, range_size, info.protection ^ VM_PROT_EXECUTE((vm_prot_t) 0x04));
873 mach_vm_address_t region_addr = new_range.from;
874 mach_vm_size_t region_sz = range_size;
875 vm_region_submap_info_data_64_t region_info;
876 mach_target->GetRegionSubmapInfo(&region_addr, (mach_vm_size_t*)&region_sz, &region_info);
877 if (region_info.protection & VM_PROT_EXECUTE((vm_prot_t) 0x04)) {
878 if (retried) {
879 FATAL("Failed to mark the original code NON-EXECUTABLE\n")do { printf("[-] PROGRAM ABORT : " "Failed to mark the original code NON-EXECUTABLE\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 879); exit(1); } while (0)
;
880 }
881
882 kern_return_t krt;
883 krt = mach_vm_deallocate(mach_target->Task(),
884 (mach_vm_address_t)new_range.from,
885 range_size);
886
887 if (krt == KERN_SUCCESS0) {
888 mach_vm_address_t alloc_address = new_range.from;
889 krt = mach_vm_allocate(mach_target->Task(),
890 (mach_vm_address_t*)&alloc_address,
891 range_size,
892 VM_FLAGS_FIXED0x00000000);
893
894 if (krt == KERN_SUCCESS0 && alloc_address && new_range.from) {
895 RemoteWrite((void*)new_range.from, new_range.data, range_size);
896 } else {
897 FATAL("Unable to re-allocate memory after deallocate in ExtractSegmentCodeRanges\n")do { printf("[-] PROGRAM ABORT : " "Unable to re-allocate memory after deallocate in ExtractSegmentCodeRanges\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 897); exit(1); } while (0)
;
898 }
899 }
900
901 retried = true;
902 goto retry_label;
903 }
904
905 AddressRange *last_range = NULL__null;
906 if(!executable_ranges->empty()) {
907 last_range = &executable_ranges->back();
908 }
909 if(last_range && (last_range->to == new_range.from)) {
910 // merge ranges instead of creating new one
911 size_t last_range_size = last_range->to - last_range->from;
912 size_t merged_size = last_range_size + range_size;
913 last_range->data = (char *)realloc(last_range->data, merged_size);
914 memcpy(last_range->data + last_range_size, new_range.data, range_size);
915 last_range->to = new_range.to;
916 free(new_range.data);
917 } else {
918 executable_ranges->push_back(new_range);
919 }
920 *code_size += range_size;
921 }
922
923 cur_address += region_size;
924 }
925}
926
927
928void Debugger::ProtectCodeRanges(std::list<AddressRange> *executable_ranges) {
929 WARN("persist_instrumentation_data functionality was not tested on macOS."do { printf("[!] WARNING: " "persist_instrumentation_data functionality was not tested on macOS."
"ProtectCodeRanges might fail"); printf("\n"); } while (0)
930 "ProtectCodeRanges might fail")do { printf("[!] WARNING: " "persist_instrumentation_data functionality was not tested on macOS."
"ProtectCodeRanges might fail"); printf("\n"); } while (0)
;
931
932 for (auto &range: *executable_ranges) {
933 mach_vm_address_t region_address = range.from;
934 mach_vm_size_t region_size = 0;
935 vm_region_submap_info_data_64_t info;
936 mach_target->GetRegionSubmapInfo(&region_address, &region_size, &info);
937
938 if (region_address != range.from
939 || region_address + region_size != range.to
940 || !(info.protection & VM_PROT_EXECUTE((vm_prot_t) 0x04))) {
941 FATAL("Error in ProtectCodeRanges. Target incompatible with persist_instrumentation_data")do { printf("[-] PROGRAM ABORT : " "Error in ProtectCodeRanges. Target incompatible with persist_instrumentation_data"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 941); exit(1); } while (0)
;
942 }
943
944 RemoteProtect((void*)region_address, region_size, info.protection ^ VM_PROT_EXECUTE((vm_prot_t) 0x04));
945 }
946}
947
948void Debugger::PatchPointersRemote(void *base_address, std::unordered_map<size_t, size_t>& search_replace) {
949 mach_header_64 mach_header;
950 GetMachHeader(base_address, &mach_header);
951
952 void *load_commands_buffer = NULL__null;
953 GetLoadCommandsBuffer(base_address, &mach_header, &load_commands_buffer);
954
955 segment_command_64 *text_cmd = NULL__null;
956 if (!GetLoadCommand(mach_header, load_commands_buffer, LC_SEGMENT_640x19, "__TEXT", &text_cmd)) {
957 FATAL("Unable to find __TEXT command in ExtractCodeRanges\n")do { printf("[-] PROGRAM ABORT : " "Unable to find __TEXT command in ExtractCodeRanges\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 957); exit(1); } while (0)
;
958 }
959 uint64_t file_vm_slide = (uint64_t)base_address - text_cmd->vmaddr;
960
961 uint64_t load_cmd_addr = (uint64_t)load_commands_buffer;
962 for (uint32_t i = 0; i < mach_header.ncmds; ++i) {
963 load_command *load_cmd = (load_command *)load_cmd_addr;
964 if (load_cmd->cmd == LC_SEGMENT_640x19) {
965 segment_command_64 *segment_cmd = (segment_command_64*)load_cmd;
966
967 if (!strcmp(segment_cmd->segname, "__PAGEZERO")
968 || !strcmp(segment_cmd->segname, "__LINKEDIT")) {
969 load_cmd_addr += load_cmd->cmdsize;
970 continue;
971 }
972
973 mach_vm_address_t segment_start_addr = (mach_vm_address_t)segment_cmd->vmaddr + file_vm_slide;
974 mach_vm_address_t segment_end_addr = (mach_vm_address_t)segment_cmd->vmaddr + file_vm_slide + segment_cmd->vmsize;
975
976 PatchPointersRemote(segment_start_addr, segment_end_addr, search_replace);
977 }
978
979 load_cmd_addr += load_cmd->cmdsize;
980 }
981
982 free(load_commands_buffer);
983}
984
985void Debugger::PatchPointersRemote(size_t min_address, size_t max_address, std::unordered_map<size_t, size_t>& search_replace) {
986 size_t module_size = max_address - min_address;
987 char* buf = (char *)malloc(module_size);
988 RemoteRead((void *)min_address, buf, module_size);
989
990 size_t remote_address = min_address;
991 for (size_t i = 0; i < (module_size - child_ptr_size + 1); i++) {
992 size_t ptr = *(size_t *)(buf + i);
993 auto iter = search_replace.find(ptr);
994 if (iter != search_replace.end()) {
995 // printf("patching entry %zx at address %zx\n", (size_t)ptr, remote_address);
996 size_t fixed_ptr = (size_t)iter->second;
997 RemoteWrite((void *)remote_address, &fixed_ptr, child_ptr_size);
998 }
999 remote_address += 1;
1000 }
1001
1002 free(buf);
1003}
1004
1005
1006void Debugger::GetImageSize(void *base_address, size_t *min_address, size_t *max_address) {
1007 mach_header_64 mach_header;
1008 GetMachHeader(base_address, &mach_header);
1009
1010 void *load_commands_buffer = NULL__null;
1011 GetLoadCommandsBuffer(base_address, &mach_header, &load_commands_buffer);
1012
1013 *min_address = SIZE_MAX18446744073709551615UL;
1014 *max_address = 0;
1015
1016 uint64_t load_cmd_addr = (uint64_t)load_commands_buffer;
1017 for (uint32_t i = 0; i < mach_header.ncmds; ++i) {
1018 load_command *load_cmd = (load_command *)load_cmd_addr;
1019 if (load_cmd->cmd == LC_SEGMENT_640x19) {
1020 segment_command_64 *segment_cmd = (segment_command_64*)load_cmd;
1021
1022 if (!strcmp(segment_cmd->segname, "__PAGEZERO")
1023 || !strcmp(segment_cmd->segname, "__LINKEDIT")) {
1024 load_cmd_addr += load_cmd->cmdsize;
1025 continue;
1026 }
1027
1028 if (segment_cmd->vmaddr < *min_address) {
1029 *min_address = segment_cmd->vmaddr;
1030 }
1031
1032 if (segment_cmd->vmaddr + segment_cmd->vmsize > *max_address) {
1033 *max_address = segment_cmd->vmaddr + segment_cmd->vmsize;
1034 }
1035 }
1036
1037 load_cmd_addr += load_cmd->cmdsize;
1038 }
1039
1040 segment_command_64 *text_cmd = NULL__null;
1041 if (!GetLoadCommand(mach_header, load_commands_buffer, LC_SEGMENT_640x19, "__TEXT", &text_cmd)) {
1042 FATAL("Unable to find __TEXT command in GetImageSize\n")do { printf("[-] PROGRAM ABORT : " "Unable to find __TEXT command in GetImageSize\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1042); exit(1); } while (0)
;
1043 }
1044
1045 uint64_t file_vm_slide = (uint64_t)base_address - text_cmd->vmaddr;
1046 *min_address += file_vm_slide;
1047 *max_address += file_vm_slide;
1048
1049 free(load_commands_buffer);
1050}
1051
1052
1053void *Debugger::GetModuleEntrypoint(void *base_address) {
1054 mach_header_64 mach_header;
1055 GetMachHeader(base_address, &mach_header);
1056 if (mach_header.filetype != MH_EXECUTE0x2) {
1057 return NULL__null;
1058 }
1059
1060 void *load_commands_buffer = NULL__null;
1061 GetLoadCommandsBuffer(base_address, &mach_header, &load_commands_buffer);
1062
1063 entry_point_command *entry_point_cmd = NULL__null;
1064 if (GetLoadCommand(mach_header, load_commands_buffer, LC_MAIN(0x28|0x80000000), NULL__null, &entry_point_cmd)) {
1065 uint64_t entryoff = entry_point_cmd->entryoff;
1066
1067 free(load_commands_buffer);
1068 return (void*)((uint64_t)base_address + entryoff);
1069 }
1070
1071 // no LC_MAIN command, probably an older binary.
1072 // Look up LC_UNIXTHREAD instead
1073
1074 thread_command *tc;
1075 if (!GetLoadCommand(mach_header, load_commands_buffer, LC_UNIXTHREAD0x5, NULL__null, &tc)) {
1076 FATAL("Unable to find entry point in the executable module")do { printf("[-] PROGRAM ABORT : " "Unable to find entry point in the executable module"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1076); exit(1); } while (0)
;
1077 }
1078
1079 uint32_t flavor = *(uint32_t *)((char *)tc + 2 * sizeof(uint32_t));
1080 if(flavor != ARCH_THREAD_STATE6) {
1081 FATAL("Unexpected thread state flavor")do { printf("[-] PROGRAM ABORT : " "Unexpected thread state flavor"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1081); exit(1); } while (0)
;
1082 }
1083 ARCH_THREAD_STATE_Tarm_thread_state64_t *state = (ARCH_THREAD_STATE_Tarm_thread_state64_t *)((char *)tc + 4 * sizeof(uint32_t));
1084
1085 segment_command_64 *text_cmd = NULL__null;
1086 if (!GetLoadCommand(mach_header, load_commands_buffer, LC_SEGMENT_640x19, "__TEXT", &text_cmd)) {
1087 FATAL("Unable to find __TEXT command in GetModuleEntrypoint\n")do { printf("[-] PROGRAM ABORT : " "Unable to find __TEXT command in GetModuleEntrypoint\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1087); exit(1); } while (0)
;
1088 }
1089 uint64_t file_vm_slide = (uint64_t)base_address - text_cmd->vmaddr;
1090
1091 free(load_commands_buffer);
1092#ifdef ARM641
1093 return (void*)(state->__pc + file_vm_slide);
1094#else
1095 return (void*)(state->__rip + file_vm_slide);
1096#endif
1097}
1098
1099bool Debugger::IsDyld(void *base_address) {
1100 mach_header_64 mach_header;
1101 GetMachHeader(base_address, &mach_header);
1102
1103 return (mach_header.filetype == MH_DYLINKER0x7);
1104}
1105
1106
1107void *Debugger::GetSymbolAddress(void *base_address, const char *symbol_name) {
1108 mach_header_64 mach_header;
1109 GetMachHeader(base_address, &mach_header);
1110 bool in_shared_cache = (mach_header.filetype == MH_DYLIB0x6)
1111 && (mach_header.flags & MH_DYLIB_IN_CACHE0x80000000);
1112
1113 void *load_commands_buffer = NULL__null;
1114 GetLoadCommandsBuffer(base_address, &mach_header, &load_commands_buffer);
1115
1116 symtab_command *symtab_cmd = NULL__null;
1117 if (!GetLoadCommand(mach_header, load_commands_buffer, LC_SYMTAB0x2, NULL__null, &symtab_cmd)) {
1118 FATAL("Unable to find SYMTAB command in GetSymbolAddress\n")do { printf("[-] PROGRAM ABORT : " "Unable to find SYMTAB command in GetSymbolAddress\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1118); exit(1); } while (0)
;
1119 }
1120
1121 segment_command_64 *linkedit_cmd = NULL__null;
1122 if (!GetLoadCommand(mach_header, load_commands_buffer, LC_SEGMENT_640x19, "__LINKEDIT", &linkedit_cmd)) {
1123 FATAL("Unable to find __LINKEDIT command in GetSymbolAddress\n")do { printf("[-] PROGRAM ABORT : " "Unable to find __LINKEDIT command in GetSymbolAddress\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1123); exit(1); } while (0)
;
1124 }
1125
1126 segment_command_64 *text_cmd = NULL__null;
1127 if (!GetLoadCommand(mach_header, load_commands_buffer, LC_SEGMENT_640x19, "__TEXT", &text_cmd)) {
1128 FATAL("Unable to find __TEXT command in GetSymbolAddress\n")do { printf("[-] PROGRAM ABORT : " "Unable to find __TEXT command in GetSymbolAddress\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1128); exit(1); } while (0)
;
1129 }
1130
1131 uint64_t file_vm_slide = (uint64_t)base_address - text_cmd->vmaddr;
1132
1133 char *strtab = NULL__null;
1134 uint64_t strtab_addr = linkedit_cmd->vmaddr + file_vm_slide
1135 + symtab_cmd->stroff - linkedit_cmd->fileoff;
1136 if(!in_shared_cache) {
1137 strtab = (char*)malloc(symtab_cmd->strsize);
1138 RemoteRead((void*)strtab_addr, strtab, symtab_cmd->strsize);
1139 }
1140
1141 char *symtab = (char*)malloc(symtab_cmd->nsyms * sizeof(nlist_64));
1142 uint64_t symtab_addr = linkedit_cmd->vmaddr + file_vm_slide
1143 + symtab_cmd->symoff - linkedit_cmd->fileoff;
1144 RemoteRead((void*)symtab_addr, symtab, symtab_cmd->nsyms * sizeof(nlist_64));
1145
1146 void *symbol_address = NULL__null;
1147
1148 size_t curr_symbol_address = (size_t)symtab;
1149 for (int i = 0; i < symtab_cmd->nsyms && !symbol_address; ++i) {
1150 nlist_64 curr_symbol = *(nlist_64*)curr_symbol_address;
1151 if ((curr_symbol.n_type & N_TYPE0x0e) == N_SECT0xe) {
1152 char *curr_sym_name = NULL__null;
1153 std::string curr_sym_name_string;
1154 if (!in_shared_cache) {
1155 curr_sym_name = strtab + curr_symbol.n_un.n_strx;
1156 } else {
1157 mach_target->ReadCString(strtab_addr + curr_symbol.n_un.n_strx, curr_sym_name_string);
1158 curr_sym_name = (char*)curr_sym_name_string.c_str();
1159 }
1160
1161 // printf("%s\n", curr_sym_name);
1162 if (!strcmp(curr_sym_name, symbol_name)) {
1163 symbol_address = (void*)((uint64_t)base_address - text_cmd->vmaddr + curr_symbol.n_value);
1164 break;
1165 }
1166 }
1167
1168 curr_symbol_address += sizeof(nlist_64);
1169 }
1170
1171 free(strtab);
1172 free(symtab);
1173 free(load_commands_buffer);
1174 return symbol_address;
1175}
1176
1177void *Debugger::GetTargetAddress(void *base_address) {
1178 if (!target_offset) {
1179 void *method_address = GetSymbolAddress(base_address, target_method);
1180 if (method_address == NULL__null) {
1181 FATAL("Unable to find address of target method\n")do { printf("[-] PROGRAM ABORT : " "Unable to find address of target method\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1181); exit(1); } while (0)
;
1182 }
1183
1184 target_offset = (uint64_t)method_address - (uint64_t)base_address;
1185 }
1186
1187 return (void*)((uint64_t)base_address + target_offset);
1188}
1189
1190void Debugger::OnModuleLoaded(void *module, char *module_name) {
1191 if (trace_debug_events) {
1192 SAY("Debugger: Loaded module %s at %p\n", module_name, module)printf("Debugger: Loaded module %s at %p\n", module_name, module
)
;
1193 }
1194
1195 if (!attach_mode) {
1196 void *entrypoint = GetModuleEntrypoint(module);
1197 if (entrypoint) {
1198 AddBreakpoint(entrypoint, BREAKPOINT_ENTRYPOINT0x01);
1199 }
1200 }
1201
1202 if (IsDyld(module)) {
1203 HandleDyld(module);
1204 }
1205
1206 if (target_function_defined && !strcasecmp(module_name, target_module)) {
1207 target_address = GetTargetAddress(module);
1208 if (!target_address) {
1209 FATAL("Error determining target method address\n")do { printf("[-] PROGRAM ABORT : " "Error determining target method address\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1209); exit(1); } while (0)
;
1210 }
1211
1212 AddBreakpoint(target_address, BREAKPOINT_TARGET0x02);
1213 }
1214}
1215
1216void Debugger::HandleDyld(void *module) {
1217 dyld_address = module;
1218
1219 m_dyld_debugger_notification = GetSymbolAddress(module, (char*)"__dyld_debugger_notification");
1220 AddBreakpoint(m_dyld_debugger_notification, BREAKPOINT_NOTIFICATION0x04);
1221
1222#ifdef ARM641
1223 // For arm we just mov pc, lr on BREAKPOINT_NOTIFICATION
1224#else
1225 // This save us the recurring TRAP FLAG breakpoint on BREAKPOINT_NOTIFICATION.
1226 unsigned char ret = 0xC3;
1227 RemoteWrite((void*)((uint64_t)m_dyld_debugger_notification+1), (void*)&ret, 1);
1228#endif
1229}
1230
1231void Debugger::OnDyldImageNotifier(size_t mode, unsigned long infoCount, uint64_t machHeaders[]) {
1232 uint64_t *image_info_array = new uint64_t[infoCount];
1233 size_t image_info_array_size = sizeof(uint64_t) * infoCount;
1234 RemoteRead(machHeaders, (void*)image_info_array, image_info_array_size);
1235
1236 if (mode == 1) { /* dyld_image_removing */
1237 for (unsigned long i = 0; i < infoCount; ++i) {
1238 OnModuleUnloaded((void*)image_info_array[i]);
1239 }
1240 } else {
1241 dyld_all_image_infos all_image_infos = mach_target->GetAllImageInfos();
1242
1243 // on macOS, it's possible for dyld to be loaded in two places
1244 // best effort to detect this here
1245 if(all_image_infos.dyldImageLoadAddress != dyld_address) {
1246 HandleDyld((void *)all_image_infos.dyldImageLoadAddress);
1247 }
1248
1249 dyld_image_info *all_image_info_array = new dyld_image_info[all_image_infos.infoArrayCount];
1250 size_t all_image_info_array_size = sizeof(dyld_image_info) * all_image_infos.infoArrayCount;
1251 if(all_image_info_array_size) {
1252 RemoteRead((void*)all_image_infos.infoArray, (void*)all_image_info_array, all_image_info_array_size);
1253 }
1254
1255 char path[PATH_MAX1024];
1256 for (uint32_t i = 0; i < all_image_infos.infoArrayCount; ++i) {
1257 void *mach_header_addr = (void*)all_image_info_array[i].imageLoadAddress;
1258 if (mode == 2) { /* dyld_notify_remove_all */
1259 OnModuleUnloaded(mach_header_addr);
1260 } else if (std::find(image_info_array, image_info_array + infoCount, (uint64_t)mach_header_addr)
1261 != image_info_array + infoCount) {
1262 /* dyld_image_adding */
1263 mach_target->ReadCString((uint64_t)all_image_info_array[i].imageFilePath, PATH_MAX1024, path);
1264 char *base_name = strrchr((char*)path, '/');
1265 base_name = (base_name) ? base_name + 1 : (char*)path;
1266 OnModuleLoaded(mach_header_addr, base_name);
1267 }
1268 }
1269
1270 delete [] all_image_info_array;
1271 }
1272
1273 delete [] image_info_array;
1274}
1275
1276void Debugger::OnProcessCreated() {
1277 if (trace_debug_events) {
1278 SAY("Debugger: Process created or attached\n")printf("Debugger: Process created or attached\n");
1279 }
1280
1281 kern_return_t krt;
1282 dyld_process_info info = m_dyld_process_info_create(mach_target->Task(), 0, &krt);
1283 if (krt != KERN_SUCCESS0) {
1284 FATAL("Unable to retrieve dyld_process_info_create information\n")do { printf("[-] PROGRAM ABORT : " "Unable to retrieve dyld_process_info_create information\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1284); exit(1); } while (0)
;
1285 }
1286
1287 if (info) {
1288 m_dyld_process_info_for_each_image(
1289 info,
1290 ^(uint64_t mach_header_addr, const uuid_t uuid, const char *path) {
1291 if (attach_mode || IsDyld((void*)mach_header_addr)) {
1292 char *base_name = strrchr((char*)path, '/');
1293 base_name = (base_name) ? base_name + 1 : (char*)path;
1294 OnModuleLoaded((void*)mach_header_addr, (char*)base_name);
1295 }
1296 });
1297
1298 m_dyld_process_info_release(info);
1299 }
1300}
1301
1302
1303int Debugger::HandleDebuggerBreakpoint() {
1304 int ret = BREAKPOINT_UNKNOWN0x0;
1305
1306 Breakpoint *breakpoint = NULL__null, *tmp_breakpoint;
1307 for (auto iter = breakpoints.begin(); iter != breakpoints.end(); iter++) {
1308 tmp_breakpoint = *iter;
1309 if (tmp_breakpoint->address == (void*)((uint64_t)last_exception.ip)) {
1310 breakpoint = tmp_breakpoint;
1311 if (breakpoint->type & BREAKPOINT_NOTIFICATION0x04) {
1312 OnDyldImageNotifier(GetRegister(ArgumentToRegister(0)),
1313 (unsigned long)GetRegister(ArgumentToRegister(1)),
1314 (uint64_t*)GetRegister(ArgumentToRegister(2)));
1315
1316 return BREAKPOINT_NOTIFICATION0x04;
1317 }
1318
1319 breakpoints.erase(iter);
1320 break;
1321 }
1322 }
1323
1324 if (!breakpoint) {
1325 return ret;
1326 }
1327
1328 RemoteWrite(breakpoint->address, &breakpoint->original_opcode, sizeof(breakpoint->original_opcode));
1329#ifdef ARM641
1330 SetRegister(ARCH_PCPC, GetRegister(ARCH_PCPC) - 4); // ARM
1331#else
1332 SetRegister(ARCH_PCPC, GetRegister(ARCH_PCPC) - 1); // INTEL
1333#endif
1334
1335 if (breakpoint->type & BREAKPOINT_ENTRYPOINT0x01) {
1336 OnEntrypoint();
1337 }
1338
1339 if (breakpoint->type & BREAKPOINT_TARGET0x02) {
1340 if (trace_debug_events) {
1341 SAY("Target method reached\n")printf("Target method reached\n");
1342 }
1343 HandleTargetReachedInternal();
1344 }
1345
1346 if (breakpoint->type & BREAKPOINT_TARGET_END0x08) {
1347 if (trace_debug_events) {
1348 SAY("Target method ended\n")printf("Target method ended\n");
1349 }
1350 HandleTargetEnded();
1351 }
1352
1353 ret = breakpoint->type;
1354 free(breakpoint);
1355
1356 return ret;
1357}
1358
1359bool Debugger::IsTargetAlive() {
1360 return (mach_target != NULL__null && mach_target->IsTaskValid() && mach_target->IsExceptionPortValid());
1361}
1362
1363
1364void Debugger::HandleExceptionInternal(MachException *raised_mach_exception) {
1365 mach_exception = raised_mach_exception;
1366 CreateException(mach_exception, &last_exception);
1367
1368 dbg_continue_status = KERN_SUCCESS0;
1369 handle_exception_status = DEBUGGER_CONTINUE;
1370
1371 if (mach_exception->exception_type == EXC_BREAKPOINT6) {
1372 int breakpoint_type = HandleDebuggerBreakpoint();
1373 if (breakpoint_type & BREAKPOINT_TARGET0x02) {
1374 handle_exception_status = DEBUGGER_TARGET_START;
1375 }
1376 if (breakpoint_type & BREAKPOINT_TARGET_END0x08) {
1377 handle_exception_status = DEBUGGER_TARGET_END;
1378 }
1379#ifdef ARM641
1380 if (breakpoint_type & BREAKPOINT_NOTIFICATION0x04) {
1381 SetRegister(ARCH_PCPC, GetRegister(LR));
1382 return;
1383 }
1384#endif
1385
1386 if (breakpoint_type != BREAKPOINT_UNKNOWN0x0) {
1387 return;
1388 }
1389 }
1390
1391 if (OnException(&last_exception)) {
1392 return;
1393 }
1394
1395 if (trace_debug_events) {
1396 SAY("Debugger: Mach exception (%d) @ address %p\n",printf("Debugger: Mach exception (%d) @ address %p\n", mach_exception
->exception_type, last_exception.ip)
1397 mach_exception->exception_type, last_exception.ip)printf("Debugger: Mach exception (%d) @ address %p\n", mach_exception
->exception_type, last_exception.ip)
;
1398 }
1399
1400 switch(mach_exception->exception_type) {
1401 case EXC_SYSCALL7:
1402 handle_exception_status = DEBUGGER_CONTINUE;
1403 dbg_continue_status = KERN_SUCCESS0;
1404 break;
1405 case EXC_RESOURCE11:
1406 handle_exception_status = DEBUGGER_HANGED;
1407 break;
1408
1409 case EXC_BAD_ACCESS1:
1410 bad_access_label:
1411 if (target_function_defined && last_exception.ip == (void*)PERSIST_END_EXCEPTION0x0F22) {
1412 if (trace_debug_events) {
1413 SAY("Debugger: Persistence method ended\n")printf("Debugger: Persistence method ended\n");
1414 }
1415
1416 HandleTargetEnded();
1417 handle_exception_status = DEBUGGER_TARGET_END;
1418 } else {
1419 dbg_continue_status = KERN_FAILURE5;
1420 handle_exception_status = DEBUGGER_CRASHED;
1421 }
1422 break;
1423
1424 case EXC_BAD_INSTRUCTION2:
1425 case EXC_ARITHMETIC3:
1426 case EXC_CRASH10:
1427 case EXC_GUARD12:
1428 crash_label:
1429 dbg_continue_status = KERN_FAILURE5;
1430 handle_exception_status = DEBUGGER_CRASHED;
1431 break;
1432
1433 case EXC_BREAKPOINT6:
1434 dbg_continue_status = KERN_FAILURE5;
1435 break;
1436
1437 //Unix signals
1438 case EXC_SOFTWARE5:
1439 if (mach_exception->code_cnt < 2 || mach_exception->code[0] != EXC_SOFT_SIGNAL0x10003) {
1440 goto default_label;
1441 }
1442
1443 switch (mach_exception->code[1]) {
1444 case SIGSEGV11:
1445 case SIGBUS10:
1446 goto bad_access_label;
1447
1448 case SIGILL4:
1449 case SIGFPE8:
1450 case SIGABRT6:
1451 case SIGSYS12:
1452 case SIGPIPE13:
1453 goto crash_label;
1454
1455 /* Handling the Unix soft signal produced by attaching via ptrace
1456 PT_ATTACHEXC suspends the process by using a SIGSTOP signal */
1457 case SIGSTOP17:
1458 OnProcessCreated();
1459
1460 mach_exception->code[1] = 0;
1461 ptrace(PT_THUPDATE13,
1462 mach_target->Pid(),
1463 (caddr_t)(uintptr_t)mach_exception->thread_port,
1464 (int)mach_exception->code[1]);
1465
1466 break;
1467
1468 case SIGCHLD20:
1469 if (!IsTargetAlive()) {
1470 handle_exception_status = DEBUGGER_PROCESS_EXIT;
1471 }
1472 break;
1473
1474 default:
1475 goto default_label;
1476 }
1477
1478 break;
1479
1480 default:
1481 default_label:
1482 if (trace_debug_events) {
1483 WARN("Debugger: Unhandled exception, mach exception_type %x at address %p\n",do { printf("[!] WARNING: " "Debugger: Unhandled exception, mach exception_type %x at address %p\n"
, mach_exception->exception_type, last_exception.ip); printf
("\n"); } while (0)
1484 mach_exception->exception_type, last_exception.ip)do { printf("[!] WARNING: " "Debugger: Unhandled exception, mach exception_type %x at address %p\n"
, mach_exception->exception_type, last_exception.ip); printf
("\n"); } while (0)
;
1485 }
1486 dbg_continue_status = KERN_FAILURE5;
1487 }
1488}
1489
1490void Debugger::SaveRegisters(SavedRegisters *registers) {
1491 if((*(mach_exception->new_state_cnt)) * sizeof(mach_exception->new_state[0]) > sizeof(ARCH_THREAD_STATE_Tarm_thread_state64_t)) {
1492 FATAL("Unexpected thread state size")do { printf("[-] PROGRAM ABORT : " "Unexpected thread state size"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1492); exit(1); } while (0)
;
1493 }
1494
1495 registers->gpr_count = *(mach_exception->new_state_cnt);
1496
1497 memcpy(&registers->gpr_registers,
1498 mach_exception->new_state,
1499 registers->gpr_count * sizeof(natural_t));
1500
1501 registers->fpu_count = sizeof(ARCH_FPU_STATE_Tarm_neon_state64_t) / sizeof(natural_t);
1502 kern_return_t ret = thread_get_state(mach_exception->thread_port,
1503 ARCH_FPU_STATE17,
1504 (thread_state_t)&registers->fpu_registers,
1505 &registers->fpu_count);
1506
1507 if(ret != KERN_SUCCESS0) {
1508 FATAL("Error getting FPU registers %d", ret)do { printf("[-] PROGRAM ABORT : " "Error getting FPU registers %d"
, ret); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1508); exit(1); } while (0)
;
1509 }
1510}
1511
1512void Debugger::RestoreRegisters(SavedRegisters *registers) {
1513 if(*mach_exception->new_state_cnt != registers->gpr_count) {
1514 FATAL("Unexpected thread state size")do { printf("[-] PROGRAM ABORT : " "Unexpected thread state size"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1514); exit(1); } while (0)
;
1515 }
1516
1517 memcpy(mach_exception->new_state,
1518 &registers->gpr_registers,
1519 registers->gpr_count * sizeof(natural_t));
1520
1521 kern_return_t ret = thread_set_state(mach_exception->thread_port,
1522 ARCH_FPU_STATE17,
1523 (thread_state_t)&registers->fpu_registers,
1524 registers->fpu_count);
1525
1526 if(ret != KERN_SUCCESS0) {
1527 FATAL("Error setting FPU registers")do { printf("[-] PROGRAM ABORT : " "Error setting FPU registers"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1527); exit(1); } while (0)
;
1528 }
1529
1530}
1531
1532void Debugger::PrintContext() {
1533 thread_act_t *threads = NULL__null;
1534 mach_msg_type_number_t num_threads = 0;
1535 kern_return_t ret = task_threads(mach_target->Task(), &threads, &num_threads);
1536 if(ret != KERN_SUCCESS0) return;
1537 for(unsigned i=0;i<num_threads;i++) {
1538 ARCH_THREAD_STATE_Tarm_thread_state64_t state;
1539 unsigned int count = ARCH_THREAD_STATE_COUNT((mach_msg_type_number_t) (sizeof (arm_thread_state64_t)/sizeof
(uint32_t)))
;
1540 ret = thread_get_state(threads[i], ARCH_THREAD_STATE6, (thread_state_t)&state, &count);
1541 if(ret != KERN_SUCCESS0) continue;
1542#ifdef ARM641
1543 printf("thread %d\n", i);
1544 printf("pc: %llx\n", state.__pc);
1545 printf(" x0: %16llx x1: %16llx x2: %16llx x3: %16llx\n", state.__x[0], state.__x[1], state.__x[2], state.__x[3]);
1546 printf(" x4: %16llx x5: %16llx x6: %16llx x7: %16llx\n", state.__x[4], state.__x[5], state.__x[6], state.__x[7]);
1547 printf(" x8: %16llx x9: %16llx x10: %16llx x11: %16llx\n", state.__x[8], state.__x[9], state.__x[10], state.__x[11]);
1548 printf("x12: %16llx x13: %16llx x14: %16llx x15: %16llx\n", state.__x[12], state.__x[13], state.__x[14], state.__x[15]);
1549 printf("x16: %16llx x17: %16llx x18: %16llx x19: %16llx\n", state.__x[16], state.__x[17], state.__x[18], state.__x[19]);
1550 printf("x20: %16llx x21: %16llx x22: %16llx x23: %16llx\n", state.__x[20], state.__x[21], state.__x[22], state.__x[23]);
1551 printf("x24: %16llx x25: %16llx x26: %16llx x27: %16llx\n", state.__x[24], state.__x[25], state.__x[26], state.__x[27]);
1552 printf("x28: %16llx\n", state.__x[28]);
1553 printf(" sp: %16llx fp: %16llx lr: %16llx cpsr: %8x\n\n", state.__sp, state.__fp, state.__lr, state.__cpsr);
1554 printf("stack:\n");
1555 uint64_t stack[100];
1556 mach_target->ReadMemory(state.__sp, sizeof(stack), stack);
1557#else
1558 printf("thread %d\n", i);
1559 printf("rip:%llx\n", state.__rip);
1560 printf("rax:%llx rbx:%llx rcx:%llx rdx:%llx\n", state.__rax, state.__rbx, state.__rcx, state.__rdx);
1561 printf("rsi:%llx rdi:%llx rbp:%llx rsp:%llx\n", state.__rsi, state.__rdi, state.__rbp, state.__rsp);
1562 printf("r8:%llx r9:%llx r10:%llx r11:%llx\n", state.__r8, state.__r9, state.__r10, state.__r11);
1563 printf("r12:%llx r13:%llx r14:%llx r15:%llx\n", state.__r12, state.__r13, state.__r14, state.__r15);
1564 printf("stack:\n");
1565 uint64_t stack[100];
1566 mach_target->ReadMemory(state.__rsp, sizeof(stack), stack);
1567#endif
1568 for(size_t j=0; j<(sizeof(stack)/sizeof(stack[0])); j++) {
1569 printf("%16llx\n", stack[j]);
1570 }
1571 }
1572 for(unsigned i=0;i<num_threads;i++) {
1573 mach_port_deallocate(mach_task_self()mach_task_self_, threads[i]);
1574 }
1575 vm_deallocate(mach_task_self()mach_task_self_, (vm_address_t)threads, num_threads * sizeof(thread_act_t));
1576}
1577
1578DebuggerStatus Debugger::DebugLoop(uint32_t timeout) {
1579 if (!IsTargetAlive()) {
1580 OnProcessExit();
1581 return DEBUGGER_PROCESS_EXIT;
1582 }
1583
1584 if (dbg_continue_needed) {
1585 task_resume(mach_target->Task());
1586 }
1587
1588 if (dbg_reply_needed) {
1589 mach_target->ReplyToException(reply_buffer);
1590 }
1591
1592 bool alive = true;
1593 while (alive) {
1594 dbg_continue_needed = false;
1595 dbg_reply_needed = false;
1596
1597 if(target_memory_limit && alive && !killing_target) {
1598 vm_size_t mem_size = mach_target->MemSize();
1599 if(mem_size > target_memory_limit) {
1600 WARN("Target exceeded memory limit")do { printf("[!] WARNING: " "Target exceeded memory limit"); printf
("\n"); } while (0)
;
1601 task_suspend(mach_target->Task());
1602 dbg_continue_needed = true;
1603 return DEBUGGER_HANGED;
1604 }
1605 }
1606
1607 uint64_t begin_time = GetCurTime();
1608 kern_return_t krt = mach_target->WaitForException(std::min(timeout, (uint32_t)100),
1609 request_buffer,
1610 sizeof(union __RequestUnion__catch_mach_exc_subsystem));
1611 uint64_t end_time = GetCurTime();
1612
1613 uint64_t time_elapsed = end_time - begin_time;
1614 timeout = ((uint64_t)timeout >= time_elapsed) ? timeout - (uint32_t)time_elapsed : 0;
1615
1616 switch (krt) {
1617 case MACH_RCV_TIMED_OUT0x10004003:
1618 if (timeout == 0) {
1619 task_suspend(mach_target->Task());
1620 dbg_continue_needed = true;
1621 return DEBUGGER_HANGED;
1622 }
1623 //go down into the MACH_RCV_INTERRUPTED case otherwise
1624
1625 case MACH_RCV_INTERRUPTED0x10004005:
1626 if (!IsTargetAlive()) {
1627 alive = false;
1628 }
1629
1630 continue;
1631
1632 default:
1633 if (krt != MACH_MSG_SUCCESS0x00000000) {
1634 FATAL("Error (%s) returned by mach_msg (%x)\n", mach_error_string(krt), krt)do { printf("[-] PROGRAM ABORT : " "Error (%s) returned by mach_msg (%x)\n"
, mach_error_string(krt), krt); printf(" Location : %s(), %s:%u\n\n"
, __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1634); exit(1); } while (0)
;
1635 }
1636 }
1637
1638 task_suspend(mach_target->Task());
1639 dbg_continue_needed = true;
1640
1641
1642 /* mach_exc_server calls catch_mach_exception_raise
1643 HandleExceptionInternal returns in ret_HandleExceptionInternal */
1644 boolean_t message_parsed_correctly = mach_exc_server(request_buffer, reply_buffer);
1645 if (!message_parsed_correctly) {
1646 krt = ((mig_reply_error_t *)reply_buffer)->RetCode;
1647 FATAL("Error (%s) returned in reply buffer by mach_exc_server\n", mach_error_string(krt))do { printf("[-] PROGRAM ABORT : " "Error (%s) returned in reply buffer by mach_exc_server\n"
, mach_error_string(krt)); printf(" Location : %s(), %s:%u\n\n"
, __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1647); exit(1); } while (0)
;
1648 }
1649
1650 dbg_reply_needed = true;
1651
1652 if (handle_exception_status == DEBUGGER_CRASHED) {
1653 OnCrashed(&last_exception);
1654 }
1655
1656 if (handle_exception_status == DEBUGGER_PROCESS_EXIT) {
1657 alive = false;
1658 continue;
1659 }
1660
1661 if (handle_exception_status != DEBUGGER_CONTINUE) {
1662 return handle_exception_status;
1663 }
1664
1665 task_resume(mach_target->Task());
1666 mach_target->ReplyToException(reply_buffer);
1667 }
1668
1669 OnProcessExit();
1670 return DEBUGGER_PROCESS_EXIT;
1671}
1672
1673/**
1674 * Method not used, implementation is needed by the mach_exc_server method.
1675*/
1676kern_return_t catch_mach_exception_raise(
1677 mach_port_t exception_port,
1678 mach_port_t thread_port,
1679 mach_port_t task_port,
1680 exception_type_t exception_type,
1681 mach_exception_data_t code,
1682 mach_msg_type_number_t code_cnt) {
1683 return MACH_RCV_INVALID_TYPE0x1000400d;
1684}
1685
1686
1687/**
1688 * Method not used, implementation is needed by the mach_exc_server method.
1689 */
1690kern_return_t catch_mach_exception_raise_state(
1691 mach_port_t exception_port,
1692 exception_type_t exception_type,
1693 const mach_exception_data_t code,
1694 mach_msg_type_number_t code_cnt,
1695 int *flavor,
1696 const thread_state_t old_state,
1697 mach_msg_type_number_t old_state_cnt,
1698 thread_state_t new_state,
1699 mach_msg_type_number_t *new_state_cnt) {
1700 return MACH_RCV_INVALID_TYPE0x1000400d;
1701}
1702
1703/**
1704 * Called by mach_exc_server
1705 *
1706 * @param exception_port the exception_port registered in AttachToProcess() method
1707 * @param task_port the target_task
1708*/
1709kern_return_t catch_mach_exception_raise_state_identity(
1710 mach_port_t exception_port,
1711 mach_port_t thread_port,
1712 mach_port_t task_port,
1713 exception_type_t exception_type,
1714 mach_exception_data_t code,
1715 mach_msg_type_number_t code_cnt,
1716 int *flavor,
1717 thread_state_t old_state,
1718 mach_msg_type_number_t old_state_cnt,
1719 thread_state_t new_state,
1720 mach_msg_type_number_t *new_state_cnt) {
1721
1722 memcpy(new_state, old_state, old_state_cnt * sizeof(old_state[0]));
1723 *new_state_cnt = old_state_cnt;
1724
1725 Debugger::MachException *mach_exception = new Debugger::MachException(exception_port,
1726 thread_port,
1727 task_port,
1728 exception_type,
1729 code,
1730 code_cnt,
1731 flavor,
1732 new_state,
1733 new_state_cnt);
1734
1735
1736 class Debugger *dbg = NULL__null;
1737 Debugger::map_mutex.lock();
1738 auto it = Debugger::task_to_debugger_map.find(task_port);
1739 if (it == Debugger::task_to_debugger_map.end() || it->second == NULL__null) {
1
Assuming field 'second' is not equal to NULL
2
Taking false branch
1740 FATAL("Debugger object could not be found in the map, task port = (%d)\n", task_port)do { printf("[-] PROGRAM ABORT : " "Debugger object could not be found in the map, task port = (%d)\n"
, task_port); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1740); exit(1); } while (0)
;
1741 }
1742 dbg = it->second;
1743 Debugger::map_mutex.unlock();
1744
1745 if (!dbg->killing_target) {
3
Assuming field 'killing_target' is true
4
Taking false branch
1746 dbg->HandleExceptionInternal(mach_exception);
1747 } else {
1748 dbg->dbg_continue_status = KERN_FAILURE5;
5
The value 5 is assigned to field 'dbg_continue_status'
1749 dbg->handle_exception_status = DEBUGGER_CONTINUE;
1750 }
1751
1752 kern_return_t krt;
1753 krt = mach_port_deallocate(mach_task_self()mach_task_self_, task_port);
6
Value passed through parameter 'task_port' is deallocated
1754 if (krt != KERN_SUCCESS0) {
7
Assuming 'krt' is equal to KERN_SUCCESS
8
Taking false branch
1755 FATAL("Error (%s) deallocating the task port\n", mach_error_string(krt))do { printf("[-] PROGRAM ABORT : " "Error (%s) deallocating the task port\n"
, mach_error_string(krt)); printf(" Location : %s(), %s:%u\n\n"
, __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1755); exit(1); } while (0)
;
1756 }
1757
1758 krt = mach_port_deallocate(mach_task_self()mach_task_self_, thread_port);
9
Value passed through parameter 'thread_port' is deallocated
1759 if (krt != KERN_SUCCESS0) {
10
Assuming 'krt' is equal to KERN_SUCCESS
11
Taking false branch
1760 FATAL("Error (%s) deallocating the thread port\n", mach_error_string(krt))do { printf("[-] PROGRAM ABORT : " "Error (%s) deallocating the thread port\n"
, mach_error_string(krt)); printf(" Location : %s(), %s:%u\n\n"
, __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1760); exit(1); } while (0)
;
1761 }
1762
1763 delete mach_exception;
1764 mach_exception = NULL__null;
1765 return dbg->dbg_continue_status;
12
MIG callback fails with error after deallocating argument value. This is a use-after-free vulnerability because the caller will try to deallocate it again
1766}
1767
1768void Debugger::OnProcessExit() {
1769 if (trace_debug_events) {
1770 SAY("Debugger: Process exit\n")printf("Debugger: Process exit\n");
1771 }
1772
1773 if (mach_target != NULL__null) {
1774 map_mutex.lock();
1775 int removed = task_to_debugger_map.erase(mach_target->Task());
1776 if (removed == 0) {
1777 WARN("There is no task port (%u) in task_to_debugger_map to be erased", mach_target->Task())do { printf("[!] WARNING: " "There is no task port (%u) in task_to_debugger_map to be erased"
, mach_target->Task()); printf("\n"); } while (0)
;
1778 }
1779 map_mutex.unlock();
1780
1781 mach_target->CleanUp();
1782 delete mach_target;
1783 mach_target = NULL__null;
1784
1785 ClearSharedMemory();
1786 }
1787
1788 dyld_address = 0;
1789
1790 // collect any zombie processes at this point
1791 int status;
1792 while(wait3(&status, WNOHANG0x00000001, 0) > 0);
1793}
1794
1795
1796DebuggerStatus Debugger::Kill() {
1797 if (mach_target == NULL__null) {
1798 return DEBUGGER_PROCESS_EXIT;
1799 }
1800
1801 killing_target = true;
1802 int target_pid = mach_target->Pid();
1803 kill(target_pid, SIGKILL9);
1804
1805 //SIGKILL is not handled, so DebugLoop must return DEBUGGER_PROCESS_EXIT
1806 dbg_last_status = DebugLoop(0xffffffff);
1807 if (dbg_last_status != DEBUGGER_PROCESS_EXIT || IsTargetAlive()) {
1808 FATAL("Unable to kill the process\n")do { printf("[-] PROGRAM ABORT : " "Unable to kill the process\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1808); exit(1); } while (0)
;
1809 }
1810
1811 DeleteBreakpoints();
1812 killing_target = false;
1813
1814 return dbg_last_status;
1815}
1816
1817char **Debugger::GetEnvp() {
1818 int environ_size = 0;
1819 char **p = environ;
1820 while (*p) {
1821 environ_size += 1;
1822 p++;
1823 }
1824
1825 int envp_size = environ_size + additional_env.size();
1826 char **envp = (char**)malloc(sizeof(char*)*(envp_size+1));
1827 int i;
1828 for (i = 0; i < environ_size; ++i) {
1829 envp[i] = (char*)malloc(strlen(environ[i])+1);
1830 strcpy(envp[i], environ[i]);
1831 }
1832
1833 for(auto iter = additional_env.begin(); iter != additional_env.end(); iter++) {
1834 envp[i] = (char*)malloc(iter->size() + 1);
1835 strcpy(envp[i], iter->c_str());
1836 i++;
1837 }
1838
1839 envp[envp_size] = NULL__null;
1840
1841 return envp;
1842}
1843
1844
1845void Debugger::StartProcess(int argc, char **argv) {
1846 if (argc <= 0) {
1847 FATAL("Number of arguments is not strictly positive")do { printf("[-] PROGRAM ABORT : " "Number of arguments is not strictly positive"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1847); exit(1); } while (0)
;
1848 }
1849
1850 posix_spawn_file_actions_t *action_ptr = NULL__null;
1851 posix_spawn_file_actions_t action;
1852
1853 if(mute_child) {
1854 action_ptr = &action;
1855 posix_spawn_file_actions_init(&action);
1856 posix_spawn_file_actions_addopen (&action, STDOUT_FILENO1, "/dev/null", O_WRONLY0x0001|O_APPEND0x00000008, 0);
1857 posix_spawn_file_actions_addopen (&action, STDERR_FILENO2, "/dev/null", O_WRONLY0x0001|O_APPEND0x00000008, 0);
1858 }
1859
1860 pid_t pid;
1861 int status;
1862 posix_spawnattr_t attr;
1863
1864 status = posix_spawnattr_init(&attr);
1865 if (status != 0) {
1866 FATAL("Unable to init spawnattr")do { printf("[-] PROGRAM ABORT : " "Unable to init spawnattr"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1866); exit(1); } while (0)
;
1867 }
1868
1869 short posix_flags = POSIX_SPAWN_START_SUSPENDED0x0080;
1870 if(disable_aslr) {
1871 posix_flags |= _POSIX_SPAWN_DISABLE_ASLR0x0100;
1872 }
1873 status = posix_spawnattr_setflags(&attr, posix_flags);
1874 if (status != 0) {
1875 FATAL("Unable to set flags in posix_spawnattr_setflags")do { printf("[-] PROGRAM ABORT : " "Unable to set flags in posix_spawnattr_setflags"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1875); exit(1); } while (0)
;
1876 }
1877
1878 char **envp = GetEnvp();
1879 status = posix_spawn(&pid, argv[0], action_ptr, &attr, argv, envp);
1880 if (status != 0) {
1881 FATAL("Error (%s) spawning the process\n", strerror(status))do { printf("[-] PROGRAM ABORT : " "Error (%s) spawning the process\n"
, strerror(status)); printf(" Location : %s(), %s:%u\n\n"
, __FUNCTION__, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1881); exit(1); } while (0)
;
1882 }
1883
1884 for (char **p = envp; *p; p++) {
1885 free(*p);
1886 }
1887 free(envp);
1888
1889 mach_target = new MachTarget(pid);
1890}
1891
1892
1893void Debugger::AttachToProcess() {
1894 killing_target = false;
1895 dbg_continue_needed = false;
1896 dbg_reply_needed = false;
1897 target_reached = false;
1898
1899 DeleteBreakpoints();
1900
1901 int ptrace_ret;
1902 ptrace_ret = ptrace(PT_ATTACHEXC14, mach_target->Pid(), 0, 0);
1903 if (ptrace_ret == -1) {
1904 FATAL("Unable to ptrace PT_ATTACHEXC to the target process\n")do { printf("[-] PROGRAM ABORT : " "Unable to ptrace PT_ATTACHEXC to the target process\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1904); exit(1); } while (0)
;
1905 }
1906
1907 map_mutex.lock();
1908 task_to_debugger_map[mach_target->Task()] = this;
1909 map_mutex.unlock();
1910
1911 dbg_last_status = DEBUGGER_ATTACHED;
1912}
1913
1914
1915DebuggerStatus Debugger::Attach(unsigned int pid, uint32_t timeout) {
1916 attach_mode = true;
1917 mach_target = new MachTarget(pid);
1918 child_entrypoint_reached = true;
1919
1920 AttachToProcess();
1921 return Continue(timeout);
1922}
1923
1924
1925DebuggerStatus Debugger::Run(char *cmd, uint32_t timeout) {
1926 FATAL("Deprecated Run interface on macOS - use Run(int argc, char **argv, uint32_t timeout) instead")do { printf("[-] PROGRAM ABORT : " "Deprecated Run interface on macOS - use Run(int argc, char **argv, uint32_t timeout) instead"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 1926); exit(1); } while (0)
;
1927}
1928
1929
1930DebuggerStatus Debugger::Run(int argc, char **argv, uint32_t timeout) {
1931 attach_mode = false;
1932 child_entrypoint_reached = false;
1933
1934 StartProcess(argc, argv);
1935 AttachToProcess();
1936 return Continue(timeout);
1937}
1938
1939DebuggerStatus Debugger::Continue(uint32_t timeout) {
1940 if (loop_mode && (dbg_last_status == DEBUGGER_TARGET_END)) {
1941 dbg_last_status = DEBUGGER_TARGET_START;
1942 return dbg_last_status;
1943 }
1944
1945 dbg_last_status = DebugLoop(timeout);
1946 return dbg_last_status;
1947}
1948
1949
1950void Debugger::Init(int argc, char **argv) {
1951 mach_target = NULL__null;
1952 killing_target = false;
1953
1954 attach_mode = false;
1955 trace_debug_events = false;
1956 loop_mode = false;
1957 disable_aslr = false;
1958 target_function_defined = false;
1959
1960 target_return_value = 0;
1961
1962 target_module[0] = 0;
1963 target_method[0] = 0;
1964 target_offset = 0;
1965 saved_args = NULL__null;
1966 target_num_args = 0;
1967 target_address = NULL__null;
1968
1969#ifdef ARM641
1970 target_end_detection = RETADDR_BREAKPOINT;
1971 private_dlyd_cache = true;
1972#else
1973 target_end_detection = RETADDR_STACK_OVERWRITE;
1974 private_dlyd_cache = false;
1975#endif
1976
1977 dbg_last_status = DEBUGGER_NONE;
1978 shared_memory.clear();
1979
1980 dbg_continue_needed = false;
1981 dbg_reply_needed = false;
1982 request_buffer = (mach_msg_header_t *)malloc(sizeof(union __RequestUnion__catch_mach_exc_subsystem));
1983 reply_buffer = (mach_msg_header_t *)malloc(sizeof(union __ReplyUnion__catch_mach_exc_subsystem));
1984
1985 std::list<char *> env_options;
1986 GetOptionAll("-target_env", argc, argv, &env_options);
1987 for (auto iter = env_options.begin(); iter != env_options.end(); iter++) {
1988 additional_env.push_back(*iter);
1989 }
1990
1991 char *option;
1992 trace_debug_events = GetBinaryOption("-trace_debug_events",
1993 argc, argv,
1994 trace_debug_events);
1995
1996 option = GetOption("-target_module", argc, argv);
1997 if (option) strncpy(target_module, option, PATH_MAX1024);
1998
1999 option = GetOption("-target_method", argc, argv);
2000 if (option) strncpy(target_method, option, PATH_MAX1024);
2001
2002 loop_mode = GetBinaryOption("-loop", argc, argv, loop_mode);
2003 disable_aslr = GetBinaryOption("-disable_aslr", argc, argv, disable_aslr);
2004
2005 option = GetOption("-nargs", argc, argv);
2006 if (option) target_num_args = atoi(option);
2007
2008 option = GetOption("-target_offset", argc, argv);
2009 if (option) target_offset = strtoul(option, NULL__null, 0);
2010
2011 // check if we are running in persistence mode
2012 if (target_module[0] || target_offset || target_method[0]) {
2013 target_function_defined = true;
2014 if ((target_module[0] == 0) || ((target_offset == 0) && (target_method[0] == 0))) {
2015 FATAL("target_module and either target_offset or target_method must be specified together\n")do { printf("[-] PROGRAM ABORT : " "target_module and either target_offset or target_method must be specified together\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 2015); exit(1); } while (0)
;
2016 }
2017 }
2018
2019 if (loop_mode && !target_function_defined) {
2020 FATAL("Target function needs to be defined to use the loop mode\n")do { printf("[-] PROGRAM ABORT : " "Target function needs to be defined to use the loop mode\n"
); printf(" Location : %s(), %s:%u\n\n", __FUNCTION__
, "/Users/xss/tmp/Jackalope-main/TinyInst/macOS/debugger.cpp"
, 2020); exit(1); } while (0)
;
2021 }
2022
2023 // avoid overwriting return address in case we have libgmalloc in env
2024 for (auto iter = additional_env.begin(); iter != additional_env.end(); iter++) {
2025 if (iter->find("libgmalloc") != std::string::npos) {
2026 target_end_detection = RETADDR_BREAKPOINT;
2027 }
2028 }
2029 private_dlyd_cache = GetBinaryOption("-private_dlyd_cache", argc, argv, private_dlyd_cache);
2030 if (private_dlyd_cache) {
2031 additional_env.push_back("DYLD_SHARED_REGION=private");
2032 }
2033
2034 if (target_num_args) {
2035 saved_args = (void **)malloc(target_num_args * sizeof(void *));
2036 }
2037
2038 m_dyld_process_info_create =
2039 (void *(*)(task_t task, uint64_t timestamp, kern_return_t * kernelError))
2040 dlsym(RTLD_DEFAULT((void *) -2), "_dyld_process_info_create");
2041 m_dyld_process_info_for_each_image =
2042 (void (*)(void *info, void (^)(uint64_t machHeaderAddress,
2043 const uuid_t uuid, const char *path)))
2044 dlsym(RTLD_DEFAULT((void *) -2), "_dyld_process_info_for_each_image");
2045 m_dyld_process_info_release =
2046 (void (*)(void *info))dlsym(RTLD_DEFAULT((void *) -2), "_dyld_process_info_release");
2047
2048 target_memory_limit = 0;
2049 option = GetOption("-mem_limit", argc, argv);
2050 if (option) target_memory_limit = (uint64_t)strtoul(option, NULL__null, 0) * 1024 * 1024;
2051
2052 mute_child = GetBinaryOption("-mute_child", argc, argv, false);
2053
2054 dyld_address = NULL__null;
2055}