run.py 8.48 KB
Newer Older
George Hotz's avatar
George Hotz committed
1
#!/usr/bin/env python3
George Hotz's avatar
George Hotz committed
2
import os
George Hotz's avatar
George Hotz committed
3
import sys
George Hotz's avatar
George Hotz committed
4
import struct
George Hotz's avatar
George Hotz committed
5
import traceback
George Hotz's avatar
George Hotz committed
6
from elftools.elf.elffile import ELFFile
George Hotz's avatar
George Hotz committed
7 8 9 10 11
from capstone import *
md = Cs(CS_ARCH_MIPS, CS_MODE_32 + CS_MODE_BIG_ENDIAN)

icount = 0
bcount = 0
George Hotz's avatar
George Hotz committed
12

13
from termcolor import colored, cprint
George Hotz's avatar
George Hotz committed
14 15 16
from hexdump import hexdump
from unicorn import *
from unicorn.mips_const import *
George Hotz's avatar
George Hotz committed
17
from rangetree import RangeTree
George Hotz's avatar
George Hotz committed
18 19 20

mu = Uc(UC_ARCH_MIPS, UC_MODE_32 + UC_MODE_BIG_ENDIAN)

George Hotz's avatar
George Hotz committed
21 22 23
mregs = [UC_MIPS_REG_AT, UC_MIPS_REG_V0, UC_MIPS_REG_V1, UC_MIPS_REG_A0, UC_MIPS_REG_A1, UC_MIPS_REG_A2, UC_MIPS_REG_A3]
regs = ["at", "v0", "v1", "a0", "a1", "a2", "a3"]

George Hotz's avatar
George Hotz committed
24
SIZE = 16*1024*1024
25

George Hotz's avatar
George Hotz committed
26 27
heap_start = 0x20000000 # 0x20000000-0x30000000
brk_start = 0x40000000  # 0x40000000-0x80000000
George Hotz's avatar
George Hotz committed
28

29 30
tfd = 10
files = {}
George Hotz's avatar
George Hotz committed
31
fcnt = 0
George Hotz's avatar
George Hotz committed
32
def hook_interrupt(uc, intno, user_data):
33
  global heap_start, fcnt, files, tfd
George Hotz's avatar
George Hotz committed
34 35 36
  pc = uc.reg_read(UC_MIPS_REG_PC)
  if intno == 17:
    syscall_no = uc.reg_read(UC_MIPS_REG_V0)
37
    uc.reg_write(UC_MIPS_REG_V0, 0)
George Hotz's avatar
George Hotz committed
38
    uc.reg_write(UC_MIPS_REG_A3, 0)
George Hotz's avatar
George Hotz committed
39 40 41 42 43
    if syscall_no == 4004:
      # write
      fd = uc.reg_read(UC_MIPS_REG_A0)
      buf = uc.reg_read(UC_MIPS_REG_A1)
      count = uc.reg_read(UC_MIPS_REG_A2)
44 45 46 47 48 49 50 51
      if fd == 1:
        # stdout
        os.write(fd, colored(uc.mem_read(buf, count).decode('utf-8'), 'green').encode('utf-8'))
      elif fd == 2:
        # stderr
        os.write(fd, colored(uc.mem_read(buf, count).decode('utf-8'), 'red').encode('utf-8'))
      else:
        os.write(fd, uc.mem_read(buf, count))
George Hotz's avatar
George Hotz committed
52
      uc.reg_write(UC_MIPS_REG_A3, 0)
George Hotz's avatar
George Hotz committed
53 54
      return True

George Hotz's avatar
George Hotz committed
55 56 57 58 59 60
    if syscall_no == 4218:
      # madvise
      return
    elif syscall_no == 4194:
      # rt_sigaction
      return
George Hotz's avatar
George Hotz committed
61 62 63
    elif syscall_no == 4195:
      # rt_sigprocmask
      return
George Hotz's avatar
George Hotz committed
64 65 66
    elif syscall_no == 4055:
      # fcntl
      return
George Hotz's avatar
George Hotz committed
67 68 69
    elif syscall_no == 4220:
      # fcntl64
      return
George Hotz's avatar
George Hotz committed
70 71 72 73 74 75
    elif syscall_no == 4249:
      # epoll_ctl
      return
    elif syscall_no == 4263:
      # clock_gettime
      return
George Hotz's avatar
George Hotz committed
76 77 78 79 80 81 82 83 84 85 86 87
    elif syscall_no == 4326:
      # epoll_create1
      return
    elif syscall_no == 4328:
      # pipe2
      return
    elif syscall_no == 4206:
      # sigaltstack
      return
    elif syscall_no == 4222:
      # gettid
      return
George Hotz's avatar
George Hotz committed
88

George Hotz's avatar
George Hotz committed
89 90 91
    if syscall_no == 4005:
      filename = uc.reg_read(UC_MIPS_REG_A0)
      print('open("%s")' % uc.mem_read(filename, 0x100).split(b"\x00")[0].decode('utf-8'))
92
      uc.reg_write(UC_MIPS_REG_V0, 4)
George Hotz's avatar
George Hotz committed
93 94 95
    elif syscall_no == 4045:
      print("brk", hex(brk_start))
      uc.reg_write(UC_MIPS_REG_V0, brk_start)
George Hotz's avatar
George Hotz committed
96 97 98
    elif syscall_no == 4288:
      dfd = uc.reg_read(UC_MIPS_REG_A0)
      filename = uc.reg_read(UC_MIPS_REG_A1)
99 100 101
      filename = uc.mem_read(filename, 0x100).split(b"\x00")[0].decode('utf-8')
      files[tfd] = open(filename, "rb")
      uc.reg_write(UC_MIPS_REG_V0, tfd)
George Hotz's avatar
George Hotz committed
102
      print('openat("%s") = %d' % (filename, tfd))
103
      tfd += 1
George Hotz's avatar
George Hotz committed
104 105 106 107 108 109 110 111 112 113 114
    elif syscall_no == 4238:
      addr = uc.reg_read(UC_MIPS_REG_A0)
      print("futex", hex(addr))
      uc.mem_write(addr, b"\x00\x00\x00\x01")
      #raise Exception("not support")
      uc.reg_write(UC_MIPS_REG_V0, 1)
      uc.reg_write(UC_MIPS_REG_A3, 0)
      fcnt += 1
      if fcnt == 20:
        raise Exception("too much futex")
      return True
George Hotz's avatar
George Hotz committed
115 116
    elif syscall_no == 4120:
      print("clone not supported")
George Hotz's avatar
George Hotz committed
117 118
      #uc.reg_write(UC_MIPS_REG_V0, -1)
      uc.reg_write(UC_MIPS_REG_V0, 1238238)
George Hotz's avatar
George Hotz committed
119 120
      uc.reg_write(UC_MIPS_REG_A3, 0)
      return True
121 122 123
    elif syscall_no == 4006:
      fd = uc.reg_read(UC_MIPS_REG_A0)
      if fd >= 10:
George Hotz's avatar
George Hotz committed
124
        #print("close(%d)" % fd)
125 126 127
        files[fd].close()
        del files[fd]
      uc.reg_write(UC_MIPS_REG_V0, 0)
128 129 130 131
    elif syscall_no == 4003:
      fd = uc.reg_read(UC_MIPS_REG_A0)
      buf = uc.reg_read(UC_MIPS_REG_A1)
      count = uc.reg_read(UC_MIPS_REG_A2)
George Hotz's avatar
George Hotz committed
132 133
      # changing this works if we want smaller oracle
      #count = 4
134
      if fd == 4:
135 136
        val = b"2097152\n"
        uc.mem_write(buf, val)
George Hotz's avatar
George Hotz committed
137
        print("read", fd, hex(buf), count)
138
        uc.reg_write(UC_MIPS_REG_V0, len(val))
139 140 141
      else:
        ret = files[fd].read(count)
        uc.mem_write(buf, ret)
George Hotz's avatar
George Hotz committed
142
        #print("read", fd, hex(buf), count, len(ret))
143
        uc.reg_write(UC_MIPS_REG_V0, len(ret))
George Hotz's avatar
George Hotz committed
144
    elif syscall_no == 4246:
145
      a0 = uc.reg_read(UC_MIPS_REG_A0)
George Hotz's avatar
George Hotz committed
146 147 148
      print("exit(%d) ran %.2f million instructions" % (a0, icount/1_000_000))
      sys.stdout.flush()
      sys.stderr.flush()
149
      os._exit(a0)
George Hotz's avatar
George Hotz committed
150 151 152 153
    elif syscall_no == 4090:
      a0 = uc.reg_read(UC_MIPS_REG_A0)
      a1 = uc.reg_read(UC_MIPS_REG_A1)
      a2 = uc.reg_read(UC_MIPS_REG_A2)
George Hotz's avatar
George Hotz committed
154 155 156 157
      a3 = uc.reg_read(UC_MIPS_REG_A3)
      a4 = uc.reg_read(UC_MIPS_REG_T0)
      a5 = uc.reg_read(UC_MIPS_REG_T1)
      print("mmap", hex(a0), hex(a1), hex(a2), hex(a3), hex(a4), hex(a5), "at", hex(heap_start))
George Hotz's avatar
George Hotz committed
158 159 160 161
      if a0 == 0:
        print("malloced new")
        #mu.mem_map(heap_start, a1)
        uc.reg_write(UC_MIPS_REG_V0, heap_start)
George Hotz's avatar
George Hotz committed
162
        heap_start += a1
George Hotz's avatar
George Hotz committed
163 164
      else:
        uc.reg_write(UC_MIPS_REG_V0, a0)
George Hotz's avatar
George Hotz committed
165
    else:
George Hotz's avatar
George Hotz committed
166
      print("syscall", syscall_no, hex(pc))
George Hotz's avatar
George Hotz committed
167 168 169 170 171 172 173
      jj = []
      for i,r in zip(mregs, regs):
        jj += "%s: %8x " % (r, uc.reg_read(i))
      print(''.join(jj))
    return True

  print("interrupt", intno, hex(pc))
George Hotz's avatar
George Hotz committed
174
  if intno != 17:
George Hotz's avatar
George Hotz committed
175 176
    raise Exception
  return True
George Hotz's avatar
George Hotz committed
177

George Hotz's avatar
George Hotz committed
178 179 180 181
cnt = 0
def hook_code(uc, address, size, user_data):
  global cnt
  cnt += 1
George Hotz's avatar
George Hotz committed
182 183

  """
George Hotz's avatar
George Hotz committed
184 185 186
  dat = mu.mem_read(address, size)
  if dat == "\x0c\x00\x00\x00" or dat == "\x00\x00\x00\x0c":
    raise Exception("syscall")
George Hotz's avatar
George Hotz committed
187
  """
George Hotz's avatar
George Hotz committed
188 189 190
  
  #if cnt == 2000:
  #  raise Exception("too many instructions")
George Hotz's avatar
George Hotz committed
191 192
  try:
    print(">>> Tracing instruction at 0x%x, instruction size = %u" % (address, size))
George Hotz's avatar
George Hotz committed
193
    """
George Hotz's avatar
George Hotz committed
194 195 196
    jj = []
    for i in range(16):
      jj += "r%d: %x " % (i, uc.reg_read(i))
George Hotz's avatar
George Hotz committed
197 198
    print(''.join(jj))
    """
George Hotz's avatar
George Hotz committed
199 200 201 202 203 204 205
    #print('    code hook: pc=%08x sp=%08x' % (
    #  uc.reg_read(UC_MIPS_REG_PC),
    #  uc.reg_read(UC_MIPS_REG_SP)
    #  ))
  except:
    raise Exception("ctrl-c")

George Hotz's avatar
George Hotz committed
206 207
#elf = open("test", "rb")
elf = open("go-ethereum", "rb")
George Hotz's avatar
George Hotz committed
208 209 210
data = elf.read()
elf.seek(0)

George Hotz's avatar
George Hotz committed
211 212
#rte = data.find(b"\x08\x02\x2c\x95")
#print(hex(rte))
George Hotz's avatar
George Hotz committed
213

214
# program memory (16 MB)
George Hotz's avatar
George Hotz committed
215 216
mu.mem_map(0, SIZE)

George Hotz's avatar
George Hotz committed
217
# heap (256 MB) @ 0x20000000
218
mu.mem_map(heap_start, 256*1024*1024)
George Hotz's avatar
George Hotz committed
219

George Hotz's avatar
George Hotz committed
220 221 222
# brk (1024 MB) @ 0x40000000
mu.mem_map(brk_start, 1024*1024*1024)

George Hotz's avatar
George Hotz committed
223 224
# regs at 0xC0000000 in merkle

George Hotz's avatar
George Hotz committed
225
elffile = ELFFile(elf)
George Hotz's avatar
George Hotz committed
226 227 228 229
for seg in elffile.iter_segments():
  print(seg.header, hex(seg.header.p_vaddr))
  mu.mem_write(seg.header.p_vaddr, seg.data())

George Hotz's avatar
George Hotz committed
230 231
entry = elffile.header.e_entry
print("entrypoint: %x" % entry)
George Hotz's avatar
George Hotz committed
232
#hexdump(mu.mem_read(entry, 0x10))
George Hotz's avatar
George Hotz committed
233

George Hotz's avatar
George Hotz committed
234
mu.reg_write(UC_MIPS_REG_SP, SIZE-0x2000)
George Hotz's avatar
George Hotz committed
235

George Hotz's avatar
George Hotz committed
236
# http://articles.manugarg.com/aboutelfauxiliaryvectors.html
237
_AT_PAGESZ = 6
238 239 240 241 242
mu.mem_write(SIZE-0x2000, struct.pack(">IIIIIIIII",
  2,  # argc
  SIZE-0x1000, SIZE-0x800, 0,  # argv
  SIZE-0x400, 0,  # envp
  _AT_PAGESZ, 0x1000, 0)) # auxv
George Hotz's avatar
George Hotz committed
243 244

# block
245
#mu.mem_write(SIZE-0x800, b"13284491\x00")
George Hotz's avatar
George Hotz committed
246
mu.mem_write(SIZE-0x800, b"13284469\x00")
247
mu.mem_write(SIZE-0x400, b"GOGC=off\x00")
George Hotz's avatar
George Hotz committed
248

George Hotz's avatar
George Hotz committed
249
#hexdump(mu.mem_read(SIZE-0x2000, 0x100))
George Hotz's avatar
George Hotz committed
250 251 252

# nop osinit
#mu.mem_write(0x44524, b"\x03\xe0\x00\x08\x00\x00\x00\x00")
George Hotz's avatar
George Hotz committed
253

George Hotz's avatar
George Hotz committed
254
r = RangeTree()
255 256 257
for section in elffile.iter_sections():
  try:
    for nsym, symbol in enumerate(section.iter_symbols()):
George Hotz's avatar
George Hotz committed
258 259 260 261 262 263
      ss = symbol['st_value']
      se = ss+symbol['st_size']
      #print(ss, se)
      if ss != se:
        r[ss:se] = symbol.name
      #print(nsym, symbol.name, symbol['st_value'], symbol['st_size'])
264 265 266 267 268
      if symbol.name == "runtime.gcenable":
        print(nsym, symbol.name)
        # nop gcenable
        mu.mem_write(symbol['st_value'], b"\x03\xe0\x00\x08\x00\x00\x00\x00")
  except Exception:
George Hotz's avatar
George Hotz committed
269
    #traceback.print_exc()
270 271
    pass

George Hotz's avatar
George Hotz committed
272
#mu.hook_add(UC_HOOK_BLOCK, hook_code, user_data=mu)
George Hotz's avatar
George Hotz committed
273

George Hotz's avatar
George Hotz committed
274
#mu.hook_add(UC_HOOK_CODE, hook_code, user_data=mu)
George Hotz's avatar
George Hotz committed
275

George Hotz's avatar
George Hotz committed
276 277
# hmm, very slow
def hook_code_simple(uc, address, size, user_data):
George Hotz's avatar
George Hotz committed
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
  global icount, bcount
  #assert size == 4
  try:
    if bcount%1000000 == 0:
      dat = next(md.disasm(uc.mem_read(address, size), address))
      print("%10d: %s %s" % (icount, r[address], dat))
    icount += size//4
    bcount += 1
    return True
  except Exception as e:
    raise e
  except:
    raise Exception
#mu.hook_add(UC_HOOK_CODE, hook_code_simple, user_data=mu)
if os.getenv("TRACE") == "1":
  mu.hook_add(UC_HOOK_BLOCK, hook_code_simple, user_data=mu)
George Hotz's avatar
George Hotz committed
294

295 296 297 298
def hook_mem_invalid(uc, access, address, size, value, user_data):
  pc = uc.reg_read(UC_MIPS_REG_PC)
  print("UNMAPPED MEMORY:", access, hex(address), size, "at", hex(pc))
  return False
299
mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid)
300

George Hotz's avatar
George Hotz committed
301 302
mu.hook_add(UC_HOOK_INTR, hook_interrupt)
#mu.hook_add(UC_HOOK_INSN, hook_interrupt, None, 1, 0, 0x0c000000)
303
mu.emu_start(entry, 0)