[Possible Bug] Fetch rip-based address failure with UC_ERR_FETCH_UNMAPPED
Author: TommyJerryMairoCreated Nov 12, 2023Updated Aug 9, 2026
Labelsbugpoc
Describe the bug
When executing rip-based indirect call instruction, the emulated CPU attempts to fetch at an unrelated address, which is unexpected and raises a UC_ERR_FETCH_UNMAPPED error.
To Reproduce
- Download and save the proof-of-concept script
unicorn-indircall.pyto a local system - Execute the script with python
Expected behaviour
The script exits succeed with the result printed
Actual output
$ python unicorn-indircall.py
>>> Tracing instruction at 0x0000000001000000, instruction size = 0x0000000000000006
>>> RIP is 0x0000000001000000
!!! Unicorn Engine Exception: Invalid memory fetch (UC_ERR_FETCH_UNMAPPED)
!!! RIP is 0x7d894853e5894855
$Environment
- OS: ArchLinux w/ up-to-date upgrades
- Python: 3.11.5
- Unicorn Engine: 2.0.1
Proof-of-Concept: unicorn-indircall.py
#!/usr/bin/env python
from unicorn import *
from unicorn.x86_const import *
import os
# 0: ff 15 3e 00 00 00 call QWORD PTR [rip+0x3e] # 0x44
# 6: 90 nop
# ......
# 43: 90 nop
# 44: 55 push rbp
# 45: 48 89 e5 mov rbp, rsp
# 48: 53 push rbx
# 49: 48 89 7d f0 mov QWORD PTR [rbp-0x10], rdi
# 4d: 48 8b 5d f0 mov rbx, QWORD PTR [rbp-0x10]
# 51: eb 04 jmp 0x57
# 53: 48 83 c3 01 add rbx, 0x1
# 57: 0f b6 03 movzx eax, BYTE PTR [rbx]
# 5a: 84 c0 test al, al
# 5c: 75 f5 jne 0x53
# 5e: 48 89 d8 mov rax, rbx
# 61: 48 2b 45 f0 sub rax, QWORD PTR [rbp-0x10]
# 65: 48 8b 5d f8 mov rbx, QWORD PTR [rbp-0x8]
# 69: c9 leave
# 6a: c3 ret
X86_CODE64 = b'\xff\x15\x3e\x00\x00\x00'+b'\x90'*62+b'\x55\x48\x89\xe5\x53\x48\x89\x7d\xf0\x48\x8b\x5d\xf0\xeb\x04\x48\x83\xc3\x01\x0f\xb6\x03\x84\xc0\x75\xf5\x48\x89\xd8\x48\x2b\x45\xf0\x48\x8b\x5d\xf8\xc9\xc3'
ADDRESS = 0x1000000
DATA_ADDR = ADDRESS+1024*1024
STACK_ADDR = ADDRESS+2*1024*1024-16
def hook_code64(uc, address, size, user_data):
print(f">>> Tracing instruction at {address:#0{18}x}, instruction size = {size:#0{18}x}")
rip = uc.reg_read(UC_X86_REG_RIP)
print(f">>> RIP is {rip:#0{18}x}");
def main():
data = os.urandom(4096)
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(ADDRESS, 144*1024*1024)
mu.mem_write(ADDRESS, X86_CODE64)
mu.mem_write(DATA_ADDR, data)
mu.reg_write(UC_X86_REG_RSP, STACK_ADDR)
mu.reg_write(UC_X86_REG_RDI, DATA_ADDR)
mu.hook_add(UC_HOOK_CODE, hook_code64)
try:
mu.emu_start(ADDRESS,ADDRESS+8)
print(f"Result={mu.reg_read(UC_X86_REG_RAX):#0{18}x}")
except UcError as err:
print(f"!!! Unicorn Engine Exception: {err}")
print(f"!!! RIP is {mu.reg_read(UC_X86_REG_RIP):#0{18}x}")
if __name__ == '__main__':
main()
Source: unicorn-engine/unicorn