/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_bool_t tb_kernel32_instance_init(tb_handle_t instance, tb_cpointer_t priv) { // check tb_kernel32_ref_t kernel32 = (tb_kernel32_ref_t)instance; tb_assert_and_check_return_val(kernel32, tb_false); // the kernel32 module HANDLE module = GetModuleHandleA("kernel32.dll"); if (!module) module = tb_dynamic_init("kernel32.dll"); tb_assert_and_check_return_val(module, tb_false); // init interfaces // TB_INTERFACE_LOAD(kernel32, CancelIoEx); TB_INTERFACE_LOAD(kernel32, RtlCaptureStackBackTrace); TB_INTERFACE_LOAD(kernel32, GetFileSizeEx); TB_INTERFACE_LOAD(kernel32, GetQueuedCompletionStatusEx); TB_INTERFACE_LOAD(kernel32, InterlockedCompareExchange64); TB_INTERFACE_LOAD(kernel32, GetEnvironmentVariableW); TB_INTERFACE_LOAD(kernel32, SetEnvironmentVariableW); TB_INTERFACE_LOAD(kernel32, CreateProcessW); TB_INTERFACE_LOAD(kernel32, CloseHandle); TB_INTERFACE_LOAD(kernel32, WaitForSingleObject); TB_INTERFACE_LOAD(kernel32, GetExitCodeProcess); TB_INTERFACE_LOAD(kernel32, TerminateProcess); TB_INTERFACE_LOAD(kernel32, SuspendThread); TB_INTERFACE_LOAD(kernel32, ResumeThread); TB_INTERFACE_LOAD(kernel32, GetEnvironmentStringsW); TB_INTERFACE_LOAD(kernel32, FreeEnvironmentStringsW); TB_INTERFACE_LOAD(kernel32, SetHandleInformation); // ok return tb_true; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_bool_t tb_user32_instance_init(tb_handle_t instance, tb_cpointer_t priv) { // check tb_user32_ref_t user32 = (tb_user32_ref_t)instance; tb_assert_and_check_return_val(user32, tb_false); // the user32 module HANDLE module = GetModuleHandleA("user32.dll"); if (!module) module = tb_dynamic_init("user32.dll"); tb_assert_and_check_return_val(module, tb_false); // init interfaces TB_INTERFACE_LOAD(user32, GetSystemMetrics); // ok return tb_true; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_bool_t tb_shell32_instance_init(tb_handle_t instance, tb_cpointer_t priv) { // check tb_shell32_ref_t shell32 = (tb_shell32_ref_t)instance; tb_check_return_val(shell32, tb_false); // the shell32 module HANDLE module = GetModuleHandleA("shell32.dll"); if (!module) module = tb_dynamic_init("shell32.dll"); tb_check_return_val(module, tb_false); // init interfaces TB_INTERFACE_LOAD(shell32, SHGetSpecialFolderLocation); TB_INTERFACE_LOAD(shell32, SHGetPathFromIDListW); // ok return tb_true; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_bool_t tb_iphlpapi_instance_init(tb_handle_t instance, tb_cpointer_t priv) { // check tb_iphlpapi_ref_t iphlpapi = (tb_iphlpapi_ref_t)instance; tb_assert_and_check_return_val(iphlpapi, tb_false); // the iphlpapi module HANDLE module = GetModuleHandleA("iphlpapi.dll"); if (!module) module = tb_dynamic_init("iphlpapi.dll"); tb_check_return_val(module, tb_false); // init interfaces TB_INTERFACE_LOAD(iphlpapi, GetNetworkParams); TB_INTERFACE_LOAD(iphlpapi, GetAdaptersInfo); TB_INTERFACE_LOAD(iphlpapi, GetAdaptersAddresses); // ok return tb_true; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_bool_t tb_ws2_32_instance_init(tb_handle_t instance, tb_cpointer_t priv) { // check tb_ws2_32_ref_t ws2_32 = (tb_ws2_32_ref_t)instance; tb_assert_and_check_return_val(ws2_32, tb_false); // the ws2_32 module HANDLE module = GetModuleHandleA("ws2_32.dll"); if (!module) module = tb_dynamic_init("ws2_32.dll"); tb_assert_and_check_return_val(module, tb_false); // init interfaces TB_INTERFACE_LOAD(ws2_32, WSAStartup); TB_INTERFACE_LOAD(ws2_32, WSACleanup); TB_INTERFACE_LOAD(ws2_32, WSASocketA); TB_INTERFACE_LOAD(ws2_32, WSAIoctl); TB_INTERFACE_LOAD(ws2_32, WSAGetLastError); TB_INTERFACE_LOAD(ws2_32, WSASend); TB_INTERFACE_LOAD(ws2_32, WSARecv); TB_INTERFACE_LOAD(ws2_32, WSASendTo); TB_INTERFACE_LOAD(ws2_32, WSARecvFrom); TB_INTERFACE_LOAD(ws2_32, bind); TB_INTERFACE_LOAD(ws2_32, send); TB_INTERFACE_LOAD(ws2_32, recv); TB_INTERFACE_LOAD(ws2_32, sendto); TB_INTERFACE_LOAD(ws2_32, recvfrom); TB_INTERFACE_LOAD(ws2_32, accept); TB_INTERFACE_LOAD(ws2_32, listen); TB_INTERFACE_LOAD(ws2_32, select); TB_INTERFACE_LOAD(ws2_32, connect); TB_INTERFACE_LOAD(ws2_32, shutdown); TB_INTERFACE_LOAD(ws2_32, getsockname); TB_INTERFACE_LOAD(ws2_32, getsockopt); TB_INTERFACE_LOAD(ws2_32, setsockopt); TB_INTERFACE_LOAD(ws2_32, ioctlsocket); TB_INTERFACE_LOAD(ws2_32, closesocket); TB_INTERFACE_LOAD(ws2_32, gethostname); TB_INTERFACE_LOAD(ws2_32, __WSAFDIsSet); // ok return tb_true; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_bool_t tb_kernel32_instance_init(tb_handle_t instance) { // check tb_kernel32_ref_t kernel32 = (tb_kernel32_ref_t)instance; tb_assert_and_check_return_val(kernel32, tb_false); // the kernel32 module HANDLE module = GetModuleHandleA("kernel32.dll"); if (!module) module = tb_dynamic_init("kernel32.dll"); tb_assert_and_check_return_val(module, tb_false); // init interfaces // TB_INTERFACE_LOAD(kernel32, CancelIoEx); TB_INTERFACE_LOAD(kernel32, RtlCaptureStackBackTrace); TB_INTERFACE_LOAD(kernel32, GetFileSizeEx); TB_INTERFACE_LOAD(kernel32, GetQueuedCompletionStatusEx); TB_INTERFACE_LOAD(kernel32, InterlockedCompareExchange64); // ok return tb_true; }
/* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ tb_bool_t tb_dns_init_env() { // done tb_size_t count = 0; tb_handle_t library = tb_dynamic_init("libresolv.dylib"); if (library) { // the res_ninit func tb_dns_res_ninit_func_t pres_ninit = (tb_dns_res_ninit_func_t)tb_dynamic_func(library, "res_9_ninit"); if (pres_ninit) { // init state struct __res_state state; if (!pres_ninit(&state)) { // walk it tb_size_t i = 0; for (i = 0; i < state.nscount; i++, count++) { // the address tb_char_t const* addr = inet_ntoa(state.nsaddr_list[i].sin_addr); tb_assert_and_check_continue(addr); // trace tb_trace_d("addr: %s", addr); // add address tb_dns_server_add(addr); } } } } // ok return tb_true; }
static tb_bool_t it_inject(pid_t pid, tb_char_t const* path) { // check tb_assert_and_check_return_val(pid && path, tb_false); // trace tb_trace_d("inject: pid: %lu, path: %s: ..", (tb_size_t)pid, path); #ifdef TB_ARCH_ARM64 // uses libsubstrate first? if (tb_file_info("/usr/lib/libsubstrate.dylib", tb_null)) { // init library tb_bool_t ok = tb_false; tb_handle_t library = tb_dynamic_init("/usr/lib/libsubstrate.dylib"); if (library) { // trace tb_trace_d("library: %p", library); // the func it_MSHookProcess_t pMSHookProcess = tb_dynamic_func(library, "MSHookProcess"); if (pMSHookProcess) { // trace tb_trace_d("MSHookProcess: %p", pMSHookProcess); // hook process ok = pMSHookProcess(pid, path)? tb_true : tb_false; } // exit library tb_dynamic_exit(library); // trace tb_trace_i("%s", ok? "ok" : "no"); // ok? return ok; } } #endif // pid => task task_t task = 0; if (task_for_pid(mach_task_self(), (tb_int_t)pid, &task)) { tb_trace_i("task_for_pid: %lu failed, errno: %d", (tb_size_t)pid, errno); return tb_false; } // trace tb_trace_d("task: %u", task); // stuff cpu_type_t cputype; it_addr_bundle_t addrs; if (!it_stuff(task, &cputype, &addrs)) return tb_false; // trace tb_trace_d("dlopen: %p", addrs.dlopen); tb_trace_d("syscall: %p", addrs.syscall); // alloc stack mach_vm_address_t stack_address = 0; if (mach_vm_allocate(task, &stack_address, it_stack_size, VM_FLAGS_ANYWHERE)) return tb_false; // write path mach_vm_address_t stack_end = stack_address + it_stack_size - 0x100; if (mach_vm_write(task, stack_address, (vm_offset_t)it_address_cast(path), strlen(path) + 1)) return tb_false; /* the first one is the return address * * syscall(SYS_bsdthread_create, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0) */ tb_uint32_t args_32[] = {0, 360, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0}; tb_uint64_t args_64[] = {0, 360, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0}; // init thread state union { it_arm_thread_state_t arm; it_arm_thread_state64_t arm64; it_x86_thread_state32_t x86; it_x86_thread_state64_t x64; natural_t nat; }state; thread_state_flavor_t state_flavor; mach_msg_type_number_t state_count; memset(&state, 0, sizeof(state)); // init thread state for the cpu type switch (cputype) { case CPU_TYPE_ARM: { tb_trace_i("cputype: arm"); memcpy(&state.arm.r[0], args_32 + 1, 4 * sizeof(tb_uint32_t)); if (mach_vm_write(task, stack_end, (vm_offset_t)it_address_cast(args_32 + 5), 2 * sizeof(tb_uint32_t))) return tb_false; state.arm.sp = (tb_uint32_t) stack_end; state.arm.pc = (tb_uint32_t) addrs.syscall; state.arm.lr = (tb_uint32_t) args_32[0]; state_flavor = ARM_THREAD_STATE; state_count = sizeof(state.arm) / sizeof(state.nat); // trace tb_trace_d("init: pc: %x", state.arm.pc); tb_trace_d("init: lr: %x", state.arm.lr); tb_trace_d("init: sp: %x", state.arm.sp); } break; case CPU_TYPE_ARM64: { tb_trace_i("cputype: arm64"); memcpy(&state.arm64.x[0], args_64 + 1, 6 * sizeof(tb_uint64_t)); state.arm64.sp = (tb_uint64_t) stack_end; // state.arm64.fp = (tb_uint64_t) stack_end; state.arm64.pc = (tb_uint64_t) addrs.syscall; state.arm64.lr = (tb_uint64_t) args_64[0]; state_flavor = ARM_THREAD_STATE64; state_count = sizeof(state.arm64) / sizeof(state.nat); // trace tb_trace_d("init: pc: %llx", state.arm64.pc); tb_trace_d("init: lr: %llx", state.arm64.lr); tb_trace_d("init: sp: %llx", state.arm64.sp); } break; case CPU_TYPE_X86: { tb_trace_i("cputype: x86"); if (mach_vm_write(task, stack_end, (vm_offset_t)it_address_cast(args_32), 7 * 4)) return tb_false; state.x86.esp = state.x86.ebp = (tb_uint32_t) stack_end; state.x86.eip = (tb_uint32_t)addrs.syscall; state_flavor = x86_THREAD_STATE32; state_count = sizeof(state.x86) / sizeof(state.nat); } break; case CPU_TYPE_X86_64: { tb_trace_i("cputype: x64"); state.x64.rdi = args_64[1]; state.x64.rsi = args_64[2]; state.x64.rdx = args_64[3]; state.x64.rcx = args_64[4]; state.x64.r8 = args_64[5]; state.x64.r9 = args_64[6]; state.x64.rsp = state.x64.rbp = stack_end; state.x64.rip = addrs.syscall; state_flavor = x86_THREAD_STATE64; state_count = sizeof(state.x64) / sizeof(state.nat); } break; default: tb_trace_i("cputype: unknown: %lx", (tb_size_t)cputype); return tb_false; } // init a remote thread thread_act_t thread = 0; if (thread_create(task, &thread)) return tb_false; // trace tb_trace_d("init: thread: %x", thread); // alloc port mach_port_t exc = 0; mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exc); if (mach_port_insert_right(mach_task_self(), exc, exc, MACH_MSG_TYPE_MAKE_SEND)) return tb_false; // swap port exception_mask_t em[2]; exception_handler_t eh[2]; exception_behavior_t eb[2]; thread_state_flavor_t ef[2]; mach_msg_type_number_t em_count = 2; if (task_swap_exception_ports(task, EXC_MASK_BAD_ACCESS, exc, EXCEPTION_STATE_IDENTITY, state_flavor, em, &em_count, eh, eb, ef)) return tb_false; tb_assert_and_check_return_val(em_count <= 1, tb_false); // resume thread, done: syscall(SYS_bsdthread_create, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0) if (thread_set_state(thread, state_flavor, &state.nat, state_count)) return tb_false; if (thread_resume(thread)) return tb_false; // we expect three exceptions: one from thread when it returns, one from the new thread when it calls the fake handler, and one from the new thread when it returns from dlopen. tb_bool_t started_dlopen = tb_false; while (1) { // recv msg it_exception_message_t msg; if (mach_msg_overwrite(tb_null, MACH_RCV_MSG, 0, sizeof(msg), exc, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, (tb_pointer_t) &msg, sizeof(msg))) return tb_false; // trace tb_trace_d("recv: msg: from thread: %x", msg.thread.name); // check tb_assert_and_check_return_val((msg.Head.msgh_bits & MACH_MSGH_BITS_COMPLEX), tb_false); tb_assert_and_check_return_val((msg.msgh_body.msgh_descriptor_count != 0), tb_false); tb_assert_and_check_return_val((msg.Head.msgh_size >= offsetof(it_exception_message_t, old_state)), tb_false); tb_assert_and_check_return_val((msg.old_stateCnt == state_count), tb_false); tb_assert_and_check_return_val((msg.Head.msgh_size >= offsetof(it_exception_message_t, old_state) + msg.old_stateCnt * sizeof(natural_t)), tb_false); // the msg state memcpy(&state, msg.old_state, sizeof(state)); // dump // tb_dump_data((tb_byte_t const*)&state, sizeof(state)); // done if (msg.thread.name == thread) { tb_trace_d("terminate"); if (thread_terminate(thread)) return tb_false; } else { // init cond tb_bool_t cond = tb_false; switch(cputype) { case CPU_TYPE_ARM: { // trace tb_trace_d("recv: pc: %x", state.arm.pc); tb_trace_d("recv: lr: %x", state.arm.lr); tb_trace_d("recv: sp: %x", state.arm.sp); // cond cond = ((state.arm.pc & ~1) == 0xdeadbeee)? tb_true : tb_false; } break; case CPU_TYPE_ARM64: { // trace tb_trace_d("recv: pc: %llx", state.arm64.pc); tb_trace_d("recv: lr: %llx", state.arm64.lr); tb_trace_d("recv: sp: %llx", state.arm64.sp); // cond cond = ((state.arm64.pc & ~1) == 0xdeadbeee)? tb_true : tb_false; } break; case CPU_TYPE_X86: cond = (state.x86.eip == 0xdeadbeef)? tb_true : tb_false; break; case CPU_TYPE_X86_64: cond = (state.x64.rip == 0xdeadbeef)? tb_true : tb_false; break; } tb_trace_d("cond: %d, started_dlopen: %d", cond, started_dlopen); if (!cond) { // let the normal crash mechanism handle it task_set_exception_ports(task, em[0], eh[0], eb[0], ef[0]); tb_assert_and_check_return_val(0, tb_false); } else if (started_dlopen) { tb_trace_d("terminate"); if (thread_terminate(msg.thread.name)) return tb_false; break; } else { // done: dlopen(path, RTLD_LAZY) switch(cputype) { case CPU_TYPE_ARM: { state.arm.r[0] = (tb_uint32_t) stack_address; state.arm.r[1] = RTLD_LAZY; state.arm.pc = (tb_uint32_t) addrs.dlopen; state.arm.lr = 0xdeadbeef; } break; case CPU_TYPE_ARM64: { state.arm64.x[0] = (tb_uint64_t) stack_address; state.arm64.x[1] = RTLD_LAZY; state.arm64.pc = (tb_uint64_t) addrs.dlopen; state.arm64.lr = 0xdeadbeef; } break; case CPU_TYPE_X86: { tb_uint32_t stack_stuff[3] = {0xdeadbeef, (tb_uint32_t)stack_address, RTLD_LAZY}; if (mach_vm_write(task, (mach_vm_address_t)state.x86.esp, (vm_offset_t)it_address_cast(&stack_stuff), sizeof(stack_stuff))) return tb_false; } state.x86.eip = (tb_uint32_t) addrs.dlopen; break; case CPU_TYPE_X86_64: { tb_uint64_t stack_stuff = 0xdeadbeef; if (mach_vm_write(task, (mach_vm_address_t)state.x64.rsp, (vm_offset_t)it_address_cast(&stack_stuff), sizeof(stack_stuff))) return tb_false; state.x64.rip = addrs.dlopen; state.x64.rdi = stack_address; state.x64.rsi = RTLD_LAZY; } break; } it_exception_reply_t reply; memcpy(&reply.Head, &msg.Head, sizeof(mach_msg_header_t)); reply.Head.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX; reply.Head.msgh_size = offsetof(it_exception_reply_t, new_state) + state_count * sizeof(natural_t); reply.Head.msgh_id += 100; memcpy(&reply.NDR, &msg.NDR, sizeof(NDR_record_t)); reply.RetCode = 0; reply.flavor = state_flavor; reply.new_stateCnt = state_count; memcpy(&reply.new_state, &state, sizeof(state)); if (thread_set_state(msg.thread.name, state_flavor, &state.nat, state_count)) return tb_false; if (mach_msg(&reply.Head, MACH_SEND_MSG, reply.Head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)) return tb_false; started_dlopen = tb_true; } } } // exit if (stack_address) vm_deallocate(task, stack_address, it_stack_size); if (thread) { thread_terminate(thread); mach_port_deallocate(mach_task_self(), thread); } if (task) mach_port_deallocate(mach_task_self(), task); if (exc) mach_port_deallocate(mach_task_self(), exc); // ok tb_trace_i("ok"); return tb_true; }