Exemple #1
0
/* //////////////////////////////////////////////////////////////////////////////////////
 * 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;
}
Exemple #2
0
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;
}