diff options
31 files changed, 685 insertions, 77 deletions
diff --git a/architecture.cpp b/architecture.cpp index 169a8c0c..3ca41741 100644 --- a/architecture.cpp +++ b/architecture.cpp @@ -30,6 +30,7 @@ using namespace std; InstructionInfo::InstructionInfo() { length = 0; + archTransitionByTargetAddr = false; branchCount = 0; branchDelay = false; } @@ -111,6 +112,13 @@ size_t Architecture::GetDefaultIntegerSizeCallback(void* ctxt) } +size_t Architecture::GetInstructionAlignmentCallback(void* ctxt) +{ + Architecture* arch = (Architecture*)ctxt; + return arch->GetInstructionAlignment(); +} + + size_t Architecture::GetMaxInstructionLengthCallback(void* ctxt) { Architecture* arch = (Architecture*)ctxt; @@ -471,6 +479,7 @@ void Architecture::Register(Architecture* arch) callbacks.getEndianness = GetEndiannessCallback; callbacks.getAddressSize = GetAddressSizeCallback; callbacks.getDefaultIntegerSize = GetDefaultIntegerSizeCallback; + callbacks.getInstructionAlignment = GetInstructionAlignmentCallback; callbacks.getMaxInstructionLength = GetMaxInstructionLengthCallback; callbacks.getOpcodeDisplayLength = GetOpcodeDisplayLengthCallback; callbacks.getAssociatedArchitectureByAddress = GetAssociatedArchitectureByAddressCallback; @@ -554,6 +563,12 @@ size_t Architecture::GetDefaultIntegerSize() const } +size_t Architecture::GetInstructionAlignment() const +{ + return 1; +} + + size_t Architecture::GetMaxInstructionLength() const { return BN_DEFAULT_NSTRUCTION_LENGTH; @@ -968,6 +983,12 @@ size_t CoreArchitecture::GetDefaultIntegerSize() const } +size_t CoreArchitecture::GetInstructionAlignment() const +{ + return BNGetArchitectureInstructionAlignment(m_object); +} + + size_t CoreArchitecture::GetMaxInstructionLength() const { return BNGetArchitectureMaxInstructionLength(m_object); diff --git a/binaryninjaapi.cpp b/binaryninjaapi.cpp index 6f488788..f5eede03 100644 --- a/binaryninjaapi.cpp +++ b/binaryninjaapi.cpp @@ -173,6 +173,15 @@ string BinaryNinja::GetVersionString() } +string BinaryNinja::GetLicensedUserEmail() +{ + char* str = BNGetLicensedUserEmail(); + string result = str; + BNFreeString(str); + return result; +} + + string BinaryNinja::GetProduct() { char* str = BNGetProduct(); @@ -191,6 +200,15 @@ string BinaryNinja::GetProductType() } +string BinaryNinja::GetSerialNumber() +{ + char* str = BNGetSerialNumber(); + string result = str; + BNFreeString(str); + return result; +} + + int BinaryNinja::GetLicenseCount() { return BNGetLicenseCount(); @@ -326,3 +344,21 @@ string BinaryNinja::GetUniqueIdentifierString() BNFreeString(str); return result; } + + +string BinaryNinja::GetLinuxCADirectory() +{ + char* str = BNGetLinuxCADirectory(); + string result = str; + BNFreeString(str); + return result; +} + + +string BinaryNinja::GetLinuxCABundlePath() +{ + char* str = BNGetLinuxCABundlePath(); + string result = str; + BNFreeString(str); + return result; +} diff --git a/binaryninjaapi.h b/binaryninjaapi.h index d4624ca5..b90f72a2 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -575,8 +575,10 @@ namespace BinaryNinja std::string& output, std::string& errors, bool stdoutIsText=false, bool stderrIsText=true); std::string GetVersionString(); + std::string GetLicensedUserEmail(); std::string GetProduct(); std::string GetProductType(); + std::string GetSerialNumber(); int GetLicenseCount(); bool IsUIEnabled(); uint32_t GetBuildId(); @@ -1025,6 +1027,7 @@ namespace BinaryNinja uint64_t start, length; uint64_t dataOffset, dataLength; uint32_t flags; + bool autoDefined; }; struct Section @@ -1035,6 +1038,7 @@ namespace BinaryNinja uint64_t infoData; uint64_t align, entrySize; BNSectionSemantics semantics; + bool autoDefined; }; struct QualifiedNameAndType; @@ -1086,6 +1090,7 @@ namespace BinaryNinja virtual uint64_t PerformGetEntryPoint() const { return 0; } virtual bool PerformIsExecutable() const { return false; } virtual BNEndianness PerformGetDefaultEndianness() const; + virtual bool PerformIsRelocatable() const; virtual size_t PerformGetAddressSize() const; virtual bool PerformSave(FileAccessor* file); @@ -1113,6 +1118,7 @@ namespace BinaryNinja static uint64_t GetEntryPointCallback(void* ctxt); static bool IsExecutableCallback(void* ctxt); static BNEndianness GetDefaultEndiannessCallback(void* ctxt); + static bool IsRelocatableCallback(void* ctxt); static size_t GetAddressSizeCallback(void* ctxt); static bool SaveCallback(void* ctxt, BNFileAccessor* file); @@ -1179,6 +1185,7 @@ namespace BinaryNinja void SetDefaultPlatform(Platform* platform); BNEndianness GetDefaultEndianness() const; + bool IsRelocatable() const; size_t GetAddressSize() const; bool IsExecutable() const; @@ -1580,6 +1587,7 @@ namespace BinaryNinja static BNEndianness GetEndiannessCallback(void* ctxt); static size_t GetAddressSizeCallback(void* ctxt); static size_t GetDefaultIntegerSizeCallback(void* ctxt); + static size_t GetInstructionAlignmentCallback(void* ctxt); static size_t GetMaxInstructionLengthCallback(void* ctxt); static size_t GetOpcodeDisplayLengthCallback(void* ctxt); static BNArchitecture* GetAssociatedArchitectureByAddressCallback(void* ctxt, uint64_t* addr); @@ -1639,6 +1647,7 @@ namespace BinaryNinja virtual size_t GetAddressSize() const = 0; virtual size_t GetDefaultIntegerSize() const; + virtual size_t GetInstructionAlignment() const; virtual size_t GetMaxInstructionLength() const; virtual size_t GetOpcodeDisplayLength() const; @@ -1784,6 +1793,7 @@ namespace BinaryNinja virtual BNEndianness GetEndianness() const override; virtual size_t GetAddressSize() const override; virtual size_t GetDefaultIntegerSize() const override; + virtual size_t GetInstructionAlignment() const override; virtual size_t GetMaxInstructionLength() const override; virtual size_t GetOpcodeDisplayLength() const override; virtual Ref<Architecture> GetAssociatedArchitectureByAddress(uint64_t& addr) override; @@ -3033,6 +3043,7 @@ namespace BinaryNinja class FunctionRecognizer { static bool RecognizeLowLevelILCallback(void* ctxt, BNBinaryView* data, BNFunction* func, BNLowLevelILFunction* il); + static bool RecognizeMediumLevelILCallback(void* ctxt, BNBinaryView* data, BNFunction* func, BNMediumLevelILFunction* il); public: FunctionRecognizer(); @@ -3041,6 +3052,7 @@ namespace BinaryNinja static void RegisterArchitectureFunctionRecognizer(Architecture* arch, FunctionRecognizer* recog); virtual bool RecognizeLowLevelIL(BinaryView* data, Function* func, LowLevelILFunction* il); + virtual bool RecognizeMediumLevelIL(BinaryView* data, Function* func, MediumLevelILFunction* il); }; class UpdateException: public std::exception @@ -3059,7 +3071,7 @@ namespace BinaryNinja static std::vector<UpdateChannel> GetList(); - bool AreUpdatesAvailable(); + bool AreUpdatesAvailable(uint64_t* expireTime, uint64_t* serverTime); BNUpdateResult UpdateToVersion(const std::string& version); BNUpdateResult UpdateToVersion(const std::string& version, @@ -3674,4 +3686,7 @@ namespace BinaryNinja bool IsArray() const; bool IsKeyValueStore() const; }; + + std::string GetLinuxCADirectory(); + std::string GetLinuxCABundlePath(); } diff --git a/binaryninjacore.h b/binaryninjacore.h index 7f107c60..baca94be 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -996,6 +996,7 @@ extern "C" uint64_t (*getEntryPoint)(void* ctxt); bool (*isExecutable)(void* ctxt); BNEndianness (*getDefaultEndianness)(void* ctxt); + bool (*isRelocatable)(void* ctxt); size_t (*getAddressSize)(void* ctxt); bool (*save)(void* ctxt, BNFileAccessor* accessor); }; @@ -1033,6 +1034,7 @@ extern "C" { size_t length; size_t branchCount; + bool archTransitionByTargetAddr; bool branchDelay; BNBranchType branchType[BN_MAX_INSTRUCTION_BRANCHES]; uint64_t branchTarget[BN_MAX_INSTRUCTION_BRANCHES]; @@ -1063,6 +1065,7 @@ extern "C" BNEndianness (*getEndianness)(void* ctxt); size_t (*getAddressSize)(void* ctxt); size_t (*getDefaultIntegerSize)(void* ctxt); + size_t (*getInstructionAlignment)(void* ctxt); size_t (*getMaxInstructionLength)(void* ctxt); size_t (*getOpcodeDisplayLength)(void* ctxt); BNArchitecture* (*getAssociatedArchitectureByAddress)(void* ctxt, uint64_t* addr); @@ -1254,6 +1257,7 @@ extern "C" { void* context; bool (*recognizeLowLevelIL)(void* ctxt, BNBinaryView* data, BNFunction* func, BNLowLevelILFunction* il); + bool (*recognizeMediumLevelIL)(void* ctxt, BNBinaryView* data, BNFunction* func, BNMediumLevelILFunction* il); }; struct BNTypeParserResult @@ -1268,7 +1272,8 @@ extern "C" { UpdateFailed = 0, UpdateSuccess = 1, - AlreadyUpToDate = 2 + AlreadyUpToDate = 2, + UpdateAvailable = 3 }; struct BNUpdateChannel @@ -1596,6 +1601,7 @@ extern "C" uint64_t start, length; uint64_t dataOffset, dataLength; uint32_t flags; + bool autoDefined; }; enum BNSectionSemantics @@ -1616,6 +1622,7 @@ extern "C" uint64_t infoData; uint64_t align, entrySize; BNSectionSemantics semantics; + bool autoDefined; }; struct BNAddressRange @@ -1680,7 +1687,10 @@ extern "C" BINARYNINJACOREAPI char* BNGetVersionString(void); BINARYNINJACOREAPI uint32_t BNGetBuildId(void); + BINARYNINJACOREAPI char* BNGetSerialNumber(void); + BINARYNINJACOREAPI uint64_t BNGetLicenseExpirationTime(void); BINARYNINJACOREAPI bool BNIsLicenseValidated(void); + BINARYNINJACOREAPI char* BNGetLicensedUserEmail(void); BINARYNINJACOREAPI char* BNGetProduct(void); BINARYNINJACOREAPI char* BNGetProductType(void); BINARYNINJACOREAPI int BNGetLicenseCount(void); @@ -1850,6 +1860,7 @@ extern "C" BINARYNINJACOREAPI BNPlatform* BNGetDefaultPlatform(BNBinaryView* view); BINARYNINJACOREAPI void BNSetDefaultPlatform(BNBinaryView* view, BNPlatform* platform); BINARYNINJACOREAPI BNEndianness BNGetDefaultEndianness(BNBinaryView* view); + BINARYNINJACOREAPI bool BNIsRelocatable(BNBinaryView* view); BINARYNINJACOREAPI size_t BNGetViewAddressSize(BNBinaryView* view); BINARYNINJACOREAPI bool BNIsViewModified(BNBinaryView* view); @@ -2017,6 +2028,7 @@ extern "C" BINARYNINJACOREAPI BNEndianness BNGetArchitectureEndianness(BNArchitecture* arch); BINARYNINJACOREAPI size_t BNGetArchitectureAddressSize(BNArchitecture* arch); BINARYNINJACOREAPI size_t BNGetArchitectureDefaultIntegerSize(BNArchitecture* arch); + BINARYNINJACOREAPI size_t BNGetArchitectureInstructionAlignment(BNArchitecture* arch); BINARYNINJACOREAPI size_t BNGetArchitectureMaxInstructionLength(BNArchitecture* arch); BINARYNINJACOREAPI size_t BNGetArchitectureOpcodeDisplayLength(BNArchitecture* arch); BINARYNINJACOREAPI BNArchitecture* BNGetAssociatedArchitectureByAddress(BNArchitecture* arch, uint64_t* addr); @@ -2860,7 +2872,7 @@ extern "C" BINARYNINJACOREAPI BNUpdateVersion* BNGetUpdateChannelVersions(const char* channel, size_t* count, char** errors); BINARYNINJACOREAPI void BNFreeUpdateChannelVersionList(BNUpdateVersion* list, size_t count); - BINARYNINJACOREAPI bool BNAreUpdatesAvailable(const char* channel, char** errors); + BINARYNINJACOREAPI bool BNAreUpdatesAvailable(const char* channel, uint64_t* expireTime, uint64_t* serverTime, char** errors); BINARYNINJACOREAPI BNUpdateResult BNUpdateToVersion(const char* channel, const char* version, char** errors, bool (*progress)(void* ctxt, uint64_t progress, uint64_t total), @@ -3277,6 +3289,8 @@ extern "C" BINARYNINJACOREAPI BNMetadata* BNBinaryViewQueryMetadata(BNBinaryView* view, const char* key); BINARYNINJACOREAPI void BNBinaryViewRemoveMetadata(BNBinaryView* view, const char* key); + BINARYNINJACOREAPI char* BNGetLinuxCADirectory(); + BINARYNINJACOREAPI char* BNGetLinuxCABundlePath(); #ifdef __cplusplus } #endif diff --git a/binaryview.cpp b/binaryview.cpp index 213be79a..50011a0f 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -288,6 +288,7 @@ BinaryView::BinaryView(const std::string& typeName, FileMetadata* file, BinaryVi view.getEntryPoint = GetEntryPointCallback; view.isExecutable = IsExecutableCallback; view.getDefaultEndianness = GetDefaultEndiannessCallback; + view.isRelocatable = IsRelocatableCallback; view.getAddressSize = GetAddressSizeCallback; view.save = SaveCallback; @@ -431,6 +432,13 @@ BNEndianness BinaryView::GetDefaultEndiannessCallback(void* ctxt) } +bool BinaryView::IsRelocatableCallback(void* ctxt) +{ + BinaryView* view = (BinaryView*)ctxt; + return view->PerformIsRelocatable(); +} + + size_t BinaryView::GetAddressSizeCallback(void* ctxt) { BinaryView* view = (BinaryView*)ctxt; @@ -494,6 +502,11 @@ BNEndianness BinaryView::PerformGetDefaultEndianness() const } +bool BinaryView::PerformIsRelocatable() const +{ + return false; +} + size_t BinaryView::PerformGetAddressSize() const { Ref<Architecture> arch = GetDefaultArchitecture(); @@ -836,6 +849,12 @@ BNEndianness BinaryView::GetDefaultEndianness() const } +bool BinaryView::IsRelocatable() const +{ + return BNIsRelocatable(m_object); +} + + size_t BinaryView::GetAddressSize() const { return BNGetViewAddressSize(m_object); @@ -1705,6 +1724,7 @@ vector<Segment> BinaryView::GetSegments() segment.dataOffset = segments[i].dataOffset; segment.dataLength = segments[i].dataLength; segment.flags = segments[i].flags; + segment.autoDefined = segments[i].autoDefined; result.push_back(segment); } @@ -1712,7 +1732,6 @@ vector<Segment> BinaryView::GetSegments() return result; } - bool BinaryView::GetSegmentAt(uint64_t addr, Segment& result) { BNSegment segment; diff --git a/docs/getting-started.md b/docs/getting-started.md index 692c1e67..88945f7b 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -210,6 +210,8 @@ By default the interactive python prompt has a number of convenient helper funct - `bv` / `current_view` / : the current [BinaryView](https://api.binary.ninja/binaryninja.BinaryView.html) - `current_function`: the current [Function](https://api.binary.ninja/binaryninja.Function.html) - `current_basic_block`: the current [BasicBlock](https://api.binary.ninja/binaryninja.BasicBlock.html) +- `current_llil`: the current [LowLevelILBasicBlock](https://api.binary.ninja/binaryninja.lowlevelil.LowLevelILBasicBlock.html) +- `current_mlil`: the current [MediumLevelILBasicBlock](https://api.binary.ninja/binaryninja.mediumlevelil.MediumLevelILBasicBlock.html) - `current_selection`: a tuple of the start and end addresses of the current selection - `write_at_cursor(data)`: function that writes data to the start of the current selection - `get_selected_data()`: function that returns the data in the current selection @@ -253,6 +255,8 @@ Settings are stored in the _user_ directory in the file `settings.json`. Each to |Plugin | Setting | Type | Default | Description | |------:|-------------------------:|-------------:|-----------------------------------------------:|:----------------------------------------------------------------------------------------------| +| core | linux\_ca\_bundle | string | "" | Certificate authority (.pem or .crt) file to be used for secure downloads | +| core | linux\_ca\_dir | string | "" | Certificate authority directory (for distributions without a CA bundle) | | ui | activeContent | boolean | True | Allow Binary Ninja to connect to the web to check for updates | | ui | colorblind | boolean | True | Choose colors that are visible to those with red/green colorblind | | ui | debug | boolean | False | Enable developer debugging features (Additional views: Lifted IL, and SSA forms) | diff --git a/docs/guide/plugins.md b/docs/guide/plugins.md index 9c67d44f..442d6fe4 100644 --- a/docs/guide/plugins.md +++ b/docs/guide/plugins.md @@ -36,9 +36,9 @@ Binary Ninja now offers a [PluginManager API] which can simplify the process of ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'add_repository', 'check_for_updates', 'default_repository', 'disable_plugin', 'enable_plugin', 'handle', 'install_plugin', 'plugins', 'repositories', 'uninstall_plugin', 'update_plugin'] >>> mgr.plugins {'default': [<binaryninja-bookmarks not-installed/disabled>, <binaryninja-msp430 not-installed/disabled>, <binaryninja-radare2 not-installed/disabled>, <binaryninja-spu not-installed/disabled>, <binja-avr not-installed/disabled>, <binja_smali not-installed/disabled>, <binjatron not-installed/disabled>, <binoculars not-installed/disabled>, <easypatch not-installed/disabled>, <liil installed/enabled>, <list_comments not-installed/disabled>, <x64dbgbinja not-installed/disabled>]} ->>> mgr.install_plugin(easypatch) +>>> mgr.install_plugin("easypatch") True ->>> mgr.enable(easypatch) +>>> mgr.enable_plugin("easypatch") True ``` diff --git a/docs/guide/troubleshooting.md b/docs/guide/troubleshooting.md index a640d47e..5e310dfb 100644 --- a/docs/guide/troubleshooting.md +++ b/docs/guide/troubleshooting.md @@ -36,6 +36,16 @@ Next, if running a python plugin, make sure the python requirements are met by y - If experiencing problems with Windows UAC permissions during an update, the easiest fix is to completely un-install and [recover][recover] the latest installer and license. Preferences are saved outside the installation folder and are preserved, though you might want to remove your [license](/getting-started/#license). - If you need to change the email address on your license, contact [support]. +## OS X + +While OS X is generally the most trouble-free environment for Binary Ninja, very old versions may have problems with the RPATH for our binaries and libraries. There are two solutions. First, run Binary Ninja with: + +``` +DYLD_LIBRARY_PATH="/Applications/Binary Ninja.app/Contents/MacOS" /Applications/Binary\ Ninja.app/Contents/MacOS/binaryninja +``` + +Or second, modify the binary itself using the [install_name_tool](https://blogs.oracle.com/dipol/dynamic-libraries,-rpath,-and-mac-os). + ## Linux Given the diversity of Linux distributions, some work-arounds are required to run Binary Ninja on platforms that are not [officially supported][faq]. @@ -67,9 +77,17 @@ QT_PLUGIN_PATH=./qt ./binaryninja For Debian variants that (Kali, eg) don't match packages with Ubuntu LTS or the latest stable, the following might fix problems with libssl and libcrypto: ``` -$ cd binaryninja/plugins -$ ln -s libssl.so libssl.so.1.0.0 -$ ln -s libcrypto.so libcrypto.so.1.0.0 +$ cd binaryninja +$ ln -s plugins/libssl.so libssl.so.1.0.0 +$ ln -s plugins/libcrypto.so libcrypto.so.1.0.0 +``` + +Alternatively, you might need to (as root): + +``` +apt-get install libssl-dev +ln -s /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.2 /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0 +ln -s /usr/lib/x86_64-linux-gnu/libssl.so.1.0.2 /usr/lib/x86_64-linux-gnu/libssl.so.1.0.0 ``` ### Gentoo diff --git a/examples/cmdline_disasm/Makefile b/examples/cmdline_disasm/Makefile new file mode 100644 index 00000000..12931876 --- /dev/null +++ b/examples/cmdline_disasm/Makefile @@ -0,0 +1,51 @@ +# Path to prebuilt libbinaryninjaapi.a +BINJA_API_A := ../../bin/libbinaryninjaapi.a + +# Path to binaryninjaapi.h and json +INC := -I../../ + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + # Path to binaryninja install + BINJAPATH := $(HOME)/binaryninja/ + CC := gcc +else + BINJAPATH := /Applications/Binary\ Ninja.app/Contents/MacOS + CC := clang +endif + +SRCDIR := src +BUILDDIR := build +TARGETDIR := bin + +TARGETNAME := disasm +TARGET := $(TARGETDIR)/$(TARGETNAME) + +SRCEXT := cpp +SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT)) +OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o)) + +LIBS := -L $(BINJAPATH) -lbinaryninjacore +CPPFLAGS := -c -O2 -Wall -W -fPIC --std=c++11 -pipe + +all: $(TARGET) + +ifeq ($(UNAME_S),Linux) +$(TARGET): $(OBJECTS) + @mkdir -p $(TARGETDIR) + $(CC) $^ $(BINJA_API_A) $(LIBS) -Wl,-rpath=$(BINJAPATH) -ldl -o $@ +else +$(TARGET): $(OBJECTS) + @mkdir -p $(TARGETDIR) + $(CC) $^ $(BINJA_API_A) $(LIBS) -o $@ + install_name_tool -change @rpath/libbinaryninjacore.dylib $(BINJAPATH)/libbinaryninjacore.dylib $@ +endif + +$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT) + @mkdir -p $(BUILDDIR) + $(CC) $(CPPFLAGS) $(INC) -c -o $@ $< + +clean: + $(RM) -r $(BUILDDIR) $(TARGETDIR) + +.PHONY: clean diff --git a/examples/cmdline_disasm/src/disasm.cpp b/examples/cmdline_disasm/src/disasm.cpp new file mode 100644 index 00000000..c763fc11 --- /dev/null +++ b/examples/cmdline_disasm/src/disasm.cpp @@ -0,0 +1,152 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include "binaryninjacore.h" +#include "binaryninjaapi.h" + +using namespace BinaryNinja; + +/* forward declarations */ +int parse_nib(const char *str, uint8_t *val); +int parse_uint8_hex(const char *str, uint8_t *result); + +/****************************************************************************** + MAIN +******************************************************************************/ + +void usage(int ac, char **av) +{ + (void)ac; + printf(" syntax: %s <arch+mode> <byte0> <byte1> ...\n", av[0]); + printf("examples:\n"); + printf(" %s x86 83 83 ec 0c\n", av[0]); + printf(" %s x86_64 48 89 e5\n", av[0]); + printf(" %s armv7 14 d0 4d e2\n", av[0]); + printf(" %s armv7eb d0 14 e2 4d\n", av[0]); + printf(" %s thumb2 4f f0 00 0c\n", av[0]); + printf(" %s thumb2eb f0 4f 0c 00\n", av[0]); + printf(" %s ppc 93 e1 ff fc\n", av[0]); + printf(" %s aarch64 ff 43 00 d1\n", av[0]); + printf(" %s mips32 27 bd ff f0\n", av[0]); + printf(" %s mipsel32 f0 ff bd 27\n", av[0]); +} + +int main(int ac, char **av) +{ + int rc = -1; + unsigned int i; + + char *archmode; + BNArchitecture *arch; + + size_t nBytesDisasm; + + uint8_t input[64]; + unsigned int input_n; + + BNInstructionTextToken *ttResult = NULL; + size_t ttCount; + + char *path_bundled_plugins; + + /* plugin path */ + path_bundled_plugins = BNGetBundledPluginDirectory(); + printf("using bundled plugin path: %s\n", path_bundled_plugins); + BNSetBundledPluginDirectory(path_bundled_plugins); + BNInitCorePlugins(); + + /* parse architecture argument */ + if(ac < 2) + { usage(ac, av); goto cleanup; } + archmode = av[1]; + + printf("looking up architecture \"%s\"\n", archmode); + arch = BNGetArchitectureByName(archmode); + if(!arch) { + printf("ERROR: BNGetArchitectureByName() (is \"%s\" valid?)\n", archmode); + usage(ac, av); + goto cleanup; + } + + /* parse bytes argument */ + input_n = ac - 2; + for(i=0; i<input_n && i<sizeof(input); ++i) { + if(parse_uint8_hex(av[i+2], input+i)) { + printf("ERROR: can't parse byte: %s\n", av[i+2]); + goto cleanup; + } + } + + printf("parsed bytes: "); + for(i=0; i<input_n; ++i) + printf("%02X ", input[i]); + printf("\n"); + + /* actually disassemble now */ + nBytesDisasm = input_n; + BNGetInstructionText(arch, (const uint8_t *)input, 0, &nBytesDisasm, + &ttResult, &ttCount); + + //printf("%zu text tokens\n", ttCount); + + for(i=0; i<ttCount; ++i) + printf("%s", ttResult[i].text); + printf("\n"); + + /* done! */ + cleanup: + if(ttResult) + BNFreeInstructionText(ttResult, ttCount); + return rc; +} + +/****************************************************************************** + PARSING +******************************************************************************/ + +int parse_nib(const char *str, uint8_t *val) +{ + int rc = -1; + char c = *str; + + if(c>='0' && c<='9') { + *val = c-'0'; + rc = 0; + } + else if(c>='a' && c<='f') { + *val = 10 + (c-'a'); + rc = 0; + } + else if(c>='A' && c<='F') { + *val = 10 + (c-'A'); + rc = 0; + } + else { + printf("ERROR: %s('%c', ...)\n", __func__, c); + } + + return rc; +} + +int parse_uint8_hex(const char *str, uint8_t *result) +{ + int rc=-1; + uint8_t v1, v2; + + if(parse_nib(str, &v1)) + goto cleanup; + if(parse_nib(str+1, &v2)) + goto cleanup; + + *result = (v1 << 4) | v2; + rc = 0; + + cleanup: + return rc; +} + diff --git a/examples/x86_extension/src/asmx86 b/examples/x86_extension/src/asmx86 -Subproject f78096d79ccfcc5169b6e2ae0fa89e3eed5b85c +Subproject 9a1bf01f4c456779544a445db45b1496c50ff37 diff --git a/examples/x86_extension/src/x86_extension.cpp b/examples/x86_extension/src/x86_extension.cpp index 9efcc119..a2ba4c9c 100644 --- a/examples/x86_extension/src/x86_extension.cpp +++ b/examples/x86_extension/src/x86_extension.cpp @@ -306,6 +306,7 @@ static void Repeat(size_t addrSize, } } + // This is a wrapper for the x86 architecture. Its useful for extending and improving // the existing core x86 architecture. class x86ArchitectureExtension: public Architecture @@ -327,6 +328,11 @@ public: return LittleEndian; } + virtual size_t GetInstructionAlignment() const override + { + return 1; + } + virtual bool GetInstructionInfo(const uint8_t* data, uint64_t addr, size_t maxLen, InstructionInfo& result) override { return m_arch->GetInstructionInfo(data, addr, maxLen, result); @@ -345,8 +351,11 @@ public: il.AddInstruction(il.Undefined()); return false; } - if (instr.operation == CPUID) + + size_t addrSize = 4; + switch (instr.operation) { + case CPUID: // The default implementation of CPUID doesn't set registers to constant values // Here we'll emulate a Intel(R) Core(TM) i5-6267U CPU @ 2.90GHz with _eax set to 1 il.AddInstruction(il.Register(4, REG_EAX)); // Reference the register so we know it is read @@ -356,8 +365,96 @@ public: il.AddInstruction(il.SetRegister(4, REG_EDX, il.Const(4, 0xbfebfbff))); len = instr.length; return true; + + case JMP: + if (instr.operands[0].operand == IMM) + il.AddInstruction(DirectJump(this, il, instr.operands[0].immediate, addrSize)); + else + il.AddInstruction(il.Jump(ReadILOperand(il, instr, 0, addrSize, true))); + return false; + + case JO: + ConditionalJump(this, il, il.FlagCondition(LLFC_O), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JNO: + ConditionalJump(this, il, il.FlagCondition(LLFC_NO), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JB: + ConditionalJump(this, il, il.FlagCondition(LLFC_ULT), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JAE: + ConditionalJump(this, il, il.FlagCondition(LLFC_UGE), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JE: + ConditionalJump(this, il, il.FlagCondition(LLFC_E), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JNE: + ConditionalJump(this, il, il.FlagCondition(LLFC_NE), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JBE: + ConditionalJump(this, il, il.FlagCondition(LLFC_ULE), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JA: + ConditionalJump(this, il, il.FlagCondition(LLFC_UGT), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JS: + ConditionalJump(this, il, il.FlagCondition(LLFC_NEG), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JNS: + ConditionalJump(this, il, il.FlagCondition(LLFC_POS), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JPE: + ConditionalJump(this, il, il.Not(0, il.Flag(IL_FLAG_P)), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JPO: + ConditionalJump(this, il, il.Flag(IL_FLAG_P), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JL: + ConditionalJump(this, il, il.FlagCondition(LLFC_SLT), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JGE: + ConditionalJump(this, il, il.FlagCondition(LLFC_SGE), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JLE: + ConditionalJump(this, il, il.FlagCondition(LLFC_SLE), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JG: + ConditionalJump(this, il, il.FlagCondition(LLFC_SGT), addrSize, instr.operands[0].immediate, addr + instr.length); + return false; + + case JCXZ: + ConditionalJump(this, il, il.CompareEqual(2, il.Register(2, REG_CX), il.Const(2, 0)), addrSize, + instr.operands[0].immediate, addr + instr.length); + return false; + + case JECXZ: + ConditionalJump(this, il, il.CompareEqual(4, il.Register(4, REG_ECX), il.Const(4, 0)), addrSize, + instr.operands[0].immediate, addr + instr.length); + return false; + + case JRCXZ: + ConditionalJump(this, il, il.CompareEqual(8, il.Register(8, REG_RCX), il.Const(8, 0)), addrSize, + instr.operands[0].immediate, addr + instr.length); + return false; + + default: + return m_arch->GetInstructionLowLevelIL(data, addr, len, il); } - return m_arch->GetInstructionLowLevelIL(data, addr, len, il); } virtual size_t GetFlagWriteLowLevelIL(BNLowLevelILOperation op, size_t size, uint32_t flagWriteType, @@ -485,6 +582,12 @@ public: extern "C" { + BINARYNINJAPLUGIN void CorePluginDependencies() + { + // Make sure we load after the original x86 plugin loads + SetCurrentPluginLoadOrder(LatePluginLoadOrder); + } + BINARYNINJAPLUGIN bool CorePluginInit() { Architecture* x86ext = new x86ArchitectureExtension(); diff --git a/functionrecognizer.cpp b/functionrecognizer.cpp index 32c7245c..34f1db80 100644 --- a/functionrecognizer.cpp +++ b/functionrecognizer.cpp @@ -38,11 +38,22 @@ bool FunctionRecognizer::RecognizeLowLevelILCallback(void* ctxt, BNBinaryView* d } +bool FunctionRecognizer::RecognizeMediumLevelILCallback(void* ctxt, BNBinaryView* data, BNFunction* func, BNMediumLevelILFunction* il) +{ + FunctionRecognizer* recog = (FunctionRecognizer*)ctxt; + Ref<BinaryView> dataObj = new BinaryView(BNNewViewReference(data)); + Ref<Function> funcObj = new Function(BNNewFunctionReference(func)); + Ref<MediumLevelILFunction> ilObj = new MediumLevelILFunction(BNNewMediumLevelILFunctionReference(il)); + return recog->RecognizeMediumLevelIL(dataObj, funcObj, ilObj); +} + + void FunctionRecognizer::RegisterGlobalRecognizer(FunctionRecognizer* recog) { BNFunctionRecognizer reg; reg.context = recog; reg.recognizeLowLevelIL = RecognizeLowLevelILCallback; + reg.recognizeMediumLevelIL = RecognizeMediumLevelILCallback; BNRegisterGlobalFunctionRecognizer(®); } @@ -52,6 +63,7 @@ void FunctionRecognizer::RegisterArchitectureFunctionRecognizer(Architecture* ar BNFunctionRecognizer reg; reg.context = recog; reg.recognizeLowLevelIL = RecognizeLowLevelILCallback; + reg.recognizeMediumLevelIL = RecognizeMediumLevelILCallback; BNRegisterArchitectureFunctionRecognizer(arch->GetObject(), ®); } @@ -60,3 +72,9 @@ bool FunctionRecognizer::RecognizeLowLevelIL(BinaryView*, Function*, LowLevelILF { return false; } + + +bool FunctionRecognizer::RecognizeMediumLevelIL(BinaryView*, Function*, MediumLevelILFunction*) +{ + return false; +} diff --git a/interaction.cpp b/interaction.cpp index fb4eb6d4..2f84c4ec 100644 --- a/interaction.cpp +++ b/interaction.cpp @@ -119,8 +119,6 @@ void InteractionHandler::ShowHTMLReport(Ref<BinaryView> view, const string& titl bool InteractionHandler::GetIntegerInput(int64_t& result, const string& prompt, const string& title) { - string input; - while (true) { string input; diff --git a/lowlevelilinstruction.h b/lowlevelilinstruction.h index cfc7e2d7..a0a867af 100644 --- a/lowlevelilinstruction.h +++ b/lowlevelilinstruction.h @@ -183,10 +183,10 @@ namespace std #else typedef BinaryNinja::SSARegister argument_type; #endif - typedef uint64_t result_type; + typedef uint32_t result_type; result_type operator()(argument_type const& value) const { - return ((result_type)value.reg) ^ ((result_type)value.version << 32); + return ((result_type)value.reg) ^ ((result_type)value.version << 16); } }; @@ -219,10 +219,10 @@ namespace std #else typedef BinaryNinja::SSAFlag argument_type; #endif - typedef uint64_t result_type; + typedef uint32_t result_type; result_type operator()(argument_type const& value) const { - return ((result_type)value.flag) ^ ((result_type)value.version << 32); + return ((result_type)value.flag) ^ ((result_type)value.version << 16); } }; diff --git a/mediumlevelilinstruction.h b/mediumlevelilinstruction.h index 85630843..8e671aaf 100644 --- a/mediumlevelilinstruction.h +++ b/mediumlevelilinstruction.h @@ -133,10 +133,11 @@ namespace std #else typedef BinaryNinja::SSAVariable argument_type; #endif - typedef uint64_t result_type; + typedef uint32_t result_type; result_type operator()(argument_type const& value) const { - return ((result_type)value.var.ToIdentifier()) ^ ((result_type)value.version << 40); + uint64_t hashTmp = ((uint64_t)value.var.ToIdentifier()) ^ ((uint64_t)value.version << 40); + return (uint32_t)((hashTmp >> 32) ^ (uint32_t)hashTmp); } }; diff --git a/python/__init__.py b/python/__init__.py index f4a8fac8..729e4f8a 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -21,6 +21,7 @@ import atexit import sys +from time import gmtime # Binary Ninja components import _binaryninjacore as core @@ -147,6 +148,12 @@ core_version = core.BNGetVersionString() core_build_id = core.BNGetBuildId() '''Build ID''' +core_serial = core.BNGetSerialNumber() +'''Serial Number''' + +core_expires = gmtime(core.BNGetLicenseExpirationTime()) +'''License Expiration''' + core_product = core.BNGetProduct() '''Product string from the license file''' diff --git a/python/architecture.py b/python/architecture.py index c4179b00..08049d46 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -111,6 +111,7 @@ class Architecture(object): endianness = Endianness.LittleEndian address_size = 8 default_int_size = 4 + instr_alignment = 1 max_instr_length = 16 opcode_display_length = 8 regs = {} @@ -133,6 +134,7 @@ class Architecture(object): self.__dict__["endianness"] = Endianness(core.BNGetArchitectureEndianness(self.handle)) self.__dict__["address_size"] = core.BNGetArchitectureAddressSize(self.handle) self.__dict__["default_int_size"] = core.BNGetArchitectureDefaultIntegerSize(self.handle) + self.__dict__["instr_alignment"] = core.BNGetArchitectureInstructionAlignment(self.handle) self.__dict__["max_instr_length"] = core.BNGetArchitectureMaxInstructionLength(self.handle) self.__dict__["opcode_display_length"] = core.BNGetArchitectureOpcodeDisplayLength(self.handle) self.__dict__["stack_pointer"] = core.BNGetArchitectureRegisterName(self.handle, @@ -245,6 +247,7 @@ class Architecture(object): self._cb.getEndianness = self._cb.getEndianness.__class__(self._get_endianness) self._cb.getAddressSize = self._cb.getAddressSize.__class__(self._get_address_size) self._cb.getDefaultIntegerSize = self._cb.getDefaultIntegerSize.__class__(self._get_default_integer_size) + self._cb.getInstructionAlignment = self._cb.getInstructionAlignment.__class__(self._get_instruction_alignment) self._cb.getMaxInstructionLength = self._cb.getMaxInstructionLength.__class__(self._get_max_instruction_length) self._cb.getOpcodeDisplayLength = self._cb.getOpcodeDisplayLength.__class__(self._get_opcode_display_length) self._cb.getAssociatedArchitectureByAddress = \ @@ -429,7 +432,8 @@ class Architecture(object): def __setattr__(self, name, value): if ((name == "name") or (name == "endianness") or (name == "address_size") or - (name == "default_int_size") or (name == "regs") or (name == "get_max_instruction_length")): + (name == "default_int_size") or (name == "regs") or (name == "get_max_instruction_length") or + (name == "get_instruction_alignment")): raise AttributeError("attribute '%s' is read only" % name) else: try: @@ -464,6 +468,13 @@ class Architecture(object): log.log_error(traceback.format_exc()) return 4 + def _get_instruction_alignment(self, ctxt): + try: + return self.__class__.instr_alignment + except: + log.log_error(traceback.format_exc()) + return 1 + def _get_max_instruction_length(self, ctxt): try: return self.__class__.max_instr_length @@ -495,6 +506,7 @@ class Architecture(object): if info is None: return False result[0].length = info.length + result[0].archTransitionByTargetAddr = info.arch_transition_by_target_addr result[0].branchDelay = info.branch_delay result[0].branchCount = len(info.branches) for i in xrange(0, len(info.branches)): @@ -1247,6 +1259,7 @@ class Architecture(object): return None result = function.InstructionInfo() result.length = info.length + result.arch_transition_by_target_addr = info.archTransitionByTargetAddr result.branch_delay = info.branchDelay for i in xrange(0, info.branchCount): target = info.branchTarget[i] diff --git a/python/basicblock.py b/python/basicblock.py index 26db925d..8e64c1c1 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -35,6 +35,14 @@ class BasicBlockEdge(object): self.target = target self.back_edge = back_edge + def __eq__(self, value): + if not isinstance(value, BasicBlockEdge): + return False + return (self.type, self.source, self.target, self.back_edge) == (value.type, value.source, value.target, value.back_edge) + + def __hash__(self): + return hash((self.type, self.source, self.target, self.back_edge)) + def __repr__(self): if self.type == BranchType.UnresolvedBranch: return "<%s>" % BranchType(self.type).name @@ -68,6 +76,9 @@ class BasicBlock(object): """Internal method used to instantiante child instances""" return BasicBlock(view, handle) + def __hash__(self): + return hash((self.start, self.end, self.arch.name)) + @property def function(self): """Basic block function (read-only)""" diff --git a/python/binaryview.py b/python/binaryview.py index 9304d412..6eb59db1 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -103,6 +103,17 @@ class StringReference(object): class AnalysisCompletionEvent(object): + """ + The ``AnalysisCompletionEvent`` object provides an asynchronous mechanism for receiving + callbacks when analysis is complete. + + :Example: + >>> def on_complete(self): + ... print "Analysis Complete", self.view + ... + >>> evt = AnalysisCompletionEvent(bv, on_complete) + >>> + """ def __init__(self, view, callback): self.view = view self.callback = callback @@ -114,7 +125,7 @@ class AnalysisCompletionEvent(object): def _notify(self, ctxt): try: - self.callback() + self.callback(self) except: log.log_error(traceback.format_exc()) @@ -405,12 +416,13 @@ class BinaryViewType(object): class Segment(object): - def __init__(self, start, length, data_offset, data_length, flags): + def __init__(self, start, length, data_offset, data_length, flags, auto_defined): self.start = start self.length = length self.data_offset = data_offset self.data_length = data_length self.flags = flags + self.auto_defined = auto_defined @property def executable(self): @@ -439,7 +451,7 @@ class Segment(object): class Section(object): - def __init__(self, name, section_type, start, length, linked_section, info_section, info_data, align, entry_size, semantics): + def __init__(self, name, section_type, start, length, linked_section, info_section, info_data, align, entry_size, semantics, auto_defined): self.name = name self.type = section_type self.start = start @@ -450,6 +462,7 @@ class Section(object): self.align = align self.entry_size = entry_size self.semantics = SectionSemantics(semantics) + self.auto_defined = auto_defined @property def end(self): @@ -572,6 +585,7 @@ class BinaryView(object): self._cb.getEntryPoint = self._cb.getEntryPoint.__class__(self._get_entry_point) self._cb.isExecutable = self._cb.isExecutable.__class__(self._is_executable) self._cb.getDefaultEndianness = self._cb.getDefaultEndianness.__class__(self._get_default_endianness) + self._cb.isRelocatable = self._cb.isRelocatable.__class__(self._is_relocatable) self._cb.getAddressSize = self._cb.getAddressSize.__class__(self._get_address_size) self._cb.save = self._cb.save.__class__(self._save) self.file = file_metadata @@ -828,6 +842,11 @@ class BinaryView(object): return Endianness(core.BNGetDefaultEndianness(self.handle)) @property + def relocatable(self): + """Boolean - is the binary relocatable (read-only)""" + return core.BNIsRelocatable(self.handle) + + @property def address_size(self): """Address size of the binary (read-only)""" return core.BNGetViewAddressSize(self.handle) @@ -948,7 +967,7 @@ class BinaryView(object): result = [] for i in xrange(0, count.value): result.append(Segment(segment_list[i].start, segment_list[i].length, - segment_list[i].dataOffset, segment_list[i].dataLength, segment_list[i].flags)) + segment_list[i].dataOffset, segment_list[i].dataLength, segment_list[i].flags, segment_list[i].autoDefined)) core.BNFreeSegmentList(segment_list) return result @@ -962,7 +981,7 @@ class BinaryView(object): result[section_list[i].name] = Section(section_list[i].name, section_list[i].type, section_list[i].start, section_list[i].length, section_list[i].linkedSection, section_list[i].infoSection, section_list[i].infoData, section_list[i].align, section_list[i].entrySize, - section_list[i].semantics) + section_list[i].semantics, section_list[i].autoDefined) core.BNFreeSectionList(section_list, count.value) return result @@ -1191,6 +1210,13 @@ class BinaryView(object): log.log_error(traceback.format_exc()) return Endianness.LittleEndian + def _is_relocatable(self, ctxt): + try: + return self.perform_is_relocatable() + except: + log.log_error(traceback.format_exc()) + return False + def _get_address_size(self, ctxt): try: return self.perform_get_address_size() @@ -1483,6 +1509,19 @@ class BinaryView(object): """ return Endianness.LittleEndian + def perform_is_relocatable(self): + """ + ``perform_is_relocatable`` implements a check which returns true if the BinaryView is relocatable. Defaults to + True. + + .. note:: This method **may** be implemented for custom BinaryViews that are relocatable. + .. warning:: This method **must not** be called directly. + + :return: True if the BinaryView is relocatable, False otherwise + :rtype: boolean + """ + return True + def create_database(self, filename, progress_func=None): """ ``create_database`` writes the current database (.bndb) file out to the specified file. @@ -3316,7 +3355,7 @@ class BinaryView(object): if not core.BNGetSegmentAt(self.handle, addr, segment): return None result = Segment(segment.start, segment.length, segment.dataOffset, segment.dataLength, - segment.flags) + segment.flags, segment.autoDefined) return result def get_address_for_data_offset(self, offset): @@ -3349,7 +3388,7 @@ class BinaryView(object): result.append(Section(section_list[i].name, section_list[i].type, section_list[i].start, section_list[i].length, section_list[i].linkedSection, section_list[i].infoSection, section_list[i].infoData, section_list[i].align, section_list[i].entrySize, - section_list[i].semantics)) + section_list[i].semantics, section_list[i].autoDefined)) core.BNFreeSectionList(section_list, count.value) return result @@ -3358,7 +3397,8 @@ class BinaryView(object): if not core.BNGetSectionByName(self.handle, name, section): return None result = Section(section.name, section.type, section.start, section.length, section.linkedSection, - section.infoSection, section.infoData, section.align, section.entrySize, section.semantics) + section.infoSection, section.infoData, section.align, section.entrySize, section.semantics, + section_list.autoDefined) core.BNFreeSection(section) return result diff --git a/python/examples/nes.py b/python/examples/nes.py index e55a90b7..39544c9f 100644 --- a/python/examples/nes.py +++ b/python/examples/nes.py @@ -367,6 +367,7 @@ class M6502(Architecture): name = "6502" address_size = 2 default_int_size = 1 + instr_alignment = 1 max_instr_length = 3 regs = { "a": RegisterInfo("a", 1), diff --git a/python/function.py b/python/function.py index db4ca0f5..10583b58 100644 --- a/python/function.py +++ b/python/function.py @@ -171,6 +171,8 @@ class PossibleValueSet(object): self.reg = arch.get_reg_name(value.value) elif value.state == RegisterValueType.ConstantValue: self.value = value.value + elif value.state == RegisterValueType.ConstantPointerValue: + self.value = value.value elif value.state == RegisterValueType.StackFrameOffset: self.offset = value.value elif value.state == RegisterValueType.SignedRangeValue: @@ -212,6 +214,8 @@ class PossibleValueSet(object): return "<entry %s>" % self.reg if self.type == RegisterValueType.ConstantValue: return "<const %#x>" % self.value + if self.type == RegisterValueType.ConstantPointerValue: + return "<const ptr %#x>" % self.value if self.type == RegisterValueType.StackFrameOffset: return "<stack frame offset %#x>" % self.offset if self.type == RegisterValueType.SignedRangeValue: @@ -290,10 +294,10 @@ class Variable(object): return self.name def __eq__(self, other): - return self.identifier == other.identifier + return (self.identifier, self.function) == (other.identifier, other.function) def __hash__(self): - return hash(self.identifier) + return hash((self.identifier, self.function)) class ConstantReference(object): @@ -356,6 +360,8 @@ class Function(object): self._view = view self.handle = core.handle_of_type(handle, core.BNFunction) self._advanced_analysis_requests = 0 + self._arch = None + self._platform = None def __del__(self): if self._advanced_analysis_requests > 0: @@ -407,18 +413,26 @@ class Function(object): @property def arch(self): """Function architecture (read-only)""" - arch = core.BNGetFunctionArchitecture(self.handle) - if arch is None: - return None - return architecture.Architecture(arch) + if self._arch: + return self._arch + else: + arch = core.BNGetFunctionArchitecture(self.handle) + if arch is None: + return None + self._arch = architecture.Architecture(arch) + return self._arch @property def platform(self): """Function platform (read-only)""" - plat = core.BNGetFunctionPlatform(self.handle) - if plat is None: - return None - return platform.Platform(None, handle = plat) + if self._platform: + return self._platform + else: + plat = core.BNGetFunctionPlatform(self.handle) + if plat is None: + return None + self._platform = platform.Platform(None, handle = plat) + return self._platform @property def start(self): @@ -768,6 +782,41 @@ class Function(object): """Sets a comment for the current function""" return core.BNSetFunctionComment(self.handle, comment) + @property + def llil_basic_blocks(self): + """A generator of all LowLevelILBasicBlock objects in the current function""" + for block in self.low_level_il: + yield block + + @property + def mlil_basic_blocks(self): + """A generator of all MediumLevelILBasicBlock objects in the current function""" + for block in self.medium_level_il: + yield block + + @property + def instructions(self): + """A generator of instruction tokens and their start addresses for the current function""" + for block in self.basic_blocks: + start = block.start + for i in block: + yield (i[0], start) + start += i[1] + + @property + def llil_instructions(self): + """A generator of llil instructions of the current function""" + for block in self.llil_basic_blocks: + for i in block: + yield i + + @property + def mlil_instructions(self): + """A generator of mlil instructions of the current function""" + for block in self.mlil_basic_blocks: + for i in block: + yield i + def __iter__(self): count = ctypes.c_ulonglong() blocks = core.BNGetFunctionBasicBlockList(self.handle, count) @@ -829,7 +878,13 @@ class Function(object): """ if arch is None: arch = self.arch - return self.low_level_il[core.BNGetLowLevelILForInstruction(self.handle, arch.handle, addr)] + + idx = core.BNGetLowLevelILForInstruction(self.handle, arch.handle, addr) + + if idx == len(self.low_level_il): + return None + + return self.low_level_il[idx] def get_low_level_il_exits_at(self, addr, arch=None): if arch is None: @@ -980,7 +1035,13 @@ class Function(object): def get_lifted_il_at(self, addr, arch=None): if arch is None: arch = self.arch - return self.lifted_il[core.BNGetLiftedILForInstruction(self.handle, arch.handle, addr)] + + idx = core.BNGetLiftedILForInstruction(self.handle, arch.handle, addr) + + if idx == len(self.lifted_il): + return None + + return self.lifted_il[idx] def get_lifted_il_flag_uses_for_definition(self, i, flag): flag = self.arch.get_flag_index(flag) @@ -1833,6 +1894,7 @@ class InstructionBranch(object): class InstructionInfo(object): def __init__(self): self.length = 0 + self.arch_transition_by_target_addr = False self.branch_delay = False self.branches = [] diff --git a/python/functionrecognizer.py b/python/functionrecognizer.py index 8514a2ee..4ac304ca 100644 --- a/python/functionrecognizer.py +++ b/python/functionrecognizer.py @@ -36,6 +36,7 @@ class FunctionRecognizer(object): self._cb = core.BNFunctionRecognizer() self._cb.context = 0 self._cb.recognizeLowLevelIL = self._cb.recognizeLowLevelIL.__class__(self._recognize_low_level_il) + self._cb.recognizeMediumLevelIL = self._cb.recognizeMediumLevelIL.__class__(self._recognize_medium_level_il) @classmethod def register_global(cls): @@ -62,3 +63,17 @@ class FunctionRecognizer(object): def recognize_low_level_il(self, data, func, il): return False + + def _recognize_medium_level_il(self, ctxt, data, func, il): + try: + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(data)) + view = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(data)) + func = function.Function(view, handle = core.BNNewFunctionReference(func)) + il = mediumlevelil.MediumLevelILFunction(func.arch, handle = core.BNNewMediumLevelILFunctionReference(il)) + return self.recognize_medium_level_il(view, func, il) + except: + log.log_error(traceback.format_exc()) + return False + + def recognize_medium_level_il(self, data, func, il): + return False diff --git a/python/interaction.py b/python/interaction.py index 979549f5..96cac42d 100644 --- a/python/interaction.py +++ b/python/interaction.py @@ -520,7 +520,7 @@ def show_html_report(title, contents, plaintext=""): :param str contents: HTML contents to display :param str plaintext: Plain text version to display (used on the command line) :rtype: None - :Example" + :Example: >>> show_html_report("title", "<h1>Contents</h1>", "Plain text contents") Plain text contents """ diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 3810e742..42c34ee0 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -2171,6 +2171,9 @@ class LowLevelILBasicBlock(basicblock.BasicBlock): """Internal method by super to instantiante child instances""" return LowLevelILBasicBlock(view, handle, self.il_function) + def __hash__(self): + return hash((self.start, self.end, self.il_function)) + def LLIL_TEMP(n): return n | 0x80000000 diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 144c7e0b..85feba0a 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -40,12 +40,12 @@ class SSAVariable(object): def __eq__(self, other): return ( - (self.var.identifier, self.version) == - (other.var.identifier, other.version) + (self.var, self.version) == + (other.var, other.version) ) def __hash__(self): - return hash((self.var.identifier, self.version)) + return hash((self.var, self.version)) class MediumLevelILLabel(object): @@ -921,3 +921,6 @@ class MediumLevelILBasicBlock(basicblock.BasicBlock): def _create_instance(self, view, handle): """Internal method by super to instantiante child instances""" return MediumLevelILBasicBlock(view, handle, self.il_function) + + def __hash__(self): + return hash((self.start, self.end, self.il_function)) diff --git a/python/pluginmanager.py b/python/pluginmanager.py index 6896d699..2f293577 100644 --- a/python/pluginmanager.py +++ b/python/pluginmanager.py @@ -382,7 +382,6 @@ class RepositoryManager(object): >>> mgr = RepositoryManager() >>> mgr.add_repository(url="https://github.com/vector35/community-plugins.git", repopath="myrepo", - repomanifest="plugins", localreference="master", remotereference="origin") True >>> diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py index ed9688b9..c92c249a 100644 --- a/python/scriptingprovider.py +++ b/python/scriptingprovider.py @@ -42,14 +42,14 @@ class _ThreadActionContext(object): def __init__(self, func): self.func = func self.interpreter = None - if "value" in dir(PythonScriptingInstance._interpreter): + if hasattr(PythonScriptingInstance._interpreter, "value"): self.interpreter = PythonScriptingInstance._interpreter.value self.__class__._actions.append(self) self.callback = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(lambda ctxt: self.execute()) def execute(self): old_interpreter = None - if "value" in dir(PythonScriptingInstance._interpreter): + if hasattr(PythonScriptingInstance._interpreter, "value"): old_interpreter = PythonScriptingInstance._interpreter.value PythonScriptingInstance._interpreter.value = self.interpreter try: @@ -380,7 +380,7 @@ class _PythonScriptingInstanceOutput(object): def write(self, data): interpreter = None - if "value" in dir(PythonScriptingInstance._interpreter): + if hasattr(PythonScriptingInstance._interpreter, "value"): interpreter = PythonScriptingInstance._interpreter.value if interpreter is None: @@ -419,7 +419,7 @@ class _PythonScriptingInstanceInput(object): def read(self, size): interpreter = None - if "value" in dir(PythonScriptingInstance._interpreter): + if hasattr(PythonScriptingInstance._interpreter, "value"): interpreter = PythonScriptingInstance._interpreter.value if interpreter is None: @@ -434,7 +434,7 @@ class _PythonScriptingInstanceInput(object): def readline(self): interpreter = None - if "value" in dir(PythonScriptingInstance._interpreter): + if hasattr(PythonScriptingInstance._interpreter, "value"): interpreter = PythonScriptingInstance._interpreter.value if interpreter is None: @@ -457,7 +457,7 @@ class PythonScriptingInstance(ScriptingInstance): super(PythonScriptingInstance.InterpreterThread, self).__init__() self.instance = instance self.locals = {"__name__": "__console__", "__doc__": None, "binaryninja": sys.modules[__name__]} - self.interpreter = code.InteractiveInterpreter(self.locals) + self.interpreter = code.InteractiveConsole(self.locals) self.event = threading.Event() self.daemon = True @@ -484,7 +484,7 @@ class PythonScriptingInstance(ScriptingInstance): self.code = None self.input = "" - self.interpreter.runsource("from binaryninja import *\n") + self.interpreter.push("from binaryninja import *\n") def execute(self, code): self.code = code @@ -540,8 +540,15 @@ class PythonScriptingInstance(ScriptingInstance): self.locals["current_address"] = self.active_addr self.locals["here"] = self.active_addr self.locals["current_selection"] = (self.active_selection_begin, self.active_selection_end) + if self.active_func == None: + self.locals["current_llil"] = None + self.locals["current_mlil"] = None + else: + self.locals["current_llil"] = self.active_func.low_level_il + self.locals["current_mlil"] = self.active_func.medium_level_il - self.interpreter.runsource(code) + for line in code.split("\n"): + self.interpreter.push(line) if self.locals["here"] != self.active_addr: if not self.active_view.file.navigate(self.active_view.file.view, self.locals["here"]): diff --git a/python/update.py b/python/update.py index be6962d7..1eb8ea61 100644 --- a/python/update.py +++ b/python/update.py @@ -154,7 +154,7 @@ class UpdateChannel(object): def updates_available(self): """Whether updates are available (read-only)""" errors = ctypes.c_char_p() - result = core.BNAreUpdatesAvailable(self.name, errors) + result = core.BNAreUpdatesAvailable(self.name, None, None, errors) if errors: error_str = errors.value core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) diff --git a/scripts/linux-setup.sh b/scripts/linux-setup.sh index f1650b7f..bb1e0f28 100755 --- a/scripts/linux-setup.sh +++ b/scripts/linux-setup.sh @@ -14,7 +14,7 @@ setvars() APP="binaryninja" FILECOMMENT="Binary Ninja Analysis Database" APPCOMMENT="Binary Ninja: A Reverse Engineering Platform" - BNPATH=$(dirname $(readlink -f "$0")) + BNPATH="$(dirname $(readlink -f "$0"))/.." EXEC="${BNPATH}/binaryninja" PNG="${BNPATH}/docs/images/logo.png" EXT="bndb" @@ -54,6 +54,10 @@ lastrun() then echo lastrun already exists, remove to create a new one else + if [ ! -d ${HOME}/.binaryninja ] + then + mkdir ${HOME}/.binaryninja + fi echo ${BNPATH} > ${HOME}/.binaryninja/lastrun fi } @@ -61,7 +65,12 @@ lastrun() pythonpath() { echo Configuring python path - ${SUDO}python ${BNPATH}/install_api.py $ROOT + if [[ $(python -V) == "Python 3."* ]] + then + ${SUDO}python2 ${BNPATH}/scripts/install_api.py $ROOT + else + ${SUDO}python ${BNPATH}/scripts/install_api.py $ROOT + fi } createdesktopfile() @@ -81,14 +90,9 @@ Type=Application Categories=Utility; Comment=${APPCOMMENT} EOF - if [ "${ROOT}" == "root" ] - then - echo ${DESKTOP} | $SUDO tee ${DESKTOPFILE} >/dev/null - $SUDO chmod +x ${DESKTOPFILE} - $SUDO update-desktop-database ${SHARE}/applications - else - echo ${DESKTOP} > ${HOME}/Desktop/${APP}.desktop - fi + echo "${DESKTOP}" | $SUDO tee ${DESKTOPFILE} >/dev/null + $SUDO chmod +x ${DESKTOPFILE} + $SUDO update-desktop-database ${SHARE}/applications } createmime() @@ -112,12 +116,8 @@ createmime() #echo Copying icon #$SUDO cp $PNG $IMAGEFILE - if [ "${ROOT}" == "root" ] - then - $SUDO cp ${PNG} ${IMAGEFILE} - $SUDO update-mime-database ${SHARE}/mime - fi - + $SUDO cp ${PNG} ${IMAGEFILE} + $SUDO update-mime-database ${SHARE}/mime } addtodesktop() @@ -127,11 +127,8 @@ addtodesktop() uninstall() { - rm -i -r $DESKTOPFILE $MIMEFILE $IMAGEFILE - if [ "$ROOT" == "root" ] - then - $SUDO update-mime-database ${SHARE}/mime - fi + rm -i -r $DESKTOPFILE $MIMEFILE $IMAGEFILE ${HOME}/Desktop/${APP}.desktop + $SUDO update-mime-database ${SHARE}/mime exit 0 } @@ -67,10 +67,10 @@ vector<UpdateChannel> UpdateChannel::GetList() } -bool UpdateChannel::AreUpdatesAvailable() +bool UpdateChannel::AreUpdatesAvailable(uint64_t* expireTime, uint64_t* serverTime) { char* errors; - bool result = BNAreUpdatesAvailable(name.c_str(), &errors); + bool result = BNAreUpdatesAvailable(name.c_str(), expireTime, serverTime, &errors); if (errors) { |
