130 lines
4.5 KiB
Python
130 lines
4.5 KiB
Python
import copy
|
|
import sys
|
|
import sys
|
|
import time
|
|
import subprocess
|
|
from distorm3 import Decompose, Decode16Bits, Decode32Bits, Decode64Bits, Mnemonics, Registers
|
|
|
|
count = 0
|
|
|
|
class Gdb(subprocess.Popen):
|
|
def __init__(self, prg, prompt='(gdb) '):
|
|
"""Construct interactive Popen."""
|
|
self.prompt = prompt
|
|
subprocess.Popen.__init__(self, ['gdb', prg], stdin=subprocess.PIPE, stdout=subprocess.PIPE , stderr=subprocess.STDOUT)
|
|
|
|
def correspond(self, text):
|
|
"""Communicate with the child process without closing stdin."""
|
|
self.stdin.write(text)
|
|
self.stdin.flush()
|
|
str_buffer = ''
|
|
while not str_buffer.endswith(self.prompt):
|
|
str_buffer += self.stdout.read(1)
|
|
return str_buffer
|
|
|
|
def getR(self, reg):
|
|
reg = "$"+reg
|
|
if "XMM" in reg:
|
|
reg = reg+".uint128"
|
|
val = self.correspond('p %s\n'%reg.lower()).split("=")[-1].split("\n")[0]
|
|
if "0x" in val:
|
|
return int(val.split("0x")[-1],16)
|
|
else:
|
|
return int(val)
|
|
if "FLAG" in reg:
|
|
reg = "(unsigned) "+reg
|
|
if reg in ['$R%dB'%i for i in range(16)] :
|
|
reg = reg[:-1] + "&0xff"
|
|
if reg in ['$R%dW'%i for i in range(16)] :
|
|
reg = reg[:-1] + "&0xffff"
|
|
val = self.correspond('p /x %s\n'%reg.lower()).split("0x")[-1]
|
|
return long(val.split("\n")[0],16)
|
|
|
|
def setR(self, reg, value):
|
|
self.correspond('set $%s = %s\n'%(reg.lower(), int(value)))
|
|
def setByte(self, m, value):
|
|
self.correspond('set *(char*)(%s) = %s\n'%(m,value))
|
|
|
|
def stepi(self):
|
|
#print self.correspond("x/i $pc\n")
|
|
self.correspond("stepi\n")
|
|
def getM(self, m):
|
|
try:
|
|
return long(self.correspond('x/xg %s\n'%m).split("\t")[-1].split("0x")[-1].split("\n")[0],16)
|
|
except Exception,e:
|
|
print 'x/xg %s\n'%m
|
|
print self.correspond('x/xg %s\n'%m)
|
|
raise e
|
|
return 0
|
|
def getPid(self):
|
|
return int(self.correspond('info proc\n').split("\n")[0].split(" ")[-1])
|
|
def getStack(self):
|
|
maps = file("/proc/%s/maps"%self.correspond('info proc\n').split("\n")[0].split(" ")[-1]).read().split("\n")
|
|
i,o = [ int(x,16) for x in maps[-3].split(" ")[0].split('-')]
|
|
print self.correspond('dump mem lala 0x%x 0x%x\n'%(i,o))
|
|
def getByte(self, m):
|
|
arch = self.get_arch()
|
|
mask = {'i386': 0xffffffff, 'amd64': 0xffffffffffffffff}[arch]
|
|
return int(self.correspond("x/1bx %d\n"%(m&mask)).split("\t")[-1].split("\n")[0][2:],16)
|
|
def get_entry(self):
|
|
a=self.correspond('info target\n')
|
|
return int(a[a.find("Entry point:"):].split('\n')[0].split(' ')[-1][2:],16)
|
|
|
|
_arch = None
|
|
def get_arch(self):
|
|
if self._arch is not None:
|
|
return self._arch
|
|
infotarget = self.correspond('info target\n')
|
|
if 'elf32-i386' in infotarget:
|
|
self._arch = 'i386'
|
|
return 'i386'
|
|
elif 'elf64-x86-64' in infotarget:
|
|
self._arch = 'amd64'
|
|
return 'amd64'
|
|
else:
|
|
print infotarget
|
|
raise NotImplementedError()
|
|
|
|
|
|
gdb = Gdb(sys.argv[1])
|
|
arch = gdb.correspond('')
|
|
|
|
#guess arch
|
|
arch = gdb.get_arch()
|
|
|
|
#gues architecture from file
|
|
entry = gdb.get_entry()
|
|
gdb.correspond("b *0\n")
|
|
gdb.correspond("run arg1 arg2 arg3 < /dev/urandom > /dev/null\n")
|
|
gdb.correspond("d 1\n")
|
|
|
|
# Simulate no vdso (As when analized with symbemu)
|
|
found = 0
|
|
for i in range(75,120):
|
|
if gdb.getM('$sp+sizeof(void*)*%d'%i) ==0x19 and gdb.getM('$sp+%d'%(i+2))==0x1f:
|
|
found = i
|
|
if found !=0:
|
|
gdb.setByte('$sp+sizeof(void*)*%d'%found,1)
|
|
gdb.setByte('$sp+sizeof(void*)*%d'%(found+2),1)
|
|
|
|
vdso = gdb.getM('$sp+sizeof(void*)*%d'%(found+1))
|
|
for i in range(75,120):
|
|
val = gdb.getM('$sp+sizeof(void*)*%d'%i)
|
|
if val > vdso-0x10000 and val <= vdso+0x10000:
|
|
if (gdb.getM('$sp+sizeof(void*)*%d'%(i-1))) != 1:
|
|
gdb.setByte('$sp+sizeof(void*)*%d'%(i-1),1)
|
|
|
|
STACK_INSTRUCTIONS = ['BOUND', 'CALL', 'CALLF', 'ENTER', 'INT', 'INT1', 'INTO', 'IRET', 'IRETD', 'LEAVE', 'POP', 'POPA', 'POPAD', 'POPF', 'POPFD', 'PUSH', 'PUSHA', 'PUSHAD', 'PUSHF', 'PUSHFD', 'RETF', 'RETN', 'RET']
|
|
while True:
|
|
try:
|
|
stepped = False
|
|
pc = gdb.getR({'i386': 'EIP', 'amd64': 'RIP'}[arch])
|
|
print hex(pc)
|
|
gdb.stepi()
|
|
print gdb.correspond('info registers\n')
|
|
except Exception,e:
|
|
print e
|
|
print "# Processed %d instructions." % count
|
|
|
|
|