bf.py
December 19, 2017 ยท View on GitHub
from keystone import * import struct import sys
arch = KS_ARCH_X86 mode = KS_MODE_64 ks = Ks(arch, mode)
memory_top = 0x900000 memory_size = 100000 entry_point = 0x500078
def asm(code): c, _ = ks.asm(code) return ''.join([chr(x) for x in c])
def p8(x): return struct.pack("<B", x)
def p16(x): return struct.pack("<H", x)
def p32(x): return struct.pack("<L", x)
def p64(x): return struct.pack("<Q", x)
def gen_header(code): elfh = '' elfh += '\x7fELF' # magic elfh += p8(2) # Class: 2 is 64bit elfh += p8(1) # Endinan: little endian elfh += p8(1) # ELF Version: EV Current elfh += p8(0) # EI_OSABI: It is often set to 0 regardless of the target platform.(Wikipedia) elfh += p8(0) # ABI version: (not used) elfh += p8(0) * 7 # Padding: currently unused elfh += p16(2) # e_type: 2 is exectable file elfh += p16(0x3e) # e_machine: 0x3e is x86-64 elfh += p32(1) # e_version: original version(maybe whatever) elfh += p64(entry_point) # e_entry: entry point elfh += p64(0x40) # e_phoff: program header table offset -> 64bit is 0x40 elfh += p64(0) # e_shoff: section header table offset -> notable elfh += p32(0) # e_flags: maybe whatever elfh += p16(0x40) # e_ehsize: ELF Header Size elfh += p16(0x38) # e_phentsize elfh += p16(1) # e_phnum: the number of program header entries elfh += p16(0) # e_shentsize: no section headers elfh += p16(0) # e_shnum: no section headers elfh += p16(0) # e_shstrndx: no section headers
# Program Header
prmh = ''
prmh += p32(1) # p_type: type of segment
prmh += p32(5) # p_flags: memory segment permission. 0b101 -> Exec + Read
prmh += p64(0x40 + 0x38) # p_offset: offset of the segment
prmh += p64(entry_point) # p_vaddr: virtual address to be mapped in memory
prmh += p64(entry_point) # p_paddr: physical address to be mapped in memory (maybe not used in my machine)
prmh += p64(len(code)) # p_filesz: file size of this segment
prmh += p64(len(code)) # p_memsz: file size of this segment
prmh += p64(0x1000) # p_align: alignment
return elfh + prmh
def inc_ptr(): code = asm('inc rbx') return code
def dec_ptr(): code = asm('dec rbx') return code
def inc_val(): code = asm('mov al, [rbx]') code += asm('inc al') code += asm('mov [rbx], al') return code
def dec_val(): code = asm('mov al, [rbx]') code += asm('dec al') code += asm('mov [rbx], al') return code
def put_char(): code = asm('mov rax, 1') code += asm('mov rdi, 1') code += asm('mov rsi, rbx') code += asm('mov rdx, 1') code += asm('syscall') return code
def get_char(): code = asm('mov rax, 0') code += asm('mov rdi, 0') code += asm('mov rsi, rbx') code += asm('mov rdx, 1') code += asm('syscall') return code
def push_fun(addr): code = asm('mov al, [rbx]') code += asm('cmp al, 0') code += asm('je %d' % addr) return code
def pop_fun(addr): code = asm('mov al, [rbx]') code += asm('cmp al, 0') code += asm('jne %d' % (addr - len(code))) return code
def epilogue(): code = '' code += asm('mov rax, 60') code += asm('mov rdi, 0') code += asm('syscall') return code
def prologue(): code = ''
# create the area of 'memory'
code += asm('mov rax, 9') # mmap
code += asm('mov rdi, %d' % memory_top)
code += asm('mov rsi, %d' % memory_size) # size
code += asm('mov rdx, 7')
code += asm('mov r10, 34')
code += asm('mov r8, 0xffffffffff')
code += asm('mov r9, 0')
code += asm('syscall')
# use rbx as current memory addr
code += asm('mov rbx, %d' % memory_top)
return code
class InvalidSyntax(Exception): pass
def inner(base, root=False): code = ''
while True:
c = sys.stdin.read(1)
if not c:
break
if c == '>':
code += inc_ptr()
elif c == '<':
code += dec_ptr()
elif c == '+':
code += inc_val()
elif c == '-':
code += dec_val()
elif c == '.':
code += put_char()
elif c == ',':
code += get_char()
elif c == '[':
code += inner(base + len(code))
elif c == ']':
if len(code) > 129:
tmp = push_fun(130)
else:
tmp = push_fun(129)
code += pop_fun(-len(code))
return push_fun(len(code)) + code
if root:
return code
raise InvalidSyntax
def main(): base = entry_point
code = prologue()
code += inner(base + len(code), root=True)
code += epilogue()
h = gen_header(code)
artifact = h + code
return artifact
open('bf', 'w').write(main())