├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── VERSION ├── docker ├── Dockerfile ├── build.sh └── test.sh ├── extra ├── analysis │ ├── block_analysis.py │ ├── build_multigraph.py │ ├── db_commit_blocks.py │ ├── function_analysis.py │ └── loop_analysis.py ├── byteweight │ ├── README │ ├── _oasis │ ├── byte.ml │ ├── byteweight.ml │ ├── byteweight.mli │ ├── dism.ml │ ├── mock.ml │ ├── normalize.ml │ ├── train.ml │ ├── trie.ml │ └── trie.mli ├── cda │ ├── cachegen.py │ ├── cacheserver.py │ ├── cda_build.sh │ ├── cda_config.py │ ├── clang │ │ ├── __init__.py │ │ ├── cindex.py │ │ └── enumerations.py │ ├── clang_build.sh │ ├── include.tar.gz │ └── static │ │ ├── cda.css │ │ ├── cda.js │ │ ├── jquery-2.1.0.js │ │ ├── jquery.scrollTo.min.js │ │ └── socket.io.min.js ├── install.bat ├── llvmpatch │ └── c-disasm-mcinst ├── middleware │ ├── dump_log.py │ ├── qira_memory.py │ └── qira_trace.py ├── newscripts │ └── qira_log.py ├── old_static │ ├── qira_static.py │ └── radare_build.sh ├── parseida │ ├── gdb.sh │ ├── ltracer.sh │ ├── parseidb.py │ └── parseidc.py ├── qemu_mods │ ├── disas.c │ ├── gen_patch.sh │ ├── main.c │ ├── qemu.h │ ├── strace.c │ ├── strace.list │ └── tci.c ├── qira.bat ├── qiradb │ ├── build.sh │ ├── qiradb │ └── qiradb.cc ├── scripts │ ├── db_commit_asm.py │ ├── db_commit_log.py │ ├── db_filter_log.py │ ├── gen_reg_colors.py │ ├── go.sh │ ├── mem_json_extract.py │ ├── mongo.sh │ └── segment_extract.py ├── servers │ ├── memory_server.py │ ├── qira_meteor.py │ └── regmem.js ├── vim │ └── qira.vim ├── web │ └── changeeditor.js ├── website │ ├── css │ │ └── bootstrap.min.css │ ├── dl │ ├── favicon.ico │ ├── img │ │ ├── first_splash.png │ │ ├── haddrbar.png │ │ ├── hexdump.png │ │ ├── ida.png │ │ └── watch.png │ ├── index.html │ ├── js │ │ ├── bootstrap.min.js │ │ └── jquery.min.js │ └── pull.php └── webstatic │ ├── fetch.sh │ └── package.js ├── fetchlibs.sh ├── ida ├── bin │ ├── qira_ida66_linux.plx │ ├── qira_ida66_linux.plx64 │ ├── qira_ida66_mac.pmc │ ├── qira_ida66_mac.pmc64 │ ├── qira_ida66_windows.p64 │ └── qira_ida66_windows.plw ├── build.sh ├── libs │ ├── libZLIB.a │ ├── libwebsockets_static.a │ ├── linux_libwebsockets.a │ └── mac_libwebsockets.a ├── libwebsockets.h ├── mingw_build.sh ├── python │ └── qira.py └── template.cpp ├── install.sh ├── middleware ├── __init__.py ├── arch.py ├── qira.py ├── qira_analysis.py ├── qira_base.py ├── qira_config.py ├── qira_log.py ├── qira_program.py ├── qira_socat.py ├── qira_webserver.py ├── qira_webstatic.py └── qiradb │ ├── .gitignore │ ├── Trace │ ├── Trace.cpp │ ├── Trace.h │ ├── Trace.pxd │ └── __init__.py │ ├── __init__.py │ ├── qiradb.pyx │ └── qiradb.pyxbld ├── qira ├── qira_tests ├── bin │ ├── hello_trace │ └── loop ├── load_page.js ├── test_qira_program_runs.py ├── test_qiradb.py ├── test_static2.py └── testvm │ ├── Vagrantfile │ └── test.sh ├── requirements.txt ├── run_tests.sh ├── run_tests_static.sh ├── static2 ├── TESTING ├── analyzer.py ├── loader.py ├── model.py ├── static2.py └── testing.py ├── tests_auto ├── autogen-extras.sh ├── autogen.py └── source-autogen │ ├── argtest.c │ ├── aslrtest.c │ ├── call_mem.c │ ├── cfgifloop.c │ ├── changetest.c │ ├── demo.c │ ├── echo.c │ ├── forktest.c │ ├── forloop.c │ ├── functest.c │ ├── heapfunn.c │ ├── heaptest.c │ ├── loop.c │ ├── loophaxx.c │ ├── million.c │ ├── procselfmaps.c │ ├── slicingtest.c │ ├── stackframetest.c │ ├── switchtest.c │ └── test64.c ├── tests_manual ├── DBRUMLEY_0004_release ├── algo.c ├── arm-hello ├── arm-loop ├── bap │ └── run_pin.sh ├── bookstore ├── build_asm.sh ├── build_asm64.sh ├── busybox-i686 ├── busybox-mips ├── calltest.asm ├── checksec.sh ├── confound ├── coreutils_O0_echo ├── ctf │ ├── bctf │ │ ├── pattern-29123faa33d7d85163c7165ea6bd1662 │ │ └── qoobee-a53284060b93371c32322f8a522db98d │ ├── csaw │ │ └── exploit2 │ ├── dc2013 │ │ ├── avoir │ │ ├── bookworm │ │ ├── bookworm_noalarm │ │ ├── lonetuna │ │ └── reeses │ ├── dc2014 │ │ ├── eliza-arm │ │ ├── eliza_orig │ │ ├── imap │ │ ├── imapv1 │ │ ├── justify │ │ ├── justify_patched │ │ └── wdub2 │ ├── dc2015 │ │ └── tachikoma │ ├── deepblue-337848eb3f394204c016331a0e1b3b5a │ ├── exploits │ │ ├── ezhp.py │ │ └── ezhp_live.py │ ├── ezhp │ ├── gits2014 │ │ ├── fuzzy-29074b5fa6ed6aebb16390ef122ad61f7b9200ed │ │ ├── gitsmsg-04e8d34d76e3d6dedf79273dad97193377ecb3e3 │ │ └── ti-5b1ab693bc0298f8da4b22612d1a7683ed55d93a │ ├── hitcon │ │ ├── a679df07a8f3a8d590febad45336d031-stkof │ │ ├── hop-62fa7ade9a1fa9254361e69d70e7a7e3.exe │ │ └── ty-b83f0d0edeb8cfad76d30eddc58da139 │ ├── hudak │ ├── irkd │ ├── justify_exploit.py │ ├── membership │ ├── ombdsu │ ├── pctf │ │ └── harry_potter │ ├── secu │ │ ├── notes │ │ ├── numbers │ │ └── ws │ ├── secuquals │ │ └── TearsInWooyaggo │ ├── simple │ └── stkof_exploit.py ├── double_link ├── double_link.c ├── double_link_64 ├── doubleshell ├── doubleshell.c ├── haskell │ ├── hello │ ├── hello.hi │ ├── hello.hs │ └── hello.o ├── hello ├── hello.S ├── hello.c ├── helloc ├── jmpbug.asm ├── loop_macho32 ├── loop_macho64 ├── printesp.c ├── printesp32 ├── printesp64 ├── realworld │ ├── zpipe │ └── zpipe.c ├── stackframetest_x86 ├── suite │ ├── a679df07a8f3a8d590febad45336d031-stkof │ ├── deepblue-337848eb3f394204c016331a0e1b3b5a │ ├── echo64 │ ├── exploit2 │ ├── ezhp │ ├── hop-62fa7ade9a1fa9254361e69d70e7a7e3.exe │ ├── justify │ └── ty-b83f0d0edeb8cfad76d30eddc58da139 ├── supanoob ├── thread_test.c ├── vimplugin │ ├── a.out │ ├── main.c │ ├── swag.c │ └── swag.h ├── vortex │ ├── vortex4 │ └── vortex4.c └── windows │ ├── fibonacci32.exe │ ├── fibonacci64.exe │ ├── fibonacci64 │ ├── 14072703531940 │ ├── 14072703531940_base │ └── 14072703531940_strace │ └── paris.exe ├── tracers ├── angr │ └── angr_trace.py ├── concrete_executor │ ├── bitvector.py │ └── concrete_execution.py ├── pin │ ├── .gitignore │ ├── makefile │ ├── qirapin.cpp │ └── strace │ │ ├── gen_tables.py │ │ ├── osx_gen.py │ │ ├── osx_syscalls.h │ │ ├── syscallents_32.h │ │ ├── syscallents_64.h │ │ └── syscalls.h ├── pin_build.sh ├── qemu │ ├── .gitignore │ ├── qira-aarch64 │ ├── qira-arm │ ├── qira-i386 │ ├── qira-mips │ ├── qira-mipsel │ ├── qira-ppc │ └── qira-x86_64 └── qemu_build.sh └── web ├── client ├── compatibility │ ├── base.js │ ├── bignum.js │ ├── early.js │ ├── fakemeteor.js │ ├── font-awesome.min.css │ ├── head.core.min.js │ ├── highlight.js │ ├── jquery-2.1.1.min.js │ ├── jquery.contextMenu.css │ ├── jquery.contextMenu.js │ ├── jquery.ui.position.js │ ├── socket.io.min.js │ ├── wcDocker.min.css │ └── wcDocker.window-patch.js ├── controls.js ├── fonts │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── haddrline.js ├── ida.js ├── idump.js ├── regmem.js ├── static │ ├── graph.js │ └── static.js ├── strace.js ├── ui.js └── vtimeline.js ├── favicon.ico ├── index.html ├── qira_layout.css ├── qira_new.css ├── qira_theme.css └── qira_types.css /.gitignore: -------------------------------------------------------------------------------- 1 | web/.meteor/local 2 | .*.swp 3 | .*.swo 4 | tests/a.out 5 | tests/*.o 6 | *.pyc 7 | ida/*.o 8 | ida/qira.* 9 | ida/libwebsockets.a 10 | tests/idb 11 | old/qiradb/qiradb 12 | db/ 13 | qemu/qemu-2* 14 | distrib/ 15 | qiradb/build 16 | cda/include 17 | cda/clang-latest 18 | tests/system 19 | pin/pin-* 20 | pin/obj-* 21 | pin.log 22 | *~ 23 | cda/codesearch-* 24 | *.DS_Store 25 | /libs/ 26 | tests/bap/out.* 27 | tests/bap/*.log 28 | bap/ 29 | static/python32 30 | testvm/.vagrant 31 | radare 32 | venv 33 | capstone 34 | tests_auto/binary-autogen 35 | 36 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: true 2 | 3 | language: python 4 | 5 | python: 6 | - 2.7 7 | 8 | addons: 9 | apt: 10 | sources: 11 | - ubuntu-toolchain-r-test 12 | packages: 13 | - gcc-4.8 14 | - g++-4.8 15 | - clang 16 | 17 | install: 18 | - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi 19 | - ./install.sh 20 | 21 | script: 22 | - ./run_tests.sh 23 | - ./run_tests_static.sh 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, George Hotz 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.4 2 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | # system basics 4 | RUN apt-get update && apt-get -y install build-essential gcc-multilib g++-multilib lib32z1 git curl python python-virtualenv python-dev 5 | 6 | # qemu deps 7 | RUN apt-get -y install pkg-config zlib1g-dev libglib2.0-dev libpixman-1-dev 8 | 9 | WORKDIR /qira 10 | 11 | # install python venv 12 | RUN virtualenv venv 13 | RUN bash -c 'source venv/bin/activate && pip install --upgrade pip' 14 | 15 | # install python deps, this step will be cached 16 | COPY ./requirements.txt ./requirements.txt 17 | RUN bash -c 'source venv/bin/activate && pip install --upgrade -r requirements.txt' 18 | 19 | #build qemu and link qira 20 | COPY ./tracers ./tracers 21 | RUN cd tracers && ./qemu_build.sh 22 | RUN ln -sf /qira/qira /usr/local/bin/qira 23 | 24 | COPY . . 25 | 26 | # test will build Cython qiradb 27 | RUN ./run_tests.sh 28 | -------------------------------------------------------------------------------- /docker/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker build -t qira -f Dockerfile ../ 3 | -------------------------------------------------------------------------------- /docker/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # simple loop test 4 | #docker run --workdir /qira --rm qira bash -c "./run_tests.sh && ./run_tests_static.sh" 5 | docker run -p 3002:3002 --rm qira qira qira_tests/bin/loop 6 | 7 | -------------------------------------------------------------------------------- /extra/analysis/block_analysis.py: -------------------------------------------------------------------------------- 1 | from qira_log import * 2 | 3 | def do_block_analysis(dat): 4 | # look at addresses 5 | # if an address can accept control from two addresses, it starts a basic block 6 | # if an address can give control to two addresses, it ends a basic block 7 | # so add those two addresses to the basic block breaker set 8 | 9 | 10 | # address = [all that lead into it] 11 | prev_map = {} 12 | next_map = {} 13 | 14 | # address 15 | 16 | prev = None 17 | next_instruction = None 18 | 19 | basic_block_starts = set() 20 | 21 | for (address, data, clnum, flags) in dat: 22 | if not flags & IS_START: 23 | continue 24 | if next_instruction != None and next_instruction != address: 25 | # anytime we don't run the next instruction in sequence 26 | # this is a basic block starts 27 | # print next_instruction, address, data 28 | basic_block_starts.add(address) 29 | 30 | if address not in prev_map: 31 | prev_map[address] = set() 32 | if prev not in next_map: 33 | next_map[prev] = set() 34 | 35 | prev_map[address].add(prev) 36 | next_map[prev].add(address) 37 | prev = address 38 | next_instruction = address + data 39 | 40 | #print prev_map 41 | #print next_map 42 | 43 | # accepts control from two addresses 44 | for a in prev_map: 45 | if len(prev_map[a]) > 1: 46 | basic_block_starts.add(a) 47 | # gives control to two addresses 48 | for a in next_map: 49 | if len(next_map[a]) > 1: 50 | for i in next_map[a]: 51 | basic_block_starts.add(i) 52 | 53 | #print basic_block_starts 54 | 55 | blocks = [] 56 | cchange = None 57 | last = None 58 | 59 | for (address, data, clnum, flags) in dat: 60 | if not flags & IS_START: 61 | continue 62 | if cchange == None: 63 | cchange = (clnum, address) 64 | if address in basic_block_starts: 65 | blocks.append({'clstart': cchange[0], 'clend': last[0], 'start': cchange[1], 'end': last[1]}) 66 | cchange = (clnum, address) 67 | last = (clnum, address) 68 | 69 | blocks.append({'clstart': cchange[0], 'clend': last[0], 'start': cchange[1], 'end': last[1]}) 70 | return blocks 71 | 72 | 73 | -------------------------------------------------------------------------------- /extra/analysis/build_multigraph.py: -------------------------------------------------------------------------------- 1 | from qira_log import * 2 | from block_analysis import * 3 | import pydot 4 | 5 | dat = read_log("/tmp/qira_log") 6 | 7 | print "extracting blocks" 8 | blocks = do_block_analysis(dat) 9 | 10 | print "generating traces" 11 | 12 | arr = [] 13 | trace = [] 14 | cls = [] 15 | for i in range(len(blocks)): 16 | h = hex(blocks[i]['start']) + "-" + hex(blocks[i]['end']) 17 | if h not in arr: 18 | arr.append(h) 19 | trace.append(arr.index(h)) 20 | cls.append(blocks[i]['clstart']) 21 | 22 | 23 | # this is the whole graph with an edge between each pair 24 | #print trace 25 | #print cls 26 | 27 | graph = pydot.Dot(graph_type='digraph') 28 | 29 | print "adding nodes" 30 | nodes = [] 31 | for a in arr: 32 | n = pydot.Node(a, shape="box") 33 | graph.add_node(n) 34 | nodes.append(n) 35 | 36 | edges = [] 37 | cnts = [] 38 | 39 | print "trace size",len(trace) 40 | print "realblock count",len(arr) 41 | 42 | print "counting edges" 43 | for i in range(0, len(trace)-1): 44 | #e = pydot.Edge(nodes[trace[i]], nodes[trace[i+1]], label=str(cls[i+1]), headport="n", tailport="s") 45 | te = [nodes[trace[i]], nodes[trace[i+1]]] 46 | if te not in edges: 47 | edges.append(te) 48 | cnts.append(1) 49 | else: 50 | a = edges.index(te) 51 | cnts[a] += 1 52 | 53 | print "edge count",len(edges) 54 | 55 | print "adding edges" 56 | for i in range(len(edges)): 57 | te = edges[i] 58 | #print cnts[i] 59 | if cnts[i] > 1: 60 | e = pydot.Edge(te[0], te[1], headport="n", tailport="s", color="blue", label=str(cnts[i])) 61 | else: 62 | e = pydot.Edge(te[0], te[1], headport="n", tailport="s") 63 | graph.add_edge(e) 64 | 65 | print "drawing png" 66 | graph.write_png('/tmp/graph.png') 67 | 68 | 69 | -------------------------------------------------------------------------------- /extra/analysis/db_commit_blocks.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | from qira_log import * 3 | from function_analysis import * 4 | from loop_analysis import * 5 | from block_analysis import * 6 | 7 | db = MongoClient('localhost', 3001).meteor 8 | 9 | print "reading log" 10 | dat = read_log("/tmp/qira_log") 11 | fxns = do_function_analysis(dat) 12 | print fxns 13 | 14 | print "building blocks data" 15 | 16 | blocks = do_block_analysis(dat) 17 | 18 | for b in blocks: 19 | b['depth'] = get_depth(fxns, b['clstart']) 20 | 21 | (blocks, loops, realblocks, realtrace) = do_loop_analysis(blocks) 22 | 23 | print realtrace 24 | 25 | coll = db.fxns 26 | print "doing fxns insert" 27 | coll.drop() 28 | coll.insert(fxns) 29 | print "db insert done, building indexes" 30 | coll.ensure_index("clstart") 31 | coll.ensure_index("clend") 32 | print "indexes built" 33 | 34 | coll = db.loops 35 | print "doing loops insert" 36 | coll.drop() 37 | coll.insert(loops) 38 | print "db insert done, building indexes" 39 | coll.ensure_index("blockidx") 40 | print "indexes built" 41 | 42 | coll = db.realblocks 43 | print "doing db insert" 44 | coll.drop() 45 | coll.insert(realblocks) 46 | print "db insert done, building indexes" 47 | coll.ensure_index("start") 48 | coll.ensure_index("idx") 49 | print "realblocks idx built" 50 | 51 | coll = db.blocks 52 | print "doing db insert" 53 | coll.drop() 54 | coll.insert(blocks) 55 | print "db insert done, building indexes" 56 | coll.ensure_index("clstart") 57 | coll.ensure_index("clend") 58 | coll.ensure_index("start") 59 | coll.ensure_index("end") 60 | print "indexes built" 61 | 62 | -------------------------------------------------------------------------------- /extra/analysis/function_analysis.py: -------------------------------------------------------------------------------- 1 | from qira_log import * 2 | 3 | def do_function_analysis(dat): 4 | next_instruction = None 5 | 6 | fxn_stack = [] 7 | cancel_stack = [] 8 | cl_stack = [] 9 | 10 | fxn = [] 11 | 12 | for (address, data, clnum, flags) in dat: 13 | if not flags & IS_START: 14 | continue 15 | if address in cancel_stack: 16 | # reran this address, this isn't return 17 | idx = cancel_stack.index(address) 18 | fxn_stack = fxn_stack[0:idx] 19 | cancel_stack = cancel_stack[0:idx] 20 | cl_stack = cl_stack[0:idx] 21 | #print map(hex, fxn_stack), clnum, "cancel" 22 | if address in fxn_stack: 23 | idx = fxn_stack.index(address) 24 | fxn.append({"clstart":cl_stack[idx],"clend":(clnum-1)}) 25 | fxn_stack = fxn_stack[0:idx] 26 | cancel_stack = cancel_stack[0:idx] 27 | cl_stack = cl_stack[0:idx] 28 | #print map(hex, fxn_stack), clnum, "return" 29 | elif next_instruction != None and next_instruction != address: 30 | fxn_stack.append(next_instruction) 31 | cancel_stack.append(last_instruction) 32 | cl_stack.append(clnum) 33 | #print map(hex, fxn_stack), clnum 34 | next_instruction = address + data 35 | last_instruction = address 36 | return fxn 37 | 38 | def get_depth(fxns, clnum): 39 | d = 0 40 | for f in fxns: 41 | if clnum >= f['clstart'] and clnum <= f['clend']: 42 | d += 1 43 | return d 44 | 45 | if __name__ == "__main__": 46 | dat = read_log("/tmp/qira_log") 47 | print do_function_analysis(dat) 48 | 49 | -------------------------------------------------------------------------------- /extra/analysis/loop_analysis.py: -------------------------------------------------------------------------------- 1 | def do_loop_analysis(blocks): 2 | #blocks = blocks[0:0x30] 3 | arr = [] 4 | bb = [] 5 | ab = [] 6 | 7 | realblocks = [] 8 | realtrace = [] 9 | 10 | idx = 0 11 | for i in range(len(blocks)): 12 | h = hex(blocks[i]['start']) + "-" + hex(blocks[i]['end']) 13 | if h not in arr: 14 | realblocks.append({'start': blocks[i]['start'], 'end': blocks[i]['end'], 'idx': idx}) 15 | idx += 1 16 | arr.append(h) 17 | realtrace.append(arr.index(h)) 18 | bb.append(arr.index(h)) 19 | ab.append(i) 20 | 21 | loops = [] 22 | # write this n^2 then make it fast 23 | did_update = True 24 | while did_update: 25 | did_update = False 26 | for i in range(len(bb)): 27 | for j in range(1,i): 28 | # something must run 3 times to make it a loop 29 | if bb[i:i+j] == bb[i+j:i+j*2] and bb[i:i+j] == bb[i+j*2:i+j*3]: 30 | loopcnt = 1 31 | while bb[i+j*loopcnt:i+j*(loopcnt+1)] == bb[i:i+j]: 32 | loopcnt += 1 33 | #print "loop",bb[i:i+j],"@",i,"with count",loopcnt 34 | # document the loop 35 | loop = {"clstart":blocks[ab[i]]['clstart'], 36 | "clendone":blocks[ab[i+j-1]]['clend'], 37 | "clend":blocks[ab[i+j*loopcnt]]['clend'], 38 | "blockstart":ab[i], 39 | "blockend":ab[i]+j-1, 40 | "count": loopcnt} 41 | # remove the loop from the blocks 42 | bb = bb[0:i] + bb[i:i+j] + bb[i+j*loopcnt:] 43 | ab = ab[0:i] + ab[i:i+j] + ab[i+j*loopcnt:] 44 | print loop 45 | loops.append(loop) 46 | did_update = True 47 | break 48 | if did_update: 49 | break 50 | 51 | ret = [] 52 | for i in ab: 53 | t = blocks[i] 54 | t["blockidx"] = i 55 | ret.append(t) 56 | return (ret, loops, realblocks, realtrace) 57 | 58 | 59 | -------------------------------------------------------------------------------- /extra/byteweight/README: -------------------------------------------------------------------------------- 1 | ByteWeight is a function identification project for cross platforms. It is based 2 | on CMU Binary Analysis Platform. 3 | 4 | Current code contains both training and testing implementation. To train out 5 | signature file, one should use train by: 6 | ./train -bin-dir [training binary] -sig [output signature file] 7 | -------------------------------------------------------------------------------- /extra/byteweight/_oasis: -------------------------------------------------------------------------------- 1 | OASISFormat: 0.4 2 | Name: byteweight 3 | Version: 0.1 4 | Synopsis: Function Identification Tool 5 | Authors: Tiffany Bao 6 | License: MIT 7 | Plugins: META (0.4), DevFiles (0.4) 8 | BuildTools: ocamlbuild 9 | BuildDepends: str, 10 | bap-lifter, 11 | bap-types, 12 | bap-container 13 | 14 | Library "byteweight" 15 | Path: . 16 | BuildTools: ocamlbuild 17 | Modules: Byteweight 18 | CompiledObject: best 19 | 20 | Executable "byteweight" 21 | Path: . 22 | MainIs: byteweight.ml 23 | CompiledObject: best 24 | 25 | Executable "train" 26 | Path: . 27 | MainIs: train.ml 28 | CompiledObject: best 29 | -------------------------------------------------------------------------------- /extra/byteweight/byte.ml: -------------------------------------------------------------------------------- 1 | 2 | let generate_keys bytes = 3 | let rec rec_g res bytes = 4 | let len = String.length bytes in 5 | if len == 0 then res 6 | else 7 | let tl_bytes = 8 | String.sub bytes 0 (len-1) 9 | in 10 | rec_g (bytes :: res) tl_bytes 11 | in 12 | rec_g [] bytes 13 | 14 | (*consecutive : addr -> addr -> int -> Exec_container.t -> string *) 15 | let consecutive addr end_addr len container = 16 | let real_end = 17 | let max_addr = Bitvector.plus addr (Bitvector.lit len 32) in 18 | if Bitvector.bool_of (Bitvector.lt end_addr max_addr) then end_addr 19 | else max_addr 20 | in 21 | Exec_container.Reader.get_bytes container addr real_end 22 | -------------------------------------------------------------------------------- /extra/byteweight/byteweight.ml: -------------------------------------------------------------------------------- 1 | (* TODO: convert to Core_list? *) 2 | module DismTrie = Dism.Trie 3 | let usage = "./match [binary file]" 4 | let k = 10 5 | 6 | let g_wpt = Filename.concat (Filename.dirname Sys.executable_name) "signatures/sig_arm" 7 | 8 | let threshold = ref 0.5 9 | let d_bin = ref None 10 | let d_out = ref None 11 | let bin = ref None 12 | let out = ref stdout 13 | let f_wpt = ref g_wpt 14 | (* let arch = ref None *) 15 | 16 | let arg_specs = 17 | ("-wpt", Arg.String(fun s -> f_wpt := s), "weighted prefix tree file") 18 | :: ("-bin-dir", Arg.String(fun s -> d_bin := Some s), "test binary directory") 19 | (* :: ("-bin", Arg.String(fun s -> bin := Some s), "test binary") *) 20 | :: ("-o-dir", Arg.String(fun s -> d_out := Some s; try Unix.mkdir s 0o755 with _ -> ()), "output directory") 21 | :: ("-o", Arg.String(fun s -> out := open_out s), "output file") 22 | :: ("-t", Arg.Float(fun f -> threshold := f), "threshold") 23 | (* Question: can BAP infer architecture from binaries? *) 24 | :: [] 25 | 26 | let anon_fun s = bin := Some s 27 | 28 | 29 | (* fsi_container : Trie.t -> Container.exec_container -> addr list -> addr list *) 30 | let fsi_container trie container codes = 31 | let fs_sec = List.map (fun (start_addr, end_addr) -> 32 | (* score : Trie.t -> addr -> float *) 33 | let score addr = 34 | let disms = Dism.consecutive addr end_addr k container in 35 | DismTrie.find trie disms 36 | in 37 | 38 | let rec rec_score addr fs = 39 | if (Bitvector.bool_of (Bitvector.lt end_addr addr)) then fs 40 | else 41 | let s = score addr in 42 | if s > !threshold then 43 | rec_score (Bitvector.incr addr) (addr :: fs) 44 | else 45 | rec_score (Bitvector.incr addr) fs 46 | in 47 | 48 | rec_score start_addr [] 49 | ) codes in 50 | (* List.concat fs_sec *) 51 | (* List.concat is not tail-recursive, so I use List.fold_left instead *) 52 | List.sort 53 | Bitvector.compare 54 | (List.fold_left (fun res l -> List.rev_append (List.rev res) l) [] fs_sec) 55 | 56 | 57 | (* output: out_channel -> addr list -> unit *) 58 | let output oc fsi = 59 | List.iter (fun addr -> 60 | Printf.fprintf oc "%s\n" (Bitvector.to_hex addr) 61 | ) fsi; 62 | close_out oc 63 | 64 | let get_code_segments container = 65 | let sections = Exec_container.Reader.get_sections container in 66 | List.fold_left ( 67 | fun res {Exec_container.start_addr=start_addr; 68 | Exec_container.end_addr=end_addr; 69 | Exec_container.permissions=permissions} -> 70 | if List.mem Exec_container.X permissions then 71 | (start_addr, end_addr) :: res 72 | else 73 | res 74 | ) [] sections 75 | 76 | (* fsi_bin : string -> Trie.t -> addr list *) 77 | let fsi_bin bin trie = 78 | let exec_container = Dism.get_container bin in 79 | match exec_container with 80 | | None -> failwith (Printf.sprintf "Binary Load Error %s" bin) 81 | | Some container -> 82 | (* codes: (addr * addr) list *) 83 | let codes = get_code_segments container in 84 | (* List.iter (fun (st, en) -> Printf.printf "%s %s\n%!" 85 | (Bitvector.to_hex st) (Bitvector.to_hex en)) codes; *) 86 | fsi_container trie container codes 87 | 88 | 89 | (* main *) 90 | let () = 91 | let () = Arg.parse arg_specs anon_fun usage in 92 | match !bin, !d_bin with 93 | | None, Some d_i -> ( 94 | match !d_out with 95 | | None -> 96 | let err = 97 | Printf.sprintf "Output directory is required.\n" ^ usage 98 | in 99 | raise (Arg.Bad err) 100 | | Some d_o -> 101 | let trie = Dism.load !f_wpt in 102 | let bins = List.map 103 | (Filename.concat d_i) 104 | (Array.to_list (Sys.readdir d_i)) 105 | in 106 | List.iter (fun bin -> 107 | let fs = fsi_bin bin trie in 108 | let oc = 109 | let bin_out = Filename.concat d_o (Filename.basename bin) in 110 | open_out bin_out 111 | in 112 | output oc fs 113 | ) bins 114 | ) 115 | | Some i, None -> 116 | let trie = Dism.load !f_wpt in 117 | let fs = fsi_bin i trie in 118 | output !out fs 119 | | _ -> raise (Arg.Bad usage) 120 | 121 | 122 | (* get_functions: exec_container -> addr list *) 123 | let get_functions container = 124 | let trie = Dism.load g_wpt in 125 | let codes = get_code_segments container in 126 | fsi_container trie container codes 127 | -------------------------------------------------------------------------------- /extra/byteweight/byteweight.mli: -------------------------------------------------------------------------------- 1 | val get_functions : Exec_container.t -> Exec_container.addr list 2 | -------------------------------------------------------------------------------- /extra/byteweight/dism.ml: -------------------------------------------------------------------------------- 1 | exception No_Dism 2 | module Instr = struct 3 | type t = string 4 | let equal i j = i = j 5 | let hash = Hashtbl.hash 6 | end 7 | 8 | module M = struct 9 | module D = Hashtbl.Make(Instr) 10 | include D 11 | let format a = a 12 | end 13 | 14 | module Trie = Trie.Make(M) 15 | 16 | let sep = ";" 17 | 18 | (* read_from_ic : in_channel -> string list * float *) 19 | let read_from_ic ic = 20 | let to_dism_score line = 21 | let words = Str.split (Str.regexp "->") line in 22 | match words with 23 | | [disms_str; counts] -> 24 | let disms = Str.split (Str.regexp ";") disms_str in 25 | let p, n = 26 | let p_n = Str.split (Str.regexp ",") counts in 27 | match p_n with 28 | | [p;n] -> float_of_string p, float_of_string n 29 | | _ -> failwith "WPT File Format error" 30 | in 31 | disms, (p /. (p +. n)) 32 | | _ -> failwith "WPT File Format error" 33 | in 34 | let sigs = ref [] in 35 | try 36 | while true; do 37 | let line = input_line ic in 38 | let disms, score = to_dism_score line in 39 | sigs := (disms, score) :: !sigs 40 | done; 41 | [] 42 | with End_of_file -> 43 | close_in ic; 44 | !sigs 45 | 46 | let load file = 47 | let ic = open_in file in 48 | (* sigs : string list * float *) 49 | let sigs = read_from_ic ic in 50 | let trie = Trie.init 0.0 in 51 | List.iter (fun (k, v) -> 52 | Trie.add trie k v 53 | ) sigs; 54 | trie 55 | 56 | let get_disasm container addr = 57 | let module ARM = Arch_arm.ARM in 58 | (* Printf.printf "%s\n" (Bitvector.to_hex addr); *) 59 | let _, _, fallthrough, dism = 60 | ARM.disasm ARM.init_state (fun addr -> 61 | String.get 62 | (Exec_container.Reader.get_bytes container addr (Bitvector.incr addr)) 0 63 | ) addr 64 | in 65 | match dism with 66 | | None -> raise No_Dism 67 | | Some d -> d, fallthrough 68 | 69 | 70 | (* consecutive: addr -> addr -> int -> Container.exec_container -> asm list *) 71 | let consecutive addr end_addr len container = 72 | let rec rec_consecutive addr i disms = 73 | if (i >= len) || (Bitvector.bool_of (Bitvector.lt end_addr addr)) then 74 | List.rev disms 75 | else try ( 76 | let dism, fallthrough = get_disasm container addr in 77 | rec_consecutive fallthrough (i + 1) (Normalize.normalize dism :: disms) 78 | ) 79 | with _ -> List.rev disms 80 | in 81 | rec_consecutive addr 0 [] 82 | 83 | 84 | let get_container bin = 85 | let ic = open_in_bin bin in 86 | let buf = String.create (in_channel_length ic) in 87 | let () = really_input ic buf 0 (String.length buf) in 88 | let () = close_in ic in 89 | Elf_container.load_executable buf 90 | 91 | 92 | let generate_keys disms = 93 | let rec rec_g res prefix = function 94 | | [] -> res 95 | | hd :: tl -> 96 | let new_key = 97 | if prefix = "" then hd 98 | else Printf.sprintf "%s%s%s" prefix sep hd 99 | in 100 | rec_g (new_key :: res) new_key tl 101 | in 102 | rec_g [] "" disms 103 | 104 | -------------------------------------------------------------------------------- /extra/byteweight/mock.ml: -------------------------------------------------------------------------------- 1 | open Core_kernel.Std 2 | open Or_error 3 | open Dwarf 4 | 5 | module Buffer = Dwarf_data.Buffer 6 | (* 7 | let fb bin = 8 | let tmp_file = Filename.temp_file bin ".tmp" in 9 | let command = 10 | Printf.sprintf 11 | "arm-linux-gnueabi-objdump -t %s | grep \"F .text\" | \ 12 | gawk `{ \ 13 | start=strtonum(\"0x\"$1); \ 14 | size=strtonum(\"0x\"$5); \ 15 | printf(\"%%x %%x\\n\", start, start+size)}` | sort -u > %s" 16 | bin tmp_file 17 | in 18 | let () = Sys.command command in 19 | read_fb tmp_file 20 | *) 21 | 22 | let read_fs filename = 23 | let lines = In_channel.read_lines filename in 24 | List.map lines ~f: (fun line -> 25 | let addr_int = int_of_string (Printf.sprintf "0x%s" line) in 26 | Bitvector.lit addr_int 32 27 | ) 28 | 29 | let fs bin = 30 | let tmp_file = Filename.temp_file (Filename.basename bin) ".tmp" in 31 | let command = 32 | Printf.sprintf 33 | "arm-linux-gnueabi-objdump -t %s | grep \"F .text\" | \ 34 | awk '{print $1}' | sort -u > %s" 35 | bin tmp_file 36 | in 37 | (* Printf.printf "%s%!" command; *) 38 | let _ = Sys.command command in 39 | read_fs tmp_file 40 | (* 41 | let fs_dwarf filename = 42 | let filedata = In_channel.read_all filename in 43 | match Elf.parse filedata with 44 | | None -> (*errorf "%s is not an elf file\n" filename *) [] 45 | | Some elf -> 46 | let open Elf in 47 | let endian = match elf.e_data with 48 | | ELFDATA2LSB -> LittleEndian 49 | | ELFDATA2MSB -> BigEndian in 50 | let create name s = Some (name, Buffer.create s.sh_data) in 51 | let sections = List.filter_map elf.e_sections ~f:(fun s -> 52 | match s.sh_name with 53 | | ".debug_info" -> create Section.Info s 54 | | ".debug_abbrev" -> create Section.Abbrev s 55 | | ".debug_str" -> create Section.Str s 56 | | _ -> None) in 57 | match Dwarf_data.create endian sections with 58 | | Ok data -> 59 | (match Dff.create data with 60 | | Ok dff -> 61 | let seq = Sequence.map (Dff.functions dff) ~f:(fun (_, fn) -> 62 | match Dff.Fn.pc_lo fn with 63 | | Dwarf.Addr.Int64 x -> Bitvector.litz (Z.of_int64 x) 64 64 | | Dwarf.Addr.Int32 x -> Bitvector.litz (Z.of_int32 x) 32 65 | ) in 66 | Sequence.to_list seq 67 | | Error err -> (* eprintf "error" @@ Error.to_string_hum err; *) []) 68 | | _ -> [] 69 | *) 70 | 71 | let dwarf_to_bitvector = function 72 | | Dwarf.Addr.Int64 x -> Bitvector.litz (Z.of_int64 x) 64 73 | | Dwarf.Addr.Int32 x -> Bitvector.litz (Z.of_int32 x) 32 74 | 75 | let fs_dwarf filename = 76 | let filedata = In_channel.read_all filename in 77 | let res = 78 | match Elf.parse filedata with 79 | | None -> errorf "%s is not an elf file\n" filename 80 | | Some elf -> 81 | let open Elf in 82 | let endian = match elf.e_data with 83 | | ELFDATA2LSB -> LittleEndian 84 | | ELFDATA2MSB -> BigEndian in 85 | let create name s = Some (name, Buffer.create s.sh_data) in 86 | let sections = List.filter_map elf.e_sections ~f:(fun s -> 87 | match s.sh_name with 88 | | ".debug_info" -> create Section.Info s 89 | | ".debug_abbrev" -> create Section.Abbrev s 90 | | ".debug_str" -> create Section.Str s 91 | | _ -> None) in 92 | Dwarf_data.create endian sections >>= fun data -> 93 | Dff.create data >>| fun dff -> 94 | let seq = Sequence.map (Dff.functions dff) ~f:(fun (_, fn) -> 95 | dwarf_to_bitvector (Dff.Fn.pc_lo fn) 96 | ) in 97 | Sequence.to_list seq 98 | in match res with 99 | | Ok x -> 100 | (* 101 | let gt = Filename.concat "gt_dwarf" (Filename.basename filename) in 102 | Out_channel.write_lines gt (List.map x ~f:Bitvector.to_hex); 103 | *) 104 | x 105 | | Error err -> Printf.printf "dwarf error %s: %s\n" filename 106 | (Error.to_string_hum err); [] 107 | -------------------------------------------------------------------------------- /extra/byteweight/normalize.ml: -------------------------------------------------------------------------------- 1 | type t_arch = 2 | | Arm 3 | | X86 4 | | X86_64 5 | 6 | 7 | let replace_patt str patt = 8 | Str.global_replace (Str.regexp patt) patt str 9 | 10 | let normalize ?(arch=None) s = 11 | let s_trimmed = String.trim s in 12 | let s_normalized = 13 | match arch with 14 | | None | Some Arm -> 15 | let norm_const = 16 | let neg = "#-[1-9a-f][0-9a-f]*" 17 | and pos = "#[1-9a-f][0-9a-f]*" 18 | and zero = "#0+" in 19 | List.fold_left replace_patt s_trimmed [neg;pos;zero] 20 | in 21 | let norm_branch = 22 | let bl = "^b\\(l\\)?[ \t]+[1-9a-f]+" in 23 | replace_patt norm_const bl 24 | in 25 | norm_branch 26 | | Some X86 27 | | Some X86_64 -> 28 | let norm_const = 29 | let neg = "-\\(\\$\\)?\\(0x\\)?[0-9a-f]+" 30 | and pos = "\\(\\$\\)?\\(0x\\)?[0-9a-f]+" 31 | and zero = "\\(\\$\\)?\\(0x\\)?0+" in 32 | List.fold_left replace_patt s_trimmed [neg;pos;zero] 33 | in 34 | let norm_branch = 35 | let jump = "^j[a-z]+[ \t]+\\(\\*\\)?[0-9a-f]+" 36 | and call = "^call[a-z]+[ \t]+\\(\\*\\)?[0-9a-f]+" in 37 | List.fold_left replace_patt norm_const [jump;call] 38 | in 39 | norm_branch 40 | in 41 | let s_stripped = 42 | let s_splitted = Str.split (Str.regexp "[ \t]+") s_normalized in 43 | String.concat "" s_splitted 44 | in 45 | (* Printf.printf "====\n%s\n%s\n====\n%!" s s_stripped; *) 46 | s_stripped 47 | -------------------------------------------------------------------------------- /extra/byteweight/trie.ml: -------------------------------------------------------------------------------- 1 | module type M = sig 2 | type 'a t 3 | type key 4 | val create : int -> 'a t 5 | val iter : (key -> 'a -> unit) -> 'a t -> unit 6 | val add : 'a t -> key -> 'a -> unit 7 | val replace : 'a t -> key -> 'a -> unit 8 | val find : 'a t -> key -> 'a 9 | val format : key -> string 10 | end 11 | 12 | module type TRIE = sig 13 | type 'a t 14 | type key 15 | val init : 'a -> 'a t 16 | val add : 'a t -> key -> 'a -> unit 17 | val find : 'a t -> key -> 'a 18 | val output : 'a t -> string -> ('a -> string) -> unit 19 | end 20 | 21 | 22 | module Make (M : M) : (TRIE with type key = M.key list) = struct 23 | type key = M.key list 24 | type 'a t = Node of 'a * 'a t M.t 25 | 26 | let init v = Node (v, M.create 10) 27 | 28 | (* add : 'a t -> key -> 'a -> unit *) 29 | let rec add trie k v = match k with 30 | | [] -> () 31 | | hd :: [] -> ( 32 | match trie with 33 | | Node (_, m) -> 34 | try 35 | match (M.find m hd) with 36 | | Node (_, sub) -> M.replace m hd (Node (v, sub)) 37 | with Not_found -> 38 | (* If this is a new node, add to its father node's map *) 39 | let subtrie_init = init v in 40 | M.add m hd subtrie_init 41 | ) 42 | | hd :: tl -> 43 | match trie with 44 | | Node (_, m) -> 45 | let subtrie = 46 | try 47 | M.find m hd 48 | with Not_found -> ( 49 | (* If this is a new node, add to its father node's map *) 50 | let subtrie_init = init v in 51 | M.add m hd subtrie_init; 52 | subtrie_init 53 | ) 54 | in 55 | add subtrie tl v 56 | 57 | (* find : 'a t -> key -> 'a -> 'a *) 58 | (* find : return the longest match *) 59 | let find trie k = 60 | let rec rec_find trie k t_v = match k with 61 | | [] -> t_v 62 | | hd :: tl -> 63 | match trie with 64 | | Node (_, m) -> 65 | try 66 | (* let subtrie = M.find m hd in 67 | match subtrie with *) 68 | match M.find m hd with 69 | | Node (v, _) as subtrie -> 70 | rec_find subtrie tl v 71 | (* Not_found means reach the longest match, so return t_v *) 72 | with Not_found -> 73 | t_v 74 | in 75 | let root_v = match trie with 76 | | Node (v, _) -> v 77 | in 78 | rec_find trie k root_v 79 | 80 | (* output : 'a t -> string -> ('a -> string) -> unit *) 81 | let output trie file format_v = 82 | let oc = open_out file in 83 | let rec rec_output prefix = function 84 | | Node (v, m) -> 85 | Printf.fprintf oc "%s->%s\n" (String.concat ";" (List.rev prefix)) (format_v v); 86 | M.iter (fun k v -> 87 | rec_output (M.format k :: prefix) v 88 | ) m 89 | in 90 | rec_output [] trie; 91 | close_out oc 92 | end 93 | 94 | (* 95 | module type DISM = sig 96 | type t 97 | val equal : t -> t -> bool 98 | val hash : t -> int 99 | end 100 | 101 | module Dism : DISM = struct 102 | type t = string 103 | let equal i j = i = j 104 | let hash = Hashtbl.hash 105 | end 106 | 107 | module M = struct 108 | module D = Hashtbl.Make(Dism) 109 | include D 110 | let format a = a 111 | end 112 | 113 | module DismTrie = Make(M) *) 114 | -------------------------------------------------------------------------------- /extra/byteweight/trie.mli: -------------------------------------------------------------------------------- 1 | module type M = sig 2 | type 'a t 3 | type key 4 | val create : int -> 'a t 5 | val iter : (key -> 'a -> unit) -> 'a t -> unit 6 | val add : 'a t -> key -> 'a -> unit 7 | val replace : 'a t -> key -> 'a -> unit 8 | val find : 'a t -> key -> 'a 9 | val format : key -> string 10 | end 11 | 12 | module type TRIE = sig 13 | type 'a t 14 | type key 15 | val init : 'a -> 'a t 16 | val add : 'a t -> key -> 'a -> unit 17 | val find : 'a t -> key -> 'a 18 | val output : 'a t -> string -> ('a -> string) -> unit 19 | end 20 | 21 | module Make (M : M) : (TRIE with type key = M.key list) 22 | -------------------------------------------------------------------------------- /extra/cda/cachegen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.7 2 | import os 3 | import sys 4 | import cda_config 5 | 6 | basedir = os.path.dirname(os.path.realpath(__file__)) 7 | #sys.path.append(basedir+"/clang/llvm/tools/clang/bindings/python") 8 | import clang.cindex as ci 9 | ci.Config.set_library_file(cda_config.LIBCLANG_PATH) 10 | 11 | import pickle 12 | from clang.cindex import CursorKind 13 | 14 | import json 15 | from hashlib import sha1 16 | 17 | # debug 18 | DEBUG = 0 19 | 20 | # cache generated 21 | file_cache = {} 22 | object_cache = {} 23 | xref_cache = {} 24 | 25 | # a single index for the runtime of the server 26 | index = ci.Index.create() 27 | 28 | def parse_node(node, d, filename, care): 29 | #print node.location.file 30 | if node.location.file != None and str(node.location.file) != filename: 31 | return 32 | 33 | ref = node.referenced 34 | if type(ref) != type(None): 35 | usr = ref.get_usr() 36 | #print " "*d, node.kind, node.spelling, node.displayname, node.location, node.extent.start.offset, node.extent.end.offset, node.get_usr(), "****", ref.spelling, ref.location, ref.get_usr() 37 | else: 38 | usr = None 39 | 40 | if DEBUG == 1: 41 | print " "*d, node.kind, node.spelling, node.displayname, node.location, node.location.offset, node.extent.start.offset, node.extent.end.offset, usr 42 | 43 | """ 44 | if DEBUG == 1: 45 | print " "*d, node.kind, node.spelling, node.displayname, node.location, node.location.offset, node.extent.start.offset, node.extent.end.offset, usr 46 | """ 47 | 48 | #print dir(node) 49 | """ 50 | print ref, node.get_usr() 51 | print ref.location 52 | for i in deff: 53 | print i 54 | """ 55 | 56 | klass = str(node.kind).split('.')[-1] 57 | (start, end) = (None, None) 58 | if node.kind in [CursorKind.STRING_LITERAL, CursorKind.INTEGER_LITERAL, CursorKind.TYPE_REF, CursorKind.TEMPLATE_REF]: 59 | #if node.kind in [CursorKind.STRING_LITERAL, CursorKind.TYPE_REF, CursorKind.TEMPLATE_REF]: 60 | start = node.extent.start.offset 61 | end = node.extent.end.offset 62 | elif node.kind in [CursorKind.FUNCTION_DECL, CursorKind.FUNCTION_TEMPLATE, CursorKind.VAR_DECL, CursorKind.CLASS_DECL, CursorKind.CXX_METHOD, CursorKind.CLASS_TEMPLATE, CursorKind.PARM_DECL]: 63 | start = node.location.offset 64 | end = node.location.offset + len(node.spelling) 65 | elif node.kind in [CursorKind.MEMBER_REF_EXPR]: 66 | #print node.location.offset, node.extent.start.offset, node.extent.end.offset 67 | if node.location.offset != 0: 68 | start = node.location.offset 69 | else: 70 | start = node.extent.start.offset 71 | end = node.extent.end.offset 72 | #end = node.location.offset + len(node.displayname) 73 | elif node.kind in [CursorKind.DECL_REF_EXPR]: 74 | start = node.location.offset 75 | end = node.extent.end.offset 76 | 77 | if end != None: 78 | care.append((start, end, klass, usr)) 79 | 80 | if end != None and usr != None and node.location.line > 0: 81 | newval = filename+"#"+str(node.location.line) 82 | if node.is_definition(): 83 | # defining the object 84 | if usr in object_cache: 85 | object_cache[usr].append(newval) 86 | else: 87 | object_cache[usr] = [newval] 88 | else: 89 | # xref 90 | if usr in xref_cache: 91 | xref_cache[usr].append(newval) 92 | else: 93 | xref_cache[usr] = [newval] 94 | # link here is good 95 | 96 | for child in node.get_children(): 97 | parse_node(child, d+1, filename, care) 98 | 99 | def parse_file(filename, args=[]): 100 | # traversal attack 101 | exargs = ["-I", cda_config.CLANG_INCLUDES] 102 | tu = index.parse(filename, args=exargs+args) 103 | 104 | # bad shit happened 105 | bad = False 106 | for m in tu.diagnostics: 107 | if m.severity >= 3: 108 | print m 109 | bad = True 110 | if bad == True: 111 | #raise Exception("parsing issue") 112 | print "parsing issue" 113 | 114 | # extract the things we care about 115 | care = [] 116 | parse_node(tu.cursor, 0, filename, care) 117 | care = sorted(care) 118 | 119 | # get file data 120 | rdat = open(filename).read() 121 | 122 | return (care, rdat) 123 | 124 | def parse_files(files, args=[]): 125 | # for unbuilt clang 126 | for fn in files: 127 | print "CDA: caching",fn 128 | try: 129 | file_cache[fn] = parse_file(fn, args) 130 | except Exception as e: 131 | print "CDA: error on",fn,":",e 132 | dat = (object_cache, file_cache, xref_cache) 133 | return dat 134 | 135 | -------------------------------------------------------------------------------- /extra/cda/cacheserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.7 2 | import os 3 | import sys 4 | import cgi 5 | from flask import Flask,redirect,request,Blueprint 6 | from html import XHTML 7 | 8 | app = Blueprint('cda',__name__) 9 | 10 | # escape on the real 11 | def escape(s, crap=False): 12 | return s.replace("<", "<").replace(">", ">").replace(" ", " ").replace("\n", "
").replace("\t", " "*4).replace("\x00", " ") 13 | cgi.escape = escape 14 | 15 | @app.route("/list") 16 | def list(): 17 | h = XHTML().html 18 | for f in sorted(file_cache.keys()): 19 | h.body.div.a(f, href="#"+f+",0,") 20 | return str(h) 21 | 22 | # only path that should be here now 23 | @app.route("/cda") 24 | def home(): 25 | # generate html 26 | h = XHTML().html 27 | h.head.link(rel="stylesheet", href="/cdastatic/cda.css") 28 | h.head.script(src="/cdastatic/socket.io.min.js") 29 | h.head.script(src="/cdastatic/jquery-2.1.0.js") 30 | h.head.script(src="/cdastatic/jquery.scrollTo.min.js") 31 | h.head.script(src="/cdastatic/cda.js?"+os.urandom(16).encode("hex")) 32 | body = h.body 33 | prog = body.div(id="program") 34 | xrefs = body.div(id="xrefs") 35 | 36 | return str(h) 37 | 38 | @app.route("/x/") 39 | def display_xref(b64xref): 40 | xref = b64xref.decode("base64") 41 | h = XHTML().html 42 | h.head.link(rel="stylesheet", href="/cdastatic/cda.css") 43 | body = h.body(klass="xref") 44 | body.div.div(xref, klass="xrefstitle") 45 | if xref in xref_cache: 46 | for obj in xref_cache[xref]: 47 | linkobj = obj.replace("#",",")+","+b64xref 48 | body.div.a(obj, onclick="location.replace('#"+linkobj+"')", klass="filelink") 49 | return str(body) 50 | 51 | @app.route("/f") 52 | def display_file(): 53 | path = request.query_string 54 | if path not in file_cache: 55 | return "file "+str(path)+" not found" 56 | # generate the HTML 57 | h = XHTML().html 58 | body = h.body 59 | body.div(path, id='filename') 60 | #body.iframe(id='bottomframe') 61 | 62 | # get parsed file 63 | (care, rdat) = file_cache[path] 64 | 65 | # add line numbers 66 | lc = len(rdat.split("\n")) 67 | ln = body.div(id="ln") 68 | for linenum in range(lc): 69 | ln.span("%5d \n" % (linenum+1), id="l"+str(linenum+1), onclick='go_to_line('+str(linenum+1)+')') 70 | 71 | # add the code 72 | #print object_cache 73 | p = body.div(id="code") 74 | last = 0 75 | for (start, end, klass, usr) in care: 76 | if last > start: 77 | # this is not the proper fix 78 | #print "OMG ISSUE ",last,start,klass,usr 79 | continue 80 | p.span(rdat[last:start]) 81 | if usr != None: 82 | if usr in object_cache: 83 | #p.span(klass=klass, usr=usr).a(rdat[start:end], href="/f/"+object_cache[usr][0]) 84 | #if usr in xref_cache: 85 | #p.span(rdat[start:end], klass=klass+"\x00link", usr=usr, targets='\x00'.join(object_cache[usr]), xrefs='\x00'.join(xref_cache[usr])) 86 | #else: 87 | p.span(rdat[start:end], klass=klass+"\x00link", name=usr, targets='\x00'.join(object_cache[usr])) 88 | else: 89 | p.span(rdat[start:end], klass=klass, name=usr) 90 | else: 91 | p.span(rdat[start:end], klass=klass) 92 | last = end 93 | p.span(rdat[last:]) 94 | 95 | return str(body) 96 | 97 | def set_cache(cache): 98 | global object_cache, file_cache, xref_cache 99 | (object_cache, file_cache, xref_cache) = cache 100 | print "CDA: read",len(file_cache),"files",len(object_cache),"objects",len(xref_cache),"xrefs" 101 | 102 | -------------------------------------------------------------------------------- /extra/cda/cda_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | echo "installing cda packages" 4 | sudo apt-get install libclang-3.4-dev 5 | 6 | echo "installing codesearch" 7 | wget -O /tmp/cs.zip https://codesearch.googlecode.com/files/codesearch-0.01-linux-amd64.zip 8 | unzip -o /tmp/cs.zip 9 | rm /tmp/cs.zip 10 | ln -sf codesearch-0.01 codesearch-latest 11 | 12 | -------------------------------------------------------------------------------- /extra/cda/cda_config.py: -------------------------------------------------------------------------------- 1 | #ci.Config.set_library_file(basedir+"/clang/build/Release+Asserts/lib/libclang.so") 2 | #ci.Config.set_library_file(basedir+"/libclang.so") 3 | LIBCLANG_PATH = '/usr/lib/x86_64-linux-gnu/libclang.so.1' 4 | #args.append(basedir+"/clang-latest/build/Release+Asserts/lib/clang/3.4.2/include") 5 | #args.append(basedir+"/include") 6 | CLANG_INCLUDES = '/usr/lib/llvm-3.4/lib/clang/3.4/include' 7 | 8 | -------------------------------------------------------------------------------- /extra/cda/clang/__init__.py: -------------------------------------------------------------------------------- 1 | #===- __init__.py - Clang Python Bindings --------------------*- python -*--===# 2 | # 3 | # The LLVM Compiler Infrastructure 4 | # 5 | # This file is distributed under the University of Illinois Open Source 6 | # License. See LICENSE.TXT for details. 7 | # 8 | #===------------------------------------------------------------------------===# 9 | 10 | r""" 11 | Clang Library Bindings 12 | ====================== 13 | 14 | This package provides access to the Clang compiler and libraries. 15 | 16 | The available modules are: 17 | 18 | cindex 19 | 20 | Bindings for the Clang indexing library. 21 | """ 22 | 23 | __all__ = ['cindex'] 24 | 25 | -------------------------------------------------------------------------------- /extra/cda/clang/enumerations.py: -------------------------------------------------------------------------------- 1 | #===- enumerations.py - Python Enumerations ------------------*- python -*--===# 2 | # 3 | # The LLVM Compiler Infrastructure 4 | # 5 | # This file is distributed under the University of Illinois Open Source 6 | # License. See LICENSE.TXT for details. 7 | # 8 | #===------------------------------------------------------------------------===# 9 | 10 | """ 11 | Clang Enumerations 12 | ================== 13 | 14 | This module provides static definitions of enumerations that exist in libclang. 15 | 16 | Enumerations are typically defined as a list of tuples. The exported values are 17 | typically munged into other types or classes at module load time. 18 | 19 | All enumerations are centrally defined in this file so they are all grouped 20 | together and easier to audit. And, maybe even one day this file will be 21 | automatically generated by scanning the libclang headers! 22 | """ 23 | 24 | # Maps to CXTokenKind. Note that libclang maintains a separate set of token 25 | # enumerations from the C++ API. 26 | TokenKinds = [ 27 | ('PUNCTUATION', 0), 28 | ('KEYWORD', 1), 29 | ('IDENTIFIER', 2), 30 | ('LITERAL', 3), 31 | ('COMMENT', 4), 32 | ] 33 | 34 | __all__ = ['TokenKinds'] 35 | -------------------------------------------------------------------------------- /extra/cda/clang_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | #sudo pip install html 3 | 4 | mkdir -p clang-latest 5 | cd clang-latest 6 | if [ ! -f .downloaded_clang ]; then 7 | echo "downloading" 8 | wget http://llvm.org/releases/3.4.2/cfe-3.4.2.src.tar.gz 9 | wget http://llvm.org/releases/3.4/compiler-rt-3.4.src.tar.gz 10 | wget http://llvm.org/releases/3.4.2/llvm-3.4.2.src.tar.gz 11 | touch .downloaded_clang 12 | fi 13 | 14 | echo "extracting" 15 | tar xf llvm-3.4.2.src.tar.gz 16 | tar xf cfe-3.4.2.src.tar.gz 17 | tar xf compiler-rt-3.4.src.tar.gz 18 | 19 | echo "making symlinks" 20 | ln -sf llvm-3.4.2.src llvm 21 | ln -sf ../../cfe-3.4.2.src llvm/tools/clang 22 | ln -sf ../../compiler-rt-3.4 llvm/projects/compiler-rt 23 | rm -f ../clang 24 | ln -s clang-latest/llvm/tools/clang/bindings/python/clang ../clang 25 | rm -f ../include 26 | ln -s clang-latest/cfe-3.4.2.src/lib/Headers ../include 27 | 28 | # don't actually build clang because it takes forever and sucks 29 | exit 0 30 | 31 | mkdir -p build 32 | cd build 33 | ../llvm/configure --enable-optimized 34 | make -j $(grep processor < /proc/cpuinfo | wc -l) 35 | 36 | -------------------------------------------------------------------------------- /extra/cda/include.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/extra/cda/include.tar.gz -------------------------------------------------------------------------------- /extra/cda/static/cda.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: monospace; 3 | } 4 | 5 | a { 6 | color: inherit; 7 | } 8 | 9 | span { 10 | white-space: nowrap; 11 | } 12 | 13 | .link { 14 | /*background-color: #F0F0F0;*/ 15 | text-decoration: underline; 16 | /*font-style: italic;*/ 17 | } 18 | 19 | .xref { 20 | background-color: #EEEEEE; 21 | padding: 5px; 22 | } 23 | 24 | .xrefstitle { 25 | color: blue; 26 | } 27 | 28 | #ln { 29 | display: inline-block; 30 | float: left; 31 | color: gray; 32 | } 33 | 34 | .line_highlighted { 35 | background-color: #EE8888; 36 | } 37 | 38 | .highlighted { 39 | background-color: #EEEE88; 40 | } 41 | 42 | #code { 43 | overflow: hidden; 44 | } 45 | 46 | .dirlink { 47 | color: blue; 48 | } 49 | .filelink { 50 | color: black; 51 | text-decoration: underline; 52 | } 53 | 54 | /* declaring a function in the global scope */ 55 | .FUNCTION_DECL { 56 | color: red; 57 | } 58 | 59 | /* C++ method in class */ 60 | .CXX_METHOD { 61 | color: #AAAAAA; 62 | } 63 | 64 | /* a variable or function reference */ 65 | .DECL_REF_EXPR { 66 | color: #00AA00; 67 | } 68 | 69 | /* calling a C++ member function */ 70 | .MEMBER_REF_EXPR { 71 | color: #AAAA55; 72 | } 73 | 74 | /* string in quotes */ 75 | .STRING_LITERAL { 76 | color: blue; 77 | } 78 | 79 | /* integer */ 80 | .INTEGER_LITERAL { 81 | color: purple; 82 | } 83 | 84 | .VAR_DECL { 85 | color: orange; 86 | } 87 | 88 | .PARM_DECL { 89 | color: orange; 90 | } 91 | 92 | .CLASS_DECL { 93 | color: #00AAAA; 94 | } 95 | 96 | .CLASS_TEMPLATE { 97 | color: #00AAAA; 98 | } 99 | 100 | .TYPE_REF { 101 | color: #AAAA00; 102 | } 103 | 104 | .TEMPLATE_REF { 105 | color: #AA4400; 106 | } 107 | 108 | iframe { 109 | margin: 0; 110 | padding: 0; 111 | border: 0 none; 112 | } 113 | 114 | body { 115 | margin: 0; 116 | padding: 0; 117 | } 118 | 119 | #xrefs { 120 | width: 100%; 121 | height: 19%; 122 | border-top: 1px solid black; 123 | position: fixed; 124 | bottom: 0; 125 | left: 0; 126 | background-color: #EEEEEE; 127 | overflow-y: scroll; 128 | } 129 | 130 | #program { 131 | padding: 5px; 132 | height: 80%; 133 | overflow-y: scroll; 134 | } 135 | 136 | #filename { 137 | display: none; 138 | } 139 | 140 | -------------------------------------------------------------------------------- /extra/cda/static/cda.js: -------------------------------------------------------------------------------- 1 | // connect to the QIRA stream 2 | stream = io.connect("http://localhost:3002/cda"); 3 | 4 | var current_line = ""; 5 | 6 | function go_to_filename_line(filename, line) { 7 | //p('setline'); 8 | var b64xref = location.hash.split(",")[1]; 9 | if (b64xref === undefined) b64xref = ""; 10 | else b64xref = ","+b64xref; 11 | 12 | //location.replace("/f?"+filename+"#"+line+b64xref); 13 | session[0] = filename; 14 | session[1] = line; 15 | } 16 | 17 | stream.on('setline', function(filename, line) { 18 | current_line = filename+"#"+line; 19 | go_to_filename_line(filename, line); 20 | }); 21 | 22 | function p(s) { 23 | console.log(s); 24 | } 25 | 26 | var highlighted = $(); 27 | 28 | // ugh hacks 29 | var sline = undefined; 30 | var sfile = undefined; 31 | var sb64xref = undefined; 32 | 33 | function refresh() { 34 | if (location.hash == "") { 35 | $.ajax("/list").done(function(a) { 36 | $('#program')[0].innerHTML = a; 37 | }); 38 | sfile = undefined; 39 | sline = undefined; 40 | return; 41 | } 42 | 43 | //p(location.hash); 44 | 45 | var file = location.hash.substr(1).split(",")[0]; 46 | var ln = location.hash.split(",")[1]; 47 | var b64xref = location.hash.split(",")[2]; 48 | 49 | if (sfile !== file) { 50 | $.ajax("/f?"+file).done(function(a) { 51 | $('#program')[0].innerHTML = a; 52 | sfile = file; 53 | sline = undefined; 54 | refresh(); 55 | }); 56 | } 57 | if (sline != parseInt(ln)) { 58 | highlighted.removeClass("line_highlighted") 59 | highlighted = $("#l" + ln) 60 | if (highlighted.length > 0) { 61 | highlighted.addClass("line_highlighted"); 62 | $('#program').scrollTo(highlighted, {offset: -150}) 63 | var new_line = file+"#"+parseInt(ln); 64 | if (current_line != new_line) { 65 | stream.emit('navigateline', sfile, parseInt(ln)) 66 | current_line = new_line; 67 | } 68 | sline = parseInt(ln); 69 | } 70 | } 71 | if (b64xref !== undefined && b64xref !== "" && b64xref != sb64xref) { 72 | selected.removeClass('highlighted'); 73 | selected = $(document.getElementsByName(atob(b64xref))); 74 | selected.addClass('highlighted'); 75 | $.ajax("/x/"+b64xref).done(function(a) { 76 | //p(a); 77 | $('#xrefs')[0].innerHTML = a; 78 | sb64xref = b64xref; 79 | }); 80 | } 81 | } 82 | 83 | // all of the session is stored in the hash 84 | 85 | var session = []; 86 | var selected = $(); 87 | 88 | // 0 = filename 89 | // 1 = linenumber 90 | // 2 = xref 91 | for (var i = 0; i < 3; i++) { 92 | session.__defineSetter__(i, function(val) { 93 | var tmp = location.hash.substr(1).split(","); 94 | if (this == 0 && val.indexOf("#") != -1) { 95 | tmp[0] = val.split("#")[0]; 96 | tmp[1] = val.split("#")[1]; 97 | } else { 98 | tmp[this] = val; 99 | } 100 | if (this == 2) { 101 | location.replace("#"+tmp.join(",")); 102 | } else { 103 | // for back and forward 104 | location = "#"+tmp.join(","); 105 | } 106 | }.bind(i)); 107 | } 108 | 109 | function link_click_handler(e) { 110 | var usr = e.target.getAttribute('name'); 111 | session[2] = btoa(usr); 112 | } 113 | 114 | function link_dblclick_handler(e) { 115 | var targets = e.target.getAttribute('targets').split(" "); 116 | var usr = e.target.getAttribute('name'); 117 | session[0] = targets[0]; 118 | } 119 | 120 | function go_to_line(line) { 121 | session[1] = line; 122 | } 123 | 124 | window.onmousedown = function() { return false; }; 125 | 126 | // when the page loads we need to check the hash 127 | window.onload = function() { 128 | $('#program').on('click', '.link', link_click_handler); 129 | $('#program').on('dblclick', '.link', link_dblclick_handler); 130 | $(window).on('hashchange', refresh); 131 | refresh(); 132 | }; 133 | 134 | window.onkeydown = function(e) { 135 | if (e.keyCode == 191) { // / 136 | re = prompt("enter regex") 137 | $.ajax("/s/"+btoa(re)).done(function(a) { 138 | $('#xrefs')[0].innerHTML = a; 139 | }); 140 | } 141 | }; 142 | 143 | -------------------------------------------------------------------------------- /extra/cda/static/jquery.scrollTo.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2007-2014 Ariel Flesler - afleslergmailcom | http://flesler.blogspot.com 3 | * Licensed under MIT 4 | * @author Ariel Flesler 5 | * @version 1.4.13 6 | */ 7 | ;(function(k){'use strict';k(['jquery'],function($){var j=$.scrollTo=function(a,b,c){return $(window).scrollTo(a,b,c)};j.defaults={axis:'xy',duration:parseFloat($.fn.jquery)>=1.3?0:1,limit:!0};j.window=function(a){return $(window)._scrollable()};$.fn._scrollable=function(){return this.map(function(){var a=this,isWin=!a.nodeName||$.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!isWin)return a;var b=(a.contentWindow||a).document||a.ownerDocument||a;return/webkit/i.test(navigator.userAgent)||b.compatMode=='BackCompat'?b.body:b.documentElement})};$.fn.scrollTo=function(f,g,h){if(typeof g=='object'){h=g;g=0}if(typeof h=='function')h={onAfter:h};if(f=='max')f=9e9;h=$.extend({},j.defaults,h);g=g||h.duration;h.queue=h.queue&&h.axis.length>1;if(h.queue)g/=2;h.offset=both(h.offset);h.over=both(h.over);return this._scrollable().each(function(){if(f==null)return;var d=this,$elem=$(d),targ=f,toff,attr={},win=$elem.is('html,body');switch(typeof targ){case'number':case'string':if(/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)){targ=both(targ);break}targ=win?$(targ):$(targ,this);if(!targ.length)return;case'object':if(targ.is||targ.style)toff=(targ=$(targ)).offset()}var e=$.isFunction(h.offset)&&h.offset(d,targ)||h.offset;$.each(h.axis.split(''),function(i,a){var b=a=='x'?'Left':'Top',pos=b.toLowerCase(),key='scroll'+b,old=d[key],max=j.max(d,a);if(toff){attr[key]=toff[pos]+(win?0:old-$elem.offset()[pos]);if(h.margin){attr[key]-=parseInt(targ.css('margin'+b))||0;attr[key]-=parseInt(targ.css('border'+b+'Width'))||0}attr[key]+=e[pos]||0;if(h.over[pos])attr[key]+=targ[a=='x'?'width':'height']()*h.over[pos]}else{var c=targ[pos];attr[key]=c.slice&&c.slice(-1)=='%'?parseFloat(c)/100*max:c}if(h.limit&&/^\d+$/.test(attr[key]))attr[key]=attr[key]<=0?0:Math.min(attr[key],max);if(!i&&h.queue){if(old!=attr[key])animate(h.onAfterFirst);delete attr[key]}});animate(h.onAfter);function animate(a){$elem.animate(attr,g,h.easing,a&&function(){a.call(this,targ,h)})}}).end()};j.max=function(a,b){var c=b=='x'?'Width':'Height',scroll='scroll'+c;if(!$(a).is('html,body'))return a[scroll]-$(a)[c.toLowerCase()]();var d='client'+c,html=a.ownerDocument.documentElement,body=a.ownerDocument.body;return Math.max(html[scroll],body[scroll])-Math.min(html[d],body[d])};function both(a){return $.isFunction(a)||typeof a=='object'?a:{top:a,left:a}}return j})}(typeof define==='function'&&define.amd?define:function(a,b){if(typeof module!=='undefined'&&module.exports){module.exports=b(require('jquery'))}else{b(jQuery)}})); -------------------------------------------------------------------------------- /extra/install.bat: -------------------------------------------------------------------------------- 1 | C:\Python27\Scripts\pip.exe install --upgrade html flask-socketio pillow pyelftools socketIO-client pydot ipaddr capstone ./qiradb 2 | -------------------------------------------------------------------------------- /extra/middleware/dump_log.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.7 2 | 3 | from middleware import qira_log 4 | import sys 5 | logs = qira_log.read_log(sys.argv[1]) 6 | for l in logs: 7 | print "address: %8x data: %8x clnum: %4d flags: %s" % (l[0], l[1], l[2], qira_log.flag_to_type(l[3])) 8 | 9 | -------------------------------------------------------------------------------- /extra/middleware/qira_memory.py: -------------------------------------------------------------------------------- 1 | # rewrite this whole thing in c? 2 | # we also have to move the pydb 3 | import blist 4 | 5 | class Address: 6 | def __init__(this): 7 | this.backing = blist.sorteddict() 8 | 9 | def fetch(this, clnum): 10 | kclnum = this.backing.keys().bisect_right(clnum) 11 | if kclnum == 0: 12 | return None 13 | else: 14 | rclnum = this.backing.keys()[kclnum-1] 15 | #print this.backing.keys(), clnum, rclnum 16 | return this.backing[rclnum] 17 | 18 | def commit(this, clnum, dat): 19 | this.backing[clnum] = dat 20 | 21 | class Memory: 22 | def __init__(this): 23 | this.daddr = {} 24 | this.backing = {} 25 | 26 | def copy(this): 27 | new = Memory() 28 | new.daddr = this.daddr.copy() 29 | new.backing = this.backing # no copy required 30 | return new 31 | 32 | def fetch(this, clnum, addr, l): 33 | ret = {} 34 | for i in range(addr, addr+l): 35 | if i in this.daddr: 36 | rret = this.daddr[i].fetch(clnum) 37 | if rret != None: 38 | ret[i] = rret 39 | continue 40 | # slow 41 | for (s, e) in this.backing: 42 | if s <= i and i < e: 43 | ret[i] = ord(this.backing[(s,e)][i-s]) 44 | return ret 45 | 46 | # backing commit 47 | def bcommit(this, addr, dat): 48 | this.backing[(addr, addr+len(dat))] = dat 49 | 50 | def dump(this): 51 | ret = {} 52 | for i in this.daddr: 53 | rret = {} 54 | for j in this.daddr[i].backing: 55 | rret[j] = this.daddr[i].backing[j] 56 | ret[i] = rret 57 | return ret 58 | 59 | def commit(this, clnum, addr, dat): 60 | if addr not in this.daddr: 61 | this.daddr[addr] = Address() 62 | this.daddr[addr].commit(clnum, dat) 63 | 64 | -------------------------------------------------------------------------------- /extra/middleware/qira_trace.py: -------------------------------------------------------------------------------- 1 | import qiradb 2 | import threading 3 | import struct 4 | from collections import defaultdict 5 | import os 6 | import sys 7 | import time 8 | 9 | class Trace: 10 | def __init__(self, program, forknum): 11 | self.logfile = open("/tmp/qira_logs/"+str(forknum)) 12 | 13 | self.program = program 14 | self.program.traces[forknum] = self 15 | 16 | self.forknum = forknum 17 | 18 | self.reset() 19 | 20 | def reset(self): 21 | self.regs = qira_memory.Memory() 22 | self.mem = qira_memory.Memory() 23 | 24 | self.minclnum = -1 25 | self.maxclnum = 1 26 | 27 | self.changes_committed = 1 28 | 29 | # python db has two indexes 30 | # pydb_addr: (addr, type) -> [clnums] 31 | # pydb_clnum: (clnum, type) -> [changes] 32 | self.pydb_addr = defaultdict(list) 33 | self.pydb_clnum = defaultdict(list) 34 | 35 | try: 36 | f = open("/tmp/qira_logs/"+str(self.forknum)+"_base") 37 | except: 38 | # done 39 | return 40 | 41 | for ln in f.read().split("\n"): 42 | ln = ln.split(" ") 43 | if len(ln) < 3: 44 | continue 45 | (ss, se) = ln[0].split("-") 46 | ss = int(ss, 16) 47 | se = int(se, 16) 48 | offset = int(ln[1], 16) 49 | fn = ' '.join(ln[2:]) 50 | 51 | try: 52 | f = open(fn) 53 | except: 54 | continue 55 | f.seek(offset) 56 | dat = f.read(se-ss) 57 | self.mem.bcommit(ss, dat) 58 | f.close() 59 | #print hex(ss)+"-"+hex(se), offset, fn 60 | 61 | def poll(self): 62 | max_changes = qira_log.get_log_length(self.logfile) 63 | if self.changes_committed < max_changes: 64 | total_changes = max_changes - self.changes_committed 65 | # clamping to keep the server responsive 66 | # python threads really aren't very good 67 | if total_changes > 30000: 68 | total_changes = 30000 69 | if self.changes_committed > 1000000: 70 | # clamped 71 | return False 72 | sys.stdout.write("on %d going from %d to %d..." % (self.forknum, self.changes_committed,max_changes)) 73 | sys.stdout.flush() 74 | log = qira_log.read_log(self.logfile, self.changes_committed, total_changes) 75 | sys.stdout.write("read..."); sys.stdout.flush() 76 | self.process(log) 77 | print "done", self.maxclnum 78 | self.changes_committed += total_changes 79 | return True 80 | return False 81 | 82 | 83 | # *** HANDLER FOR qira_log *** 84 | def process(self, log_entries): 85 | for (address, data, clnum, flags) in log_entries: 86 | if self.minclnum == -1 or clnum < self.minclnum: 87 | self.minclnum = clnum 88 | if clnum > self.maxclnum: 89 | self.maxclnum = clnum 90 | 91 | # construct this_change 92 | pytype = qira_log.flag_to_type(flags) 93 | this_change = {'address': address, 'type': pytype, 94 | 'size': flags&qira_log.SIZE_MASK, 'clnum': clnum, 'data': data} 95 | """ 96 | if address in self.program.instructions: 97 | this_change['instruction'] = self.program.instructions[address] 98 | """ 99 | 100 | # update python database 101 | self.pydb_addr[(address, pytype)].append(clnum) 102 | self.pydb_clnum[(clnum, pytype)].append(this_change) 103 | 104 | # update local regs and mem database 105 | # this is somewhat slow... 106 | if flags & qira_log.IS_WRITE and flags & qira_log.IS_MEM: 107 | size = flags & qira_log.SIZE_MASK 108 | # support big endian 109 | for i in range(0, size/8): 110 | self.mem.commit(clnum, address+i, data & 0xFF) 111 | data >>= 8 112 | elif flags & qira_log.IS_WRITE: 113 | size = flags & qira_log.SIZE_MASK 114 | # support big endian 115 | self.regs.commit(clnum, address, data) 116 | 117 | # for Pmaps 118 | # shouldn't really send this each time, but it should be smaller anyway 119 | page_base = (address>>12)<<12 120 | if flags & qira_log.IS_MEM and page_base not in self.program.pmaps: 121 | self.program.pmaps[page_base] = "memory" 122 | if flags & qira_log.IS_START: 123 | self.program.pmaps[page_base] = "instruction" 124 | # *** FOR LOOP END *** 125 | self.program.read_asm_file() 126 | 127 | 128 | -------------------------------------------------------------------------------- /extra/newscripts/qira_log.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | IS_VALID = 0x80000000 4 | IS_WRITE = 0x40000000 5 | IS_MEM = 0x20000000 6 | IS_START = 0x10000000 7 | IS_BIGE = 0x08000000 # not supported 8 | SIZE_MASK = 0xFF 9 | 10 | LOGFILE = "/tmp/qira_log" 11 | 12 | def flag_to_type(flags): 13 | if flags & IS_START: 14 | typ = "I" 15 | elif flags & IS_WRITE and flags & IS_MEM: 16 | typ = "S" 17 | elif not flags & IS_WRITE and flags & IS_MEM: 18 | typ = "L" 19 | elif flags & IS_WRITE and not flags & IS_MEM: 20 | typ = "W" 21 | elif not flags & IS_WRITE and not flags & IS_MEM: 22 | typ = "R" 23 | return typ 24 | 25 | def get_log_length(f): 26 | try: 27 | f.seek(0) 28 | dat = f.read(4) 29 | return struct.unpack("I", dat)[0] 30 | except: 31 | return None 32 | 33 | def read_log(f, seek=1, cnt=0): 34 | f.seek(seek*0x18) 35 | if cnt == 0: 36 | dat = f.read() 37 | else: 38 | dat = f.read(cnt * 0x18) 39 | 40 | ret = [] 41 | for i in range(0, len(dat), 0x18): 42 | (address, data, clnum, flags) = struct.unpack("QQII", dat[i:i+0x18]) 43 | if not flags & IS_VALID: 44 | break 45 | ret.append((address, data, clnum, flags)) 46 | 47 | return ret 48 | 49 | def write_log(fn, dat): 50 | # untested 51 | ss = [struct.pack("I", len(dat)) + "\x00"*0x14] 52 | for (address, data, clnum, flags) in dat: 53 | ss.append(struct.pack("QQII", address, data, clnum, flags)) 54 | f = open(fn, "wb") 55 | f.write(''.join(ss)) 56 | f.close() 57 | 58 | -------------------------------------------------------------------------------- /extra/old_static/radare_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | mkdir -p radare 3 | cd radare 4 | 5 | sudo apt-get install valac-0.22 libvala-0.22-dev 6 | 7 | pushd . 8 | git clone https://github.com/radare/valabind.git 9 | cd valabind 10 | make 11 | sudo make install 12 | popd 13 | 14 | pushd . 15 | git clone https://github.com/radare/radare2.git 16 | cd radare2 17 | ./configure 18 | make 19 | sudo make install 20 | sys/python.sh 21 | popd 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /extra/parseida/gdb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | gdb /home/vagrant/idademo66/python -ex "r trial.py" 3 | 4 | -------------------------------------------------------------------------------- /extra/parseida/ltracer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ltrace -n2 --library=libida.so ~/idademo66/idaq ~/qira/tests/idb/a.out 2>&1 | grep -v "qstrncpy" | grep -v "lxget" | grep -v "qfree" | grep -v "qmutex" | grep -v "invoke_callbacks" | grep -v "netnode_inited" | grep -v "qalloc" | grep -v "qvector_reserve" | grep -v "qvsnprintf" 3 | -------------------------------------------------------------------------------- /extra/parseida/parseidb.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from hexdump import hexdump 3 | 4 | # name.id0 - contains contents of B-tree style database 5 | # name.id1 - contains flags that describe each program byte 6 | # name.nam - contains index information related to named program locations 7 | # name.til - contains information about local type definitions 8 | 9 | BTREE_PAGE_SIZE = 8192 10 | 11 | #dat = open(sys.argv[1]).read() 12 | 13 | #id0 = dat[0x104:] 14 | 15 | dat = open("/Users/geohot/tmp/test.id0").read() 16 | print hex(len(dat)), len(dat)/BTREE_PAGE_SIZE 17 | 18 | for i in range(0, len(dat), BTREE_PAGE_SIZE): 19 | hexdump(dat[i:i+0xC0]) 20 | print "" 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /extra/parseida/parseidc.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import collections 3 | 4 | def ghex(a): 5 | if a == None: 6 | return None 7 | return hex(a).strip("L") 8 | 9 | tags = collections.defaultdict(dict) 10 | 11 | for ln in open(sys.argv[1]).read().split("\n"): 12 | ln = ln.strip(" \n\t") 13 | if ln.startswith("MakeName"): 14 | (addr,name) = ln.split("(")[1].split(")")[0].split(",") 15 | addr = addr.strip(" \t") 16 | name = name.strip(" \t\"") 17 | addr = ghex(int(addr, 16)) 18 | tags[addr]['name'] = name 19 | 20 | tags = dict(tags) 21 | print tags 22 | 23 | # upload the tags 24 | 25 | from socketIO_client import SocketIO, BaseNamespace 26 | class QiraNamespace(BaseNamespace): 27 | pass 28 | 29 | sio = SocketIO('localhost', 3002) 30 | qira = sio.define(QiraNamespace, '/qira') 31 | qira.emit("settags", dict(tags)) 32 | 33 | -------------------------------------------------------------------------------- /extra/qemu_mods/gen_patch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | wget http://wiki.qemu-project.org/download/qemu-2.1.0-rc0.tar.bz2 4 | tar xf qemu-2.1.0-rc0.tar.bz2 5 | cp -r qemu-2.1.0-rc0 qemu-2.1.0-rc0-patch 6 | cp tci.c qemu-2.1.0-rc0-patch/tci.c 7 | cp disas.c qemu-2.1.0-rc0-patch/disas.c 8 | cp qemu.h qemu-2.1.0-rc0-patch/linux-user/qemu.h 9 | cp main.c qemu-2.1.0-rc0-patch/linux-user/main.c 10 | cp strace.c qemu-2.1.0-rc0-patch/linux-user/strace.c 11 | cp strace.list qemu-2.1.0-rc0-patch/linux-user/strace.list 12 | diff -rupN qemu-2.1.0-rc0 qemu-2.1.0-rc0-patch > out.patch 13 | -------------------------------------------------------------------------------- /extra/qira.bat: -------------------------------------------------------------------------------- 1 | C:\Python27\python.exe middleware/qira.py %* 2 | -------------------------------------------------------------------------------- /extra/qiradb/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | g++ qiradb.cc -O3 -lmongoc-1.0 -lbson-1.0 -o qiradb 4 | 5 | -------------------------------------------------------------------------------- /extra/qiradb/qiradb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/extra/qiradb/qiradb -------------------------------------------------------------------------------- /extra/qiradb/qiradb.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define MONGO_DEBUG printf 10 | //#define MONGO_DEBUG(...) {} 11 | 12 | // use like an include maybe? 13 | // struct storing change data 14 | struct change { 15 | uint64_t address; 16 | uint64_t data; 17 | uint32_t changelist_number; 18 | uint32_t flags; 19 | }; 20 | 21 | #define IS_VALID 0x80000000 22 | #define IS_WRITE 0x40000000 23 | #define IS_MEM 0x20000000 24 | #define IS_START 0x10000000 25 | #define SIZE_MASK 0xFF 26 | 27 | int main(int argc, char* argv[]) { 28 | bool ret; 29 | 30 | mongoc_init(); 31 | mongoc_client_t *client; 32 | mongoc_collection_t *collection; 33 | client = mongoc_client_new("mongodb://localhost:3001"); 34 | //client = mongoc_client_new("mongodb://localhost:27017"); 35 | collection = mongoc_client_get_collection(client, "meteor", "change"); 36 | ret = mongoc_collection_drop(collection, NULL); 37 | if (!ret) MONGO_DEBUG("drop failed\n"); 38 | 39 | uint32_t mongo_qira_log_fd = open("/tmp/qira_log", O_RDONLY); 40 | uint32_t mongo_change_count = 1; 41 | 42 | struct change *GLOBAL_change_buffer; 43 | uint32_t *GLOBAL_change_count; 44 | 45 | GLOBAL_change_buffer = 46 | (struct change *)mmap(NULL, 4, PROT_READ, MAP_SHARED, mongo_qira_log_fd, 0); 47 | GLOBAL_change_count = (uint32_t*)GLOBAL_change_buffer; 48 | 49 | // begin thread run loop 50 | while (1) { 51 | // poll the websocket 52 | 53 | // commit every 10ms 54 | usleep(10*1000); 55 | 56 | // check for new changes 57 | uint32_t change_count = *GLOBAL_change_count; 58 | if (mongo_change_count == change_count) continue; 59 | 60 | // set up bulk operation 61 | mongoc_bulk_operation_t *bulk; 62 | bson_t reply; 63 | bson_error_t error; 64 | bson_t *doc; 65 | bulk = mongoc_collection_create_bulk_operation(collection, true, NULL); 66 | 67 | // add new changes 68 | GLOBAL_change_buffer = 69 | (struct change *)mmap(NULL, change_count*sizeof(struct change), 70 | PROT_READ, MAP_SHARED, mongo_qira_log_fd, 0); 71 | GLOBAL_change_count = (uint32_t*)GLOBAL_change_buffer; 72 | 73 | /*if (change_count > mongo_change_count+5000) { 74 | change_count = mongo_change_count+5000; 75 | }*/ 76 | 77 | while (mongo_change_count < change_count) { 78 | struct change *tmp = &GLOBAL_change_buffer[mongo_change_count]; 79 | 80 | char typ[2]; typ[1] = '\0'; 81 | uint32_t flags = tmp->flags; 82 | if (flags & IS_START) typ[0] = 'I'; 83 | else if ((flags & IS_WRITE) && (flags & IS_MEM)) typ[0] = 'S'; 84 | else if (!(flags & IS_WRITE) && (flags & IS_MEM)) typ[0] = 'L'; 85 | else if ((flags & IS_WRITE) && !(flags & IS_MEM)) typ[0] = 'W'; 86 | else if (!(flags & IS_WRITE) && !(flags & IS_MEM)) typ[0] = 'R'; 87 | 88 | doc = bson_new(); 89 | BSON_APPEND_INT32(doc, "address", tmp->address); 90 | BSON_APPEND_UTF8(doc, "type", typ); 91 | BSON_APPEND_INT32(doc, "size", tmp->flags & SIZE_MASK); 92 | BSON_APPEND_INT32(doc, "clnum", tmp->changelist_number); 93 | BSON_APPEND_INT32(doc, "data", tmp->data); 94 | mongoc_bulk_operation_insert(bulk, doc); 95 | bson_destroy(doc); 96 | 97 | mongo_change_count++; 98 | } 99 | 100 | // do bulk operation 101 | timespec ts_start, ts_end; 102 | MONGO_DEBUG("commit to %d...", mongo_change_count); 103 | fflush(stdout); 104 | clock_gettime(CLOCK_REALTIME, &ts_start); 105 | ret = mongoc_bulk_operation_execute(bulk, &reply, &error); 106 | clock_gettime(CLOCK_REALTIME, &ts_end); 107 | double secs = ts_end.tv_sec - ts_start.tv_sec; 108 | secs += (ts_end.tv_nsec - ts_start.tv_nsec) / 1000000000.0; 109 | MONGO_DEBUG("done in %f seconds\n", secs); 110 | 111 | // debugging 112 | char *str = bson_as_json(&reply, NULL); 113 | printf("%s\n", str); 114 | bson_free(str); 115 | if (!ret) MONGO_DEBUG("mongo error: %s\n", error.message); 116 | 117 | // did bulk operation 118 | bson_destroy(&reply); 119 | mongoc_bulk_operation_destroy(bulk); 120 | } 121 | 122 | // thread exit 123 | mongoc_collection_destroy(collection); 124 | mongoc_client_destroy(client); 125 | mongoc_cleanup(); 126 | return 0; 127 | } 128 | 129 | -------------------------------------------------------------------------------- /extra/scripts/db_commit_asm.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | import sys 3 | db = MongoClient('localhost', 3001).meteor 4 | 5 | ds = [] 6 | 7 | sdict = {} 8 | cdict = {} 9 | 10 | has_elf_tools = 0 11 | try: 12 | from elftools.elf.elffile import ELFFile 13 | has_elf_tools = 1 14 | except: 15 | print "no elf tools found" 16 | 17 | if has_elf_tools: 18 | elf = ELFFile(open(sys.argv[1])) 19 | for section in elf.iter_sections(): 20 | try: 21 | for symbol in section.iter_symbols(): 22 | if len(symbol.name) > 0: 23 | sdict[symbol['st_value']] = symbol.name 24 | except: 25 | pass 26 | 27 | if elf.has_dwarf_info() and len(sys.argv) > 2: 28 | src = open(sys.argv[2]).read().split("\n") 29 | di = elf.get_dwarf_info() 30 | for CU in di.iter_CUs(): 31 | for DIE in CU.iter_DIEs(): 32 | #print DIE 33 | if DIE.tag == 'DW_TAG_subprogram': 34 | try: 35 | lowpc = DIE.attributes['DW_AT_low_pc'].value 36 | highpc = DIE.attributes['DW_AT_high_pc'].value 37 | fil = DIE.attributes['DW_AT_decl_file'] 38 | line = DIE.attributes['DW_AT_decl_line'].value 39 | except: 40 | pass 41 | print lowpc, highpc, fil, line, src[line] 42 | cdict[lowpc] = src[line] 43 | 44 | dat = open("/tmp/qira_disasm").read().split("\n") 45 | for d in dat: 46 | if ": " in d: 47 | (addr, inst) = d.split(": ") 48 | addr = int(addr, 16) 49 | #print addr, inst 50 | d = {'address': addr, 'instruction': inst} 51 | if addr in sdict: 52 | d['name'] = sdict[addr] 53 | if addr in cdict: 54 | print hex(addr) 55 | d['comment'] = cdict[addr] 56 | ds.append(d) 57 | 58 | 59 | # DWARF data will go here too 60 | coll = db.program 61 | print "doing db insert" 62 | coll.drop() 63 | coll.insert(ds) 64 | print "db insert done, building indexes" 65 | coll.ensure_index("address") 66 | print "indexes built" 67 | 68 | 69 | -------------------------------------------------------------------------------- /extra/scripts/db_commit_log.py: -------------------------------------------------------------------------------- 1 | from qira_log import * 2 | from pymongo import MongoClient 3 | 4 | db = MongoClient('localhost', 3001).meteor 5 | #db = MongoClient('localhost', 27017).meteor 6 | 7 | print "reading log" 8 | dat = read_log("/tmp/qira_log") 9 | #dat = read_log("/tmp/qira_log_filtered") 10 | 11 | print "building database data" 12 | 13 | ds = [] 14 | 15 | for (address, data, clnum, flags) in dat: 16 | if flags & IS_START: 17 | typ = "I" 18 | elif flags & IS_WRITE and flags & IS_MEM: 19 | typ = "S" 20 | elif not flags & IS_WRITE and flags & IS_MEM: 21 | typ = "L" 22 | elif flags & IS_WRITE and not flags & IS_MEM: 23 | typ = "W" 24 | elif not flags & IS_WRITE and not flags & IS_MEM: 25 | typ = "R" 26 | 27 | d = {'address': address, 'type': typ, 'size': flags&SIZE_MASK, 'clnum': clnum} 28 | d['data'] = data 29 | ds.append(d) 30 | 31 | #coll = db.tinychange 32 | coll = db.change 33 | print "doing db insert of",len(ds),"changes" 34 | coll.drop() 35 | coll.insert(ds) 36 | #print "db insert done, building indexes" 37 | #coll.ensure_index("data") 38 | #coll.ensure_index([("data", 1), ("address", 1)]) 39 | #coll.ensure_index("address") 40 | #coll.ensure_index("clnum") 41 | #coll.ensure_index([("address", 1), ("type", 1)]) 42 | #print "indexes built" 43 | print "db insert done" 44 | 45 | -------------------------------------------------------------------------------- /extra/scripts/db_filter_log.py: -------------------------------------------------------------------------------- 1 | from qira_log import * 2 | from pymongo import MongoClient 3 | 4 | def is_library_address(address): 5 | return address > 0x80000000 6 | 7 | db = MongoClient('localhost', 3001).meteor 8 | 9 | print "reading log" 10 | dat = read_log("/tmp/qira_log") 11 | 12 | print "filtering data" 13 | ds = [] 14 | dds = [] 15 | 16 | maxclnum = 0 17 | fixclnum = 0 18 | 19 | clignore = 0 20 | 21 | for (address, data, clnum, flags) in dat: 22 | if clnum > maxclnum: 23 | maxclnum = clnum 24 | if flags & IS_START: 25 | if is_library_address(address): 26 | clignore = clnum 27 | else: 28 | fixclnum += 1 29 | dds.append((address, data, fixclnum, flags)) 30 | if clnum == clignore and not (flags & IS_MEM): 31 | continue 32 | ds.append((address, data, fixclnum, flags)) 33 | 34 | print "filtered from %d(%d) to %d(%d)" % (maxclnum, len(dat), clnum, len(ds)) 35 | write_log("/tmp/qira_log", dds) 36 | write_log("/tmp/qira_log_filtered", ds) 37 | 38 | -------------------------------------------------------------------------------- /extra/scripts/gen_reg_colors.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | c = [] 4 | for i in range(40): 5 | r = random.randint(40, 192) 6 | g = random.randint(40, 192) 7 | b = random.randint(40, 192) 8 | c.append("#%02X%02X%02X" % (r,g,b)) 9 | 10 | print c 11 | 12 | -------------------------------------------------------------------------------- /extra/scripts/go.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | BIN=../tests/ctf/ezhp 5 | #BIN=../tests/ctf/hudak 6 | #BIN=../tests/ctf/simple 7 | #SRC=../tests/hello.c 8 | #SRC=../tests/algo.c 9 | 10 | if [ "$SRC" != "" ]; then 11 | cd tests 12 | #gcc -m32 -nostdlib -static -g $src 13 | gcc -m32 -static -g $SRC 14 | BIN=../tests/a.out 15 | cd ../ 16 | fi 17 | 18 | 19 | rm -f /tmp/qira_binary 20 | ln -s $(realpath $BIN) /tmp/qira_binary 21 | #echo "hello" | ./run_qemu.sh $BIN 22 | #echo "4t_l34st_it_was_1mperat1v3..." | ./run_qemu.sh $BIN 23 | #echo "i wish i were a valid key bob" | ./run_qemu.sh $BIN 24 | 25 | pushd . 26 | cd ./qemu/qemu-latest/ 27 | make -j32 28 | popd 29 | 30 | #rm -rf /tmp/qira* 31 | #../qemu/qemu-latest/i386-linux-user/qemu-i386 -singlestep -d in_asm $@ 2> /tmp/qira_disasm 32 | ./qemu/qemu-latest/i386-linux-user/qemu-i386 -singlestep $@ 33 | ls -l /tmp/qira* 34 | 35 | : <<'END' 36 | echo "*** build the Program database" 37 | time python db_commit_asm.py $BIN $SRC 38 | #echo "*** filter the Change database" 39 | #time python db_filter_log.py 40 | echo "*** build the Change database" 41 | time python db_commit_log.py 42 | echo "*** build the memory json" 43 | time python mem_json_extract.py 44 | echo "*** build the pmaps database" 45 | time python segment_extract.py 46 | END 47 | 48 | #python db_commit_blocks.py 49 | #python memory_server.py 50 | #python build_multigraph.py 51 | 52 | -------------------------------------------------------------------------------- /extra/scripts/mem_json_extract.py: -------------------------------------------------------------------------------- 1 | from qira_log import * 2 | import json 3 | from qira_memory import * 4 | 5 | regs = Memory() 6 | mem = Memory() 7 | 8 | def init(): 9 | dat = read_log("/tmp/qira_log") 10 | for (address, data, clnum, flags) in dat: 11 | if flags & IS_WRITE and flags & IS_MEM: 12 | size = flags & SIZE_MASK 13 | # support big endian 14 | for i in range(0, size/8): 15 | mem.commit(clnum, address+i, data & 0xFF) 16 | data >>= 8 17 | elif flags & IS_WRITE: 18 | size = flags & SIZE_MASK 19 | # support big endian 20 | regs.commit(clnum, address, data) 21 | 22 | if __name__ == '__main__': 23 | init() 24 | print "init done" 25 | dat = {"regs": regs.dump(), "mem": mem.dump()} 26 | open("/tmp/qira_memdb", "wb").write(json.dumps(dat)) 27 | print "json extracted" 28 | 29 | -------------------------------------------------------------------------------- /extra/scripts/mongo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | numactl --interleave=all ~/build/mongodb-linux-x86_64-2.6.3/bin/mongod --dbpath=$(pwd)/db --bind_ip 127.0.0.1 4 | 5 | -------------------------------------------------------------------------------- /extra/scripts/segment_extract.py: -------------------------------------------------------------------------------- 1 | from qira_log import * 2 | 3 | from pymongo import MongoClient 4 | db = MongoClient('localhost', 3001).meteor 5 | 6 | mem_addrs = set() 7 | ins_addrs = set() 8 | 9 | # page level granularity 10 | dat = read_log("/tmp/qira_log") 11 | for (address, data, clnum, flags) in dat: 12 | if flags & IS_MEM: 13 | mem_addrs.add(address & 0xFFFFF000) 14 | if flags & IS_START: 15 | ins_addrs.add(address & 0xFFFFF000) 16 | 17 | pmaps = [] 18 | 19 | print "instructions" 20 | for i in sorted(ins_addrs): 21 | pmaps.append({"address": i, "type": "instruction"}) 22 | 23 | print "memory" 24 | for i in sorted(mem_addrs): 25 | if i not in ins_addrs: 26 | pmaps.append({"address": i, "type": "memory"}) 27 | 28 | 29 | coll = db.pmaps 30 | print "doing db insert" 31 | coll.drop() 32 | coll.insert(pmaps) 33 | print "db insert done, building indexes" 34 | coll.ensure_index("address") 35 | print "indexes built" 36 | 37 | -------------------------------------------------------------------------------- /extra/servers/memory_server.py: -------------------------------------------------------------------------------- 1 | from qira_log import * 2 | from flask import Flask 3 | from flask.ext.socketio import SocketIO, emit 4 | import base64 5 | 6 | class Address: 7 | def __init__(this): 8 | this.backing = {} 9 | 10 | def fetch(this, clnum): 11 | # use binary search lol 12 | while clnum >= 0: 13 | if clnum in this.backing: 14 | return this.backing[clnum] 15 | clnum -= 1 16 | # if the change is before it was written to 17 | return 0 # canary 18 | 19 | def commit(this, clnum, dat): 20 | this.backing[clnum] = dat 21 | 22 | class Memory: 23 | def __init__(this): 24 | this.daddr = {} 25 | def fetch(this, clnum, addr, l): 26 | ret = [] 27 | for i in range(addr, addr+l): 28 | if i in this.daddr: 29 | ret.append(chr(this.daddr[i].fetch(clnum))) 30 | else: 31 | ret.append("\xAA") # best canary value 32 | return ''.join(ret) 33 | def commit(this, clnum, addr, dat): 34 | if addr not in this.daddr: 35 | this.daddr[addr] = Address() 36 | this.daddr[addr].commit(clnum, dat) 37 | 38 | regs = Memory() 39 | mem = Memory() 40 | 41 | def init(): 42 | dat = read_log("/tmp/qira_log") 43 | for (address, data, clnum, flags) in dat: 44 | if flags & IS_WRITE and flags & IS_MEM: 45 | size = flags & SIZE_MASK 46 | # support big endian 47 | for i in range(0, size/8): 48 | mem.commit(clnum, address+i, data & 0xFF) 49 | data >>= 8 50 | elif flags & IS_WRITE: 51 | size = flags & SIZE_MASK 52 | # support big endian 53 | regs.commit(clnum, address, data) 54 | 55 | app = Flask(__name__) 56 | app.config['SECRET_KEY'] = 'secret!' 57 | socketio = SocketIO(app) 58 | 59 | @socketio.on('getmemory') 60 | def event(m): 61 | if m['clnum'] == None or m['address'] == None or m['len'] == None: 62 | return 63 | print "my event ",m 64 | dat = mem.fetch(m['clnum'], m['address'], m['len']) 65 | emit('memory', {'address': m['address'], 'raw': base64.b64encode(dat)}) 66 | 67 | @socketio.on('getregisters') 68 | def regevent(m): 69 | if m['clnum'] == None: 70 | return 71 | # register names shouldn't be here 72 | X86REGS = ['EAX', 'ECX', 'EDX', 'EBX', 'ESP', 'EBP', 'ESI', 'EDI', 'EIP'] 73 | ret = {} 74 | for i in range(0, len(X86REGS)): 75 | if i*4 in regs.daddr: 76 | ret[X86REGS[i]] = regs.daddr[i*4].fetch(m['clnum']) 77 | emit('registers', ret) 78 | 79 | if __name__ == '__main__': 80 | init() 81 | print "init done" 82 | socketio.run(app, port=3002) 83 | 84 | -------------------------------------------------------------------------------- /extra/servers/qira_meteor.py: -------------------------------------------------------------------------------- 1 | import time 2 | import socket 3 | import signal 4 | from pymongo import MongoClient 5 | import json 6 | 7 | # communication through a file like this is bad 8 | def write_memdb(regs, mem): 9 | open("/tmp/qira_memdb", "wb").write( 10 | json.dumps({"regs": regs.dump(), "mem": mem.dump()})) 11 | 12 | meteor_pid = -1 13 | 14 | def db_push_changes(db_changes): 15 | if len(db_changes) > 0: 16 | db = mongo_connect() 17 | Change = db.change 18 | Change.insert(db_changes) 19 | db.connection.close() 20 | 21 | def mongo_connect(): 22 | while 1: 23 | try: 24 | db = MongoClient('localhost', 3001).meteor 25 | db.bob.insert([{"test":"test"}]) 26 | db.bob.drop() # poor bob, be master 27 | break 28 | except: 29 | try: 30 | db.connection.close() 31 | except: 32 | pass 33 | time.sleep(0.1) 34 | return db 35 | 36 | def meteor_init(is_managing_meteor): 37 | # connect to db, set up collections, and drop 38 | if is_managing_meteor: 39 | print "restarting meteor" 40 | kill_meteor() 41 | start_meteor() 42 | print "waiting for mongo connection" 43 | db = mongo_connect() 44 | Change = db.change 45 | Change.drop() 46 | db.connection.close() 47 | print "dropped old databases" 48 | 49 | def wait_for_port(port, closed=False): 50 | while 1: 51 | try: 52 | s = socket.create_connection(("localhost", port)) 53 | s.close() 54 | if closed == False: 55 | return 56 | except socket.error: 57 | if closed == True: 58 | return 59 | time.sleep(0.1) 60 | 61 | def start_meteor(): 62 | global meteor_pid 63 | ret = os.fork() 64 | if ret == 0: 65 | os.chdir(os.path.dirname(os.path.realpath(__file__))+"/../web/") 66 | os.environ['PATH'] += ":"+os.getenv("HOME")+"/.meteor/tools/latest/bin/" 67 | os.execvp("mrt", ["mrt"]) 68 | meteor_pid = ret 69 | print "waiting for mongodb startup" 70 | wait_for_port(3000) 71 | wait_for_port(3001) 72 | print "socket ports are open" 73 | time.sleep(5) 74 | print "meteor started with pid",meteor_pid 75 | 76 | def kill_meteor(): 77 | global meteor_pid 78 | if meteor_pid != -1: 79 | print "killing meteor" 80 | sys.stdout.flush() 81 | os.kill(meteor_pid, signal.SIGINT) 82 | print os.waitpid(meteor_pid, 0) 83 | print "meteor is dead" 84 | meteor_pid = -1 85 | 86 | print "waiting for ports to be closed" 87 | wait_for_port(3000, True) 88 | os.system("killall mongod") # OMG WHY DO I NEED THIS? 89 | wait_for_port(3001, True) 90 | print "ports are closed" 91 | 92 | -------------------------------------------------------------------------------- /extra/servers/regmem.js: -------------------------------------------------------------------------------- 1 | stream = new Meteor.Stream('regmem'); 2 | 3 | // these must be kept sorted 4 | var regs = []; 5 | var mem = []; 6 | 7 | var fs = Npm.require('fs'); 8 | 9 | // eww javascript classes 10 | 11 | function map_create(dic) { 12 | var ret = {}; 13 | for (j in dic) { 14 | var map = []; 15 | for (i in dic[j]) { 16 | map.push([i, dic[j][i]]); 17 | } 18 | map.sort(function(a, b) { return a[0]-b[0]; }) 19 | ret[j] = map; 20 | } 21 | return ret; 22 | } 23 | 24 | function map_getbelow(map, a) { 25 | if (map == undefined) return undefined; 26 | // real binary search from real algorithm class 27 | var b = 0; 28 | var e = map.length-1; 29 | var best = undefined; 30 | while (b <= e) { 31 | var mid = (b+e)>>1; 32 | // do we include the current change? 33 | if (map[mid][0] <= a) { 34 | b = mid+1; 35 | best = mid; 36 | } else { 37 | e = mid-1; 38 | } 39 | } 40 | if (best == undefined) { 41 | return undefined; 42 | } else { 43 | //console.log("search for "+a+" found "+map[best][0]); 44 | return map[best][1]; 45 | } 46 | } 47 | 48 | function read_memdb() { 49 | fs.readFile("/tmp/qira_memdb", function(err, data) { 50 | if (err) { console.log(err); return; } 51 | console.log("read memdb"); 52 | var dat = JSON.parse(data); 53 | regs = map_create(dat['regs']); 54 | mem = map_create(dat['mem']); 55 | console.log("updated memdb"); 56 | }); 57 | } 58 | 59 | var tmout = undefined; 60 | Meteor.startup(function () { 61 | read_memdb(); 62 | fs.watch("/tmp/qira_memdb", {}, function(e, fn) { 63 | //console.log("watch tripped "+e+" "+fn); 64 | if (tmout !== undefined) { 65 | clearTimeout(tmout); 66 | tmout = undefined; 67 | } 68 | tmout = setTimeout(read_memdb, 500); 69 | }); 70 | }); 71 | 72 | // consider a better way to do this 73 | var X86REGS = ['EAX', 'ECX', 'EDX', 'EBX', 'ESP', 'EBP', 'ESI', 'EDI', 'EIP']; 74 | var REGS = X86REGS; 75 | 76 | stream.on('getregisters', function(clnum) { 77 | var ret = []; 78 | for (var i = 0; i < REGS.length; i++) { 79 | var val = map_getbelow(regs[i*4], clnum); 80 | if (val !== undefined) { 81 | ret.push({"name": REGS[i], "address": i*4, "value": val}); 82 | } 83 | } 84 | stream.emit("registers", ret); 85 | }); 86 | 87 | stream.on('getmemory', function(msg) { 88 | var ret = {} 89 | for (var i = msg['address']; i < msg['address'] + msg['len']; i++) { 90 | var val = map_getbelow(mem[i], msg['clnum']); 91 | if (val !== undefined) { 92 | ret[i] = val; 93 | } 94 | } 95 | var rret = {'address': msg['address'], 'len': msg['len'], 'dat': ret}; 96 | stream.emit("memory", rret); 97 | }); 98 | 99 | -------------------------------------------------------------------------------- /extra/vim/qira.vim: -------------------------------------------------------------------------------- 1 | if !has('python') 2 | echo "vim must be compiled with +python" 3 | finish 4 | endif 5 | 6 | " highlight the line 7 | " hi CursorLine cterm=NONE ctermbg=darkblue 8 | set cursorline 9 | 10 | function! UpdateQIRALine() 11 | 12 | python << EOF 13 | 14 | from socketIO_client import SocketIO, BaseNamespace 15 | import vim 16 | 17 | class CdaNamespace(BaseNamespace): 18 | pass 19 | 20 | fn = vim.current.window.buffer.name 21 | (row, col) = vim.current.window.cursor 22 | 23 | sio = SocketIO('localhost', 3002) 24 | cda_namespace = sio.define(CdaNamespace, '/cda') 25 | cda_namespace.emit('navigateline', fn, row) 26 | 27 | EOF 28 | 29 | endfunction 30 | 31 | autocmd CursorMoved * :call UpdateQIRALine() 32 | 33 | -------------------------------------------------------------------------------- /extra/web/changeeditor.js: -------------------------------------------------------------------------------- 1 | Template.changeeditor.events = { 2 | 'click #changeadd': function(e) { 3 | var pending = Session.get('pending'); 4 | var daddr = Session.get('daddr'); 5 | if (daddr === undefined) return; 6 | // no dups 7 | for (var i=0;i 2 | package.js 10 | yui-compressor package.js -o package.js 11 | 12 | # *** FOR DEBUGGING *** 13 | 14 | #JSFILES=$(wget -qO- http://localhost:3000/index.html | grep packages | awk '{ print $3 }' | sed 's/src="/http:\/\/localhost:3000/' | sed 's/?.*//') 15 | #cd packages 16 | #wget -q $JSFILES 17 | 18 | -------------------------------------------------------------------------------- /fetchlibs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | DEBOOTSTRAP_DIR=/usr/share/debootstrap 4 | UBUNTU_KEYRING=/usr/share/keyrings/ubuntu-archive-keyring.gpg 5 | DEBIAN_KEYRING=/usr/share/keyrings/debian-archive-keyring.gpg 6 | 7 | if [ ! -d "$DEBOOTSTRAP_DIR" ] || [ ! -f "$DEBIAN_KEYRING" ]; then 8 | echo "this script requires debootstrap and debian-archive-keyring to be installed" 9 | exit 1 10 | fi 11 | 12 | # this is ubuntu specific i think 13 | fetcharch() { 14 | ARCH="$1" 15 | DISTRO="$2" 16 | SUITE="$3" 17 | exec 4>&1 18 | SHA_SIZE=256 19 | DEBOOTSTRAP_CHECKSUM_FIELD="SHA$SHA_SIZE" 20 | TARGET="$ARCH" 21 | TARGET="$(echo "`pwd`/$TARGET")" 22 | HOST_ARCH=`/usr/bin/dpkg --print-architecture` 23 | HOST_OS=linux 24 | USE_COMPONENTS=main 25 | RESOLVE_DEPS=true 26 | export DEBOOTSTRAP_CHECKSUM_FIELD 27 | 28 | mkdir -p "$TARGET" "$TARGET/debootstrap" 29 | 30 | . $DEBOOTSTRAP_DIR/functions 31 | . $DEBOOTSTRAP_DIR/scripts/$SUITE 32 | 33 | if [ $DISTRO == "ubuntu" ]; then 34 | KEYRING=$UBUNTU_KEYRING 35 | MIRRORS="$DEF_MIRROR" 36 | elif [ $DISTRO == "debian" ]; then 37 | KEYRING=$DEBIAN_KEYRING 38 | MIRRORS="http://ftp.us.debian.org/debian" 39 | else 40 | echo "need a distro" 41 | exit 1 42 | fi 43 | 44 | download_indices 45 | work_out_debs 46 | 47 | all_debs=$(resolve_deps $LIBS) 48 | echo "$all_debs" 49 | download $all_debs 50 | 51 | choose_extractor 52 | extract $all_debs 53 | } 54 | 55 | #rm -rf libs 56 | mkdir -p libs 57 | cd libs 58 | 59 | LIBS="libc-bin libstdc++6" 60 | fetcharch armhf ubuntu trusty 61 | fetcharch armel ubuntu precise 62 | fetcharch powerpc ubuntu trusty 63 | fetcharch arm64 ubuntu trusty 64 | fetcharch i386 ubuntu trusty 65 | fetcharch mips debian jessie 66 | fetcharch mipsel debian jessie 67 | 68 | # mini debootstrap 69 | 70 | -------------------------------------------------------------------------------- /ida/bin/qira_ida66_linux.plx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/ida/bin/qira_ida66_linux.plx -------------------------------------------------------------------------------- /ida/bin/qira_ida66_linux.plx64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/ida/bin/qira_ida66_linux.plx64 -------------------------------------------------------------------------------- /ida/bin/qira_ida66_mac.pmc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/ida/bin/qira_ida66_mac.pmc -------------------------------------------------------------------------------- /ida/bin/qira_ida66_mac.pmc64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/ida/bin/qira_ida66_mac.pmc64 -------------------------------------------------------------------------------- /ida/bin/qira_ida66_windows.p64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/ida/bin/qira_ida66_windows.p64 -------------------------------------------------------------------------------- /ida/bin/qira_ida66_windows.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/ida/bin/qira_ida66_windows.plw -------------------------------------------------------------------------------- /ida/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | SDKROOT=$IDA_SDK 4 | unamestr=$(uname) 5 | if [[ "$unamestr" == 'Linux' ]]; then 6 | IDAROOT=$IDA_DIR 7 | OUTPUT="qira.plx" 8 | OUTPUT64="qira.plx64" 9 | ln -sf libs/linux_libwebsockets.a libwebsockets.a 10 | elif [[ "$unamestr" == 'Darwin' ]]; then 11 | IDAROOT="/Applications/IDA Pro 6.7/idaq.app/Contents/MacOS/" 12 | OUTPUT="qira.pmc" 13 | OUTPUT64="qira.pmc64" 14 | ln -sf libs/mac_libwebsockets.a libwebsockets.a 15 | fi 16 | 17 | # build 32 18 | g++ template.cpp -m32 -fPIC -D__IDP__ -D__PLUGIN__ -c -D__LINUX__ -I . -I$SDKROOT/include 19 | g++ -m32 --shared template.o "-L$IDAROOT" -lida -o $OUTPUT libwebsockets.a -lcrypto -lz -lssl -lpthread 20 | echo "built 32" 21 | 22 | # build 64 23 | g++ template.cpp -D__EA64__=1 -m32 -fPIC -D__IDP__ -D__PLUGIN__ -c -D__LINUX__ -I . -I$SDKROOT/include 24 | g++ -m32 --shared template.o "-L$IDAROOT" -lida64 -o $OUTPUT64 libwebsockets.a -lcrypto -lz -lssl -lpthread 25 | echo "built 64" 26 | 27 | if [[ "$unamestr" == 'Linux' ]]; then 28 | strip $OUTPUT 29 | strip $OUTPUT64 30 | fi 31 | 32 | sha1sum $OUTPUT $OUTPUT64 33 | echo "installing plugin" 34 | cp $OUTPUT "$IDAROOT/plugins" 35 | cp $OUTPUT64 "$IDAROOT/plugins" 36 | 37 | if [[ "$unamestr" == 'Linux' ]]; then 38 | cp $OUTPUT bin/qira_ida_linux.plx 39 | cp $OUTPUT64 bin/qira_ida_linux.plx64 40 | elif [[ "$unamestr" == 'Darwin' ]]; then 41 | cp $OUTPUT bin/qira_ida_mac.pmc 42 | cp $OUTPUT64 bin/qira_ida_mac.pmc64 43 | fi 44 | 45 | -------------------------------------------------------------------------------- /ida/libs/libZLIB.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/ida/libs/libZLIB.a -------------------------------------------------------------------------------- /ida/libs/libwebsockets_static.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/ida/libs/libwebsockets_static.a -------------------------------------------------------------------------------- /ida/libs/linux_libwebsockets.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/ida/libs/linux_libwebsockets.a -------------------------------------------------------------------------------- /ida/libs/mac_libwebsockets.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/ida/libs/mac_libwebsockets.a -------------------------------------------------------------------------------- /ida/mingw_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # build websockets with 4 | # cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-ming.cmake -DLWS_WITH_SSL=0 5 | 6 | SDKROOT=~/build/idasdk66 7 | OUTPUT="qira.plw" 8 | OUTPUT64="qira.p64" 9 | OPENSSL=~/.wine/drive_c/OpenSSL-Win32 10 | MINGW_PREFIX="i686-w64-mingw32" 11 | 12 | # build 32 13 | $MINGW_PREFIX-g++ template.cpp -fPIC -D__IDP__ -D__PLUGIN__ -c -D__NT__ -I . -I$SDKROOT/include 14 | $MINGW_PREFIX-g++ --shared template.o $SDKROOT/lib/x86_win_gcc_32/ida.a \ 15 | -static-libgcc -static-libstdc++ \ 16 | libs/libwebsockets_static.a \ 17 | libs/libZLIB.a \ 18 | -o $OUTPUT -lws2_32 19 | $MINGW_PREFIX-strip $OUTPUT 20 | echo "built 32" 21 | 22 | # build 64 23 | $MINGW_PREFIX-g++ template.cpp -D__EA64__=1 -fPIC -D__IDP__ -D__PLUGIN__ -c -D__NT__ -I . -I$SDKROOT/include 24 | $MINGW_PREFIX-g++ --shared template.o $SDKROOT/lib/x86_win_gcc_64/ida.a \ 25 | -static-libgcc -static-libstdc++ \ 26 | libs/libwebsockets_static.a \ 27 | libs/libZLIB.a \ 28 | -o $OUTPUT64 -lws2_32 29 | $MINGW_PREFIX-strip $OUTPUT64 30 | echo "built 64" 31 | 32 | sha1sum $OUTPUT $OUTPUT64 33 | 34 | cp $OUTPUT bin/qira_ida66_windows.plw 35 | cp $OUTPUT64 bin/qira_ida66_windows.p64 36 | 37 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # install system deps 4 | if [ $(which apt-get) ]; then 5 | echo "installing deps for ubuntu" 6 | sudo apt-get -y install git curl python python-dev python3-pip build-essential pkg-config zlib1g-dev libglib2.0-dev libpixman-1-dev 7 | sudo pip3 install virtualenv 8 | 9 | else 10 | echo "*** You'll need to install Ubuntu or get a working build env for qemu and python yourself ***" 11 | fi 12 | 13 | # build qemu 14 | if [[ "$(uname)" == 'Linux' ]]; then 15 | if [ $(tracers/qemu/qira-i386 > /dev/null; echo $?) == 1 ]; then 16 | echo "QIRA QEMU appears to run okay" 17 | else 18 | echo "building QEMU" 19 | cd tracers 20 | ./qemu_build.sh 21 | cd ../ 22 | fi 23 | else 24 | echo "QEMU user only works on Linux." 25 | echo "While the rest of QIRA will run, you cannot run binaries." 26 | echo "This is due to QEMU user forwarding the syscalls to the kernel." 27 | echo "See other backends in qira/tracers, PIN may work on Windows and OS X" 28 | fi 29 | 30 | echo "building python venv" 31 | virtualenv venv 32 | source venv/bin/activate 33 | pip install --upgrade pip 34 | pip install --upgrade -r requirements.txt 35 | 36 | echo "running tests" 37 | ./run_tests.sh 38 | 39 | echo "making systemwide symlink" 40 | sudo ln -sf $(pwd)/qira /usr/local/bin/qira 41 | 42 | echo "***************************************" 43 | echo " Thanks for installing QIRA" 44 | echo " Check out README for more info" 45 | echo " Or just dive in with 'qira /bin/ls'" 46 | echo " And point Chrome to localhost:3002" 47 | echo " ~geohot" 48 | 49 | -------------------------------------------------------------------------------- /middleware/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/middleware/__init__.py -------------------------------------------------------------------------------- /middleware/arch.py: -------------------------------------------------------------------------------- 1 | # (regname, regsize, is_big_endian, arch_name, branches) 2 | 3 | # PowerPC CPU REGS 4 | PPCREGS = [[], 4, True, "ppc", ["bl "]] 5 | for i in range(32): 6 | PPCREGS[0].append("r"+str(i)) 7 | for i in range(32): 8 | PPCREGS[0].append(None) 9 | PPCREGS[0].append("lr") 10 | PPCREGS[0].append("ctr") 11 | for i in range(8): 12 | PPCREGS[0].append("cr"+str(i)) 13 | 14 | # Aarch64 CPU REGS 15 | AARCH64REGS = [[], 8, False, "aarch64", ["bl ", "blx "]] 16 | for i in range(8): 17 | AARCH64REGS[0].append(None) 18 | for i in range(32): 19 | AARCH64REGS[0].append("x"+str(i)) 20 | #AARCH64REGS[0][8+29] = "fp" 21 | AARCH64REGS[0][8+31] = "sp" 22 | AARCH64REGS[0].append("pc") 23 | 24 | # MIPS CPU REGS 25 | MIPSREGLIST = ['$zero', '$at', '$v0', '$v1', '$a0', '$a1', '$a2', '$a3'] 26 | for i in range(8): 27 | MIPSREGLIST.append('$t'+str(i)) 28 | for i in range(8): 29 | MIPSREGLIST.append('$s'+str(i)) 30 | MIPSREGLIST.append('$t8') 31 | MIPSREGLIST.append('$t9') 32 | MIPSREGLIST.append('$k0') 33 | MIPSREGLIST.append('$k1') 34 | MIPSREGLIST.append('$gp') 35 | MIPSREGLIST.append('$sp') 36 | MIPSREGLIST.append('$fp') 37 | MIPSREGLIST.append('$ra') 38 | MIPSREGLIST.append('$pc') 39 | MIPSREGS = [MIPSREGLIST, 4, True, "mips", ["jal\t","jr\t","jal","jr"]] 40 | 41 | # ARM CPU REGS 42 | 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. 43 | 44 | # Intel x86 CPU REGS 45 | X86REGS = [['EAX', 'ECX', 'EDX', 'EBX', 'ESP', 'EBP', 'ESI', 'EDI', 'EIP'], 4, False, "i386"] 46 | 47 | # x86_64 CPU REGS 48 | X64REGS = [['RAX', 'RCX', 'RDX', 'RBX', 'RSP', 'RBP', 'RSI', 'RDI', "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", 'RIP'], 8, False, "x86-64"] 49 | 50 | -------------------------------------------------------------------------------- /middleware/qira.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.7 2 | from __future__ import print_function 3 | import os 4 | import sys 5 | basedir = os.path.dirname(os.path.realpath(__file__)) 6 | import argparse 7 | import ipaddr 8 | import socket 9 | import threading 10 | import time 11 | 12 | import qira_config 13 | import qira_socat 14 | import qira_program 15 | import qira_webserver 16 | 17 | if __name__ == '__main__': 18 | # define arguments 19 | parser = argparse.ArgumentParser(description = 'Analyze binary. Like "qira /bin/ls /"') 20 | parser.add_argument('-s', "--server", help="bind on port 4000. like socat", action="store_true") 21 | parser.add_argument('-t', "--tracelibraries", help="trace into all libraries", action="store_true") 22 | parser.add_argument('binary', help="path to the binary") 23 | parser.add_argument('args', nargs='*', help="arguments to the binary") 24 | parser.add_argument("--gate-trace", metavar="ADDRESS", help="don't start tracing until this address is hit") 25 | parser.add_argument("--flush-cache", help="flush all QIRA caches", action="store_true") 26 | parser.add_argument("--pin", help="use pin as the backend, requires ./pin_build.sh", action="store_true") 27 | parser.add_argument("--host", metavar="HOST", help="listen address for web interface and socat. "+qira_config.HOST+" by default", default=qira_config.HOST) 28 | parser.add_argument("--web-port", metavar="PORT", help="listen port for web interface. 3002 by default", type=int, default=qira_config.WEB_PORT) 29 | parser.add_argument("--socat-port", metavar="PORT", help="listen port for socat. 4000 by default", type=int, default=qira_config.SOCAT_PORT) 30 | parser.add_argument('-S', '--static', help="enable static2", action="store_true") 31 | parser.add_argument('--no-run', help="don't run the program", action="store_true") 32 | parser.add_argument('--no-delete-runs', help="don't clear the logs", action="store_true") 33 | #capstone flag in qira_config for now 34 | 35 | # parse arguments, first try 36 | args, unknown = parser.parse_known_args() 37 | 38 | # hack to allow arguments to be passed to the analyzed program 39 | sys.argv.insert(sys.argv.index(args.binary), "--") 40 | 41 | # parse args, second try 42 | args = parser.parse_args() 43 | 44 | # validate arguments 45 | if args.web_port < 1 or args.web_port > 65535: 46 | raise Exception("--web-port must be a valid port number (1-65535)") 47 | if args.socat_port < 1 or args.socat_port > 65534: 48 | raise Exception("--socat-port must be a valid port number (1-65534)") 49 | try: 50 | args.host = ipaddr.IPAddress(args.host).exploded 51 | except ValueError: 52 | raise Exception("--web-host must be a valid IPv4/IPv6 address") 53 | 54 | # handle arguments 55 | if sys.platform == "darwin": 56 | print("*** running on darwin, defaulting to --pin") 57 | qira_config.USE_PIN = True 58 | else: 59 | qira_config.USE_PIN = args.pin 60 | 61 | 62 | qira_config.HOST = args.host 63 | qira_config.WEB_PORT = args.web_port 64 | qira_config.SOCAT_PORT = args.socat_port 65 | qira_config.FORK_PORT = args.socat_port + 1 66 | 67 | if args.tracelibraries: 68 | qira_config.TRACE_LIBRARIES = True 69 | 70 | if args.static: 71 | print("*** using static") 72 | qira_config.WITH_STATIC = True 73 | if args.flush_cache: 74 | print("*** flushing caches") 75 | os.system("rm -rfv /tmp/qira*") 76 | 77 | # qemu args from command line 78 | qemu_args = [] 79 | if args.gate_trace != None: 80 | qemu_args.append("-gatetrace") 81 | qemu_args.append(args.gate_trace) 82 | 83 | # creates the file symlink, program is constant through server run 84 | program = qira_program.Program(args.binary, args.args, qemu_args) 85 | 86 | is_qira_running = 1 87 | try: 88 | socket.create_connection(('127.0.0.1', qira_config.WEB_PORT)) 89 | if args.server: 90 | raise Exception("can't run as server if QIRA is already running") 91 | except: 92 | is_qira_running = 0 93 | print("no qira server found, starting it") 94 | program.clear(not args.no_delete_runs) 95 | 96 | # start the binary runner 97 | if args.server: 98 | qira_socat.start_bindserver(program, qira_config.SOCAT_PORT, -1, 1, True) 99 | else: 100 | if not args.no_run: 101 | print("**** running",program.program) 102 | program.execqira(shouldfork=not is_qira_running) 103 | 104 | if not is_qira_running: 105 | # start the http server 106 | qira_webserver.run_server(args, program) 107 | 108 | -------------------------------------------------------------------------------- /middleware/qira_base.py: -------------------------------------------------------------------------------- 1 | def ghex(a): 2 | if a == None: 3 | return None 4 | return hex(a).strip("L") 5 | 6 | def fhex(a): 7 | try: 8 | return int(a, 16) 9 | except: 10 | return None 11 | 12 | -------------------------------------------------------------------------------- /middleware/qira_config.py: -------------------------------------------------------------------------------- 1 | import os,sys 2 | 3 | TRACE_LIBRARIES = False 4 | HOST = '0.0.0.0' 5 | WEB_PORT = 3002 6 | SOCAT_PORT = 4000 7 | FORK_PORT = SOCAT_PORT + 1 8 | USE_PIN = False 9 | if os.name == "nt": 10 | TRACE_FILE_BASE = "c:/qiratmp" 11 | else: 12 | TRACE_FILE_BASE = "/tmp/qira_logs/" 13 | 14 | BASEDIR = os.path.realpath(os.path.dirname(os.path.realpath(__file__))+"/../") 15 | sys.path.append(BASEDIR) 16 | 17 | # TODO: make this true in v3 18 | WITH_STATIC = False 19 | STATIC_CACHE_BASE = "/tmp/qira_static_cache/" 20 | 21 | WEBSOCKET_DEBUG = False 22 | 23 | -------------------------------------------------------------------------------- /middleware/qira_log.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.7 2 | import struct 3 | 4 | IS_VALID = 0x80000000 5 | IS_WRITE = 0x40000000 6 | IS_MEM = 0x20000000 7 | IS_START = 0x10000000 8 | IS_BIGE = 0x08000000 # not supported 9 | SIZE_MASK = 0xFF 10 | 11 | LOGFILE = "/tmp/qira_log" 12 | LOGDIR = "/tmp/qira_logs/" 13 | 14 | def flag_to_type(flags): 15 | if flags & IS_START: 16 | typ = "I" 17 | elif flags & IS_WRITE and flags & IS_MEM: 18 | typ = "S" 19 | elif not flags & IS_WRITE and flags & IS_MEM: 20 | typ = "L" 21 | elif flags & IS_WRITE and not flags & IS_MEM: 22 | typ = "W" 23 | elif not flags & IS_WRITE and not flags & IS_MEM: 24 | typ = "R" 25 | return typ 26 | 27 | def get_log_length(f): 28 | try: 29 | f.seek(0) 30 | dat = f.read(4) 31 | return struct.unpack("I", dat)[0] 32 | except: 33 | return None 34 | 35 | def read_log(f, seek=1, cnt=0): 36 | f.seek(seek*0x18) 37 | if cnt == 0: 38 | dat = f.read() 39 | else: 40 | dat = f.read(cnt * 0x18) 41 | 42 | ret = [] 43 | for i in range(0, len(dat), 0x18): 44 | (address, data, clnum, flags) = struct.unpack("QQII", dat[i:i+0x18]) 45 | if not flags & IS_VALID: 46 | break 47 | ret.append((address, data, clnum, flags)) 48 | 49 | return ret 50 | 51 | def write_log(fn, dat): 52 | # untested 53 | ss = [struct.pack("I", len(dat)) + "\x00"*0x14] 54 | for (address, data, clnum, flags) in dat: 55 | ss.append(struct.pack("QQII", address, data, clnum, flags)) 56 | f = open(fn, "wb") 57 | f.write(''.join(ss)) 58 | f.close() 59 | 60 | if __name__ == "__main__": 61 | import sys 62 | # standalone this can dump a log 63 | for (address, data, clnum, flags) in read_log(open(sys.argv[1])): 64 | print("%4d: %X -> %X %X" % (clnum, address, data, flags)) 65 | 66 | -------------------------------------------------------------------------------- /middleware/qira_socat.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import os 3 | import socket 4 | import signal 5 | import qira_config 6 | 7 | def get_next_run_id(): 8 | ret = -1 9 | for i in os.listdir(qira_config.TRACE_FILE_BASE): 10 | if "_" in i: 11 | continue 12 | ret = max(ret, int(i)) 13 | return ret+1 14 | 15 | bound_ports = {} 16 | 17 | def start_bindserver(program, port, parent_id, start_cl, loop = False): 18 | if port not in bound_ports: 19 | myss = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 20 | myss.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 21 | myss.bind((qira_config.HOST, port)) 22 | myss.listen(5) 23 | bound_ports[port] = myss 24 | else: 25 | myss = bound_ports[port] 26 | 27 | if os.fork() != 0: 28 | return 29 | print("**** socat listening on %s:%s" % myss.getsockname()) 30 | 31 | # bindserver runs in a fork 32 | while 1: 33 | (cs, address) = myss.accept() 34 | # fork off the child if we are looping 35 | if loop: 36 | if os.fork() != 0: 37 | cs.close() 38 | continue 39 | run_id = get_next_run_id() 40 | fd = cs.fileno() 41 | print("**** ID %s CLIENT %s:%s fd: %s" % (run_id, address[0], address[1], fd)) 42 | 43 | # python nonblocking is a lie... 44 | signal.signal(signal.SIGPIPE, signal.SIG_DFL) 45 | try: 46 | import fcntl 47 | fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL, 0) & ~os.O_NONBLOCK) 48 | except: 49 | pass 50 | os.dup2(fd, 0) 51 | os.dup2(fd, 1) 52 | os.dup2(fd, 2) 53 | for i in range(3, fd+1): 54 | try: 55 | os.close(i) 56 | except: 57 | pass 58 | # fingerprint here 59 | program.execqira(["-qirachild", "%d %d %d" % (parent_id, start_cl, run_id)], shouldfork=False) 60 | 61 | -------------------------------------------------------------------------------- /middleware/qiradb/.gitignore: -------------------------------------------------------------------------------- 1 | qiradb.cpp 2 | *.pyxbldc 3 | -------------------------------------------------------------------------------- /middleware/qiradb/Trace/Trace.pxd: -------------------------------------------------------------------------------- 1 | # distutils: language = c++ 2 | 3 | from libc.stdint cimport uint32_t, uint64_t, uint16_t 4 | from libcpp cimport bool 5 | from libcpp.map cimport map 6 | from libcpp.vector cimport vector 7 | 8 | cdef extern from "Trace.cpp": 9 | pass 10 | 11 | cdef extern from "Trace.h": 12 | ctypedef uint32_t Clnum; 13 | ctypedef uint64_t Address; 14 | ctypedef uint16_t MemoryWithValid; 15 | 16 | cdef struct change: 17 | Address address 18 | uint64_t data 19 | Clnum clnum 20 | uint32_t flags 21 | 22 | cdef cppclass Trace: 23 | Trace() 24 | bool ConnectToFileAndStart(char *filename, unsigned int trace_index, int register_size, int register_count, bool is_big_endian) 25 | Clnum GetMaxClnum() 26 | Clnum GetMinClnum() 27 | bool GetDidUpdate() 28 | 29 | map[Address, char] GetPages() 30 | vector[Clnum] FetchClnumsByAddressAndType(Address, char, Clnum, Clnum, unsigned int) 31 | vector[uint64_t] FetchRegisters(Clnum clnum) 32 | vector[MemoryWithValid] FetchMemory(Clnum clnum, Address address, int len) 33 | vector[change] FetchChangesByClnum(Clnum clnum, unsigned int limit) 34 | 35 | char get_type_from_flags(uint32_t flags) 36 | 37 | -------------------------------------------------------------------------------- /middleware/qiradb/Trace/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/middleware/qiradb/Trace/__init__.py -------------------------------------------------------------------------------- /middleware/qiradb/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | # only pyximport this 4 | import pyximport 5 | py_importer, pyx_importer = pyximport.install() 6 | from .qiradb import PyTrace 7 | sys.meta_path.remove(pyx_importer) 8 | 9 | -------------------------------------------------------------------------------- /middleware/qiradb/qiradb.pyx: -------------------------------------------------------------------------------- 1 | from Trace.Trace cimport Trace 2 | 3 | # copied from Trace.h 4 | SIZE_MASK = 0xFF 5 | PAGE_INSTRUCTION = 1 6 | PAGE_READ = 2 7 | PAGE_WRITE = 4 8 | 9 | MAXINT = 2**32-1 10 | 11 | cdef class PyTrace: 12 | cdef Trace *t 13 | 14 | def __cinit__(self, filename, trace_index, register_size, register_count, is_big_endian): 15 | self.t = new Trace() 16 | assert self.t.ConnectToFileAndStart(filename.encode('utf-8'), trace_index, register_size, register_count, is_big_endian) 17 | 18 | def __dealloc__(self): 19 | del self.t 20 | 21 | def get_maxclnum(self): 22 | return self.t.GetMaxClnum() 23 | 24 | def get_minclnum(self): 25 | return self.t.GetMinClnum() 26 | 27 | def did_update(self): 28 | return self.t.GetDidUpdate() 29 | 30 | def get_pmaps(self): 31 | ret = {} 32 | pagemap = self.t.GetPages() 33 | for address,ttype in pagemap: 34 | if ttype & PAGE_INSTRUCTION: 35 | ret[address] = "instruction" 36 | elif ttype & PAGE_WRITE: 37 | ret[address] = "memory" 38 | elif ttype & PAGE_READ: 39 | ret[address] = "romemory" 40 | return ret 41 | 42 | def fetch_clnums_by_address_and_type(self, address, ttype, start_clnum, end_clnum, limit): 43 | return self.t.FetchClnumsByAddressAndType(address, ord(ttype), start_clnum, end_clnum, limit) 44 | 45 | def fetch_registers(self, clnum): 46 | if clnum == -1: # fetch the latest 47 | clnum = MAXINT 48 | return self.t.FetchRegisters(clnum) 49 | 50 | def fetch_memory(self, clnum, address, llen): 51 | if clnum == -1: # fetch the latest 52 | clnum = MAXINT 53 | return self.t.FetchMemory(clnum, address, llen) 54 | 55 | def fetch_changes_by_clnum(self, clnum, limit): 56 | ret = [] 57 | if limit == -1: 58 | limit = 0 59 | its = self.t.FetchChangesByClnum(clnum, limit) 60 | for it in its: 61 | tl = {"address": it.address, 62 | "data": it.data, 63 | "clnum": it.clnum, 64 | "type": chr(self.t.get_type_from_flags(it.flags)), 65 | "size": it.flags & SIZE_MASK} 66 | ret.append(tl) 67 | return ret 68 | 69 | -------------------------------------------------------------------------------- /middleware/qiradb/qiradb.pyxbld: -------------------------------------------------------------------------------- 1 | import os 2 | def make_ext(modname, pyxfilename): 3 | from distutils.extension import Extension 4 | include_dir = os.path.join(os.path.dirname(pyxfilename), 'Trace') 5 | return Extension(name=modname, 6 | include_dirs=[include_dir], 7 | sources=[pyxfilename], 8 | language='c++') 9 | 10 | -------------------------------------------------------------------------------- /qira: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | unamestr=$(uname) 3 | if [[ "$unamestr" == 'Linux' ]]; then 4 | DIR=$(dirname $(readlink -f $0)) 5 | elif [[ "$unamestr" == "Darwin" ]]; then 6 | cmd=$(which "$0") 7 | if [ -L "$cmd" ]; then 8 | cmd=$(readlink "$cmd") 9 | fi 10 | DIR=$(dirname "$cmd") 11 | else 12 | echo "Only Linux and Mac OS X are supported!" 13 | exit 14 | fi 15 | 16 | unset PYTHONPATH 17 | source $DIR/venv/bin/activate 18 | exec /usr/bin/env python $DIR/middleware/qira.py $* 19 | -------------------------------------------------------------------------------- /qira_tests/bin/hello_trace: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/qira_tests/bin/hello_trace -------------------------------------------------------------------------------- /qira_tests/bin/loop: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/qira_tests/bin/loop -------------------------------------------------------------------------------- /qira_tests/load_page.js: -------------------------------------------------------------------------------- 1 | var page = require('webpage').create(); 2 | page.settings.javascriptEnabled = true; 3 | 4 | page.onConsoleMessage = function(msg) { 5 | console.log(msg); 6 | }; 7 | 8 | page.open('http://localhost:3002/', function() { 9 | var title = page.evaluate(function() { return document.title; }); 10 | if (title !== "qira") { 11 | console.log("BAD TITLE"); 12 | phantom.exit(-1); 13 | } 14 | phantom.exit(); 15 | }); 16 | 17 | 18 | -------------------------------------------------------------------------------- /qira_tests/test_qira_program_runs.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append("middleware/") 3 | import qira_program 4 | import time 5 | 6 | def test(): 7 | program = qira_program.Program("qira_tests/bin/loop") 8 | program.execqira(shouldfork=True) 9 | time.sleep(1) 10 | 11 | 12 | -------------------------------------------------------------------------------- /qira_tests/test_qiradb.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import qiradb 3 | import time 4 | #print dir(qiradb) 5 | 6 | LIMIT = 10000 7 | 8 | #print "new_trace:", qiradb.new_trace("/tmp/qira_logs/0", 0, 4, 16) 9 | #time.sleep(100000.0) 10 | 11 | # register size = 4, register count = 9 12 | def test(): 13 | t = qiradb.PyTrace("qira_tests/bin/hello_trace", 0, 4, 9, False) 14 | print("trace created") 15 | 16 | while not t.did_update(): 17 | print("waiting...") 18 | time.sleep(0.1) 19 | 20 | # get max change 21 | ret = t.get_maxclnum() 22 | print("maxclnum:",ret) 23 | assert ret == 116 24 | 25 | # get min change 26 | ret = t.get_minclnum() 27 | print("minclnum:",ret) 28 | assert ret == 0 29 | 30 | # who loads argc? 31 | ret = t.fetch_clnums_by_address_and_type(0xf6fff090, 'L', 0, 1000, LIMIT) 32 | print("load argc:",ret) 33 | assert ret == [0,2] 34 | 35 | # fetch registers 36 | ret = t.fetch_registers(113) 37 | print("fetch regs:",list(map(hex, ret))) 38 | assert len(ret) == 9 39 | assert ret[8] == 0x80484d1 40 | assert ret[4] == 0xf6ffef00 41 | 42 | # fetch memory 43 | ret = t.fetch_memory(0, 0xf6fff080, 0x10) 44 | print(ret) 45 | ret = t.fetch_memory(7, 0xf6fff080, 0x10) 46 | print(ret) 47 | ret = t.fetch_memory(116, 0xf6fff080, 0x10) 48 | print(ret) 49 | 50 | # was a pop %esi 51 | ret = t.fetch_changes_by_clnum(2, LIMIT) 52 | print("pop esi:",ret) 53 | 54 | print(t.get_pmaps()) 55 | 56 | """ 57 | while 1: 58 | ret = t.fetch_clnums_by_address_and_type(0xf6fff090, 'L', 0, LIMIT) 59 | ret = t.fetch_registers(113) 60 | ret = t.fetch_memory(0, 0xf6fff080, 0x10) 61 | """ 62 | 63 | -------------------------------------------------------------------------------- /qira_tests/test_static2.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append("static2/") 3 | import static2 4 | 5 | def test(): 6 | static = static2.Static('qira_tests/bin/loop', debug=1) 7 | static.process() 8 | 9 | -------------------------------------------------------------------------------- /qira_tests/testvm/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | vagrant destroy 3 | vagrant up 4 | rm -rf /tmp/qira_release 5 | mkdir -p /tmp/qira_release 6 | scp e:~/qira/distrib/*.xz /tmp/qira_release/. 7 | vagrant ssh-config > /tmp/qira_release/ssh_config 8 | scp -F /tmp/qira_release/ssh_config /tmp/qira_release/*.xz default:~/ 9 | ssh -F /tmp/qira_release/ssh_config -L 3002:localhost:3002 default 10 | 11 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | capstone==4.0.1 2 | certifi==2019.3.9 3 | chardet==3.0.4 4 | Click==7.0 5 | Cython==0.29.6 6 | Flask==1.0.2 7 | Flask-SocketIO==3.3.2 8 | gevent==1.4.0 9 | greenlet==0.4.15 10 | hexdump==3.3 11 | idna==2.8 12 | ipaddr==2.2.0 13 | itsdangerous==1.1.0 14 | Jinja2==2.10 15 | MarkupSafe==1.1.1 16 | nose==1.3.7 17 | Pillow==5.4.1 18 | pydot==1.4.1 19 | pyelftools==0.25 20 | pyparsing==2.3.1 21 | python-engineio==3.5.0 22 | python-socketio==3.1.2 23 | requests==2.21.0 24 | six==1.12.0 25 | socketIO-client==0.7.2 26 | urllib3==1.24.1 27 | websocket-client==0.56.0 28 | Werkzeug==0.15.1 29 | -------------------------------------------------------------------------------- /run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # test distribution 4 | if [ "$1" == "distrib" ] ; then 5 | echo "*** testing distrib" 6 | ./bdistrib.sh 7 | cd distrib/qira 8 | ./install.sh 9 | cd ../../ 10 | fi 11 | 12 | source venv/bin/activate 13 | nosetests -v -s 14 | 15 | # integration test 16 | ./qira qira_tests/bin/loop & 17 | QIRA_PID=$! 18 | trap "kill $QIRA_PID" EXIT 19 | echo "qira pid is $QIRA_PID" 20 | sleep 2 21 | 22 | # replace phantomjs test with this 23 | #phantomjs qira_tests/load_page.js 24 | curl http://localhost:3002/ | grep "qira" 25 | 26 | echo "tests pass" 27 | 28 | -------------------------------------------------------------------------------- /run_tests_static.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | source venv/bin/activate 4 | 5 | # ned's tests, which are really awesome 6 | # why weren't these used? 7 | cd tests_auto 8 | #./autogen-extras.sh 9 | #python autogen.py --dwarf --all 10 | python autogen.py --dwarf 11 | cd ../ 12 | cd static2 13 | python testing.py 14 | 15 | -------------------------------------------------------------------------------- /static2/TESTING: -------------------------------------------------------------------------------- 1 | The goal of this library is to do a good job of recovering static structure. 2 | 3 | We should develop an automated testing framework to take in binaries, and 4 | compare the results of CFG recovery stripped and unstripped with DWARF. Variable 5 | recovery and stuff should eventually all live here. 6 | 7 | We could also have the testing framework compare against IDA, since we can script it. 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /static2/analyzer.py: -------------------------------------------------------------------------------- 1 | try: 2 | import Queue 3 | except ImportError: 4 | import queue as Queue 5 | from model import Function, Block, DESTTYPE 6 | import time 7 | 8 | def analyze_functions(static): 9 | make_function_at(static, static['entry']) 10 | main = static.get_address_by_name("main") 11 | if main != None: 12 | make_function_at(static, main) 13 | # TODO: use functions from loaded program 14 | 15 | # things to actually drive the static analyzer 16 | # runs the recursive descent parser at address 17 | # how to deal with block groupings? 18 | def make_function_at(static, address, recurse = True): 19 | if static[address]['function'] != None: 20 | # already function 21 | return 22 | start = time.time() 23 | block_starts = set([address]) 24 | function_starts = set() 25 | this_function = Function(address) 26 | static['functions'].add(this_function) 27 | 28 | def disassemble(address): 29 | raw = static.memory(address, 0x10) 30 | d = static[address]['instruction'] 31 | static[address]['function'] = this_function 32 | for (c,flag) in d.dests(): 33 | if flag == DESTTYPE.call: 34 | static._auto_update_name(c,"sub_%x"%(c)) 35 | function_starts.add(c) 36 | #print "%s %x is in %x xrefs" % (d,address, c) 37 | static[c]['xrefs'].add(address) 38 | # add this to the potential function boundary starts 39 | continue 40 | if c != address + d.size(): 41 | #print "%s %x is in %x crefs" % (d,address, c) 42 | static[c]['crefs'].add(address) 43 | static._auto_update_name(c,"loc_%x"%(c)) 44 | block_starts.add(c) 45 | 46 | #if we come after a jump and are an implicit xref, we are the start 47 | #of a new block 48 | elif d.is_jump() and not d.is_call(): 49 | static._auto_update_name(c,"loc_%x"%(c)) 50 | block_starts.add(c) 51 | return d.dests() 52 | 53 | # recursive descent pass 54 | pending = Queue.Queue() 55 | done = set() 56 | pending.put(address) 57 | while not pending.empty(): 58 | dests = disassemble(pending.get()) 59 | for (d,flag) in dests: 60 | if flag == DESTTYPE.call: 61 | #this will get handled in the function pass 62 | continue 63 | if d not in done: 64 | pending.put(d) 65 | done.add(d) 66 | if (time.time() - start) > 0.01: 67 | time.sleep(0.01) 68 | start = time.time() 69 | 70 | #print map(hex, done) 71 | 72 | # block finding pass 73 | for b in block_starts: 74 | this_block = Block(b) 75 | this_function.add_block(this_block) 76 | address = b 77 | i = static[address]['instruction'] 78 | while not i.is_ending() and i.size() != 0: 79 | if address + i.size() in block_starts: 80 | break 81 | address += i.size() 82 | i = static[address]['instruction'] 83 | this_block.add(address) 84 | static[address]['block'] = this_block 85 | if (time.time() - start) > 0.01: 86 | time.sleep(0.01) 87 | start = time.time() 88 | static['blocks'].add(this_block) 89 | 90 | # find more functions 91 | if recurse: 92 | for f in function_starts: 93 | if static[f]['function'] == None: 94 | make_function_at(static, f) 95 | 96 | -------------------------------------------------------------------------------- /static2/loader.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from elftools.elf.elffile import ELFFile 3 | from elftools.elf.sections import SymbolTableSection 4 | from elftools.elf.relocation import RelocationSection 5 | from elftools.common.exceptions import ELFError 6 | import struct 7 | 8 | def get_arch(fb): 9 | if fb == 0x28: 10 | return 'arm' 11 | elif fb == 0xb7: 12 | return 'aarch64' 13 | elif fb == 0x3e: 14 | return 'x86-64' 15 | elif fb == 0x03: 16 | return 'i386' 17 | elif fb == 0x08: 18 | return 'mipsel' 19 | elif fb == 0x1400: # big endian... 20 | return 'ppc' 21 | elif fb == 0x800: 22 | return 'mips' 23 | 24 | 25 | def load_binary(static): 26 | try: 27 | elf = ELFFile(open(static.path, "rb")) 28 | except ELFError: 29 | print("*** loader error: non-ELF detected") 30 | return 31 | 32 | # TODO: replace with elf['e_machine'] 33 | progdat = open(static.path, "rb").read(0x20) 34 | fb = struct.unpack("H", progdat[0x12:0x14])[0] # e_machine 35 | static['arch'] = get_arch(fb) 36 | static['entry'] = elf['e_entry'] 37 | 38 | ncount = 0 39 | for segment in elf.iter_segments(): 40 | addr = segment['p_vaddr'] 41 | if segment['p_type'] == 'PT_LOAD': 42 | memsize = segment['p_memsz'] 43 | static.add_memory_chunk(addr, segment.data().ljust(memsize, b"\x00")) 44 | 45 | for section in elf.iter_sections(): 46 | if static.debug >= 2: 47 | print("** found section", section.name, type(section)) 48 | 49 | if isinstance(section, RelocationSection): 50 | symtable = elf.get_section(section['sh_link']) 51 | if symtable.is_null(): 52 | continue 53 | 54 | for rel in section.iter_relocations(): 55 | symbol = symtable.get_symbol(rel['r_info_sym']) 56 | if static.debug >= 2: #suppress output for testing 57 | print("Relocation",rel, symbol.name) 58 | if rel['r_offset'] != 0 and symbol.name != "": 59 | static[rel['r_offset']]['name'] = "__"+symbol.name 60 | ncount += 1 61 | 62 | # hacks for PLT 63 | # TODO: this is fucking terrible 64 | if section.name == '.rel.plt' or section.name == '.rela.plt': 65 | # first symbol is blank 66 | plt_symbols = [] 67 | for rel in section.iter_relocations(): 68 | symbol = symtable.get_symbol(rel['r_info_sym']) 69 | plt_symbols.append(symbol.name) 70 | 71 | # does this change? 72 | PLT_ENTRY_SIZE = 0x10 73 | 74 | for section in elf.iter_sections(): 75 | if section.name == ".plt": 76 | for name, addr in zip(plt_symbols, 77 | range(section['sh_addr'] + PLT_ENTRY_SIZE, 78 | section['sh_addr'] + PLT_ENTRY_SIZE + PLT_ENTRY_SIZE*len(plt_symbols), 79 | PLT_ENTRY_SIZE)): 80 | static[addr]['name'] = name 81 | #print plt_symbols, section['sh_addr'] 82 | 83 | 84 | if isinstance(section, SymbolTableSection): 85 | for nsym, symbol in enumerate(section.iter_symbols()): 86 | #print symbol['st_info'], symbol.name, hex(symbol['st_value']) 87 | if symbol['st_value'] != 0 and symbol.name != "" and symbol['st_info']['type'] == "STT_FUNC": 88 | if static.debug >= 2: 89 | print("Symbol",hex(symbol['st_value']), symbol.name) 90 | static[symbol['st_value']]['name'] = symbol.name 91 | ncount += 1 92 | 93 | # parse the DynamicSection to get the libraries 94 | #if isinstance(section, DynamicSection): 95 | if static.debug >= 1: 96 | print("** found %d names" % ncount) 97 | 98 | -------------------------------------------------------------------------------- /tests_auto/autogen-extras.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | #installs support for cross-compiled architectures on Ubuntu 14.04 3 | 4 | sudo apt-get -y install clang gcc-4.8-multilib gcc-4.8-aarch64-linux-gnu gcc-4.8-arm-linux-gnu gcc-4.8-powerpc-linux-gnu gcc-4.8-powerpc64le-linux-gnu 5 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/argtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) { 4 | int i; 5 | for (i = 0; i < argc; i++) { 6 | printf("%d: %s\n", i, argv[i]); 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/aslrtest.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | printf("hello %p\n", main); 3 | } 4 | 5 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/call_mem.c: -------------------------------------------------------------------------------- 1 | int quad(int x) 2 | { 3 | return x*4; 4 | } 5 | 6 | int (*quad_ptr)(int); 7 | 8 | int main() 9 | { 10 | quad_ptr = &quad; 11 | return (*quad_ptr)(3); 12 | } 13 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/cfgifloop.c: -------------------------------------------------------------------------------- 1 | int main(int argc) { 2 | int i, j; 3 | for (i = 0; i < 6; i++) { 4 | if (argc==1) { 5 | for (j = 0; j < 6; j++) { 6 | printf("%d %d\n", i, j); 7 | if (j == 4) break; 8 | } 9 | } else { 10 | printf("cats %d\n", i); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/changetest.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) { 4 | int a = atoi(argv[1])+27; 5 | printf("got %d\n", a); 6 | if (a == 37) { 7 | printf("WINNER\n"); 8 | } else { 9 | printf("LOSER\n"); 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/demo.c: -------------------------------------------------------------------------------- 1 | int test(int a) { 2 | a += 3; 3 | a *= 2; 4 | return a; 5 | } 6 | 7 | int main() { 8 | printf("hello world\n"); 9 | int i; 10 | for (i = 0; i < 5; i++) { 11 | printf("%d\n", test(i)); 12 | } 13 | return 0; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/echo.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | char buf[0x100]; 5 | printf("swag is king\n"); 6 | fflush(stdout); 7 | fprintf(stderr, "error is king\n"); 8 | fflush(stderr); 9 | while (1) { 10 | int a = read(0, buf, 0x100); 11 | if (a <= 0) break; 12 | write(1, buf, a); 13 | } 14 | return -1; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/forktest.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | printf("FORK TEST\n"); 5 | fflush(stdout); 6 | fork(); 7 | printf("hi %d\n", getpid()); 8 | /*if (fork() == 0) { 9 | printf("hello child\n"); 10 | } else { 11 | printf("world parent\n"); 12 | }*/ 13 | } 14 | 15 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/forloop.c: -------------------------------------------------------------------------------- 1 | #include 2 | volatile int k = 0; 3 | 4 | void swag() { 5 | k++; 6 | } 7 | 8 | int main(int argc, char *argv[]) { 9 | int i; 10 | int j = atoi(argv[1]); 11 | for (i = 0; i < j; i++) { 12 | swag(); 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/functest.c: -------------------------------------------------------------------------------- 1 | int a() { 2 | return 27; 3 | } 4 | 5 | int b() { 6 | return 52; 7 | } 8 | 9 | int main() { 10 | int i = a() + b(); 11 | if (i > 0) { 12 | printf("%d\n", i); 13 | } else { 14 | printf("TEH FUCK\n"); 15 | } 16 | return 0; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/heapfunn.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define NUMBUFS 10 5 | char *bufs[NUMBUFS]; 6 | 7 | int main() { 8 | unsigned int bufnum, size, haxx, i; 9 | int ret; 10 | for (i = 0; i < NUMBUFS; i++) bufs[i] = NULL; 11 | printf("exploit me bro\n"); fflush(stdout); 12 | while (1) { 13 | ret = read(0, &bufnum, sizeof(bufnum)); if (ret <= 0) break; 14 | if (bufnum >= NUMBUFS) continue; 15 | ret = read(0, &size, sizeof(size)); if (ret <= 0) break; 16 | ret = read(0, &haxx, sizeof(haxx)); if (ret <= 0) break; 17 | if (size == 0) { 18 | if (bufs[bufnum] != NULL) free(bufs[bufnum]); 19 | bufs[bufnum] = NULL; 20 | } else { 21 | bufs[bufnum] = (char *)malloc(size); 22 | if (bufs[bufnum] != NULL) { 23 | printf("%p\n", bufs[bufnum]); fflush(stdout); 24 | ret = read(0, bufs[bufnum], size); if (ret <= 0) break; 25 | if (haxx) { 26 | bufs[bufnum][size] = '\0'; 27 | } 28 | } 29 | } 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/heaptest.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | char *a = malloc(0x100); 5 | char *b = malloc(0x100); 6 | memset(a, 0, 0x400); 7 | //read(0, a, 0x100); 8 | free(b); 9 | } 10 | 11 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/loop.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int i; 5 | for (i = 0; i < 5; i++) { 6 | printf("%d\n", i); 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/loophaxx.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | int print(int i) { 5 | printf("%d\n", i); 6 | } 7 | 8 | int main() { 9 | int i; 10 | for (i = 0; i < 5; i++) { 11 | print(i); 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/million.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | volatile int i; 3 | for (i = 0; i < 1000000; i++); 4 | return i; 5 | } 6 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/procselfmaps.c: -------------------------------------------------------------------------------- 1 | #include 2 | char buf[0x1000]; 3 | 4 | int main() { 5 | FILE *f = fopen("/proc/self/maps", "rb"); 6 | buf[fread(buf, 1, 0x1000, f)] = '\0'; 7 | fclose(f); 8 | printf("%s\n", buf); 9 | return 0; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/slicingtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(int argc, char *argv[]) { 3 | int i = atoi(argv[1]); 4 | int j = atoi(argv[2]); 5 | int k = atoi(argv[3]); 6 | int l = i + j; 7 | int m = i + k; 8 | int n = j + k; 9 | printf("%d %d %d\n", l, m, n); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/stackframetest.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int stacked(int input) { 4 | int plus_2 = input + 2; 5 | int times_5 = input * 5; 6 | return plus_2 + times_5; 7 | } 8 | 9 | int main() { 10 | int i; 11 | for (i = 1; i < 4; i++) printf("%d %d\n", i, stacked(i)); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/switchtest.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char *argv[]) { 2 | switch(argc) { 3 | case 1: 4 | printf("1 args\n"); 5 | break; 6 | case 2: 7 | printf("2 args\n"); 8 | break; 9 | case 3: 10 | printf("3 args\n"); 11 | break; 12 | case 10: 13 | printf("10 args\n"); 14 | break; 15 | case 47: 16 | printf("47 args\n"); 17 | break; 18 | } 19 | return 0; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /tests_auto/source-autogen/test64.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | volatile long a = 0xFFFFFFFFFFFFFFFF; 5 | a--; 6 | a *= 2; 7 | printf("%ld\n", a); 8 | return a; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /tests_manual/DBRUMLEY_0004_release: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/DBRUMLEY_0004_release -------------------------------------------------------------------------------- /tests_manual/algo.c: -------------------------------------------------------------------------------- 1 | int _start() { 2 | main(); 3 | asm("movl $1,%%eax\n" \ 4 | "xorl %%ebx,%%ebx\n" \ 5 | "int $0x80" : ); 6 | } 7 | 8 | int bubble_sort(int *dat, int len) { 9 | int ret = 0; 10 | int i, j; 11 | for (i = 0; i < len; i++) { 12 | for (j = i; j < len; j++) { 13 | if (dat[j] < dat[i]) { 14 | ret++; 15 | dat[i] ^= dat[j]; 16 | dat[j] ^= dat[i]; 17 | dat[i] ^= dat[j]; 18 | } 19 | } 20 | } 21 | return ret; 22 | } 23 | 24 | int fib(int n) { 25 | if (n == 0 || n == 1) { 26 | return 1; 27 | } 28 | return fib(n-1) + fib(n-2); 29 | } 30 | 31 | int recurse_countdown(int i) { 32 | if (i == 0) return 1; 33 | int ret = recurse_countdown(i-1); 34 | return ret+1; 35 | } 36 | 37 | int sum_of_1_through_10() { 38 | int i, j=0; 39 | for (i = 0; i < 10; i++) { 40 | j += i; 41 | } 42 | return i; 43 | } 44 | 45 | int control_flow(int a) { 46 | if (a) return 6; 47 | else return 4; 48 | } 49 | 50 | int nest2() { 51 | return 25; 52 | } 53 | 54 | int nest1() { 55 | return nest2(); 56 | } 57 | 58 | int nest() { 59 | return nest1(); 60 | } 61 | 62 | void memcpy(char *dest, char *src, int len) { 63 | int i; 64 | for (i=0;i 2 | #include 3 | 4 | int main(int argc) { 5 | printf("hello: %f\n", sin(argc)); 6 | } 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests_manual/double_link_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/double_link_64 -------------------------------------------------------------------------------- /tests_manual/doubleshell: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/doubleshell -------------------------------------------------------------------------------- /tests_manual/doubleshell.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | int main() { 6 | int (*sc)(); 7 | 8 | char *ptr = mmap(0, 0x1000, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0); 9 | sc = ptr; 10 | 11 | ptr[0] = 0x31; 12 | ptr[1] = 0xc0; 13 | ptr[2] = 0x40; 14 | ptr[3] = 0xc3; 15 | printf("%d\n", sc()); 16 | 17 | ptr[2] = 0xc3; 18 | printf("%d\n", sc()); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /tests_manual/haskell/hello: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/haskell/hello -------------------------------------------------------------------------------- /tests_manual/haskell/hello.hi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/haskell/hello.hi -------------------------------------------------------------------------------- /tests_manual/haskell/hello.hs: -------------------------------------------------------------------------------- 1 | main = putStrLn "Hello, World!" 2 | -------------------------------------------------------------------------------- /tests_manual/haskell/hello.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/haskell/hello.o -------------------------------------------------------------------------------- /tests_manual/hello: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/hello -------------------------------------------------------------------------------- /tests_manual/hello.S: -------------------------------------------------------------------------------- 1 | section .text 2 | global _start ;must be declared for linker (ld) 3 | 4 | _start: ;tell linker entry point 5 | 6 | mov edx,len ;message length 7 | mov ecx,msg ;message to write 8 | mov ebx,1 ;file descriptor (stdout) 9 | mov eax,4 ;system call number (sys_write) 10 | int 0x80 ;call kernel 11 | 12 | mov eax,1 ;system call number (sys_exit) 13 | int 0x80 ;call kernel 14 | 15 | section .data 16 | 17 | msg db 'Hello, world!',0xa ;our dear string 18 | len equ $ - msg ;length of our dear string 19 | -------------------------------------------------------------------------------- /tests_manual/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main() { write(0, "hello world\n", 12); return 0; } 3 | 4 | -------------------------------------------------------------------------------- /tests_manual/helloc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/helloc -------------------------------------------------------------------------------- /tests_manual/jmpbug.asm: -------------------------------------------------------------------------------- 1 | mov eax, 3 2 | 3 | fail: 4 | mov ebx, 2 5 | sub eax, 1 6 | cmp eax, 0 7 | jne fail 8 | 9 | mov eax, 1 10 | int 0x80 11 | 12 | -------------------------------------------------------------------------------- /tests_manual/loop_macho32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/loop_macho32 -------------------------------------------------------------------------------- /tests_manual/loop_macho64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/loop_macho64 -------------------------------------------------------------------------------- /tests_manual/printesp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | register long esp __asm__("esp"); 5 | printf("%8.8lx\n", esp); 6 | } 7 | 8 | -------------------------------------------------------------------------------- /tests_manual/printesp32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/printesp32 -------------------------------------------------------------------------------- /tests_manual/printesp64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/printesp64 -------------------------------------------------------------------------------- /tests_manual/realworld/zpipe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/realworld/zpipe -------------------------------------------------------------------------------- /tests_manual/stackframetest_x86: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/stackframetest_x86 -------------------------------------------------------------------------------- /tests_manual/suite/a679df07a8f3a8d590febad45336d031-stkof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/suite/a679df07a8f3a8d590febad45336d031-stkof -------------------------------------------------------------------------------- /tests_manual/suite/deepblue-337848eb3f394204c016331a0e1b3b5a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/suite/deepblue-337848eb3f394204c016331a0e1b3b5a -------------------------------------------------------------------------------- /tests_manual/suite/echo64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/suite/echo64 -------------------------------------------------------------------------------- /tests_manual/suite/exploit2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/suite/exploit2 -------------------------------------------------------------------------------- /tests_manual/suite/ezhp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/suite/ezhp -------------------------------------------------------------------------------- /tests_manual/suite/hop-62fa7ade9a1fa9254361e69d70e7a7e3.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/suite/hop-62fa7ade9a1fa9254361e69d70e7a7e3.exe -------------------------------------------------------------------------------- /tests_manual/suite/justify: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/suite/justify -------------------------------------------------------------------------------- /tests_manual/suite/ty-b83f0d0edeb8cfad76d30eddc58da139: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/suite/ty-b83f0d0edeb8cfad76d30eddc58da139 -------------------------------------------------------------------------------- /tests_manual/supanoob: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/supanoob -------------------------------------------------------------------------------- /tests_manual/thread_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void start1() { 5 | int i = 100; 6 | while (1) { printf("t1 %d\n", i++); sleep(1); } 7 | } 8 | 9 | void start2() { 10 | int i = 200; 11 | while (1) { printf("t2 %d\n", i++); sleep(1); } 12 | } 13 | 14 | int main() { 15 | pthread_t t1, t2; 16 | pthread_create(&t1, NULL, start1, NULL); 17 | pthread_create(&t2, NULL, start2, NULL); 18 | pthread_join(t1, NULL); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /tests_manual/vimplugin/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/vimplugin/a.out -------------------------------------------------------------------------------- /tests_manual/vimplugin/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "swag.h" 3 | 4 | int main() { 5 | int i; 6 | int j = 1; 7 | int k = 1; 8 | int l = 1; 9 | for (i = 1; i < 10; i++) { 10 | j *= i; 11 | k += 1; 12 | l += i; 13 | } 14 | swag(); 15 | swag2(); 16 | printf("%d %d %d\n", j, k, l); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /tests_manual/vimplugin/swag.c: -------------------------------------------------------------------------------- 1 | void swag() { 2 | printf("SWAG!\n"); 3 | } 4 | 5 | void swag2() { 6 | printf("SWAG2!\n"); 7 | } 8 | 9 | -------------------------------------------------------------------------------- /tests_manual/vimplugin/swag.h: -------------------------------------------------------------------------------- 1 | void swag(); 2 | void swag2(); 3 | 4 | -------------------------------------------------------------------------------- /tests_manual/vortex/vortex4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/vortex/vortex4 -------------------------------------------------------------------------------- /tests_manual/vortex/vortex4.c: -------------------------------------------------------------------------------- 1 | // -- andrewg, original author was zen-parse :) 2 | #include 3 | 4 | 5 | int main(int argc, char **argv) 6 | { 7 | if(argc) exit(0); 8 | printf(argv[3]); 9 | exit(EXIT_FAILURE); 10 | } 11 | -------------------------------------------------------------------------------- /tests_manual/windows/fibonacci32.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/windows/fibonacci32.exe -------------------------------------------------------------------------------- /tests_manual/windows/fibonacci64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/windows/fibonacci64.exe -------------------------------------------------------------------------------- /tests_manual/windows/fibonacci64/14072703531940: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/windows/fibonacci64/14072703531940 -------------------------------------------------------------------------------- /tests_manual/windows/fibonacci64/14072703531940_base: -------------------------------------------------------------------------------- 1 | 00007FF61D930000-00007FF61D93A000 0 C:\Users\user\Desktop\pin-2.13-65163-msvc11-windows\source\tools\ManualExamples\obj-intel64\fibonacci.exe 2 | 00007FFA63070000-00007FFA6317F000 0 C:\Windows\system32\KERNELBASE.dll 3 | 00007FFA653E0000-00007FFA6551A000 0 C:\Windows\system32\KERNEL32.DLL 4 | 00007FFA65900000-00007FFA65AAA000 0 C:\Windows\SYSTEM32\ntdll.dll 5 | 00007FFA57310000-00007FFA573B7000 0 C:\Windows\SYSTEM32\MSVCP110.dll 6 | 00007FFA52140000-00007FFA52214000 0 C:\Windows\SYSTEM32\MSVCR110.dll 7 | -------------------------------------------------------------------------------- /tests_manual/windows/paris.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/tests_manual/windows/paris.exe -------------------------------------------------------------------------------- /tracers/angr/angr_trace.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import angr 3 | import os 4 | 5 | # import from the qira middleware directory 6 | basedir = os.path.dirname(os.path.realpath(__file__)) + "/../../middleware" 7 | sys.path.append(basedir) 8 | import qira_log 9 | 10 | # run the program in angr, isn't realtime yet 11 | p = angr.Project(sys.argv[1]) 12 | pg = p.factory.path_group(immutable=False) 13 | pg.step(until=lambda lpg: len(lpg.deadended) > 1) 14 | 15 | # extract the trace and the concretize function 16 | pgd = pg.deadended[0] 17 | conc = pgd.state.se.any_int 18 | 19 | # loop and extract the log 20 | log = [] 21 | clnum = 0 22 | for x in pgd.actions: 23 | print x 24 | 25 | # wtf? 26 | try: 27 | if x.addr is None: 28 | continue 29 | except: 30 | continue 31 | 32 | # filter types 33 | if x.type != "mem" and x.type != "reg": 34 | continue 35 | 36 | address = x.addr.ast 37 | if type(address) != int: 38 | # BV has .size() also 39 | address = conc(address) 40 | 41 | if x.type == "reg": 42 | rn = p.arch.register_names[address] 43 | if rn == "eip" and x.action == "write": 44 | print rn, "INSTRUCTION",hex(data) 45 | # new instruction 46 | log.append((data, 0, clnum, qira_log.IS_VALID | qira_log.IS_START)) 47 | clnum += 1 48 | 49 | # this is wrong 50 | data = conc(x.data) & 0xFFFFFFFFFFFFFFFF 51 | 52 | flags = qira_log.IS_VALID 53 | if x.type == "mem": 54 | flags |= qira_log.IS_MEM 55 | if x.action == "write": 56 | flags |= qira_log.IS_WRITE 57 | 58 | le = (address, data, clnum, flags) 59 | print le 60 | 61 | log.append(le) 62 | 63 | # write the qira log 64 | qira_log.write_log(qira_log.LOGDIR + "0", log) 65 | 66 | 67 | #pg.step(until=lambda lpg: len(lpg.active) > 1) 68 | """ 69 | pg.active 70 | pg.step() 71 | pg.active 72 | pg.step() 73 | pg.active 74 | pg.active[0].backtrace 75 | p._sim_procedures 76 | [ hex(x) for x in p._sim_procedures.keys() ] 77 | pg.step() 78 | pg.active 79 | pg.step() 80 | pg.active 81 | """ 82 | 83 | #pg.step(200) 84 | 85 | #[ path.state.posix.dumps(1) for path in pg.deadended ] 86 | #[ path.state.posix.dumps(0) for path in pg.deadended ] 87 | #[ hex(x) for x in p._sim_procedures.keys() ] 88 | #[ (hex(x[0]), x[1]) for x in p._sim_procedures.items() ] 89 | #pg.deadended[0] 90 | 91 | 92 | 93 | """ 94 | pg.deadended[0].actions[0] 95 | pg.deadended[0].actions[0].type 96 | pg.deadended[0].actions[0].addr 97 | pg.deadended[0].actions[0].addr.ast 98 | p.arch.register_names[pg.deadended[0].actions[0].addr.ast] 99 | pg.deadended[0].state.se.any_int(pg.deadended[0].actions[0].data) 100 | pg.deadended[0].state.se.any_int(pg.deadended[0].actions[0].data) 101 | pg.deadended[0].actions[0].action 102 | """ 103 | 104 | # pg.deadended[0].state.se.any_int 105 | 106 | -------------------------------------------------------------------------------- /tracers/pin/.gitignore: -------------------------------------------------------------------------------- 1 | /obj-*/ 2 | /pin-* 3 | /vs_community* 4 | /qira_logs/ 5 | /pin.log 6 | -------------------------------------------------------------------------------- /tracers/pin/makefile: -------------------------------------------------------------------------------- 1 | ############################################################## 2 | # 3 | # THIS IS NOT A NORMAL MAKEFILE 4 | # 5 | ############################################################## 6 | 7 | # This integrates with Pin's makefile stuff. 8 | # Invoke with `make TARGET=???`, where ??? is either ia32 or intel64 9 | # If there isn't a pin-latest folder, PIN_ROOT must also be defined. 10 | 11 | ifndef PIN_ROOT 12 | PIN_ROOT:=$(shell test -d pin-latest && echo pin-latest) 13 | ifeq ($(PIN_ROOT),) 14 | $(error Must define a PIN_ROOT or have a pin-latest folder) 15 | endif 16 | endif 17 | 18 | CONFIG_ROOT := $(PIN_ROOT)/source/tools/Config 19 | include $(CONFIG_ROOT)/makefile.config 20 | include $(TOOLS_ROOT)/Config/makefile.default.rules 21 | 22 | QIRAPINTOOL := $(OBJDIR)qirapin$(PINTOOL_SUFFIX) 23 | ifneq ($(TARGET_OS),windows) 24 | TOOL_CXXFLAGS := $(TOOL_CXXFLAGS) -Wno-error 25 | endif 26 | 27 | $(shell mkdir -p '$(OBJDIR)') 28 | 29 | .PHONY: all clean runls 30 | all: $(QIRAPINTOOL) 31 | 32 | clean: 33 | rm -Rf '$(OBJDIR)' 34 | 35 | ifeq ($(TARGET_OS),mac) 36 | runls: all 37 | cp -f /bin/ls /tmp/ls 38 | codesign -fs- /tmp/ls 39 | $(PIN_ROOT)/pin -t $(QIRAPINTOOL) -- /tmp/ls -l 40 | else 41 | ifeq ($(TARGET_OS),windows) 42 | runls: all 43 | $(PIN_ROOT)/pin -t $(QIRAPINTOOL) -- "`cygpath -w /bin/ls`" -l 44 | else 45 | runls: all 46 | $(PIN_ROOT)/pin -t $(QIRAPINTOOL) -- /bin/ls -l 47 | endif 48 | endif 49 | -------------------------------------------------------------------------------- /tracers/pin/strace/gen_tables.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # modified from https://github.com/nelhage/ministrace by @nelhage 4 | 5 | import os 6 | import sys 7 | import re 8 | import subprocess 9 | 10 | def do_syscall_numbers(unistd_h): 11 | syscalls = {} 12 | for line in open(unistd_h): 13 | m = re.search(r'^#define\s*__NR_(\w+)\s*(\d+)', line) 14 | if m: 15 | (name, number) = m.groups() 16 | number = int(number) 17 | syscalls[number] = name 18 | 19 | return syscalls 20 | 21 | def process_define(syscalls, text): 22 | (name, types) = None, None 23 | if text.startswith('SYSCALL_DEFINE('): 24 | m = re.search(r'^SYSCALL_DEFINE\(([^)]+)\)\(([^)]+)\)$', text) 25 | if not m: 26 | print "Unable to parse:", text 27 | return 28 | name, args = m.groups() 29 | types = [s.strip().rsplit(" ", 1)[0] for s in args.split(",")] 30 | else: 31 | m = re.search(r'SYSCALL_DEFINE(\d)\(([^,]+)\s*(?:,\s*([^)]+))?\)$', text) 32 | if not m: 33 | print "Unable to parse:", text 34 | return 35 | nargs, name, argstr = m.groups() 36 | if argstr is not None: 37 | argspec = [s.strip() for s in argstr.split(",")] 38 | types = argspec[0:len(argspec):2] 39 | else: 40 | types = [] 41 | syscalls[name] = types 42 | 43 | def find_args(linux): 44 | syscalls = {} 45 | find = subprocess.Popen(["find"] + 46 | [os.path.join(linux, d) for d in 47 | "arch/x86 fs include ipc kernel mm net security".split()] + 48 | ["-name", "*.c", "-print"], 49 | stdout = subprocess.PIPE) 50 | for f in find.stdout: 51 | fh = open(f.strip()) 52 | in_syscall = False 53 | text = '' 54 | for line in fh: 55 | line = line.strip() 56 | if not in_syscall and 'SYSCALL_DEFINE' in line: 57 | text = '' 58 | in_syscall = True 59 | if in_syscall: 60 | text += line 61 | if line.endswith(')'): 62 | in_syscall = False 63 | process_define(syscalls, text) 64 | else: 65 | text += " " 66 | return syscalls 67 | 68 | def parse_type(t): 69 | if re.search(r'^(const\s*)?char\s*(__user\s*)?\*\s*$', t): 70 | return "ARG_STR" 71 | if t.endswith('*'): 72 | return "ARG_PTR" 73 | return "ARG_INT" 74 | 75 | def write_output(syscalls_h, types, numbers): 76 | out = open(syscalls_h, 'w') 77 | 78 | print >>out, "const int MAX_SYSCALL_NUM = %d;" % (max(numbers.keys()),) 79 | print >>out, "struct syscall_entry syscalls[] = {" 80 | #for num in sorted(numbers.keys()): 81 | for num in range(max(numbers.keys())): 82 | if num not in numbers: 83 | print >>out, ' { "UNKNOWN_'+str(num)+'", 6, {ARG_UNKNOWN,ARG_UNKNOWN,ARG_UNKNOWN,ARG_UNKNOWN,ARG_UNKNOWN,ARG_UNKNOWN}},' 84 | continue 85 | name = numbers[num] 86 | if name in types: 87 | args = types[name] 88 | else: 89 | args = ["void*"] * 6 90 | 91 | #print >>out, " [%d] = {" % (num,) 92 | print >>out, " { // %d" % (num,) 93 | print >>out, " /*.name =*/ \"%s\"," % (name,) 94 | print >>out, " /*.nargs =*/ %d," % (len(args,)) 95 | out.write( " /*.args =*/ {") 96 | out.write(", ".join([parse_type(t) for t in args] + ["ARG_UNKNOWN"] * (6 - len(args)))) 97 | out.write("}},\n"); 98 | 99 | print >>out, "};" 100 | out.close() 101 | 102 | def main(args): 103 | if not args: 104 | print >>sys.stderr, "Usage: %s /path/to/linux_src" % (sys.argv[0],) 105 | return 1 106 | linux_dir = args[0] 107 | for (name, unistd_h) in [("32", "/usr/include/x86_64-linux-gnu/asm/unistd_32.h"), ("64", "/usr/include/x86_64-linux-gnu/asm/unistd_64.h")]: 108 | syscall_numbers = do_syscall_numbers(unistd_h) 109 | syscall_types = find_args(linux_dir) 110 | write_output('syscallents_'+name+'.h', syscall_types, syscall_numbers) 111 | 112 | if __name__ == '__main__': 113 | sys.exit(main(sys.argv[1:])) 114 | 115 | -------------------------------------------------------------------------------- /tracers/pin/strace/osx_gen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from urllib import urlopen 3 | syscalls_master = urlopen("http://www.opensource.apple.com/source/xnu/xnu-2782.10.72/bsd/kern/syscalls.master?txt").read() 4 | x = (i.strip().split(None, 3) for i in syscalls_master.splitlines() if i.strip() and i[0] not in '#;') 5 | x = ((i[0],i[3][i[3].index('{')+1:i[3].index('}')].strip()) for i in x if len(i) == 4) 6 | x = {int(k):v for k,v in x if v != 'int nosys(void);' and v != 'int enosys(void);'} 7 | 8 | # Yay assumptions 9 | 10 | def name(v): 11 | end = v.index('(') 12 | start = 1+v.rindex(' ', 0, end) 13 | return v[start:end] 14 | 15 | def args(v): 16 | return v[v.index('(')+1:v.index(')')].split(',') 17 | 18 | def typename(arg): 19 | t = max(arg.rfind(' '), arg.rfind('*')) 20 | return arg[:t+1].strip(), arg[t+1:].strip() 21 | 22 | def isstring((typ, nam)): 23 | return typ.startswith('user_addr_t') or typ.endswith('char *') or typ.endswith('void *') 24 | 25 | def showdecimal((typ, nam)): 26 | return 'flag' not in nam and '*' not in typ and 'addr' not in typ and ('int' in typ or 'size' in typ) 27 | 28 | def showtype((typ, nam)): 29 | return 'struct' in typ or '_t *' in typ 30 | 31 | 32 | print '''#ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | #define SYSCALL_MAXARGS 8 37 | enum argtype { 38 | \tARG_INT, 39 | \tARG_PTR, 40 | \tARG_STR, 41 | \tARG_UNKNOWN 42 | }; 43 | 44 | const int MAX_SYSCALL_NUM = '''+str(max(x.iterkeys())+1)+'''; 45 | 46 | struct syscall_entry { 47 | \tconst char *name; 48 | \tint nargs; 49 | \tenum argtype args[SYSCALL_MAXARGS]; 50 | } syscalls[] = { 51 | \t{.name = "syscall", .nargs = 1, .args = { ARG_INT, }},''' 52 | 53 | def argenumconsts(v): 54 | def gen(typnam): 55 | if isstring(typnam): 56 | return 'ARG_STR' 57 | if showdecimal(typnam): 58 | return 'ARG_INT' 59 | return 'ARG_UNKNOWN' 60 | return map(gen, map(typename, args(v))) 61 | 62 | for i in range(1, max(x.iterkeys())+1): 63 | if i in x: 64 | print '\t{.name = "%s", .nargs = %d, .args = { %s}},' % (name(x[i]), len(args(x[i])), ', '.join(argenumconsts(x[i]))+', ') 65 | else: 66 | print '\t{.name = "#'+str(i)+'", .nargs = 6, .args = { '+'ARG_UNKNOWN, '*6+'}},' 67 | 68 | print '''}; 69 | 70 | #ifdef __cplusplus 71 | } 72 | #endif''' 73 | -------------------------------------------------------------------------------- /tracers/pin/strace/syscalls.h: -------------------------------------------------------------------------------- 1 | #define SYSCALL_MAXARGS 6 2 | enum argtype { 3 | ARG_INT, 4 | ARG_PTR, 5 | ARG_STR, 6 | ARG_UNKNOWN 7 | }; 8 | 9 | struct syscall_entry { 10 | const char *name; 11 | int nargs; 12 | enum argtype args[SYSCALL_MAXARGS]; 13 | }; 14 | 15 | -------------------------------------------------------------------------------- /tracers/pin_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -xe 3 | cd "$(dirname "$0")/pin" 4 | 5 | case "`uname`" in 6 | Linux) 7 | if test -d pin-latest; then true; else 8 | curl -L https://software.intel.com/sites/landingpage/pintool/downloads/pin-3.7-97619-g0d0c92f4f-gcc-linux.tar.gz | tar xz 9 | ln -s pin-3.7-97619-g0d0c92f4f-gcc-linux pin-latest 10 | fi 11 | 12 | # pin build deps, good? 13 | if which apt-get; then 14 | echo "apt-getting pin tool building deps" 15 | sudo apt-get -qq -y install g++-7 gcc-7-multilib g++-7-multilib || echo "WARNING: apt-get failed" 16 | else 17 | echo "WARNING: you don't have apt-get, you are required to fetch pin tool building deps (e.g. 32 bit libs) on your own" 18 | fi 19 | 20 | PIN_ROOT=./pin-latest TARGET=intel64 make CXX=g++-7 21 | PIN_ROOT=./pin-latest TARGET=ia32 make CXX=g++-7 22 | ;; 23 | 24 | Darwin) 25 | if test -d pin-latest; then true; else 26 | curl -L https://software.intel.com/sites/landingpage/pintool/downloads/pin-2.14-71313-clang.5.1-mac.tar.gz | tar xz 27 | ln -s pin-2.14-71313-clang.5.1-mac pin-latest 28 | fi 29 | 30 | PIN_ROOT=./pin-latest TARGET=intel64 make 31 | PIN_ROOT=./pin-latest TARGET=ia32 make 32 | ;; 33 | 34 | CYGWIN*) 35 | REQUTILS="curl unzip rm ln bash realpath make" 36 | which $REQUTILS > /dev/null || { echo You must first use Cygwin to install $REQUTILS; exit 1; } 37 | if test -d pin-latest; then true; else 38 | curl -LO https://software.intel.com/sites/landingpage/pintool/downloads/pin-2.14-71313-msvc12-windows.zip 39 | unzip -q pin-2.14-71313-msvc12-windows.zip 40 | rm pin-2.14-71313-msvc12-windows.zip 41 | ln -s pin-2.14-71313-msvc12-windows pin-latest 42 | fi 43 | 44 | rm -f ./vs_community_2013.exe 45 | if test -d 'C:\Program Files (x86)\Microsoft Visual Studio 12.0'; then 46 | export VC='C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC' 47 | export PIN_ROOT="$(cygpath -w "$(realpath ./pin-latest)")" 48 | ( { echo '"%VC%\bin\vcvars32.bat"'; echo 'make TARGET=ia32'; } | cmd ) 49 | ( { echo '"%VC%\bin\amd64\vcvars64.bat"'; echo 'make TARGET=intel64'; } | cmd ) 50 | else 51 | echo "You need vc12 to compile this PIN (newer versions probably won't work)." 52 | curl -L 'http://go.microsoft.com/fwlink/?LinkId=517284' > vs_community_2013.exe 53 | echo "Use the GUI to install Visual Studio and reboot. Run $0 again afterwards." 54 | if test -z "$SSH_CLIENT"; then 55 | ./vs_community_2013.exe 56 | else 57 | echo "Invoke ./vs_community_2013.exe from the GUI (sshd usually can't launch gui apps)." 58 | fi 59 | exit 0 60 | fi 61 | ;; 62 | esac 63 | -------------------------------------------------------------------------------- /tracers/qemu/.gitignore: -------------------------------------------------------------------------------- 1 | qemu 2 | -------------------------------------------------------------------------------- /tracers/qemu/qira-aarch64: -------------------------------------------------------------------------------- 1 | qemu/aarch64-linux-user/qemu-aarch64 -------------------------------------------------------------------------------- /tracers/qemu/qira-arm: -------------------------------------------------------------------------------- 1 | qemu/arm-linux-user/qemu-arm -------------------------------------------------------------------------------- /tracers/qemu/qira-i386: -------------------------------------------------------------------------------- 1 | qemu/i386-linux-user/qemu-i386 -------------------------------------------------------------------------------- /tracers/qemu/qira-mips: -------------------------------------------------------------------------------- 1 | qemu/mips-linux-user/qemu-mips -------------------------------------------------------------------------------- /tracers/qemu/qira-mipsel: -------------------------------------------------------------------------------- 1 | qemu/mipsel-linux-user/qemu-mipsel -------------------------------------------------------------------------------- /tracers/qemu/qira-ppc: -------------------------------------------------------------------------------- 1 | qemu/ppc-linux-user/qemu-ppc -------------------------------------------------------------------------------- /tracers/qemu/qira-x86_64: -------------------------------------------------------------------------------- 1 | qemu/x86_64-linux-user/qemu-x86_64 -------------------------------------------------------------------------------- /tracers/qemu_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | if [ ! -d qemu/qemu ]; then 4 | cd qemu 5 | git clone https://github.com/geohot/qemu.git --depth 1 --branch qira 6 | cd .. 7 | fi 8 | 9 | cd qemu/qemu 10 | ./configure --target-list=i386-linux-user,x86_64-linux-user,arm-linux-user,ppc-linux-user,aarch64-linux-user,mips-linux-user,mipsel-linux-user --enable-tcg-interpreter --enable-debug-tcg --cpu=unknown --python=python 11 | make -j$(getconf _NPROCESSORS_ONLN) 12 | -------------------------------------------------------------------------------- /web/client/compatibility/bignum.js: -------------------------------------------------------------------------------- 1 | function fhex(a) { 2 | throw ("DANGER, fhex is a bad function"); 3 | return parseInt(a, 16); 4 | } 5 | 6 | function fnum(a) { 7 | return parseInt(a, 10); 8 | } 9 | 10 | function hex2(a) { 11 | if (a == undefined) return "__"; 12 | var ret = a.toString(16); 13 | if (ret.length == 1) return "0" + ret; 14 | return ret; 15 | } 16 | 17 | function _fhex(a) { 18 | //p("DANGER, fhex is a bad function"); 19 | return parseInt(a, 16); 20 | } 21 | 22 | // this is safe to use on forknums and clnums 23 | function fdec(a) { 24 | return parseInt(a, 10); 25 | } 26 | 27 | function hex(a) { 28 | if (a == undefined) { 29 | return ""; 30 | } else { 31 | if (a < 0) a += 0x100000000; 32 | return "0x"+a.toString(16); 33 | } 34 | } 35 | 36 | 37 | // s is a hex number 38 | // num is the number of digits to round off 39 | function bn_round(s, num) { 40 | if ((s.length-2) <= num) { 41 | ret = "0x0"; 42 | } else { 43 | var ret = s.substring(0, s.length-num); 44 | for (var i = 0; i < num; i++) { 45 | ret += "0"; 46 | } 47 | } 48 | return ret; 49 | } 50 | 51 | function bn_mod(s, cnt) { 52 | s = s.substr(2); 53 | return _fhex("0x"+s.substr(Math.max(0, s.length-cnt))); 54 | } 55 | 56 | // who the hell knows if this works? 57 | function bn_add(s, num) { 58 | s = s.substr(2); 59 | if (s.length <= 8) { return hex(_fhex(s)+num); } 60 | else { 61 | var ts = _fhex("0x"+s.substr(0,s.length-8)); 62 | var ls = _fhex("0x"+s.substr(s.length-8)); 63 | ls += num; 64 | if (ls < 0) { ts -= 1; } // borrow 65 | ts += (ls/0x100000000) >> 0; 66 | ls &= 0xFFFFFFFF; 67 | ret = hex(ls).substr(2); 68 | while (ret.length != 8) ret = "0" + ret; 69 | return hex(ts)+ret; 70 | } 71 | } 72 | 73 | function bn_cmp(a, b) { 74 | if (a.length != b.length) return a.length-b.length; 75 | var aa = _fhex(a.substring(0,8)); 76 | var bb = _fhex(b.substring(0,8)); 77 | if (aa != bb) return aa-bb; 78 | aa = _fhex("0x"+a.substring(8)); 79 | bb = _fhex("0x"+b.substring(8)); 80 | return aa-bb; 81 | } 82 | 83 | // should also make lowercase 84 | function bn_canonicalize(s) { 85 | s = s.substr(2); 86 | while (s.substr(0,1) == '0') s = s.substr(1); 87 | return "0x"+s; 88 | } 89 | 90 | -------------------------------------------------------------------------------- /web/client/compatibility/early.js: -------------------------------------------------------------------------------- 1 | function p(a) { console.log(a); } 2 | //function DA(a) { p("DA: "+a); } 3 | //function DS(a) { p("DS: "+a); } 4 | //function DH(a) { p("DH: "+a); } 5 | function DA(a) {} 6 | function DS(a) {} 7 | function DH(a) {} 8 | 9 | STREAM_URL = window.location.origin+"/qira"; 10 | 11 | -------------------------------------------------------------------------------- /web/client/compatibility/fakemeteor.js: -------------------------------------------------------------------------------- 1 | Deps = { 2 | _deps: {}, 3 | autorun: function(fxn) { 4 | Session._track = []; 5 | fxn(); 6 | var tracked = Session._track; 7 | Session._track = undefined; 8 | for (var i=0;i label > input, 54 | .context-menu-item > label > textarea { 55 | -webkit-user-select: text; 56 | -moz-user-select: text; 57 | -ms-user-select: text; 58 | user-select: text; 59 | } 60 | 61 | .context-menu-item.hover { 62 | cursor: pointer; 63 | background-color: #39F; 64 | } 65 | 66 | .context-menu-item.disabled { 67 | color: #666; 68 | } 69 | 70 | .context-menu-input.hover, 71 | .context-menu-item.disabled.hover { 72 | cursor: default; 73 | background-color: #EEE; 74 | } 75 | 76 | .context-menu-submenu:after { 77 | content: ">"; 78 | color: #666; 79 | position: absolute; 80 | top: 0; 81 | right: 3px; 82 | z-index: 1; 83 | } 84 | 85 | /* icons 86 | #protip: 87 | In case you want to use sprites for icons (which I would suggest you do) have a look at 88 | http://css-tricks.com/13224-pseudo-spriting/ to get an idea of how to implement 89 | .context-menu-item.icon:before {} 90 | */ 91 | .context-menu-item.icon { min-height: 18px; background-repeat: no-repeat; background-position: 4px 2px; } 92 | .context-menu-item.icon-edit { background-image: url(images/page_white_edit.png); } 93 | .context-menu-item.icon-cut { background-image: url(images/cut.png); } 94 | .context-menu-item.icon-copy { background-image: url(images/page_white_copy.png); } 95 | .context-menu-item.icon-paste { background-image: url(images/page_white_paste.png); } 96 | .context-menu-item.icon-delete { background-image: url(images/page_white_delete.png); } 97 | .context-menu-item.icon-add { background-image: url(images/page_white_add.png); } 98 | .context-menu-item.icon-quit { background-image: url(images/door.png); } 99 | 100 | /* vertically align inside labels */ 101 | .context-menu-input > label > * { vertical-align: top; } 102 | 103 | /* position checkboxes and radios as icons */ 104 | .context-menu-input > label > input[type="checkbox"], 105 | .context-menu-input > label > input[type="radio"] { 106 | margin-left: -17px; 107 | } 108 | .context-menu-input > label > span { 109 | margin-left: 5px; 110 | } 111 | 112 | .context-menu-input > label, 113 | .context-menu-input > label > input[type="text"], 114 | .context-menu-input > label > textarea, 115 | .context-menu-input > label > select { 116 | display: block; 117 | width: 100%; 118 | 119 | -webkit-box-sizing: border-box; 120 | -moz-box-sizing: border-box; 121 | -ms-box-sizing: border-box; 122 | -o-box-sizing: border-box; 123 | box-sizing: border-box; 124 | } 125 | 126 | .context-menu-input > label > textarea { 127 | height: 100px; 128 | } 129 | .context-menu-item > .context-menu-list { 130 | display: none; 131 | /* re-positioned by js */ 132 | right: -5px; 133 | top: 5px; 134 | } 135 | 136 | .context-menu-item.hover > .context-menu-list { 137 | display: block; 138 | } 139 | 140 | .context-menu-accesskey { 141 | text-decoration: underline; 142 | } 143 | -------------------------------------------------------------------------------- /web/client/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/web/client/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /web/client/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/web/client/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /web/client/haddrline.js: -------------------------------------------------------------------------------- 1 | var PAGE_SIZE = 0x1000; 2 | 3 | Deps.autorun(function() { DA("pmaps changed, updating haddrline"); 4 | var pmaps = Session.get('pmaps'); 5 | if (pmaps === undefined) return; 6 | //p(pmaps); 7 | // eww, numbers. broken for 64-bit 8 | var addrs = []; 9 | for (k in pmaps) { 10 | // ignore the memory that's only read from 11 | if (pmaps[k] == "romemory") continue; 12 | addrs.push(k); 13 | } 14 | addrs = addrs.sort(bn_cmp); 15 | //p(addrs); 16 | 17 | // fill in the holes up to 16 pages 18 | var pchunks = []; 19 | for (var i = 0; i < addrs.length;) { 20 | var pchunk = []; 21 | var caddr = addrs[i]; 22 | 23 | // push the first one 24 | pchunk.push(caddr); 25 | i++; 26 | // addrs[i] is the next addr 27 | while (i < addrs.length && bn_cmp(bn_add(caddr, PAGE_SIZE*8), addrs[i]) > 0) { 28 | // fill in holes 29 | for (var j = bn_add(caddr, PAGE_SIZE); bn_cmp(j, addrs[i]) < 0; j = bn_add(j, PAGE_SIZE)) { 30 | pchunk.push(j); 31 | } 32 | caddr = addrs[i]; 33 | // push non holes 34 | pchunk.push(caddr); 35 | i++; 36 | } 37 | pchunks.push(pchunk); 38 | } 39 | 40 | //p(pchunks); 41 | $('#haddrline').empty(); 42 | for (var i = 0; i < pchunks.length; i++) { 43 | var pcs = $('
') 44 | for (var j = 0; j < pchunks[i].length; j++) { 45 | var addr = pchunks[i][j]; 46 | pcs.append($('
')); 47 | } 48 | $('#haddrline').append(pcs); 49 | } 50 | }); 51 | 52 | draw_hflag = function(addr, name, color, alwaysontop) { 53 | $("#hflag_"+name).remove(); 54 | var t = $("#pchunk_"+bn_round(addr, 3)); 55 | if (t.length == 1) { 56 | //p("drawing hflag"); 57 | var hflag = $('
'); 58 | if (alwaysontop) { 59 | hflag.css("z-index", 2); 60 | hflag.css("opacity", "0.8"); 61 | } else { 62 | hflag.css("opacity", "0.4"); 63 | } 64 | hflag.css("background-color", color); 65 | // pchunk.width = 15 66 | // hflag.width = 1 67 | var off = (((bn_mod(addr, 3)*1.0)/PAGE_SIZE) * 15) - (1/2.0); 68 | hflag.css("left", off+"px"); 69 | t.append(hflag); 70 | } 71 | }; 72 | 73 | Deps.autorun(function() { DA("draw haddrline iaddr flag"); 74 | var addr = Session.get('iaddr'); 75 | if (addr === undefined) return; 76 | draw_hflag(addr, 'iaddr', '#AA0000', true); 77 | }); 78 | 79 | Deps.autorun(function() { DA("draw haddrline daddr flag"); 80 | var addr = Session.get('daddr'); 81 | if (addr === undefined) return; 82 | draw_hflag(addr, 'daddr', 'yellow', true); 83 | }); 84 | 85 | $(document).ready(function() { 86 | var ee = $("#haddrline")[0]; 87 | ee.addEventListener("mousewheel", function(e) { 88 | ee.scrollLeft += e.wheelDelta; 89 | }); 90 | function get_addr(e) { 91 | var tt = [$(e.target), $(e.target).parent()]; 92 | for (i in tt) { 93 | var t = tt[i]; 94 | if (t.hasClass("pchunk")) { 95 | var addr = t.attr('id').split("_")[1]; 96 | var relX = ((e.pageX - t.offset().left)*1.0)/(t.width()); 97 | var addr_offset = Math.floor(relX*PAGE_SIZE); 98 | return bn_add(addr, addr_offset); 99 | } 100 | } 101 | return undefined; 102 | } 103 | 104 | ee.addEventListener("click", function(e) { 105 | var addr = get_addr(e); 106 | if (addr !== undefined) { 107 | update_dview(addr); 108 | } 109 | return false; 110 | }); 111 | ee.addEventListener("contextmenu", function(e) { 112 | var addr = get_addr(e); 113 | if (addr !== undefined) { 114 | Session.set("dirtyiaddr", true); 115 | Session.set('iaddr', addr); 116 | } 117 | e.preventDefault(); 118 | return false; 119 | }); 120 | }); 121 | 122 | 123 | -------------------------------------------------------------------------------- /web/client/ida.js: -------------------------------------------------------------------------------- 1 | var ws = undefined; 2 | 3 | function do_ida_socket(callme) { 4 | if (ws == undefined || ws.readyState == WebSocket.CLOSED) { 5 | ws = new WebSocket('ws://localhost:3003', 'qira'); 6 | ws.onerror = function(e) { 7 | // TODO: why doesn't this catch the "net::ERR_CONNECTION_REFUSED"? 8 | // hmm, it looks like it does, but error is still printed to console 9 | }; 10 | ws.onopen = function() { 11 | p('connected to IDA socket'); 12 | callme(); 13 | }; 14 | ws.onmessage = function(msg) { 15 | var dat = msg.data.split(" "); 16 | if (dat[0] == "setiaddr") { 17 | Session.set("iaddr", dat[1]); 18 | Session.set("dirtyiaddr", true); 19 | } 20 | else if (dat[0] == "setdaddr") { 21 | if (get_data_type(dat[1]) != "datainstruction") { 22 | update_dview(dat[1]); 23 | } 24 | } 25 | else if (dat[0] == "setname") { 26 | var send = {} 27 | var address = dat[1]; 28 | var name = dat[2]; 29 | send[address] = {"name": name}; 30 | stream.emit("settags", send); 31 | } 32 | else if (dat[0] == "setcmt") { 33 | var send = {} 34 | var address = dat[1]; 35 | var comment = dat.slice(2).join(" "); 36 | send[address] = {"comment": comment}; 37 | stream.emit("settags", send); 38 | } 39 | }; 40 | } else { 41 | callme(); 42 | } 43 | } 44 | 45 | function send_cmd(cmd) { 46 | do_ida_socket(function() { 47 | try { 48 | ws.send(cmd); 49 | } catch(err) { 50 | // nothing 51 | } 52 | }); 53 | } 54 | 55 | Deps.autorun(function() { DA("send setaddress to ida"); 56 | var iaddr = Session.get('iaddr'); 57 | send_cmd('setaddress '+iaddr); 58 | }); 59 | 60 | Deps.autorun(function() { DA("send user names and comments to ida"); 61 | var addr = Session.get("ida_sync_addr"); 62 | var tagname = Session.get("ida_sync_tagname"); 63 | var dat = Session.get("ida_sync_dat"); 64 | 65 | if (addr == undefined || tagname == undefined || dat == undefined) return; 66 | 67 | if (tagname == "name") 68 | send_cmd('setname ' + addr + " " + dat); 69 | else if (tagname == "comment") 70 | send_cmd('setcmt ' + addr + " " + dat); 71 | else { 72 | p("Unknown tag type from IDA plugin: " + tagname) 73 | } 74 | }); 75 | 76 | Deps.autorun(function() { DA("send trail to ida"); 77 | var trail = Session.get("trail"); 78 | if (trail !== undefined) { 79 | var s = "settrail "; 80 | for (var i = 0; i < trail.length; i++) { 81 | var cldiff = trail[i][0]; 82 | var addr = trail[i][1]; 83 | if (-15 < cldiff && cldiff <= 0) { 84 | s += cldiff + "," + addr + ";"; 85 | } 86 | } 87 | p(s); 88 | send_cmd(s); 89 | } 90 | }); 91 | -------------------------------------------------------------------------------- /web/client/idump.js: -------------------------------------------------------------------------------- 1 | stream = io.connect(STREAM_URL); 2 | 3 | // TODO: parameter should be dynamic? 4 | var backward_context_size = 6; 5 | 6 | // arch is public data 7 | arch = undefined; 8 | function on_arch(msg) { DS("arch"); 9 | //p(msg); 10 | arch = msg; 11 | } stream.on("arch", on_arch); 12 | 13 | function on_instructions(msg) { DS("instructions"); 14 | var clnum = Session.get("clnum"); 15 | var idump = ""; 16 | var addrs = []; 17 | for (var i = 0; i= 10 || ins.clnum >= (clnum - backward_context_size)) { 35 | idump += 36 | '
'+ 37 | '
'+ins.clnum+'
'+ 38 | ''+ins.address+' '+ 39 | '
'+highlight_instruction(ins.instruction)+'
'+ 40 | ''+(ins.comment !== undefined && ins.comment !== "" ? "; "+ins.comment : "")+''+ 41 | '
'; 42 | } 43 | } 44 | Session.set('trail', addrs); 45 | $('#idump').html(idump); 46 | rehighlight(); 47 | replace_names(); 48 | } stream.on('instructions', on_instructions); 49 | 50 | Deps.autorun(function() { DA("emit getinstructions"); 51 | var forknum = Session.get("forknum"); 52 | var clnum = Session.get("clnum"); 53 | var maxclnum = Session.get("max_clnum"); 54 | if (maxclnum === undefined) return; 55 | maxclnum = maxclnum[forknum]; 56 | 57 | // correct place for this clamp? 58 | if (clnum > (maxclnum[1]+1)) { clnum = (maxclnum[1]+1); Session.set("clnum", clnum); } 59 | if (clnum < maxclnum[0]) { clnum = maxclnum[0]; Session.set("clnum", clnum); } 60 | 61 | // TODO: make this clean 62 | var size = get_size("#idump"); 63 | var end = Math.min(maxclnum[1]+1, clnum+size-backward_context_size); 64 | var start = Math.max(maxclnum[0], end-size); 65 | if (maxclnum[0] > (end-size)) end += maxclnum[0] - (end-size) + 1; 66 | 67 | stream.emit('getinstructions', forknum, clnum, start-10, end); 68 | }); 69 | 70 | -------------------------------------------------------------------------------- /web/client/static/static.js: -------------------------------------------------------------------------------- 1 | // static stuff 2 | 3 | stream = io.connect(STREAM_URL); 4 | 5 | Deps.autorun(function() { DA("update static view"); 6 | var iview = Session.get('iview'); 7 | var flat = Session.get('flat'); 8 | if (iview === undefined) return; 9 | 10 | var size = get_size("#cfg-static"); 11 | stream.emit('getstaticview', iview, flat, [-5,size-5]); 12 | }); 13 | 14 | function draw_tags(addr, x) { 15 | var ret = "" 16 | var keys = []; 17 | for (var key in x) { keys[keys.length] = key; } 18 | keys = keys.sort(); 19 | for (var i = 0; i < keys.length; i++) { 20 | key = keys[i]; 21 | if (x[key] !== null) { 22 | ret += "" 23 | ret += "" 24 | if (key == "address") { 25 | ret += "" 26 | } else { 27 | ret += "" 28 | } 29 | ret += "" 30 | } 31 | } 32 | ret += "
"+key+""+x[key]+""+x[key]+"
" 33 | return ret; 34 | } 35 | 36 | Deps.autorun(function() { DA("update itags view"); 37 | var addr = Session.get('iaddr'); 38 | async_tags_request([addr], function(x) { 39 | $("#itags-static").html(draw_tags(addr, x[0])); 40 | }, 'gettagss') 41 | }); 42 | 43 | Deps.autorun(function() { DA("update dtags view"); 44 | var addr = Session.get('daddr'); 45 | async_tags_request([addr], function(x) { 46 | $("#dtags-static").html(draw_tags(addr, x[0])); 47 | }, 'gettagss') 48 | }); 49 | 50 | // TODO: this code is replicated in idump.js 51 | function instruction_html_from_tags(ins) { 52 | var idump = '
'; 53 | idump += ''+ins.address+' '; 54 | if (ins.instruction !== undefined) { 55 | idump += '
'+highlight_instruction(ins.instruction)+'
'; 56 | } else { 57 | if (ins.type == "string") { 58 | idump += '
'; 59 | idump += "'"; 60 | // TODO: escaping? 61 | ins.bytes.forEach(function(x) { 62 | idump += String.fromCharCode(x); 63 | }); 64 | idump += "'"; 65 | idump += '
'; 66 | } else { 67 | if (ins.type == "data") { 68 | idump += '
'; 69 | } else { 70 | idump += '
'; 71 | } 72 | ins.bytes.forEach(function(x) { 73 | idump += hex2(x)+" "; 74 | }); 75 | idump += '
'; 76 | } 77 | } 78 | 79 | idump += ''+(ins.comment != undefined ? "; "+ins.comment : "")+''; 80 | idump += '
'; 81 | return idump; 82 | } 83 | 84 | function display_flat(addrs) { 85 | //p(addrs); 86 | var idump = '
'; 87 | for (var i=0;i'); 115 | 116 | dom.html(idump); 117 | graph.addVertex(addr, cnt, dom[0]); 118 | 119 | // add edges 120 | for (var i = 0; i < bb[cnt-1].dests.length; i++) { 121 | var dd = bb[cnt-1].dests[i]; 122 | if (dd[1] == 3) continue; 123 | 124 | var col = "blue"; // base off dd[1] 125 | if (bb[cnt-1].dests.length > 1 && dd[1] == 4) { 126 | col = "red"; 127 | } else if (dd[1] == 1) { 128 | col = "green"; 129 | } 130 | graph.addEdge(addr, dd[0], col); 131 | } 132 | 133 | } 134 | 135 | graph.assignLevels(); 136 | graph.render(); 137 | 138 | rehighlight(); 139 | replace_names(); 140 | } stream.on('function', on_function); 141 | 142 | -------------------------------------------------------------------------------- /web/client/strace.js: -------------------------------------------------------------------------------- 1 | stream = io.connect(STREAM_URL); 2 | Session.setDefault('sview', [0,10]); 3 | 4 | traces = {} 5 | 6 | function on_strace(msg) { DS("strace"); 7 | traces[msg['forknum']] = msg['dat'] 8 | redraw_strace(); 9 | } stream.on('strace', on_strace); 10 | 11 | function redraw_strace() { 12 | var forknum = Session.get("forknum"); 13 | var sview = Session.get('sview'); 14 | if (traces[forknum] === undefined) return; 15 | var msg = traces[forknum].slice(sview[0], sview[1]) 16 | 17 | var strace = ""; 18 | for (i in msg) { 19 | var st = msg[i]; 20 | strace += '
'+ 21 | '
'+st.clnum+'
'+ 22 | highlight_addresses(st.sc)+ 23 | '
'; 24 | } 25 | $('#strace').html(strace); 26 | rehighlight(); 27 | } 28 | 29 | Deps.autorun(function() { DA("redrawing strace"); 30 | redraw_strace(); 31 | }); 32 | 33 | Deps.autorun(function() { DA("updating sview on fork/cl change"); 34 | var forknum = Session.get("forknum"); 35 | var clnum = Session.get("clnum"); 36 | if (traces[forknum] === undefined) return; 37 | var t = traces[forknum]; 38 | var i; 39 | // ugh, slow...binary search here 40 | for (i = 0; i < t.length; i++) { 41 | if (t[i]['clnum'] > clnum) break; 42 | } 43 | //p(i); 44 | var size = get_size("#strace"); 45 | 46 | var min = Math.max(0, i-3); 47 | var max = min+size; 48 | // ugh 49 | if (max > t.length) { 50 | var off = max-t.length; 51 | max -= off; min -= off; 52 | if (min < 0) { 53 | max -= min; 54 | min = 0; 55 | } 56 | } 57 | Session.set('sview', [min, max]); 58 | }); 59 | 60 | $(document).ready(function() { 61 | $("#strace")[0].addEventListener("wheel", function(e) { 62 | var sv = Session.get('sview'); 63 | var forknum = Session.get("forknum"); 64 | if (traces[forknum] === undefined) return; 65 | var t = traces[forknum]; 66 | if (e.deltaY > 0) { 67 | if (sv[1] < t.length) { 68 | Session.set('sview', [sv[0]+1, sv[1]+1]); 69 | } 70 | } else if (e.deltaY < 0) { 71 | if (sv[0] > 0) { 72 | Session.set('sview', [sv[0]-1, sv[1]-1]); 73 | } 74 | } 75 | }); 76 | }); 77 | 78 | 79 | -------------------------------------------------------------------------------- /web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geohot/qira/5f34406410aa492bc491fe0e579dbe103390a432/web/favicon.ico -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | qira 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 47 | 48 | 51 | 52 | 58 | 59 | 62 | 63 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /web/qira_layout.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | margin: 0; 4 | overflow: hidden; 5 | padding: 0; 6 | width: 100%; 7 | } 8 | 9 | 10 | /* universal things */ 11 | input { 12 | font-family: monospace; 13 | } 14 | 15 | td { 16 | font-family: monospace; 17 | } 18 | 19 | .dynamic-info { 20 | width: 100%; 21 | background-color: #AAAAAA; 22 | } 23 | 24 | .splitter { 25 | position: absolute; 26 | top: 0px; 27 | left: 0px; 28 | right: 0px; 29 | bottom: 0px; 30 | overflow: hidden; 31 | } 32 | 33 | .fill { 34 | overflow-y: hidden; 35 | } 36 | 37 | /* controls */ 38 | 39 | #controls { 40 | padding-top: 4px; 41 | padding-bottom: 4px; 42 | } 43 | 44 | .control { 45 | font-family: monospace; 46 | font-size: 12pt; 47 | /*width: 165px;*/ 48 | border: 1px solid black; 49 | /*padding: 2px; 50 | margin: 3px;*/ 51 | background-color: #ddd; 52 | } 53 | 54 | #control_fork { 55 | /*margin-left: 0px; 56 | width: 50px;*/ 57 | } 58 | 59 | #control_changeeditor { 60 | /*margin-left: 0px; 61 | width: 30px; 62 | margin-right: 0px;*/ 63 | } 64 | 65 | #control_analysis { 66 | /*margin-left: 0px; 67 | width: auto; 68 | padding-left: 5px; 69 | padding-right: 5px;*/ 70 | } 71 | 72 | /* everything in the right panel */ 73 | 74 | #onlypanel { 75 | width: 620px; 76 | height: 100%; 77 | /*border: 1px solid black;*/ 78 | border-left: 1px solid black; 79 | border-right: 1px solid black; 80 | padding: 4px; 81 | box-sizing: border-box; 82 | z-index: 1; 83 | position: relative; 84 | } 85 | 86 | .panelthing { 87 | border: 1px solid gray; 88 | background-color: #DDDDDD; 89 | } 90 | 91 | /* instruction dump */ 92 | 93 | #static { 94 | padding: 5px; 95 | overflow-x: auto; 96 | } 97 | 98 | #idump { 99 | padding: 5px; 100 | overflow-y: hidden; 101 | overflow-x: auto; 102 | } 103 | 104 | 105 | .container { 106 | background-color: #AAAAAA; 107 | } 108 | 109 | .container:after { 110 | content: ""; 111 | display: table; 112 | clear: both; 113 | } 114 | 115 | .col { 116 | float: left; 117 | background-color: #AAAAAA; 118 | } 119 | 120 | #vtimelinebox { 121 | padding-top: 4px; 122 | height: 100%; 123 | width: 100%; 124 | /*background-color: #AAAAAA;*/ 125 | overflow-x: auto; 126 | overflow-y: hidden; 127 | white-space: nowrap; 128 | box-sizing: border-box; 129 | z-index: 1; 130 | position: absolute; 131 | top: 0; 132 | } 133 | 134 | .tags { 135 | border: 1px solid grey; 136 | width: 49.8%; 137 | display: inline-block; 138 | height: 100%; 139 | min-height: 18px; 140 | position: absolute; 141 | top: 0; 142 | background-color: #BBBBBB; 143 | } 144 | 145 | #itags-static { 146 | border-color: #cc0000; 147 | } 148 | 149 | #dtags-static { 150 | border-color: #888800; 151 | left: 50%; 152 | } 153 | 154 | 155 | -------------------------------------------------------------------------------- /web/qira_new.css: -------------------------------------------------------------------------------- 1 | .name { 2 | /*color: purple !important;*/ 3 | /*background-color: #cccccc;*/ 4 | } 5 | 6 | .autohighlight { 7 | background-color: #FF7777 !important; 8 | } 9 | 10 | .autohighlighti { 11 | background-color: #FFAA77; 12 | } 13 | 14 | .insaddr { 15 | min-width: 7em; 16 | display: inline-block; 17 | } 18 | 19 | .comment { 20 | color: blue; 21 | } 22 | 23 | .flat { 24 | border: 1px solid gray; 25 | background-color: #CCCCCC; 26 | padding: 10px; 27 | } 28 | 29 | #outergbox { 30 | position: absolute; 31 | height: 100%; 32 | width: 100%; 33 | } 34 | 35 | --------------------------------------------------------------------------------