Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignoring a Branchs/Handling Invalid Memory Access Handling Gracefully #1949

Open
pinwhell opened this issue Apr 29, 2024 · 4 comments
Open

Comments

@pinwhell
Copy link

say for arm64 how to handle branches outside of a region, assuming all branchs set the link register, how to gracefully simply come back without Halting the entire emulatino with an exception? also how to ignore all memory access attempt, and return 0 instead? can unicorn let me do this in python?

@wtdcode
Copy link
Member

wtdcode commented May 6, 2024

I fail to get your point. Could you show a few code snippets to illustrate your use case better?

@pinwhell
Copy link
Author

pinwhell commented May 7, 2024

from unicorn import *
from unicorn.arm_const import *

def hook_mem_invalid(uc, access, address, size, value, user_data):
    # Allocate a new page of memory at the accessed address

    if access == UC_MEM_READ_UNMAPPED:
        print("Remapping 0x{:X}".format(address & 0xFFFFF000))
        uc.mem_map(address & 0xFFFFF000, 0x1000)
        uc.mem_write(address & 0xFFFFF000, bytes.fromhex("70 00 20 E1")) # BKPT #0

    return True

def hook_intr(uc, int, user_data):
    print("Interrupt {} Detected".format(int))
    print("Assuming Remap BKPT Source")
    print("Jmping Back to LR")

    uc.reg_write(UC_ARM_REG_PC, uc.reg_read(UC_ARM_REG_LR))

    return True

def emulate_code():
    # Define the ARM code to be emulated
    ARM_CODE =  bytes.fromhex("01 06 A0 E3")  # MOV r0, 0x100000
    ARM_CODE += bytes.fromhex("00 10 90 E5")  # LDR r1, [r0] ; Load contents of memory at address stored in r0 into r1
    ARM_CODE += bytes.fromhex("30 FF 2F E1")  # BLX r0
    ARM_CODE += bytes.fromhex("02 06 A0 E3")  # MOV r0, 0x200000

    # Initialize Unicorn emulator
    uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)

    # Memory region for code
    ADDRESS = 0x1000
    uc.mem_map(ADDRESS, 0x1000)
    uc.mem_write(ADDRESS, ARM_CODE)

    # Set up hook for invalid memory access
    uc.hook_add(UC_HOOK_MEM_INVALID, hook_mem_invalid)

    # Set up hook for interrupts
    uc.hook_add(UC_HOOK_INTR, hook_intr)

    # Emulate code
    try:
        # Emulate code starting at address 0x1000
        uc.emu_start(ADDRESS, ADDRESS + len(ARM_CODE))

    except UcError as e:
        print("Error:", e)

    # Log register state after emulation
    print("Register state after emulation:")
    index = 0
    for reg in range(UC_ARM_REG_R0, UC_ARM_REG_R12 + 1):
        print("  R{}: 0x{:x}".format(index, uc.reg_read(reg)))
        index += 1
    print("  LR: 0x{:x}".format(uc.reg_read(UC_ARM_REG_LR)))
    print("  PC: 0x{:x}".format(uc.reg_read(UC_ARM_REG_PC)))


if __name__ == "__main__":
    emulate_code()

take this as example, it does what i initially wanted, gives this output:

Remapping 0x100000
Interrupt 7 Detected
Assuming Remap BKPT Source
Jmping Back to LR
Register state after emulation:
  R0: 0x200000
  R1: 0xe1200070
...
  LR: 0x100c
  PC: 0x1010

Process finished with exit code 0

it successfully reached

MOV r0, 0x200000

ignoring the branch

it is currently constrained to ARM, is there any way to make it more general?

@pinwhell
Copy link
Author

pinwhell commented May 7, 2024

not triggering the read fault with LDR

    # Define the ARM code to be emulated
    ARM_CODE =  bytes.fromhex("01 06 A0 E3")  # MOV r0, 0x100000
    # ARM_CODE += bytes.fromhex("00 10 90 E5")  # LDR r1, [r0] ; Load contents of memory at address stored in r0 into r1
    ARM_CODE += bytes.fromhex("30 FF 2F E1")  # BLX r0
    ARM_CODE += bytes.fromhex("02 06 A0 E3")  # MOV r0, 0x200000

and handling for all faults

def hook_mem_invalid(uc, access, address, size, value, user_data):
    # Allocate a new page of memory at the accessed address

    print("Remapping 0x{:X}".format(address & 0xFFFFF000))
    uc.mem_map(address & 0xFFFFF000, 0x1000)
    uc.mem_write(address & 0xFFFFF000, bytes.fromhex("70 00 20 E1"))  # BKPT #0

    return True

also works

  R0: 0x200000
...
  LR: 0x1008
  PC: 0x100c

Process finished with exit code 0

@pinwhell
Copy link
Author

pinwhell commented May 7, 2024

I fail to get your point. Could you show a few code snippets to illustrate your use case better?

so overall, the initial question in other, words, is there any way to generalize this behavior & convert it to platform agnostic, is there any way to simply hook branches and cancel them all? without relying on hooking instructions and checking for specific instructions ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants