├── .gitattributes ├── .gitignore ├── .travis.yml ├── COPYRIGHT ├── Elf ├── __init__.py └── elf_lookup.py ├── LICENSE.txt ├── PE ├── __init__.py ├── carve.py ├── cofflib.py ├── ordlookup │ ├── __init__.py │ ├── comctl32.py │ ├── mfc42.py │ ├── msvbvm60.py │ ├── oleaut32.py │ ├── oledlg.py │ ├── printord.py │ └── ws2_32.py ├── petool.py └── tests │ ├── __init__.py │ └── test_version.py ├── README.md ├── cobra ├── __init__.py ├── auth │ ├── __init__.py │ └── shadowfile.py ├── cache.py ├── cluster.py ├── dcode.py ├── devent.py ├── dispatcher.py ├── hostid │ ├── __init__.py │ ├── darwinhostid.py │ └── windowshostid.py ├── http.py ├── pool.py ├── py3compat.py ├── remoteapp.py ├── tests │ ├── __init__.py │ ├── shadowpass.txt │ ├── testbasic.py │ ├── testcache.py │ ├── testevents.py │ └── testnewobj.py └── tools │ ├── __init__.py │ ├── burnapp.py │ ├── queend.py │ ├── runtests.py │ └── workerd.py ├── envi ├── __init__.py ├── archs │ ├── __init__.py │ ├── amd64 │ │ ├── __init__.py │ │ ├── disasm.py │ │ ├── opcode64.py │ │ ├── regs.py │ │ └── vmcslookup.py │ ├── arm │ │ ├── __init__.py │ │ ├── const.py │ │ ├── disasm.py │ │ ├── emu.py │ │ └── regs.py │ ├── h8 │ │ ├── __init__.py │ │ ├── const.py │ │ ├── disasm.py │ │ ├── emu.py │ │ ├── optables.py │ │ ├── parsers.py │ │ └── regs.py │ ├── i386 │ │ ├── __init__.py │ │ ├── disasm.py │ │ ├── emu.py │ │ ├── opcode86.py │ │ ├── opconst.py │ │ └── regs.py │ ├── msp430 │ │ ├── __init__.py │ │ ├── const.py │ │ ├── disasm.py │ │ ├── emu.py │ │ └── regs.py │ ├── thumb16 │ │ ├── __init__.py │ │ └── disasm.py │ └── z80 │ │ ├── __init__.py │ │ ├── const.py │ │ ├── disasm.py │ │ ├── regs.py │ │ └── z80opcode.py ├── bintree.py ├── bits.py ├── bytesig.py ├── cli.py ├── codeflow.py ├── config.py ├── const.py ├── encoding.py ├── expression.py ├── memcanvas │ ├── __init__.py │ └── renderers │ │ └── __init__.py ├── memory.py ├── pagelookup.py ├── pyzip.py ├── qt │ ├── __init__.py │ ├── config.py │ ├── html.py │ ├── jquery.py │ ├── memcanvas.py │ ├── memdump.py │ ├── memory.py │ ├── memorymap.py │ ├── memsearch.py │ └── memwrite.py ├── radixtree.py ├── registers.py ├── resolver.py ├── symstore │ ├── __init__.py │ ├── resolver.py │ └── symcache.py ├── tests │ ├── __init__.py │ ├── msp430 │ │ ├── __init__.py │ │ ├── iadc.py │ │ ├── iadd.py │ │ ├── iaddc.py │ │ ├── iand.py │ │ ├── ibic.py │ │ ├── ibis.py │ │ ├── ibit.py │ │ ├── ibr.py │ │ ├── icall.py │ │ ├── iclr.py │ │ ├── iclrc.py │ │ ├── iclrn.py │ │ ├── iclrz.py │ │ ├── icmp.py │ │ ├── idadc.py │ │ ├── idadd.py │ │ ├── idec.py │ │ ├── idecd.py │ │ ├── iinc.py │ │ ├── iincd.py │ │ ├── iinv.py │ │ ├── ijumps.py │ │ ├── imov.py │ │ ├── inop.py │ │ ├── ipop.py │ │ ├── ipush.py │ │ ├── iret.py │ │ ├── irla.py │ │ ├── irlc.py │ │ ├── irra.py │ │ ├── irrc.py │ │ ├── isbc.py │ │ ├── isetc.py │ │ ├── isetn.py │ │ ├── isetz.py │ │ ├── isub.py │ │ ├── isubc.py │ │ ├── iswpb.py │ │ ├── isxt.py │ │ ├── itst.py │ │ └── ixor.py │ ├── test_arch_amd64.py │ ├── test_arch_arm.py │ ├── test_arch_h8.py │ ├── test_arch_i386.py │ ├── test_arch_msp430.py │ ├── test_bits.py │ ├── test_emu_lockstep.py │ ├── test_memory.py │ └── test_symstore.py ├── tests_memory.py └── threads.py ├── requirements.txt ├── setup.py ├── vdb ├── __init__.py ├── ext │ ├── __init__.py │ └── execsc.py ├── extensions │ ├── __init__.py │ ├── amd64.py │ ├── arm.py │ ├── darwin.py │ ├── gdbstub.py │ ├── i386.py │ ├── i486.py │ ├── i586.py │ ├── i686.py │ ├── windows.py │ └── winkern.py ├── qt │ ├── __init__.py │ ├── base.py │ ├── main.py │ ├── memory.py │ ├── memwrite.py │ ├── registers.py │ └── threads.py ├── recon │ ├── __init__.py │ ├── dopestack.py │ └── sniper.py ├── release.py ├── renderers.py ├── stalker │ └── __init__.py ├── testmods │ ├── __init__.py │ ├── callingconventions.py │ └── hookbptest.py ├── tests │ ├── __init__.py │ └── teststalker.py ├── tools │ ├── __init__.py │ ├── android.py │ ├── androidpy.sh │ ├── gendocs.py │ ├── vdb.epydoc │ └── vdb.epydoc.css ├── unittest.py └── vdbbin.py ├── visgraph ├── __init__.py ├── cli.py ├── dbcore.py ├── drawing │ ├── __init__.py │ ├── bezier.py │ └── catmullrom.py ├── exc.py ├── graphcore.py ├── layouts │ ├── __init__.py │ ├── dynadag.py │ └── force.py ├── pathcore.py ├── renderers │ ├── __init__.py │ ├── gtkrend.py │ ├── qgraphtree.py │ ├── qtrend.py │ └── svgrend.py └── tests │ ├── __init__.py │ ├── test_graphcore.py │ └── test_layouts.py ├── vivisect ├── __init__.py ├── analysis │ ├── __init__.py │ ├── amd64 │ │ ├── __init__.py │ │ └── emulation.py │ ├── crypto │ │ ├── __init__.py │ │ └── constants.py │ ├── elf │ │ ├── __init__.py │ │ └── elfplt.py │ ├── generic │ │ ├── __init__.py │ │ ├── codeblocks.py │ │ ├── emucode.py │ │ ├── funcentries.py │ │ ├── impapi.py │ │ ├── mkpointers.py │ │ ├── pointers.py │ │ ├── pointertables.py │ │ ├── relocations.py │ │ ├── strconst.py │ │ ├── switchcase.py │ │ └── thunks.py │ ├── i386 │ │ ├── __init__.py │ │ ├── calling.py │ │ ├── importcalls.py │ │ └── thunk_bx.py │ ├── ms │ │ ├── __init__.py │ │ ├── hotpatch.py │ │ ├── localhints.py │ │ ├── msvc.py │ │ ├── msvcfunc.py │ │ └── vftables.py │ └── pe.py ├── base.py ├── cli.py ├── codegraph.py ├── colormap.py ├── const.py ├── contrib │ ├── __init__.py │ ├── ply │ │ ├── EGG-INFO │ │ │ ├── PKG-INFO │ │ │ ├── SOURCES.txt │ │ │ ├── dependency_links.txt │ │ │ ├── top_level.txt │ │ │ └── zip-safe │ │ └── ply │ │ │ ├── __init__.py │ │ │ ├── cpp.py │ │ │ ├── ctokens.py │ │ │ ├── lex.py │ │ │ └── yacc.py │ └── pycparser │ │ └── pycparser │ │ ├── __init__.py │ │ ├── _ast_gen.py │ │ ├── _build_tables.py │ │ ├── _c_ast.cfg │ │ ├── ast_transforms.py │ │ ├── c_ast.py │ │ ├── c_generator.py │ │ ├── c_lexer.py │ │ ├── c_parser.py │ │ ├── ply │ │ ├── LICENSE │ │ ├── __init__.py │ │ ├── cpp.py │ │ ├── ctokens.py │ │ ├── lex.py │ │ └── yacc.py │ │ ├── plyparser.py │ │ └── yacctab.py ├── defconfig.py ├── emutils.py ├── exc.py ├── extensions │ ├── __init__.py │ └── example_gui_extension.py ├── impapi │ ├── __init__.py │ ├── gentool.py │ ├── windows │ │ ├── __init__.py │ │ ├── advapi_32.py │ │ ├── advapi_64.py │ │ ├── amd64.py │ │ ├── gdi_32.py │ │ ├── gdi_64.py │ │ ├── i386.py │ │ ├── kernel_32.py │ │ ├── kernel_64.py │ │ ├── msvcr100_32.py │ │ ├── msvcr100_64.py │ │ ├── msvcr110_32.py │ │ ├── msvcr110_64.py │ │ ├── msvcr120_32.py │ │ ├── msvcr120_64.py │ │ ├── msvcr71_32.py │ │ ├── msvcr80_32.py │ │ ├── msvcr80_64.py │ │ ├── msvcr90_32.py │ │ ├── msvcr90_64.py │ │ ├── msvcrt_32.py │ │ ├── msvcrt_64.py │ │ ├── ntdll_32.py │ │ ├── ntdll_64.py │ │ ├── ole_32.py │ │ ├── ole_64.py │ │ ├── rpcrt4_32.py │ │ ├── rpcrt4_64.py │ │ ├── user_32.py │ │ ├── user_64.py │ │ ├── ws2plus_32.py │ │ └── ws2plus_64.py │ └── winkern │ │ ├── __init__.py │ │ └── i386.py ├── impemu │ ├── __init__.py │ ├── emulator.py │ ├── lookup.py │ ├── monitor.py │ └── platarch │ │ ├── __init__.py │ │ ├── amd64.py │ │ ├── arm.py │ │ ├── h8.py │ │ ├── i386.py │ │ ├── msp430.py │ │ └── windows.py ├── parsers │ ├── __init__.py │ ├── blob.py │ ├── elf.py │ ├── ihex.py │ ├── macho.py │ ├── pe.py │ └── utils.py ├── qt │ ├── __init__.py │ ├── ctxmenu.py │ ├── default.lyt │ ├── funcgraph.py │ ├── funcviews.py │ ├── main.py │ ├── memory.py │ ├── remote.py │ ├── symboliks.py │ ├── tips.py │ ├── ustruct.py │ └── views.py ├── remote │ ├── __init__.py │ ├── client.py │ ├── server.py │ └── share.py ├── renderers │ └── __init__.py ├── reports │ ├── __init__.py │ ├── funccomplexity.py │ ├── locationdist.py │ ├── overlaplocs.py │ └── undeftargets.py ├── storage │ ├── __init__.py │ └── basicfile.py ├── symboliks │ ├── __init__.py │ ├── analysis.py │ ├── archind.py │ ├── archs │ │ ├── __init__.py │ │ ├── amd64.py │ │ └── i386.py │ ├── callconv.py │ ├── common.py │ ├── constraints.py │ ├── effects.py │ ├── emulator.py │ ├── expression.py │ ├── functions.py │ ├── reducers.py │ ├── substitution.py │ ├── tests │ │ ├── __init__.py │ │ ├── test_analysis.py │ │ ├── test_cache.py │ │ ├── test_callingconv.py │ │ └── test_reduce.py │ └── translator.py ├── tests │ ├── __init__.py │ ├── helpers.py │ ├── samplecode.py │ ├── test_helpers.py │ ├── testcconvs.py │ ├── testcodegraph.py │ ├── testimpapi.py │ ├── testpe.py │ ├── testvivgraph.py │ ├── testvivisect.py │ └── vivbins.py ├── tools │ ├── __init__.py │ ├── fscope.py │ └── graphutil.py ├── vamp │ ├── __init__.py │ └── msvc │ │ └── __init__.py ├── vdbext.py ├── vector.py └── vivbin.py ├── vqt ├── __init__.py ├── application.py ├── basics.py ├── cli.py ├── colors.py ├── common.py ├── hotkeys.py ├── main.py ├── menubuilder.py ├── qpython.py ├── saveable.py ├── shortcut.py └── tree.py ├── vstruct ├── __init__.py ├── bitfield.py ├── builder.py ├── constants │ ├── __init__.py │ └── ntstatus.py ├── cparse.py ├── defs │ ├── __init__.py │ ├── arm7 │ │ └── __init__.py │ ├── bmp.py │ ├── dns.py │ ├── elf.py │ ├── gif.py │ ├── ihex.py │ ├── inet.py │ ├── java.py │ ├── kdcom.py │ ├── macho │ │ ├── __init__.py │ │ ├── const.py │ │ ├── fat.py │ │ ├── loader.py │ │ └── stabs.py │ ├── minidump.py │ ├── pcap.py │ ├── pe.py │ ├── pptp.py │ ├── rar.py │ ├── swf.py │ ├── win32.py │ └── windows │ │ ├── __init__.py │ │ ├── win_5_1_i386 │ │ ├── __init__.py │ │ ├── ntdll.py │ │ ├── ntoskrnl.py │ │ └── win32k.py │ │ ├── win_5_2_i386 │ │ ├── __init__.py │ │ ├── ntdll.py │ │ ├── ntoskrnl.py │ │ └── win32k.py │ │ ├── win_6_1_amd64 │ │ ├── __init__.py │ │ ├── ntdll.py │ │ ├── ntoskrnl.py │ │ └── win32k.py │ │ ├── win_6_1_i386 │ │ ├── __init__.py │ │ ├── ntdll.py │ │ ├── ntoskrnl.py │ │ └── win32k.py │ │ ├── win_6_1_wow64 │ │ ├── __init__.py │ │ └── ntdll.py │ │ ├── win_6_2_amd64 │ │ ├── __init__.py │ │ ├── ntdll.py │ │ ├── ntoskrnl.py │ │ └── win32k.py │ │ ├── win_6_2_i386 │ │ ├── __init__.py │ │ ├── ntdll.py │ │ ├── ntoskrnl.py │ │ └── win32k.py │ │ ├── win_6_2_wow64 │ │ ├── __init__.py │ │ └── ntdll.py │ │ ├── win_6_3_amd64 │ │ ├── __init__.py │ │ ├── ntdll.py │ │ └── ntoskrnl.py │ │ ├── win_6_3_i386 │ │ ├── __init__.py │ │ ├── ntdll.py │ │ └── ntoskrnl.py │ │ └── win_6_3_wow64 │ │ ├── __init__.py │ │ └── ntdll.py ├── primitives.py ├── qt │ └── __init__.py └── tests │ ├── __init__.py │ ├── testbasic.py │ └── tests_vstruct.py └── vtrace ├── __init__.py ├── archs ├── __init__.py ├── amd64.py ├── arm.py ├── i386.py └── ppc.py ├── audit.py ├── breakpoints.py ├── const.py ├── envitools.py ├── notifiers.py ├── platforms ├── __init__.py ├── base.py ├── darwin │ ├── Makefile │ ├── __init__.py │ ├── exc.h │ ├── excServer.c │ ├── excUser.c │ ├── machhelper.c │ └── machhelper.dylib ├── freebsd.py ├── gdbstub.py ├── linux.py ├── posix.py ├── solaris.py ├── vmware.py ├── win32.py ├── windll │ ├── amd64 │ │ ├── dbghelp.dll │ │ ├── symsrv.dll │ │ └── symsrv.yes │ └── i386 │ │ ├── dbghelp.dll │ │ ├── symsrv.dll │ │ └── symsrv.yes └── winkern.py ├── qt.py ├── rmi.py ├── snapshot.py ├── tests ├── __init__.py ├── mains │ ├── main.py │ ├── mainexec.py │ ├── mainthreads.py │ └── mainwritemem.py ├── mainwritemem.py ├── testbasic.py ├── tests_breakpoints.py ├── tests_envitools.py ├── testthread.py └── testwritemem.py ├── tools ├── __init__.py ├── iathook.py ├── win32alloc.py ├── win32aslr.py ├── win32heap.py └── win32stealth.py ├── util.py └── watchpoints.py /.gitattributes: -------------------------------------------------------------------------------- 1 | *.py eol=lf 2 | *.c eol=lf 3 | *.h eol=lf 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.swp 3 | *.swo 4 | *.py~ 5 | .hg* 6 | build 7 | dist 8 | *.egg-info 9 | .idea 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | matrix: 4 | include: 5 | - os: linux 6 | sudo: required 7 | python: 2.7 8 | 9 | # travis doesn't support py2.7: https://github.com/travis-ci/travis-ci/issues/2312 10 | 11 | install: 12 | - pip install pyinstaller pep8 13 | - git clone https://github.com/vivisect/vivtestfiles.git /tmp/vivtestfiles 14 | - pip install -e . 15 | 16 | script: 17 | - find . -name \*.py -exec pep8 --ignore=E501 {} \; 18 | - py.test -v 19 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright 2014 invisigoth 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /PE/ordlookup/__init__.py: -------------------------------------------------------------------------------- 1 | import mfc42 2 | import oledlg 3 | import ws2_32 4 | import comctl32 5 | import msvbvm60 6 | import oleaut32 7 | 8 | ''' 9 | A small module for keeping a database of ordinal to symbol 10 | mappings for DLLs which frequently get linked without symbolic 11 | infoz. 12 | ''' 13 | 14 | ords = { 15 | 'mfc42.dll':mfc42.ord_names, 16 | 'oledlg.dll':oledlg.ord_names, 17 | 'ws2_32.dll':ws2_32.ord_names, 18 | 'wsock32.dll':ws2_32.ord_names, 19 | 'msvbvm60.dll':msvbvm60.ord_names, 20 | 'comctl32.dll':comctl32.ord_names, 21 | 'oleaut32.dll':oleaut32.ord_names, 22 | } 23 | 24 | def ordLookup(libname, ord): 25 | ''' 26 | Lookup a name for the given ordinal if it's in our 27 | database. 28 | ''' 29 | names = ords.get(libname.lower()) 30 | if names == None: 31 | return 'ord%d' % ord 32 | name = names.get(ord) 33 | if name == None: 34 | return 'ord%d' % ord 35 | return name 36 | 37 | 38 | -------------------------------------------------------------------------------- /PE/ordlookup/oledlg.py: -------------------------------------------------------------------------------- 1 | ord_names = { 2 | 1:'OleUIAddVerbMenuA', 3 | 2:'OleUICanConvertOrActivateAs', 4 | 3:'OleUIInsertObjectA', 5 | 4:'OleUIPasteSpecialA', 6 | 5:'OleUIEditLinksA', 7 | 6:'OleUIChangeIconA', 8 | 7:'OleUIConvertA', 9 | 8:'OleUIBusyA', 10 | 9:'OleUIUpdateLinksA', 11 | 10:'OleUIPromptUserA', 12 | 11:'OleUIObjectPropertiesA', 13 | 12:'OleUIChangeSourceA', 14 | 13:'OleUIAddVerbMenuW', 15 | 14:'OleUIBusyW', 16 | 15:'OleUIChangeIconW', 17 | 16:'OleUIChangeSourceW', 18 | 17:'OleUIConvertW', 19 | 18:'OleUIEditLinksW', 20 | 19:'OleUIInsertObjectW', 21 | 20:'OleUIObjectPropertiesW', 22 | 21:'OleUIPasteSpecialW', 23 | 22:'OleUIPromptUserW', 24 | 23:'OleUIUpdateLinksW', 25 | } 26 | -------------------------------------------------------------------------------- /PE/ordlookup/printord.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | ''' 4 | Quick utility to generate ord lookups from DLL exports. 5 | ''' 6 | 7 | import PE 8 | 9 | p = PE.PE(file(sys.argv[1], 'rb')) 10 | 11 | base = long(p.IMAGE_EXPORT_DIRECTORY.Base) 12 | 13 | ords = {} 14 | for fva, ord, name in p.getExports(): 15 | ords[ord+base] = name 16 | 17 | keys = ords.keys() 18 | keys.sort() 19 | for k in keys: 20 | print ''' %d:'%s',''' % (k,ords.get(k)) 21 | 22 | -------------------------------------------------------------------------------- /PE/petool.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import code 4 | import optparse 5 | 6 | import PE 7 | 8 | ''' 9 | For now, all this does is rename files to their exportname and version info. 10 | (more to come is likely) 11 | ''' 12 | 13 | def main(): 14 | 15 | parser = optparse.OptionParser() 16 | parser.add_option('--version', dest='version', default=False, action='store_true') 17 | parser.add_option('--resources', dest='resources', default=False, action='store_true') 18 | 19 | opts,argv = parser.parse_args() 20 | 21 | for fname in argv: 22 | 23 | print 'Parsing: %s' % fname 24 | 25 | vsver = None 26 | expname = None 27 | 28 | pe = PE.peFromFileName(fname) 29 | 30 | if opts.resources: 31 | print('Type Nameid - rva size sample') 32 | for rtype,nameid,(rva,size,codepage) in pe.getResources(): 33 | hexstr = pe.readAtRva(rva, max(size,8)).encode('hex') 34 | print('0x%.4x 0x%.4x - 0x%.8x 0x%.8x %s' % (rtype,nameid,rva,size,hexstr)) 35 | 36 | if opts.version: 37 | vs = pe.getVS_VERSIONINFO() 38 | if vs == None: 39 | print 'No VS_VERSIONINFO found!' 40 | 41 | else: 42 | keys = vs.getVersionKeys() 43 | keys.sort() 44 | for k in keys: 45 | val = vs.getVersionValue(k) 46 | print '%s: %r' % (k, val) 47 | 48 | code.interact(local=locals()) 49 | 50 | if __name__ == "__main__": 51 | sys.exit(main()) 52 | -------------------------------------------------------------------------------- /PE/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/PE/tests/__init__.py -------------------------------------------------------------------------------- /PE/tests/test_version.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | 4 | import PE 5 | import vivisect.tests.vivbins as vivbins 6 | 7 | vs_version = { 8 | 'CompanyName': u'Microsoft Corporation', 9 | 'FileDescription': u'Windows NET Device Class Co-Installer for Wireless WAN', 10 | 'FileVersion': u'08.01.02.00 (win7_rtm.090713-1255)', 11 | 'InternalName': u'wwaninst.dll', 12 | 'LegalCopyright': u'\xa9 Microsoft Corporation. All rights reserved.', 13 | 'OriginalFilename': u'wwaninst.dll', 14 | 'ProductName': u'Microsoft\xae Windows\xae Operating System', 15 | 'ProductVersion': u'08.01.02.00', 16 | 'Translation': 78644233, 17 | } 18 | 19 | 20 | class PEResourceTest(unittest.TestCase): 21 | 22 | @vivbins.require 23 | def test_pe_vsersion(self): 24 | fpath = os.path.join('test_pe','bins','wwaninst.dll') 25 | pe = PE.peFromFileName(fpath) 26 | vs = pe.getVS_VERSIONINFO() 27 | self.assertIsNotNone(vs) 28 | keys = vs.getVersionKeys() 29 | self.assertEqual(len(keys), len(vs_version)) 30 | for key in vs.getVersionKeys(): 31 | self.assertEqual(vs_version.get(key), vs.getVersionValue(key)) 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vivisect / Vdb / Vtrace 2 | 3 | Now all as one project! ( made sense once vivisect went public ) 4 | For more in-depth docs on various topics, see the wiki at 5 | [http://visi.kenshoto.com/](http://visi.kenshoto.com/) 6 | 7 | ## Vdb 8 | 9 | As in previous vdb releases, the command ```python vdbbin``` from the 10 | checkout directory will drop you into a debugger prompt on supported 11 | platforms. ( Windows / Linux / FreeBSD / OSX... kinda? ) 12 | 13 | Commands in vdb grow/refine quickly, so use in-line help such as: 14 | 15 | > vdb> help 16 | 17 | or... 18 | 19 | > vdb> help writemem 20 | 21 | to show available commands and options. Additionally, for basic vdb 22 | use, the wiki at [http://visi.kenshoto.com/](http://visi.kenshoto.com/) 23 | 24 | ## Vivisect 25 | 26 | Fairly un-documented static analysis / emulation / symbolik analysis 27 | framework for PE/Elf/Mach-O/Blob binary formats on various architectures. 28 | To start with, you probably want to run a "bulk analysis" pass on a binary 29 | using: 30 | 31 | > python vivbin -B 32 | 33 | which will leave you with .viv 34 | 35 | Then run: 36 | 37 | > python vivbin .viv 38 | 39 | to open the GUI and begin reverse engineering. As with most vtoys, the ui 40 | relies fairly heavily on right-click context menus and various memory 41 | views. 42 | 43 | For the binary ninjas, all APIs used during automatic analysis ( and several 44 | that aren't ) are directly accessible for use writing your own custom 45 | research tools... The interface should be nearly the same when dealing with 46 | a real process ( via vdb/vtrace ) and dealing with an emulator / viv workspace. 47 | 48 | ## Build Status 49 | 50 | [![Build Status](https://travis-ci.org/vivisect/vivisect.svg?branch=master)](https://travis-ci.org/vivisect/vivisect) 51 | -------------------------------------------------------------------------------- /cobra/auth/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | The cobra "auth" package allows modular authentication 3 | for cobra shared objects 4 | ''' 5 | 6 | class CobraAuthenticator: 7 | 8 | def __init__(self): 9 | pass 10 | 11 | def authCobraUser(self, authinfo): 12 | ''' 13 | Authenticate a user and return their user name. 14 | Arguments: 15 | authinfo - a dictionary which can be authmod dependant 16 | ( but probably just has user & passwd ) 17 | ''' 18 | # This is *totally* example code... you probably want something 19 | # from a submodule like cobra.auth.shadowfile 20 | if authinfo.get('user') != 'invisigoth': 21 | return None 22 | if authinfo.get('passwd') != 'secret': 23 | return None 24 | return 'invisigoth' 25 | 26 | def checkUserAccess(self, authuser, objname ): 27 | ''' 28 | Enforce access control on a per shared object basis. 29 | ''' 30 | return True 31 | 32 | -------------------------------------------------------------------------------- /cobra/auth/shadowfile.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import getpass 4 | import hashlib 5 | 6 | import cobra.auth as c_auth 7 | 8 | class ShadowFileAuth(c_auth.CobraAuthenticator): 9 | 10 | ''' 11 | An auth module which uses a simple text file with salted SHA256 12 | password hashes. ( this module may be executed as main to produce 13 | rows for the file ) 14 | 15 | File Format: 16 | # comment 17 | :$ 18 | ''' 19 | def __init__(self, filename): 20 | c_auth.CobraAuthenticator.__init__(self) 21 | self.filename = filename 22 | if not os.path.isfile( filename ): 23 | raise Exception('No Such File: %s' % filename) 24 | 25 | def authCobraUser(self, authinfo): 26 | user = authinfo.get('user').lower() 27 | passwd = authinfo.get('passwd') 28 | userhdr = '%s:' % user 29 | for line in open(self.filename,'rb').readlines(): 30 | if not line.startswith(userhdr): 31 | continue 32 | 33 | line = line.strip() 34 | # We are on the correct line 35 | suser,spasswd = line.split(':') 36 | salt,pwhash = spasswd.split('$') 37 | if hashlib.sha256( salt + passwd ).hexdigest() == pwhash: 38 | return user 39 | 40 | break 41 | 42 | return None 43 | 44 | if __name__ == '__main__': 45 | # A helper for making shadow file rows... 46 | if len(sys.argv) == 1: 47 | print('Usage: python -m cobra.auth.shadowfile [password]') 48 | sys.exit(0) 49 | 50 | user = sys.argv[1].lower() 51 | if len(sys.argv) == 2: 52 | passwd = getpass.getpass() 53 | else: 54 | passwd = sys.argv[2] 55 | 56 | salt = os.urandom(8).encode('hex') 57 | hash = hashlib.sha256( salt + passwd ).hexdigest() 58 | print '%s:%s$%s' % (user,salt,hash) 59 | -------------------------------------------------------------------------------- /cobra/cache.py: -------------------------------------------------------------------------------- 1 | ''' 2 | An API implementing a few caching utilities. 3 | ( use carefully! caches are dangerous ;) ) 4 | ''' 5 | from functools import wraps 6 | from collections import deque 7 | 8 | class FixedDepthCache: 9 | ''' 10 | A fixed depth cache. 11 | ''' 12 | def __init__(self, depth, misscb=None, finicb=None): 13 | self.cache = {} 14 | self.depth = depth 15 | self.cdeque = deque() 16 | 17 | self.misscb = misscb 18 | self.finicb = finicb 19 | 20 | def clear(self): 21 | ''' 22 | Clear all the elements of the cache. 23 | ''' 24 | self.cache.clear() 25 | self.cdeque.clear() 26 | 27 | def get(self, key, default=None): 28 | ''' 29 | Retrieve the given key's value in the cache. 30 | ''' 31 | if not self.cache.has_key(key) and self.misscb: 32 | val = self.misscb(key) 33 | self.put( key, val ) 34 | return val 35 | 36 | return self.cache.get(key, default) 37 | 38 | def put(self, key, value): 39 | ''' 40 | Insert the given key/value pair into the cache. 41 | ''' 42 | self.cache[ key ] = value 43 | self.cdeque.append( key ) 44 | while len(self.cdeque) > self.depth: 45 | popkey = self.cdeque.popleft() 46 | popval = self.cache.pop(popkey, None) 47 | if self.finicb: 48 | self.finicb(popkey,popval) 49 | 50 | def pop(self): 51 | key = self.cdeque.popleft() 52 | val = self.cache.pop(key) 53 | return (key,val) 54 | 55 | def has(self, key): 56 | return self.cache.has_key(key) 57 | 58 | def __len__(self): 59 | return len(self.cdeque) 60 | 61 | def cachefunc(depth): 62 | cache = FixedDepthCache(depth) 63 | 64 | def wrapdef(f): 65 | 66 | @wraps(f) 67 | def funcdef(*args): 68 | if not cache.has( args ): 69 | ret = f(*args) 70 | cache.put(args,ret) 71 | return ret 72 | return cache.get(args) 73 | 74 | return funcdef 75 | 76 | return wrapdef 77 | -------------------------------------------------------------------------------- /cobra/dispatcher.py: -------------------------------------------------------------------------------- 1 | import cobra 2 | 3 | verbose = False 4 | 5 | class CobraDispatchMethod: 6 | ''' 7 | implements use of async cobra calls 8 | ''' 9 | def __init__(self, dispatcher, methname): 10 | self.dispatcher = dispatcher 11 | self.methname = methname 12 | 13 | def __call__(self, *args, **kwargs): 14 | if verbose: print "CALLING:",name,self.methname,repr(args)[:20],repr(kwargs)[:20] 15 | waiters = [] 16 | 17 | try: 18 | for proxy in self.dispatcher.getCobraProxies(): 19 | waiters.append( getattr(proxy, self.methname)(*args, _cobra_async=True, **kwargs) ) 20 | return [waiter.wait() for waiter in waiters] 21 | except: 22 | for waiter in waiters: 23 | if waiter.csock: 24 | waiter.csock.trashed = True 25 | raise 26 | finally: 27 | for waiter in waiters: 28 | if waiter.csock and waiter.csock.pool != None: 29 | waiter.csock.pool.put(waiter.csock) 30 | 31 | 32 | class CobraDispatcher: 33 | ''' 34 | class implements logic around making async calls 35 | to multiple cobra proxies. specifically enforces requeuing 36 | of socket objects when proxy uses sockpool. list of proxies 37 | can be a mix of proxies with different settings. 38 | ''' 39 | def __init__(self, proxies): 40 | self._cobra_proxies = proxies 41 | 42 | def addCobraProxy(self, proxy): 43 | self._cobra_proxies.append(proxy) 44 | 45 | def delCobraProxy(self, proxy): 46 | self._cobra_proxies.remove(proxy) 47 | 48 | def getCobraProxies(self): 49 | return self._cobra_proxies 50 | 51 | def __getattr__(self, name): 52 | if verbose: print "GETATTR",name 53 | 54 | if name == "__getinitargs__": 55 | raise AttributeError() 56 | 57 | self._cobra_methods = self._cobra_proxies[0]._cobra_methods 58 | self._cobra_name = self._cobra_proxies[0]._cobra_name 59 | # Handle methods 60 | if self._cobra_methods.get(name, False): 61 | meth = CobraDispatchMethod(self, name) 62 | setattr(self, name, meth) 63 | return meth 64 | 65 | 66 | -------------------------------------------------------------------------------- /cobra/hostid/__init__.py: -------------------------------------------------------------------------------- 1 | import platform 2 | # This module needs to be "relocatable" 3 | 4 | def getHostId(): 5 | osname = platform.system().lower() 6 | if osname == 'darwin': 7 | import darwinhostid 8 | return darwinhostid.getHostId() 9 | 10 | elif osname in ['microsoft','windows']: 11 | import windowshostid 12 | return windowshostid.getHostId() 13 | 14 | return None 15 | 16 | -------------------------------------------------------------------------------- /cobra/hostid/darwinhostid.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | from ctypes import util 3 | 4 | iokit = cdll.LoadLibrary(util.find_library('IOKit')) 5 | cf = cdll.LoadLibrary(util.find_library('CoreFoundation')) 6 | 7 | cf.CFStringCreateWithCString.argtypes = [c_void_p, c_char_p, c_int32] 8 | cf.CFStringCreateWithCString.restype = c_void_p 9 | cf.CFStringGetCStringPtr.argtypes = [c_void_p, c_uint32] 10 | cf.CFStringGetCStringPtr.restype = c_char_p 11 | 12 | kCFAllocatorDefault = c_void_p.in_dll(cf, "kCFAllocatorDefault") 13 | kCFStringEncodingMacRoman = 0 14 | 15 | kIOMasterPortDefault = c_void_p.in_dll(iokit, "kIOMasterPortDefault") 16 | kIOPlatformSerialNumberKey = "IOPlatformSerialNumber".encode("mac_roman") 17 | kIOPlatformUUIDKey = "IOPlatformUUID".encode("mac_roman") 18 | 19 | iokit.IOServiceMatching.restype = c_void_p 20 | iokit.IOServiceGetMatchingService.argtypes = [c_void_p, c_void_p] 21 | iokit.IOServiceGetMatchingService.restype = c_void_p 22 | iokit.IORegistryEntryCreateCFProperty.argtypes = [c_void_p, c_void_p, c_void_p, c_uint32] 23 | iokit.IORegistryEntryCreateCFProperty.restype = c_void_p 24 | iokit.IOObjectRelease.argtypes = [c_void_p] 25 | 26 | 27 | def getHostId(): 28 | platformExpert = iokit.IOServiceGetMatchingService(kIOMasterPortDefault, 29 | iokit.IOServiceMatching("IOPlatformExpertDevice")) 30 | if platformExpert: 31 | #key = cf.CFStringCreateWithCString(kCFAllocatorDefault, kIOPlatformSerialNumberKey, kCFStringEncodingMacRoman) 32 | key = cf.CFStringCreateWithCString(kCFAllocatorDefault, kIOPlatformUUIDKey, kCFStringEncodingMacRoman) 33 | serialNumberAsCFString = \ 34 | iokit.IORegistryEntryCreateCFProperty(platformExpert, 35 | key, 36 | kCFAllocatorDefault, 0); 37 | if serialNumberAsCFString: 38 | SERIAL = cf.CFStringGetCStringPtr(serialNumberAsCFString, 0) 39 | 40 | iokit.IOObjectRelease(platformExpert) 41 | 42 | return SERIAL 43 | -------------------------------------------------------------------------------- /cobra/hostid/windowshostid.py: -------------------------------------------------------------------------------- 1 | import os 2 | import ctypes 3 | 4 | def getHostId(): 5 | sysdrive = os.getenv('SystemDrive') + '\\' 6 | buf = ctypes.create_string_buffer(64) 7 | if not ctypes.windll.kernel32.GetVolumeNameForVolumeMountPointA(sysdrive, buf, ctypes.c_uint32(64)): 8 | return None 9 | return buf.value 10 | 11 | -------------------------------------------------------------------------------- /cobra/py3compat.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | # abstract several python 2 vs 3 imports / apis 4 | 5 | pyver = tuple([ int(v) for v in platform.python_version().split('.') ]) 6 | 7 | if pyver >= (3,0,0): 8 | import queue 9 | import pickle 10 | import urllib.parse as urlparse 11 | import urllib.request as urllib 12 | 13 | else: # python 2.x.... 14 | 15 | #if os.getenv('VIVPY3'): 16 | # avoid globally scoped import parser... 17 | #from __future__ import division 18 | #from __future__ import print_function 19 | #from __future__ import absolute_import 20 | #from __future__ import unicode_literals 21 | 22 | import urlparse 23 | import Queue as queue 24 | import cPickle as pickle 25 | 26 | # must go at the end due to "urllib" override 27 | import urllib2 as urllib 28 | -------------------------------------------------------------------------------- /cobra/tests/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import cobra 3 | 4 | class TestObject: 5 | 6 | def __init__(self): 7 | self.x = 10 8 | self.y = 20 9 | self.z = 90 10 | 11 | def addToZ(self, val): 12 | self.z += val 13 | 14 | def getUser(self): 15 | return cobra.getUserInfo() 16 | 17 | def accessTestObject( t ): 18 | assert( t.x == 10 ) 19 | t.y = 333 20 | assert( t.y == 333 ) 21 | t.addToZ( 10 ) 22 | assert( t.z == 100 ) 23 | 24 | dirname = os.path.dirname(__file__) 25 | def openTestFile(name): 26 | return file(testFileName(name),'rb') 27 | 28 | def testFileName(name): 29 | return os.path.join(dirname, name) 30 | 31 | -------------------------------------------------------------------------------- /cobra/tests/shadowpass.txt: -------------------------------------------------------------------------------- 1 | invisigoth:9f1bda9528b44f79$d6c7fa1f1747dcd68ba34fb840a11406a1d332443f6a396738aef5cad66064d9 2 | -------------------------------------------------------------------------------- /cobra/tests/testcache.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | 4 | import cobra.cache as c_cache 5 | 6 | class CobraCacheTest(unittest.TestCase): 7 | 8 | #def setUp(self): 9 | #pass 10 | 11 | #def tearDown(self): 12 | #pass 13 | 14 | def test_cobra_cache_basic(self): 15 | cache = c_cache.FixedDepthCache( 5 ) 16 | for i in xrange(10): 17 | cache.put(i, 'I: %d' % i) 18 | 19 | self.assertEqual( cache.get(0), None) 20 | self.assertEqual( cache.get(9), 'I: 9') 21 | 22 | def test_cobra_cache_misscb(self): 23 | 24 | def misscb(x): 25 | return 'X: %d' % x 26 | 27 | cache = c_cache.FixedDepthCache( 5, misscb=misscb ) 28 | self.assertEqual( cache.get(33), 'X: 33') 29 | 30 | def test_cobra_cache_size(self): 31 | 32 | cache = c_cache.FixedDepthCache( 5 ) 33 | for i in xrange(10): 34 | cache.put(i, 'I: %d' % i) 35 | 36 | self.assertEqual( len(cache), 5 ) 37 | 38 | def test_cobra_cache_cachefunc(self): 39 | 40 | d = {'hits':0} 41 | @c_cache.cachefunc(10) 42 | def cacheme(): 43 | d['hits'] += 1 44 | 45 | cacheme() 46 | cacheme() 47 | 48 | self.assertEqual( d['hits'], 1 ) 49 | 50 | -------------------------------------------------------------------------------- /cobra/tests/testevents.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import unittest 4 | 5 | import cobra.devent as c_devent 6 | 7 | class CobraEventTest(unittest.TestCase): 8 | 9 | #def setUp(self): 10 | #pass 11 | 12 | #def tearDown(self): 13 | #pass 14 | 15 | def test_cobra_devent(self): 16 | 17 | eventcore = c_devent.CobraEventCore() 18 | chan = eventcore.initEventChannel() 19 | eventcore.fireEvent('blah',(1,2,3)) 20 | etup = eventcore.getNextEventsForChan(chan)[0] 21 | self.assertEqual(etup[0], 'blah') 22 | 23 | def test_cobra_devent_timeout(self): 24 | eventcore = c_devent.CobraEventCore() 25 | chan = eventcore.initEventChannel() 26 | self.assertFalse( eventcore.getNextEventsForChan( chan, timeout=0.01 ) ) 27 | -------------------------------------------------------------------------------- /cobra/tests/testnewobj.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | 4 | import cobra 5 | 6 | import cStringIO as StringIO 7 | 8 | class NewObjectReturn: 9 | 10 | @cobra.newobj 11 | def open(self): 12 | return StringIO.StringIO('asdf') 13 | 14 | class CobraNewObjTest(unittest.TestCase): 15 | 16 | #def setUp(self): 17 | #pass 18 | 19 | #def tearDown(self): 20 | #pass 21 | 22 | def test_cobra_newobj(self): 23 | 24 | daemon = cobra.CobraDaemon(port=60500,msgpack=True) 25 | objname = daemon.shareObject( NewObjectReturn() ) 26 | daemon.fireThread() 27 | 28 | t = cobra.CobraProxy('cobra://localhost:60500/%s?msgpack=1' % objname) 29 | 30 | with t.open() as fd: 31 | self.assertEqual(fd.read(),'asdf') 32 | 33 | self.assertEqual( len(daemon.shared.keys()), 1) 34 | daemon.stopServer() 35 | -------------------------------------------------------------------------------- /cobra/tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/cobra/tools/__init__.py -------------------------------------------------------------------------------- /cobra/tools/queend.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import cobra 4 | import cobra.cluster as c_cluster 5 | 6 | def usage(): 7 | print('Usage: python -m cobra.tools.queend ') 8 | print('( ifaceip is the IP of the interface facing the cluster)') 9 | sys.exit(-1) 10 | 11 | def main(): 12 | if len(sys.argv) != 2: 13 | usage() 14 | 15 | ip = sys.argv[1] 16 | q = c_cluster.ClusterQueen(ip) 17 | 18 | daemon = cobra.CobraDaemon(port=c_cluster.queen_port) 19 | daemon.shareObject(q, 'ClusterQueen') 20 | daemon.serve_forever() 21 | 22 | if __name__ == '__main__': 23 | sys.exit(main()) 24 | -------------------------------------------------------------------------------- /cobra/tools/runtests.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import cobra.unittests 4 | 5 | # Import order here is by test run order! 6 | import cobra.unittests.basictest as c_basictest 7 | import cobra.unittests.msgpacktest as c_msgpacktest 8 | import cobra.unittests.reftest as c_reftest 9 | import cobra.unittests.authtest as c_authtest 10 | import cobra.unittests.shadowtest as c_shadowtest 11 | 12 | def main(): 13 | cobra.unittests.runUnitTests() 14 | 15 | if __name__ == '__main__': 16 | sys.exit(main()) 17 | -------------------------------------------------------------------------------- /cobra/tools/workerd.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import cobra 4 | import cobra.cluster as c_cluster 5 | 6 | def usage(): 7 | print('Usage: python -m cobra.tools.workerd ') 8 | sys.exit(-1) 9 | 10 | def main(): 11 | 12 | if len(sys.argv) != 2: 13 | usage() 14 | 15 | cname = sys.argv[1] 16 | worker = c_cluster.ClusterClient(cname, docode=True) 17 | worker.processWork() 18 | 19 | if __name__ == '__main__': 20 | # FIXME make this actually take arguments 21 | sys.exit(main()) 22 | -------------------------------------------------------------------------------- /envi/archs/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The new top level home for all the envi architecture modules. 3 | """ 4 | import os 5 | import sys 6 | 7 | def dismain(d): 8 | ''' 9 | Easy utility for implementing stand-alone disassembler utils... 10 | ''' 11 | 12 | if os.path.isfile( sys.argv[1] ): 13 | b = file(sys.argv[1], 'rb').read() 14 | else: 15 | b = sys.argv[1].decode('hex') 16 | 17 | offset = 0 18 | va = 0x41414141 19 | while offset < len(b): 20 | op = d.disasm(b, offset, va+offset) 21 | print '0x%.8x %s %s' % (va+offset, b[offset:offset+len(op)].encode('hex').ljust(16), repr(op)) 22 | offset += len(op) 23 | -------------------------------------------------------------------------------- /envi/archs/arm/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | The initial arm module. 4 | """ 5 | 6 | import envi 7 | 8 | from envi.archs.arm.regs import * 9 | from envi.archs.arm.disasm import * 10 | 11 | class ArmModule(envi.ArchitectureModule): 12 | 13 | def __init__(self, name='armv6'): 14 | import envi.archs.thumb16.disasm as eatd 15 | # these are required for setEndian() which is called from ArchitectureModule.__init__() 16 | self._arch_dis = ArmDisasm() 17 | self._arch_thumb_dis = eatd.Thumb2Disasm() 18 | 19 | envi.ArchitectureModule.__init__(self, name, maxinst=4) 20 | self._arch_reg = self.archGetRegCtx() 21 | 22 | def archGetRegCtx(self): 23 | return ArmRegisterContext() 24 | 25 | def archGetBreakInstr(self): 26 | raise Exception ("weird... what are you trying to do here? ARM has a complex breakpoint instruction") 27 | return 28 | 29 | def archGetNopInstr(self): 30 | return '\x00' 31 | 32 | def getPointerSize(self): 33 | return 4 34 | 35 | def pointerString(self, va): 36 | return "0x%.8x" % va 37 | 38 | def archParseOpcode(self, bytes, offset=0, va=0): 39 | """ 40 | Parse a sequence of bytes out into an envi.Opcode instance. 41 | """ 42 | if va & 3: 43 | return self._arch_thumb_dis.disasm(bytes, offset, va) 44 | 45 | return self._arch_dis.disasm(bytes, offset, va) 46 | 47 | def getEmulator(self): 48 | return ArmEmulator() 49 | 50 | def setEndian(self, endian): 51 | self._endian = endian 52 | self._arch_dis.setEndian(endian) 53 | self._arch_thumb_dis.setEndian(endian) 54 | 55 | def archModifyFuncAddr(self, va, info): 56 | if va & 1: 57 | return va & -2, {'arch' : envi.ARCH_THUMB2} 58 | return va, {} 59 | 60 | def archModifyXrefAddr(self, tova, reftype, rflags): 61 | if tova & 1: 62 | return tova & -2, reftype, rflags 63 | return tova, reftype, rflags 64 | 65 | 66 | 67 | 68 | from envi.archs.arm.emu import * 69 | -------------------------------------------------------------------------------- /envi/archs/h8/const.py: -------------------------------------------------------------------------------- 1 | from envi.const import * 2 | 3 | REG_PC = 8 4 | REG_SP = 7 5 | REG_FLAGS = 9 6 | 7 | 8 | # opcode flags 9 | IF_B = 0x100 10 | IF_W = 0x200 11 | IF_L = 0x400 12 | 13 | OSZ_FLAGS = ( 14 | None, 15 | IF_B, 16 | IF_W, 17 | None, 18 | IF_L, 19 | ) 20 | 21 | # operand flags 22 | OF_PREDEC = 1 23 | OF_POSTINC = 2 24 | -------------------------------------------------------------------------------- /envi/archs/i386/__init__.py: -------------------------------------------------------------------------------- 1 | import envi 2 | import envi.bits as e_bits 3 | 4 | #TODO 5 | # f0 0f c7 4d 00 75 f0 5d 5b - this is NOT right in disasm 6 | 7 | import copy 8 | import struct 9 | import traceback 10 | 11 | # Gank in our bundled libdisassemble 12 | import opcode86 13 | 14 | from envi.archs.i386.regs import * 15 | from envi.archs.i386.disasm import * 16 | 17 | class i386Module(envi.ArchitectureModule): 18 | 19 | def __init__(self): 20 | envi.ArchitectureModule.__init__(self, 'i386') 21 | self._arch_dis = i386Disasm() 22 | 23 | def archGetRegCtx(self): 24 | return i386RegisterContext() 25 | 26 | def archGetBreakInstr(self): 27 | return '\xcc' 28 | 29 | def archGetNopInstr(self): 30 | return '\x90' 31 | 32 | def archGetRegisterGroups(self): 33 | groups = envi.ArchitectureModule.archGetRegisterGroups(self) 34 | general = ('general', ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 35 | 'ebp', 'esp', 'eip', ], ) 36 | 37 | groups.append(general) 38 | return groups 39 | 40 | def getPointerSize(self): 41 | return 4 42 | 43 | def pointerString(self, va): 44 | return '0x%.8x' % va 45 | 46 | def archParseOpcode(self, bytes, offset=0, va=0): 47 | return self._arch_dis.disasm(bytes, offset, va) 48 | 49 | def getEmulator(self): 50 | return IntelEmulator() 51 | 52 | # NOTE: This one must be after the definition of i386Module 53 | from envi.archs.i386.emu import * 54 | 55 | -------------------------------------------------------------------------------- /envi/archs/msp430/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | msp430 module 3 | """ 4 | 5 | ############ 6 | # Author: Don C. Weber 7 | # Started: 05/23/2009 8 | # 9 | 10 | import envi 11 | 12 | from envi.archs.msp430.regs import * 13 | from envi.archs.msp430.disasm import * 14 | from envi.archs.msp430.const import * 15 | 16 | class Msp430Module(envi.ArchitectureModule): 17 | 18 | def __init__(self): 19 | envi.ArchitectureModule.__init__(self, "msp430", maxinst=4) 20 | self._arch_dis = Msp430Disasm() 21 | 22 | def archGetRegCtx(self): 23 | return Msp430RegisterContext() 24 | 25 | def archGetNopInstr(self): 26 | return '\x03\x43' # NOP is emulated with: MOV #0, R3 27 | 28 | def archGetRegisterGroups(self): 29 | groups = envi.ArchitectureModule.archGetRegisterGroups(self) 30 | general= ('general', registers, ) 31 | groups.append(general) 32 | return groups 33 | 34 | def getPointerSize(self): 35 | return 2 36 | 37 | def pointerString(self, va): 38 | return '0x{:04x}'.format(va) 39 | 40 | def archParseOpcode(self, bytes, offset=0, va=0): 41 | return self._arch_dis.disasm(bytes, offset, va) 42 | 43 | def getEmulator(self): 44 | return Msp430Emulator() 45 | 46 | def getArchDefaultCall(self): 47 | return 'msp430call' 48 | 49 | # NOTE: This one must be after the definition of Msp430Module 50 | from envi.archs.msp430.emu import * 51 | -------------------------------------------------------------------------------- /envi/archs/msp430/regs.py: -------------------------------------------------------------------------------- 1 | import envi.registers as e_reg 2 | 3 | from envi.archs.msp430.const import * 4 | 5 | registers = [ 6 | 'pc','sp','sr','cg','r4','r5','r6','r7', 7 | 'r8','r9','r10','r11','r12','r13','r14','r15' 8 | ] 9 | 10 | registers_info = [ (reg, 16) for reg in registers ] 11 | 12 | l = locals() 13 | e_reg.addLocalEnums(l, registers_info) 14 | 15 | registers_meta = [ 16 | ("r0", REG_PC, 0, 16), 17 | ("r1", REG_SP, 0, 16), 18 | ("r2", REG_SR, 0, 16), 19 | ("r3", REG_CG, 0, 16), 20 | ] 21 | 22 | status_meta = [ 23 | ('C', REG_SR, 0, 1, 'Carry Flag'), 24 | ('Z', REG_SR, 1, 1, 'Zero Flag'), 25 | ('N', REG_SR, 2, 1, 'Negative (Sign) Flag'), 26 | ('GIE', REG_SR, 3, 1, 'General Interrupt Enable Flag'), 27 | ('CPUOFF', REG_SR, 4, 1, 'CPU Off Flag'), 28 | ('OSCOFF', REG_SR, 5, 1, 'Oscillator Off Flag'), 29 | ('SCG0', REG_SR, 6, 1, 'System Clock Generator 0 Off Flag'), 30 | ('SCG1', REG_SR, 7, 1, 'System Clock Generotor 1 Off Flag'), 31 | ('V', REG_SR, 8, 1, 'Overflow Flag'), 32 | ] 33 | 34 | e_reg.addLocalStatusMetas(l, registers_meta, status_meta, 'SR') 35 | e_reg.addLocalMetas(l, registers_meta) 36 | 37 | class Msp430RegisterContext(e_reg.RegisterContext): 38 | def __init__(self): 39 | e_reg.RegisterContext.__init__(self) 40 | self.loadRegDef(registers_info) 41 | self.loadRegMetas([], statmetas=status_meta) 42 | self.setRegisterIndexes(REG_PC, REG_SP, srindex=REG_SR) 43 | -------------------------------------------------------------------------------- /envi/archs/thumb16/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from envi.archs.arm import * 3 | 4 | import disasm as th_disasm 5 | 6 | class Thumb16Module(ArmModule): 7 | 8 | def __init__(self): 9 | self._arch_dis = th_disasm.Thumb16Disasm() 10 | ArmModule.__init__(self, name='thumb16') 11 | 12 | 13 | class Thumb2Module(Thumb16Module): 14 | 15 | def __init__(self): 16 | self._arch_dis = th_disasm.Thumb2Disasm() 17 | ArmModule.__init__(self, name='thumb2') 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /envi/archs/z80/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Z80 architecture base... 3 | ''' 4 | -------------------------------------------------------------------------------- /envi/archs/z80/const.py: -------------------------------------------------------------------------------- 1 | 2 | OPTYPE_Reg = 1 3 | OPTYPE_RegMem = 2 4 | OPTYPE_const = 3 5 | OPTYPE_imm8 = 4 6 | OPTYPE_imm16 = 5 7 | OPTYPE_RegAlt = 6 8 | OPTYPE_Ind = 7 9 | OPTYPE_Cond = 8 10 | OPTYPE_immmem16 = 9 11 | OPTYPE_immmem8 = 10 12 | OPTYPE_RegMemDisp = 11 13 | 14 | 15 | COND_NZ = 1 16 | COND_Z = 2 17 | COND_NC = 3 18 | COND_PO = 4 19 | COND_PE = 5 20 | COND_P = 6 21 | COND_M = 7 22 | -------------------------------------------------------------------------------- /envi/archs/z80/regs.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Register definition for the z80 architecture 3 | ''' 4 | 5 | import envi.registers as e_reg 6 | 7 | z80regs = [ 8 | ('AF', 16), 9 | ('BC', 16), 10 | ('DE', 16), 11 | ('HL', 16), 12 | 13 | ('IX', 16), 14 | ('IY', 16), 15 | 16 | ('PC', 16), 17 | ('SP', 16), 18 | 19 | ('I', 8), 20 | ('R', 8), 21 | ] 22 | 23 | l = locals() 24 | e_reg.addLocalEnums(l, z80regs) 25 | 26 | z80meta = [ 27 | ('A', REG_AF, 8, 8), 28 | ('B', REG_BC, 8, 8), 29 | ('C', REG_BC, 0, 8), 30 | ('D', REG_DE, 8, 8), 31 | ('E', REG_DE, 0, 8), 32 | ('F', REG_AF, 0, 8), 33 | ('H', REG_HL, 8, 8), 34 | ('L', REG_HL, 0, 8), 35 | ] 36 | 37 | e_reg.addLocalMetas(l, z80meta) 38 | 39 | class z80RegisterContext(e_reg.RegisterContext): 40 | def __init__(self): 41 | e_reg.RegisterContext.__init__(self) 42 | self.loadRegDef(z80regs) 43 | self.loadRegMetas(z80meta) 44 | self.setRegisterIndexes(REG_PC, REG_SP) 45 | 46 | regctx = z80RegisterContext() 47 | 48 | -------------------------------------------------------------------------------- /envi/bintree.py: -------------------------------------------------------------------------------- 1 | import envi.bits as e_bits 2 | 3 | class BinaryTree: 4 | ''' 5 | A simple binary search tree capable of using integers 6 | or string representations of binary integers as inputs. 7 | 8 | NOTE: the lookup routines assume once a node is found which 9 | has nodeinfo, we have matched. It does *not* need to walk 10 | the rest of the values... 11 | ''' 12 | def __init__(self): 13 | self.basenode = [None, None, None] 14 | 15 | def addInt(self, intval, width, nodeinfo): 16 | node = self.basenode 17 | for sh in xrange(width-1, -1, -1): 18 | choice = (intval >> sh) & 1 19 | if node[choice] == None: 20 | node[choice] = [None, None, None] 21 | node = node[choice] 22 | node[2] = nodeinfo 23 | 24 | def addBinstr(self, binstr, nodeinfo): 25 | bval = e_bits.binary(binstr) 26 | return self.addInt(bval, len(binstr), nodeinfo) 27 | 28 | #def addString(self, charstr, nodeinfo): 29 | # e_bits the whole string to a huge int? 30 | 31 | def getInt(self, intval, width): 32 | ''' 33 | Get an element back out of the tree. 34 | 35 | width is in bits... 36 | ''' 37 | node = self.basenode 38 | for sh in xrange(width-1, -1, -1): 39 | choice = (intval >> sh) & 1 40 | node = node[choice] 41 | ninfo = node[2] 42 | if ninfo != None: 43 | return ninfo 44 | return node[2] 45 | 46 | def getBinstr(self, binstr): 47 | bval = e_bits.binary(binstr) 48 | return self.getInt(bval, len(bstr)) 49 | 50 | -------------------------------------------------------------------------------- /envi/const.py: -------------------------------------------------------------------------------- 1 | # calling convention constants 2 | CC_REG = 1 << 0 # argument is stored in a register 3 | CC_STACK = 1 << 1 # argument is stored on the stack 4 | CC_STACK_INF = 1 << 2 # all following args are stored on the stack 5 | CC_CALLEE_CLEANUP = 1 << 3 # callee cleans up the stack 6 | CC_CALLER_CLEANUP = 1 << 4 # caller cleans up the stack 7 | 8 | # meta-register constants 9 | RMETA_MASK = 0xffff0000 10 | RMETA_NMASK = 0x0000ffff 11 | 12 | ENDIAN_LSB = 0 13 | ENDIAN_MSB = 1 14 | -------------------------------------------------------------------------------- /envi/encoding.py: -------------------------------------------------------------------------------- 1 | """ 2 | Helpers for several encodings. 3 | """ 4 | 5 | def int_to_bcd(val): 6 | if val < 0: 7 | raise ValueError("negative value") 8 | 9 | mult = 1 10 | res = 0 11 | while val > 0: 12 | res += mult * (val % 10) 13 | mult *= 16 14 | val /= 10 15 | 16 | return res 17 | 18 | def bcd_to_int(val, strict=False): 19 | if val < 0: 20 | raise ValueError("negative value") 21 | 22 | mult = 1 23 | res = 0 24 | while val > 0: 25 | nibble = val & 0xf 26 | if strict and nibble > 9: 27 | raise ValueError("invalid bcd value") 28 | 29 | res += nibble * mult 30 | mult *= 10 31 | val >>= 4 32 | 33 | return res 34 | -------------------------------------------------------------------------------- /envi/pyzip.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import zipfile 4 | 5 | ''' 6 | A utility package (in a central location) for packaging up 7 | zip files full of source or whatever... 8 | ''' 9 | 10 | def callback(z, dname, files): 11 | if dname.find('.svn') != -1: 12 | return 13 | 14 | for fname in files: 15 | if fname.endswith('.py'): 16 | fpath = os.path.join(dname, fname) 17 | z.write(fpath) 18 | 19 | def addSource(z, dname): 20 | os.path.walk(dname, callback, z) 21 | 22 | def main(): 23 | 24 | zipname = sys.argv[1] 25 | pz = zipfile.PyZipFile(zipname, 'w') 26 | 27 | dirnames = sys.argv[2:] 28 | if not len(dirnames): 29 | dirnames = [ dname for dname in os.listdir('.') if os.path.isdir(dname) and dname != '.svn' ] 30 | 31 | for dirname in dirnames: 32 | addSource(pz, dirname) 33 | pz.writepy(dirname) 34 | 35 | pz.close() 36 | 37 | if __name__ == '__main__': 38 | sys.exit(main()) 39 | 40 | -------------------------------------------------------------------------------- /envi/qt/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Gui objects for things in the envi package. 3 | ''' 4 | -------------------------------------------------------------------------------- /envi/resolver.py: -------------------------------------------------------------------------------- 1 | print('WARNING WARNING WARNING! envi/resolver.py is depricated!') 2 | print('You may replace all references with envi/symstore/resolver.py') 3 | from envi.symstore.resolver import * 4 | -------------------------------------------------------------------------------- /envi/symstore/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | The envi symstor package contains various symbol resolvers, 3 | servers, and mechanisms for symbol caching. 4 | ''' 5 | -------------------------------------------------------------------------------- /envi/tests/__init__.py: -------------------------------------------------------------------------------- 1 | import envi 2 | import platform 3 | import unittest 4 | 5 | def skip(*skips): 6 | arch = envi.getCurrentArch() 7 | plat = platform.system().lower() 8 | 9 | cur = set([arch,plat]) 10 | skips = set(skips) 11 | 12 | def skipfunc(f): 13 | has = cur & skips 14 | if not has: 15 | return f 16 | 17 | def doskip(*args, **kwargs): 18 | raise unittest.SkipTest('Skipped For: %s' % (repr(has),)) 19 | 20 | return doskip 21 | 22 | return skipfunc 23 | 24 | -------------------------------------------------------------------------------- /envi/tests/msp430/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/envi/tests/msp430/__init__.py -------------------------------------------------------------------------------- /envi/tests/msp430/iand.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # AND 5 | ( 6 | 'AND r14, r15 (result zero)', 7 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x5555)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 1), (SR_V, 1)], 'code': "0ffe", 'data': "" }, 8 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x0)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 0), (SR_V, 0)], 'code': "0ffe", 'data': "" } 9 | ), 10 | ( 11 | 'AND r14, r15 (result non-zero + msb)', 12 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x8555)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 0), (SR_V, 1)], 'code': "0ffe", 'data': "" }, 13 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x8000)], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "0ffe", 'data': "" } 14 | ), 15 | 16 | # AND.b 17 | ( 18 | 'AND.b r14, r15 (result zero)', 19 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x8555)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 1), (SR_V, 1)], 'code': "4ffe", 'data': "" }, 20 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x0)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 0), (SR_V, 0)], 'code': "4ffe", 'data': "" } 21 | ), 22 | ( 23 | 'AND.b r14, r15 (result non-zero + msb)', 24 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0xaa80)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 0), (SR_V, 1)], 'code': "4ffe", 'data': "" }, 25 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x80)], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "4ffe", 'data': "" } 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /envi/tests/msp430/ibic.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | #BIC 5 | ( 6 | 'BIC r14, r15', 7 | { 'regs': [(REG_R14, 0x5555), (REG_R15, 0xaaaa)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0fce", 'data': "" }, 8 | { 'regs': [(REG_R14, 0x5555), (REG_R15, 0xaaaa)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0fce", 'data': "" } 9 | ), 10 | ( 11 | 'BIC r14, r15 (result zero)', 12 | { 'regs': [(REG_R14, 0x5555), (REG_R15, 0x5555)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0fce", 'data': "" }, 13 | { 'regs': [(REG_R14, 0x5555), (REG_R15, 0x0000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0fce", 'data': "" } 14 | ), 15 | ( 16 | 'BIC r14, r15 (result eq destination)', 17 | { 'regs': [(REG_R14, 0x0), (REG_R15, 0x5555)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0fce", 'data': "" }, 18 | { 'regs': [(REG_R14, 0x0), (REG_R15, 0x5555)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0fce", 'data': "" } 19 | ), 20 | 21 | #BIC.b 22 | ( 23 | 'BIC.b r14, r15', 24 | { 'regs': [(REG_R14, 0x5555), (REG_R15, 0xaaaa)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4fce", 'data': "" }, 25 | { 'regs': [(REG_R14, 0x5555), (REG_R15, 0xaa)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4fce", 'data': "" } 26 | ), 27 | ( 28 | 'BIC.b r14, r15 (result zero)', 29 | { 'regs': [(REG_R14, 0x5555), (REG_R15, 0x5555)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4fce", 'data': "" }, 30 | { 'regs': [(REG_R14, 0x5555), (REG_R15, 0x00)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4fce", 'data': "" } 31 | ), 32 | ( 33 | 'BIC.b r14, r15 (result eq src)', 34 | { 'regs': [(REG_R14, 0x0), (REG_R15, 0x5555)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4fce", 'data': "" }, 35 | { 'regs': [(REG_R14, 0x0), (REG_R15, 0x55)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4fce", 'data': "" } 36 | ), 37 | ] 38 | -------------------------------------------------------------------------------- /envi/tests/msp430/ibit.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # BIT 5 | ( 6 | 'BIT r14, r15 (result zero)', 7 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x5555)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 1), (SR_V, 1)], 'code': "0fbe", 'data': "" }, 8 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x0)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 0), (SR_V, 0)], 'code': "0fbe", 'data': "" } 9 | ), 10 | ( 11 | 'BIT r14, r15 (result non-zero + msb)', 12 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x8555)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 0), (SR_V, 1)], 'code': "0fbe", 'data': "" }, 13 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x8000)], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "0fbe", 'data': "" } 14 | ), 15 | 16 | # BIT.b 17 | ( 18 | 'BIT.b r14, r15 (result zero)', 19 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x8555)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 1), (SR_V, 1)], 'code': "4fbe", 'data': "" }, 20 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x0)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 0), (SR_V, 0)], 'code': "4fbe", 'data': "" } 21 | ), 22 | ( 23 | 'BIT.b r14, r15 (result non-zero + msb)', 24 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0xaa80)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 0), (SR_V, 1)], 'code': "4fbe", 'data': "" }, 25 | { 'regs': [(REG_R14, 0xaaaa), (REG_R15, 0x80)], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "4fbe", 'data': "" } 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /envi/tests/msp430/ibr.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # BR 5 | ( 6 | 'BR #0x4412', 7 | { 'regs': [], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "30401244", 'data': "" }, 8 | { 'regs': [(REG_PC, 0x4412)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "30401244", 'data': "" } 9 | ), 10 | ] 11 | -------------------------------------------------------------------------------- /envi/tests/msp430/icall.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # CALL 5 | ( 6 | 'CALL #0x4412', 7 | { 'regs': [(REG_SP, 0x1002)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "b0121244", 'data': "00001122" }, 8 | { 'regs': [(REG_PC, 0x4412), (REG_SP, 0x1000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "b0121244", 'data': "04441122" } 9 | ), 10 | ] 11 | -------------------------------------------------------------------------------- /envi/tests/msp430/iclr.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # CLR 5 | ( 6 | 'CLR R15', 7 | { 'regs': [(REG_R15, 0xffff)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0f43", 'data': "" }, 8 | { 'regs': [(REG_R15, 0x0)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0f43", 'data': "" } 9 | ), 10 | ( 11 | 'CLR @R15', 12 | { 'regs': [(REG_R15, 0x1000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "8f430000", 'data': "11223344" }, 13 | { 'regs': [(REG_R15, 0x1000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "8f430000", 'data': "00003344" } 14 | ), 15 | 16 | # CLR.b 17 | ( 18 | 'CLR.b R15', 19 | { 'regs': [(REG_R15, 0xffff)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4f43", 'data': "" }, 20 | { 'regs': [(REG_R15, 0x0)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4f43", 'data': "" } 21 | ), 22 | ( 23 | 'CLR @R15', 24 | { 'regs': [(REG_R15, 0x1000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "cf430000", 'data': "11223344" }, 25 | { 'regs': [(REG_R15, 0x1000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "cf430000", 'data': "00223344" } 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /envi/tests/msp430/iclrc.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # CLRC 5 | ( 6 | 'CLRC', 7 | { 'regs': [], 'flags': [(SR_N, 1), (SR_Z, 1), (SR_C, 1), (SR_V, 1)], 'code': "12c3", 'data': "" }, 8 | { 'regs': [], 'flags': [(SR_N, 1), (SR_Z, 1), (SR_C, 0), (SR_V, 1)], 'code': "12c3", 'data': "" } 9 | ), 10 | ] 11 | -------------------------------------------------------------------------------- /envi/tests/msp430/iclrn.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # CLRN 5 | ( 6 | 'CLRN', 7 | { 'regs': [], 'flags': [(SR_N, 1), (SR_Z, 1), (SR_C, 1), (SR_V, 1)], 'code': "22c2", 'data': "" }, 8 | { 'regs': [], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 1), (SR_V, 1)], 'code': "22c2", 'data': "" } 9 | ), 10 | ] 11 | -------------------------------------------------------------------------------- /envi/tests/msp430/iclrz.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # CLRZ 5 | ( 6 | 'CLRZ', 7 | { 'regs': [], 'flags': [(SR_N, 1), (SR_Z, 1), (SR_C, 1), (SR_V, 1)], 'code': "22c3", 'data': "" }, 8 | { 'regs': [], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 1), (SR_V, 1)], 'code': "22c3", 'data': "" } 9 | ), 10 | ] 11 | -------------------------------------------------------------------------------- /envi/tests/msp430/iinv.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # INV 5 | ( 6 | 'INV R15', 7 | { 'regs': [(REG_R15, 0x5a5a)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "3fe3", 'data': "" }, 8 | { 'regs': [(REG_R15, 0xa5a5)], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "3fe3", 'data': "" } 9 | ), 10 | ( 11 | 'INV R15 (destination zero + overflow)', 12 | { 'regs': [(REG_R15, 0xffff)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "3fe3", 'data': "" }, 13 | { 'regs': [(REG_R15, 0x0)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 0), (SR_V, 1)], 'code': "3fe3", 'data': "" } 14 | ), 15 | 16 | # INV.b 17 | ( 18 | 'INV.b R15', 19 | { 'regs': [(REG_R15, 0x115a)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "7fe3", 'data': "" }, 20 | { 'regs': [(REG_R15, 0xa5)], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "7fe3", 'data': "" } 21 | ), 22 | ( 23 | 'INV.b R15 (destination zero + overflow)', 24 | { 'regs': [(REG_R15, 0x11ff)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "7fe3", 'data': "" }, 25 | { 'regs': [(REG_R15, 0x0)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 0), (SR_V, 1)], 'code': "7fe3", 'data': "" } 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /envi/tests/msp430/inop.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # NOP 5 | ( 6 | 'NOP', 7 | { 'regs': [], 'flags': [(SR_N, 1), (SR_Z, 1), (SR_C, 1), (SR_V, 1)], 'code': "0343", 'data': "" }, 8 | { 'regs': [], 'flags': [(SR_N, 1), (SR_Z, 1), (SR_C, 1), (SR_V, 1)], 'code': "0343", 'data': "" } 9 | ), 10 | ] 11 | -------------------------------------------------------------------------------- /envi/tests/msp430/ipop.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # POP 5 | ( 6 | 'POP R15', 7 | { 'regs': [(REG_SP, 0x1000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "3f41", 'data': "11223344" }, 8 | { 'regs': [(REG_SP, 0x1002), (REG_R15, 0x2211)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "3f41", 'data': "11223344" } 9 | ), 10 | 11 | # POP.b 12 | ( 13 | 'POP.b R15', 14 | { 'regs': [(REG_SP, 0x1000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "7f41", 'data': "11223344" }, 15 | { 'regs': [(REG_SP, 0x1002), (REG_R15, 0x11)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "7f41", 'data': "11223344" } 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /envi/tests/msp430/ipush.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # PUSH 5 | ( 6 | 'PUSH R15', 7 | { 'regs': [(REG_SP, 0x1004), (REG_R15, 0xaabb)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0f12", 'data': "112233445566" }, 8 | { 'regs': [(REG_SP, 0x1002), (REG_R15, 0xaabb)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0f12", 'data': "1122bbaa5566" } 9 | ), 10 | 11 | # PUSH.b 12 | ( 13 | 'PUSH.b R15', 14 | { 'regs': [(REG_SP, 0x1004), (REG_R15, 0xaabb)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4f12", 'data': "112233445566" }, 15 | { 'regs': [(REG_SP, 0x1002), (REG_R15, 0xaabb)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4f12", 'data': "1122bb445566" } 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /envi/tests/msp430/iret.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # RET 5 | ( 6 | 'RET', 7 | { 'regs': [(REG_SP, 0x1000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "3041", 'data': "11223344" }, 8 | { 'regs': [(REG_SP, 0x1002), (REG_PC, 0x2211)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "3041", 'data': "11223344" } 9 | ), 10 | ] 11 | -------------------------------------------------------------------------------- /envi/tests/msp430/irra.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # RRA 5 | ( 6 | 'RRA r15 (destination carry)', 7 | { 'regs': [(REG_R15, 0x5555)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "0f11", 'data': "" }, 8 | { 'regs': [(REG_R15, 0x2aaa)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "0f11", 'data': "" } 9 | ), 10 | ( 11 | 'RRA r15 (destination zero + carry)', 12 | { 'regs': [(REG_R15, 0x1)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0f11", 'data': "" }, 13 | { 'regs': [(REG_R15, 0x0)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 1), (SR_V, 0)], 'code': "0f11", 'data': "" } 14 | ), 15 | ( 16 | 'RRA r15 (destination negative)', 17 | { 'regs': [(REG_R15, 0x8000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0f11", 'data': "" }, 18 | { 'regs': [(REG_R15, 0xc000)], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0f11", 'data': "" } 19 | ), 20 | 21 | # RRA.b 22 | ( 23 | 'RRA.b r15 (destination carry)', 24 | { 'regs': [(REG_R15, 0x1155)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "4f11", 'data': "" }, 25 | { 'regs': [(REG_R15, 0x2a)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "4f11", 'data': "" } 26 | ), 27 | ( 28 | 'RRA.b r15 (destination zero + carry)', 29 | { 'regs': [(REG_R15, 0x1)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4f11", 'data': "" }, 30 | { 'regs': [(REG_R15, 0x0)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 1), (SR_V, 0)], 'code': "4f11", 'data': "" } 31 | ), 32 | ( 33 | 'RRA.b r15 (destination negative)', 34 | { 'regs': [(REG_R15, 0x1180)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4f11", 'data': "" }, 35 | { 'regs': [(REG_R15, 0xc0)], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4f11", 'data': "" } 36 | ), 37 | ] 38 | -------------------------------------------------------------------------------- /envi/tests/msp430/irrc.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # RRC 5 | ( 6 | 'RRC r15 (destination carry + negative)', 7 | { 'regs': [(REG_R15, 0x5555)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "0f10", 'data': "" }, 8 | { 'regs': [(REG_R15, 0xaaaa)], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "0f10", 'data': "" } 9 | ), 10 | ( 11 | 'RRC r15 (destination zero + carry)', 12 | { 'regs': [(REG_R15, 0x1)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0f10", 'data': "" }, 13 | { 'regs': [(REG_R15, 0x0)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 1), (SR_V, 0)], 'code': "0f10", 'data': "" } 14 | ), 15 | ( 16 | 'RRC r15 (destination negative)', 17 | { 'regs': [(REG_R15, 0x8000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0f10", 'data': "" }, 18 | { 'regs': [(REG_R15, 0x4000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "0f10", 'data': "" } 19 | ), 20 | 21 | # RRC.b 22 | ( 23 | 'RRC.b r15 (destination carry)', 24 | { 'regs': [(REG_R15, 0x1155)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "4f10", 'data': "" }, 25 | { 'regs': [(REG_R15, 0xaa)], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "4f10", 'data': "" } 26 | ), 27 | ( 28 | 'RRC.b r15 (destination zero + carry)', 29 | { 'regs': [(REG_R15, 0x1)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4f10", 'data': "" }, 30 | { 'regs': [(REG_R15, 0x0)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 1), (SR_V, 0)], 'code': "4f10", 'data': "" } 31 | ), 32 | ( 33 | 'RRC.b r15 (destination negative)', 34 | { 'regs': [(REG_R15, 0x1180)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4f10", 'data': "" }, 35 | { 'regs': [(REG_R15, 0x40)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "4f10", 'data': "" } 36 | ), 37 | ] 38 | -------------------------------------------------------------------------------- /envi/tests/msp430/isetc.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # SETC 5 | ( 6 | 'SETC', 7 | { 'regs': [], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "12d3", 'data': "" }, 8 | { 'regs': [], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "12d3", 'data': "" } 9 | ), 10 | ] 11 | -------------------------------------------------------------------------------- /envi/tests/msp430/isetn.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # SETN 5 | ( 6 | 'SETN', 7 | { 'regs': [], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "22d2", 'data': "" }, 8 | { 'regs': [], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "22d2", 'data': "" } 9 | ), 10 | ] 11 | -------------------------------------------------------------------------------- /envi/tests/msp430/isetz.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # SETZ 5 | ( 6 | 'SETZ', 7 | { 'regs': [], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "22d3", 'data': "" }, 8 | { 'regs': [], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 0), (SR_V, 0)], 'code': "22d3", 'data': "" } 9 | ), 10 | ] 11 | -------------------------------------------------------------------------------- /envi/tests/msp430/iswpb.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # SWPB 5 | ( 6 | 'DEC r15', 7 | { 'regs': [(REG_R15, 0xaabb)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "8f10", 'data': "" }, 8 | { 'regs': [(REG_R15, 0xbbaa)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "8f10", 'data': "" } 9 | ), 10 | ] 11 | -------------------------------------------------------------------------------- /envi/tests/msp430/isxt.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # SXT 5 | ( 6 | 'SXT r15 (destionation carry)', 7 | { 'regs': [(REG_R15, 0xaa11)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "8f11", 'data': "" }, 8 | { 'regs': [(REG_R15, 0x0011)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "8f11", 'data': "" } 9 | ), 10 | ( 11 | 'SXT r15 (destination negative + extend sign + carry)', 12 | { 'regs': [(REG_R15, 0x0080)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "8f11", 'data': "" }, 13 | { 'regs': [(REG_R15, 0xff80)], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "8f11", 'data': "" } 14 | ), 15 | ( 16 | 'SXT r15 (destination zero)', 17 | { 'regs': [(REG_R15, 0x0000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 0)], 'code': "8f11", 'data': "" }, 18 | { 'regs': [(REG_R15, 0x0000)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 0), (SR_V, 0)], 'code': "8f11", 'data': "" } 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /envi/tests/msp430/itst.py: -------------------------------------------------------------------------------- 1 | from envi.archs.msp430.regs import * 2 | 3 | checks = [ 4 | # TST 5 | ( 6 | 'TST R15 (destination negative)', 7 | { 'regs': [(REG_R15, 0x8000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 1)], 'code': "0f93", 'data': "" }, 8 | { 'regs': [(REG_R15, 0x8000)], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "0f93", 'data': "" } 9 | ), 10 | ( 11 | 'TST R15 (destination zero)', 12 | { 'regs': [(REG_R15, 0x0000)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 1)], 'code': "0f93", 'data': "" }, 13 | { 'regs': [(REG_R15, 0x0000)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 1), (SR_V, 0)], 'code': "0f93", 'data': "" } 14 | ), 15 | 16 | # TST.b 17 | ( 18 | 'TST.b R15 (destination negative)', 19 | { 'regs': [(REG_R15, 0x1180)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 1)], 'code': "4f93", 'data': "" }, 20 | { 'regs': [(REG_R15, 0x1180)], 'flags': [(SR_N, 1), (SR_Z, 0), (SR_C, 1), (SR_V, 0)], 'code': "4f93", 'data': "" } 21 | ), 22 | ( 23 | 'TST.b R15 (destination zero)', 24 | { 'regs': [(REG_R15, 0x1100)], 'flags': [(SR_N, 0), (SR_Z, 0), (SR_C, 0), (SR_V, 1)], 'code': "4f93", 'data': "" }, 25 | { 'regs': [(REG_R15, 0x1100)], 'flags': [(SR_N, 0), (SR_Z, 1), (SR_C, 1), (SR_V, 0)], 'code': "4f93", 'data': "" } 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /envi/tests/test_arch_arm.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | class ArmInstructionSet(unittest.TestCase): 4 | def test_msr(self): 5 | # test the MSR instruction 6 | import envi.archs.arm as e_arm;reload(e_arm) 7 | am=e_arm.ArmModule() 8 | op = am.archParseOpcode('d3f021e3'.decode('hex')) 9 | self.assertEqual('msr CPSR_c, #0xd3', repr(op)) 10 | -------------------------------------------------------------------------------- /envi/tests/test_bits.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import envi.bits as e_bits 3 | 4 | class EnviBitsTest(unittest.TestCase): 5 | 6 | def test_envi_bits_masktest(self): 7 | self.assertTrue( e_bits.masktest('11001100')(0xcc) ) 8 | self.assertTrue( e_bits.masktest('1100110011001100')(0xcccc) ) 9 | self.assertTrue( e_bits.masktest('1100xxxx1100xxxx')(0xc2c2) ) 10 | self.assertFalse( e_bits.masktest('110011xx110011xx')(0xc2c2) ) 11 | -------------------------------------------------------------------------------- /envi/tests/test_memory.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import envi.memory as e_mem 4 | 5 | class EnviMemoryTest(unittest.TestCase): 6 | 7 | def test_envi_memory_cache(self): 8 | mem = e_mem.MemoryObject() 9 | mem.addMemoryMap(0x41410000, e_mem.MM_RWX, 'stack', 'B'*16384) 10 | 11 | cache = e_mem.MemoryCache(mem) 12 | self.assertEqual(cache.readMemory(0x41410041, 30), 'B' * 30) 13 | 14 | cache.writeMemory(0x41410041, 'V') 15 | 16 | self.assertEqual(cache.readMemory(0x41410040, 3), 'BVB') 17 | self.assertTrue(cache.isDirtyPage(0x41410040)) 18 | self.assertEqual(mem.readMemory(0x41410040, 3), 'BBB') 19 | # Test a cross page read 20 | self.assertEqual(mem.readMemory(0x41410000 + (cache.pagesize - 2), 4), 'BBBB') 21 | -------------------------------------------------------------------------------- /envi/tests_memory.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import envi.memory 4 | 5 | class Memory(unittest.TestCase): 6 | def setUp(self): 7 | self.mem = envi.memory.MemoryObject() 8 | 9 | def test_getMaxReadSize(self): 10 | mmaps = [ (0, envi.memory.MM_READ, None, 0x1000 * '\x41'), 11 | (0x1000, envi.memory.MM_READ, None, 0x500 * '\x42'), 12 | # gap 13 | (0x2000, envi.memory.MM_READ, None, 0x100 * '\x43'), 14 | (0x2100, envi.memory.MM_NONE, None, 0x1000 * '\x44'), 15 | (0x3100, envi.memory.MM_READ, None, 0x200 * '\x45'), 16 | ] 17 | 18 | # reverse the list just to make sure we aren't making assumptions 19 | # about ascending order. 20 | mmaps = reversed(mmaps) 21 | for mmap in mmaps: 22 | self.mem.addMemoryMap(*mmap) 23 | 24 | # (va, known max read size) 25 | answers = [ (0, 0x1500), # across contiguous maps 26 | (0x1000, 0x500), # an entire map 27 | (0x2100, 0), # va inside map without MM_READ 28 | (0x2000, 0x100), # borders map without MM_READ 29 | (10, 0x1500-10), # offsets inside single maps 30 | (0x1001, 0x4ff), 31 | (0x2050, 0x2100-0x2000-0x50), 32 | (0x2150, 0), 33 | (0xffff, 0), # last va in map 34 | (0x2fff, 0), # last va in map 35 | (0x123456789, 0) # no mans land. 36 | ] 37 | 38 | for va, answer in answers: 39 | size = self.mem.getMaxReadSize(va) 40 | 41 | self.assertEqual(answer, size) 42 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pycparser 2 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='vivisect', 5 | author='', 6 | author_email='', 7 | version='0.0.20170525', 8 | url='https://github.com/vivisect/vivisect', 9 | py_modules=[''], 10 | packages=find_packages(), 11 | package_data={ 12 | '': ['*.dll', '*.dylib', '*.yes', '*.cfg', '*.lyt', 13 | '*.c', '*.h', 'Makefile',], 14 | }, 15 | entry_points={ 16 | "console_scripts": [ 17 | "vivbin=vivisect.vivbin:main", 18 | "vdbbin=vdb.vdbbin:main", 19 | ] 20 | }, 21 | install_requires=[ 22 | "pycparser", 23 | ], 24 | description='', 25 | zip_safe=False, 26 | classifiers=[ 27 | 'License :: OSI Approved :: Apache Software License', 28 | 'Programming Language :: Python' 29 | 'Topic :: Security', 30 | 'Topic :: Software Development :: Debuggers', 31 | 'Topic :: Software Development :: Disassemblers', 32 | ] 33 | ) 34 | -------------------------------------------------------------------------------- /vdb/ext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vdb/ext/__init__.py -------------------------------------------------------------------------------- /vdb/ext/execsc.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import shlex 3 | 4 | import vtrace 5 | 6 | class ShellcodeLoadNotifier(vtrace.Notifier): 7 | def __init__(self, db, fname): 8 | self.db = db 9 | self.fname = fname 10 | 11 | def notify(self, event, trace): 12 | if event != vtrace.NOTIFY_BREAK: 13 | return 14 | 15 | bytez = None 16 | with open(self.fname, 'rb') as f: 17 | bytez = f.read() 18 | 19 | va = trace.allocateMemory(len(bytez)) 20 | trace.writeMemory(va, bytez) 21 | 22 | self.db.vprint('Loaded shellcode at address: 0x%x' % va) 23 | 24 | trace.setProgramCounter(va) 25 | trace.addBreakByAddr(va) 26 | 27 | self.db.deregisterNotifier(vtrace.NOTIFY_BREAK, self) 28 | 29 | def execsc(db, line): 30 | ''' 31 | Load and execute shellcode stub from file 32 | 33 | Usage: execsc 34 | ''' 35 | argv = shlex.split(line) 36 | if len(argv) != 1: 37 | return db.do_help('execsc') 38 | 39 | cmd = sys.executable 40 | trace = db.newTrace() 41 | db.vprint('Executing %s' % cmd) 42 | 43 | sc = ShellcodeLoadNotifier(db, argv[0]) 44 | db.registerNotifier(vtrace.NOTIFY_BREAK, sc) 45 | 46 | trace.execute(cmd) 47 | 48 | def vdbExtension(db, trace): 49 | db.registerCmdExtension(execsc) 50 | -------------------------------------------------------------------------------- /vdb/extensions/amd64.py: -------------------------------------------------------------------------------- 1 | import vdb.extensions.i386 as v_ext_i386 2 | 3 | import vdb.extensions.i386 as vdb_ext_i386 4 | 5 | def vdbExtension(vdb, trace): 6 | vdb.addCmdAlias('db','mem -F bytes') 7 | vdb.addCmdAlias('dw','mem -F u_int_16') 8 | vdb.addCmdAlias('dd','mem -F u_int_32') 9 | vdb.addCmdAlias('dq','mem -F u_int_64') 10 | vdb.addCmdAlias('dr','mem -F "Deref View"') 11 | vdb.addCmdAlias('ds','mem -F "Symbols View"') 12 | 13 | vdb.registerCmdExtension(vdb_ext_i386.eflags,'amd64') 14 | -------------------------------------------------------------------------------- /vdb/extensions/arm.py: -------------------------------------------------------------------------------- 1 | 2 | import envi.cli as e_cli 3 | import envi.archs.arm.thumb as e_thumb 4 | 5 | def thumb(db, line): 6 | ''' 7 | Disassemble thumb instructions from the given address. 8 | 9 | Usage: thumb 10 | ''' 11 | t = db.getTrace() 12 | 13 | d = e_thumb.ArmThumbDisasm() 14 | 15 | argv = e_cli.splitargs(line) 16 | size = 20 17 | argc = len(argv) 18 | if argc == 0: 19 | addr = t.getProgramCounter() 20 | else: 21 | addr = t.parseExpression(argv[0]) 22 | 23 | if argc > 1: 24 | size = t.parseExpression(argv[1]) 25 | 26 | bytes = t.readMemory(addr, size) 27 | offset = 0 28 | 29 | db.vprint("Dissassembly:") 30 | while offset < size: 31 | va = addr + offset 32 | op = d.disasm(bytes, offset, va) 33 | obytes = bytes[offset:offset+len(op)] 34 | 35 | 36 | db.canvas.addVaText('0x%.8x' % va, va=va) 37 | db.canvas.addText(": %s " % obytes.encode('hex').ljust(17)) 38 | op.render(db.canvas) 39 | db.canvas.addText("\n") 40 | 41 | offset += len(op) 42 | 43 | def vdbExtension(db, trace): 44 | vdb.addCmdAlias('db','mem -F bytes') 45 | vdb.addCmdAlias('dw','mem -F u_int_16') 46 | vdb.addCmdAlias('dd','mem -F u_int_32') 47 | vdb.addCmdAlias('dq','mem -F u_int_64') 48 | vdb.addCmdAlias('dr','mem -F "Deref View"') 49 | vdb.addCmdAlias('ds','mem -F "Symbols View"') 50 | db.registerCmdExtension(thumb) 51 | 52 | -------------------------------------------------------------------------------- /vdb/extensions/darwin.py: -------------------------------------------------------------------------------- 1 | 2 | def einfo(db, line): 3 | db.vprint('EINFO') 4 | 5 | def vdbExtension(vdb, trace): 6 | vdb.registerCmdExtension(einfo) 7 | 8 | -------------------------------------------------------------------------------- /vdb/extensions/i386.py: -------------------------------------------------------------------------------- 1 | import shlex 2 | import envi.archs.i386 as e_i386 3 | 4 | def eflags(vdb, line): 5 | ''' 6 | Shows or flips the status of the eflags register bits. 7 | 8 | Usage: eflags [flag short name] 9 | ''' 10 | trace = vdb.getTrace() 11 | argv = shlex.split(line) 12 | if len(argv) not in (0, 1): 13 | return vdb.do_help('eflags') 14 | 15 | if len(argv) > 0: 16 | flag = argv[0].upper() 17 | valid_flags = trace.getStatusFlags().keys() 18 | if flag not in valid_flags: 19 | raise Exception('invalid flag: %s, valid flags %s' % (flag, valid_flags)) 20 | value = trace.getRegisterByName(flag) 21 | trace.setRegisterByName(flag, not bool(value)) 22 | # TODO: this is not plumbed through to flags gui due to new gui 23 | # eventing coming soon. 24 | vdb.vdbUIEvent('vdb:setflags') 25 | return 26 | 27 | ef = trace.getRegisterByName('eflags') 28 | vdb.vprint('%16s: %s' % ('Carry', bool(ef & e_i386.EFLAGS_CF))) 29 | vdb.vprint('%16s: %s' % ('Parity', bool(ef & e_i386.EFLAGS_PF))) 30 | vdb.vprint('%16s: %s' % ('Adjust', bool(ef & e_i386.EFLAGS_AF))) 31 | vdb.vprint('%16s: %s' % ('Zero', bool(ef & e_i386.EFLAGS_ZF))) 32 | vdb.vprint('%16s: %s' % ('Sign', bool(ef & e_i386.EFLAGS_SF))) 33 | vdb.vprint('%16s: %s' % ('Trap', bool(ef & e_i386.EFLAGS_TF))) 34 | vdb.vprint('%16s: %s' % ('Interrupt', bool(ef & e_i386.EFLAGS_IF))) 35 | vdb.vprint('%16s: %s' % ('Direction', bool(ef & e_i386.EFLAGS_DF))) 36 | vdb.vprint('%16s: %s' % ('Overflow', bool(ef & e_i386.EFLAGS_OF))) 37 | 38 | def vdbExtension(vdb, trace): 39 | vdb.addCmdAlias('db','mem -F bytes') 40 | vdb.addCmdAlias('dw','mem -F u_int_16') 41 | vdb.addCmdAlias('dd','mem -F u_int_32') 42 | vdb.addCmdAlias('dq','mem -F u_int_64') 43 | vdb.addCmdAlias('dr','mem -F "Deref View"') 44 | vdb.addCmdAlias('ds','mem -F "Symbols View"') 45 | vdb.registerCmdExtension(eflags) 46 | 47 | -------------------------------------------------------------------------------- /vdb/extensions/i486.py: -------------------------------------------------------------------------------- 1 | 2 | from vdb.extensions.i386 import * 3 | 4 | -------------------------------------------------------------------------------- /vdb/extensions/i586.py: -------------------------------------------------------------------------------- 1 | 2 | from vdb.extensions.i386 import * 3 | 4 | -------------------------------------------------------------------------------- /vdb/extensions/i686.py: -------------------------------------------------------------------------------- 1 | 2 | from vdb.extensions.i386 import * 3 | 4 | -------------------------------------------------------------------------------- /vdb/qt/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | The package for the QT gui code for VDB. 3 | ''' 4 | # No code here! 5 | -------------------------------------------------------------------------------- /vdb/qt/base.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtGui 2 | 3 | import vqt.saveable as vq_save 4 | 5 | import vtrace.qt 6 | 7 | class VdbWidgetWindow(QtGui.QWidget, vq_save.SaveableWidget, vtrace.qt.VQTraceNotifier): 8 | ''' 9 | a base window class for widgets to inherit from for vdb. 10 | this gives your window/widget access to the vdb instance (self.db), the gui 11 | instance (self.db.gui), and the persistent trace object (self.dbt). 12 | 13 | implement vqLoad for tracer events. 14 | implement vdbUIEvent for events caused by user interaction. 15 | state between runs of the debugger. 16 | ''' 17 | def __init__(self, db, dbt, parent=None): 18 | QtGui.QWidget.__init__(self, parent=parent) 19 | vq_save.SaveableWidget.__init__(self) 20 | vtrace.qt.VQTraceNotifier.__init__(self, trace=dbt) 21 | 22 | self.db = db 23 | self.dbt = dbt 24 | 25 | def keyPressEvent(self, event): 26 | ''' 27 | handle the global hotkeys. 28 | ''' 29 | self.db.gui.keyPressEvent(event) 30 | -------------------------------------------------------------------------------- /vdb/qt/memwrite.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtGui 2 | 3 | import vdb.qt.base 4 | import envi.qt.memwrite as e_qt_mw 5 | 6 | from vqt.main import * 7 | 8 | class VdbMemWriteWindow(vdb.qt.base.VdbWidgetWindow): 9 | 10 | def __init__(self, db, dbt, expr='', esize='', parent=None): 11 | vdb.qt.base.VdbWidgetWindow.__init__(self, db, dbt, parent=parent) 12 | 13 | self.memWriteWidget = e_qt_mw.MemWriteWindow(expr=expr, esize=esize, emu=dbt, parent=parent) 14 | vbox = QtGui.QVBoxLayout() 15 | vbox.addWidget(self.memWriteWidget) 16 | self.setLayout(vbox) 17 | 18 | self.memWriteWidget.writeToMemory.connect(self.writeMemory) 19 | self.setWindowTitle('Write Memory') 20 | 21 | vqtconnect( self.vdbWriteMem, 'vdb:writemem' ) 22 | 23 | def vdbWriteMem(self, event, einfo): 24 | self.vqLoad() 25 | 26 | def vqLoad(self): 27 | self.memWriteWidget.renderMemory() 28 | 29 | def enviNavGoto(self, expr, esize='', rend=''): 30 | self.memWriteWidget.setValues(expr, esize) 31 | self.vqLoad() 32 | 33 | def vqGetSaveState(self): 34 | expr, esize = self.memWriteWidget.getValues() 35 | return {'expr': expr, 'esize': esize} 36 | 37 | def vqSetSaveState(self, state): 38 | self.memWriteWidget.setValues(state.get('expr', ''), state.get('esize', '')) 39 | 40 | def writeMemory(self, expr, hexbytez): 41 | self.db.do_writemem('-X %s %s' % (expr, hexbytez)) 42 | -------------------------------------------------------------------------------- /vdb/qt/registers.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtCore, QtGui 2 | 3 | import vtrace.qt 4 | import vdb.qt.base 5 | 6 | from vqt.main import * 7 | 8 | class VdbRegistersWindow(vdb.qt.base.VdbWidgetWindow): 9 | def __init__(self, db, dbt, parent=None): 10 | vdb.qt.base.VdbWidgetWindow.__init__(self, db, dbt, parent=parent) 11 | 12 | self.regsWidget = vtrace.qt.RegistersView(trace=dbt, parent=parent) 13 | 14 | vbox = QtGui.QVBoxLayout() 15 | vbox.addWidget(self.regsWidget) 16 | self.setLayout(vbox) 17 | 18 | self.setWindowTitle('Registers') 19 | 20 | vqtconnect(self.vqLoad, 'vdb:setregs') 21 | vqtconnect(self.vqLoad, 'vdb:setthread') 22 | 23 | def vqLoad(self): 24 | ''' 25 | the widgets in RegistersView already register for notifications. 26 | ''' 27 | self.regsWidget.reglist.vqLoad() 28 | 29 | -------------------------------------------------------------------------------- /vdb/qt/threads.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtCore, QtGui 2 | 3 | import vtrace.qt 4 | import vdb.qt.base 5 | 6 | class VdbThreadsWindow(vdb.qt.base.VdbWidgetWindow): 7 | def __init__(self, db, dbt, parent=None): 8 | vdb.qt.base.VdbWidgetWindow.__init__(self, db, dbt, parent=parent) 9 | 10 | self.threadWidget = vtrace.qt.VQThreadsView(trace=dbt, parent=parent) 11 | 12 | vbox = QtGui.QVBoxLayout() 13 | vbox.addWidget(self.threadWidget) 14 | self.setLayout(vbox) 15 | 16 | self.setWindowTitle('Threads') 17 | 18 | def vqLoad(self): 19 | ''' 20 | the widgets in VQThreadsView already register for notifications. 21 | ''' 22 | self.threadWidget.vqLoad() 23 | -------------------------------------------------------------------------------- /vdb/recon/dopestack.py: -------------------------------------------------------------------------------- 1 | ''' 2 | A quick set of tools for doing stack doping. 3 | ''' 4 | import vtrace 5 | 6 | def dopeThreadStack(trace, threadid): 7 | curthread = trace.getCurrentThread() 8 | try: 9 | trace.selectThread(threadid) 10 | sp = trace.getStackCounter() 11 | mmap = trace.getMemoryMap(sp) 12 | if mmap == None: 13 | raise Exception('Thread %d has invalid stack pointer 0x%.8x' % (threadid, sp)) 14 | 15 | mapva, mapsize, mperms, mfname = mmap 16 | 17 | dopesize = sp - mapva 18 | trace.writeMemory(mapva, 'V' * dopesize) 19 | 20 | except Exception, e: 21 | print 'dopeThreadStack Failed On %d' % threadid 22 | trace.selectThread(curthread) 23 | 24 | def dopeAllThreadStacks(trace): 25 | ''' 26 | Apply stack doping to all thread stacks. 27 | ''' 28 | for threadid in trace.getThreads().keys(): 29 | dopeThreadStack(trace, threadid) 30 | 31 | class ThreadDopeNotifier(vtrace.Notifier): 32 | 33 | def notify(self, event, trace): 34 | dopeAllThreadStacks(trace) 35 | 36 | dopenotif = ThreadDopeNotifier() 37 | 38 | def enableEventDoping(trace): 39 | trace.registerNotifier(vtrace.NOTIFY_CONTINUE, dopenotif) 40 | 41 | def disableEventDoping(trace): 42 | trace.deregisterNotifier(vtrace.NOTIFY_CONTINUE, dopenotif) 43 | 44 | -------------------------------------------------------------------------------- /vdb/recon/sniper.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Specialized breakpoints which identify dangerous calling 3 | mechanisms and tag them. 4 | ''' 5 | import envi.memory as e_mem 6 | import vtrace.breakpoints as vt_breakpoints 7 | 8 | def getStackArg(trace, argidx): 9 | ''' 10 | Assuming we are at the instruction after 11 | a call, grab the stack argument at the specified 12 | index (skipping the saved instruction pointer). 13 | ''' 14 | stack = trace.getStackCounter() 15 | fmt = ' 2) 23 | -------------------------------------------------------------------------------- /vdb/tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vdb/tools/__init__.py -------------------------------------------------------------------------------- /vdb/tools/android.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Some utilities for debugging on android. 3 | ''' 4 | import os 5 | import subprocess 6 | 7 | import vdb.release as vdb_release 8 | 9 | utildir = os.path.dirname( __file__ ) 10 | 11 | droidtmp = '/data/local/tmp/' 12 | 13 | def adbCommand(*argv): 14 | return subprocess.check_output(argv, stderr=subprocess.PIPE) 15 | 16 | message = ''' 17 | Due to silly/complicated reasons, you have to issue the 18 | vdb command from within adb yourself ( ask visi to rage about 19 | it if youd like to know why...) 20 | 21 | Please run this: 22 | cd %s; sh androidpy.sh vdb.pyz 23 | ''' % droidtmp 24 | 25 | def runVdbOnDroid(): 26 | zfile = os.path.join(utildir,'vdb.pyz') 27 | script = os.path.join(utildir, 'androidpy.sh') 28 | vdb_release.getSourceZip(fname=zfile) 29 | 30 | # copy in the script and the source zip 31 | print('Pushing vdb.pyz...') 32 | adbCommand('adb','push',zfile, droidtmp + 'vdb.pyz') 33 | print('Pushing python shell script...') 34 | adbCommand('adb','push',script, droidtmp + 'androidpy.sh') 35 | print(message) 36 | #os.system('adb shell sh %s/androidpy.sh %s/vdb.pyz' % ( droidtmp, droidtmp )) 37 | os.system('adb shell') 38 | 39 | if __name__ == '__main__': 40 | runVdbOnDroid() 41 | 42 | -------------------------------------------------------------------------------- /vdb/tools/androidpy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | PY4APATH=/data/data/com.googlecode.pythonforandroid 3 | PY4ADATA=${EXTERNAL_STORAGE}/com.googlecode.pythonforandroid 4 | PYTHONPATH=${PY4ADATA}/extras/python:${PY4APATH}/files/python/lib/python2.6/lib-dynload 5 | export PYTHONPATH 6 | export TEMP=${PY4ADATA}/extras/python/tmp 7 | export PYTHON_EGG_CACHE=${TEMP} 8 | export PYTHONHOME=${PY4APATH}/files/python 9 | export LD_LIBRARY_PATH=${PY4APATH}/files/python/lib:/system/lib 10 | export HOME=${PY4ADATA} 11 | ${PY4APATH}/files/python/bin/python "$@" 12 | 13 | -------------------------------------------------------------------------------- /vdb/tools/vdb.epydoc: -------------------------------------------------------------------------------- 1 | [epydoc] # Epydoc section marker (required by ConfigParser) 2 | 3 | # Configuration file for epydoc, use gendoc.py to generate the docs 4 | 5 | # Information about the project. 6 | name: vtrace/vdb/vivisect 7 | url: http://visi.kenshoto.com/ 8 | 9 | # The list of modules to document. Modules can be named using 10 | # dotted names, module filenames, or package directory names. 11 | modules: cobra, envi, Elf, PE, vdb, visgraph, vqt, vstruct, vtrace, vivisect 12 | 13 | # Whether or not parsing should be used to examine objects. 14 | parse: yes 15 | 16 | # Whether or not introspection should be used to examine objects. 17 | introspect: no 18 | 19 | # Don't examine in any way the modules whose dotted name match this 20 | # regular expression pattern. 21 | exclude: vstruct\.defs\.windows\..* 22 | 23 | # Write html output to the directory "apidocs" 24 | output: html 25 | 26 | # Include all automatically generated graphs. These graphs are 27 | # generated using Graphviz dot. 28 | graph: all 29 | -------------------------------------------------------------------------------- /visgraph/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | The new visgraph package... 4 | 5 | Sigh... If you want something done right... 6 | ''' 7 | 8 | -------------------------------------------------------------------------------- /visgraph/cli.py: -------------------------------------------------------------------------------- 1 | ''' 2 | A package for a basic command interpreter for the graph. 3 | (and graph db...) 4 | ''' 5 | 6 | import sys 7 | import cmd 8 | 9 | import visgraph.dbcore as vg_dbcore 10 | import visgraph.pathcore as vg_pcore 11 | import visgraph.graphcore as vg_gcore 12 | 13 | class GraphCli(cmd.Cmd): 14 | 15 | def __init__(self, graph=None): 16 | cmd.Cmd.__init__(self) 17 | if graph == None: 18 | graph = vg_gcore.Graph() 19 | self.graph = graph 20 | 21 | def do_addnode(self, line): 22 | ''' 23 | Add a node with the given key=value properties on the CLI. 24 | (the property nid is special and MUST be an integer) 25 | ''' 26 | nid = self.graph.addNode() 27 | print 'Node %d added!' % nid 28 | 29 | def do_quit(self, line): 30 | ''' 31 | Exit the visgraph cli.... 32 | ''' 33 | raise SystemExit() 34 | 35 | #class GraphDBCli( 36 | 37 | def main(): 38 | cli = GraphCli() 39 | cli.cmdloop() 40 | 41 | if __name__ == '__main__': 42 | sys.exit(main()) 43 | 44 | -------------------------------------------------------------------------------- /visgraph/drawing/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Some utils for drawing... 3 | ''' 4 | -------------------------------------------------------------------------------- /visgraph/drawing/bezier.py: -------------------------------------------------------------------------------- 1 | 2 | def splitline(pt1, pt2, percent=0.5): 3 | ''' 4 | Return a point which splits the given line at the 5 | given percentage... 6 | 7 | Example: splitline( (0,0), (20, 30), 0.1) 8 | ''' 9 | 10 | pt1_x, pt1_y = pt1 11 | pt2_x, pt2_y = pt2 12 | 13 | deltax = (pt2_x - pt1_x) * percent 14 | deltay = (pt2_y - pt1_y) * percent 15 | 16 | return int(pt1_x + deltax), int(pt1_y + deltay) 17 | 18 | def calculate_bezier(points, steps = 30): 19 | ''' 20 | Arbitrary depth and arbitrary precision bezier implementation. Takes 21 | a list of (x,y) point tuples and returnes the points to draw for the 22 | bezier curve. 23 | ''' 24 | ret = [] 25 | points = [ (float(x),float(y)) for x,y in points ] 26 | 27 | for i in xrange(steps+1): 28 | 29 | pcent = i / float(steps) 30 | 31 | layers = [ points, ] 32 | while len(layers[-1]) != 1: 33 | l_points = layers[-1] 34 | newpoints = [ splitline( l_points[i], l_points[i+1], pcent) for i in xrange(len(l_points)-1) ] 35 | layers.append(newpoints) 36 | 37 | ret.append(layers[-1][0]) 38 | 39 | return ret 40 | 41 | if __name__ == '__main__': 42 | print calculate_bezier( [ (0,0), (3, 20), (20, 23), (20, 20)] ) 43 | 44 | print calculate_bezier( [ (0,0), (10,10) ], 10) 45 | 46 | -------------------------------------------------------------------------------- /visgraph/drawing/catmullrom.py: -------------------------------------------------------------------------------- 1 | 2 | def spline4p(t, p_1, p0, p1, p2): 3 | x_1a = t * ((2-t) * t - 1) * p_1[0] 4 | x_1b = t * ((2-t) * t - 1) * p_1[1] 5 | 6 | x0a = (t * t * (3 * t - 5) + 2) * p0[0] 7 | x0b = (t * t * (3 * t - 5) + 2) * p0[1] 8 | 9 | x1a = t * ((4 - 3 * t) * t + 1) * p1[0] 10 | x1b = t * ((4 - 3 * t) * t + 1) * p1[1] 11 | 12 | x2a = (t - 1) * t * t * p2[0] 13 | x2b = (t - 1) * t * t * p2[1] 14 | 15 | final = ( (x_1a + x0a + x1a + x2a) / 2, 16 | (x_1b + x0b + x1b + x2b) / 2) 17 | 18 | return final 19 | 20 | def calculate_catmullrom(points, steps = 30): 21 | ret = [] 22 | percents = [ step / float(steps) for step in range(steps) ] 23 | for i in xrange(1, len(points) - 2): 24 | for t in percents: 25 | ret.append(spline4p(t, points[i-1], points[i], points[i+1], points[i+2])) 26 | return ret 27 | 28 | 29 | -------------------------------------------------------------------------------- /visgraph/exc.py: -------------------------------------------------------------------------------- 1 | 2 | class VisGraphException(Exception): 3 | pass 4 | 5 | class DuplicateNode(VisGraphException): 6 | def __init__(self, node): 7 | Exception.__init__(self, repr(node)) 8 | self.node = node 9 | 10 | class NodeNonExistant(VisGraphException): 11 | def __init__(self, nodeid): 12 | self.nodeid = nodeid 13 | Exception.__init__(self, 'Node %d does not exist!' % nodeid) 14 | 15 | class EdgeNonExistant(VisGraphException): 16 | def __init__(self, edgeid): 17 | self.edgeid = edgeid 18 | Exception.__init__(self, 'Edge %d does not exist!' % edgeid) 19 | -------------------------------------------------------------------------------- /visgraph/layouts/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | A package for each of the different layout managers. 3 | ''' 4 | 5 | 6 | # Some helper utils... 7 | def exit_pos(ninfo): 8 | x,y = ninfo.get('position') 9 | xsize, ysize = ninfo.get('size', (0,0)) 10 | return (x + xsize/2, y + ysize) 11 | 12 | def entry_pos(ninfo): 13 | x,y = ninfo.get('position') 14 | xsize, ysize = ninfo.get('size', (0,0)) 15 | return (x + xsize/2, y) 16 | 17 | def center_pos(ninfo): 18 | x,y = ninfo.get('position') 19 | xsize, ysize = ninfo.get('size', (0,0)) 20 | return (x + (xsize/2), y + (ysize/2)) 21 | 22 | class GraphLayout: 23 | 24 | ''' 25 | A graph layout uses several graph meta properties and node properties 26 | to communicate with a renderer which is expected to display the graph: 27 | 28 | size = ( width, height ) - Set by the renderer 29 | position = ( x, y ) - Set by the layout 30 | repr = - A fallback for what to display on a node 31 | ''' 32 | 33 | def __init__(self, graph): 34 | self.graph = graph 35 | 36 | def layoutGraph(self): 37 | ''' 38 | Layout the graph nodes and edges 39 | ''' 40 | raise Exception('%s must implement layoutGraph()!' % self.__class__.__name__) 41 | 42 | def getLayoutSize(self): 43 | raise Exception('%s must implement getLayoutSize()!' % self.__class__.__name__) 44 | 45 | def renderGraph(self, rend): 46 | ''' 47 | Render the graph to the given renderer. 48 | ''' 49 | rend.setNodeSizes(self.graph) 50 | self.layoutGraph() 51 | width, height = self.getLayoutSize() 52 | self.graph.setMeta('size', (width, height) ) 53 | 54 | rend.renderGraph() 55 | -------------------------------------------------------------------------------- /visgraph/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/visgraph/tests/__init__.py -------------------------------------------------------------------------------- /vivisect/analysis/amd64/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 3 | Amd64 Analysis Modules 4 | 5 | ''' 6 | 7 | -------------------------------------------------------------------------------- /vivisect/analysis/crypto/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vivisect/analysis/crypto/__init__.py -------------------------------------------------------------------------------- /vivisect/analysis/elf/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | import vivisect 3 | 4 | import envi.bits as e_bits 5 | 6 | from vivisect.const import * 7 | 8 | def ffTermFptrArray(vw, va, max=100): 9 | ret = [] 10 | ffterm = e_bits.u_maxes[vw.psize] 11 | for i in xrange(max): 12 | 13 | ltup = vw.makeNumber(va, vw.psize) 14 | 15 | val = vw.parseNumber(va, vw.psize) 16 | if val == ffterm: 17 | return ret 18 | 19 | try: 20 | vw.makeFunction(val) 21 | ret.append(val) 22 | except Exception, e: 23 | print "FIXME (ffTermFptrArray): ",e 24 | va += vw.psize 25 | return ret 26 | 27 | def analyze(vw): 28 | 29 | # Go through the elf sections and handle known types. 30 | for segva,segsize,segname,segfname in vw.getSegments(): 31 | 32 | if segname == ".ctors": 33 | if vw.getLocation(segva) != None: # Check if it's already done 34 | continue 35 | for f in ffTermFptrArray(vw, segva): 36 | vw.makeName(f, "ctor_%.8x" % f) 37 | 38 | elif segname == ".dtors": 39 | if vw.getLocation(segva) != None: # Check if it's already done 40 | continue 41 | for f in ffTermFptrArray(vw, segva): 42 | vw.makeName(f, "dtor_%.8x" % f) 43 | 44 | elif segname == ".plt": 45 | pass 46 | # Do linear disassembly of the PLT here... 47 | -------------------------------------------------------------------------------- /vivisect/analysis/elf/elfplt.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | If a "function" is in the plt it's a wrapper for something in the GOT. 4 | Make that apparent. 5 | """ 6 | 7 | import vivisect 8 | import envi 9 | import envi.archs.i386 as e_i386 10 | import envi.archs.i386.opcode86 as opcode86 11 | 12 | def analyze(vw): 13 | """ 14 | Do simple linear disassembly of the .plt section if present. 15 | """ 16 | for sva,ssize,sname,sfname in vw.getSegments(): 17 | if sname != ".plt": 18 | continue 19 | nextva = sva + ssize 20 | while sva < nextva: 21 | vw.makeCode(sva) 22 | ltup = vw.getLocation(sva) 23 | sva += ltup[vivisect.L_SIZE] 24 | 25 | def analyzeFunction(vw, funcva): 26 | 27 | seg = vw.getSegment(funcva) 28 | if seg == None: 29 | return 30 | 31 | segva, segsize, segname, segfname = seg 32 | 33 | if segname != ".plt": 34 | return 35 | 36 | #FIXME check for i386 37 | op = vw.parseOpcode(funcva) 38 | if op.opcode != opcode86.INS_BRANCH: 39 | return 40 | 41 | loctup = None 42 | oper0 = op.opers[0] 43 | 44 | if isinstance(oper0, e_i386.i386ImmMemOper): 45 | 46 | loctup = vw.getLocation(oper0.getOperAddr(op)) 47 | 48 | elif isinstance(oper0, e_i386.i386RegMemOper): 49 | # FIXME this is i386 elf only! 50 | if oper0.reg != e_i386.REG_EBX: 51 | print "UNKNOWN PLT CALL",hex(funcva) 52 | got = vw.vaByName("%s._GLOBAL_OFFSET_TABLE_" % segfname) 53 | 54 | #FIXME this totally sucks 55 | if got == None: 56 | for va,size,name,fname in vw.getSegments(): 57 | if name == ".got.plt": 58 | got = va 59 | break 60 | 61 | if got != None: 62 | loctup = vw.getLocation(got+oper0.disp) 63 | 64 | if loctup == None: 65 | return 66 | 67 | if loctup[vivisect.L_LTYPE] != vivisect.LOC_IMPORT: 68 | return 69 | 70 | tinfo = loctup[vivisect.L_TINFO] 71 | lname,fname = tinfo.split(".") 72 | #vw.makeName(funcva, "plt_%s" % fname, filelocal=True) 73 | vw.makeFunctionThunk(funcva, tinfo) 74 | 75 | -------------------------------------------------------------------------------- /vivisect/analysis/generic/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vivisect/analysis/generic/__init__.py -------------------------------------------------------------------------------- /vivisect/analysis/generic/funcentries.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use the generic "signature" tree in the workspace to brute 3 | force attempt to find function entry points. This is 4 | slightly desperate, so do it late when most locations are 5 | already defined... Additionally, if the "pointers" generic 6 | module is run first, there is a reasonabily high likelyhood 7 | that the code this finds is dead... 8 | """ 9 | import traceback 10 | 11 | import envi 12 | import envi.memory as e_mem 13 | import vivisect 14 | 15 | def analyze(vw): 16 | """ 17 | Assuming that a bunch of functions have already been defined and 18 | fully analyzed, use the compiler against itself and attempt to 19 | brute force find other function entry points based on the 20 | entry signatures db. 21 | """ 22 | # FIXME make the below code an undefined space iterator 23 | # and use in findPointers too 24 | for mapva,mapsize,mapflags,fname in vw.getMemoryMaps(): 25 | 26 | # Segment permissions check for likely code stuff at all 27 | if not mapflags & e_mem.MM_EXEC: 28 | continue 29 | 30 | i = 0 31 | maxsize = mapsize - 4 32 | while i < maxsize: 33 | va = mapva + i 34 | loctup = vw.getLocation(va) 35 | if loctup != None: 36 | i += loctup[vivisect.L_SIZE] 37 | continue 38 | 39 | i+=1 40 | 41 | try: 42 | 43 | if vw.isFunctionSignature(va): 44 | #print "MATCH MATCH MATCH: 0x%.8x" % va 45 | vw.makeFunction(va) 46 | 47 | except vivisect.InvalidLocation, msg: 48 | if vw.verbose: vw.vprint("InvalidLocation: %s" % msg) 49 | except envi.InvalidInstruction, e: 50 | continue 51 | except envi.EnviException, msg: 52 | if vw.verbose: vw.vprint("%s: %s" % (msg.__class__.__name__,msg)) 53 | except Exception, msg: 54 | traceback.print_exc() 55 | continue 56 | 57 | -------------------------------------------------------------------------------- /vivisect/analysis/generic/impapi.py: -------------------------------------------------------------------------------- 1 | """ 2 | Function analysis module which sets function APIs based 3 | on function's name matching impapi. This should ideally go 4 | early in the module order to get the APIs marked asap. 5 | """ 6 | def analyzeFunction(vw, fva): 7 | fname = vw.getName(fva) 8 | api = vw.getImpApi(fname) 9 | if api == None: 10 | return 11 | 12 | rettype,retname,callconv,callname,callargs = api 13 | callargs = [ callargs[i] if callargs[i][1] else (callargs[i][0],'arg%d' % i) for i in xrange(len(callargs)) ] 14 | 15 | vw.setFunctionApi(fva, (rettype,retname,callconv,callname,callargs)) 16 | 17 | -------------------------------------------------------------------------------- /vivisect/analysis/generic/mkpointers.py: -------------------------------------------------------------------------------- 1 | """ 2 | generic workspace analysis module to seek through the undiscovered 3 | country looking for pointers to interesting things. 4 | 5 | in a previous life, this analysis code lived inside VivWorkspace.analyze() 6 | This will *actually* make pointers! 7 | """ 8 | def analyze(vw): 9 | 10 | if vw.verbose: vw.vprint('...analyzing pointers.') 11 | 12 | # Now, lets find likely free-hanging pointers 13 | for addr, pval in vw.findPointers(): 14 | try: 15 | vw.followPointer(pval) 16 | if vw.getLocation(addr) == None: 17 | # RP we need to make pointers out of what we find... 18 | # otherwise we miss a ton of functions because we mark sections exec when subsystem < win7 19 | vw.makePointer(addr) 20 | except Exception, e: 21 | if vw.verbose: vw.vprint("followPointer() failed for 0x%.8x (pval: 0x%.8x)" % (addr,pval)) 22 | 23 | -------------------------------------------------------------------------------- /vivisect/analysis/generic/pointers.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | generic workspace analysis module to seek through the undiscovered 4 | country looking for pointers to interesting things. 5 | 6 | in a previous life, this analysis code lived inside VivWorkspace.analyze() 7 | """ 8 | def analyze(vw): 9 | 10 | if vw.verbose: vw.vprint('...analyzing pointers.') 11 | 12 | # Now, lets find likely free-hanging pointers 13 | for addr, pval in vw.findPointers(): 14 | if vw.isDeadData(pval): 15 | continue 16 | try: 17 | vw.followPointer(pval) 18 | except Exception, e: 19 | if vw.verbose: vw.vprint("followPointer() failed for 0x%.8x (pval: 0x%.8x)" % (addr,pval)) 20 | 21 | -------------------------------------------------------------------------------- /vivisect/analysis/generic/pointertables.py: -------------------------------------------------------------------------------- 1 | """ 2 | A quick and dirty analysis pass looking for pointer arrays. Pointers 3 | in code regions are trixy because they might be immediate operands on 4 | instructions. However, if they are pointer-length aligned *and* back-to-back 5 | they are probably really pointers... 6 | """ 7 | 8 | import vivisect 9 | from vivisect.const import * 10 | 11 | def handleArray(vw, plist): 12 | tlist = [] 13 | 14 | for va,targ in plist: 15 | if vw.getLocation(va) == None: 16 | vw.makePointer(va) 17 | loctup = vw.getLocation(targ) 18 | if loctup != None: 19 | ltype = loctup[L_LTYPE] 20 | if ltype not in tlist: 21 | tlist.append(ltype) 22 | 23 | def analyze(vw): 24 | 25 | #FIXME this won't do anything on a second pass and it might be good if it did 26 | align = vw.arch.getPointerSize() 27 | rlen = vw.config.viv.analysis.pointertables.table_min_len 28 | 29 | plist = [] 30 | for va, pval in vw.findPointers(): 31 | 32 | if len(plist): 33 | 34 | lastva, lastptr = plist[-1] 35 | 36 | # If we maybe hit a pointer in the middle 37 | if lastva != va - align: 38 | nloc = vw.getLocation(lastva+align) 39 | while nloc != None: 40 | if nloc[L_LTYPE] != LOC_POINTER: 41 | break 42 | lva = nloc[L_VA] 43 | plist.append((lva, vw.castPointer(lva))) 44 | nloc = vw.getLocation(lva + nloc[L_SIZE]) 45 | 46 | if lastva != va - align: 47 | if len(plist) > rlen: 48 | handleArray(vw, plist) 49 | plist = [] 50 | 51 | plist.append((va,pval)) 52 | 53 | # Handle possible last plist 54 | if len(plist) > rlen: 55 | handleArray(vw, plist) 56 | -------------------------------------------------------------------------------- /vivisect/analysis/generic/relocations.py: -------------------------------------------------------------------------------- 1 | """ 2 | An analysis module which checks that all relocations *targets* 3 | point to valid locations. 4 | """ 5 | 6 | import vivisect 7 | 8 | def analyze(vw): 9 | for va, rtype in vw.getRelocations(): 10 | if rtype == vivisect.RTYPE_BASERELOC and not vw.isLocation(va): 11 | vw.makePointer(va, follow=True) 12 | -------------------------------------------------------------------------------- /vivisect/analysis/generic/strconst.py: -------------------------------------------------------------------------------- 1 | import envi 2 | from vivisect.const import * 3 | 4 | 5 | def analyze(vw): 6 | ''' 7 | Find string constants used in function calls and add them to the 8 | workspace location set. The goal is to identify string constants 9 | for symboliks parsing, where they become string arguments. 10 | 11 | Functions and xrefs have already been identified. Analysis of opcodes 12 | is closely related to the makeOpcode() logic in vivisect/__init__.py. 13 | ''' 14 | 15 | for fva in vw.getFunctions(): 16 | for va, size, funcva in vw.getFunctionBlocks(fva): 17 | maxva = va+size 18 | while va < maxva: 19 | op = vw.parseOpcode(va) 20 | for o in op.opers: 21 | if o.isDeref(): 22 | continue 23 | ref = o.getOperValue(op, None) 24 | 25 | # Candidates will be listed with the Xrefs thanks to 26 | # logic in makeOpcode(). 27 | if not (vw.getXrefsTo(ref) and vw.getXrefsFrom(va)): 28 | continue 29 | 30 | # String constants must be in a defined memory segment. 31 | if not vw.getSegment(ref): 32 | continue 33 | 34 | # Look for Unicode before ASCII to catch UTF-16 LE. 35 | sz = vw.detectUnicode(ref) 36 | if sz > 0: 37 | vw.addLocation(ref, sz, LOC_UNI) 38 | else: 39 | sz = vw.detectString(ref) 40 | if sz > 0: 41 | vw.addLocation(ref, sz, LOC_STRING) 42 | 43 | va += len(op) 44 | return 45 | -------------------------------------------------------------------------------- /vivisect/analysis/generic/thunks.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | A simple analysis module to detect import thunks. 4 | """ 5 | 6 | import envi 7 | import vivisect 8 | 9 | def analyzeFunction(vw, funcva): 10 | 11 | for fromva, tova, rtype, rflags in vw.getXrefsFrom(funcva, vivisect.REF_CODE): 12 | 13 | # You goin NOWHERE! 14 | loc = vw.getLocation(tova) 15 | if loc == None: 16 | continue 17 | 18 | # FIXME this could check for thunks to other known function pointers... 19 | 20 | va, size, ltype, linfo = loc 21 | if ltype != vivisect.LOC_IMPORT: 22 | continue 23 | 24 | vw.makeFunctionThunk(funcva, linfo) 25 | 26 | -------------------------------------------------------------------------------- /vivisect/analysis/i386/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Some utilities related to i386 analysis. Loaders and analysis 4 | modules may use these as needed... 5 | """ 6 | 7 | sigs = [ 8 | ("558bec", "ffffff"), # push ebp; mov ebp,esp; Intel/Microsoft 9 | ("568bf1", "ffffff"), # push esi; mov esi,ecx (c++) 10 | ("5589e5", "ffffff"), # push ebp; mov ebp,esp; GCC 11 | ("8bff558bec", "ffffffffff"), # mov edi,edi; push ebp; mov epb, esp 12 | # Ok... here's where things get cool... 13 | # This is push , push , call # ms seh setup entry 14 | ("6a006800000000e8", "ff00ff00000000ff") 15 | ] 16 | 17 | def addEntrySigs(vw): 18 | for sigstr, maskstr in sigs: 19 | bytes = sigstr.decode('hex') 20 | masks = maskstr.decode('hex') 21 | vw.addFunctionSignatureBytes(bytes, masks) 22 | 23 | -------------------------------------------------------------------------------- /vivisect/analysis/i386/importcalls.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | An analysis module that looks for likely *code* pointers by 4 | checking for them to be pointing to imports and having 5 | "call [deref]" bytes before them. 6 | """ 7 | 8 | import vivisect 9 | from vivisect.const import * 10 | 11 | def analyze(vw): 12 | 13 | for va,dest in vw.findPointers(): 14 | # Is there a location already at the target? 15 | loc = vw.getLocation(dest) 16 | if loc == None: 17 | continue 18 | 19 | if loc[L_LTYPE] != LOC_IMPORT: 20 | continue 21 | 22 | offset,bytes = vw.getByteDef(va) 23 | if offset < 2: 24 | continue 25 | 26 | if bytes[offset-2:offset] == "\xff\x15": # call [importloc] 27 | # If there's a pointer here, remove it. 28 | if vw.getLocation(va): 29 | vw.delLocation(va) 30 | vw.makeCode(va-2) 31 | -------------------------------------------------------------------------------- /vivisect/analysis/i386/thunk_bx.py: -------------------------------------------------------------------------------- 1 | import vivisect 2 | 3 | thunk_bx_sig = '8b1c24c3'.decode('hex') 4 | def analyzeFunction(vw, fva): 5 | ''' 6 | this analysis module will identify thunk_bx functions, which take the return value and place 7 | it into EBX. this is done for position-independent code in i386 elf binaries. a call to this 8 | function will be followed by an immediate add to find the start of the module. that value is 9 | then used with fixed offsets to access resources within the binary. it's a bit like the old 10 | shellcode trick. 11 | 12 | store funcva in "thunk_bx" VaSet in case we identify multiples (not likely) or misidentify 13 | something. 14 | 15 | then store the module base in metadata as "PIE_ebx", accessible by other analysis modules. 16 | ''' 17 | if vw.readMemory(fva, 4) == thunk_bx_sig: 18 | 19 | # have we already recorded this thunk_bx? 20 | if vw.getVaSetRow('thunk_bx', fva) != None: 21 | if vw.verbose: print("ditching thunk_bx: %s") 22 | return 23 | 24 | vw.setVaSetRow('thunk_bx', (fva,)) 25 | 26 | 27 | # determine where ebx ends up pointing to 28 | # this requires checking the calling function's next instruction 29 | refs = vw.getXrefsTo(fva) 30 | if refs == None or not len(refs): 31 | return 32 | 33 | va = refs[0][0] 34 | op = vw.parseOpcode(va) 35 | op2 = vw.parseOpcode(va + len(op)) 36 | if op2.mnem != "add": 37 | if vw.verbose: print("call to thunk_bx not followed by an add: %s" % op2) 38 | return 39 | 40 | addt = op2.opers[1].getOperValue(op2) 41 | ebx = op2.va + addt 42 | if vw.getMeta('PIE_ebx') != None: 43 | return 44 | 45 | if vw.verbose: print("__x86.get_pc_thunk.bx: ", hex(ebx)) 46 | curname = vw.getName(fva) 47 | if curname == None or curname == "sub_%.8x"%fva: 48 | vw.makeName(fva, "thunk_bx_%.8x"%fva) 49 | 50 | vw.setMeta('PIE_ebx', ebx) 51 | -------------------------------------------------------------------------------- /vivisect/analysis/ms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vivisect/analysis/ms/__init__.py -------------------------------------------------------------------------------- /vivisect/analysis/ms/hotpatch.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | A function analysis module to detect and properly mark 4 | microsoft hotpatch pads... 5 | """ 6 | 7 | import vivisect 8 | 9 | def analyzeFunction(vw, funcva): 10 | 11 | offset, bytes = vw.getByteDef(funcva) 12 | ob = ord(bytes[offset-1]) 13 | if ob not in [0x90, 0xcc]: 14 | return 15 | 16 | count = 1 17 | newb = ord(bytes[offset-count]) 18 | while newb == ob: 19 | count += 1 20 | newb = ord(bytes[offset-count]) 21 | 22 | count -= 1 23 | 24 | va = funcva - count 25 | if count >= 5 and not vw.isLocation(va): 26 | vw.makePad(va, count) 27 | 28 | -------------------------------------------------------------------------------- /vivisect/analysis/ms/localhints.py: -------------------------------------------------------------------------------- 1 | 2 | def analyze(vw): 3 | 4 | for fname in vw.getFiles(): 5 | 6 | h = vw.getFileMeta(fname, 'PELocalHints', None) 7 | if h == None: 8 | continue 9 | 10 | for fva, hints in h.items(): 11 | if not vw.isFunction(fva): 12 | vw.makeFunction(fva) 13 | 14 | for name, offset, size, flags in hints: 15 | 16 | if offset > 0: 17 | # Take 2 away for offset from frame.... 18 | offset = offset - (vw.psize * 2) 19 | idx = offset / vw.psize 20 | 21 | if idx > 100: 22 | continue 23 | 24 | print('FIXME: %d %s' % (name,offset)) 25 | 26 | #atype, aname = vw.getFunctionArg(fva, idx) 27 | #if atype == None: 28 | #atype = viv_magic.Unknown 29 | #print 'ARG',idx, name 30 | #vw.setFunctionArg(fva, idx, atype, name) 31 | 32 | elif offset < 0: 33 | # "offset" is from frame, *we* are from initial esp... 34 | offset -= vw.psize 35 | vw.setFunctionLocal(fva, offset, None, name) 36 | 37 | -------------------------------------------------------------------------------- /vivisect/analysis/ms/msvc.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | An emulation module to detect SEH setup and apply structs where possible. 4 | """ 5 | 6 | import vivisect.vamp.msvc as v_msvc 7 | from vivisect.const import * 8 | 9 | vs = v_msvc.VisualStudioVamp() 10 | 11 | def analyzeFunction(vw, funcva): 12 | 13 | offset, bytes = vw.getByteDef(funcva) 14 | sig = vs.getSignature(bytes, offset) 15 | if sig != None: 16 | fname = sig.split(".")[-1] 17 | vw.makeName(funcva, "%s_%.8x" % (fname,funcva), filelocal=True) 18 | vw.makeFunctionThunk(funcva, sig) 19 | -------------------------------------------------------------------------------- /vivisect/analysis/ms/msvcfunc.py: -------------------------------------------------------------------------------- 1 | import envi.archs.i386.opcode86 as e_opcode86 2 | def analyze(vw): 3 | 4 | for fva in vw.getFunctions(): 5 | fname =vw.getName(fva) 6 | # XXX - get func by name 7 | # find the security_check_cookie function 8 | if fname.startswith('security_check_cookie'): 9 | # parse teh first opcode in the function 10 | op = vw.parseOpcode(fva) 11 | if len(op.opers) != 2: 12 | return 13 | 14 | gscookie = None 15 | if op.opers[1].isDeref(): 16 | # get the address of the cookie 17 | gscookie = op.opers[1].getOperAddr(op, None) 18 | 19 | if not gscookie: 20 | return 21 | 22 | # iterate over all references to the cookie 23 | for fromva, tova, rtype, rflags in vw.getXrefsTo(gscookie): 24 | op = vw.parseOpcode(fromva) 25 | cb = vw.getCodeBlock(fromva) 26 | if not cb: 27 | continue 28 | 29 | va, cbsize, funcva = cb 30 | # if the start of the code block containing a reference to the gs cookie location isn't a function then we need to make it 31 | # XXX - do we want to hard code mov or use a flag?? If so which flag? 32 | if not vw.isFunction(va) and op.mnem == 'mov': 33 | vw.makeFunction(va) 34 | 35 | -------------------------------------------------------------------------------- /vivisect/analysis/ms/vftables.py: -------------------------------------------------------------------------------- 1 | """ 2 | Attempt to find locations that are likely vftable arrays 3 | by finding lists of function pointers in memory. 4 | 5 | This should be a *late* pass after all code that is possible 6 | is defined. 7 | """ 8 | import vivisect 9 | 10 | def analyze(vw): 11 | 12 | psize = vw.arch.getPointerSize() 13 | 14 | #for lva,lsize,ltype,tinfo in vw.getLocations(vivisect.LOC_POINTER): 15 | for lva, pval in vw.findPointers(): 16 | xrto = vw.getXrefsFrom(lva) 17 | if not xrto: 18 | continue 19 | 20 | if not vw.isFunction(xrto[0][vivisect.XR_TO]): 21 | continue 22 | 23 | count = 1 24 | va = lva + psize 25 | while True: 26 | 27 | if vw.getLocation(va) != None: 28 | break 29 | 30 | ptrva = vw.castPointer(va) 31 | #FIXME this might make us miss stuff 32 | if not vw.isFunction(ptrva): 33 | #print "SKIPPING:",hex(ptrva) 34 | break 35 | 36 | count += 1 37 | va += psize 38 | 39 | if count >= 4: 40 | print "VFTABLE? 0x%.8x" % ptrva 41 | 42 | -------------------------------------------------------------------------------- /vivisect/analysis/pe.py: -------------------------------------------------------------------------------- 1 | """ 2 | PE Extended analysis module. 3 | """ 4 | 5 | import vivisect 6 | import envi.bits as e_bits 7 | 8 | def analyze(vw): 9 | """ 10 | """ 11 | # Go through the relocations and create locations for them 12 | for segva,segsize,segname,segfname in vw.getSegments(): 13 | reloc_va = vw.getFileMeta(segfname, "reloc_va") 14 | # Found binaries with multiple sections named .reloc where one was iat another 15 | # was actual reloc 16 | if reloc_va != segva: 17 | continue 18 | 19 | offset, bytes = vw.getByteDef(segva) 20 | while offset < segsize: 21 | # error cehck to make sure we are providing four bytes 22 | # to the parse routine 23 | if len(bytes[offset+4:offset+8]) != 4: 24 | break 25 | 26 | basepage = e_bits.parsebytes(bytes, offset, 4) 27 | 28 | vaoff = segva + offset 29 | vw.makeNumber(vaoff, 4) 30 | vw.makeName(vaoff, "reloc_chunk_%.8x" % vaoff) 31 | 32 | recsize = e_bits.parsebytes(bytes, offset+4, 4) 33 | if offset + recsize > segsize: 34 | break 35 | vw.makeNumber(segva+offset+4, 4) 36 | 37 | ioff = offset + 8 38 | while ioff < offset+recsize: 39 | vw.makeNumber(segva + ioff, 2) 40 | ioff += 2 41 | 42 | offset += recsize 43 | if recsize == 0: 44 | break 45 | 46 | 47 | -------------------------------------------------------------------------------- /vivisect/colormap.py: -------------------------------------------------------------------------------- 1 | 2 | import vivisect.exc as viv_exc 3 | 4 | class VivColorMap: 5 | ''' 6 | An easier to use color map object. 7 | ''' 8 | 9 | def __init__(self, vw): 10 | self.vw = vw 11 | self.cmap = {} 12 | 13 | def colorVa(self, va, color): 14 | ''' 15 | Set the color for a particular virtual memory location 16 | when viewed with this color map. 17 | 18 | Example: m.colorVa(va, 'red') 19 | ''' 20 | self.cmap[va] = color 21 | 22 | def colorBlock(self, va, color): 23 | ''' 24 | Similar to colorVa(), but loops coloring all the virtual 25 | addresses in the given block. 26 | ''' 27 | cbtup = self.vw.getCodeBlock(va) 28 | if cbtup == None: 29 | raise viv_exc.InvalidCodeBlock(va) 30 | 31 | cbva, cbsize, fva = cbtup 32 | for i in xrange(cbsize): 33 | self.cmap[cbva + i] = color 34 | 35 | def colorFunction(self, fva, color): 36 | ''' 37 | Similar to colorVa(), but loops coloring all the virtual 38 | addresses in the given function. 39 | ''' 40 | fva = self.vw.getFunction(fva) 41 | for cbva, cbsize, fva in self.vw.getFunctionBlocks(fva): 42 | for i in xrange(cbsize): 43 | self.cmap[cbva + i] = color 44 | 45 | def saveAs(self, name): 46 | ''' 47 | Save the color map to the workspace with the given name. 48 | ''' 49 | self.vw.addColorMap(name, dict(self.cmap)) 50 | 51 | def setGuiMap(self): 52 | ''' 53 | Set this as the display color map for the vivisect gui. (obviously 54 | only works when GUI is running...) 55 | ''' 56 | self.vw._viv_gui.setColorMap(self.cmap) 57 | 58 | def getColorDict(self): 59 | return dict(self.cmap) 60 | 61 | -------------------------------------------------------------------------------- /vivisect/contrib/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | # Add the contrib directories to our python path 5 | contribdir = os.path.dirname( __file__ ) 6 | if os.path.isdir( contribdir ): 7 | 8 | for contrib in os.listdir( contribdir ): 9 | 10 | contpath = os.path.join( contribdir, contrib ) 11 | 12 | if not os.path.isdir( contpath ): 13 | if contrib.endswith('.egg'): 14 | sys.path.insert(0, contpath) 15 | 16 | continue 17 | 18 | if contrib.startswith('.'): 19 | continue 20 | 21 | #sys.path.append( contpath ) 22 | sys.path.insert(0, contpath) 23 | 24 | -------------------------------------------------------------------------------- /vivisect/contrib/ply/EGG-INFO/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.0 2 | Name: ply 3 | Version: 3.4 4 | Summary: Python Lex & Yacc 5 | Home-page: http://www.dabeaz.com/ply/ 6 | Author: David Beazley 7 | Author-email: dave@dabeaz.com 8 | License: BSD 9 | Description: 10 | PLY is yet another implementation of lex and yacc for Python. Some notable 11 | features include the fact that its implemented entirely in Python and it 12 | uses LALR(1) parsing which is efficient and well suited for larger grammars. 13 | 14 | PLY provides most of the standard lex/yacc features including support for empty 15 | productions, precedence rules, error recovery, and support for ambiguous grammars. 16 | 17 | PLY is extremely easy to use and provides very extensive error checking. 18 | It is compatible with both Python 2 and Python 3. 19 | 20 | Platform: UNKNOWN 21 | Classifier: Programming Language :: Python :: 3 22 | Classifier: Programming Language :: Python :: 2 23 | -------------------------------------------------------------------------------- /vivisect/contrib/ply/EGG-INFO/SOURCES.txt: -------------------------------------------------------------------------------- 1 | README 2 | setup.py 3 | ply/__init__.py 4 | ply/cpp.py 5 | ply/ctokens.py 6 | ply/lex.py 7 | ply/yacc.py 8 | ply.egg-info/PKG-INFO 9 | ply.egg-info/SOURCES.txt 10 | ply.egg-info/dependency_links.txt 11 | ply.egg-info/top_level.txt 12 | test/testlex.py 13 | test/testyacc.py -------------------------------------------------------------------------------- /vivisect/contrib/ply/EGG-INFO/dependency_links.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /vivisect/contrib/ply/EGG-INFO/top_level.txt: -------------------------------------------------------------------------------- 1 | ply 2 | -------------------------------------------------------------------------------- /vivisect/contrib/ply/EGG-INFO/zip-safe: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /vivisect/contrib/ply/ply/__init__.py: -------------------------------------------------------------------------------- 1 | # PLY package 2 | # Author: David Beazley (dave@dabeaz.com) 3 | 4 | __all__ = ['lex','yacc'] 5 | -------------------------------------------------------------------------------- /vivisect/contrib/pycparser/pycparser/_build_tables.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------- 2 | # pycparser: _build_tables.py 3 | # 4 | # A dummy for generating the lexing/parsing tables and and 5 | # compiling them into .pyc for faster execution in optimized mode. 6 | # Also generates AST code from the configuration file. 7 | # Should be called from the pycparser directory. 8 | # 9 | # Copyright (C) 2008-2012, Eli Bendersky 10 | # License: BSD 11 | #----------------------------------------------------------------- 12 | 13 | # Generate c_ast.py 14 | # 15 | from _ast_gen import ASTCodeGenerator 16 | ast_gen = ASTCodeGenerator('_c_ast.cfg') 17 | ast_gen.generate(open('c_ast.py', 'w')) 18 | 19 | import sys 20 | sys.path[0:0] = ['.', '..'] 21 | from pycparser import c_parser 22 | 23 | # Generates the tables 24 | # 25 | c_parser.CParser( 26 | lex_optimize=True, 27 | yacc_debug=False, 28 | yacc_optimize=True) 29 | 30 | # Load to compile into .pyc 31 | # 32 | import lextab 33 | import yacctab 34 | import c_ast 35 | -------------------------------------------------------------------------------- /vivisect/contrib/pycparser/pycparser/ply/LICENSE: -------------------------------------------------------------------------------- 1 | This is Ply 3.4, which is copyrighted by David Beazley. 2 | It's licensed under BSD and re-distributed with pycparser in accordance 3 | with this license. Please see PLY's website for more details: 4 | http://www.dabeaz.com/ply 5 | 6 | -------------------------------------------------------------------------------- /vivisect/contrib/pycparser/pycparser/ply/__init__.py: -------------------------------------------------------------------------------- 1 | # PLY package 2 | # Author: David Beazley (dave@dabeaz.com) 3 | 4 | __all__ = ['lex','yacc'] 5 | -------------------------------------------------------------------------------- /vivisect/contrib/pycparser/pycparser/plyparser.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------- 2 | # plyparser.py 3 | # 4 | # PLYParser class and other utilites for simplifying programming 5 | # parsers with PLY 6 | # 7 | # Copyright (C) 2008-2012, Eli Bendersky 8 | # License: BSD 9 | #----------------------------------------------------------------- 10 | 11 | 12 | class Coord(object): 13 | """ Coordinates of a syntactic element. Consists of: 14 | - File name 15 | - Line number 16 | - (optional) column number, for the Lexer 17 | """ 18 | def __init__(self, file, line, column=None): 19 | self.file = file 20 | self.line = line 21 | self.column = column 22 | 23 | def __str__(self): 24 | str = "%s:%s" % (self.file, self.line) 25 | if self.column: str += ":%s" % self.column 26 | return str 27 | 28 | 29 | class ParseError(Exception): pass 30 | 31 | 32 | class PLYParser(object): 33 | def _create_opt_rule(self, rulename): 34 | """ Given a rule name, creates an optional ply.yacc rule 35 | for it. The name of the optional rule is 36 | _opt 37 | """ 38 | optname = rulename + '_opt' 39 | 40 | def optrule(self, p): 41 | p[0] = p[1] 42 | 43 | optrule.__doc__ = '%s : empty\n| %s' % (optname, rulename) 44 | optrule.__name__ = 'p_%s' % optname 45 | setattr(self.__class__, optrule.__name__, optrule) 46 | 47 | def _coord(self, lineno, column=None): 48 | return Coord( 49 | file=self.clex.filename, 50 | line=lineno, 51 | column=column) 52 | 53 | def _parse_error(self, msg, coord): 54 | raise ParseError("%s: %s" % (coord, msg)) 55 | 56 | -------------------------------------------------------------------------------- /vivisect/emutils.py: -------------------------------------------------------------------------------- 1 | import envi 2 | import envi.memory as e_mem 3 | 4 | class WorkspaceMemoryObject(e_mem.MemoryObject): 5 | 6 | def __init__(self, vw, maps, nosegfault=False): 7 | self.vw = vw 8 | self.nosegfault = nosegfault 9 | e_mem.MemoryObject.__init__(self, maps) 10 | 11 | #FIXME make this copy on write from the workspace 12 | 13 | def readMemory(self, va, size): 14 | if self.checkMemory(va): 15 | return e_mem.MemoryObject.readMemory(self, va, size) 16 | if self.vw.getSegment(va) != None: 17 | return self.vw.readMemory(va, size) 18 | # We don't have it 19 | if self.nosegfault: 20 | return "A"*size 21 | raise envi.SegmentationViolation(va) 22 | 23 | 24 | -------------------------------------------------------------------------------- /vivisect/exc.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | All the exception types raised by workspace APIs go here. 4 | """ 5 | 6 | class InvalidLocation(Exception): 7 | def __init__(self, va, msg=None): 8 | Exception.__init__(self, "Invalid Location 0x%.8x: %s" % (va,msg)) 9 | 10 | class DuplicateName(Exception): 11 | def __init__(self, origva, newva, name): 12 | Exception.__init__(self, "Duplicate Name: %s at 0x%.8x and 0x%.8x" % (name,origva,newva)) 13 | 14 | class InvalidVaSet(Exception): 15 | def __init__(self, name): 16 | Exception.__init__(self, "Invalid Va Set Specified: %s" % name) 17 | 18 | class InvalidFunction(Exception): 19 | def __init__(self, va): 20 | Exception.__init__(self, "VA 0x%.8x is not a function" % va) 21 | 22 | class InvalidCodeBlock(Exception): 23 | def __init__(self, cbva): 24 | Exception.__init__(self, 'VA 0x%.8x is not in a code block!' % va) 25 | 26 | class UnknownCallingConvention(Exception): 27 | def __init__(self, fva, cc=None): 28 | Exception.__init__(self, "Function 0x%.8x has unknown CallingConvention: %s" % (fva, cc)) 29 | 30 | class InvalidWorkspace(Exception): 31 | """ 32 | Raised when a storage module is given bunk data for loading 33 | a workspace. 34 | """ 35 | def __init__(self, nameinfo, errinfo): 36 | Exception.__init__(self, "Failed to load %s: %s" % (nameinfo, errinfo)) 37 | -------------------------------------------------------------------------------- /vivisect/extensions/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import imp 3 | import traceback 4 | 5 | ''' 6 | Extensions for vivisect may be implemented as python 7 | modules which contain the function "vivExtension". 8 | 9 | All ";" seperated directories listed in the VIV_EXT_PATH 10 | environment variable will be searched for ".py" python 11 | modules which implement "vivExtension" 12 | 13 | The module's vivExtension function takes a vivisect workspace 14 | (vw) and an vivisect gui reference (if present). 15 | ''' 16 | 17 | def loadExtensions( vw, vwgui ): 18 | 19 | extdir = os.getenv('VIV_EXT_PATH') 20 | 21 | if extdir == None: 22 | return 23 | 24 | for dirname in extdir.split(';'): 25 | 26 | if not os.path.isdir(dirname): 27 | vw.vprint('Invalid VIV_EXT_PATH dir: %s' % dirname) 28 | continue 29 | 30 | for fname in os.listdir(dirname): 31 | 32 | if not fname.endswith('.py'): 33 | continue 34 | 35 | # Build code objects from the module files 36 | mod = imp.new_module('viv_ext') 37 | filepath = os.path.join(dirname, fname) 38 | filebytes = file( filepath, 'r' ).read() 39 | mod.__file__ = filepath 40 | try: 41 | exec filebytes in mod.__dict__ 42 | mod.vivExtension(vw, vwgui) 43 | except Exception, e: 44 | vw.vprint( traceback.format_exc() ) 45 | vw.vprint('Extension Error: %s' % filepath) 46 | 47 | -------------------------------------------------------------------------------- /vivisect/extensions/example_gui_extension.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtGui,QtCore 2 | from vqt.main import idlethread 3 | from vqt.basics import VBox 4 | 5 | ''' 6 | This is an example of a vivisect GUI extension module. 7 | Set the environment variable VIV_EXT_PATH to point at a 8 | directory full of python modules such as this to extend 9 | and implement your own vivisect features. 10 | ''' 11 | 12 | class ExampleToolbar(QtGui.QToolBar): 13 | def __init__(self, vw, vwgui): 14 | self.vw = vw 15 | self.vwgui = vwgui 16 | 17 | QtGui.QToolBar.__init__(self, parent=vwgui) 18 | self.addWidget( QtGui.QLabel('Example Toolbar:', parent=self) ) 19 | self.addAction('ONE', self.doOne) 20 | 21 | def doOne(self): 22 | self.vw.vprint('did one!') 23 | 24 | class ExampleWindow(QtGui.QWidget): 25 | def __init__(self, vw, vwgui): 26 | self.vw = vw 27 | self.vwgui = vwgui 28 | 29 | QtGui.QWidget.__init__(self, parent=vwgui) 30 | self.setWindowTitle('Example Window!') 31 | button = QtGui.QPushButton('My Button!', parent=self) 32 | textedit = QtGui.QTextEdit('WOOT! Some text!', parent=self) 33 | self.setLayout( VBox(button, textedit) ) 34 | 35 | @idlethread 36 | def vivExtension(vw, vwgui): 37 | toolbar = ExampleToolbar(vw, vwgui) 38 | vwgui.addToolBar(QtCore.Qt.TopToolBarArea, toolbar) 39 | 40 | window = ExampleWindow(vw, vwgui) 41 | d = vwgui.vqDockWidget(window, floating=True) 42 | d.resize(300,200) 43 | -------------------------------------------------------------------------------- /vivisect/impapi/gentool.py: -------------------------------------------------------------------------------- 1 | ''' 2 | A very simple tool for generating import API definitions from a viv 3 | workspace... 4 | ''' 5 | import sys 6 | import vivisect 7 | 8 | type_lookup = { 9 | 'Unknown':'int', 10 | 'Pointer':'void *', 11 | 'FUNCPTR':'void *', 12 | 'ObjectRef':'void *', 13 | } 14 | 15 | name_lookup = { 16 | 'DWORD':None, 17 | 'Unknown':None, 18 | 'Pointer':'ptr', 19 | 'ObjectRef':'obj', 20 | 'FUNCPTR':'funcptr' 21 | } 22 | 23 | def main(): 24 | 25 | sys.stdout.write("# ") 26 | vw = vivisect.VivWorkspace() 27 | vw.loadWorkspace(sys.argv[1]) 28 | 29 | print '# %s' % sys.argv[1] 30 | 31 | fnames = {} 32 | 33 | for fva, etype, ename, fname in vw.getExports(): 34 | 35 | enamekey = ename.lower() 36 | fnamekey = fname.lower() 37 | 38 | fnames[fname] = True 39 | 40 | # Skip past forwarders 41 | if not vw.isFunction(fva): 42 | continue 43 | 44 | 45 | rtype, rname, ccname, funcname, args = vw.getFunctionApi(fva) 46 | argv = tuple([ (type_lookup.get(t, t), name_lookup.get(t)) for t,name in args ]) 47 | #argv = tuple([ (type_lookup.get(t.__name__, t.__name__), name_lookup.get(t.__name__)) for t,name in vw.getFunctionArgs(fva) ]) 48 | #rtype = vw.getFunctionMeta(fva, 'ReturnType', 'int') 49 | #ccname = vw.getFunctionMeta(fva, 'CallingConvention') 50 | print " '%s.%s':( %r, None, %r, '%s.%s', %r )," % (fnamekey,enamekey,rtype,ccname,fname,ename,argv) 51 | 52 | for fwdfname in fnames.keys(): 53 | 54 | for rva, name, fwdname in vw.getFileMeta(fwdfname, 'forwarders', ()): 55 | fwdapi = vw.getImpApi( fwdname ) 56 | if not fwdapi: 57 | print(' # FIXME unresolved %s -> %s' % (name, fwdname)) 58 | continue 59 | 60 | print(" '%s.%s':%r," % ( fwdfname.lower(), name.lower(), fwdapi)) 61 | 62 | if __name__ == '__main__': 63 | sys.exit(main()) 64 | 65 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vivisect/impapi/windows/__init__.py -------------------------------------------------------------------------------- /vivisect/impapi/windows/advapi_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit advapi library. 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [] 9 | 10 | # Define any functions specific to 64-bit. 11 | api_64_adds = { 12 | } 13 | 14 | 15 | # Build from the 32-bit API, skipping omits, changing the calling convention, 16 | # and adding any specific 64-bit functions. 17 | api_defs_64 = {} 18 | 19 | import vivisect.impapi.windows.advapi_32 as m32 20 | for name in m32.api_defs.iterkeys(): 21 | if name in api_32_omits: 22 | continue 23 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 24 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 25 | api_defs_64.update(api_64_adds) 26 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/gdi_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit gdi32 library. 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [] 9 | 10 | # Define any functions specific to 64-bit. 11 | api_64_adds = { 12 | } 13 | 14 | 15 | # Build from the 32-bit API, skipping omits, changing the calling convention, 16 | # and adding any specific 64-bit functions. 17 | api_defs_64 = {} 18 | 19 | import vivisect.impapi.windows.gdi_32 as m32 20 | for name in m32.api_defs.iterkeys(): 21 | if name in api_32_omits: 22 | continue 23 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 24 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 25 | api_defs_64.update(api_64_adds) 26 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/kernel_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit kernel32 library 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [] 9 | 10 | # Define any functions specific to 64-bit. 11 | api_64_adds = { 12 | } 13 | 14 | 15 | # Build from the 32-bit API, skipping omits, changing the calling convention, 16 | # and adding any specific 64-bit functions. 17 | api_defs_64 = {} 18 | 19 | import vivisect.impapi.windows.kernel_32 as m32 20 | for name in m32.api_defs.iterkeys(): 21 | if name in api_32_omits: 22 | continue 23 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 24 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 25 | api_defs_64.update(api_64_adds) 26 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/msvcr100_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit MSVC 2010 runtime library (msvcr100). 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [ 9 | 'msvcr100.??2@yapaxi@z', 10 | 'msvcr100.??_u@yapaxi@z', 11 | 'msvcr100.??3@yaxpax@z', 12 | 'msvcr100.??_v@yaxpax@z' 13 | ] 14 | 15 | # Define any functions specific to 64-bit. 16 | api_64_adds = { 17 | 'msvcr100.??2@yapeax_k@z':( 'int', None, 'cdecl', 'msvcr100.??2@YAPEAX_K@Z', (('int', None),) ), 18 | 'msvcr100.??_u@yapeax_k@z':( 'int', None, 'cdecl', 'msvcr100.??_U@YAPEAX_K@Z', (('int', None),) ), 19 | 'msvcr100.??3@yaxpeax@z':( 'void', None, 'cdecl', 'msvcr100.??3@YAXPEAX@Z', (('void *', 'ptr'),) ), 20 | 'msvcr100.??_v@yaxpeax@z':( 'void', None, 'cdecl', 'msvcr100.??_V@YAXPEAX@Z', (('void *', 'ptr'),) ), 21 | } 22 | 23 | 24 | # Build from the 32-bit API, skipping omits, changing the calling convention, 25 | # and adding any specific 64-bit functions. 26 | api_defs_64 = {} 27 | 28 | import vivisect.impapi.windows.msvcr100_32 as m32 29 | for name in m32.api_defs.iterkeys(): 30 | if name in api_32_omits: 31 | continue 32 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 33 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 34 | api_defs_64.update(api_64_adds) 35 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/msvcr110_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit MSVC 2012 runtime library (msvcr110). 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [ 9 | 'msvcr110.??2@yapaxi@z', 10 | 'msvcr110.??_u@yapaxi@z', 11 | 'msvcr110.??3@yaxpax@z', 12 | 'msvcr110.??_v@yaxpax@z' 13 | ] 14 | 15 | # Define any functions specific to 64-bit. 16 | api_64_adds = { 17 | 'msvcr110.??2@yapeax_k@z':( 'int', None, 'cdecl', 'msvcr110.??2@YAPEAX_K@Z', (('int', None),) ), 18 | 'msvcr110.??_u@yapeax_k@z':( 'int', None, 'cdecl', 'msvcr110.??_U@YAPEAX_K@Z', (('int', None),) ), 19 | 'msvcr110.??3@yaxpeax@z':( 'void', None, 'cdecl', 'msvcr110.??3@YAXPEAX@Z', (('void *', 'ptr'),) ), 20 | 'msvcr110.??_v@yaxpeax@z':( 'void', None, 'cdecl', 'msvcr110.??_V@YAXPEAX@Z', (('void *', 'ptr'),) ), 21 | } 22 | 23 | 24 | # Build from the 32-bit API, skipping omits, changing the calling convention, 25 | # and adding any specific 64-bit functions. 26 | api_defs_64 = {} 27 | 28 | import vivisect.impapi.windows.msvcr110_32 as m32 29 | for name in m32.api_defs.iterkeys(): 30 | if name in api_32_omits: 31 | continue 32 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 33 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 34 | api_defs_64.update(api_64_adds) 35 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/msvcr120_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit MSVC 2013 runtime library (msvcr120). 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [ 9 | 'msvcr120.??2@yapaxi@z', 10 | 'msvcr120.??_u@yapaxi@z', 11 | 'msvcr120.??3@yaxpax@z', 12 | 'msvcr120.??_v@yaxpax@z' 13 | ] 14 | 15 | # Define any functions specific to 64-bit. 16 | api_64_adds = { 17 | 'msvcr120.??2@yapeax_k@z':( 'int', None, 'cdecl', 'msvcr120.??2@YAPEAX_K@Z', (('int', None),) ), 18 | 'msvcr120.??_u@yapeax_k@z':( 'int', None, 'cdecl', 'msvcr120.??_U@YAPEAX_K@Z', (('int', None),) ), 19 | 'msvcr120.??3@yaxpeax@z':( 'void', None, 'cdecl', 'msvcr120.??3@YAXPEAX@Z', (('void *', 'ptr'),) ), 20 | 'msvcr120.??_v@yaxpeax@z':( 'void', None, 'cdecl', 'msvcr120.??_V@YAXPEAX@Z', (('void *', 'ptr'),) ), 21 | } 22 | 23 | 24 | # Build from the 32-bit API, skipping omits, changing the calling convention, 25 | # and adding any specific 64-bit functions. 26 | api_defs_64 = {} 27 | 28 | import vivisect.impapi.windows.msvcr120_32 as m32 29 | for name in m32.api_defs.iterkeys(): 30 | if name in api_32_omits: 31 | continue 32 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 33 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 34 | api_defs_64.update(api_64_adds) 35 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/msvcr80_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit MSVC 2005 runtime library (msvcr80). 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [ 9 | 'msvcr80.??2@yapaxi@z', 10 | 'msvcr80.??_u@yapaxi@z', 11 | 'msvcr80.??3@yaxpax@z', 12 | 'msvcr80.??_v@yaxpax@z' 13 | ] 14 | 15 | # Define any functions specific to 64-bit. 16 | api_64_adds = { 17 | 'msvcr80.??2@yapeax_k@z':( 'int', None, 'cdecl', 'msvcr80.??2@YAPEAX_K@Z', (('int', None),) ), 18 | 'msvcr80.??_u@yapeax_k@z':( 'int', None, 'cdecl', 'msvcr80.??_U@YAPEAX_K@Z', (('int', None),) ), 19 | 'msvcr80.??3@yaxpeax@z':( 'void', None, 'cdecl', 'msvcr80.??3@YAXPEAX@Z', (('void *', 'ptr'),) ), 20 | 'msvcr80.??_v@yaxpeax@z':( 'void', None, 'cdecl', 'msvcr80.??_V@YAXPEAX@Z', (('void *', 'ptr'),) ), 21 | } 22 | 23 | 24 | # Build from the 32-bit API, skipping omits, changing the calling convention, 25 | # and adding any specific 64-bit functions. 26 | api_defs_64 = {} 27 | 28 | import vivisect.impapi.windows.msvcr80_32 as m32 29 | for name in m32.api_defs.iterkeys(): 30 | if name in api_32_omits: 31 | continue 32 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 33 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 34 | api_defs_64.update(api_64_adds) 35 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/msvcr90_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit MSVC 2008 runtime library (msvcr90). 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [ 9 | 'msvcr90.??2@yapaxi@z', 10 | 'msvcr90.??_u@yapaxi@z', 11 | 'msvcr90.??3@yaxpax@z', 12 | 'msvcr90.??_v@yaxpax@z' 13 | ] 14 | 15 | # Define any functions specific to 64-bit. 16 | api_64_adds = { 17 | 'msvcr90.??2@yapeax_k@z':( 'int', None, 'cdecl', 'msvcr90.??2@YAPEAX_K@Z', (('int', None),) ), 18 | 'msvcr90.??_u@yapeax_k@z':( 'int', None, 'cdecl', 'msvcr90.??_U@YAPEAX_K@Z', (('int', None),) ), 19 | 'msvcr90.??3@yaxpeax@z':( 'void', None, 'cdecl', 'msvcr90.??3@YAXPEAX@Z', (('void *', 'ptr'),) ), 20 | 'msvcr90.??_v@yaxpeax@z':( 'void', None, 'cdecl', 'msvcr90.??_V@YAXPEAX@Z', (('void *', 'ptr'),) ), 21 | } 22 | 23 | 24 | # Build from the 32-bit API, skipping omits, changing the calling convention, 25 | # and adding any specific 64-bit functions. 26 | api_defs_64 = {} 27 | 28 | import vivisect.impapi.windows.msvcr90_32 as m32 29 | for name in m32.api_defs.iterkeys(): 30 | if name in api_32_omits: 31 | continue 32 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 33 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 34 | api_defs_64.update(api_64_adds) 35 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/msvcrt_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit MVSC runtime library (msvcrt). 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [ 9 | 'msvcrt.??2@yapaxi@z', 10 | 'msvcrt.??_u@yapaxi@z', 11 | 'msvcrt.??3@yaxpax@z', 12 | 'msvcrt.??_v@yaxpax@z' 13 | ] 14 | 15 | # Define any functions specific to 64-bit. 16 | api_64_adds = { 17 | 'msvcrt.??2@yapeax_k@z':( 'int', None, 'cdecl', 'msvcrt.??2@YAPEAX_K@Z', (('int', None),) ), 18 | 'msvcrt.??_u@yapeax_k@z':( 'int', None, 'cdecl', 'msvcrt.??_U@YAPEAX_K@Z', (('int', None),) ), 19 | 'msvcrt.??3@yaxpeax@z':( 'void', None, 'cdecl', 'msvcrt.??3@YAXPEAX@Z', (('void *', 'ptr'),) ), 20 | 'msvcrt.??_v@yaxpeax@z':( 'void', None, 'cdecl', 'msvcrt.??_V@YAXPEAX@Z', (('void *', 'ptr'),) ), 21 | } 22 | 23 | 24 | # Build from the 32-bit API, skipping omits, changing the calling convention, 25 | # and adding any specific 64-bit functions. 26 | api_defs_64 = {} 27 | 28 | import vivisect.impapi.windows.msvcrt_32 as m32 29 | for name in m32.api_defs.iterkeys(): 30 | if name in api_32_omits: 31 | continue 32 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 33 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 34 | api_defs_64.update(api_64_adds) 35 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/ntdll_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit ntdll library. 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [ 9 | 'ntdll.seh3_prolog', 10 | 'ntdll.seh4_prolog', 11 | 'ntdll.seh4_gs_prolog', 12 | 'ntdll.seh3_epilog', 13 | 'ntdll.seh4_epilog', 14 | 'ntdll.eh_prolog', 15 | 'ntdll.gs_prolog', 16 | 'ntdll.security_check_cookie' 17 | ] 18 | 19 | # Define any functions specific to 64-bit. 20 | api_64_adds = { 21 | 'ntdll.security_check_cookie_64': ('void', None, 'msx64call', 'ntdll.security_check_cookie_64', (('int', None),)) 22 | } 23 | 24 | 25 | # Build from the 32-bit API, skipping omits, changing the calling convention, 26 | # and adding any specific 64-bit functions. 27 | api_defs_64 = {} 28 | 29 | import vivisect.impapi.windows.ntdll_32 as m32 30 | for name in m32.api_defs.iterkeys(): 31 | if name in api_32_omits: 32 | continue 33 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 34 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 35 | api_defs_64.update(api_64_adds) 36 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/ole_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit ole32 library. 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [] 9 | 10 | # Define any functions specific to 64-bit. 11 | api_64_adds = { 12 | } 13 | 14 | 15 | # Build from the 32-bit API, skipping omits, changing the calling convention, 16 | # and adding any specific 64-bit functions. 17 | api_defs_64 = {} 18 | 19 | import vivisect.impapi.windows.ole_32 as m32 20 | for name in m32.api_defs.iterkeys(): 21 | if name in api_32_omits: 22 | continue 23 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 24 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 25 | api_defs_64.update(api_64_adds) 26 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/rpcrt4_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit rpcrt4 library. 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [] 9 | 10 | # Define any functions specific to 64-bit. 11 | api_64_adds = { 12 | } 13 | 14 | 15 | # Build from the 32-bit API, skipping omits, changing the calling convention, 16 | # and adding any specific 64-bit functions. 17 | api_defs_64 = {} 18 | 19 | import vivisect.impapi.windows.rpcrt4_32 as m32 20 | for name in m32.api_defs.iterkeys(): 21 | if name in api_32_omits: 22 | continue 23 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 24 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 25 | api_defs_64.update(api_64_adds) 26 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/user_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit user32 library. 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [] 9 | 10 | # Define any functions specific to 64-bit. 11 | api_64_adds = { 12 | } 13 | 14 | 15 | # Build from the 32-bit API, skipping omits, changing the calling convention, 16 | # and adding any specific 64-bit functions. 17 | api_defs_64 = {} 18 | 19 | import vivisect.impapi.windows.user_32 as m32 20 | for name in m32.api_defs.iterkeys(): 21 | if name in api_32_omits: 22 | continue 23 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 24 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 25 | api_defs_64.update(api_64_adds) 26 | -------------------------------------------------------------------------------- /vivisect/impapi/windows/ws2plus_64.py: -------------------------------------------------------------------------------- 1 | # APIs for Windows 64-bit libraries ws2_32, mswsock, wsock32, and wininet. 2 | # Built as a delta from the 32-bit version. 3 | # Format: retval, rettype, callconv, exactname, arglist(type, name) 4 | # arglist type is one of ['int', 'void *'] 5 | # arglist name is one of [None, 'funcptr', 'obj', 'ptr'] 6 | 7 | # List the normalized name of any 32-bit functions to omit. 8 | api_32_omits = [] 9 | 10 | # Define any functions specific to 64-bit. 11 | api_64_adds = { 12 | } 13 | 14 | 15 | # Build from the 32-bit API, skipping omits, changing the calling convention, 16 | # and adding any specific 64-bit functions. 17 | api_defs_64 = {} 18 | 19 | import vivisect.impapi.windows.ws2plus_32 as m32 20 | for name in m32.api_defs.iterkeys(): 21 | if name in api_32_omits: 22 | continue 23 | (rtype,rname,cconv,cname,cargs) = m32.api_defs[name] 24 | api_defs_64[name] = (rtype, rname, 'msx64call', cname, cargs) 25 | api_defs_64.update(api_64_adds) 26 | -------------------------------------------------------------------------------- /vivisect/impapi/winkern/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vivisect/impapi/winkern/__init__.py -------------------------------------------------------------------------------- /vivisect/impemu/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vivisect/impemu/__init__.py -------------------------------------------------------------------------------- /vivisect/impemu/lookup.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Home for the registered emulators of different types... 3 | ''' 4 | import vivisect.impemu.platarch.h8 as v_i_h8 5 | import vivisect.impemu.platarch.arm as v_i_arm 6 | import vivisect.impemu.platarch.i386 as v_i_i386 7 | import vivisect.impemu.platarch.amd64 as v_i_amd64 8 | import vivisect.impemu.platarch.msp430 as v_i_msp430 9 | import vivisect.impemu.platarch.windows as v_i_windows 10 | 11 | workspace_emus = { 12 | 'h8' :v_i_h8.H8WorkspaceEmulator, 13 | 'arm' :v_i_arm.ArmWorkspaceEmulator, 14 | 'i386' :v_i_i386.i386WorkspaceEmulator, 15 | 'amd64' :v_i_amd64.Amd64WorkspaceEmulator, 16 | 'msp430' :v_i_msp430.Msp430WorkspaceEmulator, 17 | ('windows','i386'):v_i_windows.Windowsi386Emulator, 18 | } 19 | -------------------------------------------------------------------------------- /vivisect/impemu/platarch/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vivisect/impemu/platarch/__init__.py -------------------------------------------------------------------------------- /vivisect/impemu/platarch/h8.py: -------------------------------------------------------------------------------- 1 | import envi.archs.h8 as e_h8 2 | import vivisect.impemu.emulator as v_i_emulator 3 | 4 | class H8WorkspaceEmulator(v_i_emulator.WorkspaceEmulator, e_h8.H8Emulator): 5 | 6 | taintregs = [ 7 | e_h8.REG_ER0, e_h8.REG_ER1, e_h8.REG_ER2, 8 | ] 9 | 10 | def __init__(self, vw, logwrite=False, logread=False): 11 | e_h8.H8Emulator.__init__(self) 12 | v_i_emulator.WorkspaceEmulator.__init__(self, vw, logwrite=logwrite, logread=logread) 13 | 14 | -------------------------------------------------------------------------------- /vivisect/impemu/platarch/i386.py: -------------------------------------------------------------------------------- 1 | import envi.archs.i386 as e_i386 2 | import vivisect.impemu.emulator as v_i_emulator 3 | 4 | class i386WorkspaceEmulator(v_i_emulator.WorkspaceEmulator, e_i386.IntelEmulator): 5 | 6 | taintregs = [ 7 | e_i386.REG_EAX, e_i386.REG_ECX, e_i386.REG_EDX, 8 | e_i386.REG_EBX, e_i386.REG_EBP, e_i386.REG_ESI, 9 | e_i386.REG_EDI, 10 | ] 11 | 12 | def __init__(self, vw, logwrite=False, logread=False): 13 | e_i386.IntelEmulator.__init__(self) 14 | v_i_emulator.WorkspaceEmulator.__init__(self, vw, logwrite=logwrite, logread=logread) 15 | self.setEmuOpt('i386:reponce',True) 16 | -------------------------------------------------------------------------------- /vivisect/impemu/platarch/msp430.py: -------------------------------------------------------------------------------- 1 | import envi.archs.msp430.emu as e_msp430e 2 | import vivisect.impemu.emulator as v_i_emulator 3 | 4 | class Msp430WorkspaceEmulator(v_i_emulator.WorkspaceEmulator, e_msp430e.Msp430Emulator): 5 | 6 | taintregs = [ x for x in range(2, 16) ] 7 | 8 | def __init__(self, vw, logwrite=False, logread=False): 9 | e_msp430e.Msp430Emulator.__init__(self) 10 | v_i_emulator.WorkspaceEmulator.__init__(self, vw, logwrite=logwrite, logread=logread) 11 | 12 | ''' 13 | st0len gratuitously from mspgcc: 14 | Function calling conventions 15 | 16 | Fixed argument lists 17 | 18 | Function arguments are allocated left to right. They are assigned from r15 to r12. If more parameters are passed than will fit in the registers, the rest are passed on the stack. This should be avoided since the code takes a performance hit when using variables residing on the stack. 19 | 20 | Variable argument lists 21 | 22 | Parameters passed to functions that have a variable argument list (printf, scanf, etc.) are all passed on the stack. Any char parameters are extended to ints. 23 | 24 | Return values 25 | 26 | The various functions types return the results as follows: 27 | 28 | char, int and pointer functions return their values r15 29 | 30 | long and float functions return their values in r15:r14 31 | 32 | long long functions return their values r15:r14:r13:r12 33 | 34 | If the returned value wider than 64 bits, it is returned in memory. The first 'hidden' argument to such a function call will be a memory address. All other arguments will be allocated in the usual way, from r14. 35 | ''' 36 | -------------------------------------------------------------------------------- /vivisect/parsers/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | The vivisect.parsers package contains all the known file format parsers 4 | for vivisect. Each parser module must implement the following functions: 5 | 6 | parseFile(workspace, filename): 7 | Load the file into the given workspace 8 | parseBytes(workspace, bytes): 9 | Load the file (pre-read in) into the workspace 10 | 11 | """ 12 | # Some parser utilities 13 | 14 | import md5 15 | import sys 16 | import struct 17 | 18 | import vstruct.defs.macho as vs_macho 19 | 20 | from .utils import md5File 21 | from .utils import md5Bytes 22 | from .utils import guessFormat 23 | from .utils import guessFormatFilename 24 | 25 | 26 | def getParserModule(fmt): 27 | # wb: this importing by incomplete package doesn't seem like a 28 | # good idea. but, this works with pyinstaller 29 | if fmt == "pe": 30 | import pe 31 | return pe 32 | elif fmt == "blob": 33 | import blob 34 | return blob 35 | elif fmt == "elf": 36 | import elf 37 | return elf 38 | elif fmt == "ihex": 39 | import ihex 40 | return ihex 41 | elif fmt == "macho": 42 | import macho 43 | return macho 44 | 45 | mname = "%s" % fmt 46 | mod = sys.modules.get(mname) 47 | if mod == None: 48 | __import__(mname) 49 | mod = sys.modules[mname] 50 | return mod 51 | 52 | -------------------------------------------------------------------------------- /vivisect/parsers/ihex.py: -------------------------------------------------------------------------------- 1 | import envi 2 | import vivisect 3 | import vstruct.defs.ihex as v_ihex 4 | from .utils import md5File 5 | 6 | from vivisect.const import * 7 | 8 | archcalls = { 9 | 'i386':'cdecl', 10 | 'amd64':'sysvamd64call', 11 | 'arm':'armcall', 12 | } 13 | 14 | def parseFile(vw, filename): 15 | 16 | arch = vw.config.viv.parsers.ihex.arch 17 | if not arch: 18 | raise Exception('IHex loader *requires* arch option (-O viv.parsers.ihex.arch=\\"\\")') 19 | 20 | envi.getArchModule(arch) 21 | 22 | vw.setMeta('Architecture', arch) 23 | vw.setMeta('Platform','Unknown') 24 | vw.setMeta('Format','ihex') 25 | vw.setMeta('DefaultCall', archcalls.get(arch,'unknown')) 26 | 27 | fname = vw.addFile(filename, 0, md5File(filename)) 28 | 29 | ihex = v_ihex.IHexFile() 30 | ihex.vsParse( file(filename, 'rb').read() ) 31 | 32 | for addr, perms, notused, bytes in ihex.getMemoryMaps(): 33 | vw.addMemoryMap( addr, perms, fname, bytes ) 34 | vw.addSegment( addr, len(bytes), '%.8x' % addr, fname ) 35 | 36 | def parseMemory(vw, memobj, baseaddr): 37 | raise Exception('ihex loader cannot parse memory!') 38 | -------------------------------------------------------------------------------- /vivisect/parsers/utils.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | The vivisect.parsers package contains all the known file format parsers 4 | for vivisect. Each parser module must implement the following functions: 5 | 6 | parseFile(workspace, filename): 7 | Load the file into the given workspace 8 | parseBytes(workspace, bytes): 9 | Load the file (pre-read in) into the workspace 10 | 11 | """ 12 | # Some parser utilities 13 | 14 | import md5 15 | import sys 16 | import struct 17 | 18 | import vstruct.defs.macho as vs_macho 19 | 20 | 21 | def md5File(filename): 22 | d = md5.md5() 23 | f = file(filename,"rb") 24 | bytes = f.read(4096) 25 | while len(bytes): 26 | d.update(bytes) 27 | bytes = f.read(4096) 28 | return d.hexdigest() 29 | 30 | def md5Bytes(bytes): 31 | d = md5.md5() 32 | d.update(bytes) 33 | return d.hexdigest() 34 | 35 | macho_magics = ( 36 | vs_macho.MH_MAGIC, 37 | vs_macho.MH_CIGAM, 38 | vs_macho.MH_MAGIC_64, 39 | vs_macho.MH_CIGAM_64, 40 | vs_macho.FAT_MAGIC, 41 | vs_macho.FAT_CIGAM, 42 | ) 43 | 44 | def guessFormat(bytes): 45 | if bytes.startswith('VIV'): 46 | return 'viv' 47 | 48 | if bytes.startswith("MZ"): 49 | return 'pe' 50 | 51 | if bytes.startswith("\x7fELF"): 52 | return 'elf' 53 | 54 | if bytes.startswith("\x7fCGC"): 55 | return 'cgc' 56 | 57 | bytemagic = struct.unpack(' to move using the mouse in Function Graph view!', 5 | 'You may drag rows from "List Views" to "Memory Views"', 6 | ] 7 | 8 | def getRandomTip(): 9 | return random.choice(tips) 10 | -------------------------------------------------------------------------------- /vivisect/qt/ustruct.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtCore, QtGui 2 | 3 | from vqt.basics import * 4 | 5 | example_src = ''' 6 | // A comment (not /* yet... */ ) 7 | // "pure" c types only for now... 8 | struct example { 9 | char x; // This is ok too... 10 | unsigned int y[20]; 11 | }; 12 | 13 | ''' 14 | 15 | class UserStructEditor(QtGui.QWidget): 16 | 17 | def __init__(self, vw, name=None, parent=None): 18 | ''' 19 | Open a view to edit/create user structure defs. 20 | If "name" is none, we assume they are creating one. 21 | ''' 22 | QtGui.QWidget.__init__(self, parent=parent) 23 | self._v_vw = vw 24 | self._v_sname = name 25 | self._v_changed = True 26 | 27 | ssrc = example_src 28 | if name: 29 | ssrc = vw.getUserStructSource( name ) 30 | self._v_changed = False 31 | 32 | self.srcedit = QtGui.QTextEdit(parent=self) 33 | self.srcedit.setText( ssrc ) 34 | self.srcedit.textChanged.connect( self._text_changed ) 35 | 36 | buttons = QtGui.QDialogButtonBox( QtGui.QDialogButtonBox.Save, parent=self) 37 | buttons.accepted.connect( self._save_event ) 38 | 39 | self._set_title() 40 | self.setLayout( VBox( self.srcedit, buttons ) ) 41 | 42 | def _set_title(self): 43 | 44 | name = self._v_sname 45 | if name == None: 46 | name = '(new)' 47 | 48 | status = '' 49 | if self._v_changed: 50 | status = '(unsaved!)' 51 | 52 | self.setWindowTitle('Struct Edit: %s %s' % (name, status)) 53 | 54 | def _save_event(self): 55 | 56 | ssrc = str(self.srcedit.toPlainText()) 57 | 58 | try: 59 | self._v_sname = self._v_vw.setUserStructSource( ssrc ) 60 | self._v_changed = False 61 | self._set_title() 62 | except Exception, e: 63 | QtGui.QMessageBox.warning(self, 'Syntax Error', str(e), QtGui.QMessageBox.Ok ) 64 | 65 | 66 | def _text_changed(self): 67 | self._v_changed = True 68 | self._set_title() 69 | 70 | -------------------------------------------------------------------------------- /vivisect/remote/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vivisect/remote/__init__.py -------------------------------------------------------------------------------- /vivisect/remote/client.py: -------------------------------------------------------------------------------- 1 | import time 2 | import vivisect 3 | import vivisect.cli as viv_cli 4 | import vivisect.qt.main as viv_qt_main 5 | 6 | def remotemain(appsrv): 7 | 8 | # The "appsrv" is a remote workspace... 9 | vw = viv_cli.VivCli() 10 | vw.initWorkspaceClient(appsrv) 11 | 12 | # If we are interactive, lets turn on extended output... 13 | vw.verbose = True 14 | viv_qt_main.main(vw) 15 | 16 | -------------------------------------------------------------------------------- /vivisect/remote/share.py: -------------------------------------------------------------------------------- 1 | import cobra.dcode 2 | import cobra.remoteapp 3 | 4 | def shareWorkspace(vw, doref=False): 5 | daemon = cobra.CobraDaemon('', 0, msgpack=True) 6 | daemon.fireThread() 7 | cobra.dcode.enableDcodeServer(daemon=daemon) 8 | cobra.remoteapp.shareRemoteApp('vivisect.remote.client', appsrv=vw, daemon=daemon) 9 | return daemon 10 | -------------------------------------------------------------------------------- /vivisect/reports/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | A package of builtin vivisect reports which produce runtime 4 | generated lists of workspace statistics and anomalies. 5 | 6 | Each report module must have 2 things. It must have a variable 7 | declared named "columns" which is a list of (colname, coltype) 8 | tuples, and a "report" function which returns a VA Set style 9 | dictionary. 10 | """ 11 | 12 | rep_mods = [ 13 | ('Undefined Xrefs/Names','vivisect.reports.undeftargets'), 14 | ('Overlapped Locations','vivisect.reports.overlaplocs'), 15 | ('Function Complexity', 'vivisect.reports.funccomplexity'), 16 | ('Location Distribution', 'vivisect.reports.locationdist'), 17 | ] 18 | 19 | def listReportModules(): 20 | ''' 21 | Return a list of (, ) tuples for the known 22 | report types. 23 | ''' 24 | return list(rep_mods) 25 | 26 | def runReportModule(vw, modname): 27 | mod = vw.loadModule(modname) 28 | return mod.report(vw) 29 | 30 | -------------------------------------------------------------------------------- /vivisect/reports/funccomplexity.py: -------------------------------------------------------------------------------- 1 | 2 | # Mnemonic distribution 3 | # Reverse depth 4 | 5 | columns = ( 6 | ("Code Blocks",int), 7 | ("Mnem Dist", int), 8 | ) 9 | 10 | def report(vw): 11 | 12 | ret = {} 13 | cbtot = {} 14 | mntot = {} 15 | for f in vw.getFunctions(): 16 | fblocks = vw.getFunctionBlocks(f) 17 | cbtot[f] = len(fblocks) 18 | 19 | for f,c in cbtot.items(): 20 | mndist = vw.getFunctionMeta(f, "MnemDist", -1) 21 | ret[f] = (c,mndist) 22 | 23 | return ret 24 | 25 | -------------------------------------------------------------------------------- /vivisect/reports/locationdist.py: -------------------------------------------------------------------------------- 1 | 2 | columns = ( 3 | ("Location Type",str), 4 | ("Instance Count", int), 5 | ("Size (bytes)", int), 6 | ("Size Percent", int), 7 | ) 8 | 9 | def report(vw): 10 | return vw.getLocationDistribution() 11 | -------------------------------------------------------------------------------- /vivisect/reports/overlaplocs.py: -------------------------------------------------------------------------------- 1 | """Locate locations which overlap""" 2 | import vivisect 3 | 4 | from vivisect.const import * 5 | 6 | columns = ( 7 | ("Overlap Size", int), 8 | ("This Location", str), 9 | ("Other Location", str), 10 | ) 11 | 12 | def report(vw): 13 | res = {} 14 | for i in xrange(LOC_MAX): 15 | for lva,size,ltype,tinfo in vw.getLocations(i): 16 | va = lva + 1 17 | maxva = lva + size 18 | while va < maxva: 19 | x = vw.getLocation(va) 20 | if x != None: 21 | res[lva] = (va-lva, vw.reprLocation((lva,size,ltype,tinfo)),vw.reprLocation(x)) 22 | va += 1 23 | 24 | return res 25 | 26 | -------------------------------------------------------------------------------- /vivisect/reports/undeftargets.py: -------------------------------------------------------------------------------- 1 | """Locate any xrefs/names to undefined locations""" 2 | 3 | import vivisect 4 | 5 | ref_names = { 6 | vivisect.REF_CODE:"Code", 7 | vivisect.REF_DATA:"Data", 8 | vivisect.REF_PTR:"Pointer", 9 | } 10 | 11 | columns = ( ("Bytes",str), ("Name", str) ) 12 | 13 | def report(vw): 14 | 15 | res = {} 16 | 17 | for fromva, tova, reftype, rflags in vw.getXrefs(): 18 | if vw.getLocation(tova, range=True) == None: 19 | rname = ref_names.get(reftype, "Unknown") 20 | sname = "Unknown" 21 | seg = vw.getSegment(tova) 22 | if seg != None: 23 | sname = seg[vivisect.SEG_NAME] 24 | try: 25 | b = vw.readMemory(tova, 8).encode('hex') 26 | except Exception, e: 27 | b = str(e) 28 | res[tova] = (b, "%s ref from 0x%x (%s)" % (rname,fromva,sname)) 29 | 30 | for va, name in vw.getNames(): 31 | if vw.getLocation(va) == None: 32 | try: 33 | b = vw.readMemory(tova, 8).encode('hex') 34 | except Exception, e: 35 | b = str(e) 36 | res[va] = (b, name) 37 | 38 | return res 39 | 40 | -------------------------------------------------------------------------------- /vivisect/storage/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Each sub-module here is capable of saving or loading 3 | a workspace. the saveWorkspace and loadWorkspace functions 4 | each take a string for "backing info" 5 | """ 6 | 7 | -------------------------------------------------------------------------------- /vivisect/storage/basicfile.py: -------------------------------------------------------------------------------- 1 | import cPickle as pickle 2 | import vivisect 3 | 4 | vivsig_cpickle = 'VIV'.ljust(8,'\x00') 5 | 6 | def saveWorkspaceChanges(vw, filename): 7 | elist = vw.exportWorkspaceChanges() 8 | if len(elist): 9 | f = file(filename, 'ab') 10 | pickle.dump(elist, f, protocol=2) 11 | f.close() 12 | 13 | def saveWorkspace(vw, filename): 14 | events = vw.exportWorkspace() 15 | vivEventsToFile(filename, events) 16 | 17 | def vivEventsAppendFile(filename, events): 18 | f = file(filename, 'ab') 19 | # Mime type for the basic workspace 20 | pickle.dump(events, f, protocol=2) 21 | f.close() 22 | 23 | def vivEventsToFile(filename, events): 24 | f = file(filename, 'wb') 25 | # Mime type for the basic workspace 26 | f.write(vivsig_cpickle) 27 | pickle.dump(events, f, protocol=2) 28 | f.close() 29 | 30 | def vivEventsFromFile(filename): 31 | f = file(filename, "rb") 32 | vivsig = f.read(8) 33 | 34 | # check for various viv serial formats 35 | if vivsig == vivsig_cpickle: 36 | pass 37 | 38 | else: # FIXME legacy file format.... ( eventually remove ) 39 | f.seek(0) 40 | 41 | events = [] 42 | # Incremental changes are saved to the file by appending more pickled 43 | # lists of exported events 44 | while True: 45 | try: 46 | events.extend( pickle.load(f) ) 47 | except EOFError, e: 48 | break 49 | except pickle.UnpicklingError, e: 50 | raise vivisect.InvalidWorkspace(filename, "invalid workspace file") 51 | 52 | f.close() 53 | 54 | # FIXME - diagnostics to hunt msgpack unsave values 55 | #for event in events: 56 | #import msgpack 57 | #try: 58 | #msgpack.dumps(event) 59 | #except Exception, e: 60 | #print('Unsafe Event: %d %r' % event) 61 | 62 | return events 63 | 64 | def loadWorkspace(vw, filename): 65 | events = vivEventsFromFile(filename) 66 | vw.importWorkspace(events) 67 | return 68 | 69 | -------------------------------------------------------------------------------- /vivisect/symboliks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vivisect/symboliks/__init__.py -------------------------------------------------------------------------------- /vivisect/symboliks/archs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vivisect/symboliks/archs/__init__.py -------------------------------------------------------------------------------- /vivisect/symboliks/functions.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ''' 3 | import inspect 4 | 5 | import vstruct 6 | import vivisect.symboliks 7 | 8 | from vivisect.symboliks.common import * 9 | 10 | class CallingConventionProxy: 11 | 12 | def __init__(self, cconv, argv, funcsym): 13 | self.argv = argv # viv style (type,name) tuple list 14 | self.cconv = cconv 15 | self.funcsym = funcsym 16 | 17 | def __call__(self, emu): 18 | 19 | # Get and update the symbolik args 20 | args = self.cconv.getSymbolikArgs(emu, self.argv) 21 | args = [ arg.update(emu) for arg in args ] 22 | 23 | # If callFunction returns something, snap it back in. 24 | # Otherwise, snap in a Call symbol. 25 | ret = self.callFunction(emu, *args) 26 | if ret == None: 27 | ret = Call(self.funcsym, emu.__width__, args) 28 | 29 | # Set the return value into the symbolik state 30 | self.cconv.setSymbolikReturn(emu, ret, self.argv) 31 | 32 | def getSymbolikArgs(self, emu): 33 | return self.cconv.getSymbolikArgs(emu, self.argv) 34 | 35 | def callFunction(emu, *args): 36 | # Each calling convention proxy must implement this to do 37 | # the actual call hook... 38 | return None 39 | 40 | class ImportCallProxy(CallingConventionProxy): 41 | ''' 42 | A calling convention proxy allows the definition of 43 | a pythonic function which may then be called by an emulator 44 | during symbolik effect processing. 45 | ''' 46 | 47 | def __init__(self, func, cconv): 48 | 49 | # Do crazy introspection shit to make calling convention 50 | # map function args to names / vstruct types. 51 | aspec = inspect.getargspec(func) 52 | argn = aspec.args[1:] 53 | argt = aspec.defaults 54 | 55 | argv = [ (argt[i],argn[i]) for i in xrange(len(argn)) ] 56 | 57 | modlast = func.__module__.split('.')[-1] 58 | funcsym = Var('%s.%s' % (modlast, func.__name__)) 59 | 60 | CallingConventionProxy.__init__(self, cconv, argv, funcsym) 61 | 62 | self.func = func 63 | 64 | def callFunction(self, emu, *args): 65 | return self.func(emu, *args) 66 | -------------------------------------------------------------------------------- /vivisect/symboliks/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vivisect/symboliks/tests/__init__.py -------------------------------------------------------------------------------- /vivisect/symboliks/tests/test_cache.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from vivisect.const import * 4 | from vivisect.symboliks.common import * 5 | from vivisect.symboliks.expression import symexp 6 | 7 | class TestSymbolikCache(unittest.TestCase): 8 | ''' 9 | tests the reduction of asts consisting of add's and sub's if widths are 10 | the same. 11 | ''' 12 | def test_symboliks_cache_solve_vars(self): 13 | s = symexp('x + 20') 14 | 15 | self.assertEqual(s.solve(vals={'x':10}), 30) 16 | self.assertEqual(s.solve(vals={'x':20}), 40) 17 | 18 | self.assertIsNone(s.cache.get('solve')) 19 | s.solve() 20 | self.assertIsNotNone(s.cache.get('solve')) 21 | 22 | def test_symboliks_cache_walktree(self): 23 | 24 | s = symexp('x + 30') 25 | 26 | solved1 = s.solve() 27 | 28 | self.assertIsNotNone(s.cache.get('solve')) 29 | 30 | def swapx(path,sym,ctx): 31 | if sym.symtype == SYMT_VAR and sym.name == 'x': 32 | return Var('y',4) 33 | 34 | s = s.walkTree(swapx) 35 | 36 | # check the partial cache clear 37 | self.assertIsNone(s.cache.get('solve')) 38 | self.assertIsNone(s.kids[0].cache.get('solve')) 39 | self.assertIsNotNone(s.kids[1].cache.get('solve')) 40 | 41 | solved2 = s.solve() 42 | self.assertEqual(str(s),'(y + 30)') 43 | 44 | self.assertNotEqual(solved1,solved2) 45 | 46 | # be *really* mean and manually slice a kid 47 | # then confirm that the cache still hits.. 48 | s.kids[0] = Var('x',4) 49 | self.assertEqual(s.solve(), solved2) 50 | 51 | -------------------------------------------------------------------------------- /vivisect/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vivisect/tests/__init__.py -------------------------------------------------------------------------------- /vivisect/tests/helpers.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | 4 | def getTestPath(*paths): 5 | ''' 6 | Return the join'd path to a file in the vivtestfiles repo 7 | by using the environment variable "VIVTESTFILES" 8 | 9 | ( raises SkipTest if env var is not present ) 10 | ''' 11 | testdir = os.getenv('VIVTESTFILES') 12 | if not testdir: 13 | raise unittest.SkipTest('VIVTESTFILES env var not found!') 14 | 15 | return os.path.join(testdir,*paths) 16 | -------------------------------------------------------------------------------- /vivisect/tests/samplecode.py: -------------------------------------------------------------------------------- 1 | ''' 2 | bits 32 3 | 4 | foo: 5 | push ebp 6 | mov ebp, esp 7 | mov ecx,[ebp+8] 8 | xor edx,edx 9 | cmp ecx,edx 10 | jz bar 11 | 12 | mov eax, 1 13 | 14 | bar: 15 | mov eax, 2 16 | 17 | baz: 18 | mov esp, ebp 19 | pop ebp 20 | ret 21 | ''' 22 | func1 = '5589e58b4d0831d239d17405b801000000b80200000089ec5dc3'.decode('hex') 23 | 24 | -------------------------------------------------------------------------------- /vivisect/tests/test_helpers.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import vivisect.tests.helpers as helpers 3 | 4 | class HelperTest(unittest.TestCase): 5 | 6 | def test_helper_pathjoin(self): 7 | # retrieve a known vivtestfiles path ( or skip ) 8 | helpers.getTestPath('windows','i386','helloworld.exe') 9 | 10 | -------------------------------------------------------------------------------- /vivisect/tests/testcodegraph.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import vivisect 4 | import vivisect.codegraph as codegraph 5 | import vivisect.tests.samplecode as samplecode 6 | 7 | class GraphCoreTest(unittest.TestCase): 8 | 9 | def test_vivisect_codegraph_func1(self): 10 | vw = vivisect.VivWorkspace() 11 | vw.setMeta('Architecture','i386') 12 | vw.addMemoryMap(0x41410000, 0xff, 'none', samplecode.func1) 13 | vw.makeFunction(0x41410000) 14 | 15 | -------------------------------------------------------------------------------- /vivisect/tests/testimpapi.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import vivisect.impapi as viv_impapi 4 | 5 | class ImpApiTest(unittest.TestCase): 6 | 7 | #def setUp(self): 8 | #pass 9 | 10 | #def tearDown(self): 11 | #pass 12 | 13 | def test_impapi_windows(self): 14 | imp = viv_impapi.getImportApi('windows','i386') 15 | self.assertEqual( imp.getImpApiCallConv('ntdll.RtlAllocateHeap'), 'stdcall') 16 | 17 | #def test_impapi_posix(self): 18 | #imp = viv_impapi.getImpApi('windows','i386') 19 | 20 | def test_impapi_winkern(self): 21 | imp = viv_impapi.getImportApi('winkern','i386') 22 | self.assertEqual( imp.getImpApiCallConv('ntoskrnl.ObReferenceObjectByHandle'), 'stdcall') 23 | -------------------------------------------------------------------------------- /vivisect/tests/testpe.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | 4 | import PE 5 | import vivisect.tests.helpers as helpers 6 | 7 | class PETests(unittest.TestCase): 8 | 9 | def test_export_by_name(self): 10 | file_path = helpers.getTestPath('windows', 'i386', 'export_by_name.dll') 11 | pe = PE.peFromFileName(file_path) 12 | export_list = pe.getExports() 13 | self.assertEquals(len(export_list), 2, "expecting 2 exported functions") 14 | self.assertEquals(export_list[0][1], 0, "exported function with ordinal 0 not found") 15 | self.assertEquals(export_list[0][2], "Func1", "exported function with name 'Func1' not found") 16 | self.assertEquals(export_list[1][1], 1, "exported function with ordinal 1 not found") 17 | self.assertEquals(export_list[1][2], "Func2", "exported function with name 'Func2' not found") 18 | 19 | def test_export_by_ordinal_base_01(self): 20 | file_path = helpers.getTestPath('windows', 'i386', 'export_by_ordinal_base_01.dll') 21 | pe = PE.peFromFileName(file_path) 22 | export_list = pe.getExports() 23 | self.assertEquals(len(export_list), 2, "expecting 2 exported functions") 24 | self.assertEquals(export_list[0][1], 1, "exported function with ordinal 1 not found") 25 | self.assertEquals(export_list[1][1], 2, "exported function with ordinal 2 not found") 26 | 27 | def test_export_by_ordinal_base_45(self): 28 | file_path = helpers.getTestPath('windows', 'i386', 'export_by_ordinal_base_45.dll') 29 | pe = PE.peFromFileName(file_path) 30 | export_list = pe.getExports() 31 | self.assertEquals(len(export_list), 2, "expecting 2 exported functions") 32 | self.assertEquals(export_list[0][1], 45, "exported function with ordinal 45 not found") 33 | self.assertEquals(export_list[1][1], 55, "exported function with ordinal 55 not found") 34 | -------------------------------------------------------------------------------- /vivisect/tests/vivbins.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | import vivisect 4 | 5 | def require(f): 6 | def skipit(*args, **kwargs): 7 | raise unittest.SkipTest('VIVBINS env var...') 8 | 9 | if os.getenv('VIVBINS') == None: 10 | return skipit 11 | 12 | return f 13 | 14 | def getTestWorkspace(fname, analyze=True): 15 | fpath = os.path.join('test_vivisect','bins',fname) 16 | vw = vivisect.VivWorkspace() 17 | vw.loadFromFile(fpath) 18 | if analyze: 19 | vw.analyze() 20 | return vw 21 | 22 | def getAnsWorkspace(fname): 23 | fpath = os.path.join('test_vivisect','bins','%s.viv' % fname) 24 | vw = vivisect.VivWorkspace() 25 | vw.loadWorkspace(fpath) 26 | return vw 27 | 28 | -------------------------------------------------------------------------------- /vivisect/tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vivisect/tools/__init__.py -------------------------------------------------------------------------------- /vivisect/vamp/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Vamp is a function/codeblock signaturing framework which is 4 | a subcomponent of vivisect. These may be used to import/export 5 | signature sets and potentially identify code reuse or static 6 | linking... 7 | 8 | Current signature ideas: 9 | function arg count 10 | code block count 11 | globals refs 12 | code block refs 13 | unusual instruction use 14 | odd immediates 15 | import calls 16 | other signature calls 17 | certianty index 18 | Exception handling 19 | 20 | There will be function characteristics and code-block 21 | characteristics... 22 | 23 | NOTE: Initial signature code consists entirely of the envi 24 | bytesig module and byte/mask sets for known function signatures. 25 | """ 26 | 27 | 28 | class Signature: 29 | """ 30 | A function/procedure signature. 31 | """ 32 | pass 33 | 34 | from vivisect.const import * 35 | 36 | def genSigAndMask(vw, funcva): 37 | 38 | """ 39 | Generate an envi bytesig signature and mask for the given 40 | function block. This will properly mask off relocations 41 | if present. 42 | """ 43 | 44 | fsize = 0 45 | 46 | # Figgure out the size of the first linear chunk 47 | # in this function... 48 | cb = vw.getCodeBlock(funcva) 49 | while cb != None: 50 | cbva, cbsize, cbfunc = cb 51 | if cbfunc != funcva: 52 | break 53 | fsize += cbsize 54 | cb = vw.getCodeBlock(cbva+cbsize) 55 | 56 | if fsize == 0: 57 | raise Exception("0 length function??!?1") 58 | 59 | bytes = vw.readMemory(funcva, fsize) 60 | 61 | sig = "" 62 | mask = "" 63 | i = 0 64 | while i < fsize: 65 | rtype = vw.getRelocation(funcva + i) 66 | if rtype == None: 67 | sig += bytes[i] 68 | mask += "\xff" 69 | i += 1 70 | elif rtype == RTYPE_BASERELOC: 71 | x = "\x00" * vw.psize 72 | sig += x 73 | mask += x 74 | i += vw.psize 75 | else: 76 | raise Exception("Unhandled Reloc Type: %d" % rtype) 77 | 78 | return sig,mask 79 | 80 | -------------------------------------------------------------------------------- /vqt/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vqt/__init__.py -------------------------------------------------------------------------------- /vqt/saveable.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | class SaveableWidget(object): 4 | ''' 5 | Inherited by widgets that want to save and restore settings. 6 | 7 | Implement vqGetSaveState/vqSetSaveState. 8 | ''' 9 | def vqSaveState(self, settings, name): 10 | state = self.vqGetSaveState() 11 | settings.setValue(name, json.dumps(state)) 12 | 13 | def vqRestoreState(self, settings, name): 14 | qstate = settings.value(name) 15 | if qstate.isNull(): 16 | return 17 | 18 | try: 19 | state = json.loads(str(qstate.toString())) 20 | self.vqSetSaveState(state) 21 | except Exception, e: 22 | print('failed to restore %s: %s' % (name,e)) 23 | 24 | def vqGetSaveState(self): 25 | return None 26 | 27 | def vqSetSaveState(self, state): 28 | return None 29 | 30 | -------------------------------------------------------------------------------- /vqt/shortcut.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Some utilities for adding shortcut keys to widgets... 3 | ''' 4 | 5 | from PyQt4 import QtCore, QtGui 6 | 7 | def addShortCut(widget, keycode, callback): 8 | if isinstance(keycode, str): 9 | keycode = ord(keycode) 10 | keyseq = QtGui.QKeySequence(keycode) 11 | short = QtGui.QShortcut(keyseq, widget) 12 | widget.connect(short, QtCore.SIGNAL('activated()'), callback) 13 | 14 | -------------------------------------------------------------------------------- /vstruct/constants/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | class VSConstResolver: 3 | def __init__(self): 4 | self.rev_lookup = {} 5 | self.const_lookup = {} 6 | 7 | def clearAll(self): 8 | self.rev_lookup = {} 9 | self.const_lookup = {} 10 | 11 | def addModule(self, mod): 12 | for name in dir(mod): 13 | val = getattr(mod, name) 14 | if type(val) not in (int,long): 15 | continue 16 | 17 | # First lets add the "reverse" lookup 18 | revs = self.rev_lookup.get(val) 19 | if revs == None: 20 | revs = [] 21 | self.rev_lookup[val] = revs 22 | revs.append(name) 23 | 24 | # Now the forward.... 25 | self.const_lookup[name] = val 26 | 27 | def constLookup(self, name): 28 | return self.const_lookup.get(name) 29 | 30 | def revLookup(self, const): 31 | ''' 32 | Lookup the possible names of a constant based on 33 | modules added with constAddModule() 34 | ''' 35 | return self.rev_lookup.get(const) 36 | 37 | -------------------------------------------------------------------------------- /vstruct/defs/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | # Import all local structure modules 3 | import elf 4 | import pe 5 | import win32 6 | 7 | -------------------------------------------------------------------------------- /vstruct/defs/arm7/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | import vstruct 3 | from vstruct.primitives import * 4 | 5 | # Mapped at 0xe000e000 in arm7 6 | class SCS(vstruct.VStruct): 7 | 8 | def __init__(self): 9 | vstruct.VStruct.__init__(self) 10 | self.MasterControl = v_uint32() 11 | self.InterruptControllerType = v_uint32() 12 | self.AuxiliaryControl = v_uint32() 13 | self.ReservedSpace = v_bytes(3320) 14 | self.CPUIDBase = v_uint32() 15 | self.InterruptControlState = v_uint32() 16 | self.VectorTableOffset = v_uint32() 17 | self.AppInterr_ResetControl = v_uint32() 18 | self.SystemControl = v_uint32() 19 | self.ConfigurationControl = v_uint32() 20 | -------------------------------------------------------------------------------- /vstruct/defs/bmp.py: -------------------------------------------------------------------------------- 1 | import vstruct 2 | from vstruct.primitives import * 3 | 4 | class BITMAPINFOHEADER(vstruct.VStruct): 5 | def __init__(self): 6 | vstruct.VStruct.__init__(self) 7 | self.biSize = v_uint32() 8 | self.biWidth = v_int32() 9 | self.biHeight = v_int32() 10 | self.biPlanes = v_uint16() 11 | self.biBitCount = v_uint16() 12 | self.biCompression = v_uint32() 13 | self.biSizeImage = v_uint32() 14 | self.biXPelsPerMeter = v_int32() 15 | self.biYPelsPerMeter = v_int32() 16 | self.biClrUser = v_uint32() 17 | self.biClrImportant = v_uint32() 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /vstruct/defs/macho/fat.py: -------------------------------------------------------------------------------- 1 | 2 | import vstruct 3 | from vstruct.primitives import * 4 | import vstruct.primitives as vs_prim 5 | 6 | class fat_header(vstruct.VStruct): 7 | def __init__(self): 8 | vstruct.VStruct.__init__(self) 9 | self.magic = v_uint32(bigend=True) 10 | self.nfat_arch = v_uint32(bigend=True) 11 | 12 | class fat_arch(vstruct.VStruct): 13 | def __init__(self): 14 | vstruct.VStruct.__init__(self) 15 | self.cputype = v_uint32(bigend=True) # cpu specifier (int) */ 16 | self.cpusubtype = v_uint32(bigend=True) # machine specifier (int) */ 17 | self.offset = v_uint32(bigend=True) # file offset to this object file */ 18 | self.size = v_uint32(bigend=True) # size of this object file */ 19 | self.align = v_uint32(bigend=True) # alignment as a power of 2 */ 20 | 21 | -------------------------------------------------------------------------------- /vstruct/defs/macho/stabs.py: -------------------------------------------------------------------------------- 1 | import vstruct 2 | 3 | from vstruct.primitives import * 4 | from vstruct.defs.macho.const import * 5 | 6 | class nlist(vstruct.VStruct): 7 | ''' 8 | A symbol table entry in a Mach-O binary is called an nlist. 9 | ''' 10 | def __init__(self): 11 | vstruct.VStruct.__init__(self) 12 | self.n_strx = v_uint32() # index into the string table 13 | self.n_type = v_uint8() # type flag (see const...) 14 | self.n_sect = v_uint8() # section number or NO_SECT (index from 1...) 15 | self.n_desc = v_uint16() # desription (see const...) 16 | self.n_value = v_uint32() # value of this symbol (or stab offset) 17 | 18 | class nlist64(vstruct.VStruct): 19 | 20 | def __init__(self): 21 | vstruct.VStruct.__init__(self) 22 | self.n_strx = v_uint32() 23 | self.n_type = v_uint8() 24 | self.n_sect = v_uint8() 25 | self.n_desc = v_uint16() 26 | self.n_value = v_uint64() 27 | 28 | -------------------------------------------------------------------------------- /vstruct/defs/windows/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | The pre-made windows structure defs (extracted from pdb syms) 3 | ''' 4 | 5 | import envi 6 | import ctypes 7 | import platform 8 | 9 | def isSysWow64(): 10 | k32 = ctypes.windll.kernel32 11 | if not hasattr(k32, 'IsWow64Process'): 12 | return False 13 | ret = ctypes.c_ulong(0) 14 | myproc = ctypes.c_size_t(-1) 15 | if not k32.IsWow64Process(myproc, ctypes.addressof(ret)): 16 | return False 17 | return bool(ret.value) 18 | 19 | def getCurrentDef(normname): 20 | bname, wver, stuff, whichkern = platform.win32_ver() 21 | wvertup = wver.split('.') 22 | arch = envi.getCurrentArch() 23 | if isSysWow64(): 24 | arch = 'wow64' 25 | 26 | modname = 'vstruct.defs.windows.win_%s_%s_%s.%s' % (wvertup[0], wvertup[1], arch, normname) 27 | 28 | try: 29 | mod = __import__(modname, {}, {}, 1) 30 | except ImportError, e: 31 | mod = None 32 | return mod 33 | 34 | if __name__ == '__main__': 35 | print getCurrentDef('ntdll') 36 | 37 | -------------------------------------------------------------------------------- /vstruct/defs/windows/win_5_1_i386/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /vstruct/defs/windows/win_5_2_i386/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vstruct/defs/windows/win_5_2_i386/__init__.py -------------------------------------------------------------------------------- /vstruct/defs/windows/win_6_1_amd64/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vstruct/defs/windows/win_6_1_amd64/__init__.py -------------------------------------------------------------------------------- /vstruct/defs/windows/win_6_1_i386/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vstruct/defs/windows/win_6_1_i386/__init__.py -------------------------------------------------------------------------------- /vstruct/defs/windows/win_6_1_wow64/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /vstruct/defs/windows/win_6_2_amd64/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vstruct/defs/windows/win_6_2_amd64/__init__.py -------------------------------------------------------------------------------- /vstruct/defs/windows/win_6_2_amd64/win32k.py: -------------------------------------------------------------------------------- 1 | # Version: 6.2 2 | # Architecture: amd64 3 | import vstruct 4 | from vstruct.primitives import * 5 | 6 | 7 | -------------------------------------------------------------------------------- /vstruct/defs/windows/win_6_2_i386/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vstruct/defs/windows/win_6_2_i386/__init__.py -------------------------------------------------------------------------------- /vstruct/defs/windows/win_6_2_i386/win32k.py: -------------------------------------------------------------------------------- 1 | # Version: 6.2 2 | # Architecture: i386 3 | import vstruct 4 | from vstruct.primitives import * 5 | 6 | 7 | -------------------------------------------------------------------------------- /vstruct/defs/windows/win_6_2_wow64/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vstruct/defs/windows/win_6_2_wow64/__init__.py -------------------------------------------------------------------------------- /vstruct/defs/windows/win_6_3_amd64/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vstruct/defs/windows/win_6_3_amd64/__init__.py -------------------------------------------------------------------------------- /vstruct/defs/windows/win_6_3_i386/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vstruct/defs/windows/win_6_3_i386/__init__.py -------------------------------------------------------------------------------- /vstruct/defs/windows/win_6_3_wow64/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vstruct/defs/windows/win_6_3_wow64/__init__.py -------------------------------------------------------------------------------- /vstruct/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vstruct/tests/__init__.py -------------------------------------------------------------------------------- /vtrace/archs/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Architecture Support Modules 3 | 4 | """ 5 | # Copyright (C) 2007 Invisigoth - See LICENSE file for details 6 | -------------------------------------------------------------------------------- /vtrace/archs/amd64.py: -------------------------------------------------------------------------------- 1 | """ 2 | Amd64 Support Module 3 | """ 4 | # Copyright (C) 2007 Invisigoth - See LICENSE file for details 5 | import struct 6 | 7 | import envi.archs.amd64 as e_amd64 8 | import vtrace.archs.i386 as vt_i386 9 | 10 | class Amd64Mixin( 11 | e_amd64.Amd64Module, 12 | e_amd64.Amd64RegisterContext, 13 | vt_i386.i386WatchMixin): 14 | """ 15 | Do what we need to for the lucious amd64 16 | """ 17 | def __init__(self): 18 | e_amd64.Amd64Module.__init__(self) 19 | e_amd64.Amd64RegisterContext.__init__(self) 20 | vt_i386.i386WatchMixin.__init__(self) 21 | 22 | self.setMeta('Architecture','amd64') 23 | 24 | def archGetStackTrace(self): 25 | self.requireAttached() 26 | current = 0 27 | sanity = 1000 28 | frames = [] 29 | rbp = self.getRegisterByName("rbp") 30 | rip = self.getRegisterByName("rip") 31 | frames.append((rip,rbp)) 32 | 33 | while rbp != 0 and current < sanity: 34 | try: 35 | rbp,rip = self.readMemoryFormat(rbp, "=:unsigned) 0 22 | return "\x0e\x80\x00\x00" 23 | 24 | def archGetPcName(self): 25 | return "r0" 26 | 27 | def archGetSpName(self): 28 | return "r1" 29 | 30 | def platformCall(self, address, args, convention=None): 31 | pass 32 | -------------------------------------------------------------------------------- /vtrace/audit.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test for platform functionality (for internal use). 3 | """ 4 | # Copyright (C) 2007 Invisigoth - See LICENSE file for details 5 | import vtrace 6 | import vtrace.platforms.base as v_base 7 | 8 | ############################################ 9 | # 10 | # FIXME this is dorked for now based on the new platforms/archs design 11 | # 12 | ############################################ 13 | 14 | def auditTracer(trace): 15 | """ 16 | Print out a list of platform requirements and weather 17 | a particular tracer meets them. This is mostly a 18 | development tool to determin what's left to do on a 19 | tracer implementation. 20 | """ 21 | for mname in dir(v_base.BasePlatformMixin): 22 | if "__" in mname: 23 | continue 24 | if getattr(trace.__class__, mname) == getattr(v_base.BasePlatformMixin, mname): 25 | print "LACKS:",mname 26 | else: 27 | print "HAS:",mname 28 | 29 | if __name__ == "__main__": 30 | trace = vtrace.getTrace() 31 | auditTracer(trace) 32 | -------------------------------------------------------------------------------- /vtrace/const.py: -------------------------------------------------------------------------------- 1 | # Order must match format junk 2 | # NOTIFY_ALL is kinda special, if you registerNotifier 3 | # with it, you get ALL notifications. 4 | NOTIFY_ALL = 0 # Get all notifications 5 | NOTIFY_SIGNAL = 1 # Callback on signal/exception 6 | NOTIFY_BREAK = 2 # Callback on breakpoint / sigtrap 7 | NOTIFY_STEP = 3 # Callback on singlestep complete 8 | NOTIFY_SYSCALL = 4 # Callback on syscall (linux only for now) 9 | NOTIFY_CONTINUE = 5 # Callback on continue (not done for step) 10 | NOTIFY_EXIT = 6 # Callback on process exit 11 | NOTIFY_ATTACH = 7 # Callback on successful attach 12 | NOTIFY_DETACH = 8 # Callback on impending process detach 13 | # The following notifiers are *only* available on some platforms 14 | # (and may be kinda faked out ala library load events on posix) 15 | NOTIFY_LOAD_LIBRARY = 9 16 | NOTIFY_UNLOAD_LIBRARY = 10 17 | NOTIFY_CREATE_THREAD = 11 18 | NOTIFY_EXIT_THREAD = 12 19 | NOTIFY_DEBUG_PRINT = 13 # Some platforms support this (win32). 20 | NOTIFY_MAX = 20 21 | 22 | # File Descriptor / Handle Types 23 | FD_UNKNOWN = 0 # Unknown or we don't have a type for it 24 | FD_FILE = 1 25 | FD_SOCKET = 2 26 | FD_PIPE = 3 27 | FD_LOCK = 4 # Win32 Mutant/Lock/Semaphore 28 | FD_EVENT = 5 # Win32 Event/KeyedEvent 29 | FD_THREAD = 6 # Win32 Thread 30 | FD_REGKEY = 7 # Win32 Registry Key 31 | 32 | # Vtrace Symbol Types 33 | SYM_MISC = -1 34 | SYM_GLOBAL = 0 # Global (mostly vars) 35 | SYM_LOCAL = 1 # Locals 36 | SYM_FUNCTION = 2 # Functions 37 | SYM_SECTION = 3 # Binary section 38 | SYM_META = 4 # Info that we enumerate 39 | 40 | # Vtrace Symbol Offsets 41 | VSYM_NAME = 0 42 | VSYM_ADDR = 1 43 | VSYM_SIZE = 2 44 | VSYM_TYPE = 3 45 | VSYM_FILE = 4 46 | -------------------------------------------------------------------------------- /vtrace/platforms/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Platform Support Modules 3 | 4 | The vtrace platforms package is where the modules live that 5 | implement platform specific functionality that is used behind 6 | the scenes of the top level Trace object. If you're not porting 7 | vtrace to a new platform, or chasing a bug, you probably don't need 8 | anything from here... 9 | """ 10 | # Copyright (C) 2007 Invisigoth - See LICENSE file for details 11 | -------------------------------------------------------------------------------- /vtrace/platforms/darwin/Makefile: -------------------------------------------------------------------------------- 1 | SRCS=machhelper.c excServer.c excUser.c 2 | DYLIB=machhelper.dylib 3 | 4 | # mig /usr/include/mach/exc.defs 5 | # edit all catch_exception_* references to vtrace_catch_exception_* 6 | # then our exc_server doesn't try to locate those functions in the 7 | # main exe.... #fuckingwinning 8 | 9 | all: 10 | gcc -dynamiclib -arch i386 -arch x86_64 ${SRCS} -o ${DYLIB} 11 | 12 | clean: 13 | rm -rf ${DYLIB} 14 | -------------------------------------------------------------------------------- /vtrace/platforms/darwin/machhelper.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vtrace/platforms/darwin/machhelper.dylib -------------------------------------------------------------------------------- /vtrace/platforms/windll/amd64/dbghelp.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vtrace/platforms/windll/amd64/dbghelp.dll -------------------------------------------------------------------------------- /vtrace/platforms/windll/amd64/symsrv.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vtrace/platforms/windll/amd64/symsrv.dll -------------------------------------------------------------------------------- /vtrace/platforms/windll/amd64/symsrv.yes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vtrace/platforms/windll/amd64/symsrv.yes -------------------------------------------------------------------------------- /vtrace/platforms/windll/i386/dbghelp.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vtrace/platforms/windll/i386/dbghelp.dll -------------------------------------------------------------------------------- /vtrace/platforms/windll/i386/symsrv.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vtrace/platforms/windll/i386/symsrv.dll -------------------------------------------------------------------------------- /vtrace/platforms/windll/i386/symsrv.yes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vtrace/platforms/windll/i386/symsrv.yes -------------------------------------------------------------------------------- /vtrace/tests/mains/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import errno 3 | 4 | def waitForTest(): 5 | sys.stdout.write('testwait\n') 6 | sys.stdout.flush() 7 | while True: 8 | line = safeReadline().strip() 9 | if line == 'testmod': 10 | break 11 | 12 | def safeReadline(): 13 | while True: 14 | try: # Crazy loop for freebsd readline failure 15 | r = sys.stdin.readline() 16 | break 17 | except IOError,e: 18 | if e.errno == errno.EINTR: 19 | continue 20 | raise 21 | return r 22 | 23 | def exitTest(): 24 | sys.exit(33) 25 | 26 | def main(): 27 | waitForTest() 28 | return 33 29 | 30 | if __name__ == '__main__': 31 | sys.exit(main()) 32 | -------------------------------------------------------------------------------- /vtrace/tests/mains/mainexec.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def main(): 4 | return 33 5 | 6 | if __name__ == '__main__': 7 | sys.exit(main()) 8 | -------------------------------------------------------------------------------- /vtrace/tests/mains/mainthreads.py: -------------------------------------------------------------------------------- 1 | import time 2 | import threading 3 | 4 | import main 5 | 6 | if __name__ == '__main__': 7 | main.waitForTest() 8 | thr = threading.Thread( target=time.sleep, args=(0.1, ) ) 9 | thr.start() 10 | thr.join() 11 | time.sleep(0.1) 12 | main.exitTest() 13 | -------------------------------------------------------------------------------- /vtrace/tests/mains/mainwritemem.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import ctypes 3 | 4 | import main 5 | 6 | if __name__ == '__main__': 7 | main.waitForTest() 8 | 9 | buf = ctypes.create_string_buffer( 32 ) 10 | sys.stdout.write('0x%.8x\r\n' % ctypes.addressof( buf )) 11 | sys.stdout.flush() 12 | 13 | main.safeReadline() 14 | 15 | sys.stdout.write('%s\n' % buf.value ) 16 | sys.stdout.flush() 17 | 18 | main.exitTest() 19 | -------------------------------------------------------------------------------- /vtrace/tests/mainwritemem.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import ctypes 3 | 4 | import main 5 | 6 | if __name__ == '__main__': 7 | main.waitForTest() 8 | 9 | buf = ctypes.create_string_buffer( 32 ) 10 | sys.stdout.write('0x%.8x\r\n' % ctypes.addressof( buf )) 11 | sys.stdout.flush() 12 | 13 | main.safeReadline() 14 | 15 | sys.stdout.write('%s\n' % buf.value ) 16 | sys.stdout.flush() 17 | 18 | main.exitTest() 19 | -------------------------------------------------------------------------------- /vtrace/tests/tests_breakpoints.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import vtrace.breakpoints 4 | 5 | # TODO: move testmods.hookbptest tests in here as well. 6 | 7 | class MockTrace(object): 8 | def getCurrentThread(self): 9 | return 0 10 | 11 | class HookBpPostTests(unittest.TestCase): 12 | def test_PostHitNoCallinfo(self): 13 | ''' 14 | tests condition where: 15 | 1. thread 1 hits hookbp and sets up postbp 16 | 2. thread 2 hits postbp (there's nothing in callinfo for thread 2) 17 | ''' 18 | hbp = vtrace.breakpoints.HookBreakpoint('0xdeadbeef') 19 | phbp = vtrace.breakpoints.PostHookBreakpoint('0xcafebabe', hbp) 20 | 21 | phbp.notify(None, MockTrace()) 22 | -------------------------------------------------------------------------------- /vtrace/tests/tests_envitools.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import vtrace 4 | import vtrace.envitools 5 | 6 | class EnvitoolsTests(vtrace.tests.VtraceProcessTest): 7 | def test_emulatorFromTrace(self): 8 | emu = vtrace.envitools.emuFromTrace(self.trace) 9 | 10 | ctx = self.trace.getRegisterContext() 11 | for rname, idx in ctx.getRegisterNameIndexes(): 12 | self.assertEqual(self.trace.getRegister(idx), emu.getRegister(idx)) 13 | 14 | emu.stepi() 15 | -------------------------------------------------------------------------------- /vtrace/tests/testthread.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import unittest 4 | 5 | import vtrace 6 | import vtrace.tests as vt_tests 7 | 8 | class ThreadNotifier(vtrace.Notifier): 9 | 10 | def __init__(self): 11 | vtrace.Notifier.__init__(self) 12 | self.threadexit = False 13 | self.threadcreate = False 14 | 15 | def notify(self, event, trace): 16 | if event == vtrace.NOTIFY_CREATE_THREAD: 17 | self.threadcreate = True 18 | return 19 | 20 | if event == vtrace.NOTIFY_EXIT_THREAD: 21 | self.threadexit = True 22 | return 23 | 24 | class VtraceThreadTest(vt_tests.VtraceProcessTest): 25 | 26 | pypath = os.path.join('vtrace','tests','mains','mainthreads.py') 27 | 28 | def test_vtrace_threads(self): 29 | #if self.trace.getMeta('Platform') not in ('windows',): 30 | #raise unittest.SkipTest('Thread Catching Fails...') 31 | 32 | n = ThreadNotifier() 33 | 34 | self.trace.registerNotifier( vtrace.NOTIFY_ALL, n) 35 | self.runUntilExit() 36 | 37 | self.assertTrue( n.threadexit ) 38 | self.assertTrue( n.threadcreate ) 39 | 40 | 41 | -------------------------------------------------------------------------------- /vtrace/tests/testwritemem.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import ctypes 4 | import unittest 5 | 6 | import vtrace.tests as vt_tests 7 | 8 | class VtraceWritememTest(vt_tests.VtraceProcessTest): 9 | 10 | pypath = os.path.join('vtrace','tests','mains','mainwritemem.py') 11 | 12 | def test_vtrace_writemem(self): 13 | 14 | self.runProcess() 15 | 16 | addrstr = self.proc.stdout.readline() 17 | addr = long( addrstr, 16 ) 18 | 19 | testbuf = os.urandom( 10 ).encode('hex') 20 | 21 | # Stop him so we can write to the buffer he created 22 | self.trace.sendBreak() 23 | self.trace.writeMemory( addr, testbuf ) 24 | 25 | self.runUntilExit() 26 | 27 | # He should now print what we wrote... 28 | gotline = self.proc.stdout.readline().strip() 29 | self.assertEqual(testbuf,gotline) 30 | 31 | -------------------------------------------------------------------------------- /vtrace/tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mandiant/vivisect/dea425eed796176309a3be46936eb682598271aa/vtrace/tools/__init__.py -------------------------------------------------------------------------------- /vtrace/tools/win32alloc.py: -------------------------------------------------------------------------------- 1 | ''' 2 | A module with some cute toys for monitoring allocations. 3 | ''' 4 | 5 | import vtrace 6 | 7 | import envi.archs.i386 as e_i386 8 | 9 | class ReturnBreak(vtrace.Breakpoint): 10 | def __init__(self, addr, chsize, chflags): 11 | vtrace.Breakpoint.__init__(self, addr) 12 | self.fastbreak = True 13 | self._chsize = chsize 14 | self._chflags = chflags 15 | 16 | def notify(self, event, trace): 17 | eax = trace.getRegister(e_i386.REG_EAX) 18 | a = trace.getMeta('HeapAllocs') 19 | a.append((self.address, eax, self._chsize, self._chflags)) 20 | trace.runAgain() 21 | 22 | class RtlAllocateHeapBreak(vtrace.Breakpoint): 23 | 24 | def __init__(self, addr): 25 | vtrace.Breakpoint.__init__(self, addr) 26 | self.fastbreak = True 27 | 28 | def notify(self, event, trace): 29 | 30 | sp = trace.getStackCounter() 31 | ( saved_eip, 32 | heap, 33 | flags, 34 | size ) = trace.readMemoryFormat(sp, '<4P') 35 | 36 | if trace.getBreakpointByAddr(saved_eip) == None: 37 | bp = ReturnBreak(saved_eip, size, flags) 38 | trace.addBreakpoint(bp) 39 | 40 | trace.runAgain() 41 | 42 | def watchHeapAllocs(trace): 43 | ''' 44 | Add a breakpoint to ntdll.RtlAllocateHeap to watch for 45 | allocations and track who made them... 46 | ''' 47 | clearHeapAllocs(trace) 48 | addr = trace.parseExpression('ntdll.RtlAllocateHeap') 49 | bp = RtlAllocateHeapBreak(addr) 50 | trace.addBreakpoint(bp) 51 | 52 | def clearHeapAllocs(trace): 53 | trace.setMeta('HeapAllocs', []) 54 | 55 | def getHeapAllocs(trace): 56 | ''' 57 | Return a list of (caller_eip, heap_chunk, size, flags) tuples 58 | ''' 59 | return trace.getMeta('HeapAllocs', []) 60 | 61 | -------------------------------------------------------------------------------- /vtrace/tools/win32aslr.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Utilities for windows tracer objects. 3 | ''' 4 | import PE 5 | import vtrace 6 | import envi.bits as e_bits 7 | 8 | def deAslr(trace, va): 9 | ''' 10 | Given an address in an ASLR'd library, rebase 11 | it back to the address as it would be if the 12 | given PE were at it's suggested address... 13 | ''' 14 | 15 | if vtrace.remote: 16 | raise Exception('deAslr only works for local debuggers!') 17 | 18 | map = trace.getMemoryMap(va) 19 | if map == None: 20 | return va 21 | 22 | mapva, mapsize, mapperm, mapfname = map 23 | if not mapfname: 24 | return va 25 | 26 | normname = trace.normFileName(mapfname) 27 | sym = trace.getSymByName(normname) 28 | if sym == None: 29 | return va 30 | 31 | membase = long(sym) 32 | 33 | pe = PE.peFromFileName(mapfname) 34 | filebase = pe.IMAGE_NT_HEADERS.OptionalHeader.ImageBase 35 | 36 | rva = va - membase 37 | 38 | return filebase + rva 39 | 40 | 41 | --------------------------------------------------------------------------------