Skip to content

Instantly share code, notes, and snippets.

@BinaryResearch
Last active January 10, 2020 17:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BinaryResearch/9bca1b5b0b4b03c8d0a3ec01696cf650 to your computer and use it in GitHub Desktop.
Save BinaryResearch/9bca1b5b0b4b03c8d0a3ec01696cf650 to your computer and use it in GitHub Desktop.
Assemble and emulate snippets of x86-64 assembly code using Keystone and Unicorn
#!/usr/bin/python3
from keystone import *
from capstone import *
from unicorn import *
from unicorn.x86_const import *
# GCC - 9 divided by 5
# from https://stackoverflow.com/questions/41183935/why-does-gcc-use-multiplication-by-a-strange-number-in-implementing-integer-divi
ASM = "mov rax, 9; \
movabs rdx, -3689348814741910323; \
mul rdx; \
mov rax, rdx; \
shr rax, 2;"
def assemble_snippet():
try:
ks = Ks(KS_ARCH_X86, KS_MODE_64) # initialize assembler object
encoding, count = ks.asm(ASM) # save results of assembly
except KsError as e:
print("ERROR: %s" %e)
return bytes(encoding) # return assembled object code
# callback for tracing instructions
def hook_code(uc, address, size, user_data):
# print contents of registers of interest
print("RAX = 0x%x" % uc.reg_read(UC_X86_REG_RAX))
print("RDX = 0x%x" % uc.reg_read(UC_X86_REG_RDX))
print("=================================================")
# print disassembly of intruction stream
instruction = uc.mem_read(address, size)
md = user_data
for i in md.disasm(instruction, address):
print(">>> 0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str))
# from https://github.com/unicorn-engine/unicorn/blob/8621bca53758532ad6a4ec5d17684fcdb9923cc6/bindings/python/sample_x86.py#L475
def emulate():
ADDRESS = 0x1000000 # memory address where emulation starts
CODE = assemble_snippet() # object code to emulate
mu = Uc(UC_ARCH_X86, UC_MODE_64) # Initialize emulator in X86-64bit mode
mu.mem_map(ADDRESS, 2 * 1024 * 1024) # map 2MB memory for this emulation
mu.mem_write(ADDRESS, CODE) # map machine code to be emulated to memory
mu.reg_write(UC_X86_REG_RSP, ADDRESS + 0x200000) # set up stack
md = Cs(CS_ARCH_X86, CS_MODE_64) # initialize disassembly engine
mu.hook_add(UC_HOOK_CODE, hook_code, md) # pass diassembly engine to hook
print("Initial state:")
try:
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + len(CODE))
except UcError as e:
print("ERROR: %s" % e)
# final state
print("RAX = 0x%x" % mu.reg_read(UC_X86_REG_RAX))
print("RDX = 0x%x" % mu.reg_read(UC_X86_REG_RDX))
print("\n>>>Emulation complete.")
if __name__ == "__main__":
emulate()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment