ZZSTATUS ZzBuildHalfTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { zbyte temp_code_slice_data[256] = {0}; ZzArm64Writer *arm64_writer = NULL; ZzCodeSlice *code_slice = NULL; ZzArm64HookFunctionEntryBackend *entry_backend = (ZzArm64HookFunctionEntryBackend *)entry->backend; ZZSTATUS status = ZZ_SUCCESS; zaddr target_addr = (zaddr)entry->target_ptr; arm64_writer = &self->arm64_writer; zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); /* prepare 2 stack space: 1. next_hop 2. entry arg */ zz_arm64_writer_put_sub_reg_reg_imm(arm64_writer, ZZ_ARM64_REG_SP, ZZ_ARM64_REG_SP, 2 * 0x8); zz_arm64_writer_put_ldr_b_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry); zz_arm64_writer_put_str_reg_reg_offset(arm64_writer, ZZ_ARM64_REG_X17, ZZ_ARM64_REG_SP, 0x0); /* jump to half thunk */ zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)self->half_thunk); /* code patch */ code_slice = zz_code_patch_arm64_writer(arm64_writer, self->allocator, 0, 0); if (code_slice) entry->on_half_trampoline = code_slice->data; else return ZZ_FAILED; return status; }
ZZSTATUS ZzBuildEnterTransferTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { zbyte temp_code_slice_data[256] = {0}; ZzArm64Writer *arm64_writer = NULL; ZzCodeSlice *code_slice = NULL; ZzArm64HookFunctionEntryBackend *entry_backend = (ZzArm64HookFunctionEntryBackend *)entry->backend; ZZSTATUS status = ZZ_SUCCESS; zaddr target_addr = (zaddr)entry->target_ptr; arm64_writer = &self->arm64_writer; zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry->on_enter_trampoline); code_slice = zz_code_patch_arm64_writer(arm64_writer, self->allocator, target_addr, zz_arm64_writer_near_jump_range_size()); if (code_slice) entry->on_enter_transfer_trampoline = code_slice->data; else return ZZ_FAILED; if (ZzIsEnableDebugMode()) { char buffer[1024] = {}; sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildEnterTransferTrampoline:"); sprintf(buffer + strlen(buffer), "LogInfo: on_enter_transfer_trampoline at %p, length: %ld. and will jump to on_enter_trampoline(%p).\n", code_slice->data, code_slice->size, entry->on_enter_trampoline); ZzInfoLog("%s", buffer); } free(code_slice); return status; }
ZZSTATUS ZzBuildEnterTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { zbyte temp_code_slice_data[256] = {0}; ZzArm64Writer *arm64_writer = NULL; ZzCodeSlice *code_slice = NULL; ZzArm64HookFunctionEntryBackend *entry_backend = (ZzArm64HookFunctionEntryBackend *)entry->backend; ZZSTATUS status = ZZ_SUCCESS; zaddr target_addr = (zaddr)entry->target_ptr; arm64_writer = &self->arm64_writer; zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); /* prepare 2 stack space: 1. next_hop 2. entry arg */ zz_arm64_writer_put_sub_reg_reg_imm(arm64_writer, ZZ_ARM64_REG_SP, ZZ_ARM64_REG_SP, 2 * 0x8); zz_arm64_writer_put_ldr_b_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry); zz_arm64_writer_put_str_reg_reg_offset(arm64_writer, ZZ_ARM64_REG_X17, ZZ_ARM64_REG_SP, 0x0); /* jump to enter thunk */ zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)self->enter_thunk); /* code patch */ code_slice = zz_code_patch_arm64_writer(arm64_writer, self->allocator, 0, 0); if (code_slice) entry->on_enter_trampoline = code_slice->data; else return ZZ_FAILED; /* debug log */ if (ZzIsEnableDebugMode()) { char buffer[1024] = {}; sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildEnterTrampoline:"); sprintf(buffer + strlen(buffer), "LogInfo: on_enter_trampoline at %p, length: %ld. hook-entry: %p. and will jump to enter_thunk(%p).\n", code_slice->data, code_slice->size, (void *)entry, (void *)self->enter_thunk); ZzInfoLog("%s", buffer); } if (entry_backend->redirect_code_size == ZZ_ARM64_TINY_REDIRECT_SIZE) { ZzBuildEnterTransferTrampoline(self, entry); } free(code_slice); return status; }
ZZSTATUS ZzActivateTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { zbyte temp_code_slice_data[256] = {0}; ZzCodeSlice *code_slice = NULL; ZzArm64HookFunctionEntryBackend *entry_backend = (ZzArm64HookFunctionEntryBackend *)entry->backend; ZZSTATUS status = ZZ_SUCCESS; zaddr target_addr = (zaddr)entry->target_ptr; ZzArm64Writer *arm64_writer; arm64_writer = &self->arm64_writer; zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); arm64_writer->pc = target_addr; if (entry_backend->redirect_code_size == ZZ_ARM64_TINY_REDIRECT_SIZE) { zz_arm64_writer_put_b_imm(arm64_writer, (zaddr)entry->on_enter_transfer_trampoline - (zaddr)arm64_writer->pc); } else { zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry->on_enter_trampoline); } if (!ZzMemoryPatchCode((zaddr)target_addr, arm64_writer->base, arm64_writer->size)) status = ZZ_FAILED; return status; }
ZZSTATUS ZzBuildInvokeTrampoline(ZzInterceptorBackend *self, ZzHookFunctionEntry *entry) { zbyte temp_code_slice_data[256] = {0}; ZzCodeSlice *code_slice = NULL; ZzArm64HookFunctionEntryBackend *entry_backend = (ZzArm64HookFunctionEntryBackend *)entry->backend; ZZSTATUS status = ZZ_SUCCESS; zaddr target_addr = (zaddr)entry->target_ptr; zpointer restore_target_addr; ZzArm64Relocator *arm64_relocator; ZzArm64Writer *arm64_writer; arm64_relocator = &self->arm64_relocator; arm64_writer = &self->arm64_writer; zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); zz_arm64_relocator_reset(arm64_relocator, (zpointer)target_addr, arm64_writer); zsize tmp_relocator_insn_size = 0; entry->target_half_ret_addr = 0; if (entry->hook_type == HOOK_FUNCTION_TYPE) { do { zz_arm64_relocator_read_one(arm64_relocator, NULL); tmp_relocator_insn_size = arm64_relocator->input_cur - arm64_relocator->input_start; } while (tmp_relocator_insn_size < entry_backend->redirect_code_size); zz_arm64_relocator_write_all(arm64_relocator); } else if (entry->hook_type == HOOK_ADDRESS_TYPE) { do { zz_arm64_relocator_read_one(arm64_relocator, NULL); zz_arm64_relocator_write_one(arm64_relocator); tmp_relocator_insn_size = arm64_relocator->input_cur - arm64_relocator->input_start; if (arm64_relocator->input_cur >= entry->target_end_ptr && !entry->target_half_ret_addr) { zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)entry->on_half_trampoline); entry->target_half_ret_addr = (zpointer)arm64_writer->size; } } while (tmp_relocator_insn_size < entry_backend->redirect_code_size || arm64_relocator->input_cur < entry->target_end_ptr); } /* jump to rest target address */ restore_target_addr = (zpointer)((zaddr)target_addr + tmp_relocator_insn_size); zz_arm64_writer_put_ldr_br_reg_address(arm64_writer, ZZ_ARM64_REG_X17, (zaddr)restore_target_addr); /* code patch */ code_slice = zz_code_patch_arm64_relocate_writer(arm64_relocator, arm64_writer, self->allocator, 0, 0); if (code_slice) entry->on_invoke_trampoline = code_slice->data; else return ZZ_FAILED; /* update target_half_ret_addr */ if (entry->hook_type == HOOK_ADDRESS_TYPE) { entry->target_half_ret_addr += (zaddr)code_slice->data; } /* debug log */ if (ZzIsEnableDebugMode()) { char buffer[1024] = {0}; sprintf(buffer + strlen(buffer), "%s\n", "ZzBuildInvokeTrampoline:"); sprintf(buffer + strlen(buffer), "LogInfo: on_invoke_trampoline at %p, length: %ld. and will jump to rest code(%p).\n", code_slice->data, code_slice->size, restore_target_addr); sprintf(buffer + strlen(buffer), "ArmInstructionFix: origin instruction at %p, relocator end at %p, relocator instruction nums %ld\n", (&self->arm64_relocator)->input_start, (&self->arm64_relocator)->input_cur, (&self->arm64_relocator)->inpos); char origin_prologue[256] = {0}; int t = 0; zpointer p; for (p = (&self->arm64_relocator)->input_start; p < (&self->arm64_relocator)->input_cur; p++, t = t + 5) { sprintf(origin_prologue + t, "0x%.2x ", *(unsigned char *)p); } sprintf(buffer + strlen(buffer), "origin_prologue: %s\n", origin_prologue); ZzInfoLog("%s", buffer); } free(code_slice); return status; }
ZZSTATUS ZzThunkerBuildThunk(ZzInterceptorBackend *self) { char temp_code_slice_data[512] = {0}; ZzArm64Writer *arm64_writer = NULL; ZzCodeSlice *code_slice = NULL; ZZSTATUS status = ZZ_SUCCESS; arm64_writer = &self->arm64_writer; zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); /* build enter_thunk */ zz_arm64_thunker_build_enter_thunk(arm64_writer); /* code patch */ code_slice = zz_code_patch_arm64_writer(arm64_writer, self->allocator, 0, 0); if (code_slice) self->enter_thunk = (void *)enter_thunk_template; // self->enter_thunk = code_slice->data; else return ZZ_FAILED; /* debug log */ if (ZzIsEnableDebugMode()) { char buffer[1024] = {}; sprintf(buffer + strlen(buffer), "%s\n", "ZzThunkerBuildThunk:"); sprintf(buffer + strlen(buffer), "LogInfo: enter_thunk at %p, use enter_thunk_template.\n", (void *)enter_thunk_template); // sprintf(buffer + strlen(buffer), "LogInfo: enter_thunk at %p, length: %ld.\n", code_slice->data, // code_slice->size); ZzDebugInfoLog("%s", buffer); } zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); /* build leave_thunk */ zz_arm64_thunker_build_leave_thunk(arm64_writer); /* code patch */ code_slice = zz_code_patch_arm64_writer(arm64_writer, self->allocator, 0, 0); if (code_slice) self->leave_thunk = code_slice->data; else return ZZ_FAILED; /* debug log */ if (ZzIsEnableDebugMode()) { char buffer[1024] = {}; sprintf(buffer + strlen(buffer), "%s\n", "ZzThunkerBuildThunk:"); sprintf(buffer + strlen(buffer), "LogInfo: leave_thunk at %p, length: %ld.\n", code_slice->data, code_slice->size); ZzDebugInfoLog("%s", buffer); } zz_arm64_writer_reset(arm64_writer, temp_code_slice_data); /* build half_thunk */ zz_arm64_thunker_build_half_thunk(arm64_writer); /* code patch */ code_slice = zz_code_patch_arm64_writer(arm64_writer, self->allocator, 0, 0); if (code_slice) self->half_thunk = code_slice->data; else return ZZ_FAILED; /* debug log */ if (ZzIsEnableDebugMode()) { char buffer[1024] = {}; sprintf(buffer + strlen(buffer), "%s\n", "ZzThunkerBuildThunk:"); sprintf(buffer + strlen(buffer), "LogInfo: half_thunk at %p, length: %ld.\n", code_slice->data, code_slice->size); ZzDebugInfoLog("%s", buffer); } return status; }