diff --git a/include/uc_priv.h b/include/uc_priv.h index 81a640fd..c45214eb 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -240,6 +240,7 @@ struct uc_struct { int thumb; // thumb mode for ARM // full TCG cache leads to middle-block break in the last translation? bool block_full; + int size_arg; // what tcg arg slot do we need to update with the size of the block? MemoryRegion **mapped_blocks; uint32_t mapped_block_count; uint32_t mapped_block_cache_index; diff --git a/qemu/target-arm/translate-a64.c b/qemu/target-arm/translate-a64.c index e869da01..11790a32 100644 --- a/qemu/target-arm/translate-a64.c +++ b/qemu/target-arm/translate-a64.c @@ -11115,7 +11115,10 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; + env->uc->size_arg = tcg_ctx->gen_opparam_buf - tcg_ctx->gen_opparam_ptr + 1; gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); + } else { + env->uc->size_arg = -1; } gen_tb_start(tcg_ctx); diff --git a/qemu/target-arm/translate.c b/qemu/target-arm/translate.c index d097c236..2ac5f47d 100644 --- a/qemu/target-arm/translate.c +++ b/qemu/target-arm/translate.c @@ -11233,7 +11233,10 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; + env->uc->size_arg = tcg_ctx->gen_opparam_buf - tcg_ctx->gen_opparam_ptr + 1; gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); + } else { + env->uc->size_arg = -1; } gen_tb_start(tcg_ctx); diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index e176c417..771b294b 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -8388,15 +8388,17 @@ static inline void gen_intermediate_code_internal(uint8_t *gen_opc_cc_op, dc->is_jmp = DISAS_NEXT; lj = -1; max_insns = tb->cflags & CF_COUNT_MASK; - if (max_insns <= 1) + if (max_insns == 0) max_insns = CF_COUNT_MASK; // Unicorn: trace this block on request - // Only hook this block if it is not broken from previous translation due to - // full translation cache + // Only hook this block if the previous block was not truncated due to space if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { env->uc->block_addr = pc_start; + env->uc->size_arg = tcg_ctx->gen_opparam_buf - tcg_ctx->gen_opparam_ptr + 1; gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); + } else { + env->uc->size_arg = -1; } gen_tb_start(tcg_ctx); diff --git a/qemu/target-m68k/translate.c b/qemu/target-m68k/translate.c index bf45a66a..f50ef2b4 100644 --- a/qemu/target-m68k/translate.c +++ b/qemu/target-m68k/translate.c @@ -3109,7 +3109,10 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb, if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; + env->uc->size_arg = tcg_ctx->gen_opparam_buf - tcg_ctx->gen_opparam_ptr + 1; gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); + } else { + env->uc->size_arg = -1; } gen_tb_start(tcg_ctx); diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index ea9aa453..cd6255b8 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -19217,7 +19217,10 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; + env->uc->size_arg = tcg_ctx->gen_opparam_buf - tcg_ctx->gen_opparam_ptr + 1; gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); + } else { + env->uc->size_arg = -1; } gen_tb_start(tcg_ctx); diff --git a/qemu/target-sparc/translate.c b/qemu/target-sparc/translate.c index 77dc4cb8..f1e1c801 100644 --- a/qemu/target-sparc/translate.c +++ b/qemu/target-sparc/translate.c @@ -5421,6 +5421,7 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; + env->uc->size_arg = tcg_ctx->gen_opparam_buf - tcg_ctx->gen_opparam_ptr + 1; gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); } diff --git a/qemu/translate-all.c b/qemu/translate-all.c index a476c0f7..c9787ca1 100644 --- a/qemu/translate-all.c +++ b/qemu/translate-all.c @@ -179,12 +179,12 @@ static int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_s gen_intermediate_code(env, tb); - // Unicorn: when tracing block, patch 1st operand for block size - if (env->uc->block_addr == tb->pc && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, tb->pc)) { + // Unicorn: when tracing block, patch block size operand for callback + if (env->uc->size_arg != -1 && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, tb->pc)) { if (env->uc->block_full) // block size is unknown - *(s->gen_opparam_buf + 1) = 0; + *(s->gen_opparam_buf + env->uc->size_arg) = 0; else - *(s->gen_opparam_buf + 1) = tb->size; + *(s->gen_opparam_buf + env->uc->size_arg) = tb->size; } /* generate machine code */ diff --git a/tests/regress/invalid_read_in_cpu_tb_exec.c b/tests/regress/invalid_read_in_cpu_tb_exec.c index d618c31a..7654c07e 100644 --- a/tests/regress/invalid_read_in_cpu_tb_exec.c +++ b/tests/regress/invalid_read_in_cpu_tb_exec.c @@ -1,7 +1,7 @@ #include static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { - printf("hook_block(…)\n"); + printf("hook_block(%p, %lx, %d, %p)\n", uc, address, size, user_data); } /* diff --git a/tests/regress/x86_self_modifying.elf b/tests/regress/x86_self_modifying.elf new file mode 100755 index 00000000..c8613d04 Binary files /dev/null and b/tests/regress/x86_self_modifying.elf differ diff --git a/tests/regress/x86_self_modifying.py b/tests/regress/x86_self_modifying.py new file mode 100755 index 00000000..189faa77 --- /dev/null +++ b/tests/regress/x86_self_modifying.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +from unicorn import * +from unicorn.x86_const import * +from struct import pack + +import os +import regress + +CODE_ADDR = 0x08048000 +STACK_ADDR = 0x2000000 +CODE = open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'x86_self_modifying.elf')).read() +CODE_SIZE = len(CODE) + (0x1000 - len(CODE)%0x1000) +STACK_SIZE = 0x8000 + +ENTRY_POINT = 0x8048074 + +def hook_intr(uc, intno, data): + uc.emu_stop() + +class SelfModifying(regress.RegressTest): + def test_self_modifying(self): + uc = Uc(UC_ARCH_X86, UC_MODE_32) + + uc.mem_map(CODE_ADDR, CODE_SIZE, 5) + uc.mem_map(STACK_ADDR, STACK_SIZE, 7) + uc.mem_write(CODE_ADDR, CODE) + uc.reg_write(UC_X86_REG_ESP, STACK_ADDR + STACK_SIZE) + + uc.hook_add(UC_HOOK_INTR, hook_intr) + + uc.emu_start(ENTRY_POINT, -1) + + retcode = uc.reg_read(UC_X86_REG_EBX) + self.assertEqual(retcode, 65) + +if __name__ == '__main__': + regress.main() diff --git a/tests/regress/x86_self_modifying.s b/tests/regress/x86_self_modifying.s new file mode 100644 index 00000000..86a5114e --- /dev/null +++ b/tests/regress/x86_self_modifying.s @@ -0,0 +1,51 @@ +.intel_syntax noprefix + +.global _start +_start: + mov ebp, esp + sub ebp, 0x4000 + mov edx, ebp + + lea esi, [self_modifying] + mov edi, ebp + mov ecx, 0x2d + call memcpy + add ebp, 0x2d + xor ebx, ebx + call edx + + mov eax, 1 + int 0x80 + +memcpy: + cmp ecx, 0 + je _end + dec ecx + mov al, byte ptr [esi+ecx] + mov byte ptr [edi+ecx], al + jmp memcpy + +_end: + ret + +self_modifying: + inc ebx + call $+5 + pop esi + dec byte ptr [esi+11] + xor edx, edx + sub esi, 6 +_loop_start: + cmp edx, 5 + jz _loop_end + + mov edi, ebp + mov ecx, 0x2d + lea eax, [memcpy] + call eax + inc edx + add ebp, 0x2d + mov byte ptr [ebp], 0xc3 + jmp _loop_start + +_loop_end: