unicorn
unicorn copied to clipboard
Existence of HOOK_CODE changes behavior of HOOK_BLOCK
I have a unicorn instance hooking functions via the HOOK_BLOCK
callback. In that callback I alter the stack and the IP.
This method worked fine for me in versions up until version 2.0.rc7 (rc6 and 1.0.3 worked fine).
When I changed the callback from HOOK_BLOCK
to HOOK_CODE
(in the newer version) the code worked fine.
The weird thing is that if I do something like this
temp_hook = uc.hook_add(UC_HOOK_CODE, temp_func)
uc.hook_del(temp_hook)
block_hook = uc.hook_add(UC_HOOK_BLOCK, block_callback)
then the code works as it was before.
Even before doing emu_start
it seems to matter somehow.
I have the exact same issue. My arm64 code is jumping to a block that is hooked with HOOK_BLOCK
, I then handle it in my own code and set the X0
and PC
so the arm64 code resumes. This used to work fine with Unicorn 1. Now, when I run the same code it fails to work properly and keeps calling the block, creating an infinite loop.
Then, I added a HOOK_CODE
block in an attempt to debug it. To my confusion it started working after I added the debug hook.
I will attempt to create a small repro.
Here is a repro of the issue.
from unicorn import *
from unicorn.arm64_const import *
# MOV x0, #1234
# MOV x1, #2345
# MOV x2, #4331
# LDR x9, =0x2000
# BLR x9
# MOV x8, x2
code_1 = '409A80D2212581D2621D82D2090084D220013FD6E80302AA'
addr_1 = 0x1000
# MOV x2, #9999
# RET
code_2 = 'E2E184D2C0035FD6'
addr_2 = 0x2000
def hook_code(uc_, address, size, user_data):
print('Called hook_code')
pass
def hook_block(uc_, address, size, user_data):
print('Called hook_block')
uc_.reg_write(UC_ARM64_REG_X2, 1337)
uc_.reg_write(UC_ARM64_REG_PC, uc_.reg_read(UC_ARM64_REG_LR))
uc = Uc(UC_ARCH_ARM64, UC_MODE_ARM)
uc.mem_map(addr_1, 0x1000)
uc.mem_map(addr_2, 0x2000)
uc.mem_write(addr_1, bytes.fromhex(code_1))
uc.mem_write(addr_2, bytes.fromhex(code_2))
# uc.hook_del(uc.hook_add(UC_HOOK_CODE, hook_code))
uc.hook_add(UC_HOOK_BLOCK, hook_block, user_data=None, begin=addr_2, end=addr_2 + 4)
uc.emu_start(addr_1, until=addr_1 + len(code_1) // 2)
print('x2 = 1337 (EXPECTED)')
print('x2 = %d (ACTUAL)' % uc.reg_read(UC_ARM64_REG_X2))
This code will infinite loop with the Unicorn 2.0.0 tag.
If you uncomment uc.hook_del(uc.hook_add(UC_HOOK_CODE, hook_code))
it will work.
Reverting commit https://github.com/unicorn-engine/unicorn/commit/b7bc13650c56ebaad47264c7c7cf5a5a72e25fd4 fixes the issue.
Fixed in c4a0813
@wtdcode The commit linked is a test case, where is the actual fix commited?
092014a6cc85ee94b42646eed2db4a98012e1e31