Skip to content

Instantly share code, notes, and snippets.

@mkow
Created April 4, 2018 20:25
Show Gist options
  • Save mkow/b8784816777cde5f7b877d9ea17da8ba to your computer and use it in GitHub Desktop.
Save mkow/b8784816777cde5f7b877d9ea17da8ba to your computer and use it in GitHub Desktop.
Baby VM - 0CTF 2018 - solver
from struct import pack
def make_insn(op, mode):
assert 0 <= op < 0x40
assert 0 <= mode < 4
return chr(op | (mode << 6))
DATA = 0
ADDR = 2
BOOL = 3
SYS_OPEN = 0
SYS_READ = 1
SYS_IOCTL = 2
SYS_PUTS = 3
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
GENERIC_EXECUTE = 0x20000000
GENERIC_ALL = 0x10000000
FILE_READ_DATA = 0x0001
FILE_ATTRIBUTE_NORMAL = 0x00000080
# OP=0, EXIT
def exit():
return make_insn(0, 0)
# OP=1, RET??
def ret_push_2():
return make_insn(1, 0)
# OP=2, SYSCALL
def syscall():
return make_insn(2, 0)
# OP=5, RET
def ret():
return make_insn(5, 0)
# OP=6, JNZ (bool, dest)
def jnz():
return make_insn32(6, 0)
# OP=7, PUSH0
def push_0():
return make_insn(7, 0)
# OP=8, PUSH1
def push_1():
return make_insn(8, 0)
# OP=13, PUSH_ADDR
def push_byte_addr(arg):
return make_insn(13, 0) + chr(arg)
def push_word_addr(arg):
return make_insn(13, 1) + pack('<H', arg)
def push_dword_addr(arg):
assert arg <= 0x3fffffff
return make_insn(13, 2) + pack('<I', arg)
def push_acc_addr():
return make_insn(13, 3)
# OP=14, PUSH_DATA
def push_byte_data(arg):
return make_insn(14, 0) + chr(arg)
def push_word_data(arg):
return make_insn(14, 1) + pack('<H', arg)
def push_dword_data(arg):
assert arg <= 0x3fffffff
return make_insn(14, 2) + pack('<I', arg)
def push_acc_data():
return make_insn(14, 3)
# OP=15, POP_ACC
def pop_acc():
return make_insn(15, 0)
# OP=16, DUP
def dup():
return make_insn(16, 0)
# OP=17, NOT
def not_():
return make_insn(17, 0)
# OP=18, ADD
def add():
return make_insn(18, 0)
# OP=19, SUB
def sub():
return make_insn(19, 0)
# OP=20, MUL
def mul():
return make_insn(20, 0)
# OP=21, DIV
def div():
return make_insn(21, 0)
# OP=22, MOD
def mod():
return make_insn(22, 0)
# OP=23, PUSH3_IF_LT_32
# BITSCAN which doesn't work?
def push3_if_lt_32():
return make_insn(23, 0)
# OP=24, AND
def and_():
return make_insn(24, 0)
# OP=25, OR
def or_():
return make_insn(25, 0)
# OP=24, AND
def and_():
return make_insn(24, 0)
#OP 26-31: drop + push3 ?
##################################################
# Payload
##################################################
# data section
data = ''
cur_addr = 0x8000
def decl_bytes(s):
global data, cur_addr
res = cur_addr
data += s
cur_addr += len(s)
return res
def decl_str(s):
global data, cur_addr
res = cur_addr
data += chr(len(s)) + s
cur_addr += 1 + len(s)
return res
flag_txt = decl_str(r'''flag.txt''')
decl_bytes('\0')
marker_1 = decl_bytes('MARKER #1\n\0')
marker_2 = decl_bytes('MARKER #2\n\0')
marker_3 = decl_bytes('MARKER #3\n\0')
# code section
code = ''
code += push_dword_addr(marker_1)
code += push_dword_data(SYS_PUTS)
code += syscall()
code += push_dword_data(FILE_ATTRIBUTE_NORMAL) # dwFlagsAndAttributes
code += push_dword_data(FILE_READ_DATA) # dwDesiredAccess
code += push_dword_addr(flag_txt) # path
code += push_dword_data(SYS_OPEN)
code += syscall()
code += pop_acc()
# handle is in acc
code += push_dword_data(0x100) # read size
code += push_dword_addr(flag_txt) # read addr
code += push_acc_data() # handle
code += push_dword_data(SYS_READ)
code += syscall()
code += push_dword_addr(marker_2)
code += push_dword_data(SYS_PUTS)
code += syscall()
code += push_dword_addr(flag_txt)
code += push_dword_data(SYS_PUTS)
code += syscall()
code += push_dword_addr(marker_3)
code += push_dword_data(SYS_PUTS)
code += syscall()
code += exit()
assert len(code) <= 0x8000
code += '\0' * (0x8000 - len(code))
with open('code.bin', 'wb') as f:
f.write(code + data)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment