Created
November 29, 2020 18:33
-
-
Save wumb0/da8fc7865da2489d3148b65d3baa54cd to your computer and use it in GitHub Desktop.
command line assembly emulator that allows you to quickly see the results of instructions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# requires keystone-engine, capstone, prompt_toolkit, and pygments | |
import keystone as ks | |
import unicorn as uc | |
import math | |
import sys | |
from pygments.lexers.asm import NasmLexer | |
from pygments.styles import get_style_by_name | |
from prompt_toolkit.shortcuts import prompt | |
from prompt_toolkit.lexers import PygmentsLexer | |
from prompt_toolkit.validation import Validator, ValidationError | |
from prompt_toolkit.styles.pygments import style_from_pygments_cls | |
k = ks.Ks(ks.KS_ARCH_X86, ks.KS_MODE_LITTLE_ENDIAN|ks.KS_MODE_64) | |
code_base = 0x1000 | |
stack_base = 0x10000 | |
class AsmVal(Validator): | |
def validate(self, doc): | |
if not doc.text: | |
raise ValidationError(message="Invalid input") | |
try: | |
k.asm(doc.text, code_base, True) | |
except: | |
raise ValidationError(message="Invalid assembly syntax") | |
def emulate(data): | |
asm = k.asm(data, code_base, True) | |
u = uc.Uc(uc.UC_ARCH_X86, uc.UC_MODE_LITTLE_ENDIAN|uc.UC_MODE_64) | |
u.mem_map(code_base, int(math.ceil(len(asm[0]) / float(0x1000))) * 0x1000) | |
u.mem_map(stack_base, 0x2000, uc.UC_PROT_READ | uc.UC_PROT_WRITE) | |
u.mem_write(code_base, asm[0]) | |
u.reg_write(uc.x86_const.UC_X86_REG_RIP, code_base) | |
u.reg_write(uc.x86_const.UC_X86_REG_RSP, stack_base) | |
regs = ["RIP", "RAX", "RBX", "RCX", "RDX", "RSI", "RDI", "RSP", "RBP", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"] | |
u.emu_start(0x1000, 0x1000 + len(asm[0]), count=asm[1]) | |
for reg in regs: | |
print("{}:\t0x{:016x}".format(reg, u.reg_read(getattr(uc.x86_const, "UC_X86_REG_" + reg)))) | |
print("FLAGS:") | |
ef = u.reg_read(uc.x86_const.UC_X86_REG_EFLAGS) | |
flags = {"CF": 0, "PF": 2, "AF": 4, "ZF": 6, "SF": 7, "TF": 8, "IF": 9, "DF": 10, "OF": 11} | |
for name, bit in flags.items(): | |
print(f"\t{name}: {ef & (1 << bit) == (1 << bit)}") | |
if len(sys.argv) > 1: | |
data = open(sys.argv[1]).read() | |
emulate(data) | |
else: | |
data = "" | |
while 1: | |
try: | |
style = style_from_pygments_cls(get_style_by_name('colorful')) | |
data = prompt("Enter some assembly\n", multiline=True, validator=AsmVal(), lexer=PygmentsLexer(NasmLexer), default=data, style=style) | |
except KeyboardInterrupt: | |
break | |
emulate(data) | |
print() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment