Merge branch 'master' of github.com:BinaryAnalysisPlatform/qira

This commit is contained in:
Ned Williamson 2016-03-24 21:41:50 -04:00
commit e7c0dbef5c
15 changed files with 241 additions and 75 deletions

View File

@ -15,8 +15,8 @@ addons:
- clang
install:
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
- ./install.sh
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
- ./install.sh
script:
- ./run_tests.sh

View File

@ -23,7 +23,7 @@ cd qira/
## Installation Extras
* ./fetchlibs.sh will fetch the libraries for i386, armhf, armel, aarch64, mips, mipsel, and ppc
* ./pin_build.sh will install the QIRA PIN plugin, allowing --pin to work
* ./tracers/pin_build.sh will install the QIRA PIN plugin, allowing --pin to work
## Releases
@ -77,8 +77,6 @@ m -- go to return from current function
z -- zoom out max on vtimeline
l -- set iaddr to instruction at current clnum
left -- -1 fork
right -- +1 fork
up -- -1 clnum
@ -90,8 +88,8 @@ shift-c -- clear all forks
n -- rename instruction
shift-n -- rename data
; -- add comment at instruction
shift-; -- add comment at data
: -- add comment at instruction
shift-: -- add comment at data
g -- go to change, address, or name
space -- toggle flat/function view

View File

@ -35,10 +35,10 @@ cp $OUTPUT "$IDAROOT/plugins"
cp $OUTPUT64 "$IDAROOT/plugins"
if [[ "$unamestr" == 'Linux' ]]; then
cp $OUTPUT bin/qira_ida66_linux.plx
cp $OUTPUT64 bin/qira_ida66_linux.plx64
cp $OUTPUT bin/qira_ida_linux.plx
cp $OUTPUT64 bin/qira_ida_linux.plx64
elif [[ "$unamestr" == 'Darwin' ]]; then
cp $OUTPUT bin/qira_ida66_mac.pmc
cp $OUTPUT64 bin/qira_ida66_mac.pmc64
cp $OUTPUT bin/qira_ida_mac.pmc
cp $OUTPUT64 bin/qira_ida_mac.pmc64
fi

View File

@ -13,32 +13,40 @@ def start_server():
def set_qira_address(la):
global qira_address
#if qira_address != BADADDR:
# del_bpt(qira_address)
ea=0
if qira_address is not None and qira_address != BADADDR:
ea=idaapi.toEA(0, qira_address)
if CheckBpt(ea) > 0:
idaapi.del_bpt(ea)
qira_address = la
#idaapi.add_bpt(qira_address)
#idaapi.disable_bpt(qira_address)
idaapi.add_bpt(qira_address, 0, BPT_SOFT)
EnableBpt(qira_address, False)
def jump_to(a):
if (qira_address != a):
set_qira_address(a)
idaapi.jumpto(qira_address, -1, 0)
else:
idaapi.jumpto(qira_address, -1, 0)
global qira_address
if a is not None:
if (a != qira_address) and (a != BADADDR):
set_qira_address(a)
idaapi.jumpto(qira_address, -1, 0)
else:
idaapi.jumpto(qira_address, -1, 0)
def ws_send(msg):
if wsserver is not None:
global wsserver
if (wsserver is not None) and (msg is not None):
for conn in wsserver.connections.itervalues():
conn.sendMessage(msg)
def update_address(addr_type, addr):
cmd = "set%s 0x%x" % (addr_type, addr,)
ws_send(cmd)
if (addr_type is not None) and (addr is not None):
cmd = "set%s 0x%x" % (addr_type, addr)
ws_send(cmd)
class qiraplugin_t(idaapi.plugin_t):
flags = 0
comment = ""
help = ""
comment = "QEMU Interactive Runtime Analyser plugin"
help = "Visit qira.me for more infos"
wanted_name = "QIRA Plugin"
wanted_hotkey = "Alt-F5"
@ -53,12 +61,14 @@ class qiraplugin_t(idaapi.plugin_t):
def run(self, arg):
global qira_address
idaapi.msg("[QIRA Plugin] Syncing with Qira\n")
self.addr = idaapi.get_screen_ea()
if (self.old_addr != self.addr):
if (idaapi.isCode(idaapi.getFlags(self.addr))):
# don't update the address if it's already the qira address
if (self.addr != qira_address):
# don't update the address if it's already the qira address or None
if (self.addr is not None) and (self.addr != qira_address):
idaapi.msg("[QIRA Plugin] Qira Address %x \n" % (self.addr))
# Instruction Address
set_qira_address(self.addr)
update_address("iaddr", self.addr)

View File

@ -1,7 +1,12 @@
#include <ida.hpp>
#include <idp.hpp>
#include <dbg.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
#include <bytes.hpp>
#include <offset.hpp>
#include <auto.hpp>
#include <entry.hpp>
#include <name.hpp>
#include <time.h>
@ -516,8 +521,8 @@ void idaapi IDAP_run(int arg) {
return;
}
char IDAP_comment[] = "This is my test plug-in";
char IDAP_help[] = "My plugin";
char IDAP_comment[] = "QEMU Interactive Runtime Analyser server";
char IDAP_help[] = "Visit qira.me for more infos";
char IDAP_name[] = "QIRA server";
char IDAP_hotkey[] = "Alt-X";

View File

@ -7,9 +7,12 @@ else
PIP="pip"
fi
LIBCAPSTONE_SHA256="a7bf1cb814c6e712a314659b074bc4c00d2e0006cac67d055d3130d4ecdd525d"
LIBCAPSTONE64_SHA256="a7bf1cb814c6e712a314659b074bc4c00d2e0006cac67d055d3130d4ecdd525d"
LIBCAPSTONE32_SHA256="4ffb4630829b9b4e8c713ae8336a8259b180194233f248170bfe0d1577257fb2"
unamestr=$(uname)
arch=$(uname -p)
if [[ "$unamestr" == 'Linux' ]]; then
# we need pip to install python stuff
# build for building qiradb and stuff for flask like gevent
@ -20,10 +23,14 @@ if [[ "$unamestr" == 'Linux' ]]; then
sudo apt-get -qq -y install build-essential python-dev python-pip python-virtualenv debootstrap debian-archive-keyring libjpeg-dev zlib1g-dev unzip wget graphviz curl
# install capstone
curl -o /tmp/libcapstone3.deb http://www.capstone-engine.org/download/3.0.4/ubuntu-14.04/libcapstone3_3.0.4-0.1ubuntu1_amd64.deb
if [ "$arch" == 'i686' ]; then
curl -o /tmp/libcapstone3.deb http://www.capstone-engine.org/download/3.0.4/ubuntu-14.04/libcapstone3_3.0.4-0.1ubuntu1_i386.deb
else
curl -o /tmp/libcapstone3.deb http://www.capstone-engine.org/download/3.0.4/ubuntu-14.04/libcapstone3_3.0.4-0.1ubuntu1_amd64.deb
fi
HASH=`sha256sum /tmp/libcapstone3.deb 2>/dev/null | cut -d' ' -f1`
if [ "$HASH" != "$LIBCAPSTONE_SHA256" ]; then
if [ "$HASH" != "$LIBCAPSTONE64_SHA256" ] || [ "$HASH" != "$LIBCAPSTONE32_SHA256" ]; then
echo "Error: libcapstone3.deb has an invalid checksum."
exit 1
fi

View File

@ -1,16 +1,18 @@
# (regname, regsize, is_big_endian, arch_name, branches)
PPCREGS = ([], 4, True, "ppc", ["bl "])
# PowerPC CPU REGS
PPCREGS = [[], 4, True, "ppc", ["bl "]]
for i in range(32):
PPCREGS[0].append("r"+str(i))
for i in range(32):
PPCREGS[0].append(None)
PPCREGS[0].append("lr")
PPCREGS[0].append("ctr")
for i in range(8):
PPCREGS[0].append("cr"+str(i))
AARCH64REGS = ([], 8, False, "aarch64", ["bl ", "blx "])
# Aarch64 CPU REGS
AARCH64REGS = [[], 8, False, "aarch64", ["bl ", "blx "]]
for i in range(8):
AARCH64REGS[0].append(None)
for i in range(32):
@ -19,6 +21,7 @@ for i in range(32):
AARCH64REGS[0][8+31] = "sp"
AARCH64REGS[0].append("pc")
# MIPS CPU REGS
MIPSREGLIST = ['$zero', '$at', '$v0', '$v1', '$a0', '$a1', '$a2', '$a3']
for i in range(8):
MIPSREGLIST.append('$t'+str(i))
@ -33,12 +36,14 @@ MIPSREGLIST.append('$sp')
MIPSREGLIST.append('$fp')
MIPSREGLIST.append('$ra')
MIPSREGLIST.append('$pc')
MIPSREGS = [MIPSREGLIST, 4, True, "mips", ["jal\t","jr\t","jal","jr"]]
MIPSREGS = (MIPSREGLIST, 4, True, "mips", ["jal\t","jr\t","jal","jr"])
MIPSELREGS = (MIPSREGLIST, 4, False, "mipsel", ["jal\t","jr\t","jal","jr"])
# ARM CPU REGS
ARMREGS = [['R0','R1','R2','R3','R4','R5','R6','R7','R8','R9','R10','R11','IP','SP','LR','PC'], 4, False, "arm"] # FP = R7 If THUMB2 Mode enabled, & R11 If not.
# this stuff should be moved to static
ARMREGS = (['R0','R1','R2','R3','R4','R5','R6','R7','R8','R9','R10','R11','IP','SP','LR','PC'], 4, False, "arm")
X86REGS = (['EAX', 'ECX', 'EDX', 'EBX', 'ESP', 'EBP', 'ESI', 'EDI', 'EIP'], 4, False, "i386")
X64REGS = (['RAX', 'RCX', 'RDX', 'RBX', 'RSP', 'RBP', 'RSI', 'RDI', "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", 'RIP'], 8, False, "x86-64")
# Intel x86 CPU REGS
X86REGS = [['EAX', 'ECX', 'EDX', 'EBX', 'ESP', 'EBP', 'ESI', 'EDI', 'EIP'], 4, False, "i386"]
# x86_64 CPU REGS
X64REGS = [['RAX', 'RCX', 'RDX', 'RBX', 'RSP', 'RBP', 'RSI', 'RDI', "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", 'RIP'], 8, False, "x86-64"]

View File

@ -90,6 +90,49 @@ class Program:
# pmaps is global, but updated by the traces
progdat = open(self.program, "rb").read(0x800)
CPU_TYPE_ARM = "\x0C"
CPU_TYPE_ARM64 = "\x01\x00\x00\x0C"
CPU_SUBTYPE_ARM_ALL = "\x00"
CPU_SUBTYPE_ARM_V4T = "\x05"
CPU_SUBTYPE_ARM_V6 = "\x06"
CPU_SUBTYPE_ARM_V5TEJ = "\x07"
CPU_SUBTYPE_ARM_XSCALE = "\x08"
CPU_SUBTYPE_ARM_V7 = "\x09"
CPU_SUBTYPE_ARM_V7F = "\x0A"
CPU_SUBTYPE_ARM_V7S = "\x0B"
CPU_SUBTYPE_ARM_V7K = "\x0C"
CPU_SUBTYPE_ARM_V6M = "\x0E"
CPU_SUBTYPE_ARM_V7M = "\x0F"
CPU_SUBTYPE_ARM_V7EM = "\x10"
CPU_SUBTYPE_ARM = [
CPU_SUBTYPE_ARM_V4T,
CPU_SUBTYPE_ARM_V6,
CPU_SUBTYPE_ARM_V5TEJ,
CPU_SUBTYPE_ARM_XSCALE,
CPU_SUBTYPE_ARM_V7,
CPU_SUBTYPE_ARM_V7F,
CPU_SUBTYPE_ARM_V7K,
CPU_SUBTYPE_ARM_V6M,
CPU_SUBTYPE_ARM_V7M,
CPU_SUBTYPE_ARM_V7EM
]
CPU_SUBTYPE_ARM64 = [
CPU_SUBTYPE_ARM_ALL,
CPU_SUBTYPE_ARM_V7S
]
MACHO_MAGIC = "\xFE\xED\xFA\xCE"
MACHO_CIGAM = "\xCE\xFA\xED\xFE"
MACHO_MAGIC_64 = "\xFE\xED\xFA\xCF"
MACHO_CIGAM_64 = "\xCF\xFA\xED\xFE"
MACHO_FAT_MAGIC = "\xCA\xFE\xBA\xBE"
MACHO_FAT_CIGAM = "\xBE\xBA\xFE\xCA"
MACHO_P200_FAT_MAGIC = "\xCA\xFE\xD0\x0D"
MACHO_P200_FAT_CIGAM = "\x0D\xD0\xFE\xCA"
# Linux binaries
if progdat[0:4] == "\x7FELF":
# get file type
@ -121,18 +164,20 @@ class Program:
self.tregs = arch.X86REGS
self.qirabinary = qemu_dir + "qira-i386"
self.pintool = pin_dir + "obj-ia32/qirapin.so"
elif self.fb == 0x800:
use_lib('mips')
arch.MIPSREGS[2:-1] = (True, "mips")
self.tregs = arch.MIPSREGS
self.qirabinary = qemu_dir + 'qira-mips'
elif self.fb == 0x08:
use_lib('mipsel')
self.tregs = arch.MIPSELREGS
arch.MIPSREGS[2:-1] = (False, "mipsel")
self.tregs = arch.MIPSREGS
self.qirabinary = qemu_dir + 'qira-mipsel'
elif self.fb == 0x1400: # big endian...
use_lib('powerpc')
self.tregs = arch.PPCREGS
self.qirabinary = qemu_dir + "qira-ppc"
elif self.fb == 0x800:
use_lib('mips')
self.tregs = arch.MIPSREGS
self.qirabinary = qemu_dir + 'qira-mips'
else:
raise Exception("binary type "+hex(self.fb)+" not supported")
@ -157,23 +202,81 @@ class Program:
else:
raise Exception("windows binary with machine "+hex(wh)+" not supported")
# Mach-O binaries
elif progdat[0:4] in ("\xCF\xFA\xED\xFE", "\xFE\xED\xFA\xCF", "\xCE\xFA\xED\xFE", "\xFE\xED\xFA\xCE"):
# MACHO FAT binaries
elif progdat[0x0:0x04] in (MACHO_FAT_MAGIC, MACHO_FAT_CIGAM, MACHO_P200_FAT_MAGIC, MACHO_P200_FAT_CIGAM):
print "**** Mach-O FAT (Universal) binary detected"
if progdat[0x04:0x05] == CPU_TYPE_ARM and progdat[0x08:0x09] in CPU_SUBTYPE_ARM:
print "**** Mach-O ARM architecture detected"
self.macharch = "arm"
elif (progdat[0x08:0x0c] == CPU_TYPE_ARM64) or (progdat[0x1c:0x20] == CPU_TYPE_ARM64) or (progdat[0x30:0x34] == CPU_TYPE_ARM64):
print "**** Mach-O Aarch64 architecture detected"
self.macharch = "aarch64"
else:
self.macharch = ""
print "**** Mach-O X86/64 architecture detected"
if progdat[0x0:0x04] in (MACHO_P200_FAT_MAGIC, MACHO_P200_FAT_CIGAM):
raise NotImplementedError("Pack200 compressed files are not supported yet")
elif progdat[0x0:0x04] in (MACHO_FAT_MAGIC, MACHO_FAT_CIGAM):
if progdat[0x0:0x04] == MACHO_FAT_CIGAM:
arch.ARMREGS[2] = True
arch.AARCH64REGS[2] = True
if self.macharch == "arm":
self.tregs = arch.ARMREGS
self.pintool = ""
elif self.macharch == "aarch64":
self.tregs = arch.AARCH64REGS
self.pintool = ""
else:
self.tregs = arch.X86REGS
self.pintool = pin_dir + "obj-ia32/qirapin.dylib"
else:
raise Exception("Mach-O FAT (Universal) binary not supported")
if self.macharch == "arm" or self.macharch == "aarch64":
raise NotImplementedError("ARM/Aarch64 Support is not implemented")
if not os.path.isfile(self.pintool):
print "Running a Mach-O FAT (Universal) binary requires PIN support. See tracers/pin_build.sh"
exit()
raise NotImplementedError("Mach-O FAT (Universal) binary not supported")
self.runnable = True
# MACHO binaries
elif progdat[0x0:0x04] in (MACHO_MAGIC_64, MACHO_CIGAM_64, MACHO_MAGIC, MACHO_CIGAM):
print "**** Mach-O binary detected"
if progdat[0:4] == "\xCF\xFA\xED\xFE":
self.tregs = arch.X64REGS
self.pintool = pin_dir + "obj-intel64/qirapin.dylib"
elif progdat[0:4] == "\xFE\xED\xFA\xCF": # big endian...
self.tregs = arch.X64REGS
self.pintool = pin_dir + "obj-intel64/qirapin.dylib"
elif progdat[0:4] == "\xCE\xFA\xED\xFE":
self.tregs = arch.X86REGS
self.pintool = pin_dir + "obj-ia32/qirapin.dylib"
elif progdat[0:4] == "\xFE\xED\xFA\xCE": # big endian...
self.tregs = arch.X86REGS
self.pintool = pin_dir + "obj-ia32/qirapin.dylib"
if progdat[0x04:0x05] == CPU_TYPE_ARM and progdat[0x08:0x09] in CPU_SUBTYPE_ARM:
print "**** Mach-O ARM architecture detected"
self.macharch = "arm"
elif progdat[0x04:0x05] == CPU_TYPE_ARM and progdat[0x08:0x09] in CPU_SUBTYPE_ARM64:
print "**** Mach-O Aarch64 architecture detected"
self.macharch = "aarch64"
else:
self.macharch = ""
print "**** Mach-O X86/64 architecture detected"
if progdat[0x0:0x04] in (MACHO_MAGIC_64, MACHO_CIGAM_64):
if progdat[0x0:0x04] == MACHO_CIGAM_64:
arch.AARCH64REGS[2] = True
if self.macharch == "aarch64":
self.tregs = arch.AARCH64REGS
self.pintool = ""
else:
self.tregs = arch.X64REGS
self.pintool = pin_dir + "obj-intel64/qirapin.dylib"
elif progdat[0x0:0x04] in (MACHO_MAGIC, MACHO_CIGAM):
if progdat[0x0:0x04] == MACHO_CIGAM:
arch.ARMREGS[2] = True
if self.macharch == "arm":
self.tregs = arch.ARMREGS
self.pintool = ""
else:
self.tregs = arch.X86REGS
self.pintool = pin_dir + "obj-ia32/qirapin.dylib"
else:
raise Exception("Mach-O binary not supported")
if self.macharch == "arm" or self.macharch == "aarch64":
raise NotImplementedError("ARM/Aarch64 Support is not implemented")
if not os.path.isfile(self.pintool):
print "Running a Mach-O binary requires PIN support. See tracers/pin_build.sh"
exit()

View File

@ -245,7 +245,7 @@ def navigatefunction(forknum, clnum, start):
if clnum == trace.minclnum or clnum == trace.maxclnum:
ret = clnum
break
emit('setclnum', forknum, ret)
emit('setclnum', {'forknum': forknum, 'clnum': ret})
@socketio.on('getinstructions', namespace='/qira')

View File

@ -109,7 +109,7 @@ bool Trace::remap_backing(uint64_t new_size) {
#else
while (1) {
off_t fs = lseek(fd_, 0, SEEK_END);
if (fs < new_size) {
if ((unsigned int)fs < new_size) {
printf("WARNING: requested %" PRIu64 " bytes, but only %" PRIx64 " are in the file...waiting\n", new_size, fs);
usleep(100 * 1000);
} else {
@ -196,7 +196,7 @@ void Trace::process() {
ret.first->second.insert(c->clnum);
// registers_
if (type == 'W' && c->address < (register_size_ * register_count_)) {
if (type == 'W' && (c->address < (unsigned int)(register_size_ * register_count_))) {
registers_[c->address / register_size_][c->clnum] = c->data;
}

View File

@ -1,13 +1,22 @@
#!/usr/bin/env python2.7
from setuptools import setup, Extension
import os
from version import __version__
from distutils.core import setup, Extension
import distutils.sysconfig
# should be a symlink to the root
# could also add the git rev to this?
version=open('VERSION').read().strip()
cfg_vars = distutils.sysconfig.get_config_vars()
for key, value in cfg_vars.items():
if type(value) == str:
cfg_vars[key] = value.replace("-Wstrict-prototypes", "")
# the c++ extension module
extension_mod = Extension("qiradb._qiradb", ["qiradb/Trace.cpp", "qiradb/_qiradb.cpp"])
os.environ["CC"] = "g++"
os.environ["CXX"] = "g++"
extension_mod = Extension("qiradb._qiradb", sources=["qiradb/Trace.cpp", "qiradb/_qiradb.cpp"], language="c++")
url="https://github.com/BinaryAnalysisPlatform"
description="QEMU Interactive Runtime Analyser, QIRADB Tracer package."
# specify the package
setup(name='qiradb', version=version, ext_modules=[extension_mod], packages=['qiradb'])
setup(name='qiradb', version=__version__, url=url, description=description, ext_modules=[extension_mod], packages=['qiradb'])

10
qiradb/version.py Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env python2.7
import os
import subprocess
# should be a symlink to the root
# could also add the git rev to this?
version_file = open(os.path.join('.', 'VERSION'))
version_number = version_file.read().strip()
__version__ = version_number

View File

@ -1,3 +1,4 @@
pip
six
html
flask-socketio

View File

@ -18,13 +18,29 @@ QIRA_PID=$!
echo "qira pid is $QIRA_PID"
sleep 2
LSB="/etc/lsb-release"
VER="12.04"
LIBICU="libicu48"
if [ -f $LSB ] ; then
echo "*** Debian Based Distro."
. $LSB
if [ $DISTRIB_ID == "Ubuntu" ]; then
if [ $DISTRIB_RELEASE != "12.04" ]; then
VER="14.04"
LIBICU="libicu52"
fi
fi
fi
# phantomjs
# use phantomjs2.0 for non-draft WebSockets protol
# unforunately this doesn't ship with Ubuntu by default
# the next 3 lines are 12.04 specific. maybe we should update Travis at some point
sudo apt-get install libicu48
wget https://s3.amazonaws.com/travis-phantomjs/phantomjs-2.0.0-ubuntu-12.04.tar.bz2
tar xf ./phantomjs-2.0.0-ubuntu-12.04.tar.bz2
sudo apt-get install $LIBICU
wget https://s3.amazonaws.com/travis-phantomjs/phantomjs-2.0.0-ubuntu-$VER.tar.bz2
tar xf ./phantomjs-2.0.0-ubuntu-$VER.tar.bz2
chmod +x ./phantomjs
./phantomjs qira_tests/load_page.js

View File

@ -4,7 +4,9 @@ function on_setiaddr(iaddr) { DS("setiaddr");
update_iaddr(iaddr);
} stream.on('setiaddr', on_setiaddr);
function on_setclnum(forknum, clnum) { DS("setclnum");
function on_setclnum(msg) { DS("setclnum");
var forknum = msg['forknum'];
var clnum = msg['clnum'];
Session.set('forknum', forknum);
Session.set('clnum', clnum);
push_history("remote setclnum");