summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore11
-rw-r--r--.gitmodules3
-rw-r--r--Makefile69
-rw-r--r--architecture.cpp16
-rw-r--r--basicblock.cpp4
-rw-r--r--binaryninjaapi.cpp18
-rw-r--r--binaryninjaapi.h96
-rw-r--r--binaryninjacore.h98
-rw-r--r--binaryview.cpp28
-rw-r--r--binaryviewtype.cpp2
-rw-r--r--docs/about/open-source.md6
-rw-r--r--docs/getting-started.md26
-rw-r--r--downloadprovider.cpp135
-rw-r--r--examples/llil_parser/CMakeLists.txt4
-rw-r--r--examples/llil_parser/src/llil_parser.cpp5
-rw-r--r--examples/mlil_parser/CMakeLists.txt4
-rw-r--r--examples/mlil_parser/src/mlil_parser.cpp4
-rw-r--r--function.cpp6
-rw-r--r--lowlevelilinstruction.cpp38
-rw-r--r--lowlevelilinstruction.h17
-rw-r--r--mediumlevelilinstruction.cpp87
-rw-r--r--mediumlevelilinstruction.h39
-rw-r--r--python/__init__.py148
-rw-r--r--python/architecture.py195
-rw-r--r--python/basicblock.py46
-rw-r--r--python/binaryview.py258
-rw-r--r--python/callingconvention.py68
-rw-r--r--python/databuffer.py30
-rw-r--r--python/demangle.py16
-rw-r--r--python/downloadprovider.py271
-rw-r--r--python/examples/bin_info.py10
-rw-r--r--python/examples/breakpoint.py2
-rwxr-xr-xpython/examples/export_svg.py6
-rw-r--r--python/examples/jump_table.py8
-rw-r--r--python/examples/nds.py5
-rw-r--r--python/examples/nes.py6
-rw-r--r--python/examples/notification_callbacks.py85
-rw-r--r--python/examples/version_switcher.py66
-rw-r--r--python/fileaccessor.py4
-rw-r--r--python/filemetadata.py26
-rw-r--r--python/flowgraph.py47
-rw-r--r--python/function.py142
-rw-r--r--python/functionrecognizer.py12
-rw-r--r--python/generator.cpp154
-rw-r--r--python/highlight.py4
-rw-r--r--python/interaction.py47
-rw-r--r--python/log.py17
-rw-r--r--python/lowlevelil.py113
-rw-r--r--python/mainthread.py4
-rw-r--r--python/mediumlevelil.py68
-rw-r--r--python/metadata.py24
-rw-r--r--python/platform.py83
-rw-r--r--python/plugin.py160
-rw-r--r--python/pluginmanager.py19
-rw-r--r--python/scriptingprovider.py59
-rw-r--r--python/setting.py22
-rw-r--r--python/startup.py22
-rw-r--r--python/transform.py50
-rw-r--r--python/types.py55
-rw-r--r--python/undoaction.py8
-rw-r--r--python/update.py30
-rwxr-xr-xscripts/install_api.py2
-rw-r--r--suite/api_test.py221
m---------suite/binaries0
-rwxr-xr-xsuite/generator.py328
-rw-r--r--suite/pwnadventurez.nesbin0 -> 262160 bytes
-rw-r--r--suite/testcommon.py802
-rw-r--r--themes/dark-blue.theme108
-rw-r--r--themes/high-contrast.theme107
-rw-r--r--themes/solarized-dark.theme104
-rw-r--r--themes/solarized-light.theme104
71 files changed, 3975 insertions, 907 deletions
diff --git a/.gitignore b/.gitignore
index d18d2ba8..088713e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ Thumbs.db
*.pdb
*.ilk
*.exp
+*.pkl
libbinaryninja*
binaryninjacore.lib
binaryninjacore.dll
@@ -20,6 +21,7 @@ api-docs/build/*
.env
api-docs/source/binaryninja.*
bin/
+suite/unit.py
# CMake
CMakeCache.txt
CMakeFiles
@@ -30,3 +32,12 @@ CTestTestfile.cmake
*.pyc
api-docs/source/python.rst
api-docs/source/index.rst
+.coverage
+# Make
+generator
+plugins/
+python/examples/binaryninja/
+python/plugins/
+python/types/
+suite/binaryninja/
+types/
diff --git a/.gitmodules b/.gitmodules
index 1962d2b4..35327f04 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "examples/x86_extension/src/asmx86"]
path = examples/x86_extension/src/asmx86
url = https://github.com/Vector35/asmx86.git
+[submodule "suite/binaries"]
+ path = suite/binaries
+ url = git@github.com:Vector35/BinaryTestCases.git
diff --git a/Makefile b/Makefile
index 23414c45..8480c05a 100644
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,7 @@
# LIB := -L$(HOME)/binaryninja/ -lbinaryninjacore
#endif
+INSTALLPATH := ~/binaryninja
TARGETDIR := bin
TARGETNAME := libbinaryninjaapi
@@ -15,7 +16,8 @@ SOURCES = $(wildcard *$(SRCEXT))
OBJECTS = $(SOURCES:.cpp=.o) json.o
-CFLAGS := -c -fPIC -O2 -pipe -std=gnu++11 -Wall -W
+CFLAGS := -c -fPIC -O2 -pipe -std=gnu++11 -Wall -W -Wextra -Wshadow
+CPPFLAGS := -O2 -std=c++11 -Wall -W -Wextra -Wshadow
ifeq ($(UNAME_S),Darwin)
CC := $(shell xcrun -f g++)
AR := $(shell xcrun -f ar)
@@ -30,7 +32,7 @@ all: $(TARGET).a
$(TARGET).a: $(OBJECTS)
@mkdir -p $(TARGETDIR)
$(AR) rcs $@ $^
-
+
%.o: %.cpp
@echo " Compiling... $@ $<"
$(CC) $(CFLAGS) $(INC) -c -o $@ $<
@@ -38,8 +40,67 @@ $(TARGET).a: $(OBJECTS)
json.o: ./json/jsoncpp.cpp ./json/json.h ./json/json-forwards.h
$(CC) $(CFLAGS) -I. -c -o $@ $<
+install: generate $(TARGET).a
+ @echo "Installing binaryninja API.";
+ cp -r python/* $(INSTALLPATH)/python/binaryninja
+ cp $(TARGET).a $(INSTALLPATH)
+ @echo "Done.";
+
+generator: python/generator.cpp $(TARGET).a
+ @echo "Building generator...";
+ $(CC) $(CPPFLAGS) -I . $< -L$(TARGETDIR) -lbinaryninjaapi -L $(INSTALLPATH) -lbinaryninjacore -o $@
+ chmod +x $@
+
+generate: generator
+ @echo "Running generator...";
+ LD_LIBRARY_PATH=$(INSTALLPATH) ./generator binaryninjacore.h python/_binaryninjacore.py python/enums.py
+
+python/_binaryninjacore.py: generate
+
+python/enums.py: generate
+
+python_test: environment python/_binaryninjacore.py python/enums.py
+ python2 suite/unit.py
+ python3 suite/unit.py
+
+oracle: environment python/_binaryninjacore.py python/enums.py
+ python3 suite/generator.py
+
+environment: environment_clean python/_binaryninjacore.py python/enums.py
+ @echo "Copying over libs..."
+ cp $(INSTALLPATH)/libbinaryninjacore.so.1 .
+ cp $(INSTALLPATH)/libbinaryninjacore.so.1 python/
+
+ @echo "Building 'binaryninja' Packages..."
+ mkdir -p suite/binaryninja/
+ cp -r python/* suite/binaryninja/
+ cp -r suite/binaryninja/ python/examples/
+
+ @echo "Copying Architectures Over..."
+ cp -r $(INSTALLPATH)/types/ .
+ cp -r $(INSTALLPATH)/plugins/ .
+ cp -r $(INSTALLPATH)/types/ python/
+ cp -r $(INSTALLPATH)/plugins/ python/
+
+environment_clean:
+ @echo "Removing 'binaryninja' Packages..."
+ rm -rf suite/binaryninja/
+ rm -rf python/examples/binaryninja/
+
+ @echo "Removing libs..."
+ rm -f libbinaryninjacore.so.1
+ rm -f python/libbinaryninjacore.so.1
+
+ @echo "Removing Architectures..."
+ rm -rf types/
+ rm -rf plugins/
+ rm -rf python/types/
+ rm -rf python/plugins/
+
clean:
@echo " Cleaning...";
- $(RM) -r *.o $(TARGETDIR)
+ $(RM) -r *.o $(TARGETDIR) generator
+
+squeaky: clean environment_clean
-.PHONY: clean
+.PHONY: clean environment_clean squeaky python/_binaryninjacore.py python/enums.py
diff --git a/architecture.cpp b/architecture.cpp
index a1aaca2d..682cffbc 100644
--- a/architecture.cpp
+++ b/architecture.cpp
@@ -195,8 +195,8 @@ bool Architecture::GetInstructionLowLevelILCallback(void* ctxt, const uint8_t* d
size_t* len, BNLowLevelILFunction* il)
{
Architecture* arch = (Architecture*)ctxt;
- LowLevelILFunction func(il);
- return arch->GetInstructionLowLevelIL(data, addr, *len, func);
+ Ref<LowLevelILFunction> func(new LowLevelILFunction(BNNewLowLevelILFunctionReference(il)));
+ return arch->GetInstructionLowLevelIL(data, addr, *len, *func);
}
@@ -401,8 +401,8 @@ size_t Architecture::GetFlagWriteLowLevelILCallback(void* ctxt, BNLowLevelILOper
uint32_t flag, BNRegisterOrConstant* operands, size_t operandCount, BNLowLevelILFunction* il)
{
Architecture* arch = (Architecture*)ctxt;
- LowLevelILFunction func(il);
- return arch->GetFlagWriteLowLevelIL(op, size, flagWriteType, flag, operands, operandCount, func);
+ Ref<LowLevelILFunction> func(new LowLevelILFunction(BNNewLowLevelILFunctionReference(il)));
+ return arch->GetFlagWriteLowLevelIL(op, size, flagWriteType, flag, operands, operandCount, *func);
}
@@ -410,16 +410,16 @@ size_t Architecture::GetFlagConditionLowLevelILCallback(void* ctxt, BNLowLevelIL
BNLowLevelILFunction* il)
{
Architecture* arch = (Architecture*)ctxt;
- LowLevelILFunction func(il);
- return arch->GetFlagConditionLowLevelIL(cond, semClass, func);
+ Ref<LowLevelILFunction> func(new LowLevelILFunction(BNNewLowLevelILFunctionReference(il)));
+ return arch->GetFlagConditionLowLevelIL(cond, semClass, *func);
}
size_t Architecture::GetSemanticFlagGroupLowLevelILCallback(void* ctxt, uint32_t semGroup, BNLowLevelILFunction* il)
{
Architecture* arch = (Architecture*)ctxt;
- LowLevelILFunction func(il);
- return arch->GetSemanticFlagGroupLowLevelIL(semGroup, func);
+ Ref<LowLevelILFunction> func(new LowLevelILFunction(BNNewLowLevelILFunctionReference(il)));
+ return arch->GetSemanticFlagGroupLowLevelIL(semGroup, *func);
}
diff --git a/basicblock.cpp b/basicblock.cpp
index 9cf9ed56..9fc8d8aa 100644
--- a/basicblock.cpp
+++ b/basicblock.cpp
@@ -260,8 +260,8 @@ set<Ref<BasicBlock>> BasicBlock::GetIteratedDominanceFrontier(const set<Ref<Basi
delete[] blockSet;
set<Ref<BasicBlock>> result;
- for (size_t i = 0; i < count; i++)
- result.insert(new BasicBlock(BNNewBasicBlockReference(resultBlocks[i])));
+ for (size_t k = 0; k < count; k++)
+ result.insert(new BasicBlock(BNNewBasicBlockReference(resultBlocks[k])));
BNFreeBasicBlockList(resultBlocks, count);
return result;
diff --git a/binaryninjaapi.cpp b/binaryninjaapi.cpp
index f5eede03..b774cf2b 100644
--- a/binaryninjaapi.cpp
+++ b/binaryninjaapi.cpp
@@ -344,21 +344,3 @@ 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 dd685d2b..53e0a30d 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -1044,6 +1044,25 @@ namespace BinaryNinja
void Cancel();
};
+ struct ActiveAnalysisInfo
+ {
+ Ref<Function> func;
+ uint64_t analysisTime;
+ size_t updateCount;
+ size_t submitCount;
+
+ ActiveAnalysisInfo(Ref<Function> f, uint64_t t, size_t uc, size_t sc) : func(f), analysisTime(t), updateCount(uc), submitCount(sc)
+ {
+ }
+ };
+
+ struct AnalysisInfo
+ {
+ BNAnalysisState state;
+ uint64_t analysisTime;
+ std::vector<ActiveAnalysisInfo> activeInfo;
+ };
+
struct DataVariable
{
DataVariable() { }
@@ -1293,6 +1312,7 @@ namespace BinaryNinja
Ref<AnalysisCompletionEvent> AddAnalysisCompletionEvent(const std::function<void()>& callback);
+ AnalysisInfo GetAnalysisInfo();
BNAnalysisProgress GetAnalysisProgress();
Ref<BackgroundTask> GetBackgroundAnalysisTask();
@@ -1373,6 +1393,8 @@ namespace BinaryNinja
std::vector<uint8_t> GetRawMetadata(const std::string& key);
uint64_t GetUIntMetadata(const std::string& key);
+ BNAnalysisParameters GetParametersForAnalysis();
+ void SetParametersForAnalysis(BNAnalysisParameters params);
uint64_t GetMaxFunctionSizeForAnalysis();
void SetMaxFunctionSizeForAnalysis(uint64_t size);
};
@@ -2517,6 +2539,7 @@ namespace BinaryNinja
bool IsFunctionTooLarge();
bool IsAnalysisSkipped();
+ BNAnalysisSkipReason GetAnalysisSkipReason();
BNFunctionAnalysisSkipOverride GetAnalysisSkipOverride();
void SetAnalysisSkipOverride(BNFunctionAnalysisSkipOverride skip);
@@ -2837,12 +2860,16 @@ namespace BinaryNinja
ExprId Call(ExprId dest, const ILSourceLocation& loc = ILSourceLocation());
ExprId CallStackAdjust(ExprId dest, size_t adjust, const std::map<uint32_t, int32_t>& regStackAdjust,
const ILSourceLocation& loc = ILSourceLocation());
+ ExprId TailCall(ExprId dest, const ILSourceLocation& loc = ILSourceLocation());
ExprId CallSSA(const std::vector<SSARegister>& output, ExprId dest, const std::vector<ExprId>& params,
const SSARegister& stack, size_t newMemoryVer, size_t prevMemoryVer,
const ILSourceLocation& loc = ILSourceLocation());
ExprId SystemCallSSA(const std::vector<SSARegister>& output, const std::vector<ExprId>& params,
const SSARegister& stack, size_t newMemoryVer, size_t prevMemoryVer,
const ILSourceLocation& loc = ILSourceLocation());
+ ExprId TailCallSSA(const std::vector<SSARegister>& output, ExprId dest, const std::vector<ExprId>& params,
+ const SSARegister& stack, size_t newMemoryVer, size_t prevMemoryVer,
+ const ILSourceLocation& loc = ILSourceLocation());
ExprId Return(size_t dest, const ILSourceLocation& loc = ILSourceLocation());
ExprId NoReturn(const ILSourceLocation& loc = ILSourceLocation());
ExprId FlagCondition(BNLowLevelILFlagCondition cond, uint32_t semClass = 0,
@@ -3156,6 +3183,10 @@ namespace BinaryNinja
const ILSourceLocation& loc = ILSourceLocation());
ExprId SyscallUntyped(const std::vector<Variable>& output, const std::vector<Variable>& params,
ExprId stack, const ILSourceLocation& loc = ILSourceLocation());
+ ExprId TailCall(const std::vector<Variable>& output, ExprId dest, const std::vector<ExprId>& params,
+ const ILSourceLocation& loc = ILSourceLocation());
+ ExprId TailCallUntyped(const std::vector<Variable>& output, ExprId dest, const std::vector<Variable>& params,
+ ExprId stack, const ILSourceLocation& loc = ILSourceLocation());
ExprId CallSSA(const std::vector<SSAVariable>& output, ExprId dest, const std::vector<ExprId>& params,
size_t newMemVersion, size_t prevMemVersion, const ILSourceLocation& loc = ILSourceLocation());
ExprId CallUntypedSSA(const std::vector<SSAVariable>& output, ExprId dest,
@@ -3166,6 +3197,11 @@ namespace BinaryNinja
ExprId SyscallUntypedSSA(const std::vector<SSAVariable>& output,
const std::vector<SSAVariable>& params, size_t newMemVersion, size_t prevMemVersion,
ExprId stack, const ILSourceLocation& loc = ILSourceLocation());
+ ExprId TailCallSSA(const std::vector<SSAVariable>& output, ExprId dest, const std::vector<ExprId>& params,
+ size_t newMemVersion, size_t prevMemVersion, const ILSourceLocation& loc = ILSourceLocation());
+ ExprId TailCallUntypedSSA(const std::vector<SSAVariable>& output, ExprId dest,
+ const std::vector<SSAVariable>& params, size_t newMemVersion, size_t prevMemVersion,
+ ExprId stack, const ILSourceLocation& loc = ILSourceLocation());
ExprId Return(const std::vector<ExprId>& sources, const ILSourceLocation& loc = ILSourceLocation());
ExprId NoReturn(const ILSourceLocation& loc = ILSourceLocation());
ExprId CompareEqual(size_t size, ExprId left, ExprId right,
@@ -3679,6 +3715,63 @@ namespace BinaryNinja
const std::string& autoTypeSource = "");
};
+ // DownloadProvider
+ class DownloadProvider;
+
+ class DownloadInstance: public CoreRefCountObject<BNDownloadInstance, BNNewDownloadInstanceReference, BNFreeDownloadInstance>
+ {
+ protected:
+ DownloadInstance(DownloadProvider* provider);
+ DownloadInstance(BNDownloadInstance* instance);
+
+ static void DestroyInstanceCallback(void* ctxt);
+ static int PerformRequestCallback(void* ctxt, const char* url);
+
+ virtual void DestroyInstance();
+
+ public:
+ virtual int PerformRequest(const std::string& url) = 0;
+
+ int PerformRequest(const std::string& url, BNDownloadInstanceOutputCallbacks* callbacks);
+
+ std::string GetError() const;
+ void SetError(const std::string& error);
+ };
+
+ class CoreDownloadInstance: public DownloadInstance
+ {
+ public:
+ CoreDownloadInstance(BNDownloadInstance* instance);
+
+ virtual int PerformRequest(const std::string& url) override;
+ };
+
+ class DownloadProvider: public StaticCoreRefCountObject<BNDownloadProvider>
+ {
+ std::string m_nameForRegister;
+
+ protected:
+ DownloadProvider(const std::string& name);
+ DownloadProvider(BNDownloadProvider* provider);
+
+ static BNDownloadInstance* CreateInstanceCallback(void* ctxt);
+
+ public:
+ virtual Ref<DownloadInstance> CreateNewInstance() = 0;
+
+ static std::vector<Ref<DownloadProvider>> GetList();
+ static Ref<DownloadProvider> GetByName(const std::string& name);
+ static void Register(DownloadProvider* provider);
+ };
+
+ class CoreDownloadProvider: public DownloadProvider
+ {
+ public:
+ CoreDownloadProvider(BNDownloadProvider* provider);
+ virtual Ref<DownloadInstance> CreateNewInstance() override;
+ };
+
+ // Scripting Provider
class ScriptingOutputListener
{
BNScriptingOutputListener m_callbacks;
@@ -4062,7 +4155,4 @@ namespace BinaryNinja
bool IsArray() const;
bool IsKeyValueStore() const;
};
-
- std::string GetLinuxCADirectory();
- std::string GetLinuxCABundlePath();
}
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 9359ca0e..a26d1fe6 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -120,6 +120,8 @@ extern "C"
struct BNArchitecture;
struct BNFunction;
struct BNBasicBlock;
+ struct BNDownloadProvider;
+ struct BNDownloadInstance;
struct BNFlowGraph;
struct BNFlowGraphNode;
struct BNSymbol;
@@ -333,6 +335,7 @@ extern "C"
LLIL_JUMP_TO,
LLIL_CALL,
LLIL_CALL_STACK_ADJUST,
+ LLIL_TAILCALL,
LLIL_RET,
LLIL_NORET,
LLIL_IF,
@@ -404,6 +407,7 @@ extern "C"
LLIL_FLAG_BIT_SSA,
LLIL_CALL_SSA,
LLIL_SYSCALL_SSA,
+ LLIL_TAILCALL_SSA,
LLIL_CALL_PARAM, // Only valid within the LLIL_CALL_SSA, LLIL_SYSCALL_SSA, LLIL_INTRINSIC, LLIL_INTRINSIC_SSA instructions
LLIL_CALL_STACK_SSA, // Only valid within the LLIL_CALL_SSA or LLIL_SYSCALL_SSA instructions
LLIL_CALL_OUTPUT_SSA, // Only valid within the LLIL_CALL_SSA or LLIL_SYSCALL_SSA instructions
@@ -848,8 +852,8 @@ extern "C"
MLIL_JUMP_TO,
MLIL_CALL, // Not valid in SSA form (see MLIL_CALL_SSA)
MLIL_CALL_UNTYPED, // Not valid in SSA form (see MLIL_CALL_UNTYPED_SSA)
- MLIL_CALL_OUTPUT, // Only valid within MLIL_CALL or MLIL_SYSCALL family instructions
- MLIL_CALL_PARAM, // Only valid within MLIL_CALL or MLIL_SYSCALL family instructions
+ MLIL_CALL_OUTPUT, // Only valid within MLIL_CALL, MLIL_SYSCALL, MLIL_TAILCALL family instructions
+ MLIL_CALL_PARAM, // Only valid within MLIL_CALL, MLIL_SYSCALL, MLIL_TAILCALL family instructions
MLIL_RET, // Not valid in SSA form (see MLIL_RET_SSA)
MLIL_NORET,
MLIL_IF,
@@ -869,6 +873,8 @@ extern "C"
MLIL_ADD_OVERFLOW,
MLIL_SYSCALL, // Not valid in SSA form (see MLIL_SYSCALL_SSA)
MLIL_SYSCALL_UNTYPED, // Not valid in SSA form (see MLIL_SYSCALL_UNTYPED_SSA)
+ MLIL_TAILCALL, // Not valid in SSA form (see MLIL_TAILCALL_SSA)
+ MLIL_TAILCALL_UNTYPED, // Not valid in SSA form (see MLIL_TAILCALL_UNTYPED_SSA)
MLIL_INTRINSIC, // Not valid in SSA form (see MLIL_INTRINSIC_SSA)
MLIL_FREE_VAR_SLOT, // Not valid in SSA from (see MLIL_FREE_VAR_SLOT_SSA)
MLIL_BP,
@@ -916,8 +922,10 @@ extern "C"
MLIL_CALL_UNTYPED_SSA,
MLIL_SYSCALL_SSA,
MLIL_SYSCALL_UNTYPED_SSA,
- MLIL_CALL_PARAM_SSA, // Only valid within the MLIL_CALL_SSA, MLIL_SYSCALL_SSA family instructions
- MLIL_CALL_OUTPUT_SSA, // Only valid within the MLIL_CALL_SSA or MLIL_SYSCALL_SSA family instructions
+ MLIL_TAILCALL_SSA,
+ MLIL_TAILCALL_UNTYPED_SSA,
+ MLIL_CALL_PARAM_SSA, // Only valid within the MLIL_CALL_SSA, MLIL_SYSCALL_SSA, MLIL_TAILCALL_SSA family instructions
+ MLIL_CALL_OUTPUT_SSA, // Only valid within the MLIL_CALL_SSA or MLIL_SYSCALL_SSA, MLIL_TAILCALL_SSA family instructions
MLIL_LOAD_SSA,
MLIL_LOAD_STRUCT_SSA,
MLIL_STORE_SSA,
@@ -1499,7 +1507,24 @@ extern "C"
{
IdleState,
DisassembleState,
- AnalyzeState
+ AnalyzeState,
+ ExtendedAnalyzeState
+ };
+
+ struct BNActiveAnalysisInfo
+ {
+ BNFunction* func;
+ uint64_t analysisTime;
+ size_t updateCount;
+ size_t submitCount;
+ };
+
+ struct BNAnalysisInfo
+ {
+ BNAnalysisState state;
+ uint64_t analysisTime;
+ BNActiveAnalysisInfo* activeInfo;
+ size_t count;
};
struct BNAnalysisProgress
@@ -1508,6 +1533,36 @@ extern "C"
size_t count, total;
};
+ struct BNAnalysisParameters
+ {
+ uint64_t maxAnalysisTime;
+ uint64_t maxFunctionSize;
+ uint64_t maxFunctionAnalysisTime;
+ size_t maxFunctionUpdateCount;
+ size_t maxFunctionSubmitCount;
+ };
+
+ struct BNDownloadInstanceOutputCallbacks
+ {
+ uint64_t (*writeCallback)(uint8_t* data, uint64_t len, void* ctxt);
+ void* writeContext;
+ bool (*progressCallback)(void* ctxt, uint64_t progress, uint64_t total);
+ void* progressContext;
+ };
+
+ struct BNDownloadInstanceCallbacks
+ {
+ void* context;
+ void (*destroyInstance)(void* ctxt);
+ int (*performRequest)(void* ctxt, const char* url);
+ };
+
+ struct BNDownloadProviderCallbacks
+ {
+ void* context;
+ BNDownloadInstance* (*createInstance)(void* ctxt);
+ };
+
enum BNFindFlag
{
NoFindFlags = 0,
@@ -1781,6 +1836,14 @@ extern "C"
BNFlowGraph* (*update)(void* ctxt);
};
+ enum BNAnalysisSkipReason
+ {
+ NoSkipReason,
+ AlwaysSkipReason,
+ ExceedFunctionSizeSkipReason,
+ ExceedFunctionAnalysisTimeSkipReason
+ };
+
BINARYNINJACOREAPI char* BNAllocString(const char* contents);
BINARYNINJACOREAPI void BNFreeString(char* str);
BINARYNINJACOREAPI char** BNAllocStringList(const char** contents, size_t size);
@@ -2470,9 +2533,12 @@ extern "C"
BINARYNINJACOREAPI bool BNIsFunctionTooLarge(BNFunction* func);
BINARYNINJACOREAPI bool BNIsFunctionAnalysisSkipped(BNFunction* func);
+ BINARYNINJACOREAPI BNAnalysisSkipReason BNGetAnalysisSkipReason(BNFunction* func);
BINARYNINJACOREAPI BNFunctionAnalysisSkipOverride BNGetFunctionAnalysisSkipOverride(BNFunction* func);
BINARYNINJACOREAPI void BNSetFunctionAnalysisSkipOverride(BNFunction* func, BNFunctionAnalysisSkipOverride skip);
+ BINARYNINJACOREAPI BNAnalysisParameters BNGetParametersForAnalysis(BNBinaryView* view);
+ BINARYNINJACOREAPI void BNSetParametersForAnalysis(BNBinaryView* view, BNAnalysisParameters params);
BINARYNINJACOREAPI uint64_t BNGetMaxFunctionSizeForAnalysis(BNBinaryView* view);
BINARYNINJACOREAPI void BNSetMaxFunctionSizeForAnalysis(BNBinaryView* view, uint64_t size);
@@ -2482,6 +2548,8 @@ extern "C"
BINARYNINJACOREAPI void BNFreeAnalysisCompletionEvent(BNAnalysisCompletionEvent* event);
BINARYNINJACOREAPI void BNCancelAnalysisCompletionEvent(BNAnalysisCompletionEvent* event);
+ BINARYNINJACOREAPI BNAnalysisInfo* BNGetAnalysisInfo(BNBinaryView* view);
+ BINARYNINJACOREAPI void BNFreeAnalysisInfo(BNAnalysisInfo* info);
BINARYNINJACOREAPI BNAnalysisProgress BNGetAnalysisProgress(BNBinaryView* view);
BINARYNINJACOREAPI BNBackgroundTask* BNGetBackgroundAnalysisTask(BNBinaryView* view);
@@ -3222,6 +3290,24 @@ extern "C"
char*** outVarName,
size_t* outVarNameElements);
+ // Download providers
+ BINARYNINJACOREAPI BNDownloadProvider* BNRegisterDownloadProvider(const char* name, BNDownloadProviderCallbacks* callbacks);
+ BINARYNINJACOREAPI BNDownloadProvider** BNGetDownloadProviderList(size_t* count);
+ BINARYNINJACOREAPI void BNFreeDownloadProviderList(BNDownloadProvider** providers);
+ BINARYNINJACOREAPI BNDownloadProvider* BNGetDownloadProviderByName(const char* name);
+
+ BINARYNINJACOREAPI char* BNGetDownloadProviderName(BNDownloadProvider* provider);
+ BINARYNINJACOREAPI BNDownloadInstance* BNCreateDownloadProviderInstance(BNDownloadProvider* provider);
+
+ BINARYNINJACOREAPI BNDownloadInstance* BNInitDownloadInstance(BNDownloadProvider* provider, BNDownloadInstanceCallbacks* callbacks);
+ BINARYNINJACOREAPI BNDownloadInstance* BNNewDownloadInstanceReference(BNDownloadInstance* instance);
+ BINARYNINJACOREAPI void BNFreeDownloadInstance(BNDownloadInstance* instance);
+ BINARYNINJACOREAPI int BNPerformDownloadRequest(BNDownloadInstance* instance, const char* url, BNDownloadInstanceOutputCallbacks* callbacks);
+ BINARYNINJACOREAPI uint64_t BNWriteDataForDownloadInstance(BNDownloadInstance* instance, uint8_t* data, uint64_t len);
+ BINARYNINJACOREAPI bool BNNotifyProgressForDownloadInstance(BNDownloadInstance* instance, uint64_t progress, uint64_t total);
+ BINARYNINJACOREAPI char* BNGetErrorForDownloadInstance(BNDownloadInstance* instance);
+ BINARYNINJACOREAPI void BNSetErrorForDownloadInstance(BNDownloadInstance* instance, const char* error);
+
// Scripting providers
BINARYNINJACOREAPI BNScriptingProvider* BNRegisterScriptingProvider(const char* name,
BNScriptingProviderCallbacks* callbacks);
@@ -3508,8 +3594,6 @@ 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 18dd1bef..da516184 100644
--- a/binaryview.cpp
+++ b/binaryview.cpp
@@ -1014,6 +1014,21 @@ vector<Ref<Function>> BinaryView::GetAnalysisFunctionList()
}
+AnalysisInfo BinaryView::GetAnalysisInfo()
+{
+ AnalysisInfo result;
+ BNAnalysisInfo* info = BNGetAnalysisInfo(m_object);
+ result.state = info->state;
+ result.analysisTime = info->analysisTime;
+ result.activeInfo.reserve(info->count);
+ for (size_t i = 0; i < info->count; i++)
+ result.activeInfo.emplace_back(new Function(BNNewFunctionReference(info->activeInfo[i].func)),
+ info->activeInfo[i].analysisTime, info->activeInfo[i].submitCount, info->activeInfo[i].updateCount);
+ BNFreeAnalysisInfo(info);
+ return result;
+}
+
+
bool BinaryView::HasFunctions() const
{
return BNHasFunctions(m_object);
@@ -1784,6 +1799,7 @@ bool BinaryView::GetSegmentAt(uint64_t addr, Segment& result)
result.dataOffset = segment.dataOffset;
result.dataLength = segment.dataLength;
result.flags = segment.flags;
+ result.autoDefined = segment.autoDefined;
return true;
}
@@ -1976,6 +1992,18 @@ uint64_t BinaryView::GetUIntMetadata(const string& key)
}
+BNAnalysisParameters BinaryView::GetParametersForAnalysis()
+{
+ return BNGetParametersForAnalysis(m_object);
+}
+
+
+void BinaryView::SetParametersForAnalysis(BNAnalysisParameters params)
+{
+ BNSetParametersForAnalysis(m_object, params);
+}
+
+
uint64_t BinaryView::GetMaxFunctionSizeForAnalysis()
{
return BNGetMaxFunctionSizeForAnalysis(m_object);
diff --git a/binaryviewtype.cpp b/binaryviewtype.cpp
index e8ef4f53..762b2de7 100644
--- a/binaryviewtype.cpp
+++ b/binaryviewtype.cpp
@@ -29,6 +29,8 @@ BNBinaryView* BinaryViewType::CreateCallback(void* ctxt, BNBinaryView* data)
BinaryViewType* type = (BinaryViewType*)ctxt;
Ref<BinaryView> view = new BinaryView(BNNewViewReference(data));
Ref<BinaryView> result = type->Create(view);
+ if (!result)
+ return nullptr;
return BNNewViewReference(result->GetObject());
}
diff --git a/docs/about/open-source.md b/docs/about/open-source.md
index b0a35f37..be9725d0 100644
--- a/docs/about/open-source.md
+++ b/docs/about/open-source.md
@@ -22,13 +22,11 @@ The previous tools are used in the generation of our documentation, but are not
* Core
- [discount] ([discount license] - BSD)
- - [libcurl] ([libcurl license] - MIT/X derivative)
- [libgit2] ([libgit2 license] - GPLv2 with linking exception)
- [libmspack] ([libmspack license] - LGPL, v2)
- [llvm] ([llvm license] - BSD-style)
- [lzf] ([lzf license] - BSD)
- [jemalloc] ([jemalloc license] - BSD)
- - [openssl] ([openssl license] - openssl license)
- [sqlite] ([sqlite license] - public domain)
- [zlib] ([zlib license] - zlib license)
@@ -69,8 +67,6 @@ Please note that we offer no support for running Binary Ninja with modified Qt l
[discount]: http://www.pell.portland.or.us/~orc/Code/discount/
[doxygen license]: https://github.com/doxygen/doxygen/blob/master/LICENSE
[doxygen]: http://www.stack.nl/~dimitri/doxygen/
-[libcurl]: https://curl.haxx.se/
-[libcurl license]: https://curl.haxx.se/docs/copyright.html
[libgit2]: https://libgit2.github.com/
[libgit2 license]: https://github.com/libgit2/libgit2/blob/master/COPYING
[libmspack]: https://www.cabextract.org.uk/libmspack/
@@ -87,8 +83,6 @@ Please note that we offer no support for running Binary Ninja with modified Qt l
[mkdocs]: http://www.mkdocs.org/
[opensans license]: http://www.apache.org/licenses/LICENSE-2.0.html
[opensans]: https://www.google.com/fonts/specimen/Open+Sans
-[openssl license]: https://www.openssl.org/source/license.html
-[openssl]: https://www.openssl.org/
[qt license]: https://www.qt.io/qt-licensing-terms/
[qt]: https://www.qt.io/download/
[sourcecodepro license]: https://github.com/adobe-fonts/source-code-pro/blob/master/LICENSE.txt
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 073ccd33..7e7e4acb 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -257,18 +257,20 @@ On windows, this is achieved through a separate launcher that loads first and re
Settings are stored in the _user_ directory in the file `settings.json`. Each top level object in this file is represents a different plugin. As of build 860 the following settings are available:
-|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) |
-| ui | recent-file-limit | integer | 10 | Specify limit for number of recent files |
-| pdb | local-store-absolute | string | "" | Absolute path specifying where the pdb symbol store exists on this machine, overrides relative path |
-| pdb | local-store-relative | string | "symbols" | Path *relative* to the binaryninja _user_ directory, sepcifying the pdb symbol store |
-| pdb | auto-download-pdb | boolean | True | Automatically download pdb files from specified symbol servers |
-| pdb | symbol-server-list | list(string) | ["http://msdl.microsoft.com/download/symbols"] | List of servers to query for pdb symbols. |
+|Plugin | Setting | Type | Default | Description |
+|----------:|-------------------------:|-------------:|-----------------------------------------------:|:----------------------------------------------------------------------------------------------|
+| analysis | max-function-size | integer | 65536 | Any functions over this size will not be automatically analyzed and require manual override |
+| 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) |
+| ui | recent-file-limit | integer | 10 | Specify limit for number of recent files |
+| pdb | local-store-absolute | string | "" | Absolute path specifying where the pdb symbol store exists on this machine, overrides relative path |
+| pdb | local-store-relative | string | "symbols" | Path *relative* to the binaryninja _user_ directory, sepcifying the pdb symbol store |
+| pdb | auto-download-pdb | boolean | True | Automatically download pdb files from specified symbol servers |
+| pdb | symbol-server-list | list(string) | ["http://msdl.microsoft.com/download/symbols"] | List of servers to query for pdb symbols. |
+| python | interpreter | string | "python27.{dylib,dll,so.1}" | Python interpreter to load if one is not already present when plugins are loaded |
Below is an example `settings.json` setting various options:
```
diff --git a/downloadprovider.cpp b/downloadprovider.cpp
new file mode 100644
index 00000000..0e3483df
--- /dev/null
+++ b/downloadprovider.cpp
@@ -0,0 +1,135 @@
+#include "binaryninjaapi.h"
+
+using namespace BinaryNinja;
+using namespace std;
+
+
+DownloadInstance::DownloadInstance(DownloadProvider* provider)
+{
+ BNDownloadInstanceCallbacks cb;
+ cb.context = this;
+ cb.destroyInstance = DestroyInstanceCallback;
+ cb.performRequest = PerformRequestCallback;
+ m_object = BNInitDownloadInstance(provider->GetObject(), &cb);
+}
+
+
+DownloadInstance::DownloadInstance(BNDownloadInstance* instance)
+{
+ m_object = instance;
+}
+
+
+void DownloadInstance::DestroyInstanceCallback(void* ctxt)
+{
+ DownloadInstance* instance = (DownloadInstance*)ctxt;
+ instance->DestroyInstance();
+}
+
+
+int DownloadInstance::PerformRequestCallback(void* ctxt, const char* url)
+{
+ DownloadInstance* instance = (DownloadInstance*)ctxt;
+ return instance->PerformRequest(url);
+}
+
+
+string DownloadInstance::GetError() const
+{
+ char* str = BNGetErrorForDownloadInstance(m_object);
+ string result = str;
+ BNFreeString(str);
+ return result;
+}
+
+
+void DownloadInstance::SetError(const string& error)
+{
+ BNSetErrorForDownloadInstance(m_object, error.c_str());
+}
+
+
+int DownloadInstance::PerformRequest(const string& url, BNDownloadInstanceOutputCallbacks* callbacks)
+{
+ return BNPerformDownloadRequest(m_object, url.c_str(), callbacks);
+}
+
+
+void DownloadInstance::DestroyInstance()
+{
+}
+
+
+CoreDownloadInstance::CoreDownloadInstance(BNDownloadInstance* instance): DownloadInstance(instance)
+{
+}
+
+
+int CoreDownloadInstance::PerformRequest(const std::string& url)
+{
+ (void)url;
+ return -1;
+}
+
+
+DownloadProvider::DownloadProvider(const string& name): m_nameForRegister(name)
+{
+}
+
+
+DownloadProvider::DownloadProvider(BNDownloadProvider* provider)
+{
+ m_object = provider;
+}
+
+
+BNDownloadInstance* DownloadProvider::CreateInstanceCallback(void* ctxt)
+{
+ DownloadProvider* provider = (DownloadProvider*)ctxt;
+ Ref<DownloadInstance> instance = provider->CreateNewInstance();
+ return instance ? BNNewDownloadInstanceReference(instance->GetObject()) : nullptr;
+}
+
+
+vector<Ref<DownloadProvider>> DownloadProvider::GetList()
+{
+ size_t count;
+ BNDownloadProvider** list = BNGetDownloadProviderList(&count);
+ vector<Ref<DownloadProvider>> result;
+ for (size_t i = 0; i < count; i++)
+ result.push_back(new CoreDownloadProvider(list[i]));
+ BNFreeDownloadProviderList(list);
+ return result;
+}
+
+
+Ref<DownloadProvider> DownloadProvider::GetByName(const string& name)
+{
+ BNDownloadProvider* result = BNGetDownloadProviderByName(name.c_str());
+ if (!result)
+ return nullptr;
+ return new CoreDownloadProvider(result);
+}
+
+
+void DownloadProvider::Register(DownloadProvider* provider)
+{
+ BNDownloadProviderCallbacks cb;
+ cb.context = provider;
+ cb.createInstance = CreateInstanceCallback;
+ provider->m_object = BNRegisterDownloadProvider(provider->m_nameForRegister.c_str(), &cb);
+}
+
+
+CoreDownloadProvider::CoreDownloadProvider(BNDownloadProvider* provider): DownloadProvider(provider)
+{
+}
+
+
+Ref<DownloadInstance> CoreDownloadProvider::CreateNewInstance()
+{
+ BNDownloadInstance* result = BNCreateDownloadProviderInstance(m_object);
+ if (!result)
+ return nullptr;
+ return new CoreDownloadInstance(result);
+}
diff --git a/examples/llil_parser/CMakeLists.txt b/examples/llil_parser/CMakeLists.txt
index 6d782109..868a755e 100644
--- a/examples/llil_parser/CMakeLists.txt
+++ b/examples/llil_parser/CMakeLists.txt
@@ -7,7 +7,7 @@ project(LLIL_Parser)
#-----------------------------------------------------------------------------
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../..)
#-----------------------------------------------------------------------------
-file( GLOB_RECURSE SRCS *.cpp *.h)
+set(SRCS src/llil_parser.cpp)
#-----------------------------------------------------------------------------
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
#-----------------------------------------------------------------------------
@@ -31,7 +31,7 @@ else()
CACHE PATH "Binary Ninja user plugins directory")
endif()
#-----------------------------------------------------------------------------
-add_executable (${PROJECT_NAME} ${SRCS} )
+add_executable (${PROJECT_NAME} ${SRCS})
#-----------------------------------------------------------------------------
find_library(BINJA_API_LIBRARY binaryninjaapi
HINTS ${CMAKE_CURRENT_SOURCE_DIR}/../../bin ${CMAKE_CURRENT_SOURCE_DIR}/../../bin/Release ${CMAKE_CURRENT_SOURCE_DIR}/../../bin/Debug)
diff --git a/examples/llil_parser/src/llil_parser.cpp b/examples/llil_parser/src/llil_parser.cpp
index 72ac71bd..9b73d298 100644
--- a/examples/llil_parser/src/llil_parser.cpp
+++ b/examples/llil_parser/src/llil_parser.cpp
@@ -91,6 +91,8 @@ static void PrintOperation(BNLowLevelILOperation operation)
ENUM_PRINTER(LLIL_JUMP)
ENUM_PRINTER(LLIL_JUMP_TO)
ENUM_PRINTER(LLIL_CALL)
+ ENUM_PRINTER(LLIL_CALL_STACK_ADJUST)
+ ENUM_PRINTER(LLIL_TAILCALL)
ENUM_PRINTER(LLIL_RET)
ENUM_PRINTER(LLIL_NORET)
ENUM_PRINTER(LLIL_IF)
@@ -126,7 +128,8 @@ static void PrintOperation(BNLowLevelILOperation operation)
ENUM_PRINTER(LLIL_FLAG_BIT_SSA)
ENUM_PRINTER(LLIL_CALL_SSA)
ENUM_PRINTER(LLIL_SYSCALL_SSA)
- ENUM_PRINTER(LLIL_CALL_PARAM_SSA)
+ ENUM_PRINTER(LLIL_TAILCALL_SSA)
+ ENUM_PRINTER(LLIL_CALL_PARAM)
ENUM_PRINTER(LLIL_CALL_STACK_SSA)
ENUM_PRINTER(LLIL_CALL_OUTPUT_SSA)
ENUM_PRINTER(LLIL_LOAD_SSA)
diff --git a/examples/mlil_parser/CMakeLists.txt b/examples/mlil_parser/CMakeLists.txt
index 1bf6e3a7..4ec35591 100644
--- a/examples/mlil_parser/CMakeLists.txt
+++ b/examples/mlil_parser/CMakeLists.txt
@@ -7,7 +7,7 @@ project(MLIL_Parser)
#-----------------------------------------------------------------------------
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../..)
#-----------------------------------------------------------------------------
-file( GLOB_RECURSE SRCS *.cpp *.h)
+set(SRCS src/mlil_parser.cpp)
#-----------------------------------------------------------------------------
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
#-----------------------------------------------------------------------------
@@ -31,7 +31,7 @@ else()
CACHE PATH "Binary Ninja user plugins directory")
endif()
#-----------------------------------------------------------------------------
-add_executable (${PROJECT_NAME} ${SRCS} )
+add_executable (${PROJECT_NAME} ${SRCS})
#-----------------------------------------------------------------------------
find_library(BINJA_API_LIBRARY binaryninjaapi
HINTS ${CMAKE_CURRENT_SOURCE_DIR}/../../bin ${CMAKE_CURRENT_SOURCE_DIR}/../../bin/Release ${CMAKE_CURRENT_SOURCE_DIR}/../../bin/Debug)
diff --git a/examples/mlil_parser/src/mlil_parser.cpp b/examples/mlil_parser/src/mlil_parser.cpp
index 8fb762eb..0e621ead 100644
--- a/examples/mlil_parser/src/mlil_parser.cpp
+++ b/examples/mlil_parser/src/mlil_parser.cpp
@@ -114,6 +114,8 @@ static void PrintOperation(BNMediumLevelILOperation operation)
ENUM_PRINTER(MLIL_ADD_OVERFLOW)
ENUM_PRINTER(MLIL_SYSCALL)
ENUM_PRINTER(MLIL_SYSCALL_UNTYPED)
+ ENUM_PRINTER(MLIL_TAILCALL)
+ ENUM_PRINTER(MLIL_TAILCALL_UNTYPED)
ENUM_PRINTER(MLIL_BP)
ENUM_PRINTER(MLIL_TRAP)
ENUM_PRINTER(MLIL_UNDEF)
@@ -132,6 +134,8 @@ static void PrintOperation(BNMediumLevelILOperation operation)
ENUM_PRINTER(MLIL_CALL_UNTYPED_SSA)
ENUM_PRINTER(MLIL_SYSCALL_SSA)
ENUM_PRINTER(MLIL_SYSCALL_UNTYPED_SSA)
+ ENUM_PRINTER(MLIL_TAILCALL_SSA)
+ ENUM_PRINTER(MLIL_TAILCALL_UNTYPED_SSA)
ENUM_PRINTER(MLIL_CALL_PARAM_SSA)
ENUM_PRINTER(MLIL_CALL_OUTPUT_SSA)
ENUM_PRINTER(MLIL_LOAD_SSA)
diff --git a/function.cpp b/function.cpp
index 202f6d77..ae6d3a6b 100644
--- a/function.cpp
+++ b/function.cpp
@@ -1379,6 +1379,12 @@ bool Function::IsAnalysisSkipped()
}
+BNAnalysisSkipReason Function::GetAnalysisSkipReason()
+{
+ return BNGetAnalysisSkipReason(m_object);
+}
+
+
BNFunctionAnalysisSkipOverride Function::GetAnalysisSkipOverride()
{
return BNGetFunctionAnalysisSkipOverride(m_object);
diff --git a/lowlevelilinstruction.cpp b/lowlevelilinstruction.cpp
index 8fb87a9e..5f5dc397 100644
--- a/lowlevelilinstruction.cpp
+++ b/lowlevelilinstruction.cpp
@@ -148,6 +148,7 @@ unordered_map<BNLowLevelILOperation, vector<LowLevelILOperandUsage>>
{LLIL_CALL, {DestExprLowLevelOperandUsage}},
{LLIL_CALL_STACK_ADJUST, {DestExprLowLevelOperandUsage, StackAdjustmentLowLevelOperandUsage,
RegisterStackAdjustmentsLowLevelOperandUsage}},
+ {LLIL_TAILCALL, {DestExprLowLevelOperandUsage}},
{LLIL_RET, {DestExprLowLevelOperandUsage}},
{LLIL_IF, {ConditionExprLowLevelOperandUsage, TrueTargetLowLevelOperandUsage,
FalseTargetLowLevelOperandUsage}},
@@ -161,6 +162,9 @@ unordered_map<BNLowLevelILOperation, vector<LowLevelILOperandUsage>>
{LLIL_SYSCALL_SSA, {OutputSSARegistersLowLevelOperandUsage, OutputMemoryVersionLowLevelOperandUsage,
StackSSARegisterLowLevelOperandUsage, StackMemoryVersionLowLevelOperandUsage,
ParameterExprsLowLevelOperandUsage}},
+ {LLIL_TAILCALL_SSA, {OutputSSARegistersLowLevelOperandUsage, OutputMemoryVersionLowLevelOperandUsage,
+ DestExprLowLevelOperandUsage, StackSSARegisterLowLevelOperandUsage,
+ StackMemoryVersionLowLevelOperandUsage, ParameterExprsLowLevelOperandUsage}},
{LLIL_REG_PHI, {DestSSARegisterLowLevelOperandUsage, SourceSSARegistersLowLevelOperandUsage}},
{LLIL_REG_STACK_PHI, {DestSSARegisterStackLowLevelOperandUsage, SourceSSARegisterStacksLowLevelOperandUsage}},
{LLIL_FLAG_PHI, {DestSSAFlagLowLevelOperandUsage, SourceSSAFlagsLowLevelOperandUsage}},
@@ -1808,6 +1812,9 @@ void LowLevelILInstruction::VisitExprs(const std::function<bool(const LowLevelIL
case LLIL_CALL_STACK_ADJUST:
GetDestExpr<LLIL_CALL_STACK_ADJUST>().VisitExprs(func);
break;
+ case LLIL_TAILCALL:
+ GetDestExpr<LLIL_TAILCALL>().VisitExprs(func);
+ break;
case LLIL_CALL_SSA:
GetDestExpr<LLIL_CALL_SSA>().VisitExprs(func);
for (auto& i : GetParameterExprs<LLIL_CALL_SSA>())
@@ -1817,6 +1824,11 @@ void LowLevelILInstruction::VisitExprs(const std::function<bool(const LowLevelIL
for (auto& i : GetParameterExprs<LLIL_SYSCALL_SSA>())
i.VisitExprs(func);
break;
+ case LLIL_TAILCALL_SSA:
+ GetDestExpr<LLIL_TAILCALL_SSA>().VisitExprs(func);
+ for (auto& i : GetParameterExprs<LLIL_TAILCALL_SSA>())
+ i.VisitExprs(func);
+ break;
case LLIL_RET:
GetDestExpr<LLIL_RET>().VisitExprs(func);
break;
@@ -2037,6 +2049,8 @@ ExprId LowLevelILInstruction::CopyTo(LowLevelILFunction* dest,
case LLIL_CALL_STACK_ADJUST:
return dest->CallStackAdjust(subExprHandler(GetDestExpr<LLIL_CALL_STACK_ADJUST>()),
GetStackAdjustment<LLIL_CALL_STACK_ADJUST>(), GetRegisterStackAdjustments<LLIL_CALL_STACK_ADJUST>(), *this);
+ case LLIL_TAILCALL:
+ return dest->TailCall(subExprHandler(GetDestExpr<LLIL_TAILCALL>()), *this);
case LLIL_RET:
return dest->Return(subExprHandler(GetDestExpr<LLIL_RET>()), *this);
case LLIL_JUMP_TO:
@@ -2080,6 +2094,12 @@ ExprId LowLevelILInstruction::CopyTo(LowLevelILFunction* dest,
return dest->SystemCallSSA(GetOutputSSARegisters<LLIL_SYSCALL_SSA>(),
params, GetStackSSARegister<LLIL_SYSCALL_SSA>(), GetDestMemoryVersion<LLIL_SYSCALL_SSA>(),
GetSourceMemoryVersion<LLIL_SYSCALL_SSA>(), *this);
+ case LLIL_TAILCALL_SSA:
+ for (auto& i : GetParameterExprs<LLIL_TAILCALL_SSA>())
+ params.push_back(subExprHandler(i));
+ return dest->TailCallSSA(GetOutputSSARegisters<LLIL_TAILCALL_SSA>(), subExprHandler(GetDestExpr<LLIL_TAILCALL_SSA>()),
+ params, GetStackSSARegister<LLIL_TAILCALL_SSA>(), GetDestMemoryVersion<LLIL_TAILCALL_SSA>(),
+ GetSourceMemoryVersion<LLIL_TAILCALL_SSA>(), *this);
case LLIL_REG_PHI:
return dest->RegisterPhi(GetDestSSARegister<LLIL_REG_PHI>(), GetSourceSSARegisters<LLIL_REG_PHI>(), *this);
case LLIL_REG_STACK_PHI:
@@ -3157,6 +3177,12 @@ ExprId LowLevelILFunction::CallStackAdjust(ExprId dest, size_t adjust,
}
+ExprId LowLevelILFunction::TailCall(ExprId dest, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(LLIL_TAILCALL, loc, 0, 0, dest);
+}
+
+
ExprId LowLevelILFunction::CallSSA(const vector<SSARegister>& output, ExprId dest, const vector<ExprId>& params,
const SSARegister& stack, size_t newMemoryVer, size_t prevMemoryVer, const ILSourceLocation& loc)
{
@@ -3181,6 +3207,18 @@ ExprId LowLevelILFunction::SystemCallSSA(const vector<SSARegister>& output, cons
}
+ExprId LowLevelILFunction::TailCallSSA(const vector<SSARegister>& output, ExprId dest, const vector<ExprId>& params,
+ const SSARegister& stack, size_t newMemoryVer, size_t prevMemoryVer, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(LLIL_TAILCALL_SSA, loc, 0, 0,
+ AddExprWithLocation(LLIL_CALL_OUTPUT_SSA, loc, 0, 0, newMemoryVer,
+ output.size() * 2, AddSSARegisterList(output)), dest,
+ AddExprWithLocation(LLIL_CALL_STACK_SSA, loc, 0, 0, stack.reg, stack.version, prevMemoryVer),
+ AddExprWithLocation(LLIL_CALL_PARAM, loc, 0, 0,
+ params.size(), AddOperandList(params)));
+}
+
+
ExprId LowLevelILFunction::Return(size_t dest, const ILSourceLocation& loc)
{
return AddExprWithLocation(LLIL_RET, loc, 0, 0, dest);
diff --git a/lowlevelilinstruction.h b/lowlevelilinstruction.h
index 675baa3c..e845bcd0 100644
--- a/lowlevelilinstruction.h
+++ b/lowlevelilinstruction.h
@@ -1107,6 +1107,10 @@ namespace BinaryNinja
size_t GetStackAdjustment() const { return (size_t)GetRawOperandAsInteger(1); }
std::map<uint32_t, int32_t> GetRegisterStackAdjustments() const { return GetRawOperandAsRegisterStackAdjustments(2); }
};
+ template <> struct LowLevelILInstructionAccessor<LLIL_TAILCALL>: public LowLevelILInstructionBase
+ {
+ LowLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); }
+ };
template <> struct LowLevelILInstructionAccessor<LLIL_RET>: public LowLevelILInstructionBase
{
LowLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); }
@@ -1163,6 +1167,19 @@ namespace BinaryNinja
void SetStackSSAVersion(size_t version) { GetRawOperandAsExpr(1).UpdateRawOperand(1, version); }
void SetOutputSSARegisters(const std::vector<SSARegister>& regs) { GetRawOperandAsExpr(0).UpdateRawOperandAsSSARegisterList(1, regs); }
};
+ template <> struct LowLevelILInstructionAccessor<LLIL_TAILCALL_SSA>: public LowLevelILInstructionBase
+ {
+ LowLevelILSSARegisterList GetOutputSSARegisters() const { return GetRawOperandAsExpr(0).GetRawOperandAsSSARegisterList(1); }
+ size_t GetDestMemoryVersion() const { return GetRawOperandAsExpr(0).GetRawOperandAsIndex(0); }
+ LowLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(1); }
+ SSARegister GetStackSSARegister() const { return GetRawOperandAsExpr(2).GetRawOperandAsSSARegister(0); }
+ size_t GetSourceMemoryVersion() const { return GetRawOperandAsExpr(2).GetRawOperandAsIndex(2); }
+ LowLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExpr(3).GetRawOperandAsExprList(0); }
+ void SetDestMemoryVersion(size_t version) { GetRawOperandAsExpr(0).UpdateRawOperand(0, version); }
+ void SetSourceMemoryVersion(size_t version) { GetRawOperandAsExpr(2).UpdateRawOperand(2, version); }
+ void SetStackSSAVersion(size_t version) { GetRawOperandAsExpr(2).UpdateRawOperand(1, version); }
+ void SetOutputSSARegisters(const std::vector<SSARegister>& regs) { GetRawOperandAsExpr(0).UpdateRawOperandAsSSARegisterList(1, regs); }
+ };
template <> struct LowLevelILInstructionAccessor<LLIL_INTRINSIC>: public LowLevelILInstructionBase
{
diff --git a/mediumlevelilinstruction.cpp b/mediumlevelilinstruction.cpp
index fa66f553..9cf82b08 100644
--- a/mediumlevelilinstruction.cpp
+++ b/mediumlevelilinstruction.cpp
@@ -129,6 +129,10 @@ unordered_map<BNMediumLevelILOperation, vector<MediumLevelILOperandUsage>>
{MLIL_SYSCALL, {OutputVariablesMediumLevelOperandUsage, ParameterExprsMediumLevelOperandUsage}},
{MLIL_SYSCALL_UNTYPED, {OutputVariablesSubExprMediumLevelOperandUsage,
ParameterVariablesMediumLevelOperandUsage, StackExprMediumLevelOperandUsage}},
+ {MLIL_TAILCALL, {OutputVariablesMediumLevelOperandUsage, DestExprMediumLevelOperandUsage,
+ ParameterExprsMediumLevelOperandUsage}},
+ {MLIL_TAILCALL_UNTYPED, {OutputVariablesSubExprMediumLevelOperandUsage, DestExprMediumLevelOperandUsage,
+ ParameterVariablesMediumLevelOperandUsage}},
{MLIL_CALL_SSA, {OutputSSAVariablesSubExprMediumLevelOperandUsage,
OutputSSAMemoryVersionMediumLevelOperandUsage, DestExprMediumLevelOperandUsage,
ParameterExprsMediumLevelOperandUsage, SourceMemoryVersionMediumLevelOperandUsage}},
@@ -142,6 +146,13 @@ unordered_map<BNMediumLevelILOperation, vector<MediumLevelILOperandUsage>>
{MLIL_SYSCALL_UNTYPED_SSA, {OutputSSAVariablesSubExprMediumLevelOperandUsage,
OutputSSAMemoryVersionMediumLevelOperandUsage, ParameterSSAVariablesMediumLevelOperandUsage,
ParameterSSAMemoryVersionMediumLevelOperandUsage, StackExprMediumLevelOperandUsage}},
+ {MLIL_TAILCALL_SSA, {OutputSSAVariablesSubExprMediumLevelOperandUsage,
+ OutputSSAMemoryVersionMediumLevelOperandUsage, DestExprMediumLevelOperandUsage,
+ ParameterExprsMediumLevelOperandUsage, SourceMemoryVersionMediumLevelOperandUsage}},
+ {MLIL_TAILCALL_UNTYPED_SSA, {OutputSSAVariablesSubExprMediumLevelOperandUsage,
+ OutputSSAMemoryVersionMediumLevelOperandUsage, DestExprMediumLevelOperandUsage,
+ ParameterSSAVariablesMediumLevelOperandUsage, ParameterSSAMemoryVersionMediumLevelOperandUsage,
+ StackExprMediumLevelOperandUsage}},
{MLIL_RET, {SourceExprsMediumLevelOperandUsage}},
{MLIL_IF, {ConditionExprMediumLevelOperandUsage, TrueTargetMediumLevelOperandUsage,
FalseTargetMediumLevelOperandUsage}},
@@ -1267,6 +1278,22 @@ void MediumLevelILInstruction::VisitExprs(const std::function<bool(const MediumL
for (auto& i : GetParameterExprs<MLIL_SYSCALL_SSA>())
i.VisitExprs(func);
break;
+ case MLIL_TAILCALL:
+ GetDestExpr<MLIL_TAILCALL>().VisitExprs(func);
+ for (auto& i : GetParameterExprs<MLIL_TAILCALL>())
+ i.VisitExprs(func);
+ break;
+ case MLIL_TAILCALL_UNTYPED:
+ GetDestExpr<MLIL_TAILCALL_UNTYPED>().VisitExprs(func);
+ break;
+ case MLIL_TAILCALL_SSA:
+ GetDestExpr<MLIL_TAILCALL_SSA>().VisitExprs(func);
+ for (auto& i : GetParameterExprs<MLIL_TAILCALL_SSA>())
+ i.VisitExprs(func);
+ break;
+ case MLIL_TAILCALL_UNTYPED_SSA:
+ GetDestExpr<MLIL_TAILCALL_UNTYPED_SSA>().VisitExprs(func);
+ break;
case MLIL_RET:
for (auto& i : GetSourceExprs<MLIL_RET>())
i.VisitExprs(func);
@@ -1504,6 +1531,27 @@ ExprId MediumLevelILInstruction::CopyTo(MediumLevelILFunction* dest,
GetDestMemoryVersion<MLIL_SYSCALL_UNTYPED_SSA>(),
GetSourceMemoryVersion<MLIL_SYSCALL_UNTYPED_SSA>(),
subExprHandler(GetStackExpr<MLIL_SYSCALL_UNTYPED_SSA>()), *this);
+ case MLIL_TAILCALL:
+ for (auto& i : GetParameterExprs<MLIL_TAILCALL>())
+ params.push_back(subExprHandler(i));
+ return dest->TailCall(GetOutputVariables<MLIL_TAILCALL>(), subExprHandler(GetDestExpr<MLIL_TAILCALL>()),
+ params, *this);
+ case MLIL_TAILCALL_UNTYPED:
+ return dest->TailCallUntyped(GetOutputVariables<MLIL_TAILCALL_UNTYPED>(),
+ subExprHandler(GetDestExpr<MLIL_TAILCALL_UNTYPED>()), GetParameterVariables<MLIL_TAILCALL_UNTYPED>(),
+ subExprHandler(GetStackExpr<MLIL_TAILCALL_UNTYPED>()), *this);
+ case MLIL_TAILCALL_SSA:
+ for (auto& i : GetParameterExprs<MLIL_TAILCALL_SSA>())
+ params.push_back(subExprHandler(i));
+ return dest->TailCallSSA(GetOutputSSAVariables<MLIL_TAILCALL_SSA>(), subExprHandler(GetDestExpr<MLIL_TAILCALL_SSA>()),
+ params, GetDestMemoryVersion<MLIL_TAILCALL_SSA>(), GetSourceMemoryVersion<MLIL_TAILCALL_SSA>(), *this);
+ case MLIL_TAILCALL_UNTYPED_SSA:
+ return dest->TailCallUntypedSSA(GetOutputSSAVariables<MLIL_TAILCALL_UNTYPED_SSA>(),
+ subExprHandler(GetDestExpr<MLIL_TAILCALL_UNTYPED_SSA>()),
+ GetParameterSSAVariables<MLIL_TAILCALL_UNTYPED_SSA>(),
+ GetDestMemoryVersion<MLIL_TAILCALL_UNTYPED_SSA>(),
+ GetSourceMemoryVersion<MLIL_TAILCALL_UNTYPED_SSA>(),
+ subExprHandler(GetStackExpr<MLIL_TAILCALL_UNTYPED_SSA>()), *this);
case MLIL_RET:
for (auto& i : GetSourceExprs<MLIL_RET>())
params.push_back(subExprHandler(i));
@@ -2483,6 +2531,23 @@ ExprId MediumLevelILFunction::SyscallUntyped(const vector<Variable>& output, con
}
+ExprId MediumLevelILFunction::TailCall(const vector<Variable>& output, ExprId dest,
+ const vector<ExprId>& params, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(MLIL_TAILCALL, loc, 0, output.size(), AddVariableList(output), dest,
+ params.size(), AddOperandList(params));
+}
+
+
+ExprId MediumLevelILFunction::TailCallUntyped(const vector<Variable>& output, ExprId dest,
+ const vector<Variable>& params, ExprId stack, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(MLIL_TAILCALL_UNTYPED, loc, 0,
+ AddExprWithLocation(MLIL_CALL_OUTPUT, loc, 0, output.size(), AddVariableList(output)), dest,
+ AddExprWithLocation(MLIL_CALL_PARAM, loc, 0, params.size(), AddVariableList(params)), stack);
+}
+
+
ExprId MediumLevelILFunction::CallSSA(const vector<SSAVariable>& output, ExprId dest, const vector<ExprId>& params,
size_t newMemVersion, size_t prevMemVersion, const ILSourceLocation& loc)
{
@@ -2527,6 +2592,28 @@ ExprId MediumLevelILFunction::SyscallUntypedSSA(const vector<SSAVariable>& outpu
}
+ExprId MediumLevelILFunction::TailCallSSA(const vector<SSAVariable>& output, ExprId dest, const vector<ExprId>& params,
+ size_t newMemVersion, size_t prevMemVersion, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(MLIL_TAILCALL_SSA, loc, 0,
+ AddExprWithLocation(MLIL_CALL_OUTPUT_SSA, loc, 0, newMemVersion,
+ output.size() * 2, AddSSAVariableList(output)), dest,
+ params.size(), AddOperandList(params), prevMemVersion);
+}
+
+
+ExprId MediumLevelILFunction::TailCallUntypedSSA(const vector<SSAVariable>& output, ExprId dest,
+ const vector<SSAVariable>& params, size_t newMemVersion, size_t prevMemVersion,
+ ExprId stack, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(MLIL_TAILCALL_UNTYPED_SSA, loc, 0,
+ AddExprWithLocation(MLIL_CALL_OUTPUT_SSA, loc, 0, newMemVersion,
+ output.size() * 2, AddSSAVariableList(output)), dest,
+ AddExprWithLocation(MLIL_CALL_PARAM_SSA, loc, 0, prevMemVersion,
+ params.size() * 2, AddSSAVariableList(params)), stack);
+}
+
+
ExprId MediumLevelILFunction::Return(const vector<ExprId>& sources, const ILSourceLocation& loc)
{
return AddExprWithLocation(MLIL_RET, loc, 0, sources.size(), AddOperandList(sources));
diff --git a/mediumlevelilinstruction.h b/mediumlevelilinstruction.h
index e3167585..b37b8832 100644
--- a/mediumlevelilinstruction.h
+++ b/mediumlevelilinstruction.h
@@ -839,6 +839,19 @@ namespace BinaryNinja
MediumLevelILVariableList GetParameterVariables() const { return GetRawOperandAsExpr(1).GetRawOperandAsVariableList(0); }
MediumLevelILInstruction GetStackExpr() const { return GetRawOperandAsExpr(2); }
};
+ template <> struct MediumLevelILInstructionAccessor<MLIL_TAILCALL>: public MediumLevelILInstructionBase
+ {
+ MediumLevelILVariableList GetOutputVariables() const { return GetRawOperandAsVariableList(0); }
+ MediumLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(2); }
+ MediumLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExprList(3); }
+ };
+ template <> struct MediumLevelILInstructionAccessor<MLIL_TAILCALL_UNTYPED>: public MediumLevelILInstructionBase
+ {
+ MediumLevelILVariableList GetOutputVariables() const { return GetRawOperandAsExpr(0).GetRawOperandAsVariableList(0); }
+ MediumLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(1); }
+ MediumLevelILVariableList GetParameterVariables() const { return GetRawOperandAsExpr(2).GetRawOperandAsVariableList(0); }
+ MediumLevelILInstruction GetStackExpr() const { return GetRawOperandAsExpr(3); }
+ };
template <> struct MediumLevelILInstructionAccessor<MLIL_CALL_SSA>: public MediumLevelILInstructionBase
{
@@ -890,6 +903,32 @@ namespace BinaryNinja
void SetOutputSSAVariables(const std::vector<SSAVariable>& vars) { GetRawOperandAsExpr(0).UpdateRawOperandAsSSAVariableList(1, vars); }
void SetParameterSSAVariables(const std::vector<SSAVariable>& vars) { GetRawOperandAsExpr(1).UpdateRawOperandAsSSAVariableList(1, vars); }
};
+ template <> struct MediumLevelILInstructionAccessor<MLIL_TAILCALL_SSA>: public MediumLevelILInstructionBase
+ {
+ size_t GetDestMemoryVersion() const { return GetRawOperandAsExpr(0).GetRawOperandAsIndex(0); }
+ MediumLevelILSSAVariableList GetOutputSSAVariables() const { return GetRawOperandAsExpr(0).GetRawOperandAsSSAVariableList(1); }
+ MediumLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(1); }
+ MediumLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExprList(2); }
+ size_t GetSourceMemoryVersion() const { return GetRawOperandAsIndex(4); }
+ void SetDestMemoryVersion(size_t version) { GetRawOperandAsExpr(0).UpdateRawOperand(0, version); }
+ void SetSourceMemoryVersion(size_t version) { UpdateRawOperand(4, version); }
+ void SetOutputSSAVariables(const std::vector<SSAVariable>& vars) { GetRawOperandAsExpr(0).UpdateRawOperandAsSSAVariableList(1, vars); }
+ void SetParameterExprs(const std::vector<MediumLevelILInstruction>& params) { UpdateRawOperandAsExprList(2, params); }
+ void SetParameterExprs(const std::vector<ExprId>& params) { UpdateRawOperandAsExprList(2, params); }
+ };
+ template <> struct MediumLevelILInstructionAccessor<MLIL_TAILCALL_UNTYPED_SSA>: public MediumLevelILInstructionBase
+ {
+ size_t GetDestMemoryVersion() const { return GetRawOperandAsExpr(0).GetRawOperandAsIndex(0); }
+ MediumLevelILSSAVariableList GetOutputSSAVariables() const { return GetRawOperandAsExpr(0).GetRawOperandAsSSAVariableList(1); }
+ MediumLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(1); }
+ MediumLevelILSSAVariableList GetParameterSSAVariables() const { return GetRawOperandAsExpr(2).GetRawOperandAsSSAVariableList(1); }
+ size_t GetSourceMemoryVersion() const { return GetRawOperandAsExpr(2).GetRawOperandAsIndex(0); }
+ MediumLevelILInstruction GetStackExpr() const { return GetRawOperandAsExpr(3); }
+ void SetDestMemoryVersion(size_t version) { GetRawOperandAsExpr(0).UpdateRawOperand(0, version); }
+ void SetSourceMemoryVersion(size_t version) { GetRawOperandAsExpr(2).UpdateRawOperand(0, version); }
+ void SetOutputSSAVariables(const std::vector<SSAVariable>& vars) { GetRawOperandAsExpr(0).UpdateRawOperandAsSSAVariableList(1, vars); }
+ void SetParameterSSAVariables(const std::vector<SSAVariable>& vars) { GetRawOperandAsExpr(2).UpdateRawOperandAsSSAVariableList(1, vars); }
+ };
template <> struct MediumLevelILInstructionAccessor<MLIL_RET>: public MediumLevelILInstructionBase
{
diff --git a/python/__init__.py b/python/__init__.py
index 05ba4c2b..aa7c1ed4 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -19,41 +19,115 @@
# IN THE SOFTWARE.
+from __future__ import absolute_import
import atexit
import sys
+import ctypes
from time import gmtime
+
+# 2-3 compatibility
+try:
+ import builtins # __builtins__ for python2
+except ImportError:
+ pass
+def range(*args):
+ """ A Python2 and Python3 Compatible Range Generator """
+ try:
+ return xrange(*args)
+ except NameError:
+ return builtins.range(*args)
+
+
+def with_metaclass(meta, *bases):
+ """Create a base class with a metaclass."""
+ class metaclass(type):
+ def __new__(cls, name, this_bases, d):
+ return meta(name, bases, d)
+
+ @classmethod
+ def __prepare__(cls, name, this_bases):
+ return meta.__prepare__(name, bases)
+ return type.__new__(metaclass, 'temporary_class', (), {})
+
+
+def cstr(arg):
+ if isinstance(arg, bytes) or arg is None:
+ return arg
+ else:
+ return arg.encode('charmap')
+
+
+def pyNativeStr(arg):
+ if isinstance(arg, str):
+ return arg
+ else:
+ return arg.decode('charmap')
+
+
# Binary Ninja components
-import _binaryninjacore as core
-from .enums import *
-from .databuffer import *
-from .filemetadata import *
-from .fileaccessor import *
-from .binaryview import *
-from .transform import *
-from .architecture import *
-from .basicblock import *
-from .function import *
-from .log import *
-from .lowlevelil import *
-from .mediumlevelil import *
-from .types import *
-from .functionrecognizer import *
-from .update import *
-from .plugin import *
-from .callingconvention import *
-from .platform import *
-from .demangle import *
-from .mainthread import *
-from .interaction import *
-from .lineardisassembly import *
-from .undoaction import *
-from .highlight import *
-from .scriptingprovider import *
-from .pluginmanager import *
-from .setting import *
-from .metadata import *
-from .flowgraph import *
+import binaryninja._binaryninjacore as core
+# __all__ = [
+# "enums",
+# "databuffer",
+# "filemetadata",
+# "fileaccessor",
+# "binaryview",
+# "transform",
+# "architecture",
+# "basicblock",
+# "function",
+# "log",
+# "lowlevelil",
+# "mediumlevelil",
+# "types",
+# "functionrecognizer",
+# "update",
+# "plugin",
+# "callingconvention",
+# "platform",
+# "demangle",
+# "mainthread",
+# "interaction",
+# "lineardisassembly",
+# "undoaction",
+# "highlight",
+# "scriptingprovider",
+# "pluginmanager",
+# "setting",
+# "metadata",
+# "flowgraph",
+# ]
+from binaryninja.enums import *
+from binaryninja.databuffer import *
+from binaryninja.filemetadata import *
+from binaryninja.fileaccessor import *
+from binaryninja.binaryview import *
+from binaryninja.transform import *
+from binaryninja.architecture import *
+from binaryninja.basicblock import *
+from binaryninja.function import *
+from binaryninja.log import *
+from binaryninja.lowlevelil import *
+from binaryninja.mediumlevelil import *
+from binaryninja.types import *
+from binaryninja.functionrecognizer import *
+from binaryninja.update import *
+from binaryninja.plugin import *
+from binaryninja.callingconvention import *
+from binaryninja.platform import *
+from binaryninja.demangle import *
+from binaryninja.mainthread import *
+from binaryninja.interaction import *
+from binaryninja.lineardisassembly import *
+from binaryninja.undoaction import *
+from binaryninja.highlight import *
+from binaryninja.scriptingprovider import *
+from binaryninja.downloadprovider import *
+from binaryninja.pluginmanager import *
+from binaryninja.setting import *
+from binaryninja.metadata import *
+from binaryninja.flowgraph import *
def shutdown():
@@ -138,6 +212,20 @@ class _DestructionCallbackHandler(object):
Function._unregister(func)
+_plugin_init = False
+
+
+def _init_plugins():
+ global _plugin_init
+ if not _plugin_init:
+ _plugin_init = True
+ core.BNInitCorePlugins()
+ core.BNInitUserPlugins()
+ core.BNInitRepoPlugins()
+ if not core.BNIsLicenseValidated():
+ raise RuntimeError("License is not valid. Please supply a valid license.")
+
+
_destruct_callbacks = _DestructionCallbackHandler()
bundled_plugin_path = core.BNGetBundledPluginDirectory()
diff --git a/python/architecture.py b/python/architecture.py
index c5f87ec6..aee7c301 100644
--- a/python/architecture.py
+++ b/python/architecture.py
@@ -18,55 +18,60 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
+from __future__ import absolute_import
import traceback
import ctypes
import abc
# Binary Ninja components
-import _binaryninjacore as core
-from enums import (Endianness, ImplicitRegisterExtend, BranchType,
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import (Endianness, ImplicitRegisterExtend, BranchType,
InstructionTextTokenType, LowLevelILFlagCondition, FlagRole)
-import startup
-import function
-import lowlevelil
-import callingconvention
-import platform
-import log
-import databuffer
-import types
+import binaryninja
+from binaryninja import log
+from binaryninja import lowlevelil
+from binaryninja import types
+from binaryninja import databuffer
+from binaryninja import platform
+from binaryninja import callingconvention
+
+# 2-3 compatibility
+from binaryninja import range
+from binaryninja import with_metaclass
class _ArchitectureMetaClass(type):
+
@property
def list(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
archs = core.BNGetArchitectureList(count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(CoreArchitecture._from_cache(archs[i]))
core.BNFreeArchitectureList(archs)
return result
def __iter__(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
archs = core.BNGetArchitectureList(count)
try:
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
yield CoreArchitecture._from_cache(archs[i])
finally:
core.BNFreeArchitectureList(archs)
def __getitem__(cls, name):
- startup._init_plugins()
+ binaryninja._init_plugins()
arch = core.BNGetArchitectureByName(name)
if arch is None:
raise KeyError("'%s' is not a valid architecture" % str(name))
return CoreArchitecture._from_cache(arch)
def register(cls):
- startup._init_plugins()
+ binaryninja._init_plugins()
if cls.name is None:
raise ValueError("architecture 'name' is not defined")
arch = cls()
@@ -80,12 +85,12 @@ class _ArchitectureMetaClass(type):
raise AttributeError("attribute '%s' is read only" % name)
-class Architecture(object):
+class Architecture(with_metaclass(_ArchitectureMetaClass, object)):
"""
``class Architecture`` is the parent class for all CPU architectures. Subclasses of Architecture implement assembly,
disassembly, IL lifting, and patching.
- ``class Architecture`` has a ``__metaclass__`` with the additional methods ``register``, and supports
+ ``class Architecture`` has a metaclass with the additional methods ``register``, and supports
iteration::
>>> #List the architectures
@@ -130,11 +135,10 @@ class Architecture(object):
semantic_class_for_flag_write_type = {}
reg_stacks = {}
intrinsics = {}
- __metaclass__ = _ArchitectureMetaClass
next_address = 0
def __init__(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
if self.__class__.opcode_display_length > self.__class__.max_instr_length:
self.__class__.opcode_display_length = self.__class__.max_instr_length
@@ -365,11 +369,11 @@ class Architecture(object):
for intrinsic in self.__class__.intrinsics.keys():
if intrinsic not in self._intrinsics:
info = self.__class__.intrinsics[intrinsic]
- for i in xrange(0, len(info.inputs)):
+ for i in range(0, len(info.inputs)):
if isinstance(info.inputs[i], types.Type):
- info.inputs[i] = function.IntrinsicInput(info.inputs[i])
+ info.inputs[i] = binaryninja.function.IntrinsicInput(info.inputs[i])
elif isinstance(info.inputs[i], tuple):
- info.inputs[i] = function.IntrinsicInput(info.inputs[i][0], info.inputs[i][1])
+ info.inputs[i] = binaryninja.function.IntrinsicInput(info.inputs[i][0], info.inputs[i][1])
info.index = intrinsic_index
self._intrinsics[intrinsic] = intrinsic_index
self._intrinsics_by_index[intrinsic_index] = (intrinsic, info)
@@ -392,12 +396,17 @@ class Architecture(object):
return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
@property
+ def list(self):
+ """Allow tab completion to discover metaclass list property"""
+ pass
+
+ @property
def full_width_regs(self):
"""List of full width register strings (read-only)"""
count = ctypes.c_ulonglong()
regs = core.BNGetFullWidthArchitectureRegisters(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(core.BNGetArchitectureRegisterName(self.handle, regs[i]))
core.BNFreeRegisterList(regs)
return result
@@ -408,7 +417,7 @@ class Architecture(object):
count = ctypes.c_ulonglong()
cc = core.BNGetArchitectureCallingConventions(self.handle, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
obj = callingconvention.CallingConvention(handle=core.BNNewCallingConventionReference(cc[i]))
result[obj.name] = obj
core.BNFreeCallingConventionList(cc, count)
@@ -499,7 +508,7 @@ class Architecture(object):
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)):
+ for i in range(0, len(info.branches)):
if isinstance(info.branches[i].type, str):
result[0].branchType[i] = BranchType[info.branches[i].type]
else:
@@ -525,7 +534,7 @@ class Architecture(object):
length[0] = info[1]
count[0] = len(tokens)
token_buf = (core.BNInstructionTextToken * len(tokens))()
- for i in xrange(0, len(tokens)):
+ for i in range(0, len(tokens)):
if isinstance(tokens[i].type, str):
token_buf[i].type = InstructionTextTokenType[tokens[i].type]
else:
@@ -615,10 +624,10 @@ class Architecture(object):
def _get_full_width_registers(self, ctxt, count):
try:
- regs = self._full_width_regs.values()
+ regs = list(self._full_width_regs.values())
count[0] = len(regs)
reg_buf = (ctypes.c_uint * len(regs))()
- for i in xrange(0, len(regs)):
+ for i in range(0, len(regs)):
reg_buf[i] = regs[i]
result = ctypes.cast(reg_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, reg_buf)
@@ -630,10 +639,10 @@ class Architecture(object):
def _get_all_registers(self, ctxt, count):
try:
- regs = self._regs_by_index.keys()
+ regs = list(self._regs_by_index.keys())
count[0] = len(regs)
reg_buf = (ctypes.c_uint * len(regs))()
- for i in xrange(0, len(regs)):
+ for i in range(0, len(regs)):
reg_buf[i] = regs[i]
result = ctypes.cast(reg_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, reg_buf)
@@ -645,10 +654,10 @@ class Architecture(object):
def _get_all_flags(self, ctxt, count):
try:
- flags = self._flags_by_index.keys()
+ flags = list(self._flags_by_index.keys())
count[0] = len(flags)
flag_buf = (ctypes.c_uint * len(flags))()
- for i in xrange(0, len(flags)):
+ for i in range(0, len(flags)):
flag_buf[i] = flags[i]
result = ctypes.cast(flag_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, flag_buf)
@@ -660,10 +669,10 @@ class Architecture(object):
def _get_all_flag_write_types(self, ctxt, count):
try:
- write_types = self._flag_write_types_by_index.keys()
+ write_types = list(self._flag_write_types_by_index.keys())
count[0] = len(write_types)
type_buf = (ctypes.c_uint * len(write_types))()
- for i in xrange(0, len(write_types)):
+ for i in range(0, len(write_types)):
type_buf[i] = write_types[i]
result = ctypes.cast(type_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, type_buf)
@@ -675,10 +684,10 @@ class Architecture(object):
def _get_all_semantic_flag_classes(self, ctxt, count):
try:
- sem_classes = self._semantic_flag_classes_by_index.keys()
+ sem_classes = list(self._semantic_flag_classes_by_index.keys())
count[0] = len(sem_classes)
class_buf = (ctypes.c_uint * len(sem_classes))()
- for i in xrange(0, len(sem_classes)):
+ for i in range(0, len(sem_classes)):
class_buf[i] = sem_classes[i]
result = ctypes.cast(class_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, class_buf)
@@ -690,10 +699,10 @@ class Architecture(object):
def _get_all_semantic_flag_groups(self, ctxt, count):
try:
- sem_groups = self._semantic_flag_groups_by_index.keys()
+ sem_groups = list(self._semantic_flag_groups_by_index.keys())
count[0] = len(sem_groups)
group_buf = (ctypes.c_uint * len(sem_groups))()
- for i in xrange(0, len(sem_groups)):
+ for i in range(0, len(sem_groups)):
group_buf[i] = sem_groups[i]
result = ctypes.cast(group_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, group_buf)
@@ -726,7 +735,7 @@ class Architecture(object):
flags.append(self._flags[name])
count[0] = len(flags)
flag_buf = (ctypes.c_uint * len(flags))()
- for i in xrange(0, len(flags)):
+ for i in range(0, len(flags)):
flag_buf[i] = flags[i]
result = ctypes.cast(flag_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, flag_buf)
@@ -744,7 +753,7 @@ class Architecture(object):
flags = []
count[0] = len(flags)
flag_buf = (ctypes.c_uint * len(flags))()
- for i in xrange(0, len(flags)):
+ for i in range(0, len(flags)):
flag_buf[i] = flags[i]
result = ctypes.cast(flag_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, flag_buf)
@@ -792,7 +801,7 @@ class Architecture(object):
flags = []
count[0] = len(flags)
flag_buf = (ctypes.c_uint * len(flags))()
- for i in xrange(0, len(flags)):
+ for i in range(0, len(flags)):
flag_buf[i] = flags[i]
result = ctypes.cast(flag_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, flag_buf)
@@ -819,7 +828,7 @@ class Architecture(object):
write_type_name = self._flag_write_types_by_index[write_type]
flag_name = self._flags_by_index[flag]
operand_list = []
- for i in xrange(operand_count):
+ for i in range(operand_count):
if operands[i].constant:
operand_list.append(operands[i].value)
elif lowlevelil.LLIL_REG_IS_TEMP(operands[i].reg):
@@ -908,7 +917,7 @@ class Architecture(object):
try:
count[0] = len(self.global_regs)
reg_buf = (ctypes.c_uint * len(self.global_regs))()
- for i in xrange(0, len(self.global_regs)):
+ for i in range(0, len(self.global_regs)):
reg_buf[i] = self._all_regs[self.global_regs[i]]
result = ctypes.cast(reg_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, reg_buf)
@@ -929,10 +938,10 @@ class Architecture(object):
def _get_all_register_stacks(self, ctxt, count):
try:
- regs = self._reg_stacks_by_index.keys()
+ regs = list(self._reg_stacks_by_index.keys())
count[0] = len(regs)
reg_buf = (ctypes.c_uint * len(regs))()
- for i in xrange(0, len(regs)):
+ for i in range(0, len(regs)):
reg_buf[i] = regs[i]
result = ctypes.cast(reg_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, reg_buf)
@@ -980,10 +989,10 @@ class Architecture(object):
def _get_all_intrinsics(self, ctxt, count):
try:
- regs = self._intrinsics_by_index.keys()
+ regs = list(self._intrinsics_by_index.keys())
count[0] = len(regs)
reg_buf = (ctypes.c_uint * len(regs))()
- for i in xrange(0, len(regs)):
+ for i in range(0, len(regs)):
reg_buf[i] = regs[i]
result = ctypes.cast(reg_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, reg_buf)
@@ -999,7 +1008,7 @@ class Architecture(object):
inputs = self._intrinsics_by_index[intrinsic][1].inputs
count[0] = len(inputs)
input_buf = (core.BNNameAndType * len(inputs))()
- for i in xrange(0, len(inputs)):
+ for i in range(0, len(inputs)):
input_buf[i].name = inputs[i].name
input_buf[i].type = core.BNNewTypeReference(inputs[i].type.handle)
input_buf[i].typeConfidence = inputs[i].type.confidence
@@ -1020,7 +1029,7 @@ class Architecture(object):
raise ValueError("freeing name and type list that wasn't allocated")
name_and_types = self._pending_name_and_type_lists[buf.value][1]
count = self._pending_name_and_type_lists[buf.value][2]
- for i in xrange(0, count):
+ for i in range(0, count):
core.BNFreeType(name_and_types[i].type)
del self._pending_name_and_type_lists[buf.value]
except (ValueError, KeyError):
@@ -1032,7 +1041,7 @@ class Architecture(object):
outputs = self._intrinsics_by_index[intrinsic][1].outputs
count[0] = len(outputs)
output_buf = (core.BNTypeWithConfidence * len(outputs))()
- for i in xrange(0, len(outputs)):
+ for i in range(0, len(outputs)):
output_buf[i].type = core.BNNewTypeReference(outputs[i].handle)
output_buf[i].confidence = outputs[i].confidence
result = ctypes.cast(output_buf, ctypes.c_void_p)
@@ -1052,7 +1061,7 @@ class Architecture(object):
raise ValueError("freeing type list that wasn't allocated")
types = self._pending_type_lists[buf.value][1]
count = self._pending_type_lists[buf.value][2]
- for i in xrange(0, count):
+ for i in range(0, count):
core.BNFreeType(types[i].type)
del self._pending_type_lists[buf.value]
except (ValueError, KeyError):
@@ -1064,7 +1073,6 @@ class Architecture(object):
errors[0] = core.BNAllocString(str(error_str))
if data is None:
return False
- data = str(data)
buf = ctypes.create_string_buffer(len(data))
ctypes.memmove(buf, data, len(data))
core.BNSetDataBufferContents(result, buf, len(data))
@@ -1701,7 +1709,7 @@ class Architecture(object):
:rtype: LowLevelILExpr index
"""
operand_list = (core.BNRegisterOrConstant * len(operands))()
- for i in xrange(len(operands)):
+ for i in range(len(operands)):
if isinstance(operands[i], str):
operand_list[i].constant = False
operand_list[i].reg = self.regs[operands[i]].index
@@ -1756,7 +1764,7 @@ class Architecture(object):
count = ctypes.c_ulonglong()
regs = core.BNGetModifiedArchitectureRegistersOnWrite(self.handle, reg, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(core.BNGetArchitectureRegisterName(self.handle, regs[i]))
core.BNFreeRegisterList(regs)
return result
@@ -2065,15 +2073,15 @@ class CoreArchitecture(Architecture):
self._regs_by_index = {}
self._full_width_regs = {}
self.__dict__["regs"] = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
name = core.BNGetArchitectureRegisterName(self.handle, regs[i])
info = core.BNGetArchitectureRegisterInfo(self.handle, regs[i])
full_width_reg = core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister)
- self.regs[name] = function.RegisterInfo(full_width_reg, info.size, info.offset,
+ self.regs[name] = binaryninja.function.RegisterInfo(full_width_reg, info.size, info.offset,
ImplicitRegisterExtend(info.extend), regs[i])
self._all_regs[name] = regs[i]
self._regs_by_index[regs[i]] = name
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
info = core.BNGetArchitectureRegisterInfo(self.handle, regs[i])
full_width_reg = core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister)
if full_width_reg not in self._full_width_regs:
@@ -2085,7 +2093,7 @@ class CoreArchitecture(Architecture):
self._flags = {}
self._flags_by_index = {}
self.__dict__["flags"] = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
name = core.BNGetArchitectureFlagName(self.handle, flags[i])
self._flags[name] = flags[i]
self._flags_by_index[flags[i]] = name
@@ -2097,7 +2105,7 @@ class CoreArchitecture(Architecture):
self._flag_write_types = {}
self._flag_write_types_by_index = {}
self.__dict__["flag_write_types"] = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
name = core.BNGetArchitectureFlagWriteTypeName(self.handle, write_types[i])
self._flag_write_types[name] = write_types[i]
self._flag_write_types_by_index[write_types[i]] = name
@@ -2109,7 +2117,7 @@ class CoreArchitecture(Architecture):
self._semantic_flag_classes = {}
self._semantic_flag_classes_by_index = {}
self.__dict__["semantic_flag_classes"] = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
name = core.BNGetArchitectureSemanticFlagClassName(self.handle, sem_classes[i])
self._semantic_flag_classes[name] = sem_classes[i]
self._semantic_flag_classes_by_index[sem_classes[i]] = name
@@ -2121,7 +2129,7 @@ class CoreArchitecture(Architecture):
self._semantic_flag_groups = {}
self._semantic_flag_groups_by_index = {}
self.__dict__["semantic_flag_groups"] = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
name = core.BNGetArchitectureSemanticFlagGroupName(self.handle, sem_groups[i])
self._semantic_flag_groups[name] = sem_groups[i]
self._semantic_flag_groups_by_index[sem_groups[i]] = name
@@ -2140,7 +2148,7 @@ class CoreArchitecture(Architecture):
count = ctypes.c_ulonglong()
flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, 0, count)
flag_names = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
flag_names.append(self._flags_by_index[flags[i]])
core.BNFreeRegisterList(flags)
self.__dict__["flags_required_for_flag_condition"][cond] = flag_names
@@ -2153,7 +2161,7 @@ class CoreArchitecture(Architecture):
self._semantic_flag_groups[group], count)
flag_indexes = []
flag_names = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
flag_indexes.append(flags[i])
flag_names.append(self._flags_by_index[flags[i]])
core.BNFreeRegisterList(flags)
@@ -2168,7 +2176,7 @@ class CoreArchitecture(Architecture):
self._semantic_flag_groups[group], count)
class_index_cond = {}
class_cond = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
class_index_cond[conditions[i].semanticClass] = conditions[i].condition
if conditions[i].semanticClass == 0:
class_cond[None] = conditions[i].condition
@@ -2186,7 +2194,7 @@ class CoreArchitecture(Architecture):
self._flag_write_types[write_type], count)
flag_indexes = []
flag_names = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
flag_indexes.append(flags[i])
flag_names.append(self._flags_by_index[flags[i]])
core.BNFreeRegisterList(flags)
@@ -2208,7 +2216,7 @@ class CoreArchitecture(Architecture):
count = ctypes.c_ulonglong()
regs = core.BNGetArchitectureGlobalRegisters(self.handle, count)
self.__dict__["global_regs"] = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
self.global_regs.append(core.BNGetArchitectureRegisterName(self.handle, regs[i]))
core.BNFreeRegisterList(regs)
@@ -2217,17 +2225,17 @@ class CoreArchitecture(Architecture):
self._all_reg_stacks = {}
self._reg_stacks_by_index = {}
self.__dict__["reg_stacks"] = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
name = core.BNGetArchitectureRegisterStackName(self.handle, regs[i])
info = core.BNGetArchitectureRegisterStackInfo(self.handle, regs[i])
storage = []
- for j in xrange(0, info.storageCount):
+ for j in range(0, info.storageCount):
storage.append(core.BNGetArchitectureRegisterName(self.handle, info.firstStorageReg + j))
top_rel = []
- for j in xrange(0, info.topRelativeCount):
+ for j in range(0, info.topRelativeCount):
top_rel.append(core.BNGetArchitectureRegisterName(self.handle, info.firstTopRelativeReg + j))
top = core.BNGetArchitectureRegisterName(self.handle, info.stackTopReg)
- self.reg_stacks[name] = function.RegisterStackInfo(storage, top_rel, top, regs[i])
+ self.reg_stacks[name] = binaryninja.function.RegisterStackInfo(storage, top_rel, top, regs[i])
self._all_reg_stacks[name] = regs[i]
self._reg_stacks_by_index[regs[i]] = name
core.BNFreeRegisterList(regs)
@@ -2237,23 +2245,23 @@ class CoreArchitecture(Architecture):
self._intrinsics = {}
self._intrinsics_by_index = {}
self.__dict__["intrinsics"] = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
name = core.BNGetArchitectureIntrinsicName(self.handle, intrinsics[i])
input_count = ctypes.c_ulonglong()
inputs = core.BNGetArchitectureIntrinsicInputs(self.handle, intrinsics[i], input_count)
input_list = []
- for j in xrange(0, input_count.value):
+ for j in range(0, input_count.value):
input_name = inputs[j].name
type_obj = types.Type(core.BNNewTypeReference(inputs[j].type), confidence = inputs[j].typeConfidence)
- input_list.append(function.IntrinsicInput(type_obj, input_name))
+ input_list.append(binaryninja.function.IntrinsicInput(type_obj, input_name))
core.BNFreeNameAndTypeList(inputs, input_count.value)
output_count = ctypes.c_ulonglong()
outputs = core.BNGetArchitectureIntrinsicOutputs(self.handle, intrinsics[i], output_count)
output_list = []
- for j in xrange(0, output_count.value):
+ for j in range(0, output_count.value):
output_list.append(types.Type(core.BNNewTypeReference(outputs[j].type), confidence = outputs[j].confidence))
core.BNFreeOutputTypeList(outputs, output_count.value)
- self.intrinsics[name] = function.IntrinsicInfo(input_list, output_list)
+ self.intrinsics[name] = binaryninja.function.IntrinsicInfo(input_list, output_list)
self._intrinsics[name] = intrinsics[i]
self._intrinsics_by_index[intrinsics[i]] = (name, self.intrinsics[name])
core.BNFreeRegisterList(intrinsics)
@@ -2285,16 +2293,15 @@ class CoreArchitecture(Architecture):
:rtype: InstructionInfo
"""
info = core.BNInstructionInfo()
- data = str(data)
buf = (ctypes.c_ubyte * len(data))()
ctypes.memmove(buf, data, len(data))
if not core.BNGetInstructionInfo(self.handle, buf, addr, len(data), info):
return None
- result = function.InstructionInfo()
+ result = binaryninja.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):
+ for i in range(0, info.branchCount):
target = info.branchTarget[i]
if info.branchArch[i]:
arch = CoreArchitecture._from_cache(info.branchArch[i])
@@ -2313,7 +2320,6 @@ class CoreArchitecture(Architecture):
:return: an InstructionTextToken list for the current instruction
:rtype: list(InstructionTextToken)
"""
- data = str(data)
count = ctypes.c_ulonglong()
length = ctypes.c_ulonglong()
length.value = len(data)
@@ -2323,7 +2329,7 @@ class CoreArchitecture(Architecture):
if not core.BNGetInstructionText(self.handle, buf, addr, length, tokens, count):
return None, 0
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
token_type = InstructionTextTokenType(tokens[i].type)
text = tokens[i].text
value = tokens[i].value
@@ -2332,7 +2338,7 @@ class CoreArchitecture(Architecture):
context = tokens[i].context
confidence = tokens[i].confidence
address = tokens[i].address
- result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
+ result.append(binaryninja.function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
core.BNFreeInstructionText(tokens, count.value)
return result, length.value
@@ -2350,7 +2356,6 @@ class CoreArchitecture(Architecture):
:return: the length of the current instruction
:rtype: int
"""
- data = str(data)
length = ctypes.c_ulonglong()
length.value = len(data)
buf = (ctypes.c_ubyte * len(data))()
@@ -2370,7 +2375,7 @@ class CoreArchitecture(Architecture):
"""
flag = self.get_flag_index(flag)
operand_list = (core.BNRegisterOrConstant * len(operands))()
- for i in xrange(len(operands)):
+ for i in range(len(operands)):
if isinstance(operands[i], str):
operand_list[i].constant = False
operand_list[i].reg = self.regs[operands[i]].index
@@ -2410,8 +2415,8 @@ class CoreArchitecture(Architecture):
:param str code: string representation of the instructions to be assembled
:param int addr: virtual address that the instructions will be loaded at
- :return: the bytes for the assembled instructions or error string
- :rtype: (a tuple of instructions and empty string) or (or None and error string)
+ :return: the bytes for the assembled instructions
+ :rtype: Python3 - a 'bytes' object; Python2 - a 'str'
:Example:
>>> arch.assemble("je 10")
@@ -2421,8 +2426,11 @@ class CoreArchitecture(Architecture):
result = databuffer.DataBuffer()
errors = ctypes.c_char_p()
if not core.BNAssemble(self.handle, code, addr, result.handle, errors):
- return None, errors.value
- return str(result), errors.value
+ raise ValueError("Could not assemble")
+ if isinstance(str(result), bytes):
+ return str(result)
+ else:
+ return bytes(result)
def is_never_branch_patch_available(self, data, addr):
"""
@@ -2440,7 +2448,6 @@ class CoreArchitecture(Architecture):
False
>>>
"""
- data = str(data)
buf = (ctypes.c_ubyte * len(data))()
ctypes.memmove(buf, data, len(data))
return core.BNIsArchitectureNeverBranchPatchAvailable(self.handle, buf, addr, len(data))
@@ -2462,7 +2469,6 @@ class CoreArchitecture(Architecture):
False
>>>
"""
- data = str(data)
buf = (ctypes.c_ubyte * len(data))()
ctypes.memmove(buf, data, len(data))
return core.BNIsArchitectureAlwaysBranchPatchAvailable(self.handle, buf, addr, len(data))
@@ -2483,7 +2489,6 @@ class CoreArchitecture(Architecture):
False
>>>
"""
- data = str(data)
buf = (ctypes.c_ubyte * len(data))()
ctypes.memmove(buf, data, len(data))
return core.BNIsArchitectureInvertBranchPatchAvailable(self.handle, buf, addr, len(data))
@@ -2507,7 +2512,6 @@ class CoreArchitecture(Architecture):
False
>>>
"""
- data = str(data)
buf = (ctypes.c_ubyte * len(data))()
ctypes.memmove(buf, data, len(data))
return core.BNIsArchitectureSkipAndReturnZeroPatchAvailable(self.handle, buf, addr, len(data))
@@ -2529,7 +2533,6 @@ class CoreArchitecture(Architecture):
False
>>>
"""
- data = str(data)
buf = (ctypes.c_ubyte * len(data))()
ctypes.memmove(buf, data, len(data))
return core.BNIsArchitectureSkipAndReturnValuePatchAvailable(self.handle, buf, addr, len(data))
@@ -2549,7 +2552,6 @@ class CoreArchitecture(Architecture):
'\\x90\\x90'
>>>
"""
- data = str(data)
buf = (ctypes.c_ubyte * len(data))()
ctypes.memmove(buf, data, len(data))
if not core.BNArchitectureConvertToNop(self.handle, buf, addr, len(data)):
@@ -2576,7 +2578,6 @@ class CoreArchitecture(Architecture):
(['jmp ', '0x9'], 5L)
>>>
"""
- data = str(data)
buf = (ctypes.c_ubyte * len(data))()
ctypes.memmove(buf, data, len(data))
if not core.BNArchitectureAlwaysBranch(self.handle, buf, addr, len(data)):
@@ -2604,7 +2605,6 @@ class CoreArchitecture(Architecture):
(['jl ', '0xa'], 6L)
>>>
"""
- data = str(data)
buf = (ctypes.c_ubyte * len(data))()
ctypes.memmove(buf, data, len(data))
if not core.BNArchitectureInvertBranch(self.handle, buf, addr, len(data)):
@@ -2628,7 +2628,6 @@ class CoreArchitecture(Architecture):
(['mov ', 'eax', ', ', '0x0'], 5L)
>>>
"""
- data = str(data)
buf = (ctypes.c_ubyte * len(data))()
ctypes.memmove(buf, data, len(data))
if not core.BNArchitectureSkipAndReturnValue(self.handle, buf, addr, len(data), value):
@@ -2655,7 +2654,7 @@ class CoreArchitecture(Architecture):
count = ctypes.c_ulonglong()
flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, sem_class, count)
flag_names = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
flag_names.append(self._flags_by_index[flags[i]])
core.BNFreeRegisterList(flags)
return flag_names
diff --git a/python/basicblock.py b/python/basicblock.py
index 3f615bba..353771d9 100644
--- a/python/basicblock.py
+++ b/python/basicblock.py
@@ -21,11 +21,13 @@
import ctypes
# Binary Ninja components
-import _binaryninjacore as core
-from enums import BranchType, HighlightColorStyle, HighlightStandardColor, InstructionTextTokenType
-import architecture
-import highlight
-import function
+import binaryninja
+from binaryninja import highlight
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import BranchType, HighlightColorStyle, HighlightStandardColor, InstructionTextTokenType
+
+# 2-3 compatibility
+from binaryninja import range
class BasicBlockEdge(object):
@@ -87,7 +89,7 @@ class BasicBlock(object):
func = core.BNGetBasicBlockFunction(self.handle)
if func is None:
return None
- self._func = function.Function(self.view, func)
+ self._func =binaryninja.function.Function(self.view, func)
return self._func
@property
@@ -100,7 +102,7 @@ class BasicBlock(object):
arch = core.BNGetBasicBlockArchitecture(self.handle)
if arch is None:
return None
- self._arch = architecture.CoreArchitecture._from_cache(arch)
+ self._arch = binaryninja.architecture.CoreArchitecture._from_cache(arch)
return self._arch
@property
@@ -129,7 +131,7 @@ class BasicBlock(object):
count = ctypes.c_ulonglong(0)
edges = core.BNGetBasicBlockOutgoingEdges(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
branch_type = BranchType(edges[i].type)
if edges[i].target:
target = self._create_instance(self.view, core.BNNewBasicBlockReference(edges[i].target))
@@ -145,7 +147,7 @@ class BasicBlock(object):
count = ctypes.c_ulonglong(0)
edges = core.BNGetBasicBlockIncomingEdges(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
branch_type = BranchType(edges[i].type)
if edges[i].target:
target = self._create_instance(self.view, core.BNNewBasicBlockReference(edges[i].target))
@@ -171,7 +173,7 @@ class BasicBlock(object):
count = ctypes.c_ulonglong()
blocks = core.BNGetBasicBlockDominators(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(self._create_instance(self.view, core.BNNewBasicBlockReference(blocks[i])))
core.BNFreeBasicBlockList(blocks, count.value)
return result
@@ -182,7 +184,7 @@ class BasicBlock(object):
count = ctypes.c_ulonglong()
blocks = core.BNGetBasicBlockStrictDominators(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(self._create_instance(self.view, core.BNNewBasicBlockReference(blocks[i])))
core.BNFreeBasicBlockList(blocks, count.value)
return result
@@ -201,7 +203,7 @@ class BasicBlock(object):
count = ctypes.c_ulonglong()
blocks = core.BNGetBasicBlockDominatorTreeChildren(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(self._create_instance(self.view, core.BNNewBasicBlockReference(blocks[i])))
core.BNFreeBasicBlockList(blocks, count.value)
return result
@@ -212,7 +214,7 @@ class BasicBlock(object):
count = ctypes.c_ulonglong()
blocks = core.BNGetBasicBlockDominanceFrontier(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(self._create_instance(self.view, core.BNNewBasicBlockReference(blocks[i])))
core.BNFreeBasicBlockList(blocks, count.value)
return result
@@ -225,7 +227,7 @@ class BasicBlock(object):
@property
def disassembly_text(self):
"""
- ``disassembly_text`` property which returns a list of function.DisassemblyTextLine objects for the current basic block.
+ ``disassembly_text`` property which returns a list of binaryninja.function.DisassemblyTextLine objects for the current basic block.
:Example:
>>> current_basic_block.disassembly_text
@@ -269,12 +271,12 @@ class BasicBlock(object):
if len(blocks) == 0:
return []
block_set = (ctypes.POINTER(core.BNBasicBlock) * len(blocks))()
- for i in xrange(len(blocks)):
+ for i in range(len(blocks)):
block_set[i] = blocks[i].handle
count = ctypes.c_ulonglong()
out_blocks = core.BNGetBasicBlockIteratedDominanceFrontier(block_set, len(blocks), count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(BasicBlock(blocks[0].view, core.BNNewBasicBlockReference(out_blocks[i])))
core.BNFreeBasicBlockList(out_blocks, count.value)
return result
@@ -305,6 +307,8 @@ class BasicBlock(object):
inst_info = self.arch.get_instruction_info(data, idx)
inst_text = self.arch.get_instruction_text(data, idx)
+ if inst_info is None:
+ break
yield inst_text
idx += inst_info.length
@@ -313,7 +317,7 @@ class BasicBlock(object):
def get_disassembly_text(self, settings=None):
"""
- ``get_disassembly_text`` returns a list of function.DisassemblyTextLine objects for the current basic block.
+ ``get_disassembly_text`` returns a list of binaryninja.function.DisassemblyTextLine objects for the current basic block.
:param DisassemblySettings settings: (optional) DisassemblySettings object
:Example:
@@ -328,7 +332,7 @@ class BasicBlock(object):
count = ctypes.c_ulonglong()
lines = core.BNGetBasicBlockDisassemblyText(self.handle, settings_obj, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
addr = lines[i].addr
if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(self, 'il_function'):
il_instr = self.il_function[lines[i].instrIndex]
@@ -336,7 +340,7 @@ class BasicBlock(object):
il_instr = None
color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
tokens = []
- for j in xrange(0, lines[i].count):
+ for j in range(0, lines[i].count):
token_type = InstructionTextTokenType(lines[i].tokens[j].type)
text = lines[i].tokens[j].text
value = lines[i].tokens[j].value
@@ -345,8 +349,8 @@ class BasicBlock(object):
context = lines[i].tokens[j].context
confidence = lines[i].tokens[j].confidence
address = lines[i].tokens[j].address
- tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
- result.append(function.DisassemblyTextLine(tokens, addr, il_instr, color))
+ tokens.append(binaryninja.function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
+ result.append(binaryninja.function.DisassemblyTextLine(tokens, addr, il_instr, color))
core.BNFreeDisassemblyTextLines(lines, count.value)
return result
diff --git a/python/binaryview.py b/python/binaryview.py
index ede279ad..d84ed0aa 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -22,26 +22,25 @@ import struct
import traceback
import ctypes
import abc
-import threading
# Binary Ninja components
-import _binaryninjacore as core
-from enums import (AnalysisState, SymbolType, InstructionTextTokenType,
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import (AnalysisState, SymbolType, InstructionTextTokenType,
Endianness, ModificationStatus, StringType, SegmentFlag, SectionSemantics)
-import function
-import startup
-import architecture
-import platform
-import associateddatastore
-import fileaccessor
-import filemetadata
-import log
-import databuffer
-import basicblock
-import types
-import lineardisassembly
-import metadata
-import highlight
+import binaryninja
+from binaryninja import associateddatastore # required for _BinaryViewAssociatedDataStore
+from binaryninja import log
+from binaryninja import types
+from binaryninja import fileaccessor
+from binaryninja import databuffer
+from binaryninja import basicblock
+from binaryninja import lineardisassembly
+from binaryninja import metadata
+from binaryninja import highlight
+
+# 2-3 compatibility
+from binaryninja import range
+from binaryninja import with_metaclass
class BinaryDataNotification(object):
@@ -100,21 +99,23 @@ class StringReference(object):
@property
def value(self):
- return self.view.read(self.start, self.length)
+ return binaryninja.pyNativeStr(self.view.read(self.start, self.length))
def __repr__(self):
return "<%s: %#x, len %#x>" % (self.type, self.start, self.length)
+_pending_analysis_completion_events = {}
class AnalysisCompletionEvent(object):
"""
The ``AnalysisCompletionEvent`` object provides an asynchronous mechanism for receiving
callbacks when analysis is complete. The callback runs once. A completion event must be added
- for each new analysis in order to be notified of each analysis completion.
+ for each new analysis in order to be notified of each analysis completion. The
+ AnalysisCompletionEvent class takes responcibility for keeping track of the object's lifetime.
:Example:
>>> def on_complete(self):
- ... print "Analysis Complete", self.view
+ ... print("Analysis Complete", self.view)
...
>>> evt = AnalysisCompletionEvent(bv, on_complete)
>>>
@@ -124,11 +125,19 @@ class AnalysisCompletionEvent(object):
self.callback = callback
self._cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(self._notify)
self.handle = core.BNAddAnalysisCompletionEvent(self.view.handle, None, self._cb)
+ global _pending_analysis_completion_events
+ _pending_analysis_completion_events[id(self)] = self
def __del__(self):
+ global _pending_analysis_completion_events
+ if id(self) in _pending_analysis_completion_events:
+ del _pending_analysis_completion_events[id(self)]
core.BNFreeAnalysisCompletionEvent(self.handle)
def _notify(self, ctxt):
+ global _pending_analysis_completion_events
+ if id(self) in _pending_analysis_completion_events:
+ del _pending_analysis_completion_events[id(self)]
try:
self.callback(self)
except:
@@ -144,6 +153,30 @@ class AnalysisCompletionEvent(object):
"""
self.callback = self._empty_callback
core.BNCancelAnalysisCompletionEvent(self.handle)
+ global _pending_analysis_completion_events
+ if id(self) in _pending_analysis_completion_events:
+ del _pending_analysis_completion_events[id(self)]
+
+
+class ActiveAnalysisInfo(object):
+ def __init__(self, func, analysis_time, update_count, submit_count):
+ self.func = func
+ self.analysis_time = analysis_time
+ self.update_count = update_count
+ self.submit_count = submit_count
+
+ def __repr__(self):
+ return "<ActiveAnalysisInfo %s, analysis_time %d, update_count %d, submit_count %d>" % (self.func, self.analysis_time, self.update_count, self.submit_count)
+
+
+class AnalysisInfo(object):
+ def __init__(self, state, analysis_time, active_info):
+ self.state = AnalysisState(state)
+ self.analysis_time = analysis_time
+ self.active_info = active_info
+
+ def __repr__(self):
+ return "<AnalysisInfo %s, analysis_time %d, active_info %s>" % (self.state, self.analysis_time, self.active_info)
class AnalysisProgress(object):
@@ -157,6 +190,8 @@ class AnalysisProgress(object):
return "Disassembling (%d/%d)" % (self.count, self.total)
if self.state == AnalysisState.AnalyzeState:
return "Analyzing (%d/%d)" % (self.count, self.total)
+ if self.state == AnalysisState.ExtendedAnalyzeState:
+ return "Extended Analysis"
return "Idle"
def __repr__(self):
@@ -220,25 +255,25 @@ class BinaryDataNotificationCallbacks(object):
def _function_added(self, ctxt, view, func):
try:
- self.notify.function_added(self.view, function.Function(self.view, core.BNNewFunctionReference(func)))
+ self.notify.function_added(self.view, binaryninja.function.Function(self.view, core.BNNewFunctionReference(func)))
except:
log.log_error(traceback.format_exc())
def _function_removed(self, ctxt, view, func):
try:
- self.notify.function_removed(self.view, function.Function(self.view, core.BNNewFunctionReference(func)))
+ self.notify.function_removed(self.view, binaryninja.function.Function(self.view, core.BNNewFunctionReference(func)))
except:
log.log_error(traceback.format_exc())
def _function_updated(self, ctxt, view, func):
try:
- self.notify.function_updated(self.view, function.Function(self.view, core.BNNewFunctionReference(func)))
+ self.notify.function_updated(self.view, binaryninja.function.Function(self.view, core.BNNewFunctionReference(func)))
except:
log.log_error(traceback.format_exc())
def _function_update_requested(self, ctxt, view, func):
try:
- self.notify.function_update_requested(self.view, function.Function(self.view, core.BNNewFunctionReference(func)))
+ self.notify.function_update_requested(self.view, binaryninja.function.Function(self.view, core.BNNewFunctionReference(func)))
except:
log.log_error(traceback.format_exc())
@@ -297,38 +332,38 @@ class BinaryDataNotificationCallbacks(object):
class _BinaryViewTypeMetaclass(type):
+
@property
def list(self):
"""List all BinaryView types (read-only)"""
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
types = core.BNGetBinaryViewTypes(count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(BinaryViewType(types[i]))
core.BNFreeBinaryViewTypeList(types)
return result
def __iter__(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
types = core.BNGetBinaryViewTypes(count)
try:
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
yield BinaryViewType(types[i])
finally:
core.BNFreeBinaryViewTypeList(types)
def __getitem__(self, value):
- startup._init_plugins()
+ binaryninja._init_plugins()
view_type = core.BNGetBinaryViewTypeByName(str(value))
if view_type is None:
raise KeyError("'%s' is not a valid view type" % str(value))
return BinaryViewType(view_type)
-class BinaryViewType(object):
- __metaclass__ = _BinaryViewTypeMetaclass
+class BinaryViewType(with_metaclass(_BinaryViewTypeMetaclass, object)):
def __init__(self, handle):
self.handle = core.handle_of_type(handle, core.BNBinaryViewType)
@@ -344,6 +379,11 @@ class BinaryViewType(object):
return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
@property
+ def list(self):
+ """Allow tab completion to discover metaclass list property"""
+ pass
+
+ @property
def name(self):
"""BinaryView name (read-only)"""
return core.BNGetBinaryViewTypeName(self.handle)
@@ -384,7 +424,7 @@ class BinaryViewType(object):
if f is None or f.read(len(sqlite)) != sqlite:
return None
f.close()
- view = filemetadata.FileMetadata().open_existing_database(filename)
+ view = binaryninja.filemetadata.FileMetadata().open_existing_database(filename)
else:
view = BinaryView.open(filename)
@@ -397,6 +437,9 @@ class BinaryViewType(object):
else:
bv = cls[available.name].open(filename)
+ if bv is None:
+ raise Exception("Unknown Architecture/Architecture Not Found (check plugins folder)")
+
if update_analysis:
bv.update_analysis_and_wait()
return bv
@@ -412,7 +455,7 @@ class BinaryViewType(object):
arch = core.BNGetArchitectureForViewType(self.handle, ident, endian)
if arch is None:
return None
- return architecture.CoreArchitecture._from_cache(arch)
+ return binaryninja.architecture.CoreArchitecture._from_cache(arch)
def register_platform(self, ident, arch, plat):
core.BNRegisterPlatformForViewType(self.handle, ident, arch.handle, plat.handle)
@@ -424,7 +467,7 @@ class BinaryViewType(object):
plat = core.BNGetPlatformForViewType(self.handle, ident, arch.handle)
if plat is None:
return None
- return platform.Platform(None, plat)
+ return binaryninja.platform.Platform(None, plat)
class Segment(object):
@@ -566,17 +609,17 @@ class BinaryView(object):
if handle is not None:
self.handle = core.handle_of_type(handle, core.BNBinaryView)
if file_metadata is None:
- self.file = filemetadata.FileMetadata(handle=core.BNGetFileForView(handle))
+ self.file = binaryninja.filemetadata.FileMetadata(handle=core.BNGetFileForView(handle))
else:
self.file = file_metadata
elif self.__class__ is BinaryView:
- startup._init_plugins()
+ binaryninja._init_plugins()
if file_metadata is None:
- file_metadata = filemetadata.FileMetadata()
+ file_metadata = binaryninja.filemetadata.FileMetadata()
self.handle = core.BNCreateBinaryDataView(file_metadata.handle)
- self.file = filemetadata.FileMetadata(handle=core.BNNewFileReference(file_metadata.handle))
+ self.file = binaryninja.filemetadata.FileMetadata(handle=core.BNNewFileReference(file_metadata.handle))
else:
- startup._init_plugins()
+ binaryninja._init_plugins()
if not self.__class__._registered:
raise TypeError("view type not registered")
self._cb = core.BNCustomBinaryView()
@@ -619,7 +662,7 @@ class BinaryView(object):
@classmethod
def register(cls):
- startup._init_plugins()
+ binaryninja._init_plugins()
if cls.name is None:
raise ValueError("view 'name' not defined")
if cls.long_name is None:
@@ -634,7 +677,7 @@ class BinaryView(object):
@classmethod
def _create(cls, ctxt, data):
try:
- file_metadata = filemetadata.FileMetadata(handle=core.BNGetFileForView(data))
+ file_metadata = binaryninja.filemetadata.FileMetadata(handle=core.BNGetFileForView(data))
view = cls(BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(data)))
if view is None:
return None
@@ -653,14 +696,14 @@ class BinaryView(object):
@classmethod
def open(cls, src, file_metadata=None):
- startup._init_plugins()
+ binaryninja._init_plugins()
if isinstance(src, fileaccessor.FileAccessor):
if file_metadata is None:
- file_metadata = filemetadata.FileMetadata()
+ file_metadata = binaryninja.filemetadata.FileMetadata()
view = core.BNCreateBinaryDataViewFromFile(file_metadata.handle, src._cb)
else:
if file_metadata is None:
- file_metadata = filemetadata.FileMetadata(str(src))
+ file_metadata = binaryninja.filemetadata.FileMetadata(str(src))
view = core.BNCreateBinaryDataViewFromFilename(file_metadata.handle, str(src))
if view is None:
return None
@@ -669,9 +712,9 @@ class BinaryView(object):
@classmethod
def new(cls, data=None, file_metadata=None):
- startup._init_plugins()
+ binaryninja._init_plugins()
if file_metadata is None:
- file_metadata = filemetadata.FileMetadata()
+ file_metadata = binaryninja.filemetadata.FileMetadata()
if data is None:
view = core.BNCreateBinaryDataView(file_metadata.handle)
else:
@@ -755,8 +798,8 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
funcs = core.BNGetAnalysisFunctionList(self.handle, count)
try:
- for i in xrange(0, count.value):
- yield function.Function(self, core.BNNewFunctionReference(funcs[i]))
+ for i in range(0, count.value):
+ yield binaryninja.function.Function(self, core.BNNewFunctionReference(funcs[i]))
finally:
core.BNFreeFunctionList(funcs, count.value)
@@ -824,7 +867,7 @@ class BinaryView(object):
arch = core.BNGetDefaultArchitecture(self.handle)
if arch is None:
return None
- return architecture.CoreArchitecture._from_cache(handle=arch)
+ return binaryninja.architecture.CoreArchitecture._from_cache(handle=arch)
@arch.setter
def arch(self, value):
@@ -839,7 +882,7 @@ class BinaryView(object):
plat = core.BNGetDefaultPlatform(self.handle)
if plat is None:
return None
- return platform.Platform(self.arch, handle=plat)
+ return binaryninja.platform.Platform(self.arch, handle=plat)
@platform.setter
def platform(self, value):
@@ -874,8 +917,8 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
funcs = core.BNGetAnalysisFunctionList(self.handle, count)
result = []
- for i in xrange(0, count.value):
- result.append(function.Function(self, core.BNNewFunctionReference(funcs[i])))
+ for i in range(0, count.value):
+ result.append(binaryninja.function.Function(self, core.BNNewFunctionReference(funcs[i])))
core.BNFreeFunctionList(funcs, count.value)
return result
@@ -890,7 +933,7 @@ class BinaryView(object):
func = core.BNGetAnalysisEntryPoint(self.handle)
if func is None:
return None
- return function.Function(self, func)
+ return binaryninja.function.Function(self, func)
@property
def symbols(self):
@@ -898,7 +941,7 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
syms = core.BNGetSymbols(self.handle, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
sym = types.Symbol(None, None, None, handle=core.BNNewSymbolReference(syms[i]))
result[sym.raw_name] = sym
core.BNFreeSymbolList(syms, count.value)
@@ -915,7 +958,7 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
types = core.BNGetBinaryViewTypesForData(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(BinaryViewType(types[i]))
core.BNFreeBinaryViewTypeList(types)
return result
@@ -935,6 +978,20 @@ class BinaryView(object):
self.file.saved = value
@property
+ def analysis_info(self):
+ """Relevant analysis information with list of functions under active analysis (read-only)"""
+ info_ref = core.BNGetAnalysisInfo(self.handle)
+ info = info_ref[0]
+ active_info_list = []
+ for i in xrange(0, info.count):
+ func = binaryninja.function.Function(self, core.BNNewFunctionReference(info.activeInfo[i].func))
+ active_info = ActiveAnalysisInfo(func, info.activeInfo[i].analysisTime, info.activeInfo[i].updateCount, info.activeInfo[i].submitCount)
+ active_info_list.append(active_info)
+ result = AnalysisInfo(info.state, info.analysisTime, active_info_list)
+ core.BNFreeAnalysisInfo(info_ref)
+ return result
+
+ @property
def analysis_progress(self):
"""Status of current analysis (read-only)"""
result = core.BNGetAnalysisProgress(self.handle)
@@ -951,7 +1008,7 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
var_list = core.BNGetDataVariables(self.handle, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
addr = var_list[i].address
var_type = types.Type(core.BNNewTypeReference(var_list[i].type), platform = self.platform, confidence = var_list[i].typeConfidence)
auto_discovered = var_list[i].autoDiscovered
@@ -965,7 +1022,7 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
type_list = core.BNGetAnalysisTypeList(self.handle, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
name = types.QualifiedName._from_core_struct(type_list[i].name)
result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self.platform)
core.BNFreeTypeList(type_list, count.value)
@@ -977,7 +1034,7 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
segment_list = core.BNGetSegments(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(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].autoDefined))
core.BNFreeSegmentList(segment_list)
@@ -989,7 +1046,7 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
section_list = core.BNGetSections(self.handle, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
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,
@@ -1003,7 +1060,7 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
range_list = core.BNGetAllocatedRanges(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(AddressRange(range_list[i].start, range_list[i].end))
core.BNFreeAddressRanges(range_list)
return result
@@ -1023,7 +1080,15 @@ class BinaryView(object):
def global_pointer_value(self):
"""Discovered value of the global pointer register, if the binary uses one (read-only)"""
result = core.BNGetGlobalPointerValue(self.handle)
- return function.RegisterValue(self.arch, result.value, confidence = result.confidence)
+ return binaryninja.function.RegisterValue(self.arch, result.value, confidence = result.confidence)
+
+ @property
+ def parameters_for_analysis(self):
+ return core.BNGetParametersForAnalysis(self.handle)
+
+ @parameters_for_analysis.setter
+ def parameters_for_analysis(self, params):
+ core.BNSetParametersForAnalysis(self.handle, params)
@property
def max_function_size_for_analysis(self):
@@ -1680,10 +1745,13 @@ class BinaryView(object):
"""
``read`` returns the data reads at most ``length`` bytes from virtual address ``addr``.
+ Note: Python2 returns a str, but Python3 returns a bytes object. str(DataBufferObject) will
+ still get you a str in either case.
+
:param int addr: virtual address to read from.
:param int length: number of bytes to read.
:return: at most ``length`` bytes from the virtual address ``addr``, empty string on error or no data.
- :rtype: str
+ :rtype: python2 - str; python3 - bytes
:Example:
>>> #Opening a x86_64 Mach-O binary
@@ -1692,7 +1760,7 @@ class BinaryView(object):
\'\\xcf\\xfa\\xed\\xfe\'
"""
buf = databuffer.DataBuffer(handle=core.BNReadViewBuffer(self.handle, addr, length))
- return str(buf)
+ return bytes(buf)
def write(self, addr, data):
"""
@@ -1711,6 +1779,8 @@ class BinaryView(object):
>>> bv.read(0,4)
'AAAA'
"""
+ if not isinstance(data, bytes):
+ raise TypeError("Must be bytes")
buf = databuffer.DataBuffer(data)
return core.BNWriteViewBuffer(self.handle, addr, buf.handle)
@@ -1729,6 +1799,8 @@ class BinaryView(object):
>>> bv.read(0,8)
'BBBBAAAA'
"""
+ if not isinstance(data, bytes):
+ raise TypeError("Must be bytes")
buf = databuffer.DataBuffer(data)
return core.BNInsertViewBuffer(self.handle, addr, buf.handle)
@@ -2121,7 +2193,7 @@ class BinaryView(object):
func = core.BNGetAnalysisFunction(self.handle, plat.handle, addr)
if func is None:
return None
- return function.Function(self, func)
+ return binaryninja.function.Function(self, func)
def get_functions_at(self, addr):
"""
@@ -2137,8 +2209,8 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
funcs = core.BNGetAnalysisFunctionsForAddress(self.handle, addr, count)
result = []
- for i in xrange(0, count.value):
- result.append(function.Function(self, core.BNNewFunctionReference(funcs[i])))
+ for i in range(0, count.value):
+ result.append(binaryninja.function.Function(self, core.BNNewFunctionReference(funcs[i])))
core.BNFreeFunctionList(funcs, count.value)
return result
@@ -2146,7 +2218,7 @@ class BinaryView(object):
func = core.BNGetRecentAnalysisFunctionForAddress(self.handle, addr)
if func is None:
return None
- return function.Function(self, func)
+ return binaryninja.function.Function(self, func)
def get_basic_blocks_at(self, addr):
"""
@@ -2159,7 +2231,7 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
blocks = core.BNGetBasicBlocksForAddress(self.handle, addr, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(basicblock.BasicBlock(self, core.BNNewBasicBlockReference(blocks[i])))
core.BNFreeBasicBlockList(blocks, count.value)
return result
@@ -2175,7 +2247,7 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
blocks = core.BNGetBasicBlocksStartingAtAddress(self.handle, addr, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(basicblock.BasicBlock(self, core.BNNewBasicBlockReference(blocks[i])))
core.BNFreeBasicBlockList(blocks, count.value)
return result
@@ -2206,17 +2278,17 @@ class BinaryView(object):
else:
refs = core.BNGetCodeReferencesInRange(self.handle, addr, length, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
if refs[i].func:
- func = function.Function(self, core.BNNewFunctionReference(refs[i].func))
+ func = binaryninja.function.Function(self, core.BNNewFunctionReference(refs[i].func))
else:
func = None
if refs[i].arch:
- arch = architecture.CoreArchitecture._from_cache(refs[i].arch)
+ arch = binaryninja.architecture.CoreArchitecture._from_cache(refs[i].arch)
else:
arch = None
addr = refs[i].addr
- result.append(architecture.ReferenceSource(func, arch, addr))
+ result.append(binaryninja.architecture.ReferenceSource(func, arch, addr))
core.BNFreeCodeReferences(refs, count.value)
return result
@@ -2272,7 +2344,7 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
syms = core.BNGetSymbolsByName(self.handle, name, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(types.Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i])))
core.BNFreeSymbolList(syms, count.value)
return result
@@ -2297,7 +2369,7 @@ class BinaryView(object):
else:
syms = core.BNGetSymbolsInRange(self.handle, start, length, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(types.Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i])))
core.BNFreeSymbolList(syms, count.value)
return result
@@ -2326,7 +2398,7 @@ class BinaryView(object):
else:
syms = core.BNGetSymbolsOfTypeInRange(self.handle, sym_type, start, length, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(types.Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i])))
core.BNFreeSymbolList(syms, count.value)
return result
@@ -2721,9 +2793,11 @@ class BinaryView(object):
if start is None:
strings = core.BNGetStrings(self.handle, count)
else:
+ if length is None:
+ length = self.end - start
strings = core.BNGetStringsInRange(self.handle, start, length, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(StringReference(self, StringType(strings[i].type), strings[i].start, strings[i].length))
core.BNFreeStringReferenceList(strings)
return result
@@ -2731,7 +2805,9 @@ class BinaryView(object):
def add_analysis_completion_event(self, callback):
"""
``add_analysis_completion_event`` sets up a call back function to be called when analysis has been completed.
- This is helpful when using asynchronously analysis.
+ This is helpful when using ``update_analysis`` which does not wait for analysis completion before returning.
+
+ The callee of this function is not resposible for maintaining the lifetime of the returned AnalysisCompletionEvent object.
:param callable() callback: A function to be called with no parameters when analysis has completed.
:return: An initialized AnalysisCompletionEvent object.
@@ -2739,7 +2815,7 @@ class BinaryView(object):
:Example:
>>> def completionEvent():
- ... print "done"
+ ... print("done")
...
>>> bv.add_analysis_completion_event(completionEvent)
<binaryninja.AnalysisCompletionEvent object at 0x10a2c9f10>
@@ -2933,7 +3009,7 @@ class BinaryView(object):
func = None
block = None
if pos.function:
- func = function.Function(self, pos.function)
+ func = binaryninja.function.Function(self, pos.function)
if pos.block:
block = basicblock.BasicBlock(self, pos.block)
return lineardisassembly.LinearDisassemblyPosition(func, block, pos.address)
@@ -2955,17 +3031,17 @@ class BinaryView(object):
lines = api(self.handle, pos_obj, settings, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
func = None
block = None
if lines[i].function:
- func = function.Function(self, core.BNNewFunctionReference(lines[i].function))
+ func = binaryninja.function.Function(self, core.BNNewFunctionReference(lines[i].function))
if lines[i].block:
block = basicblock.BasicBlock(self, core.BNNewBasicBlockReference(lines[i].block))
color = highlight.HighlightColor._from_core_struct(lines[i].contents.highlight)
addr = lines[i].contents.addr
tokens = []
- for j in xrange(0, lines[i].contents.count):
+ for j in range(0, lines[i].contents.count):
token_type = InstructionTextTokenType(lines[i].contents.tokens[j].type)
text = lines[i].contents.tokens[j].text
value = lines[i].contents.tokens[j].value
@@ -2974,14 +3050,14 @@ class BinaryView(object):
context = lines[i].contents.tokens[j].context
confidence = lines[i].contents.tokens[j].confidence
address = lines[i].contents.tokens[j].address
- tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
- contents = function.DisassemblyTextLine(tokens, addr, color = color)
+ tokens.append(binaryninja.function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
+ contents = binaryninja.function.DisassemblyTextLine(tokens, addr, color = color)
result.append(lineardisassembly.LinearDisassemblyLine(lines[i].type, func, block, lines[i].lineOffset, contents))
func = None
block = None
if pos_obj.function:
- func = function.Function(self, pos_obj.function)
+ func = binaryninja.function.Function(self, pos_obj.function)
if pos_obj.block:
block = basicblock.BasicBlock(self, pos_obj.block)
pos.function = func
@@ -3048,7 +3124,7 @@ class BinaryView(object):
>>> settings = DisassemblySettings()
>>> lines = bv.get_linear_disassembly(settings)
>>> for line in lines:
- ... print line
+ ... print(line)
... break
...
cf fa ed fe 07 00 00 01 ........
@@ -3411,7 +3487,7 @@ class BinaryView(object):
count = ctypes.c_ulonglong(0)
section_list = core.BNGetSectionsAt(self.handle, addr, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
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,
@@ -3431,11 +3507,11 @@ class BinaryView(object):
def get_unique_section_names(self, name_list):
incoming_names = (ctypes.c_char_p * len(name_list))()
- for i in xrange(0, len(name_list)):
- incoming_names[i] = name_list[i]
+ for i in range(0, len(name_list)):
+ incoming_names[i] = binaryninja.cstr(name_list[i])
outgoing_names = core.BNGetUniqueSectionNames(self.handle, incoming_names, len(name_list))
result = []
- for i in xrange(0, len(name_list)):
+ for i in range(0, len(name_list)):
result.append(str(outgoing_names[i]))
core.BNFreeStringList(outgoing_names, len(name_list))
return result
diff --git a/python/callingconvention.py b/python/callingconvention.py
index e3ec7261..6b906184 100644
--- a/python/callingconvention.py
+++ b/python/callingconvention.py
@@ -22,13 +22,13 @@ import traceback
import ctypes
# Binary Ninja components
-import _binaryninjacore as core
-import architecture
-import log
-import types
-import function
-import binaryview
-from enums import VariableSourceType
+import binaryninja
+from binaryninja import _binaryninjacore as core
+from binaryninja import log
+from binaryninja.enums import VariableSourceType
+
+# 2-3 compatibility
+from binaryninja import range
class CallingConvention(object):
@@ -47,7 +47,7 @@ class CallingConvention(object):
_registered_calling_conventions = []
- def __init__(self, arch=None, name=None, handle=None, confidence=types.max_confidence):
+ def __init__(self, arch=None, name=None, handle=None, confidence=binaryninja.types.max_confidence):
if handle is None:
if arch is None or name is None:
raise ValueError("Must specify either handle or architecture and name")
@@ -75,7 +75,7 @@ class CallingConvention(object):
self.__class__._registered_calling_conventions.append(self)
else:
self.handle = handle
- self.arch = architecture.CoreArchitecture._from_cache(core.BNGetCallingConventionArchitecture(self.handle))
+ self.arch = binaryninja.architecture.CoreArchitecture._from_cache(core.BNGetCallingConventionArchitecture(self.handle))
self.__dict__["name"] = core.BNGetCallingConventionName(self.handle)
self.__dict__["arg_regs_share_index"] = core.BNAreArgumentRegistersSharedIndex(self.handle)
self.__dict__["stack_reserved_for_arg_regs"] = core.BNIsStackReservedForArgumentRegisters(self.handle)
@@ -85,7 +85,7 @@ class CallingConvention(object):
regs = core.BNGetCallerSavedRegisters(self.handle, count)
result = []
arch = self.arch
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(arch.get_reg_name(regs[i]))
core.BNFreeRegisterList(regs, count.value)
self.__dict__["caller_saved_regs"] = result
@@ -94,7 +94,7 @@ class CallingConvention(object):
regs = core.BNGetIntegerArgumentRegisters(self.handle, count)
result = []
arch = self.arch
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(arch.get_reg_name(regs[i]))
core.BNFreeRegisterList(regs, count.value)
self.__dict__["int_arg_regs"] = result
@@ -103,7 +103,7 @@ class CallingConvention(object):
regs = core.BNGetFloatArgumentRegisters(self.handle, count)
result = []
arch = self.arch
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(arch.get_reg_name(regs[i]))
core.BNFreeRegisterList(regs, count.value)
self.__dict__["float_arg_regs"] = result
@@ -136,7 +136,7 @@ class CallingConvention(object):
regs = core.BNGetImplicitlyDefinedRegisters(self.handle, count)
result = []
arch = self.arch
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(arch.get_reg_name(regs[i]))
core.BNFreeRegisterList(regs, count.value)
self.__dict__["implicitly_defined_regs"] = result
@@ -161,7 +161,7 @@ class CallingConvention(object):
regs = self.__class__.caller_saved_regs
count[0] = len(regs)
reg_buf = (ctypes.c_uint * len(regs))()
- for i in xrange(0, len(regs)):
+ for i in range(0, len(regs)):
reg_buf[i] = self.arch.regs[regs[i]].index
result = ctypes.cast(reg_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, reg_buf)
@@ -176,7 +176,7 @@ class CallingConvention(object):
regs = self.__class__.int_arg_regs
count[0] = len(regs)
reg_buf = (ctypes.c_uint * len(regs))()
- for i in xrange(0, len(regs)):
+ for i in range(0, len(regs)):
reg_buf[i] = self.arch.regs[regs[i]].index
result = ctypes.cast(reg_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, reg_buf)
@@ -191,7 +191,7 @@ class CallingConvention(object):
regs = self.__class__.float_arg_regs
count[0] = len(regs)
reg_buf = (ctypes.c_uint * len(regs))()
- for i in xrange(0, len(regs)):
+ for i in range(0, len(regs)):
reg_buf[i] = self.arch.regs[regs[i]].index
result = ctypes.cast(reg_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, reg_buf)
@@ -270,7 +270,7 @@ class CallingConvention(object):
regs = self.__class__.implicitly_defined_regs
count[0] = len(regs)
reg_buf = (ctypes.c_uint * len(regs))()
- for i in xrange(0, len(regs)):
+ for i in range(0, len(regs)):
reg_buf[i] = self.arch.regs[regs[i]].index
result = ctypes.cast(reg_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, reg_buf)
@@ -282,25 +282,25 @@ class CallingConvention(object):
def _get_incoming_reg_value(self, ctxt, reg, func, result):
try:
- func_obj = function.Function(binaryview.BinaryView(handle = core.BNGetFunctionData(func)),
+ func_obj = binaryninja.function.Function(binaryninja.binaryview.BinaryView(handle = core.BNGetFunctionData(func)),
core.BNNewFunctionReference(func))
reg_name = self.arch.get_reg_name(reg)
api_obj = self.perform_get_incoming_reg_value(reg_name, func_obj)._to_api_object()
except:
log.log_error(traceback.format_exc())
- api_obj = function.RegisterValue()._to_api_object()
+ api_obj = binaryninja.function.RegisterValue()._to_api_object()
result[0].state = api_obj.state
result[0].value = api_obj.value
def _get_incoming_flag_value(self, ctxt, reg, func, result):
try:
- func_obj = function.Function(binaryview.BinaryView(handle = core.BNGetFunctionData(func)),
+ func_obj = binaryninja.function.Function(binaryninja.binaryview.BinaryView(handle = core.BNGetFunctionData(func)),
core.BNNewFunctionReference(func))
reg_name = self.arch.get_reg_name(reg)
api_obj = self.perform_get_incoming_flag_value(reg_name, func_obj)._to_api_object()
except:
log.log_error(traceback.format_exc())
- api_obj = function.RegisterValue()._to_api_object()
+ api_obj = binaryninja.function.RegisterValue()._to_api_object()
result[0].state = api_obj.state
result[0].value = api_obj.value
@@ -309,9 +309,9 @@ class CallingConvention(object):
if func is None:
func_obj = None
else:
- func_obj = function.Function(binaryview.BinaryView(handle = core.BNGetFunctionData(func)),
+ func_obj = binaryninja.function.Function(binaryninja.binaryview.BinaryView(handle = core.BNGetFunctionData(func)),
core.BNNewFunctionReference(func))
- in_var_obj = function.Variable(func_obj, in_var[0].type, in_var[0].index, in_var[0].storage)
+ in_var_obj = binaryninja.function.Variable(func_obj, in_var[0].type, in_var[0].index, in_var[0].storage)
out_var = self.perform_get_incoming_var_for_parameter_var(in_var_obj, func_obj)
result[0].type = out_var.source_type
result[0].index = out_var.index
@@ -327,9 +327,9 @@ class CallingConvention(object):
if func is None:
func_obj = None
else:
- func_obj = function.Function(binaryview.BinaryView(handle = core.BNGetFunctionData(func)),
+ func_obj = binaryninja.function.Function(binaryninja.binaryview.BinaryView(handle = core.BNGetFunctionData(func)),
core.BNNewFunctionReference(func))
- in_var_obj = function.Variable(func_obj, in_var[0].type, in_var[0].index, in_var[0].storage)
+ in_var_obj = binaryninja.function.Variable(func_obj, in_var[0].type, in_var[0].index, in_var[0].storage)
out_var = self.perform_get_parameter_var_for_incoming_var(in_var_obj, func_obj)
result[0].type = out_var.source_type
result[0].index = out_var.index
@@ -350,11 +350,11 @@ class CallingConvention(object):
reg_stack = self.arch.get_reg_stack_for_reg(reg)
if reg_stack is not None:
if reg == self.arch.reg_stacks[reg_stack].stack_top_reg:
- return function.RegisterValue.constant(0)
- return function.RegisterValue()
+ return binaryninja.function.RegisterValue.constant(0)
+ return binaryninja.function.RegisterValue()
def perform_get_incoming_flag_value(self, reg, func):
- return function.RegisterValue()
+ return binaryninja.function.RegisterValue()
def perform_get_incoming_var_for_parameter_var(self, in_var, func):
in_buf = core.BNVariable()
@@ -365,7 +365,7 @@ class CallingConvention(object):
name = None
if (func is not None) and (out_var.type == VariableSourceType.RegisterVariableSourceType):
name = func.arch.get_reg_name(out_var.storage)
- return function.Variable(func, out_var.type, out_var.index, out_var.storage, name)
+ return binaryninja.function.Variable(func, out_var.type, out_var.index, out_var.storage, name)
def perform_get_parameter_var_for_incoming_var(self, in_var, func):
in_buf = core.BNVariable()
@@ -373,7 +373,7 @@ class CallingConvention(object):
in_buf.index = in_var.index
in_buf.storage = in_var.storage
out_var = core.BNGetDefaultParameterVariableForIncomingVariable(self.handle, in_buf)
- return function.Variable(func, out_var.type, out_var.index, out_var.storage)
+ return binaryninja.function.Variable(func, out_var.type, out_var.index, out_var.storage)
def with_confidence(self, confidence):
return CallingConvention(self.arch, handle = core.BNNewCallingConventionReference(self.handle),
@@ -384,14 +384,14 @@ class CallingConvention(object):
func_handle = None
if func is not None:
func_handle = func.handle
- return function.RegisterValue(self.arch, core.BNGetIncomingRegisterValue(self.handle, reg_num, func_handle))
+ return binaryninja.function.RegisterValue(self.arch, core.BNGetIncomingRegisterValue(self.handle, reg_num, func_handle))
def get_incoming_flag_value(self, flag, func):
reg_num = self.arch.get_flag_index(flag)
func_handle = None
if func is not None:
func_handle = func.handle
- return function.RegisterValue(self.arch, core.BNGetIncomingFlagValue(self.handle, reg_num, func_handle))
+ return binaryninja.function.RegisterValue(self.arch, core.BNGetIncomingFlagValue(self.handle, reg_num, func_handle))
def get_incoming_var_for_parameter_var(self, in_var, func):
in_buf = core.BNVariable()
@@ -406,7 +406,7 @@ class CallingConvention(object):
name = None
if (func is not None) and (out_var.type == VariableSourceType.RegisterVariableSourceType):
name = func.arch.get_reg_name(out_var.storage)
- return function.Variable(func, out_var.type, out_var.index, out_var.storage, name)
+ return binaryninja.function.Variable(func, out_var.type, out_var.index, out_var.storage, name)
def get_parameter_var_for_incoming_var(self, in_var, func):
in_buf = core.BNVariable()
@@ -418,4 +418,4 @@ class CallingConvention(object):
else:
func_obj = func.handle
out_var = core.BNGetParameterVariableForIncomingVariable(self.handle, in_buf, func_obj)
- return function.Variable(func, out_var.type, out_var.index, out_var.storage)
+ return binaryninja.function.Variable(func, out_var.type, out_var.index, out_var.storage)
diff --git a/python/databuffer.py b/python/databuffer.py
index 3f9e4ce5..2fb5382d 100644
--- a/python/databuffer.py
+++ b/python/databuffer.py
@@ -21,11 +21,21 @@
import ctypes
# Binary Ninja components
-import _binaryninjacore as core
+from binaryninja import _binaryninjacore as core
+
+# 2-3 compatibility
+from binaryninja import pyNativeStr
class DataBuffer(object):
def __init__(self, contents="", handle=None):
+
+ # python3 no longer has longs
+ try:
+ long
+ except NameError:
+ long = int
+
if handle is not None:
self.handle = core.handle_of_type(handle, core.BNDataBuffer)
elif isinstance(contents, int) or isinstance(contents, long):
@@ -44,7 +54,7 @@ class DataBuffer(object):
def __getitem__(self, i):
if isinstance(i, tuple):
result = ""
- source = str(self)
+ source = bytes(self)
for s in i:
result += source[s]
return result
@@ -59,7 +69,7 @@ class DataBuffer(object):
ctypes.memmove(buf, core.BNGetDataBufferContentsAt(self.handle, start), stop - start)
return buf.raw
else:
- return str(self)[i]
+ return bytes(self)[i]
elif i < 0:
if i >= -len(self):
return chr(core.BNGetDataBufferByte(self.handle, int(len(self) + i)))
@@ -79,7 +89,7 @@ class DataBuffer(object):
if stop < start:
stop = start
if len(value) != (stop - start):
- data = str(self)
+ data = bytes(self)
data = data[0:start] + value + data[stop:]
core.BNSetDataBufferContents(self.handle, data, len(data))
else:
@@ -107,22 +117,24 @@ class DataBuffer(object):
def __str__(self):
buf = ctypes.create_string_buffer(len(self))
ctypes.memmove(buf, core.BNGetDataBufferContents(self.handle), len(self))
- return buf.raw
+ return pyNativeStr(buf.raw)
- def __repr__(self):
- return repr(str(self))
+ def __bytes__(self):
+ buf = ctypes.create_string_buffer(len(self))
+ ctypes.memmove(buf, core.BNGetDataBufferContents(self.handle), len(self))
+ return buf.raw
def escape(self):
return core.BNDataBufferToEscapedString(self.handle)
def unescape(self):
- return DataBuffer(handle=core.BNDecodeEscapedString(str(self)))
+ return DataBuffer(handle=core.BNDecodeEscapedString(bytes(self)))
def base64_encode(self):
return core.BNDataBufferToBase64(self.handle)
def base64_decode(self):
- return DataBuffer(handle = core.BNDecodeBase64(str(self)))
+ return DataBuffer(handle = core.BNDecodeBase64(bytes(self)))
def zlib_compress(self):
buf = core.BNZlibCompress(self.handle)
diff --git a/python/demangle.py b/python/demangle.py
index 11673263..2fa1028f 100644
--- a/python/demangle.py
+++ b/python/demangle.py
@@ -21,8 +21,12 @@
import ctypes
# Binary Ninja components
-import _binaryninjacore as core
-import types
+from binaryninja import _binaryninjacore as core
+from binaryninja import types
+
+# 2-3 compatibility
+from binaryninja import range
+from binaryninja import pyNativeStr
def get_qualified_name(names):
@@ -61,8 +65,8 @@ def demangle_ms(arch, mangled_name):
outSize = ctypes.c_ulonglong()
names = []
if core.BNDemangleMS(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize)):
- for i in xrange(outSize.value):
- names.append(outName[i])
+ for i in range(outSize.value):
+ names.append(pyNativeStr(outName[i]))
core.BNFreeDemangledName(ctypes.byref(outName), outSize.value)
return (types.Type(handle), names)
return (None, mangled_name)
@@ -74,8 +78,8 @@ def demangle_gnu3(arch, mangled_name):
outSize = ctypes.c_ulonglong()
names = []
if core.BNDemangleGNU3(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize)):
- for i in xrange(outSize.value):
- names.append(outName[i])
+ for i in range(outSize.value):
+ names.append(pyNativeStr(outName[i]))
core.BNFreeDemangledName(ctypes.byref(outName), outSize.value)
if not handle:
return (None, names)
diff --git a/python/downloadprovider.py b/python/downloadprovider.py
new file mode 100644
index 00000000..14368ee7
--- /dev/null
+++ b/python/downloadprovider.py
@@ -0,0 +1,271 @@
+# Copyright (c) 2015-2018 Vector 35 LLC
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+import abc
+import ctypes
+import sys
+import traceback
+
+# Binary Ninja Components
+import binaryninja._binaryninjacore as core
+from binaryninja.setting import Setting
+from binaryninja import with_metaclass
+from binaryninja import startup
+from binaryninja import log
+
+# 2-3 compatibility
+from binaryninja import pyNativeStr
+
+
+class DownloadInstance(object):
+ def __init__(self, provider, handle = None):
+ if handle is None:
+ self._cb = core.BNDownloadInstanceCallbacks()
+ self._cb.context = 0
+ self._cb.destroyInstance = self._cb.destroyInstance.__class__(self._destroy_instance)
+ self._cb.performRequest = self._cb.performRequest.__class__(self._perform_request)
+ self.handle = core.BNInitDownloadInstance(provider.handle, self._cb)
+ else:
+ self.handle = core.handle_of_type(handle, core.BNDownloadInstance)
+ self._outputCallbacks = None
+
+ def __del__(self):
+ core.BNFreeDownloadInstance(self.handle)
+
+ def _destroy_instance(self, ctxt):
+ try:
+ self.perform_destroy_instance()
+ except:
+ log.log_error(traceback.format_exc())
+
+ def _perform_request(self, ctxt, url):
+ try:
+ return self.perform_request(url)
+ except:
+ log.log_error(traceback.format_exc())
+ return -1
+
+ @abc.abstractmethod
+ def perform_destroy_instance(self):
+ raise NotImplementedError
+
+ @abc.abstractmethod
+ def perform_request(self, ctxt, url):
+ raise NotImplementedError
+
+ def perform_request(self, url, callbacks):
+ return core.BNPerformDownloadRequest(self.handle, url, callbacks)
+
+
+class _DownloadProviderMetaclass(type):
+ @property
+ def list(self):
+ """List all DownloadProvider types (read-only)"""
+ startup._init_plugins()
+ count = ctypes.c_ulonglong()
+ types = core.BNGetDownloadProviderList(count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(DownloadProvider(types[i]))
+ core.BNFreeDownloadProviderList(types)
+ return result
+
+ def __iter__(self):
+ startup._init_plugins()
+ count = ctypes.c_ulonglong()
+ types = core.BNGetDownloadProviderList(count)
+ try:
+ for i in xrange(0, count.value):
+ yield DownloadProvider(types[i])
+ finally:
+ core.BNFreeDownloadProviderList(types)
+
+ def __getitem__(self, value):
+ startup._init_plugins()
+ provider = core.BNGetDownloadProviderByName(str(value))
+ if provider is None:
+ raise KeyError("'%s' is not a valid download provider" % str(value))
+ return DownloadProvider(provider)
+
+ def __setattr__(self, name, value):
+ try:
+ type.__setattr__(self, name, value)
+ except AttributeError:
+ raise AttributeError("attribute '%s' is read only" % name)
+
+
+class DownloadProvider(with_metaclass(_DownloadProviderMetaclass, object)):
+ name = None
+ instance_class = None
+ _registered_providers = []
+
+ def __init__(self, handle = None):
+ if handle is not None:
+ self.handle = core.handle_of_type(handle, core.BNDownloadProvider)
+ self.__dict__["name"] = core.BNGetDownloadProviderName(handle)
+
+ def register(self):
+ self._cb = core.BNDownloadProviderCallbacks()
+ self._cb.context = 0
+ self._cb.createInstance = self._cb.createInstance.__class__(self._create_instance)
+ self.handle = core.BNRegisterDownloadProvider(self.__class__.name, self._cb)
+ self.__class__._registered_providers.append(self)
+
+ def _create_instance(self, ctxt):
+ try:
+ result = self.__class__.instance_class(self)
+ if result is None:
+ return None
+ return ctypes.cast(core.BNNewDownloadInstanceReference(result.handle), ctypes.c_void_p).value
+ except:
+ log.log_error(traceback.format_exc())
+ return None
+
+ def create_instance(self):
+ result = core.BNCreateDownloadProviderInstance(self.handle)
+ if result is None:
+ return None
+ return DownloadInstance(self, handle = result)
+
+
+if sys.version_info >= (2, 7, 9):
+ try:
+ from urllib.request import urlopen, build_opener, install_opener, ProxyHandler
+ from urllib.error import URLError
+ except ImportError:
+ from urllib2 import urlopen, build_opener, install_opener, ProxyHandler, URLError
+
+ class PythonDownloadInstance(DownloadInstance):
+ def __init__(self, provider):
+ super(PythonDownloadInstance, self).__init__(provider)
+
+ @abc.abstractmethod
+ def perform_destroy_instance(self):
+ pass
+
+ @abc.abstractmethod
+ def perform_request(self, url):
+ try:
+ proxy_setting = Setting('download-client').get_string('https-proxy')
+ if proxy_setting:
+ opener = build_opener(ProxyHandler({'https': proxy_setting}))
+ install_opener(opener)
+
+ r = urlopen(pyNativeStr(url))
+ total_size = int(r.headers.get('content-length', 0))
+ bytes_sent = 0
+ while True:
+ data = r.read(4096)
+ if not data:
+ break
+ raw_bytes = (ctypes.c_ubyte * len(data)).from_buffer_copy(data)
+ bytes_wrote = core.BNWriteDataForDownloadInstance(self.handle, raw_bytes, len(raw_bytes))
+ if bytes_wrote != len(raw_bytes):
+ core.BNSetErrorForDownloadInstance(self.handle, "Bytes written mismatch!")
+ return -1
+ bytes_sent = bytes_sent + bytes_wrote
+ continue_download = core.BNNotifyProgressForDownloadInstance(self.handle, bytes_sent, total_size)
+ if continue_download is False:
+ core.BNSetErrorForDownloadInstance(self.handle, "Download aborted!")
+ return -1
+
+ if not bytes_sent:
+ core.BNSetErrorForDownloadInstance(self.handle, "Received no data!")
+ return -1
+
+ except URLError as e:
+ core.BNSetErrorForDownloadInstance(self.handle, e.__class__.__name__)
+ return -1
+ except:
+ core.BNSetErrorForDownloadInstance(self.handle, "Unknown Exception!")
+ log.log_error(traceback.format_exc())
+ return -1
+
+ return 0
+
+ class PythonDownloadProvider(DownloadProvider):
+ name = "DefaultDownloadProvider"
+ instance_class = PythonDownloadInstance
+
+ PythonDownloadProvider().register()
+else:
+ try:
+ import requests
+ from requests import pyopenssl
+ class PythonDownloadInstance(DownloadInstance):
+ def __init__(self, provider):
+ super(PythonDownloadInstance, self).__init__(provider)
+
+ @abc.abstractmethod
+ def perform_destroy_instance(self):
+ pass
+
+ @abc.abstractmethod
+ def perform_request(self, url):
+ try:
+ proxy_setting = Setting('download-client').get_string('https-proxy')
+ if proxy_setting:
+ proxies = {"https": proxy_setting}
+ else:
+ proxies = None
+
+ r = requests.get(pyNativeStr(url), proxies=proxies)
+ if not r.ok:
+ core.BNSetErrorForDownloadInstance(self.handle, "Received error from server")
+ return -1
+ data = r.content
+ if len(data) == 0:
+ core.BNSetErrorForDownloadInstance(self.handle, "No data received from server!")
+ return -1
+ raw_bytes = (ctypes.c_ubyte * len(data)).from_buffer_copy(data)
+ bytes_wrote = core.BNWriteDataForDownloadInstance(self.handle, raw_bytes, len(raw_bytes))
+ if bytes_wrote != len(raw_bytes):
+ core.BNSetErrorForDownloadInstance(self.handle, "Bytes written mismatch!")
+ return -1
+ continue_download = core.BNNotifyProgressForDownloadInstance(self.handle, bytes_wrote, bytes_wrote)
+ if continue_download is False:
+ core.BNSetErrorForDownloadInstance(self.handle, "Download aborted!")
+ return -1
+ except requests.RequestException as e:
+ core.BNSetErrorForDownloadInstance(self.handle, e.__class__.__name__)
+ return -1
+ except:
+ core.BNSetErrorForDownloadInstance(self.handle, "Unknown Exception!")
+ log.log_error(traceback.format_exc())
+ return -1
+
+ return 0
+
+ class PythonDownloadProvider(DownloadProvider):
+ name = "DefaultDownloadProvider"
+ instance_class = PythonDownloadInstance
+
+ PythonDownloadProvider().register()
+ except ImportError:
+ if sys.platform == "win32":
+ log.log_error("Provided Python version is too old! Only Python 2.7.10 and above are known to work on Windows!")
+ else:
+ log.log_error("On Python versions below 2.7.9, the pip requests[security] package is required for network connectivity!")
+ log.log_error("On an Ubuntu 14.04 install, the following three commands are sufficient to enable networking for the current user:")
+ log.log_error(" sudo apt install python-pip")
+ log.log_error(" python -m pip install pip --upgrade --user")
+ log.log_error(" python -m pip install requests[security] --upgrade --user")
+
diff --git a/python/examples/bin_info.py b/python/examples/bin_info.py
index 17a96685..05a72ed0 100644
--- a/python/examples/bin_info.py
+++ b/python/examples/bin_info.py
@@ -20,11 +20,15 @@
# IN THE SOFTWARE.
import sys
+
import binaryninja.log as log
from binaryninja.binaryview import BinaryViewType
import binaryninja.interaction as interaction
from binaryninja.plugin import PluginCommand
+# 2-3 compatibility
+from binaryninja import range
+
def get_bininfo(bv):
if bv is None:
@@ -48,13 +52,13 @@ def get_bininfo(bv):
contents += "| Start | Name |\n"
contents += "|------:|:-------|\n"
- for i in xrange(min(10, len(bv.functions))):
+ for i in range(min(10, len(bv.functions))):
contents += "| 0x%x | %s |\n" % (bv.functions[i].start, bv.functions[i].symbol.full_name)
contents += "### First 10 Strings ###\n"
contents += "| Start | Length | String |\n"
contents += "|------:|-------:|:-------|\n"
- for i in xrange(min(10, len(bv.strings))):
+ for i in range(min(10, len(bv.strings))):
start = bv.strings[i].start
length = bv.strings[i].length
string = bv.read(start, length)
@@ -67,6 +71,6 @@ def display_bininfo(bv):
if __name__ == "__main__":
- print get_bininfo(None)
+ print(get_bininfo(None))
else:
PluginCommand.register("Binary Info", "Display basic info about the binary", display_bininfo)
diff --git a/python/examples/breakpoint.py b/python/examples/breakpoint.py
index a2801511..cbcb86d4 100644
--- a/python/examples/breakpoint.py
+++ b/python/examples/breakpoint.py
@@ -44,7 +44,7 @@ def write_breakpoint(view, start, length):
if bkpt is None:
log_error(err)
return
- view.write(start, bkpt * length / len(bkpt))
+ view.write(start, bkpt * length // len(bkpt))
PluginCommand.register_for_range("Convert to breakpoint", "Fill region with breakpoint instructions.", write_breakpoint)
diff --git a/python/examples/export_svg.py b/python/examples/export_svg.py
index 7814c9fd..5bb27824 100755
--- a/python/examples/export_svg.py
+++ b/python/examples/export_svg.py
@@ -48,15 +48,15 @@ def save_svg(bv, function):
def instruction_data_flow(function, address):
''' TODO: Extract data flow information '''
- length = function.view.get_instruction_length(address)
- bytes = function.view.read(address, length)
+ length = binaryninja.function.view.get_instruction_length(address)
+ bytes = binaryninja.function.view.read(address, length)
hex = bytes.encode('hex')
padded = ' '.join([hex[i:i + 2] for i in range(0, len(hex), 2)])
return 'Opcode: {bytes}'.format(bytes=padded)
def render_svg(function, origname):
- graph = function.create_graph()
+ graph = binaryninja.function.create_graph()
graph.layout_and_wait()
heightconst = 15
ratio = 0.48
diff --git a/python/examples/jump_table.py b/python/examples/jump_table.py
index 419cc188..4ed8dda2 100644
--- a/python/examples/jump_table.py
+++ b/python/examples/jump_table.py
@@ -43,16 +43,16 @@ def find_jump_table(bv, addr):
break
jump_addr += info.length
if jump_addr >= block.end:
- print "Unable to find jump after instruction 0x%x" % addr
+ print("Unable to find jump after instruction 0x%x" % addr)
continue
- print "Jump at 0x%x" % jump_addr
+ print("Jump at 0x%x" % jump_addr)
# Collect the branch targets for any tables referenced by the clicked instruction
branches = []
for token in tokens:
if InstructionTextTokenType(token.type) == InstructionTextTokenType.PossibleAddressToken: # Table addresses will be a "possible address" token
tbl = token.value
- print "Found possible table at 0x%x" % tbl
+ print("Found possible table at 0x%x" % tbl)
i = 0
while True:
# Read the next pointer from the table
@@ -66,7 +66,7 @@ def find_jump_table(bv, addr):
# If the pointer is within the binary, add it as a destination and continue
# to the next entry
if (ptr >= bv.start) and (ptr < bv.end):
- print "Found destination 0x%x" % ptr
+ print("Found destination 0x%x" % ptr)
branches.append((arch, ptr))
else:
# Once a value that is not a pointer is encountered, the jump table is ended
diff --git a/python/examples/nds.py b/python/examples/nds.py
index 34d8a292..a99303cf 100644
--- a/python/examples/nds.py
+++ b/python/examples/nds.py
@@ -27,12 +27,15 @@ from binaryninja.log import log_error
import struct
import traceback
+# 2-3 compatibility
+from binaryninja import range
+
def crc16(data):
crc = 0xffff
for ch in data:
crc ^= ord(ch)
- for bit in xrange(0, 8):
+ for bit in range(0, 8):
if (crc & 1) == 1:
crc = (crc >> 1) ^ 0xa001
else:
diff --git a/python/examples/nes.py b/python/examples/nes.py
index 00451abd..d3f75cc6 100644
--- a/python/examples/nes.py
+++ b/python/examples/nes.py
@@ -31,6 +31,10 @@ from binaryninja.log import log_error
from binaryninja.enums import (BranchType, InstructionTextTokenType,
LowLevelILOperation, LowLevelILFlagCondition, FlagRole, SegmentFlag, SymbolType)
+# 2-3 compatibility
+from binaryninja import range
+
+
InstructionNames = [
"brk", "ora", None, None, None, "ora", "asl", None, # 0x00
"php", "ora", "asl@", None, None, "ora", "asl", None, # 0x08
@@ -631,7 +635,7 @@ class NESView(BinaryView):
banks = []
-for i in xrange(0, 32):
+for i in range(0, 32):
class NESViewBank(NESView):
bank = i
name = "NES Bank %X" % i
diff --git a/python/examples/notification_callbacks.py b/python/examples/notification_callbacks.py
index b7c9cde9..02c74db9 100644
--- a/python/examples/notification_callbacks.py
+++ b/python/examples/notification_callbacks.py
@@ -1,51 +1,74 @@
-from binaryninja import BinaryDataNotification, PluginCommand, log_info
+# Copyright (c) 2015-2017 Vector 35 LLC
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
import inspect
+from binaryninja import BinaryDataNotification
+from binaryninja import PluginCommand
+
+
def reg_notif(view):
- demo_notification = DemoNotification(view)
- view.register_notification(demo_notification)
+ demo_notification = DemoNotification(view)
+ view.register_notification(demo_notification)
class DemoNotification(BinaryDataNotification):
- def __init__(self, view):
- self.view = view
+ def __init__(self, view):
+ self.view = view
- def data_written(self, *args):
- log_info(inspect.stack()[0][3] + str(args))
+ def data_written(self, *args):
+ log.log_info(inspect.stack()[0][3] + str(args))
- def data_inserted(self, *args):
- log_info(inspect.stack()[0][3] + str(args))
+ def data_inserted(self, *args):
+ log.log_info(inspect.stack()[0][3] + str(args))
- def data_removed(self, *args):
- log_info(inspect.stack()[0][3] + str(args))
+ def data_removed(self, *args):
+ log.log_info(inspect.stack()[0][3] + str(args))
- def function_added(self, *args):
- log_info(inspect.stack()[0][3] + str(args))
+ def function_added(self, *args):
+ log.log_info(inspect.stack()[0][3] + str(args))
- def function_removed(self, *args):
- log_info(inspect.stack()[0][3] + str(args))
+ def function_removed(self, *args):
+ log.log_info(inspect.stack()[0][3] + str(args))
- def function_updated(self, *args):
- log_info(inspect.stack()[0][3] + str(args))
+ def function_updated(self, *args):
+ log.log_info(inspect.stack()[0][3] + str(args))
- def data_var_added(self, *args):
- log_info(inspect.stack()[0][3] + str(args))
+ def data_var_added(self, *args):
+ log.log_info(inspect.stack()[0][3] + str(args))
- def data_var_updated(self, *args):
- log_info(inspect.stack()[0][3] + str(args))
+ def data_var_updated(self, *args):
+ log.log_info(inspect.stack()[0][3] + str(args))
- def data_var_removed(self, *args):
- log_info(inspect.stack()[0][3] + str(args))
+ def data_var_removed(self, *args):
+ log.log_info(inspect.stack()[0][3] + str(args))
- def string_found(self, *args):
- log_info(inspect.stack()[0][3] + str(args))
+ def string_found(self, *args):
+ log.log_info(inspect.stack()[0][3] + str(args))
- def string_removed(self, *args):
- log_info(inspect.stack()[0][3] + str(args))
+ def string_removed(self, *args):
+ log.log_info(inspect.stack()[0][3] + str(args))
- def type_defined(self, *args):
- log_info(inspect.stack()[0][3] + str(args))
+ def type_defined(self, *args):
+ log.log_info(inspect.stack()[0][3] + str(args))
- def type_undefined(self, *args):
- log_info(inspect.stack()[0][3] + str(args))
+ def type_undefined(self, *args):
+ log.log_info(inspect.stack()[0][3] + str(args))
PluginCommand.register("Register Notification", "", reg_notif)
diff --git a/python/examples/version_switcher.py b/python/examples/version_switcher.py
index 3e1cab40..c990a6c0 100644
--- a/python/examples/version_switcher.py
+++ b/python/examples/version_switcher.py
@@ -34,15 +34,15 @@ def load_channel(newchannel):
global channel
global versions
if (channel is not None and newchannel == channel.name):
- print "Same channel, not updating."
+ print("Same channel, not updating.")
else:
try:
- print "Loading channel %s" % newchannel
+ print("Loading channel %s" % newchannel)
channel = UpdateChannel[newchannel]
- print "Loading versions..."
+ print("Loading versions...")
versions = channel.versions
except Exception:
- print "%s is not a valid channel name. Defaulting to " % chandefault
+ print("%s is not a valid channel name. Defaulting to " % chandefault)
channel = UpdateChannel[chandefault]
@@ -50,12 +50,12 @@ def select(version):
done = False
date = datetime.datetime.fromtimestamp(version.time).strftime('%c')
while not done:
- print "Version:\t%s" % version.version
- print "Updated:\t%s" % date
- print "Notes:\n\n-----\n%s" % version.notes
- print "-----"
- print "\t1)\tSwitch to version"
- print "\t2)\tMain Menu"
+ print("Version:\t%s" % version.version)
+ print("Updated:\t%s" % date)
+ print("Notes:\n\n-----\n%s" % version.notes)
+ print("-----")
+ print("\t1)\tSwitch to version")
+ print("\t2)\tMain Menu")
selection = raw_input('Choice: ')
if selection.isdigit():
selection = int(selection)
@@ -65,44 +65,44 @@ def select(version):
done = True
elif (selection == 1):
if (version.version == channel.latest_version.version):
- print "Requesting update to latest version."
+ print("Requesting update to latest version.")
else:
- print "Requesting update to prior version."
+ print("Requesting update to prior version.")
if are_auto_updates_enabled():
- print "Disabling automatic updates."
+ print("Disabling automatic updates.")
set_auto_updates_enabled(False)
if (version.version == core_version):
- print "Already running %s" % version.version
+ print("Already running %s" % version.version)
else:
- print "version.version %s" % version.version
- print "core_version %s" % core_version
- print "Downloading..."
- print version.update()
- print "Installing..."
+ print("version.version %s" % version.version)
+ print("core_version %s" % core_version)
+ print("Downloading...")
+ print(version.update())
+ print("Installing...")
if is_update_installation_pending:
#note that the GUI will be launched after update but should still do the upgrade headless
install_pending_update()
# forward updating won't work without reloading
sys.exit()
else:
- print "Invalid selection"
+ print("Invalid selection")
def list_channels():
done = False
- print "\tSelect channel:\n"
+ print("\tSelect channel:\n")
while not done:
channel_list = UpdateChannel.list
for index, item in enumerate(channel_list):
- print "\t%d)\t%s" % (index + 1, item.name)
- print "\t%d)\t%s" % (len(channel_list) + 1, "Main Menu")
+ print("\t%d)\t%s" % (index + 1, item.name))
+ print("\t%d)\t%s" % (len(channel_list) + 1, "Main Menu"))
selection = raw_input('Choice: ')
if selection.isdigit():
selection = int(selection)
else:
selection = 0
if (selection <= 0 or selection > len(channel_list) + 1):
- print "%s is an invalid choice." % selection
+ print("%s is an invalid choice." % selection)
else:
done = True
if (selection != len(channel_list) + 1):
@@ -118,23 +118,23 @@ def main():
done = False
load_channel(chandefault)
while not done:
- print "\n\tBinary Ninja Version Switcher"
- print "\t\tCurrent Channel:\t%s" % channel.name
- print "\t\tCurrent Version:\t%s" % core_version
- print "\t\tAuto-Updates On:\t%s\n" % are_auto_updates_enabled()
+ print("\n\tBinary Ninja Version Switcher")
+ print("\t\tCurrent Channel:\t%s" % channel.name)
+ print("\t\tCurrent Version:\t%s" % core_version)
+ print("\t\tAuto-Updates On:\t%s\n" % are_auto_updates_enabled())
for index, version in enumerate(versions):
date = datetime.datetime.fromtimestamp(version.time).strftime('%c')
- print "\t%d)\t%s (%s)" % (index + 1, version.version, date)
- print "\t%d)\t%s" % (len(versions) + 1, "Switch Channel")
- print "\t%d)\t%s" % (len(versions) + 2, "Toggle Auto Updates")
- print "\t%d)\t%s" % (len(versions) + 3, "Exit")
+ print("\t%d)\t%s (%s)" % (index + 1, version.version, date))
+ print("\t%d)\t%s" % (len(versions) + 1, "Switch Channel"))
+ print("\t%d)\t%s" % (len(versions) + 2, "Toggle Auto Updates"))
+ print("\t%d)\t%s" % (len(versions) + 3, "Exit"))
selection = raw_input('Choice: ')
if selection.isdigit():
selection = int(selection)
else:
selection = 0
if (selection <= 0 or selection > len(versions) + 3):
- print "%d is an invalid choice.\n\n" % selection
+ print("%d is an invalid choice.\n\n" % selection)
else:
if (selection == len(versions) + 3):
done = True
diff --git a/python/fileaccessor.py b/python/fileaccessor.py
index 2c1f1d19..c2539b39 100644
--- a/python/fileaccessor.py
+++ b/python/fileaccessor.py
@@ -22,9 +22,7 @@ import traceback
import ctypes
# Binary Ninja components
-import _binaryninjacore as core
-import log
-
+from binaryninja import _binaryninjacore as core
class FileAccessor(object):
def __init__(self):
diff --git a/python/filemetadata.py b/python/filemetadata.py
index 4bfc0214..cafe1d67 100644
--- a/python/filemetadata.py
+++ b/python/filemetadata.py
@@ -18,16 +18,15 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
+from __future__ import absolute_import
import traceback
import ctypes
-# Binary Ninja components
-import _binaryninjacore as core
-import startup
-import associateddatastore
-import log
-import binaryview
-
+# Binary Ninja Components
+import binaryninja
+from binaryninja import _binaryninjacore as core
+from binaryninja import associateddatastore #required for _FileMetadataAssociatedDataStore
+from binaryninja import log
class NavigationHandler(object):
def _register(self, handle):
@@ -66,12 +65,13 @@ class _FileMetadataAssociatedDataStore(associateddatastore._AssociatedDataStore)
class FileMetadata(object):
- _associated_data = {}
-
"""
``class FileMetadata`` represents the file being analyzed by Binary Ninja. It is responsible for opening,
closing, creating the database (.bndb) files, and is used to keep track of undoable actions.
"""
+
+ _associated_data = {}
+
def __init__(self, filename = None, handle = None):
"""
Instantiates a new FileMetadata class.
@@ -82,7 +82,7 @@ class FileMetadata(object):
if handle is not None:
self.handle = core.handle_of_type(handle, core.BNFileMetadata)
else:
- startup._init_plugins()
+ binaryninja._init_plugins()
self.handle = core.BNCreateFileMetadata()
if filename is not None:
core.BNSetFilename(self.handle, str(filename))
@@ -167,7 +167,7 @@ class FileMetadata(object):
view = core.BNGetFileViewOfType(self.handle, "Raw")
if view is None:
return None
- return binaryview.BinaryView(file_metadata = self, handle = view)
+ return binaryninja.binaryview.BinaryView(file_metadata = self, handle = view)
@property
def saved(self):
@@ -322,7 +322,7 @@ class FileMetadata(object):
lambda ctxt, cur, total: progress_func(cur, total)))
if view is None:
return None
- return binaryview.BinaryView(file_metadata = self, handle = view)
+ return binaryninja.binaryview.BinaryView(file_metadata = self, handle = view)
def save_auto_snapshot(self, progress_func = None):
if progress_func is None:
@@ -341,7 +341,7 @@ class FileMetadata(object):
view = core.BNCreateBinaryViewOfType(view_type, self.raw.handle)
if view is None:
return None
- return binaryview.BinaryView(file_metadata = self, handle = view)
+ return binaryninja.binaryview.BinaryView(file_metadata = self, handle = view)
def __setattr__(self, name, value):
try:
diff --git a/python/flowgraph.py b/python/flowgraph.py
index e6c98597..cf2d8e02 100644
--- a/python/flowgraph.py
+++ b/python/flowgraph.py
@@ -23,16 +23,19 @@ import threading
import traceback
# Binary Ninja components
-import _binaryninjacore as core
-from enums import (BranchType, InstructionTextTokenType, HighlightStandardColor)
-import function
-import binaryview
-import lowlevelil
-import mediumlevelil
-import basicblock
-import log
-import interaction
-import highlight
+import binaryninja
+from binaryninja.enums import (BranchType, InstructionTextTokenType, HighlightStandardColor)
+from binaryninja import _binaryninjacore as core
+from binaryninja import function
+from binaryninja import binaryview
+from binaryninja import lowlevelil
+from binaryninja import mediumlevelil
+from binaryninja import basicblock
+from binaryninja import log
+from binaryninja import highlight
+
+# 2-3 compatibility
+from binaryninja import range
class FlowGraphEdge(object):
@@ -118,7 +121,7 @@ class FlowGraphNode(object):
lines = core.BNGetFlowGraphNodeLines(self.handle, count)
block = self.basic_block
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
addr = lines[i].addr
if (lines[i].instrIndex != 0xffffffffffffffff) and (block is not None) and hasattr(block, 'il_function'):
il_instr = block.il_function[lines[i].instrIndex]
@@ -126,7 +129,7 @@ class FlowGraphNode(object):
il_instr = None
color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
tokens = []
- for j in xrange(0, lines[i].count):
+ for j in range(0, lines[i].count):
token_type = InstructionTextTokenType(lines[i].tokens[j].type)
text = lines[i].tokens[j].text
value = lines[i].tokens[j].value
@@ -145,7 +148,7 @@ class FlowGraphNode(object):
if isinstance(lines, str):
lines = lines.split('\n')
line_buf = (core.BNDisassemblyTextLine * len(lines))()
- for i in xrange(0, len(lines)):
+ for i in range(0, len(lines)):
line = lines[i]
if isinstance(line, str):
line = function.DisassemblyTextLine([function.InstructionTextToken(InstructionTextTokenType.TextToken, line)])
@@ -170,7 +173,7 @@ class FlowGraphNode(object):
line_buf[i].highlight = color._get_core_struct()
line_buf[i].count = len(line.tokens)
line_buf[i].tokens = (core.BNInstructionTextToken * len(line.tokens))()
- for j in xrange(0, len(line.tokens)):
+ for j in range(0, len(line.tokens)):
line_buf[i].tokens[j].type = line.tokens[j].type
line_buf[i].tokens[j].text = line.tokens[j].text
line_buf[i].tokens[j].value = line.tokens[j].value
@@ -187,13 +190,13 @@ class FlowGraphNode(object):
count = ctypes.c_ulonglong()
edges = core.BNGetFlowGraphNodeOutgoingEdges(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
branch_type = BranchType(edges[i].type)
target = edges[i].target
if target:
target = FlowGraphNode(self.graph, core.BNNewFlowGraphNodeReference(target))
points = []
- for j in xrange(0, edges[i].pointCount):
+ for j in range(0, edges[i].pointCount):
points.append((edges[i].points[j].x, edges[i].points[j].y))
result.append(FlowGraphEdge(branch_type, self, target, points, edges[i].backEdge))
core.BNFreeFlowGraphNodeOutgoingEdgeList(edges, count.value)
@@ -235,14 +238,14 @@ class FlowGraphNode(object):
lines = core.BNGetFlowGraphNodeLines(self.handle, count)
block = self.basic_block
try:
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
addr = lines[i].addr
if (lines[i].instrIndex != 0xffffffffffffffff) and (block is not None) and hasattr(block, 'il_function'):
il_instr = block.il_function[lines[i].instrIndex]
else:
il_instr = None
tokens = []
- for j in xrange(0, lines[i].count):
+ for j in range(0, lines[i].count):
token_type = InstructionTextTokenType(lines[i].tokens[j].type)
text = lines[i].tokens[j].text
value = lines[i].tokens[j].value
@@ -353,7 +356,7 @@ class FlowGraph(object):
count = ctypes.c_ulonglong()
blocks = core.BNGetFlowGraphNodes(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(FlowGraphNode(self, core.BNNewFlowGraphNodeReference(blocks[i])))
core.BNFreeFlowGraphNodeList(blocks, count.value)
return result
@@ -451,7 +454,7 @@ class FlowGraph(object):
count = ctypes.c_ulonglong()
nodes = core.BNGetFlowGraphNodes(self.handle, count)
try:
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
yield FlowGraphNode(self, core.BNNewFlowGraphNodeReference(nodes[i]))
finally:
core.BNFreeFlowGraphNodeList(nodes, count.value)
@@ -492,7 +495,7 @@ class FlowGraph(object):
count = ctypes.c_ulonglong()
nodes = core.BNGetFlowGraphNodesInRegion(self.handle, left, top, right, bottom, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(FlowGraphNode(self, core.BNNewFlowGraphNodeReference(nodes[i])))
core.BNFreeFlowGraphNodeList(nodes, count.value)
return result
@@ -507,7 +510,7 @@ class FlowGraph(object):
return FlowGraphNode(self, node)
def show(self, title):
- interaction.show_graph_report(title, self)
+ binaryninja.interaction.show_graph_report(title, self)
def update(self):
return None
diff --git a/python/function.py b/python/function.py
index f64a9677..e840dd5e 100644
--- a/python/function.py
+++ b/python/function.py
@@ -18,28 +18,25 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
+from __future__ import absolute_import
import threading
import traceback
import ctypes
# Binary Ninja components
-import _binaryninjacore as core
-from enums import (FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType,
+import binaryninja
+from binaryninja import _binaryninjacore as core
+from binaryninja import associateddatastore # Required in the main scope due to being an argument for _FunctionAssociatedDataStore
+from binaryninja import highlight
+from binaryninja import log
+from binaryninja import types
+from binaryninja.enums import (AnalysisSkipReason, FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType,
HighlightStandardColor, HighlightColorStyle, RegisterValueType, ImplicitRegisterExtend,
DisassemblyOption, IntegerDisplayType, InstructionTextTokenContext, VariableSourceType,
FunctionAnalysisSkipOverride)
-import architecture
-import platform
-import highlight
-import associateddatastore
-import types
-import basicblock
-import lowlevelil
-import mediumlevelil
-import binaryview
-import log
-import callingconvention
-import flowgraph
+
+# 2-3 compatibility
+from binaryninja import range
class LookupTableEntry(object):
@@ -180,7 +177,7 @@ class PossibleValueSet(object):
elif value.state == RegisterValueType.SignedRangeValue:
self.offset = value.value
self.ranges = []
- for i in xrange(0, value.count):
+ for i in range(0, value.count):
start = value.ranges[i].start
end = value.ranges[i].end
step = value.ranges[i].step
@@ -192,7 +189,7 @@ class PossibleValueSet(object):
elif value.state == RegisterValueType.UnsignedRangeValue:
self.offset = value.value
self.ranges = []
- for i in xrange(0, value.count):
+ for i in range(0, value.count):
start = value.ranges[i].start
end = value.ranges[i].end
step = value.ranges[i].step
@@ -200,15 +197,15 @@ class PossibleValueSet(object):
elif value.state == RegisterValueType.LookupTableValue:
self.table = []
self.mapping = {}
- for i in xrange(0, value.count):
+ for i in range(0, value.count):
from_list = []
- for j in xrange(0, value.table[i].fromCount):
+ for j in range(0, value.table[i].fromCount):
from_list.append(value.table[i].fromValues[j])
self.mapping[value.table[i].fromValues[j]] = value.table[i].toValue
self.table.append(LookupTableEntry(from_list, value.table[i].toValue))
elif (value.state == RegisterValueType.InSetOfValues) or (value.state == RegisterValueType.NotInSetOfValues):
self.values = set()
- for i in xrange(0, value.count):
+ for i in range(0, value.count):
self.values.add(value.valueSet[i])
def __repr__(self):
@@ -421,7 +418,7 @@ class Function(object):
arch = core.BNGetFunctionArchitecture(self.handle)
if arch is None:
return None
- self._arch = architecture.CoreArchitecture._from_cache(arch)
+ self._arch = binaryninja.architecture.CoreArchitecture._from_cache(arch)
return self._arch
@property
@@ -433,7 +430,7 @@ class Function(object):
plat = core.BNGetFunctionPlatform(self.handle)
if plat is None:
return None
- self._platform = platform.Platform(None, handle = plat)
+ self._platform = binaryninja.platform.Platform(None, handle = plat)
return self._platform
@property
@@ -486,8 +483,8 @@ class Function(object):
count = ctypes.c_ulonglong()
blocks = core.BNGetFunctionBasicBlockList(self.handle, count)
result = []
- for i in xrange(0, count.value):
- result.append(basicblock.BasicBlock(self._view, core.BNNewBasicBlockReference(blocks[i])))
+ for i in range(0, count.value):
+ result.append(binaryninja.basicblock.BasicBlock(self._view, core.BNNewBasicBlockReference(blocks[i])))
core.BNFreeBasicBlockList(blocks, count.value)
return result
@@ -497,7 +494,7 @@ class Function(object):
count = ctypes.c_ulonglong()
addrs = core.BNGetCommentedAddresses(self.handle, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result[addrs[i]] = self.get_comment_at(addrs[i])
core.BNFreeAddressList(addrs)
return result
@@ -505,17 +502,17 @@ class Function(object):
@property
def low_level_il(self):
"""returns LowLevelILFunction used to represent Function low level IL (read-only)"""
- return lowlevelil.LowLevelILFunction(self.arch, core.BNGetFunctionLowLevelIL(self.handle), self)
+ return binaryninja.lowlevelil.LowLevelILFunction(self.arch, core.BNGetFunctionLowLevelIL(self.handle), self)
@property
def lifted_il(self):
"""returns LowLevelILFunction used to represent lifted IL (read-only)"""
- return lowlevelil.LowLevelILFunction(self.arch, core.BNGetFunctionLiftedIL(self.handle), self)
+ return binaryninja.lowlevelil.LowLevelILFunction(self.arch, core.BNGetFunctionLiftedIL(self.handle), self)
@property
def medium_level_il(self):
"""Function medium level IL (read-only)"""
- return mediumlevelil.MediumLevelILFunction(self.arch, core.BNGetFunctionMediumLevelIL(self.handle), self)
+ return binaryninja.mediumlevelil.MediumLevelILFunction(self.arch, core.BNGetFunctionMediumLevelIL(self.handle), self)
@property
def function_type(self):
@@ -532,7 +529,7 @@ class Function(object):
count = ctypes.c_ulonglong()
v = core.BNGetStackLayout(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name,
types.Type(handle = core.BNNewTypeReference(v[i].type), platform = self.platform, confidence = v[i].typeConfidence)))
result.sort(key = lambda x: x.identifier)
@@ -545,7 +542,7 @@ class Function(object):
count = ctypes.c_ulonglong()
v = core.BNGetFunctionVariables(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name,
types.Type(handle = core.BNNewTypeReference(v[i].type), platform = self.platform, confidence = v[i].typeConfidence)))
result.sort(key = lambda x: x.identifier)
@@ -558,8 +555,8 @@ class Function(object):
count = ctypes.c_ulonglong()
branches = core.BNGetIndirectBranches(self.handle, count)
result = []
- for i in xrange(0, count.value):
- result.append(IndirectBranchInfo(architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, architecture.CoreArchitecture._from_cache(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined))
+ for i in range(0, count.value):
+ result.append(IndirectBranchInfo(binaryninja.architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, binaryninja.architecture.CoreArchitecture._from_cache(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined))
core.BNFreeIndirectBranchList(branches)
return result
@@ -579,7 +576,7 @@ class Function(object):
count = ctypes.c_ulonglong()
info = core.BNGetFunctionAnalysisPerformanceInfo(self.handle, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result[info[i].name] = info[i].seconds
core.BNFreeAnalysisPerformanceInfo(info, count.value)
return result
@@ -613,7 +610,7 @@ class Function(object):
"""Registers that are used for the return value"""
result = core.BNGetFunctionReturnRegisters(self.handle)
reg_set = []
- for i in xrange(0, result.count):
+ for i in range(0, result.count):
reg_set.append(self.arch.get_reg_name(result.regs[i]))
regs = types.RegisterSet(reg_set, confidence = result.confidence)
core.BNFreeRegisterSet(result)
@@ -624,7 +621,7 @@ class Function(object):
regs = core.BNRegisterSetWithConfidence()
regs.regs = (ctypes.c_uint * len(value))()
regs.count = len(value)
- for i in xrange(0, len(value)):
+ for i in range(0, len(value)):
regs.regs[i] = self.arch.get_reg_index(value[i])
if hasattr(value, 'confidence'):
regs.confidence = value.confidence
@@ -638,7 +635,7 @@ class Function(object):
result = core.BNGetFunctionCallingConvention(self.handle)
if not result.convention:
return None
- return callingconvention.CallingConvention(None, handle = result.convention, confidence = result.confidence)
+ return binaryninja.callingconvention.CallingConvention(None, handle = result.convention, confidence = result.confidence)
@calling_convention.setter
def calling_convention(self, value):
@@ -656,7 +653,7 @@ class Function(object):
"""List of variables for the incoming function parameters"""
result = core.BNGetFunctionParameterVariables(self.handle)
var_list = []
- for i in xrange(0, result.count):
+ for i in range(0, result.count):
var_list.append(Variable(self, result.vars[i].type, result.vars[i].index, result.vars[i].storage))
confidence = result.confidence
core.BNFreeParameterVariables(result)
@@ -671,7 +668,7 @@ class Function(object):
var_conf = core.BNParameterVariablesWithConfidence()
var_conf.vars = (core.BNVariable * len(var_list))()
var_conf.count = len(var_list)
- for i in xrange(0, len(var_list)):
+ for i in range(0, len(var_list)):
var_conf.vars[i].type = var_list[i].source_type
var_conf.vars[i].index = var_list[i].index
var_conf.vars[i].storage = var_list[i].storage
@@ -721,7 +718,7 @@ class Function(object):
count = ctypes.c_ulonglong()
adjust = core.BNGetFunctionRegisterStackAdjustments(self.handle, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
name = self.arch.get_reg_stack_name(adjust[i].regStack)
value = types.RegisterStackAdjustmentWithConfidence(adjust[i].adjustment,
confidence = adjust[i].confidence)
@@ -749,7 +746,7 @@ class Function(object):
"""Registers that are modified by this function"""
result = core.BNGetFunctionClobberedRegisters(self.handle)
reg_set = []
- for i in xrange(0, result.count):
+ for i in range(0, result.count):
reg_set.append(self.arch.get_reg_name(result.regs[i]))
regs = types.RegisterSet(reg_set, confidence = result.confidence)
core.BNFreeRegisterSet(result)
@@ -760,7 +757,7 @@ class Function(object):
regs = core.BNRegisterSetWithConfidence()
regs.regs = (ctypes.c_uint * len(value))()
regs.count = len(value)
- for i in xrange(0, len(value)):
+ for i in range(0, len(value)):
regs.regs[i] = self.arch.get_reg_index(value[i])
if hasattr(value, 'confidence'):
regs.confidence = value.confidence
@@ -829,6 +826,11 @@ class Function(object):
"""Whether automatic analysis was skipped for this function"""
return core.BNIsFunctionAnalysisSkipped(self.handle)
+ @property
+ def analysis_skip_reason(self):
+ """Function analysis skip reason"""
+ return AnalysisSkipReason(core.BNGetAnalysisSkipReason(self.handle))
+
@analysis_skipped.setter
def analysis_skipped(self, skip):
if skip:
@@ -851,14 +853,14 @@ class Function(object):
graph = core.BNGetUnresolvedStackAdjustmentGraph(self.handle)
if not graph:
return None
- return flowgraph.CoreFlowGraph(graph)
+ return binaryninja.flowgraph.CoreFlowGraph(graph)
def __iter__(self):
count = ctypes.c_ulonglong()
blocks = core.BNGetFunctionBasicBlockList(self.handle, count)
try:
- for i in xrange(0, count.value):
- yield basicblock.BasicBlock(self._view, core.BNNewBasicBlockReference(blocks[i]))
+ for i in range(0, count.value):
+ yield binaryninja.basicblock.BasicBlock(self._view, core.BNNewBasicBlockReference(blocks[i]))
finally:
core.BNFreeBasicBlockList(blocks, count.value)
@@ -928,7 +930,7 @@ class Function(object):
count = ctypes.c_ulonglong()
exits = core.BNGetLowLevelILExitsForInstruction(self.handle, arch.handle, addr, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(exits[i])
core.BNFreeILInstructionList(exits)
return result
@@ -940,7 +942,7 @@ class Function(object):
:param int addr: virtual address of the instruction to query
:param str reg: string value of native register to query
:param Architecture arch: (optional) Architecture for the given function
- :rtype: function.RegisterValue
+ :rtype: binaryninja.function.RegisterValue
:Example:
>>> func.get_reg_value_at(0x400dbe, 'rdi')
@@ -960,7 +962,7 @@ class Function(object):
:param int addr: virtual address of the instruction to query
:param str reg: string value of native register to query
:param Architecture arch: (optional) Architecture for the given function
- :rtype: function.RegisterValue
+ :rtype: binaryninja.function.RegisterValue
:Example:
>>> func.get_reg_value_after(0x400dbe, 'rdi')
@@ -982,7 +984,7 @@ class Function(object):
:param int offset: stack offset base of stack
:param int size: size of memory to query
:param Architecture arch: (optional) Architecture for the given function
- :rtype: function.RegisterValue
+ :rtype: binaryninja.function.RegisterValue
.. note:: Stack base is zero on entry into the function unless the architecture places the return address on the
stack as in (x86/x86_64) where the stack base will start at address_size
@@ -1027,7 +1029,7 @@ class Function(object):
count = ctypes.c_ulonglong()
regs = core.BNGetRegistersReadByInstruction(self.handle, arch.handle, addr, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(arch.get_reg_name(regs[i]))
core.BNFreeRegisterList(regs)
return result
@@ -1038,7 +1040,7 @@ class Function(object):
count = ctypes.c_ulonglong()
regs = core.BNGetRegistersWrittenByInstruction(self.handle, arch.handle, addr, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(arch.get_reg_name(regs[i]))
core.BNFreeRegisterList(regs)
return result
@@ -1049,7 +1051,7 @@ class Function(object):
count = ctypes.c_ulonglong()
refs = core.BNGetStackVariablesReferencedByInstruction(self.handle, arch.handle, addr, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
var_type = types.Type(core.BNNewTypeReference(refs[i].type), platform = self.platform, confidence = refs[i].typeConfidence)
result.append(StackVariableReference(refs[i].sourceOperand, var_type,
refs[i].name, Variable.from_identifier(self, refs[i].varIdentifier, refs[i].name, var_type),
@@ -1063,7 +1065,7 @@ class Function(object):
count = ctypes.c_ulonglong()
refs = core.BNGetConstantsReferencedByInstruction(self.handle, arch.handle, addr, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(ConstantReference(refs[i].value, refs[i].size, refs[i].pointer, refs[i].intermediate))
core.BNFreeConstantReferenceList(refs)
return result
@@ -1084,7 +1086,7 @@ class Function(object):
count = ctypes.c_ulonglong()
instrs = core.BNGetLiftedILFlagUsesForDefinition(self.handle, i, flag, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(instrs[i])
core.BNFreeILInstructionList(instrs)
return result
@@ -1094,7 +1096,7 @@ class Function(object):
count = ctypes.c_ulonglong()
instrs = core.BNGetLiftedILFlagDefinitionsForUse(self.handle, i, flag, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(instrs[i])
core.BNFreeILInstructionList(instrs)
return result
@@ -1103,7 +1105,7 @@ class Function(object):
count = ctypes.c_ulonglong()
flags = core.BNGetFlagsReadByLiftedILInstruction(self.handle, i, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(self.arch._flags_by_index[flags[i]])
core.BNFreeRegisterList(flags)
return result
@@ -1112,7 +1114,7 @@ class Function(object):
count = ctypes.c_ulonglong()
flags = core.BNGetFlagsWrittenByLiftedILInstruction(self.handle, i, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(self.arch._flags_by_index[flags[i]])
core.BNFreeRegisterList(flags)
return result
@@ -1122,7 +1124,7 @@ class Function(object):
settings_obj = settings.handle
else:
settings_obj = None
- return flowgraph.CoreFlowGraph(core.BNCreateFunctionGraph(self.handle, graph_type, settings_obj))
+ return binaryninja.flowgraph.CoreFlowGraph(core.BNCreateFunctionGraph(self.handle, graph_type, settings_obj))
def apply_imported_types(self, sym):
core.BNApplyImportedTypes(self.handle, sym.handle)
@@ -1134,7 +1136,7 @@ class Function(object):
if source_arch is None:
source_arch = self.arch
branch_list = (core.BNArchitectureAndAddress * len(branches))()
- for i in xrange(len(branches)):
+ for i in range(len(branches)):
branch_list[i].arch = branches[i][0].handle
branch_list[i].address = branches[i][1]
core.BNSetAutoIndirectBranches(self.handle, source_arch.handle, source, branch_list, len(branches))
@@ -1143,7 +1145,7 @@ class Function(object):
if source_arch is None:
source_arch = self.arch
branch_list = (core.BNArchitectureAndAddress * len(branches))()
- for i in xrange(len(branches)):
+ for i in range(len(branches)):
branch_list[i].arch = branches[i][0].handle
branch_list[i].address = branches[i][1]
core.BNSetUserIndirectBranches(self.handle, source_arch.handle, source, branch_list, len(branches))
@@ -1154,8 +1156,8 @@ class Function(object):
count = ctypes.c_ulonglong()
branches = core.BNGetIndirectBranchesAt(self.handle, arch.handle, addr, count)
result = []
- for i in xrange(0, count.value):
- result.append(IndirectBranchInfo(architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, architecture.CoreArchitecture._from_cache(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined))
+ for i in range(0, count.value):
+ result.append(IndirectBranchInfo(binaryninja.architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, binaryninja.architecture.CoreArchitecture._from_cache(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined))
core.BNFreeIndirectBranchList(branches)
return result
@@ -1165,11 +1167,13 @@ class Function(object):
count = ctypes.c_ulonglong(0)
lines = core.BNGetFunctionBlockAnnotations(self.handle, arch.handle, addr, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
tokens = []
- for j in xrange(0, lines[i].count):
+ for j in range(0, lines[i].count):
token_type = InstructionTextTokenType(lines[i].tokens[j].type)
text = lines[i].tokens[j].text
+ if not isinstance(text, str):
+ text = text.encode("charmap")
value = lines[i].tokens[j].value
size = lines[i].tokens[j].size
operand = lines[i].tokens[j].operand
@@ -1201,7 +1205,7 @@ class Function(object):
regs = core.BNRegisterSetWithConfidence()
regs.regs = (ctypes.c_uint * len(value))()
regs.count = len(value)
- for i in xrange(0, len(value)):
+ for i in range(0, len(value)):
regs.regs[i] = self.arch.get_reg_index(value[i])
if hasattr(value, 'confidence'):
regs.confidence = value.confidence
@@ -1227,7 +1231,7 @@ class Function(object):
var_conf = core.BNParameterVariablesWithConfidence()
var_conf.vars = (core.BNVariable * len(var_list))()
var_conf.count = len(var_list)
- for i in xrange(0, len(var_list)):
+ for i in range(0, len(var_list)):
var_conf.vars[i].type = var_list[i].source_type
var_conf.vars[i].index = var_list[i].index
var_conf.vars[i].storage = var_list[i].storage
@@ -1284,7 +1288,7 @@ class Function(object):
regs = core.BNRegisterSetWithConfidence()
regs.regs = (ctypes.c_uint * len(value))()
regs.count = len(value)
- for i in xrange(0, len(value)):
+ for i in range(0, len(value)):
regs.regs[i] = self.arch.get_reg_index(value[i])
if hasattr(value, 'confidence'):
regs.confidence = value.confidence
@@ -1344,7 +1348,7 @@ class Function(object):
block = core.BNGetFunctionBasicBlockAtAddress(self.handle, arch.handle, addr)
if not block:
return None
- return basicblock.BasicBlock(self._view, handle = block)
+ return binaryninja.basicblock.BasicBlock(self._view, handle = block)
def get_instr_highlight(self, addr, arch=None):
"""
@@ -1472,11 +1476,11 @@ class Function(object):
count = ctypes.c_ulonglong()
lines = core.BNGetFunctionTypeTokens(self.handle, settings, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
addr = lines[i].addr
color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
tokens = []
- for j in xrange(0, lines[i].count):
+ for j in range(0, lines[i].count):
token_type = InstructionTextTokenType(lines[i].tokens[j].type)
text = lines[i].tokens[j].text
value = lines[i].tokens[j].value
@@ -1568,7 +1572,7 @@ class Function(object):
count = ctypes.c_ulonglong()
adjust = core.BNGetCallRegisterStackAdjustment(self.handle, arch.handle, addr, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result[arch.get_reg_stack_name(adjust[i].regStack)] = types.RegisterStackAdjustmentWithConfidence(
adjust[i].adjustment, confidence = adjust[i].confidence)
core.BNFreeRegisterStackAdjustments(adjust)
diff --git a/python/functionrecognizer.py b/python/functionrecognizer.py
index 4ac304ca..319bff0e 100644
--- a/python/functionrecognizer.py
+++ b/python/functionrecognizer.py
@@ -21,15 +21,15 @@
import traceback
# Binary Ninja components
-import _binaryninjacore as core
-import function
-import filemetadata
-import binaryview
-import lowlevelil
-import log
+from binaryninja import _binaryninjacore as core
+from binaryninja import function
+from binaryninja import filemetadata
+from binaryninja import binaryview
+from binaryninja import lowlevelil
class FunctionRecognizer(object):
+
_instance = None
def __init__(self):
diff --git a/python/generator.cpp b/python/generator.cpp
index f838b36d..39e45aea 100644
--- a/python/generator.cpp
+++ b/python/generator.cpp
@@ -117,7 +117,7 @@ void OutputType(FILE* out, Type* type, bool isReturnType = false, bool isCallbac
break;
}
else if ((type->GetChildType()->GetClass() == IntegerTypeClass) &&
- (type->GetChildType()->GetWidth() == 1) && (type->GetChildType()->IsSigned()))
+ (type->GetChildType()->GetWidth() == 1) && (type->GetChildType()->IsSigned()))
{
if (isReturnType)
fprintf(out, "ctypes.POINTER(ctypes.c_byte)");
@@ -173,7 +173,7 @@ int main(int argc, char* argv[])
}
bool ok = arch->GetStandalonePlatform()->ParseTypesFromSourceFile(argv[1], types, vars, funcs, errors);
- fprintf(stderr, "Errors: %s", errors.c_str());
+ fprintf(stderr, "Errors: %s\n", errors.c_str());
if (!ok)
return 1;
@@ -198,7 +198,9 @@ int main(int argc, char* argv[])
fprintf(out, "\t_base_path = os.path.join(os.path.dirname(__file__), \"..\", \"..\")\n");
fprintf(out, "\tcore = ctypes.CDLL(os.path.join(_base_path, \"binaryninjacore.dll\"))\n");
fprintf(out, "else:\n");
- fprintf(out, "\traise Exception(\"OS not supported\")\n\n");
+ fprintf(out, "\traise Exception(\"OS not supported\")\n\n\n");
+
+ fprintf(out, "from binaryninja import cstr, pyNativeStr\n\n\n");
// Create type objects
fprintf(out, "# Type definitions\n");
@@ -211,7 +213,23 @@ int main(int argc, char* argv[])
if (i.second->GetClass() == StructureTypeClass)
{
fprintf(out, "class %s(ctypes.Structure):\n", name.c_str());
- fprintf(out, "\tpass\n");
+
+ // python uses str's, C uses byte-arrays
+ bool stringField = false;
+ for (auto& arg : i.second->GetStructure()->GetMembers())
+ {
+ if ((arg.type->GetClass() == PointerTypeClass) &&
+ (arg.type->GetChildType()->GetWidth() == 1) &&
+ (arg.type->GetChildType()->IsSigned()))
+ {
+ fprintf(out, "\t@property\n\tdef %s(self):\n\t\treturn pyNativeStr(self._%s)\n", arg.name.c_str(), arg.name.c_str());
+ fprintf(out, "\t@%s.setter\n\tdef %s(self, value):\n\t\tself._%s = cstr(value)\n", arg.name.c_str(), arg.name.c_str(), arg.name.c_str());
+ stringField = true;
+ }
+ }
+
+ if (!stringField)
+ fprintf(out, "\tpass\n");
}
else if (i.second->GetClass() == EnumerationTypeClass)
{
@@ -227,7 +245,7 @@ int main(int argc, char* argv[])
}
}
else if ((i.second->GetClass() == BoolTypeClass) || (i.second->GetClass() == IntegerTypeClass) ||
- (i.second->GetClass() == FloatTypeClass) || (i.second->GetClass() == ArrayTypeClass))
+ (i.second->GetClass() == FloatTypeClass) || (i.second->GetClass() == ArrayTypeClass))
{
fprintf(out, "%s = ", name.c_str());
OutputType(out, i.second);
@@ -276,7 +294,15 @@ int main(int argc, char* argv[])
fprintf(out, "%s._fields_ = [\n", name.c_str());
for (auto& j : type->GetStructure()->GetMembers())
{
- fprintf(out, "\t\t(\"%s\", ", j.name.c_str());
+ // To help the python->C wrappers
+ if ((j.type->GetClass() == PointerTypeClass) &&
+ (j.type->GetChildType()->GetWidth() == 1) &&
+ (j.type->GetChildType()->IsSigned()))
+ {
+ fprintf(out, "\t\t(\"_%s\", ", j.name.c_str());
+ }
+ else
+ fprintf(out, "\t\t(\"%s\", ", j.name.c_str());
OutputType(out, j.type);
fprintf(out, "),\n");
}
@@ -310,6 +336,22 @@ int main(int argc, char* argv[])
(i.second->GetChildType()->GetChildType()->IsSigned());
// Pointer returns will be automatically wrapped to return None on null pointer
bool pointerResult = (i.second->GetChildType()->GetClass() == PointerTypeClass);
+
+ // From python -> C python3 requires str -> str.encode('charmap')
+ bool stringArgument = false;
+ for (auto& arg : i.second->GetParameters())
+ {
+ if ((arg.type->GetClass() == PointerTypeClass) &&
+ (arg.type->GetChildType()->GetWidth() == 1) &&
+ (arg.type->GetChildType()->IsSigned()))
+ {
+ stringArgument = true;
+ break;
+ }
+ }
+ if (name == "BNFreeString")
+ stringArgument = false;
+
bool callbackConvention = false;
if (name == "BNAllocString")
{
@@ -321,7 +363,7 @@ int main(int argc, char* argv[])
}
string funcName = name;
- if (stringResult || pointerResult)
+ if (stringResult || pointerResult || stringArgument)
funcName = string("_") + funcName;
fprintf(out, "%s = core.%s\n", funcName.c_str(), name.c_str());
@@ -349,13 +391,45 @@ int main(int argc, char* argv[])
}
fprintf(out, "\t]\n");
}
+ else
+ {
+ // As of writing this, only BNLog's have variable instruction lengths, but in an attempt not to break in the future:
+ if (funcName.compare(0, 6, "_BNLog") == 0)
+ {
+ fprintf(out, "def %s(*args):\n", name.c_str());
+ fprintf(out, "\treturn %s(*[cstr(arg) for arg in args])\n\n", funcName.c_str());
+ continue;
+ }
+ }
if (stringResult)
{
// Emit wrapper to get Python string and free native memory
fprintf(out, "def %s(*args):\n", name.c_str());
- fprintf(out, "\tresult = %s(*args)\n", funcName.c_str());
- fprintf(out, "\tstring = ctypes.cast(result, ctypes.c_char_p).value\n");
+ if (stringArgument)
+ {
+ fprintf(out, "\tresult = %s(", funcName.c_str());
+ string stringArgFuncCall = "";
+ size_t argN = 0;
+ for (auto& arg : i.second->GetParameters())
+ {
+ if ((arg.type->GetClass() == PointerTypeClass) &&
+ (arg.type->GetChildType()->GetWidth() == 1) &&
+ (arg.type->GetChildType()->IsSigned()))
+ {
+ stringArgFuncCall += "cstr(args[" + to_string(argN) + "]), ";
+ }
+ else
+ stringArgFuncCall += "args[" + to_string(argN) + "], ";
+ argN++;
+ }
+ stringArgFuncCall = stringArgFuncCall.substr(0, stringArgFuncCall.size()-2);
+ stringArgFuncCall += ")\n";
+ fprintf(out, "%s", stringArgFuncCall.c_str());
+ }
+ else
+ fprintf(out, "\tresult = %s(*args)\n", funcName.c_str());
+ fprintf(out, "\tstring = str(pyNativeStr(ctypes.cast(result, ctypes.c_char_p).value))\n");
fprintf(out, "\tBNFreeString(result)\n");
fprintf(out, "\treturn string\n");
}
@@ -363,18 +437,76 @@ int main(int argc, char* argv[])
{
// Emit wrapper to return None on null pointer
fprintf(out, "def %s(*args):\n", name.c_str());
- fprintf(out, "\tresult = %s(*args)\n", funcName.c_str());
+ if (stringArgument)
+ {
+ fprintf(out, "\tresult = %s(", funcName.c_str());
+ string stringArgFuncCall = "";
+ size_t argN = 0;
+ for (auto& arg : i.second->GetParameters())
+ {
+ if ((arg.type->GetClass() == PointerTypeClass) &&
+ (arg.type->GetChildType()->GetWidth() == 1) &&
+ (arg.type->GetChildType()->IsSigned()))
+ {
+ stringArgFuncCall += "cstr(args[" + to_string(argN) + "]), ";
+ }
+ else
+ stringArgFuncCall += "args[" + to_string(argN) + "], ";
+ argN++;
+ }
+ stringArgFuncCall = stringArgFuncCall.substr(0, stringArgFuncCall.size()-2);
+ stringArgFuncCall += ")\n";
+ fprintf(out, "%s", stringArgFuncCall.c_str());
+ }
+ else
+ fprintf(out, "\tresult = %s(*args)\n", funcName.c_str());
fprintf(out, "\tif not result:\n");
fprintf(out, "\t\treturn None\n");
fprintf(out, "\treturn result\n");
}
+ else if (stringArgument)
+ {
+ fprintf(out, "def %s(*args):\n", name.c_str());
+ {
+ fprintf(out, "\treturn %s(", funcName.c_str());
+ string stringArgFuncCall = "";
+ size_t argN = 0;
+ for (auto& arg : i.second->GetParameters())
+ {
+ if ((arg.type->GetClass() == PointerTypeClass) &&
+ (arg.type->GetChildType()->GetWidth() == 1) &&
+ (arg.type->GetChildType()->IsSigned()))
+ {
+ stringArgFuncCall += "cstr(args[" + to_string(argN) + "]), ";
+ }
+ else
+ stringArgFuncCall += "args[" + to_string(argN) + "], ";
+ argN++;
+ }
+ stringArgFuncCall = stringArgFuncCall.substr(0, stringArgFuncCall.size()-2);
+ stringArgFuncCall += ")\n";
+ fprintf(out, "%s", stringArgFuncCall.c_str());
+ }
+ }
+ fprintf(out, "\n");
}
fprintf(out, "\n# Helper functions\n");
fprintf(out, "def handle_of_type(value, handle_type):\n");
fprintf(out, "\tif isinstance(value, ctypes.POINTER(handle_type)) or isinstance(value, ctypes.c_void_p):\n");
fprintf(out, "\t\treturn ctypes.cast(value, ctypes.POINTER(handle_type))\n");
- fprintf(out, "\traise ValueError, 'expected pointer to %%s' %% str(handle_type)\n");
+ fprintf(out, "\traise ValueError('expected pointer to %%s' %% str(handle_type))\n");
+
+ // The following method is addapted from python/enum/__init__.py, lines 25-36
+ fprintf(out, "\ntry:\n");
+ fprintf(out, "\tbasestring\n");
+ fprintf(out, "\tunicode\n");
+ fprintf(out, "except NameError:\n");
+ fprintf(out, "\t# In Python 2 basestring is the ancestor of both str and unicode\n");
+ fprintf(out, "\t# in Python 3 it's just str, but was missing in 3.1\n");
+ fprintf(out, "\t# In Python 3 unicode no longer exists (it's just str)\n");
+ fprintf(out, "\tbasestring = str\n");
+ fprintf(out, "\tunicode = str\n");
fprintf(out, "\n# Set path for core plugins\n");
fprintf(out, "BNSetBundledPluginDirectory(os.path.join(_base_path, \"plugins\"))\n");
diff --git a/python/highlight.py b/python/highlight.py
index 87329202..502caa80 100644
--- a/python/highlight.py
+++ b/python/highlight.py
@@ -20,8 +20,8 @@
# Binary Ninja components
-import _binaryninjacore as core
-from enums import HighlightColorStyle, HighlightStandardColor
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import HighlightColorStyle, HighlightStandardColor
class HighlightColor(object):
diff --git a/python/interaction.py b/python/interaction.py
index b9aa0c2a..0170e6aa 100644
--- a/python/interaction.py
+++ b/python/interaction.py
@@ -22,11 +22,14 @@ import ctypes
import traceback
# Binary Ninja components
-import _binaryninjacore as core
-from enums import FormInputFieldType, MessageBoxIcon, MessageBoxButtonSet, MessageBoxButtonResult, ReportType
-import binaryview
-import log
-import flowgraph
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import FormInputFieldType, MessageBoxIcon, MessageBoxButtonSet, MessageBoxButtonResult
+from binaryninja import binaryview
+from binaryninja import log
+from binaryninja import flowgraph
+
+# 2-3 compatibility
+from binaryninja import range
class LabelField(object):
@@ -152,7 +155,11 @@ class AddressField(object):
class ChoiceField(object):
"""
``ChoiceField`` prompts the user to choose from the list of strings provided in ``choices``. Result is stored
- in self.result as an index in to the coices array.
+ in self.result as an index in to the choices array.
+
+ :attr str prompt: prompt to be presented to the user
+ :attr list(str) choices: list of choices to choose from
+
"""
def __init__(self, prompt, choices):
self.prompt = prompt
@@ -163,8 +170,8 @@ class ChoiceField(object):
value.type = FormInputFieldType.ChoiceFormField
value.prompt = self.prompt
choice_buf = (ctypes.c_char_p * len(self.choices))()
- for i in xrange(0, len(self.choices)):
- choice_buf[i] = str(self.choices[i])
+ for i in range(0, len(self.choices)):
+ choice_buf[i] = self.choices[i].encode('charmap')
value.choices = choice_buf
value.count = len(self.choices)
@@ -349,7 +356,7 @@ class InteractionHandler(object):
def _get_choice_input(self, ctxt, result, prompt, title, choice_buf, count):
try:
choices = []
- for i in xrange(0, count):
+ for i in range(0, count):
choices.append(choice_buf[i])
value = self.get_choice_input(prompt, title, choices)
if value is None:
@@ -392,7 +399,7 @@ class InteractionHandler(object):
def _get_form_input(self, ctxt, fields, count, title):
try:
field_objs = []
- for i in xrange(0, count):
+ for i in range(0, count):
if fields[i].type == FormInputFieldType.LabelFormField:
field_objs.append(LabelField(fields[i].prompt))
elif fields[i].type == FormInputFieldType.SeparatorFormField:
@@ -410,7 +417,7 @@ class InteractionHandler(object):
field_objs.append(AddressField(fields[i].prompt, view, fields[i].currentAddress))
elif fields[i].type == FormInputFieldType.ChoiceFormField:
choices = []
- for j in xrange(0, fields[i].count):
+ for j in range(0, fields[i].count):
choices.append(fields[i].choices[j])
field_objs.append(ChoiceField(fields[i].prompt, choices))
elif fields[i].type == FormInputFieldType.OpenFileNameFormField:
@@ -423,7 +430,7 @@ class InteractionHandler(object):
field_objs.append(LabelField(fields[i].prompt))
if not self.get_form_input(field_objs, title):
return False
- for i in xrange(0, count):
+ for i in range(0, count):
field_objs[i]._fill_core_result(fields[i])
return True
except:
@@ -783,8 +790,8 @@ def get_choice_input(prompt, title, choices):
0L
"""
choice_buf = (ctypes.c_char_p * len(choices))()
- for i in xrange(0, len(choices)):
- choice_buf[i] = str(choices[i])
+ for i in range(0, len(choices)):
+ choice_buf[i] = str(choices[i]).encode('charmap')
value = ctypes.c_ulonglong()
if not core.BNGetChoiceInput(value, prompt, title, choice_buf, len(choices)):
return None
@@ -839,11 +846,9 @@ def get_save_filename_input(prompt, ext="", default_name=""):
def get_directory_name_input(prompt, default_name=""):
"""
- ``get_directory_name_input`` prompts the user for a directory name to save as, optionally providing and
- default_name.
+ ``get_directory_name_input`` prompts the user for a directory name to save as, optionally providing a default_name.
- Note: This API function differently on the command line vs. the UI. In the UI a popup is used. On the commandline
- a simple text prompt is used. The ui uses the native window popup for file selection.
+ Note: This API function differently on the command line vs. the UI. In the UI a popup is used. On the commandline a simple text prompt is used. The ui uses the native window popup for file selection.
:param str prompt: Prompt to display.
:param str default_name: Optional, default directory name.
@@ -896,11 +901,11 @@ def get_form_input(fields, title):
3) Maybe
Options 1
>>> True
- >>> print tex_f.result, int_f.result, choice_f.result
+ >>> print(tex_f.result, int_f.result, choice_f.result)
Peter 1337 0
"""
value = (core.BNFormInputField * len(fields))()
- for i in xrange(0, len(fields)):
+ for i in range(0, len(fields)):
if isinstance(fields[i], str):
LabelField(fields[i])._fill_core_struct(value[i])
elif fields[i] is None:
@@ -909,7 +914,7 @@ def get_form_input(fields, title):
fields[i]._fill_core_struct(value[i])
if not core.BNGetFormInput(value, len(fields), title):
return False
- for i in xrange(0, len(fields)):
+ for i in range(0, len(fields)):
if not (isinstance(fields[i], str) or (fields[i] is None)):
fields[i]._get_result(value[i])
core.BNFreeFormInputResults(value, len(fields))
diff --git a/python/log.py b/python/log.py
index f7144183..4997b222 100644
--- a/python/log.py
+++ b/python/log.py
@@ -20,7 +20,8 @@
# Binary Ninja components
-import _binaryninjacore as core
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import LogLevel
_output_to_log = False
@@ -54,7 +55,7 @@ def log(level, text):
:param str text: message to print
:rtype: None
"""
- core.BNLog(level, "%s", str(text))
+ core.BNLog(level, '%s', text)
def log_debug(text):
@@ -69,7 +70,7 @@ def log_debug(text):
>>> log_debug("Hotdogs!")
Hotdogs!
"""
- core.BNLogDebug("%s", str(text))
+ core.BNLogDebug('%s', text)
def log_info(text):
@@ -84,7 +85,7 @@ def log_info(text):
Saucisson!
>>>
"""
- core.BNLogInfo("%s", str(text))
+ core.BNLogInfo('%s', text)
def log_warn(text):
@@ -100,7 +101,7 @@ def log_warn(text):
Chilidogs!
>>>
"""
- core.BNLogWarn("%s", str(text))
+ core.BNLogWarn('%s', text)
def log_error(text):
@@ -116,7 +117,7 @@ def log_error(text):
Spanferkel!
>>>
"""
- core.BNLogError("%s", str(text))
+ core.BNLogError('%s', text)
def log_alert(text):
@@ -132,10 +133,10 @@ def log_alert(text):
Kielbasa!
>>>
"""
- core.BNLogAlert("%s", str(text))
+ core.BNLogAlert('%s', text)
-def log_to_stdout(min_level):
+def log_to_stdout(min_level=LogLevel.InfoLog):
"""
``log_to_stdout`` redirects minimum log level to standard out.
diff --git a/python/lowlevelil.py b/python/lowlevelil.py
index ab6170a5..e714eb48 100644
--- a/python/lowlevelil.py
+++ b/python/lowlevelil.py
@@ -19,14 +19,16 @@
# IN THE SOFTWARE.
import ctypes
+import struct
# Binary Ninja components
-import _binaryninjacore as core
-from .enums import LowLevelILOperation, LowLevelILFlagCondition, InstructionTextTokenType
-import function
-import basicblock
-import mediumlevelil
-import struct
+import binaryninja
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import LowLevelILOperation, LowLevelILFlagCondition, InstructionTextTokenType
+from binaryninja import basicblock #required for LowLevelILBasicBlock
+
+# 2-3 compatibility
+from binaryninja import range
class LowLevelILLabel(object):
@@ -260,6 +262,7 @@ class LowLevelILInstruction(object):
LowLevelILOperation.LLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")],
LowLevelILOperation.LLIL_CALL: [("dest", "expr")],
LowLevelILOperation.LLIL_CALL_STACK_ADJUST: [("dest", "expr"), ("stack_adjustment", "int"), ("reg_stack_adjustments", "reg_stack_adjust")],
+ LowLevelILOperation.LLIL_TAILCALL: [("dest", "expr")],
LowLevelILOperation.LLIL_RET: [("dest", "expr")],
LowLevelILOperation.LLIL_NORET: [],
LowLevelILOperation.LLIL_IF: [("condition", "expr"), ("true", "int"), ("false", "int")],
@@ -328,6 +331,7 @@ class LowLevelILInstruction(object):
LowLevelILOperation.LLIL_FLAG_BIT_SSA: [("src", "flag_ssa"), ("bit", "int")],
LowLevelILOperation.LLIL_CALL_SSA: [("output", "expr"), ("dest", "expr"), ("stack", "expr"), ("param", "expr")],
LowLevelILOperation.LLIL_SYSCALL_SSA: [("output", "expr"), ("stack", "expr"), ("param", "expr")],
+ LowLevelILOperation.LLIL_TAILCALL_SSA: [("output", "expr"), ("dest", "expr"), ("stack", "expr"), ("param", "expr")],
LowLevelILOperation.LLIL_CALL_OUTPUT_SSA: [("dest_memory", "int"), ("dest", "reg_ssa_list")],
LowLevelILOperation.LLIL_CALL_STACK_SSA: [("src", "reg_ssa"), ("src_memory", "int")],
LowLevelILOperation.LLIL_CALL_PARAM: [("src", "expr_list")],
@@ -412,7 +416,7 @@ class LowLevelILInstruction(object):
operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
i += 1
value = []
- for j in xrange(count.value):
+ for j in range(count.value):
value.append(operand_list[j])
core.BNLowLevelILFreeOperandList(operand_list)
elif operand_type == "expr_list":
@@ -420,7 +424,7 @@ class LowLevelILInstruction(object):
operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
i += 1
value = []
- for j in xrange(count.value):
+ for j in range(count.value):
value.append(LowLevelILInstruction(func, operand_list[j]))
core.BNLowLevelILFreeOperandList(operand_list)
elif operand_type == "reg_or_flag_list":
@@ -428,7 +432,7 @@ class LowLevelILInstruction(object):
operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
i += 1
value = []
- for j in xrange(count.value):
+ for j in range(count.value):
if (operand_list[j] & (1 << 32)) != 0:
value.append(ILFlag(func.arch, operand_list[j] & 0xffffffff))
else:
@@ -439,7 +443,7 @@ class LowLevelILInstruction(object):
operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
i += 1
value = []
- for j in xrange(count.value / 2):
+ for j in range(count.value // 2):
reg = operand_list[j * 2]
reg_version = operand_list[(j * 2) + 1]
value.append(SSARegister(ILRegister(func.arch, reg), reg_version))
@@ -449,7 +453,7 @@ class LowLevelILInstruction(object):
operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
i += 1
value = []
- for j in xrange(count.value / 2):
+ for j in range(count.value // 2):
reg_stack = operand_list[j * 2]
reg_version = operand_list[(j * 2) + 1]
value.append(SSARegisterStack(ILRegisterStack(func.arch, reg_stack), reg_version))
@@ -459,7 +463,7 @@ class LowLevelILInstruction(object):
operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
i += 1
value = []
- for j in xrange(count.value / 2):
+ for j in range(count.value // 2):
flag = operand_list[j * 2]
flag_version = operand_list[(j * 2) + 1]
value.append(SSAFlag(ILFlag(func.arch, flag), flag_version))
@@ -469,7 +473,7 @@ class LowLevelILInstruction(object):
operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
i += 1
value = []
- for j in xrange(count.value / 2):
+ for j in range(count.value // 2):
if (operand_list[j * 2] & (1 << 32)) != 0:
reg_or_flag = ILFlag(func.arch, operand_list[j * 2] & 0xffffffff)
else:
@@ -482,7 +486,7 @@ class LowLevelILInstruction(object):
operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
i += 1
value = {}
- for j in xrange(count.value / 2):
+ for j in range(count.value // 2):
reg_stack = operand_list[j * 2]
adjust = operand_list[(j * 2) + 1]
if adjust & 0x80000000:
@@ -519,7 +523,7 @@ class LowLevelILInstruction(object):
self.expr_index, tokens, count):
return None
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
token_type = InstructionTextTokenType(tokens[i].type)
text = tokens[i].text
value = tokens[i].value
@@ -528,7 +532,7 @@ class LowLevelILInstruction(object):
context = tokens[i].context
confidence = tokens[i].confidence
address = tokens[i].address
- result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
+ result.append(binaryninja.function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
core.BNFreeInstructionText(tokens, count.value)
return result
@@ -550,7 +554,7 @@ class LowLevelILInstruction(object):
expr = self.function.get_medium_level_il_expr_index(self.expr_index)
if expr is None:
return None
- return mediumlevelil.MediumLevelILInstruction(self.function.medium_level_il, expr)
+ return binaryninja.mediumlevelil.MediumLevelILInstruction(self.function.medium_level_il, expr)
@property
def mapped_medium_level_il(self):
@@ -558,20 +562,20 @@ class LowLevelILInstruction(object):
expr = self.function.get_mapped_medium_level_il_expr_index(self.expr_index)
if expr is None:
return None
- return mediumlevelil.MediumLevelILInstruction(self.function.mapped_medium_level_il, expr)
+ return binaryninja.mediumlevelil.MediumLevelILInstruction(self.function.mapped_medium_level_il, expr)
@property
def value(self):
"""Value of expression if constant or a known value (read-only)"""
value = core.BNGetLowLevelILExprValue(self.function.handle, self.expr_index)
- result = function.RegisterValue(self.function.arch, value)
+ result = binaryninja.function.RegisterValue(self.function.arch, value)
return result
@property
def possible_values(self):
"""Possible values of expression using path-sensitive static data flow analysis (read-only)"""
value = core.BNGetLowLevelILPossibleExprValues(self.function.handle, self.expr_index)
- result = function.PossibleValueSet(self.function.arch, value)
+ result = binaryninja.function.PossibleValueSet(self.function.arch, value)
core.BNFreePossibleValueSet(value)
return result
@@ -601,74 +605,74 @@ class LowLevelILInstruction(object):
def get_reg_value(self, reg):
reg = self.function.arch.get_reg_index(reg)
value = core.BNGetLowLevelILRegisterValueAtInstruction(self.function.handle, reg, self.instr_index)
- result = function.RegisterValue(self.function.arch, value)
+ result = binaryninja.function.RegisterValue(self.function.arch, value)
return result
def get_reg_value_after(self, reg):
reg = self.function.arch.get_reg_index(reg)
value = core.BNGetLowLevelILRegisterValueAfterInstruction(self.function.handle, reg, self.instr_index)
- result = function.RegisterValue(self.function.arch, value)
+ result = binaryninja.function.RegisterValue(self.function.arch, value)
return result
def get_possible_reg_values(self, reg):
reg = self.function.arch.get_reg_index(reg)
value = core.BNGetLowLevelILPossibleRegisterValuesAtInstruction(self.function.handle, reg, self.instr_index)
- result = function.PossibleValueSet(self.function.arch, value)
+ result = binaryninja.function.PossibleValueSet(self.function.arch, value)
core.BNFreePossibleValueSet(value)
return result
def get_possible_reg_values_after(self, reg):
reg = self.function.arch.get_reg_index(reg)
value = core.BNGetLowLevelILPossibleRegisterValuesAfterInstruction(self.function.handle, reg, self.instr_index)
- result = function.PossibleValueSet(self.function.arch, value)
+ result = binaryninja.function.PossibleValueSet(self.function.arch, value)
core.BNFreePossibleValueSet(value)
return result
def get_flag_value(self, flag):
flag = self.function.arch.get_flag_index(flag)
value = core.BNGetLowLevelILFlagValueAtInstruction(self.function.handle, flag, self.instr_index)
- result = function.RegisterValue(self.function.arch, value)
+ result = binaryninja.function.RegisterValue(self.function.arch, value)
return result
def get_flag_value_after(self, flag):
flag = self.function.arch.get_flag_index(flag)
value = core.BNGetLowLevelILFlagValueAfterInstruction(self.function.handle, flag, self.instr_index)
- result = function.RegisterValue(self.function.arch, value)
+ result = binaryninja.function.RegisterValue(self.function.arch, value)
return result
def get_possible_flag_values(self, flag):
flag = self.function.arch.get_flag_index(flag)
value = core.BNGetLowLevelILPossibleFlagValuesAtInstruction(self.function.handle, flag, self.instr_index)
- result = function.PossibleValueSet(self.function.arch, value)
+ result = binaryninja.function.PossibleValueSet(self.function.arch, value)
core.BNFreePossibleValueSet(value)
return result
def get_possible_flag_values_after(self, flag):
flag = self.function.arch.get_flag_index(flag)
value = core.BNGetLowLevelILPossibleFlagValuesAfterInstruction(self.function.handle, flag, self.instr_index)
- result = function.PossibleValueSet(self.function.arch, value)
+ result = binaryninja.function.PossibleValueSet(self.function.arch, value)
core.BNFreePossibleValueSet(value)
return result
def get_stack_contents(self, offset, size):
value = core.BNGetLowLevelILStackContentsAtInstruction(self.function.handle, offset, size, self.instr_index)
- result = function.RegisterValue(self.function.arch, value)
+ result = binaryninja.function.RegisterValue(self.function.arch, value)
return result
def get_stack_contents_after(self, offset, size):
value = core.BNGetLowLevelILStackContentsAfterInstruction(self.function.handle, offset, size, self.instr_index)
- result = function.RegisterValue(self.function.arch, value)
+ result = binaryninja.function.RegisterValue(self.function.arch, value)
return result
def get_possible_stack_contents(self, offset, size):
value = core.BNGetLowLevelILPossibleStackContentsAtInstruction(self.function.handle, offset, size, self.instr_index)
- result = function.PossibleValueSet(self.function.arch, value)
+ result = binaryninja.function.PossibleValueSet(self.function.arch, value)
core.BNFreePossibleValueSet(value)
return result
def get_possible_stack_contents_after(self, offset, size):
value = core.BNGetLowLevelILPossibleStackContentsAfterInstruction(self.function.handle, offset, size, self.instr_index)
- result = function.PossibleValueSet(self.function.arch, value)
+ result = binaryninja.function.PossibleValueSet(self.function.arch, value)
core.BNFreePossibleValueSet(value)
return result
@@ -692,7 +696,7 @@ class LowLevelILExpr(object):
class LowLevelILFunction(object):
"""
- ``class LowLevelILFunction`` contains the list of LowLevelILExpr objects that make up a function. LowLevelILExpr
+ ``class LowLevelILFunction`` contains the list of LowLevelILExpr objects that make up a binaryninja.function. LowLevelILExpr
objects can be added to the LowLevelILFunction by calling ``append`` and passing the result of the various class
methods which return LowLevelILExpr objects.
@@ -775,7 +779,7 @@ class LowLevelILFunction(object):
view = None
if self.source_function is not None:
view = self.source_function.view
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(LowLevelILBasicBlock(view, core.BNNewBasicBlockReference(blocks[i]), self))
core.BNFreeBasicBlockList(blocks, count.value)
return result
@@ -802,7 +806,7 @@ class LowLevelILFunction(object):
result = core.BNGetMediumLevelILForLowLevelIL(self.handle)
if not result:
return None
- return mediumlevelil.MediumLevelILFunction(self.arch, result, self.source_function)
+ return binaryninja.mediumlevelil.MediumLevelILFunction(self.arch, result, self.source_function)
@property
def mapped_medium_level_il(self):
@@ -812,7 +816,7 @@ class LowLevelILFunction(object):
result = core.BNGetMappedMediumLevelIL(self.handle)
if not result:
return None
- return mediumlevelil.MediumLevelILFunction(self.arch, result, self.source_function)
+ return binaryninja.mediumlevelil.MediumLevelILFunction(self.arch, result, self.source_function)
def __setattr__(self, name, value):
try:
@@ -842,7 +846,7 @@ class LowLevelILFunction(object):
if self.source_function is not None:
view = self.source_function.view
try:
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
yield LowLevelILBasicBlock(view, core.BNNewBasicBlockReference(blocks[i]), self)
finally:
core.BNFreeBasicBlockList(blocks, count.value)
@@ -860,7 +864,7 @@ class LowLevelILFunction(object):
def set_indirect_branches(self, branches):
branch_list = (core.BNArchitectureAndAddress * len(branches))()
- for i in xrange(len(branches)):
+ for i in range(len(branches)):
branch_list[i].arch = branches[i][0].handle
branch_list[i].address = branches[i][1]
core.BNLowLevelILSetIndirectBranches(self.handle, branch_list, len(branches))
@@ -1592,10 +1596,20 @@ class LowLevelILFunction(object):
"""
return self.expr(LowLevelILOperation.LLIL_CALL_STACK_ADJUST, dest.index, stack_adjust)
+ def tailcall(self, dest):
+ """
+ ``tailcall`` returns an expression which jumps (branches) to the expression ``dest``
+
+ :param LowLevelILExpr dest: the expression to jump to
+ :return: The expression ``tailcall(dest)``
+ :rtype: LowLevelILExpr
+ """
+ return self.expr(LowLevelILOperation.LLIL_TAILCALL, dest.index)
+
def ret(self, dest):
"""
``ret`` returns an expression which jumps (branches) to the expression ``dest``. ``ret`` is a special alias for
- jump that makes the disassembler top disassembling.
+ jump that makes the disassembler stop disassembling.
:param LowLevelILExpr dest: the expression to jump to
:return: The expression ``jump(dest)``
@@ -1797,8 +1811,9 @@ class LowLevelILFunction(object):
param_list = []
for param in params:
param_list.append(param.index)
- return self.expr(LowLevelILOperation.LLIL_INTRINSIC, len(outputs), self.add_operand_list(output_list),
- self.arch.get_intrinsic_index(intrinsic), len(params), self.add_operand_list(param_list), flags = flags)
+ call_param = self.expr(LowLevelILOperation.LLIL_CALL_PARAM, len(params), self.add_operand_list(param_list).index)
+ return self.expr(LowLevelILOperation.LLIL_INTRINSIC, len(outputs), self.add_operand_list(output_list).index,
+ self.arch.get_intrinsic_index(intrinsic), call_param.index, flags = flags)
def breakpoint(self):
"""
@@ -2165,7 +2180,7 @@ class LowLevelILFunction(object):
:rtype: LowLevelILExpr
"""
label_list = (ctypes.POINTER(core.BNLowLevelILLabel) * len(labels))()
- for i in xrange(len(labels)):
+ for i in range(len(labels)):
label_list[i] = labels[i].handle
return LowLevelILExpr(core.BNLowLevelILAddLabelList(self.handle, label_list, len(labels)))
@@ -2178,7 +2193,7 @@ class LowLevelILFunction(object):
:rtype: LowLevelILExpr
"""
operand_list = (ctypes.c_ulonglong * len(operands))()
- for i in xrange(len(operands)):
+ for i in range(len(operands)):
operand_list[i] = operands[i]
return LowLevelILExpr(core.BNLowLevelILAddOperandList(self.handle, operand_list, len(operands)))
@@ -2261,7 +2276,7 @@ class LowLevelILFunction(object):
count = ctypes.c_ulonglong()
instrs = core.BNGetLowLevelILSSARegisterUses(self.handle, reg, reg_ssa.version, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(instrs[i])
core.BNFreeILInstructionList(instrs)
return result
@@ -2271,7 +2286,7 @@ class LowLevelILFunction(object):
count = ctypes.c_ulonglong()
instrs = core.BNGetLowLevelILSSAFlagUses(self.handle, flag, flag_ssa.version, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(instrs[i])
core.BNFreeILInstructionList(instrs)
return result
@@ -2280,7 +2295,7 @@ class LowLevelILFunction(object):
count = ctypes.c_ulonglong()
instrs = core.BNGetLowLevelILSSAMemoryUses(self.handle, index, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(instrs[i])
core.BNFreeILInstructionList(instrs)
return result
@@ -2288,13 +2303,13 @@ class LowLevelILFunction(object):
def get_ssa_reg_value(self, reg_ssa):
reg = self.arch.get_reg_index(reg_ssa.reg)
value = core.BNGetLowLevelILSSARegisterValue(self.handle, reg, reg_ssa.version)
- result = function.RegisterValue(self.arch, value)
+ result = binaryninja.function.RegisterValue(self.arch, value)
return result
def get_ssa_flag_value(self, flag_ssa):
flag = self.arch.get_flag_index(flag_ssa.flag)
value = core.BNGetLowLevelILSSAFlagValue(self.handle, flag, flag_ssa.version)
- result = function.RegisterValue(self.arch, value)
+ result = binaryninja.function.RegisterValue(self.arch, value)
return result
def get_medium_level_il_instruction_index(self, instr):
@@ -2340,7 +2355,7 @@ class LowLevelILBasicBlock(basicblock.BasicBlock):
self.il_function = owner
def __iter__(self):
- for idx in xrange(self.start, self.end):
+ for idx in range(self.start, self.end):
yield self.il_function[idx]
def __getitem__(self, idx):
diff --git a/python/mainthread.py b/python/mainthread.py
index 3e12bd65..5b0cd53c 100644
--- a/python/mainthread.py
+++ b/python/mainthread.py
@@ -19,8 +19,8 @@
# IN THE SOFTWARE.
# Binary Ninja components
-import _binaryninjacore as core
-import scriptingprovider
+from binaryninja import _binaryninjacore as core
+from binaryninja import scriptingprovider
def execute_on_main_thread(func):
diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py
index d87b5bf7..cfa8f900 100644
--- a/python/mediumlevelil.py
+++ b/python/mediumlevelil.py
@@ -19,15 +19,18 @@
# IN THE SOFTWARE.
import ctypes
+import struct
# Binary Ninja components
-import _binaryninjacore as core
-from .enums import MediumLevelILOperation, InstructionTextTokenType, ILBranchDependence
-import function
-import basicblock
-import lowlevelil
-import types
-import struct
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import MediumLevelILOperation, InstructionTextTokenType, ILBranchDependence
+from binaryninja import basicblock #required for MediumLevelILBasicBlock argument
+from binaryninja import function
+from binaryninja import types
+from binaryninja import lowlevelil
+
+# 2-3 compatibility
+from binaryninja import range
class SSAVariable(object):
@@ -148,6 +151,8 @@ class MediumLevelILInstruction(object):
MediumLevelILOperation.MLIL_ADD_OVERFLOW: [("left", "expr"), ("right", "expr")],
MediumLevelILOperation.MLIL_SYSCALL: [("output", "var_list"), ("params", "expr_list")],
MediumLevelILOperation.MLIL_SYSCALL_UNTYPED: [("output", "expr"), ("params", "expr"), ("stack", "expr")],
+ MediumLevelILOperation.MLIL_TAILCALL: [("output", "var_list"), ("dest", "expr"), ("params", "expr_list")],
+ MediumLevelILOperation.MLIL_TAILCALL_UNTYPED: [("output", "expr"), ("dest", "expr"), ("params", "expr"), ("stack", "expr")],
MediumLevelILOperation.MLIL_BP: [],
MediumLevelILOperation.MLIL_TRAP: [("vector", "int")],
MediumLevelILOperation.MLIL_INTRINSIC: [("output", "var_list"), ("intrinsic", "intrinsic"), ("params", "expr_list")],
@@ -193,6 +198,8 @@ class MediumLevelILInstruction(object):
MediumLevelILOperation.MLIL_CALL_UNTYPED_SSA: [("output", "expr"), ("dest", "expr"), ("params", "expr"), ("stack", "expr")],
MediumLevelILOperation.MLIL_SYSCALL_SSA: [("output", "expr"), ("params", "expr_list"), ("src_memory", "int")],
MediumLevelILOperation.MLIL_SYSCALL_UNTYPED_SSA: [("output", "expr"), ("params", "expr"), ("stack", "expr")],
+ MediumLevelILOperation.MLIL_TAILCALL_SSA: [("output", "expr"), ("dest", "expr"), ("params", "expr_list"), ("src_memory", "int")],
+ MediumLevelILOperation.MLIL_TAILCALL_UNTYPED_SSA: [("output", "expr"), ("dest", "expr"), ("params", "expr"), ("stack", "expr")],
MediumLevelILOperation.MLIL_CALL_OUTPUT_SSA: [("dest_memory", "int"), ("dest", "var_ssa_list")],
MediumLevelILOperation.MLIL_CALL_PARAM_SSA: [("src_memory", "int"), ("src", "var_ssa_list")],
MediumLevelILOperation.MLIL_LOAD_SSA: [("src", "expr"), ("src_memory", "int")],
@@ -252,7 +259,7 @@ class MediumLevelILInstruction(object):
count = ctypes.c_ulonglong()
operand_list = core.BNMediumLevelILGetOperandList(func.handle, self.expr_index, i, count)
value = []
- for j in xrange(count.value):
+ for j in range(count.value):
value.append(operand_list[j])
core.BNMediumLevelILFreeOperandList(operand_list)
elif operand_type == "var_list":
@@ -260,7 +267,7 @@ class MediumLevelILInstruction(object):
operand_list = core.BNMediumLevelILGetOperandList(func.handle, self.expr_index, i, count)
i += 1
value = []
- for j in xrange(count.value):
+ for j in range(count.value):
value.append(function.Variable.from_identifier(self.function.source_function, operand_list[j]))
core.BNMediumLevelILFreeOperandList(operand_list)
elif operand_type == "var_ssa_list":
@@ -268,7 +275,7 @@ class MediumLevelILInstruction(object):
operand_list = core.BNMediumLevelILGetOperandList(func.handle, self.expr_index, i, count)
i += 1
value = []
- for j in xrange(count.value / 2):
+ for j in range(count.value // 2):
var_id = operand_list[j * 2]
var_version = operand_list[(j * 2) + 1]
value.append(SSAVariable(function.Variable.from_identifier(self.function.source_function,
@@ -279,7 +286,7 @@ class MediumLevelILInstruction(object):
operand_list = core.BNMediumLevelILGetOperandList(func.handle, self.expr_index, i, count)
i += 1
value = []
- for j in xrange(count.value):
+ for j in range(count.value):
value.append(MediumLevelILInstruction(func, operand_list[j]))
core.BNMediumLevelILFreeOperandList(operand_list)
self.operands.append(value)
@@ -313,7 +320,7 @@ class MediumLevelILInstruction(object):
self.expr_index, tokens, count):
return None
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
token_type = InstructionTextTokenType(tokens[i].type)
text = tokens[i].text
value = tokens[i].value
@@ -359,7 +366,7 @@ class MediumLevelILInstruction(object):
count = ctypes.c_ulonglong()
deps = core.BNGetAllMediumLevelILBranchDependence(self.function.handle, self.instr_index, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result[deps[i].branch] = ILBranchDependence(deps[i].dependence)
core.BNFreeILBranchDependenceList(deps)
return result
@@ -410,11 +417,12 @@ class MediumLevelILInstruction(object):
return [self.dest]
elif self.operation in [MediumLevelILOperation.MLIL_SET_VAR_SPLIT, MediumLevelILOperation.MLIL_SET_VAR_SPLIT_SSA]:
return [self.high, self.low]
- elif self.operation in [MediumLevelILOperation.MLIL_CALL, MediumLevelILOperation.MLIL_SYSCALL]:
+ elif self.operation in [MediumLevelILOperation.MLIL_CALL, MediumLevelILOperation.MLIL_SYSCALL, MediumLevelILOperation.MLIL_TAILCALL]:
return self.output
- elif self.operation in [MediumLevelILOperation.MLIL_CALL_UNTYPED, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED,
+ elif self.operation in [MediumLevelILOperation.MLIL_CALL_UNTYPED, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED, MediumLevelILOperation.MLIL_TAILCALL_UNTYPED,
MediumLevelILOperation.MLIL_CALL_SSA, MediumLevelILOperation.MLIL_CALL_UNTYPED_SSA,
- MediumLevelILOperation.MLIL_SYSCALL_SSA, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED_SSA]:
+ MediumLevelILOperation.MLIL_SYSCALL_SSA, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED_SSA,
+ MediumLevelILOperation.MLIL_TAILCALL_SSA, MediumLevelILOperation.MLIL_TAILCALL_UNTYPED_SSA]:
return self.output.vars_written
elif self.operation in [MediumLevelILOperation.MLIL_CALL_OUTPUT, MediumLevelILOperation.MLIL_CALL_OUTPUT_SSA]:
return self.dest
@@ -430,14 +438,14 @@ class MediumLevelILInstruction(object):
elif self.operation in [MediumLevelILOperation.MLIL_SET_VAR_SSA_FIELD,
MediumLevelILOperation.MLIL_SET_VAR_ALIASED_FIELD]:
return [self.prev] + self.src.vars_read
- elif self.operation in [MediumLevelILOperation.MLIL_CALL, MediumLevelILOperation.MLIL_SYSCALL,
- MediumLevelILOperation.MLIL_CALL_SSA, MediumLevelILOperation.MLIL_SYSCALL_SSA]:
+ elif self.operation in [MediumLevelILOperation.MLIL_CALL, MediumLevelILOperation.MLIL_SYSCALL, MediumLevelILOperation.MLIL_TAILCALL,
+ MediumLevelILOperation.MLIL_CALL_SSA, MediumLevelILOperation.MLIL_SYSCALL_SSA, MediumLevelILOperation.MLIL_TAILCALL_SSA]:
result = []
for param in self.params:
result += param.vars_read
return result
- elif self.operation in [MediumLevelILOperation.MLIL_CALL_UNTYPED, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED,
- MediumLevelILOperation.MLIL_CALL_UNTYPED_SSA, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED_SSA]:
+ elif self.operation in [MediumLevelILOperation.MLIL_CALL_UNTYPED, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED, MediumLevelILOperation.MLIL_TAILCALL_UNTYPED,
+ MediumLevelILOperation.MLIL_CALL_UNTYPED_SSA, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED_SSA, MediumLevelILOperation.MLIL_TAILCALL_UNTYPED_SSA]:
return self.params.vars_read
elif self.operation in [MediumLevelILOperation.MLIL_CALL_PARAM, MediumLevelILOperation.MLIL_CALL_PARAM_SSA,
MediumLevelILOperation.MLIL_VAR_PHI]:
@@ -591,7 +599,7 @@ class MediumLevelILExpr(object):
class MediumLevelILFunction(object):
"""
- ``class MediumLevelILFunction`` contains the list of MediumLevelILExpr objects that make up a function. MediumLevelILExpr
+ ``class MediumLevelILFunction`` contains the list of MediumLevelILExpr objects that make up a binaryninja.function. MediumLevelILExpr
objects can be added to the MediumLevelILFunction by calling ``append`` and passing the result of the various class
methods which return MediumLevelILExpr objects.
"""
@@ -642,7 +650,7 @@ class MediumLevelILFunction(object):
view = None
if self.source_function is not None:
view = self.source_function.view
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(MediumLevelILBasicBlock(view, core.BNNewBasicBlockReference(blocks[i]), self))
core.BNFreeBasicBlockList(blocks, count.value)
return result
@@ -699,7 +707,7 @@ class MediumLevelILFunction(object):
if self.source_function is not None:
view = self.source_function.view
try:
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
yield MediumLevelILBasicBlock(view, core.BNNewBasicBlockReference(blocks[i]), self)
finally:
core.BNFreeBasicBlockList(blocks, count.value)
@@ -770,7 +778,7 @@ class MediumLevelILFunction(object):
:rtype: MediumLevelILExpr
"""
label_list = (ctypes.POINTER(core.BNMediumLevelILLabel) * len(labels))()
- for i in xrange(len(labels)):
+ for i in range(len(labels)):
label_list[i] = labels[i].handle
return MediumLevelILExpr(core.BNMediumLevelILAddLabelList(self.handle, label_list, len(labels)))
@@ -783,7 +791,7 @@ class MediumLevelILFunction(object):
:rtype: MediumLevelILExpr
"""
operand_list = (ctypes.c_ulonglong * len(operands))()
- for i in xrange(len(operands)):
+ for i in range(len(operands)):
operand_list[i] = operands[i]
return MediumLevelILExpr(core.BNMediumLevelILAddOperandList(self.handle, operand_list, len(operands)))
@@ -837,7 +845,7 @@ class MediumLevelILFunction(object):
var_data.storage = ssa_var.var.storage
instrs = core.BNGetMediumLevelILSSAVarUses(self.handle, var_data, ssa_var.version, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(instrs[i])
core.BNFreeILInstructionList(instrs)
return result
@@ -846,7 +854,7 @@ class MediumLevelILFunction(object):
count = ctypes.c_ulonglong()
instrs = core.BNGetMediumLevelILSSAMemoryUses(self.handle, version, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(instrs[i])
core.BNFreeILInstructionList(instrs)
return result
@@ -873,7 +881,7 @@ class MediumLevelILFunction(object):
var_data.storage = var.storage
instrs = core.BNGetMediumLevelILVariableDefinitions(self.handle, var_data, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(instrs[i])
core.BNFreeILInstructionList(instrs)
return result
@@ -886,7 +894,7 @@ class MediumLevelILFunction(object):
var_data.storage = var.storage
instrs = core.BNGetMediumLevelILVariableUses(self.handle, var_data, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(instrs[i])
core.BNFreeILInstructionList(instrs)
return result
@@ -931,7 +939,7 @@ class MediumLevelILBasicBlock(basicblock.BasicBlock):
self.il_function = owner
def __iter__(self):
- for idx in xrange(self.start, self.end):
+ for idx in range(self.start, self.end):
yield self.il_function[idx]
def __getitem__(self, idx):
diff --git a/python/metadata.py b/python/metadata.py
index 554bbcf4..606e4ceb 100644
--- a/python/metadata.py
+++ b/python/metadata.py
@@ -19,11 +19,16 @@
# IN THE SOFTWARE.
+from __future__ import absolute_import
import ctypes
# Binary Ninja components
-import _binaryninjacore as core
-from enums import MetadataType
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import MetadataType
+
+# 2-3 compatibility
+from binaryninja import range
+from binaryninja import pyNativeStr
class Metadata(object):
@@ -39,7 +44,7 @@ class Metadata(object):
self.handle = core.BNCreateMetadataBooleanData(value)
elif isinstance(value, str):
if raw:
- buffer = (ctypes.c_ubyte * len(value)).from_buffer_copy(value)
+ buffer = (ctypes.c_ubyte * len(value)).from_buffer_copy(value.encode('charmap'))
self.handle = core.BNCreateMetadataRawData(buffer, len(value))
else:
self.handle = core.BNCreateMetadataStringData(value)
@@ -137,13 +142,16 @@ class Metadata(object):
def __iter__(self):
if self.is_array:
- for i in xrange(core.BNMetadataSize(self.handle)):
+ for i in range(core.BNMetadataSize(self.handle)):
yield Metadata(handle=core.BNMetadataGetForIndex(self.handle, i)).value
elif self.is_dict:
result = core.BNMetadataGetValueStore(self.handle)
try:
- for i in xrange(result.contents.size):
- yield result.contents.keys[i]
+ for i in range(result.contents.size):
+ if isinstance(result.contents.keys[i], bytes):
+ yield str(pyNativeStr(result.contents.keys[i]))
+ else:
+ yield result.contents.keys[i]
finally:
core.BNFreeMetadataValueStore(result)
else:
@@ -168,13 +176,13 @@ class Metadata(object):
def __str__(self):
if self.is_string:
- return core.BNMetadataGetString(self.handle)
+ return str(core.BNMetadataGetString(self.handle))
if self.is_raw:
length = ctypes.c_ulonglong()
length.value = 0
native_list = core.BNMetadataGetRaw(self.handle, ctypes.byref(length))
out_list = []
- for i in xrange(length.value):
+ for i in range(length.value):
out_list.append(native_list[i])
core.BNFreeMetadataRaw(native_list)
return ''.join(chr(a) for a in out_list)
diff --git a/python/platform.py b/python/platform.py
index a79e3b9a..9a5f70df 100644
--- a/python/platform.py
+++ b/python/platform.py
@@ -21,42 +21,45 @@
import ctypes
# Binary Ninja components
-import _binaryninjacore as core
-import startup
-import architecture
-import callingconvention
-import types
+import binaryninja
+from binaryninja import _binaryninjacore as core
+from binaryninja import types
+
+# 2-3 compatibility
+from binaryninja import range
+from binaryninja import with_metaclass
class _PlatformMetaClass(type):
+
@property
def list(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
platforms = core.BNGetPlatformList(count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(Platform(None, core.BNNewPlatformReference(platforms[i])))
core.BNFreePlatformList(platforms, count.value)
return result
@property
def os_list(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
platforms = core.BNGetPlatformOSList(count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(str(platforms[i]))
core.BNFreePlatformOSList(platforms, count.value)
return result
def __iter__(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
platforms = core.BNGetPlatformList(count)
try:
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
yield Platform(None, core.BNNewPlatformReference(platforms[i]))
finally:
core.BNFreePlatformList(platforms, count.value)
@@ -68,14 +71,14 @@ class _PlatformMetaClass(type):
raise AttributeError("attribute '%s' is read only" % name)
def __getitem__(cls, value):
- startup._init_plugins()
+ binaryninja._init_plugins()
platform = core.BNGetPlatformByName(str(value))
if platform is None:
raise KeyError("'%s' is not a valid platform" % str(value))
return Platform(None, platform)
def get_list(cls, os = None, arch = None):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
if os is None:
platforms = core.BNGetPlatformList(count)
@@ -84,18 +87,17 @@ class _PlatformMetaClass(type):
else:
platforms = core.BNGetPlatformListByArchitecture(os, arch.handle)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(Platform(None, core.BNNewPlatformReference(platforms[i])))
core.BNFreePlatformList(platforms, count.value)
return result
-class Platform(object):
+class Platform(with_metaclass(_PlatformMetaClass, object)):
"""
``class Platform`` contains all information releated to the execution environment of the binary, mainly the
calling conventions used.
"""
- __metaclass__ = _PlatformMetaClass
name = None
def __init__(self, arch, handle = None):
@@ -105,7 +107,7 @@ class Platform(object):
else:
self.handle = handle
self.__dict__["name"] = core.BNGetPlatformName(self.handle)
- self.arch = architecture.CoreArchitecture._from_cache(core.BNGetPlatformArchitecture(self.handle))
+ self.arch = binaryninja.architecture.CoreArchitecture._from_cache(core.BNGetPlatformArchitecture(self.handle))
def __del__(self):
core.BNFreePlatform(self.handle)
@@ -121,6 +123,11 @@ class Platform(object):
return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
@property
+ def list(self):
+ """Allow tab completion to discover metaclass list property"""
+ pass
+
+ @property
def default_calling_convention(self):
"""
Default calling convention.
@@ -132,7 +139,7 @@ class Platform(object):
result = core.BNGetPlatformDefaultCallingConvention(self.handle)
if result is None:
return None
- return callingconvention.CallingConvention(handle=result)
+ return binaryninja.callingconvention.CallingConvention(handle=result)
@default_calling_convention.setter
def default_calling_convention(self, value):
@@ -150,7 +157,7 @@ class Platform(object):
result = core.BNGetPlatformCdeclCallingConvention(self.handle)
if result is None:
return None
- return callingconvention.CallingConvention(handle=result)
+ return binaryninja.callingconvention.CallingConvention(handle=result)
@cdecl_calling_convention.setter
def cdecl_calling_convention(self, value):
@@ -168,7 +175,7 @@ class Platform(object):
result = core.BNGetPlatformStdcallCallingConvention(self.handle)
if result is None:
return None
- return callingconvention.CallingConvention(handle=result)
+ return binaryninja.callingconvention.CallingConvention(handle=result)
@stdcall_calling_convention.setter
def stdcall_calling_convention(self, value):
@@ -186,7 +193,7 @@ class Platform(object):
result = core.BNGetPlatformFastcallCallingConvention(self.handle)
if result is None:
return None
- return callingconvention.CallingConvention(handle=result)
+ return binaryninja.callingconvention.CallingConvention(handle=result)
@fastcall_calling_convention.setter
def fastcall_calling_convention(self, value):
@@ -204,7 +211,7 @@ class Platform(object):
result = core.BNGetPlatformSystemCallConvention(self.handle)
if result is None:
return None
- return callingconvention.CallingConvention(handle=result)
+ return binaryninja.callingconvention.CallingConvention(handle=result)
@system_call_convention.setter
def system_call_convention(self, value):
@@ -221,8 +228,8 @@ class Platform(object):
count = ctypes.c_ulonglong()
cc = core.BNGetPlatformCallingConventions(self.handle, count)
result = []
- for i in xrange(0, count.value):
- result.append(callingconvention.CallingConvention(handle=core.BNNewCallingConventionReference(cc[i])))
+ for i in range(0, count.value):
+ result.append(binaryninja.callingconvention.CallingConvention(handle=core.BNNewCallingConventionReference(cc[i])))
core.BNFreeCallingConventionList(cc, count.value)
return result
@@ -232,7 +239,7 @@ class Platform(object):
count = ctypes.c_ulonglong(0)
type_list = core.BNGetPlatformTypes(self.handle, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
name = types.QualifiedName._from_core_struct(type_list[i].name)
result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self)
core.BNFreeTypeList(type_list, count.value)
@@ -244,7 +251,7 @@ class Platform(object):
count = ctypes.c_ulonglong(0)
type_list = core.BNGetPlatformVariables(self.handle, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
name = types.QualifiedName._from_core_struct(type_list[i].name)
result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self)
core.BNFreeTypeList(type_list, count.value)
@@ -256,7 +263,7 @@ class Platform(object):
count = ctypes.c_ulonglong(0)
type_list = core.BNGetPlatformFunctions(self.handle, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
name = types.QualifiedName._from_core_struct(type_list[i].name)
result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self)
core.BNFreeTypeList(type_list, count.value)
@@ -268,7 +275,7 @@ class Platform(object):
count = ctypes.c_ulonglong(0)
call_list = core.BNGetPlatformSystemCalls(self.handle, count)
result = {}
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
name = types.QualifiedName._from_core_struct(call_list[i].name)
t = types.Type(core.BNNewTypeReference(call_list[i].type), platform = self)
result[call_list[i].number] = (name, t)
@@ -383,8 +390,8 @@ class Platform(object):
if filename is None:
filename = "input"
dir_buf = (ctypes.c_char_p * len(include_dirs))()
- for i in xrange(0, len(include_dirs)):
- dir_buf[i] = str(include_dirs[i])
+ for i in range(0, len(include_dirs)):
+ dir_buf[i] = include_dirs[i].encode('charmap')
parse = core.BNTypeParserResult()
errors = ctypes.c_char_p()
result = core.BNParseTypesFromSource(self.handle, source, filename, parse, errors, dir_buf,
@@ -396,13 +403,13 @@ class Platform(object):
type_dict = {}
variables = {}
functions = {}
- for i in xrange(0, parse.typeCount):
+ for i in range(0, parse.typeCount):
name = types.QualifiedName._from_core_struct(parse.types[i].name)
type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type), platform = self)
- for i in xrange(0, parse.variableCount):
+ for i in range(0, parse.variableCount):
name = types.QualifiedName._from_core_struct(parse.variables[i].name)
variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type), platform = self)
- for i in xrange(0, parse.functionCount):
+ for i in range(0, parse.functionCount):
name = types.QualifiedName._from_core_struct(parse.functions[i].name)
functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type), platform = self)
core.BNFreeTypeParserResult(parse)
@@ -429,8 +436,8 @@ class Platform(object):
>>>
"""
dir_buf = (ctypes.c_char_p * len(include_dirs))()
- for i in xrange(0, len(include_dirs)):
- dir_buf[i] = str(include_dirs[i])
+ for i in range(0, len(include_dirs)):
+ dir_buf[i] = include_dirs[i].encode('charmap')
parse = core.BNTypeParserResult()
errors = ctypes.c_char_p()
result = core.BNParseTypesFromSourceFile(self.handle, filename, parse, errors, dir_buf,
@@ -442,13 +449,13 @@ class Platform(object):
type_dict = {}
variables = {}
functions = {}
- for i in xrange(0, parse.typeCount):
+ for i in range(0, parse.typeCount):
name = types.QualifiedName._from_core_struct(parse.types[i].name)
type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type), platform = self)
- for i in xrange(0, parse.variableCount):
+ for i in range(0, parse.variableCount):
name = types.QualifiedName._from_core_struct(parse.variables[i].name)
variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type), platform = self)
- for i in xrange(0, parse.functionCount):
+ for i in range(0, parse.functionCount):
name = types.QualifiedName._from_core_struct(parse.functions[i].name)
functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type), platform = self)
core.BNFreeTypeParserResult(parse)
diff --git a/python/plugin.py b/python/plugin.py
index c6cd9fc0..4d9add9c 100644
--- a/python/plugin.py
+++ b/python/plugin.py
@@ -23,15 +23,16 @@ import ctypes
import threading
# Binary Ninja components
-import _binaryninjacore as core
-from enums import PluginCommandType
-import startup
-import filemetadata
-import binaryview
-import function
-import log
-import lowlevelil
-import mediumlevelil
+import binaryninja
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import PluginCommandType
+from binaryninja import filemetadata
+from binaryninja import binaryview
+from binaryninja import function
+
+# 2-3 compatibility
+from binaryninja import range
+from binaryninja import with_metaclass
class PluginCommandContext(object):
@@ -46,21 +47,21 @@ class PluginCommandContext(object):
class _PluginCommandMetaClass(type):
@property
def list(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
commands = core.BNGetAllPluginCommands(count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(PluginCommand(commands[i]))
core.BNFreePluginCommandList(commands)
return result
def __iter__(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
commands = core.BNGetAllPluginCommands(count)
try:
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
yield PluginCommand(commands[i])
finally:
core.BNFreePluginCommandList(commands)
@@ -72,9 +73,8 @@ class _PluginCommandMetaClass(type):
raise AttributeError("attribute '%s' is read only" % name)
-class PluginCommand(object):
+class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)):
_registered_commands = []
- __metaclass__ = _PluginCommandMetaClass
def __init__(self, cmd):
self.command = core.BNPluginCommand()
@@ -83,42 +83,47 @@ class PluginCommand(object):
self.description = str(cmd.description)
self.type = PluginCommandType(cmd.type)
+ @property
+ def list(self):
+ """Allow tab completion to discover metaclass list property"""
+ pass
+
@classmethod
def _default_action(cls, view, action):
try:
- file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
- view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
+ file_metadata = binaryninja.filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
action(view_obj)
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
@classmethod
def _address_action(cls, view, addr, action):
try:
- file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
- view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
+ file_metadata = binaryninja.filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
action(view_obj, addr)
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
@classmethod
def _range_action(cls, view, addr, length, action):
try:
- file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
- view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
+ file_metadata = binaryninja.filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
action(view_obj, addr, length)
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
@classmethod
def _function_action(cls, view, func, action):
try:
- file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
- view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
+ file_metadata = binaryninja.filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
func_obj = function.Function(view_obj, core.BNNewFunctionReference(func))
action(view_obj, func_obj)
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
@classmethod
def _low_level_il_function_action(cls, view, func, action):
@@ -126,10 +131,10 @@ class PluginCommand(object):
file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func))
- func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner)
+ func_obj = binaryninja.lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner)
action(view_obj, func_obj)
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
@classmethod
def _low_level_il_instruction_action(cls, view, func, instr, action):
@@ -137,10 +142,10 @@ class PluginCommand(object):
file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func))
- func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner)
+ func_obj = binaryninja.lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner)
action(view_obj, func_obj[instr])
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
@classmethod
def _medium_level_il_function_action(cls, view, func, action):
@@ -148,10 +153,10 @@ class PluginCommand(object):
file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func))
- func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner)
+ func_obj = binaryninja.mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner)
action(view_obj, func_obj)
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
@classmethod
def _medium_level_il_instruction_action(cls, view, func, instr, action):
@@ -159,21 +164,21 @@ class PluginCommand(object):
file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func))
- func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner)
+ func_obj = binaryninja.mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner)
action(view_obj, func_obj[instr])
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
@classmethod
def _default_is_valid(cls, view, is_valid):
try:
if is_valid is None:
return True
- file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
- view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
+ file_metadata = binaryninja.filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
return is_valid(view_obj)
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
return False
@classmethod
@@ -181,11 +186,11 @@ class PluginCommand(object):
try:
if is_valid is None:
return True
- file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
- view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
+ file_metadata = binaryninja.filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
return is_valid(view_obj, addr)
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
return False
@classmethod
@@ -193,11 +198,11 @@ class PluginCommand(object):
try:
if is_valid is None:
return True
- file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
- view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
+ file_metadata = binaryninja.filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
return is_valid(view_obj, addr, length)
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
return False
@classmethod
@@ -205,12 +210,12 @@ class PluginCommand(object):
try:
if is_valid is None:
return True
- file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
- view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
+ file_metadata = binaryninja.filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
func_obj = function.Function(view_obj, core.BNNewFunctionReference(func))
return is_valid(view_obj, func_obj)
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
return False
@classmethod
@@ -221,10 +226,10 @@ class PluginCommand(object):
file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func))
- func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner)
+ func_obj = binaryninja.lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner)
return is_valid(view_obj, func_obj)
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
return False
@classmethod
@@ -235,10 +240,10 @@ class PluginCommand(object):
file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func))
- func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner)
+ func_obj = binaryninja.lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner)
return is_valid(view_obj, func_obj[instr])
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
return False
@classmethod
@@ -249,10 +254,10 @@ class PluginCommand(object):
file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func))
- func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner)
+ func_obj = binaryninja.mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner)
return is_valid(view_obj, func_obj)
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
return False
@classmethod
@@ -263,10 +268,10 @@ class PluginCommand(object):
file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func))
- func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner)
+ func_obj = binaryninja.mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner)
return is_valid(view_obj, func_obj[instr])
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
return False
@classmethod
@@ -282,7 +287,7 @@ class PluginCommand(object):
.. warning:: Calling ``register`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
- startup._init_plugins()
+ binaryninja._init_plugins()
action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView))(lambda ctxt, view: cls._default_action(view, action))
is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView))(lambda ctxt, view: cls._default_is_valid(view, is_valid))
cls._registered_commands.append((action_obj, is_valid_obj))
@@ -301,7 +306,7 @@ class PluginCommand(object):
.. warning:: Calling ``register_for_address`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
- startup._init_plugins()
+ binaryninja._init_plugins()
action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.c_ulonglong)(lambda ctxt, view, addr: cls._address_action(view, addr, action))
is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.c_ulonglong)(lambda ctxt, view, addr: cls._address_is_valid(view, addr, is_valid))
cls._registered_commands.append((action_obj, is_valid_obj))
@@ -320,7 +325,7 @@ class PluginCommand(object):
.. warning:: Calling ``register_for_range`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
- startup._init_plugins()
+ binaryninja._init_plugins()
action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.c_ulonglong, ctypes.c_ulonglong)(lambda ctxt, view, addr, length: cls._range_action(view, addr, length, action))
is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.c_ulonglong, ctypes.c_ulonglong)(lambda ctxt, view, addr, length: cls._range_is_valid(view, addr, length, is_valid))
cls._registered_commands.append((action_obj, is_valid_obj))
@@ -339,7 +344,7 @@ class PluginCommand(object):
.. warning:: Calling ``register_for_function`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
- startup._init_plugins()
+ binaryninja._init_plugins()
action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNFunction))(lambda ctxt, view, func: cls._function_action(view, func, action))
is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNFunction))(lambda ctxt, view, func: cls._function_is_valid(view, func, is_valid))
cls._registered_commands.append((action_obj, is_valid_obj))
@@ -358,7 +363,7 @@ class PluginCommand(object):
.. warning:: Calling ``register_for_low_level_il_function`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
- startup._init_plugins()
+ binaryninja._init_plugins()
action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction))(lambda ctxt, view, func: cls._low_level_il_function_action(view, func, action))
is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction))(lambda ctxt, view, func: cls._low_level_il_function_is_valid(view, func, is_valid))
cls._registered_commands.append((action_obj, is_valid_obj))
@@ -377,7 +382,7 @@ class PluginCommand(object):
.. warning:: Calling ``register_for_low_level_il_instruction`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
- startup._init_plugins()
+ binaryninja._init_plugins()
action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._low_level_il_instruction_action(view, func, instr, action))
is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._low_level_il_instruction_is_valid(view, func, instr, is_valid))
cls._registered_commands.append((action_obj, is_valid_obj))
@@ -396,7 +401,7 @@ class PluginCommand(object):
.. warning:: Calling ``register_for_medium_level_il_function`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
- startup._init_plugins()
+ binaryninja._init_plugins()
action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction))(lambda ctxt, view, func: cls._medium_level_il_function_action(view, func, action))
is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction))(lambda ctxt, view, func: cls._medium_level_il_function_is_valid(view, func, is_valid))
cls._registered_commands.append((action_obj, is_valid_obj))
@@ -415,7 +420,7 @@ class PluginCommand(object):
.. warning:: Calling ``register_for_medium_level_il_instruction`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
- startup._init_plugins()
+ binaryninja._init_plugins()
action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._medium_level_il_instruction_action(view, func, instr, action))
is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._medium_level_il_instruction_is_valid(view, func, instr, is_valid))
cls._registered_commands.append((action_obj, is_valid_obj))
@@ -463,7 +468,7 @@ class PluginCommand(object):
elif self.command.type == PluginCommandType.LowLevelILInstructionPluginCommand:
if context.instruction is None:
return False
- if not isinstance(context.instruction, lowlevelil.LowLevelILInstruction):
+ if not isinstance(context.instruction, binaryninja.lowlevelil.LowLevelILInstruction):
return False
if not self.command.lowLevelILInstructionIsValid:
return True
@@ -478,7 +483,7 @@ class PluginCommand(object):
elif self.command.type == PluginCommandType.MediumLevelILInstructionPluginCommand:
if context.instruction is None:
return False
- if not isinstance(context.instruction, mediumlevelil.MediumLevelILInstruction):
+ if not isinstance(context.instruction, binaryninja.mediumlevelil.MediumLevelILInstruction):
return False
if not self.command.mediumLevelILInstructionIsValid:
return True
@@ -546,7 +551,7 @@ class MainThreadActionHandler(object):
try:
self.add_action(MainThreadAction(action))
except:
- log.log_error(traceback.format_exc())
+ binaryninja.log.log_error(traceback.format_exc())
def add_action(self, action):
pass
@@ -559,25 +564,23 @@ class _BackgroundTaskMetaclass(type):
count = ctypes.c_ulonglong()
tasks = core.BNGetRunningBackgroundTasks(count)
result = []
- for i in xrange(0, count.value):
- result.append(BackgroundTask(core.BNNewBackgroundTaskReference(tasks[i])))
- core.BNFreeBackgroundTaskList(tasks)
+ for i in range(0, count.value):
+ result.append(BackgroundTask(handle=core.BNNewBackgroundTaskReference(tasks[i])))
+ core.BNFreeBackgroundTaskList(tasks, count.value)
return result
def __iter__(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
tasks = core.BNGetRunningBackgroundTasks(count)
try:
- for i in xrange(0, count.value):
- yield BackgroundTask(core.BNNewBackgroundTaskReference(tasks[i]))
+ for i in range(0, count.value):
+ yield BackgroundTask(handle=core.BNNewBackgroundTaskReference(tasks[i]))
finally:
- core.BNFreeBackgroundTaskList(tasks)
-
+ core.BNFreeBackgroundTaskList(tasks, count.value)
-class BackgroundTask(object):
- __metaclass__ = _BackgroundTaskMetaclass
+class BackgroundTask(with_metaclass(_BackgroundTaskMetaclass, object)):
def __init__(self, initial_progress_text = "", can_cancel = False, handle = None):
if handle is None:
self.handle = core.BNBeginBackgroundTask(initial_progress_text, can_cancel)
@@ -588,6 +591,11 @@ class BackgroundTask(object):
core.BNFreeBackgroundTask(self.handle)
@property
+ def list(self):
+ """Allow tab completion to discover metaclass list property"""
+ pass
+
+ @property
def progress(self):
"""Text description of the progress of the background task (displayed in status bar of the UI)"""
return core.BNGetBackgroundTaskProgressText(self.handle)
diff --git a/python/pluginmanager.py b/python/pluginmanager.py
index 2f293577..c7a0c83a 100644
--- a/python/pluginmanager.py
+++ b/python/pluginmanager.py
@@ -21,9 +21,10 @@
import ctypes
# Binary Ninja components
-import _binaryninjacore as core
-from .enums import PluginType, PluginUpdateStatus
-import startup
+from binaryninja import _binaryninjacore as core
+
+# 2-3 compatibility
+from binaryninja import range
class RepoPlugin(object):
@@ -31,7 +32,9 @@ class RepoPlugin(object):
``RepoPlugin` is mostly read-only, however you can install/uninstall enable/disable plugins. RepoPlugins are
created by parsing the plugins.json in a plugin repository.
"""
+ from binaryninja.enums import PluginType, PluginUpdateStatus
def __init__(self, handle):
+ raise Exception("RepoPlugin temporarily disabled!")
self.handle = core.handle_of_type(handle, core.BNRepoPlugin)
def __del__(self):
@@ -110,7 +113,7 @@ class RepoPlugin(object):
result = []
count = ctypes.c_ulonglong(0)
plugintypes = core.BNPluginGetPluginTypes(self.handle, count)
- for i in xrange(count.value):
+ for i in range(count.value):
result.append(PluginType(plugintypes[i]))
core.BNFreePluginTypes(plugintypes)
return result
@@ -136,6 +139,7 @@ class Repository(object):
``Repository`` is a read-only class. Use RepositoryManager to Enable/Disable/Install/Uninstall plugins.
"""
def __init__(self, handle):
+ raise Exception("Repository temporarily disabled!")
self.handle = core.handle_of_type(handle, core.BNRepository)
def __del__(self):
@@ -181,7 +185,7 @@ class Repository(object):
pluginlist = []
count = ctypes.c_ulonglong(0)
result = core.BNRepositoryGetPlugins(self.handle, count)
- for i in xrange(count.value):
+ for i in range(count.value):
pluginlist.append(RepoPlugin(handle=result[i]))
core.BNFreeRepositoryPluginList(result, count.value)
del result
@@ -199,6 +203,7 @@ class RepositoryManager(object):
the plugins that are installed/unstalled enabled/disabled
"""
def __init__(self, handle=None):
+ raise Exception("RepositoryManager temporarily disabled!")
self.handle = core.BNGetRepositoryManager()
def __getitem__(self, repo_path):
@@ -217,7 +222,7 @@ class RepositoryManager(object):
result = []
count = ctypes.c_ulonglong(0)
repos = core.BNRepositoryManagerGetRepositories(self.handle, count)
- for i in xrange(count.value):
+ for i in range(count.value):
result.append(Repository(handle=repos[i]))
core.BNFreeRepositoryManagerRepositoriesList(repos)
return result
@@ -233,7 +238,7 @@ class RepositoryManager(object):
@property
def default_repository(self):
"""Gets the default Repository"""
- startup._init_plugins()
+ binaryninja._init_plugins()
return Repository(handle=core.BNRepositoryManagerGetDefaultRepository(self.handle))
def enable_plugin(self, plugin, install=True, repo=None):
diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py
index e7838748..37642ed4 100644
--- a/python/scriptingprovider.py
+++ b/python/scriptingprovider.py
@@ -26,14 +26,15 @@ import threading
import abc
import sys
-# Binary Ninja Components
-import _binaryninjacore as core
-from enums import ScriptingProviderExecuteResult, ScriptingProviderInputReadyState
-import binaryview
-import function
-import basicblock
-import startup
-import log
+# Binary Ninja components
+import binaryninja
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import ScriptingProviderExecuteResult, ScriptingProviderInputReadyState
+from binaryninja import log
+
+# 2-3 compatibility
+from binaryninja import range
+from binaryninja import with_metaclass
class _ThreadActionContext(object):
@@ -135,7 +136,7 @@ class ScriptingInstance(object):
def _set_current_binary_view(self, ctxt, view):
try:
if view:
- view = binaryview.BinaryView(handle = core.BNNewViewReference(view))
+ view = binaryninja.binaryview.BinaryView(handle = core.BNNewViewReference(view))
else:
view = None
self.perform_set_current_binary_view(view)
@@ -145,12 +146,12 @@ class ScriptingInstance(object):
def _set_current_function(self, ctxt, func):
try:
if func:
- func = function.Function(binaryview.BinaryView(handle = core.BNGetFunctionData(func)), core.BNNewFunctionReference(func))
+ func = binaryninja.function.Function(binaryninja.binaryview.BinaryView(handle = core.BNGetFunctionData(func)), core.BNNewFunctionReference(func))
else:
func = None
self.perform_set_current_function(func)
except:
- log.log.log_error(traceback.format_exc())
+ log.log_error(traceback.format_exc())
def _set_current_basic_block(self, ctxt, block):
try:
@@ -159,7 +160,7 @@ class ScriptingInstance(object):
if func is None:
block = None
else:
- block = basicblock.BasicBlock(binaryview.BinaryView(handle = core.BNGetFunctionData(func)), core.BNNewBasicBlockReference(block))
+ block = binaryninja.basicblock.BasicBlock(binaryninja.binaryview.BinaryView(handle = core.BNGetFunctionData(func)), core.BNNewBasicBlockReference(block))
core.BNFreeFunction(func)
else:
block = None
@@ -256,30 +257,31 @@ class ScriptingInstance(object):
class _ScriptingProviderMetaclass(type):
+
@property
def list(self):
"""List all ScriptingProvider types (read-only)"""
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
types = core.BNGetScriptingProviderList(count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(ScriptingProvider(types[i]))
core.BNFreeScriptingProviderList(types)
return result
def __iter__(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
types = core.BNGetScriptingProviderList(count)
try:
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
yield ScriptingProvider(types[i])
finally:
core.BNFreeScriptingProviderList(types)
def __getitem__(self, value):
- startup._init_plugins()
+ binaryninja._init_plugins()
provider = core.BNGetScriptingProviderByName(str(value))
if provider is None:
raise KeyError("'%s' is not a valid scripting provider" % str(value))
@@ -292,8 +294,7 @@ class _ScriptingProviderMetaclass(type):
raise AttributeError("attribute '%s' is read only" % name)
-class ScriptingProvider(object):
- __metaclass__ = _ScriptingProviderMetaclass
+class ScriptingProvider(with_metaclass(_ScriptingProviderMetaclass, object)):
name = None
instance_class = None
@@ -304,6 +305,12 @@ class ScriptingProvider(object):
self.handle = core.handle_of_type(handle, core.BNScriptingProvider)
self.__dict__["name"] = core.BNGetScriptingProviderName(handle)
+ @property
+ def list(self):
+ """Allow tab completion to discover metaclass list property"""
+ pass
+
+
def register(self):
self._cb = core.BNScriptingProviderCallbacks()
self._cb.context = 0
@@ -484,7 +491,7 @@ class PythonScriptingInstance(ScriptingInstance):
self.code = None
self.input = ""
- self.interpreter.push("from binaryninja import *\n")
+ self.interpreter.push("from binaryninja import *")
def execute(self, code):
self.code = code
@@ -547,8 +554,8 @@ class PythonScriptingInstance(ScriptingInstance):
self.locals["current_llil"] = self.active_func.low_level_il
self.locals["current_mlil"] = self.active_func.medium_level_il
- for line in code.split("\n"):
- self.interpreter.push(line)
+ for line in code.split(b'\n'):
+ self.interpreter.push(line.decode('charmap'))
if self.locals["here"] != self.active_addr:
if not self.active_view.file.navigate(self.active_view.file.view, self.locals["here"]):
@@ -650,6 +657,8 @@ original_stdin = sys.stdin
original_stdout = sys.stdout
original_stderr = sys.stderr
-sys.stdin = _PythonScriptingInstanceInput(sys.stdin)
-sys.stdout = _PythonScriptingInstanceOutput(sys.stdout, False)
-sys.stderr = _PythonScriptingInstanceOutput(sys.stderr, True)
+def redirect_stdio():
+ sys.stdin = _PythonScriptingInstanceInput(sys.stdin)
+ sys.stdout = _PythonScriptingInstanceOutput(sys.stdout, False)
+ sys.stderr = _PythonScriptingInstanceOutput(sys.stderr, True)
+ sys.excepthook = sys.__excepthook__ \ No newline at end of file
diff --git a/python/setting.py b/python/setting.py
index d58c8955..93f6b72a 100644
--- a/python/setting.py
+++ b/python/setting.py
@@ -21,7 +21,11 @@
import ctypes
# Binary Ninja components
-import _binaryninjacore as core
+from binaryninja import _binaryninjacore as core
+
+# 2-3 compatibility
+from binaryninja import range
+from binaryninja import pyNativeStr
class Setting(object):
@@ -45,7 +49,7 @@ class Setting(object):
default_list[i] = default_value[i]
result = core.BNSettingGetIntegerList(self.plugin_name, name, default_list, ctypes.byref(length))
out_list = []
- for i in xrange(length.value):
+ for i in range(length.value):
out_list.append(result[i])
core.BNFreeSettingIntegerList(result)
return out_list
@@ -55,11 +59,11 @@ class Setting(object):
length.value = len(default_value)
default_list = (ctypes.c_char_p * len(default_value))()
for i in range(len(default_value)):
- default_list[i] = default_value[i]
+ default_list[i] = default_value[i].encode('charmap')
result = core.BNSettingGetStringList(self.plugin_name, name, default_list, ctypes.byref(length))
out_list = []
- for i in xrange(length.value):
- out_list.append(result[i])
+ for i in range(length.value):
+ out_list.append(pyNativeStr(result[i]))
core.BNFreeStringList(result, length)
return out_list
@@ -100,7 +104,7 @@ class Setting(object):
length = ctypes.c_ulonglong()
length.value = len(value)
default_list = (ctypes.c_longlong * len(value))()
- for i in xrange(len(value)):
+ for i in range(len(value)):
default_list[i] = value[i]
return core.BNSettingSetIntegerList(self.plugin_name, name, default_list, length, auto_flush)
@@ -109,8 +113,8 @@ class Setting(object):
length = ctypes.c_ulonglong()
length.value = len(value)
default_list = (ctypes.c_char_p * len(value))()
- for i in xrange(len(value)):
- default_list[i] = str(value[i])
+ for i in range(len(value)):
+ default_list[i] = value[i].encode('charmap')
return core.BNSettingSetStringList(self.plugin_name, name, default_list, length, auto_flush)
@@ -138,4 +142,4 @@ class Setting(object):
core.BNSettingRemoveSettingGroup(self.plugin_name, auto_flush)
def remove_setting(self, setting, auto_flush=True):
- core.BNSettingRemoveSetting(self.plugin_name, setting, auto_flush) \ No newline at end of file
+ core.BNSettingRemoveSetting(self.plugin_name, setting, auto_flush)
diff --git a/python/startup.py b/python/startup.py
index 0abc47cb..04e7b980 100644
--- a/python/startup.py
+++ b/python/startup.py
@@ -18,18 +18,18 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
-import _binaryninjacore as core
+#from binaryninja import _binaryninjacore as core
-_plugin_init = False
+#_plugin_init = False
-def _init_plugins():
- global _plugin_init
- if not _plugin_init:
- _plugin_init = True
- core.BNInitCorePlugins()
- core.BNInitUserPlugins()
- core.BNInitRepoPlugins()
- if not core.BNIsLicenseValidated():
- raise RuntimeError("License is not valid. Please supply a valid license.")
+# def _init_plugins():
+# global _plugin_init
+# if not _plugin_init:
+# _plugin_init = True
+# core.BNInitCorePlugins()
+# core.BNInitUserPlugins()
+# core.BNInitRepoPlugins()
+# if not core.BNIsLicenseValidated():
+# raise RuntimeError("License is not valid. Please supply a valid license.")
diff --git a/python/transform.py b/python/transform.py
index 59d719e7..1734d248 100644
--- a/python/transform.py
+++ b/python/transform.py
@@ -23,31 +23,35 @@ import ctypes
import abc
# Binary Ninja components
-import _binaryninjacore as core
-from enums import TransformType
-import startup
-import log
-import databuffer
+import binaryninja
+from binaryninja import log
+from binaryninja import databuffer
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import TransformType
+
+# 2-3 compatibility
+from binaryninja import range
+from binaryninja import with_metaclass
class _TransformMetaClass(type):
@property
def list(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
xforms = core.BNGetTransformTypeList(count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(Transform(xforms[i]))
core.BNFreeTransformTypeList(xforms)
return result
def __iter__(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
xforms = core.BNGetTransformTypeList(count)
try:
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
yield Transform(xforms[i])
finally:
core.BNFreeTransformTypeList(xforms)
@@ -59,14 +63,14 @@ class _TransformMetaClass(type):
raise AttributeError("attribute '%s' is read only" % name)
def __getitem__(cls, name):
- startup._init_plugins()
+ binaryninja._init_plugins()
xform = core.BNGetTransformByName(name)
if xform is None:
raise KeyError("'%s' is not a valid transform" % str(name))
return Transform(xform)
def register(cls):
- startup._init_plugins()
+ binaryninja._init_plugins()
if cls.name is None:
raise ValueError("transform 'name' is not defined")
if cls.long_name is None:
@@ -90,14 +94,13 @@ class TransformParameter(object):
self.fixed_length = fixed_length
-class Transform(object):
+class Transform(with_metaclass(_TransformMetaClass, object)):
transform_type = None
name = None
long_name = None
group = None
parameters = []
_registered_cb = None
- __metaclass__ = _TransformMetaClass
def __init__(self, handle):
if handle is None:
@@ -124,7 +127,7 @@ class Transform(object):
count = ctypes.c_ulonglong()
params = core.BNGetTransformParameterList(self.handle, count)
self.parameters = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
self.parameters.append(TransformParameter(params[i].name, params[i].longName, params[i].fixedLength))
core.BNFreeTransformParameterList(params, count.value)
@@ -145,7 +148,7 @@ class Transform(object):
try:
count[0] = len(self.parameters)
param_buf = (core.BNTransformParameterInfo * len(self.parameters))()
- for i in xrange(0, len(self.parameters)):
+ for i in range(0, len(self.parameters)):
param_buf[i].name = self.parameters[i].name
param_buf[i].longName = self.parameters[i].long_name
param_buf[i].fixedLength = self.parameters[i].fixed_length
@@ -170,7 +173,7 @@ class Transform(object):
try:
input_obj = databuffer.DataBuffer(handle = core.BNDuplicateDataBuffer(input_buf))
param_map = {}
- for i in xrange(0, count):
+ for i in range(0, count):
data = databuffer.DataBuffer(handle = core.BNDuplicateDataBuffer(params[i].value))
param_map[params[i].name] = str(data)
result = self.perform_decode(str(input_obj), param_map)
@@ -187,7 +190,7 @@ class Transform(object):
try:
input_obj = databuffer.DataBuffer(handle = core.BNDuplicateDataBuffer(input_buf))
param_map = {}
- for i in xrange(0, count):
+ for i in range(0, count):
data = databuffer.DataBuffer(handle = core.BNDuplicateDataBuffer(params[i].value))
param_map[params[i].name] = str(data)
result = self.perform_encode(str(input_obj), param_map)
@@ -200,6 +203,11 @@ class Transform(object):
log.log_error(traceback.format_exc())
return False
+ @property
+ def list(self):
+ """Allow tab completion to discover metaclass list property"""
+ pass
+
@abc.abstractmethod
def perform_decode(self, data, params):
if self.type == TransformType.InvertingTransform:
@@ -213,9 +221,9 @@ class Transform(object):
def decode(self, input_buf, params = {}):
input_buf = databuffer.DataBuffer(input_buf)
output_buf = databuffer.DataBuffer()
- keys = params.keys()
+ keys = list(params.keys())
param_buf = (core.BNTransformParameter * len(keys))()
- for i in xrange(0, len(keys)):
+ for i in range(0, len(keys)):
data = databuffer.DataBuffer(params[keys[i]])
param_buf[i].name = keys[i]
param_buf[i].value = data.handle
@@ -226,9 +234,9 @@ class Transform(object):
def encode(self, input_buf, params = {}):
input_buf = databuffer.DataBuffer(input_buf)
output_buf = databuffer.DataBuffer()
- keys = params.keys()
+ keys = list(params.keys())
param_buf = (core.BNTransformParameter * len(keys))()
- for i in xrange(0, len(keys)):
+ for i in range(0, len(keys)):
data = databuffer.DataBuffer(params[keys[i]])
param_buf[i].name = keys[i]
param_buf[i].value = data.handle
diff --git a/python/types.py b/python/types.py
index 42ed7ddd..12e7733f 100644
--- a/python/types.py
+++ b/python/types.py
@@ -18,25 +18,32 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
+from __future__ import absolute_import
max_confidence = 255
import ctypes
# Binary Ninja components
-import _binaryninjacore as core
-from enums import SymbolType, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType, VariableSourceType
-import callingconvention
-import function
+import binaryninja
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import SymbolType, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType, VariableSourceType
+
+# 2-3 compatibility
+from binaryninja import range
+from binaryninja import pyNativeStr
class QualifiedName(object):
def __init__(self, name = []):
if isinstance(name, str):
self.name = [name]
+ self.byte_name = [name.encode('charmap')]
elif isinstance(name, QualifiedName):
self.name = name.name
+ self.byte_name = [n.encode('charmap') for n in name.name]
else:
- self.name = name
+ self.name = [pyNativeStr(i) for i in name]
+ self.byte_name = name
def __str__(self):
return "::".join(self.name)
@@ -98,8 +105,8 @@ class QualifiedName(object):
def _get_core_struct(self):
result = core.BNQualifiedName()
name_list = (ctypes.c_char_p * len(self.name))()
- for i in xrange(0, len(self.name)):
- name_list[i] = self.name[i]
+ for i in range(0, len(self.name)):
+ name_list[i] = self.name[i].encode('charmap')
result.name = name_list
result.nameCount = len(self.name)
return result
@@ -107,7 +114,7 @@ class QualifiedName(object):
@classmethod
def _from_core_struct(cls, name):
result = []
- for i in xrange(0, name.nameCount):
+ for i in range(0, name.nameCount):
result.append(name.name[i])
return QualifiedName(result)
@@ -292,7 +299,7 @@ class Type(object):
result = core.BNGetTypeCallingConvention(self.handle)
if not result.convention:
return None
- return callingconvention.CallingConvention(None, handle = result.convention, confidence = result.confidence)
+ return binaryninja.callingconvention.CallingConvention(None, handle = result.convention, confidence = result.confidence)
@property
def parameters(self):
@@ -300,7 +307,7 @@ class Type(object):
count = ctypes.c_ulonglong()
params = core.BNGetTypeParameters(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
param_type = Type(core.BNNewTypeReference(params[i].type), platform = self.platform, confidence = params[i].typeConfidence)
if params[i].defaultLocation:
param_location = None
@@ -310,7 +317,7 @@ class Type(object):
name = self.platform.arch.get_reg_name(params[i].location.storage)
elif params[i].location.type == VariableSourceType.StackVariableSourceType:
name = "arg_%x" % params[i].location.storage
- param_location = function.Variable(None, params[i].location.type, params[i].location.index,
+ param_location = binaryninja.function.Variable(None, params[i].location.type, params[i].location.index,
params[i].location.storage, name, param_type)
result.append(FunctionParameter(param_type, params[i].name, param_location))
core.BNFreeTypeParameterList(params, count.value)
@@ -344,7 +351,7 @@ class Type(object):
return None
return Enumeration(result)
- @property
+ @property
def named_type_reference(self):
"""Reference to a named type (read-only)"""
result = core.BNGetTypeNamedTypeReference(self.handle)
@@ -376,7 +383,7 @@ class Type(object):
def __repr__(self):
if self.confidence < max_confidence:
- return "<type: %s, %d%% confidence>" % (str(self), (self.confidence * 100) / max_confidence)
+ return "<type: %s, %d%% confidence>" % (str(self), (self.confidence * 100) // max_confidence)
return "<type: %s>" % str(self)
def get_string_before_name(self):
@@ -403,7 +410,7 @@ class Type(object):
platform = self.platform.handle
tokens = core.BNGetTypeTokens(self.handle, platform, base_confidence, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
token_type = InstructionTextTokenType(tokens[i].type)
text = tokens[i].text
value = tokens[i].value
@@ -412,7 +419,7 @@ class Type(object):
context = tokens[i].context
confidence = tokens[i].confidence
address = tokens[i].address
- result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
+ result.append(binaryninja.function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
core.BNFreeTokenList(tokens, count.value)
return result
@@ -423,7 +430,7 @@ class Type(object):
platform = self.platform.handle
tokens = core.BNGetTypeTokensBeforeName(self.handle, platform, base_confidence, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
token_type = InstructionTextTokenType(tokens[i].type)
text = tokens[i].text
value = tokens[i].value
@@ -432,7 +439,7 @@ class Type(object):
context = tokens[i].context
confidence = tokens[i].confidence
address = tokens[i].address
- result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
+ result.append(binaryninja.function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
core.BNFreeTokenList(tokens, count.value)
return result
@@ -443,7 +450,7 @@ class Type(object):
platform = self.platform.handle
tokens = core.BNGetTypeTokensAfterName(self.handle, platform, base_confidence, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
token_type = InstructionTextTokenType(tokens[i].type)
text = tokens[i].text
value = tokens[i].value
@@ -452,7 +459,7 @@ class Type(object):
context = tokens[i].context
confidence = tokens[i].confidence
address = tokens[i].address
- result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
+ result.append(binaryninja.function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
core.BNFreeTokenList(tokens, count.value)
return result
@@ -574,7 +581,7 @@ class Type(object):
:param bool variable_arguments: optional argument for functions that have a variable number of arguments
"""
param_buf = (core.BNFunctionParameter * len(params))()
- for i in xrange(0, len(params)):
+ for i in range(0, len(params)):
if isinstance(params[i], Type):
param_buf[i].name = ""
param_buf[i].type = params[i].handle
@@ -851,7 +858,7 @@ class Structure(object):
count = ctypes.c_ulonglong()
members = core.BNGetStructureMembers(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(StructureMember(Type(core.BNNewTypeReference(members[i].type), confidence = members[i].typeConfidence),
members[i].name, members[i].offset))
core.BNFreeStructureMemberList(members, count.value)
@@ -962,7 +969,7 @@ class Enumeration(object):
count = ctypes.c_ulonglong()
members = core.BNGetEnumerationMembers(self.handle, count)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(EnumerationMember(members[i].name, members[i].value, members[i].isDefault))
core.BNFreeEnumerationMemberList(members, count.value)
return result
@@ -1018,8 +1025,8 @@ def preprocess_source(source, filename=None, include_dirs=[]):
if filename is None:
filename = "input"
dir_buf = (ctypes.c_char_p * len(include_dirs))()
- for i in xrange(0, len(include_dirs)):
- dir_buf[i] = str(include_dirs[i])
+ for i in range(0, len(include_dirs)):
+ dir_buf[i] = include_dirs[i].encode('charmap')
output = ctypes.c_char_p()
errors = ctypes.c_char_p()
result = core.BNPreprocessSource(source, filename, output, errors, dir_buf, len(include_dirs))
diff --git a/python/undoaction.py b/python/undoaction.py
index 7e3c76a0..7891bf54 100644
--- a/python/undoaction.py
+++ b/python/undoaction.py
@@ -23,10 +23,8 @@ import json
import ctypes
# Binary Ninja components
-import _binaryninjacore as core
-from enums import ActionType
-import startup
-import log
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import ActionType
class UndoAction(object):
@@ -52,7 +50,7 @@ class UndoAction(object):
@classmethod
def register(cls):
- startup._init_plugins()
+ binaryninja._init_plugins()
if cls.name is None:
raise ValueError("undo action 'name' not defined")
if cls.action_type is None:
diff --git a/python/update.py b/python/update.py
index 1eb8ea61..7f5d6f9c 100644
--- a/python/update.py
+++ b/python/update.py
@@ -22,16 +22,18 @@ import traceback
import ctypes
# Binary Ninja components
-import _binaryninjacore as core
-from enums import UpdateResult
-import startup
-import log
+from binaryninja import _binaryninjacore as core
+from binaryninja.enums import UpdateResult
+
+# 2-3 compatibility
+from binaryninja import range
+from binaryninja import with_metaclass
class _UpdateChannelMetaClass(type):
@property
def list(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
errors = ctypes.c_char_p()
channels = core.BNGetUpdateChannels(count, errors)
@@ -40,7 +42,7 @@ class _UpdateChannelMetaClass(type):
core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
raise IOError(error_str)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(UpdateChannel(channels[i].name, channels[i].description, channels[i].latestVersion))
core.BNFreeUpdateChannelList(channels, count.value)
return result
@@ -54,7 +56,7 @@ class _UpdateChannelMetaClass(type):
return core.BNSetActiveUpdateChannel(value)
def __iter__(self):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
errors = ctypes.c_char_p()
channels = core.BNGetUpdateChannels(count, errors)
@@ -63,7 +65,7 @@ class _UpdateChannelMetaClass(type):
core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
raise IOError(error_str)
try:
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
yield UpdateChannel(channels[i].name, channels[i].description, channels[i].latestVersion)
finally:
core.BNFreeUpdateChannelList(channels, count.value)
@@ -75,7 +77,7 @@ class _UpdateChannelMetaClass(type):
raise AttributeError("attribute '%s' is read only" % name)
def __getitem__(cls, name):
- startup._init_plugins()
+ binaryninja._init_plugins()
count = ctypes.c_ulonglong()
errors = ctypes.c_char_p()
channels = core.BNGetUpdateChannels(count, errors)
@@ -84,7 +86,7 @@ class _UpdateChannelMetaClass(type):
core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
raise IOError(error_str)
result = None
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
if channels[i].name == str(name):
result = UpdateChannel(channels[i].name, channels[i].description, channels[i].latestVersion)
break
@@ -108,9 +110,7 @@ class UpdateProgressCallback(object):
log.log_error(traceback.format_exc())
-class UpdateChannel(object):
- __metaclass__ = _UpdateChannelMetaClass
-
+class UpdateChannel(with_metaclass(_UpdateChannelMetaClass, object)):
def __init__(self, name, desc, ver):
self.name = name
self.description = desc
@@ -127,7 +127,7 @@ class UpdateChannel(object):
core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
raise IOError(error_str)
result = []
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
result.append(UpdateVersion(self, versions[i].version, versions[i].notes, versions[i].time))
core.BNFreeUpdateChannelVersionList(versions, count.value)
return result
@@ -143,7 +143,7 @@ class UpdateChannel(object):
core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
raise IOError(error_str)
result = None
- for i in xrange(0, count.value):
+ for i in range(0, count.value):
if versions[i].version == self.latest_version_num:
result = UpdateVersion(self, versions[i].version, versions[i].notes, versions[i].time)
break
diff --git a/scripts/install_api.py b/scripts/install_api.py
index 53679ba5..3cc0ed0d 100755
--- a/scripts/install_api.py
+++ b/scripts/install_api.py
@@ -80,6 +80,6 @@ else:
sys.exit(1)
binaryninja_pth_path = os.path.join(install_path, 'binaryninja.pth')
-open(binaryninja_pth_path, 'wb').write(api_path)
+open(binaryninja_pth_path, 'wb').write(api_path.encode('charmap'))
print("Binary Ninja API installed using {}".format(binaryninja_pth_path))
diff --git a/suite/api_test.py b/suite/api_test.py
new file mode 100644
index 00000000..740f88e3
--- /dev/null
+++ b/suite/api_test.py
@@ -0,0 +1,221 @@
+import unittest
+import platform
+import os
+from binaryninja.setting import Setting
+from binaryninja.metadata import Metadata
+from binaryninja.demangle import demangle_gnu3, get_qualified_name
+from binaryninja.architecture import Architecture
+
+
+class SettingsAPI(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ pass
+
+ @classmethod
+ def tearDownClass(cls):
+ setting = Setting("test")
+ setting.remove_setting_group("test")
+
+ def test_bool_settings(self):
+ setting = Setting("test")
+ setting.set("bool_test_true", True)
+ setting.set("bool_test_false", False)
+ assert not setting.get_bool("bool_test_false"), "bool_test_false failed"
+ assert setting.get_bool("bool_test_true"), "bool_test_true failed"
+ assert setting.get_bool("bool_test_default_True", True), "bool_test_default_True failed"
+ assert not setting.get_bool("bool_test_default_False", False), "bool_test_default_False failed"
+
+ def test_int_settings(self):
+ setting = Setting("test")
+ setting.set("int_test1", 0x100)
+ setting.set("int_test2", 0)
+ setting.set("int_test3", -1)
+ assert setting.get_integer("int_test1") == 0x100, "int_test1 failed"
+ assert setting.get_integer("int_test2") == 0, "int_test2 failed"
+ assert setting.get_integer("int_test3") == -1, "int_test3 failed"
+ assert setting.get_integer("int_test_default_1", 1) == 1, "int_test_default_1 failed"
+
+ def test_float_settings(self):
+ setting = Setting("test")
+ setting.set("float_test1", 10.5)
+ setting.set("float_test2", -0.5)
+ assert setting.get_double("float_test1") == 10.5, "float_test1 failed"
+ assert setting.get_double("float_test2") == -0.5, "float_test1 failed"
+ assert setting.get_double("float_test_default", -5.5), "float_test_default failed"
+
+ def test_str_settings(self):
+ setting = Setting("test")
+ setting.set("str_test1", "hi")
+ setting.set("str_test2", "")
+ setting.set("str_test3", "A" * 1000)
+ assert setting.get_string("str_test1") == "hi", "str_test1 failed"
+ assert setting.get_string("str_test2") == "", "str_test2 failed"
+ assert setting.get_string("str_test3") == "A" * 1000, "str_test3 failed"
+ assert setting.get_string("str_test_default", "hi") == "hi", "str_test_default failed"
+
+ def test_int_list_settings(self):
+ setting = Setting("test")
+ setting.set("int_list_test1", [0x100])
+ setting.set("int_list_test2", [1, 2])
+ setting.set("int_list_test3", [])
+ assert setting.get_integer_list("int_list_test1") == [0x100], "int_list_test1 failed"
+ assert setting.get_integer_list("int_list_test2") == [1, 2], "int_list_test2 failed"
+ assert setting.get_integer_list("int_list_test3") == [], "int_list_test3 failed"
+ assert setting.get_integer_list("int_list_test_default", [2, 3]), "int_list_test_default failed"
+
+ def test_str_list_settings(self):
+ setting = Setting("test")
+ setting.set("str_list_test1", ["hi"])
+ setting.set("str_list_test2", ["hello", "world"])
+ setting.set("str_list_test3", [])
+ assert setting.get_string_list("str_list_test1") == ["hi"], "str_list_test1 failed"
+ assert setting.get_string_list("str_list_test2") == ["hello", "world"], "str_list_test2 failed"
+ assert setting.get_string_list("str_list_test3") == [], "str_list_test3 failed"
+ assert setting.get_string_list("str_list_test_default", ["hi", "there"]), "str_list_test_default failed"
+
+
+class MetaddataAPI(unittest.TestCase):
+ def test_metadata_basic_types(self):
+ # Core is tested thoroughly through the C++ unit tests here we focus on the python api side
+ md = Metadata(1)
+ assert md.is_integer
+ assert int(md) == 1
+ assert md.value == 1
+
+ md = Metadata(-1, signed=True)
+ assert md.is_signed_integer
+ assert int(md) == -1
+ assert md.value == -1
+ md = Metadata(1, signed=False)
+ assert md.is_unsigned_integer
+ assert int(md) == 1
+ md = Metadata(3.14)
+ assert md.is_float
+ assert float(md) == 3.14
+ assert md.value == 3.14
+
+ md = Metadata("asdf")
+ assert md.is_string
+ assert str(md) == "asdf"
+ assert len(md) == 4
+ assert md.value == "asdf"
+
+ md = Metadata("\x00\x00\x41\x00", raw=True)
+ assert md.is_raw
+ assert len(md) == 4
+ assert str(md) == "\x00\x00\x41\x00"
+ assert md.value == "\x00\x00\x41\x00"
+
+ def test_metadata_compound_types(self):
+ md = Metadata([1, 2, 3])
+ assert md.is_array
+ assert md.value == [1, 2, 3]
+ assert len(md) == 3
+ assert md[0] == 1
+ assert md[1] == 2
+ assert md[2] == 3
+ assert isinstance(list(md), list)
+ md.remove(0)
+ assert len(md) == 2
+ assert md == [2, 3]
+
+ md = Metadata({"a": 1, "b": 2})
+ assert md.is_dict
+ assert len(md) == 2
+ assert md.value == {"a": 1, "b": 2}
+ assert md["a"] == 1
+ assert md["b"] == 2
+ md.remove("a")
+ assert len(md) == 1
+ assert md == {"b": 2}
+
+ def test_metadata_equality(self):
+ assert Metadata(1) == 1
+ assert Metadata(1) != 0
+ assert Metadata(1) == Metadata(1)
+ assert Metadata(1) != Metadata(0)
+
+ assert Metadata(3.14) == 3.14
+ assert Metadata(3.14) == Metadata(3.14)
+ assert Metadata(3.14) != 3.1
+ assert Metadata(3.14) != Metadata(3.1)
+
+ assert Metadata("asdf") == "asdf"
+ assert Metadata("asdf") == Metadata("asdf")
+ assert Metadata("asdf") != "qwer"
+ assert Metadata("asdf") != Metadata("qwer")
+
+ assert Metadata("as\x00df", raw=True) == "as\x00df"
+ assert Metadata("as\x00df", raw=True) == Metadata("as\x00df", raw=True)
+ assert Metadata("as\x00df", raw=True) != "qw\x00er"
+ assert Metadata("as\x00df", raw=True) != Metadata("qw\x00er", raw=True)
+
+ assert Metadata([1, 2, 3]) == [1, 2, 3]
+ assert Metadata([1, 2, 3]) == Metadata([1, 2, 3])
+ assert Metadata([1, 2, 3]) != [1, 2]
+ assert Metadata([1, 2, 3]) != Metadata([1, 2])
+
+ assert Metadata({"a": 1, "b": 2}) == {"a": 1, "b": 2}
+ assert Metadata({"a": 1, "b": 2}) == Metadata({"a": 1, "b": 2})
+ assert Metadata({"a": 1, "b": 2}) != {"a": 1}
+ assert Metadata({"a": 1, "b": 2}) != Metadata({"a": 1})
+
+
+class DemanglerTest(unittest.TestCase):
+ def get_type_string(self, t, n):
+ out = ""
+ if t is not None:
+ out = str(t.get_string_before_name())
+ if len(out) > 1 and out[-1] != ' ':
+ out += " "
+ out += get_qualified_name(n)
+ out += str(t.get_string_after_name())
+ return out
+
+ def test_demangle_gnu3(self):
+ tests = ("__ZN15BinaryNinjaCore12BinaryReader5Read8Ev",
+ "__ZN5QListIP18QAbstractAnimationE18detach_helper_growEii",
+ "__ZN13QStatePrivate22emitPropertiesAssignedEv",
+ "__ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI14QItemSelectionLb1EE9ConstructEPvPKv",
+ "__ZN18QSharedDataPointerI16QFileInfoPrivateE4dataEv",
+ "__ZN26QAbstractNativeEventFilterD2Ev",
+ "__ZN5QListIP14QAbstractStateE3endEv",
+ "__ZNK15BinaryNinjaCore19ArchitectureWrapper22GetOpcodeDisplayLengthEv",
+ "__ZN15BinaryNinjaCore17ScriptingInstance19SetCurrentSelectionEyy",
+ "__ZL32qt_meta_stringdata_QHistoryState",
+ "__ZN12_GLOBAL__N_114TypeDestructor14DestructorImplI11QStringListLb1EE8DestructEiPv",
+ "__ZN13QGb18030Codec5_nameEv",
+ "__ZN5QListIP7QObjectE6detachEv",
+ "__ZN19QBasicAtomicPointerI9QFreeListI13QMutexPrivateN12_GLOBAL__N_117FreeListConstantsEEE17testAndSetReleaseEPS4_S6_",
+ "__ZN12QJsonPrivate6Parser12reserveSpaceEi",
+ "__ZN20QStateMachinePrivate12endMacrostepEb",
+ "__ZN14QScopedPointerI20QTemporaryDirPrivate21QScopedPointerDeleterIS0_EED2Ev",
+ "__ZN14QVariantIsNullIN12_GLOBAL__N_115CoreTypesFilterEE8delegateI10QMatrix4x4EEbPKT_",
+ "__ZN26QAbstractProxyModelPrivateC2Ev",
+ "__ZNSt3__110__function6__funcIZ26BNWorkerInteractiveEnqueueE4$_16NS_9allocatorIS2_EEFvvEEclEv")
+
+ results = ("int32_t BinaryNinjaCore::BinaryReader::Read8()",
+ "int32_t QList<QAbstractAnimation*>::detach_helper_grow(int32_t, int32_t)",
+ "int32_t QStatePrivate::emitPropertiesAssigned()",
+ "int32_t QtMetaTypePrivate::QMetaTypeFunctionHelper<QItemSelection, true>::Construct(void*, void const*)",
+ "int32_t QSharedDataPointer<QFileInfoPrivate>::data()",
+ "void QAbstractNativeEventFilter::~QAbstractNativeEventFilter()",
+ "int32_t QList<QAbstractState*>::end()",
+ "int32_t BinaryNinjaCore::ArchitectureWrapper::GetOpcodeDisplayLength() const",
+ "int32_t BinaryNinjaCore::ScriptingInstance::SetCurrentSelection(uint64_t, uint64_t)",
+ "qt_meta_stringdata_QHistoryState",
+ "int32_t (anonymous namespace)::TypeDestructor::DestructorImpl<QStringList, true>::Destruct(int32_t, void*)",
+ "int32_t QGb18030Codec::_name()",
+ "int32_t QList<QObject*>::detach()",
+ "int32_t QBasicAtomicPointer<QFreeList<QMutexPrivate, (anonymous namespace)::FreeListConstants> >::testAndSetRelease(QFreeList<QMutexPrivate, (anonymous namespace)::FreeListConstants>*, QFreeList<QMutexPrivate, (anonymous namespace)::FreeListConstants>*)",
+ "int32_t QJsonPrivate::Parser::reserveSpace(int32_t)",
+ "int32_t QStateMachinePrivate::endMacrostep(bool)",
+ "void QScopedPointer<QTemporaryDirPrivate, QScopedPointerDeleter<QTemporaryDirPrivate> >::~QScopedPointer()",
+ "bool QVariantIsNull<(anonymous namespace)::CoreTypesFilter>::delegate<QMatrix4x4>(QMatrix4x4 const*)",
+ "void QAbstractProxyModelPrivate::QAbstractProxyModelPrivate()",
+ "int32_t std::__1::__function::__func<BNWorkerInteractiveEnqueue::$_16, std::__1::allocator<BNWorkerInteractiveEnqueue::$_16>, void ()>::operator()()")
+
+ for i, test in enumerate(tests):
+ t, n = demangle_gnu3(Architecture['x86'], test)
+ assert self.get_type_string(t, n) == results[i]
diff --git a/suite/binaries b/suite/binaries
new file mode 160000
+Subproject 96d08bbb4fdcf1b88c98165fcfe8474659c38d6
diff --git a/suite/generator.py b/suite/generator.py
new file mode 100755
index 00000000..09ee00dc
--- /dev/null
+++ b/suite/generator.py
@@ -0,0 +1,328 @@
+#!/usr/bin/env python2
+import pickle
+import sys
+import os
+import zipfile
+from optparse import OptionParser
+import testcommon
+import time
+
+unit_test_template = """#!/usr/bin/env python
+# This is an auto generated unit test file do not edit directly
+import os
+import sys
+import unittest
+import pickle
+import zipfile
+import difflib
+from collections import Counter
+
+api_suite_path = os.path.join(os.path.dirname(__file__), {4})
+sys.path.append(api_suite_path)
+import testcommon
+import api_test
+
+global verbose
+verbose = False
+
+
+class TestBinaryNinjaAPI(unittest.TestCase):
+ # Returns a tuple of:
+ # bool : Two lists are equal
+ # string : The string diff
+ # Args:
+ # list
+ # list : (compare list one vs list two)
+ # string : anything additional wanted to be printed before the string diff
+ # bool : the ordering of the items in the two lists must be the same
+ def report(self, oracle, test, firstText='', strictOrdering = False):
+ stringDiff = ""
+
+ equality = False
+ if not strictOrdering:
+ equality = (Counter(oracle) == Counter(test))
+ else:
+ equality = (oracle == test)
+
+ if equality:
+ return (True, '')
+ elif not strictOrdering:
+ try:
+ for elem in oracle:
+ test.remove(elem)
+ oracle.remove(elem) # If it's not in the test, it won't get here!
+ except ValueError:
+ pass
+
+ differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
+ skipped_lines = 0
+ for delta in differ.compare(oracle, test):
+ if delta[0] == ' ':
+ skipped_lines += 1
+ continue
+ if skipped_lines > 0:
+ stringDiff += "<---" + str(skipped_lines) + ' same lines--->\\n'
+ skipped_lines = 0
+ delta = delta.replace(\'\\n\', '')
+ stringDiff += delta + \'\\n\'
+
+ stringDiffList = stringDiff.split(\'\\n\')
+
+ if len(stringDiffList) > 10:
+ if not verbose:
+ stringDiff = \'\\n\'.join(line if len(line) <= 100 else line[:100] + "...and " + str(len(line) - 100) + " more characters" for line in stringDiffList[:10])
+ stringDiff += \'\\n\\n### And ' + str(len(stringDiffList)) + " more lines, use '-v' to show ###"
+ elif not verbose:
+ stringDiff = \'\\n\'.join(line if len(line) <= 100 else line[:100] + "...and " + str(len(line) - 100) + " more characters" for line in stringDiffList)
+ stringDiff = \'\\n\\n\' + firstText + stringDiff
+ return (equality, stringDiff)
+
+ @classmethod
+ def setUpClass(self):
+ self.builder = testcommon.TestBuilder("{3}")
+ pickle_path = os.path.join(os.path.dirname(__file__), "oracle.pkl")
+ try:
+ # Python 2 does not have the encodings option
+ self.oracle_test_data = pickle.load(open(pickle_path, "rb"), encoding='charmap')
+ except TypeError:
+ self.oracle_test_data = pickle.load(open(pickle_path, "rb"))
+ self.verifybuilder = testcommon.VerifyBuilder("{3}")
+
+ def run_binary_test(self, testfile):
+ testname = None
+ with zipfile.ZipFile(os.path.join(api_suite_path, testfile), "r") as zf:
+ testname = zf.namelist()[0]
+ zf.extractall(path=api_suite_path)
+
+ pickle_path = os.path.join(os.path.dirname(__file__), testname + ".pkl")
+ self.assertTrue(pickle_path, "Test pickle doesn't exist")
+ try:
+ # Python 2 does not have the encodings option
+ binary_oracle = pickle.load(open(pickle_path, "rb"), encoding='charmap')
+ except TypeError:
+ binary_oracle = pickle.load(open(pickle_path, "rb"))
+
+ test_builder = testcommon.BinaryViewTestBuilder(testname)
+ for method in test_builder.methods():
+ test = getattr(test_builder, method)()
+ oracle = binary_oracle[method]
+ if test == oracle:
+ continue
+
+ result = getattr(test_builder, method).__doc__
+ result += ":\\n"
+ report = self.report(oracle, test, result)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
+ os.unlink(os.path.join(api_suite_path, testname))
+{1}{2}
+
+if __name__ == "__main__":
+ if len(sys.argv) > 1:
+ if sys.argv[1] == '-v' or sys.argv[1] == '-V' or sys.argv[1] == '--verbose':
+ verbose = True
+
+ test_suite = unittest.defaultTestLoader.loadTestsFromModule(api_test)
+ test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestBinaryNinjaAPI))
+ runner = unittest.TextTestRunner(verbosity=2)
+ runner.run(test_suite)
+"""
+
+
+binary_test_string = """
+ def test_binary__{0}(self):
+ self.run_binary_test('{1}')
+"""
+
+test_string = """
+ def {0}(self):
+ oracle = self.oracle_test_data['{0}']
+ test = self.builder.{0}()
+ report = self.report(oracle, test)
+ self.assertTrue(report[0], report[1]) # Test does not agree with oracle
+"""
+
+verify_string = """
+ def {0}(self):
+ self.assertTrue(self.verifybuilder.{0}(), self.{0}.__doc__)
+"""
+
+
+class OracleTestFile:
+ def __init__(self, filename):
+ self.f = open(filename + ".pkl", "wb")
+ self.pkl = pickle.Pickler(self.f, protocol=2)
+ self.filename = filename
+ self.oracle_test_data = {}
+
+ def add_entry(self, builder, test_name):
+ self.oracle_test_data[test_name] = getattr(builder, test_name)()
+
+ def close(self):
+ self.pkl.dump(self.oracle_test_data)
+ self.f.close()
+
+
+class UnitTestFile:
+ def __init__(self, filename, outdir, test_store):
+ self.filename = filename
+ self.test_store = test_store
+ self.outdir = outdir
+ self.f = open(filename, "wb")
+ self.template = unit_test_template
+ self.tests = ""
+ self.binary_tests = ""
+
+ def close(self):
+ api_path = os.path.relpath(os.path.dirname(__file__), start=self.outdir)
+ api_path = os.path.normpath(api_path)
+ api_path = map(lambda x: '"{0}"'.format(x), api_path.split(os.sep))
+ api_path = '{0}'.format(', '.join(api_path))
+ self.f.write(self.template.format(self.outdir, self.tests, self.binary_tests, self.test_store, api_path).encode('charmap'))
+ self.f.close()
+
+ def add_verify(self, test_name):
+ self.tests += verify_string.format(test_name)
+
+ def add_test(self, test_name):
+ self.tests += test_string.format(test_name)
+
+ def add_binary_test(self, test_store, binary):
+ name = binary[len(test_store):].replace(os.path.sep, "_").replace(".", "_")
+ self.binary_tests += binary_test_string.format(name, binary + ".zip")
+
+
+quiet = False
+def myprint(stuff):
+ if not quiet:
+ print(stuff)
+
+
+def update_progress(complete, total, description, done=False):
+ n = 20
+ maxdesc = 50
+ if total == 0:
+ total, complete = 10, 10
+ if len(description) > maxdesc:
+ description = description[:maxdesc]
+ elif len(description) < maxdesc:
+ description += ' ' * (maxdesc - len(description))
+
+ if not quiet:
+ sys.stdout.write('\r[{0}{1}] {2:10.0f}% - {3}'.format('#' * int(n * (float(complete) / total)), ' ' * (n - int(n * (float(complete) / total))), 100 * float(complete) / total, description))
+ if done:
+ sys.stdout.write("\n")
+
+
+class TestStoreError(Exception):
+ def __init__(self, *args, **kwargs):
+ Exception.__init__(self, *args, **kwargs)
+
+
+def generate(test_store, outdir, exclude_binaries):
+ if not os.path.isdir(os.path.join(os.path.dirname(__file__), test_store)):
+ raise TestStoreError("Specified test store is not a directory")
+
+ unittest = UnitTestFile(os.path.join(outdir, "unit.py"), outdir, test_store)
+ oracle = OracleTestFile(os.path.join(outdir, "oracle"))
+
+ # Generate the tests that don't involve binaries but do involve oracles
+ builder = testcommon.TestBuilder(test_store)
+ tests = builder.methods()
+ for progress, test_name in enumerate(tests):
+ update_progress(progress, len(tests), "Generating test data")
+ oracle.add_entry(builder, test_name)
+ unittest.add_test(test_name)
+ update_progress(len(tests), len(tests), "Generating test data", True)
+
+ # Generate the tests that just verify things work as expected
+ verify = testcommon.VerifyBuilder(test_store)
+ tests = verify.methods()
+ for progress, test_name in enumerate(tests):
+ update_progress(progress, len(tests), "Generating verify data")
+ unittest.add_verify(test_name)
+ update_progress(len(tests), len(tests), "Generating verify data", True)
+
+ # Now generate test that involve binaries
+ allfiles = sorted(testcommon.get_file_list(test_store))
+ for progress, testfile in enumerate(allfiles):
+ oraclefile = None
+ if testfile.endswith(".pkl"):
+ continue
+ elif testfile.endswith(".DS_Store"):
+ continue
+ elif testfile.endswith(".zip"):
+ # We have a zipped binary unzip it so we can rebaseline
+ with zipfile.ZipFile(testfile, "r") as zf:
+ zf.extractall(path = os.path.dirname(__file__))
+ if not os.path.exists(testfile[:-4]):
+ print("Error extracting testfile %s from zip: %s" % (testfile[:-4], testfile))
+ continue
+ oraclefile = testfile[:-4]
+ else:
+ if os.path.exists(testfile + ".zip"):
+ # We've got a binary and zip for that binary just skip it
+ continue
+ # We have a binary that isn't zipped use it as a new test case
+ oraclefile = testfile
+
+ oraclefile_rel = os.path.relpath(oraclefile, start=os.path.dirname(__file__))
+
+ # Now generate the oracle data
+ update_progress(progress, len(allfiles), oraclefile_rel)
+ unittest.add_binary_test(test_store, oraclefile_rel)
+ binary_start_time = time.time()
+ if exclude_binaries:
+ continue
+ test_data = testcommon.BinaryViewTestBuilder(oraclefile_rel)
+ binary_oracle = OracleTestFile(os.path.join(outdir, oraclefile_rel))
+ for method in test_data.methods():
+ binary_oracle.add_entry(test_data, method)
+ binary_oracle.close()
+ print("{0:.2f}".format(time.time() - binary_start_time))
+
+ if not os.path.exists(oraclefile + ".zip"):
+ with zipfile.ZipFile(oraclefile + ".zip", "w") as zf:
+ zf.write(oraclefile, os.path.relpath(oraclefile, start=os.path.dirname(__file__)))
+
+ os.unlink(oraclefile)
+
+ update_progress(len(allfiles), len(allfiles), "Generating binary unit tests complete", True)
+ unittest.close()
+ oracle.close()
+
+
+def main():
+ usage = "usage: %prog [-q] [-x] [-o <dir>] [-i <dir>]"
+ parser = OptionParser(usage=usage)
+ parser.add_option("-q", "--quiet",
+ dest="quiet", action="store_true",
+ default=False, help="Don't print anything")
+ parser.add_option("-x", "--exclude",
+ dest="exclude_binary", action="store_true",
+ default=False, help="Exclude regeneration of binaries")
+ parser.add_option("-o", "--outputdir", default="suite",
+ dest="outputdir", action="store", type="string",
+ help="output directory where the unit.py and oracle.py files will be stored (relative to cwd)")
+ parser.add_option("-i", "--inputdir", default=os.path.join("binaries", "test_corpus"),
+ dest="test_store", action="store", type="string",
+ help="input directory containing the binaries you which to generate unit tests from (relative to this file)")
+
+ options, args = parser.parse_args()
+
+ myprint("[+] INFO: Using test store: %s" % options.test_store)
+ if len(testcommon.get_file_list(options.test_store)) == 0:
+ myprint("ERROR: No files in the test store %s" % testcommon.get_file_list(options.test_store))
+ sys.exit(1)
+
+ myprint("[+] INFO: Generating test store")
+ try:
+ generate(options.test_store, options.outputdir, options.exclude_binary)
+ except TestStoreError as te:
+ myprint("[-] ERROR: Failed to generate test store: %s" % te.message)
+ sys.exit(1)
+ myprint("[+] SUCCESS: Generating test store")
+ sys.exit(0)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/suite/pwnadventurez.nes b/suite/pwnadventurez.nes
new file mode 100644
index 00000000..630684e3
--- /dev/null
+++ b/suite/pwnadventurez.nes
Binary files differ
diff --git a/suite/testcommon.py b/suite/testcommon.py
new file mode 100644
index 00000000..285c24b5
--- /dev/null
+++ b/suite/testcommon.py
@@ -0,0 +1,802 @@
+import tempfile
+import pickle
+import os
+import sys
+import zipfile
+import inspect
+import binaryninja as binja
+from binaryninja.binaryview import BinaryViewType, BinaryView
+from binaryninja.filemetadata import FileMetadata
+import subprocess
+import re
+
+
+# Dear people from the future: If you're adding tests or debuging an
+# issue where python2 and python3 are producing different output
+# for the same function and it's a issue of `longs`, run the output
+# through this function. If it's a unicode/bytes issue, fix it in
+# api/python/
+def fixOutput(outputList):
+ # Apply regular expression to detect python2 longs
+ splitList = []
+ for elem in outputList:
+ if isinstance(elem, str):
+ splitList.append(re.split(r"((?<=[\[ ])0x[\da-f]+L|[\d]+L)", elem))
+ else:
+ splitList.append(elem)
+
+ # Resolve application of regular expression
+ result = []
+ for elem in splitList:
+ if isinstance(elem, list):
+ newElem = []
+ for item in elem:
+ if len(item) > 1 and item[-1] == 'L':
+ newElem.append(item[:-1])
+ else:
+ newElem.append(item)
+ result.append(''.join(newElem))
+ else:
+ result.append(elem)
+ return result
+
+
+# Alright so this one is here for Binja functions that output <in set([blah, blah, blah])>
+def fixSet(string):
+ # Apply regular expression
+ splitList = (re.split(r"((?<=<in set\(\[).*(?=\]\)>))", string))
+ if len(splitList) > 1:
+ return splitList[0] + ', '.join(sorted(splitList[1].split(', '))) + splitList[2]
+ else:
+ return string
+
+
+def get_file_list(test_store_rel):
+ test_store = os.path.join(os.path.dirname(__file__), test_store_rel)
+ all_files = []
+ for root, dir, files in os.walk(test_store):
+ for file in files:
+ all_files.append(os.path.join(root, file))
+ return all_files
+
+def remove_low_confidence(type_string):
+ low_confidence_types = ["int32_t", "void"]
+ for lct in low_confidence_types:
+ type_string = type_string.replace(lct + " ", '') # done to resolve confidence ties
+ return type_string
+
+class Builder(object):
+ def __init__(self, test_store):
+ self.test_store = test_store
+ # binja.log.log_to_stdout(binja.LogLevel.DebugLog) # Uncomment for more info
+
+ def methods(self):
+ methodnames = []
+ for methodname, method in inspect.getmembers(self, predicate=inspect.ismethod):
+ if methodname.startswith("test_"):
+ methodnames.append(methodname)
+ return methodnames
+
+ def unpackage_file(self, filename):
+ path = os.path.join(os.path.dirname(__file__), self.test_store, filename)
+ if not os.path.exists(path):
+ with zipfile.ZipFile(path + ".zip", "r") as zf:
+ zf.extractall(path = os.path.dirname(__file__))
+ assert os.path.exists(path)
+ return os.path.relpath(path)
+
+
+class BinaryViewTestBuilder(Builder):
+ """ The BinaryViewTestBuilder is for test that are verified against a binary.
+ The tests are first run on your dev machine to base line then run again
+ on the build machine to verify they are correct.
+
+ - Function that are tests should start with 'test_'
+ - Function doc string used as 'on error' message
+ - Should return: list of strings
+ """
+ def __init__(self, filename):
+ self.filename = os.path.join(os.path.dirname(__file__), filename)
+ self.bv = BinaryViewType.get_view_of_file(self.filename)
+ if self.bv is None:
+ print("%s is not an executable format" % filename)
+ return
+
+ def test_available_types(self):
+ """Available types don't match"""
+ return ["Available Type: " + x.name for x in BinaryView(FileMetadata()).open(self.filename).available_view_types]
+
+ def test_function_starts(self):
+ """Function starts list doesnt match"""
+ result = []
+ for x in self.bv.functions:
+ result.append("Function start: " + hex(x.start))
+ return fixOutput(result)
+
+ def test_function_symbol_names(self):
+ """Function.symbol.name list doesnt match"""
+ result = []
+ for x in self.bv.functions:
+ result.append("Symbol: " + x.symbol.name + ' ' + str(x.symbol.type) + ' ' + hex(x.symbol.address))
+ return fixOutput(result)
+
+ def test_function_can_return(self):
+ """Function.can_return list doesnt match"""
+ result = []
+ for x in self.bv.functions:
+ result.append("function name: " + x.symbol.name + ' type: ' + str(x.symbol.type) + ' address: ' + hex(x.symbol.address) + ' can_return: ' + str(bool(x.can_return)))
+ return fixOutput(result)
+
+ def test_function_basic_blocks(self):
+ """Function basic_block list doesnt match (start, end, has_undetermined_outgoing_edges)"""
+ bblist = []
+ for func in self.bv.functions:
+ for bb in func.basic_blocks:
+ bblist.append("basic block {} start: ".format(str(bb)) + hex(bb.start) + ' end: ' + hex(bb.end) + ' undetermined outgoing edges: ' + str(bb.has_undetermined_outgoing_edges))
+ for anno in func.get_block_annotations(bb.start):
+ bblist.append("basic block {} function annotation: ".format(str(bb)) + str(anno))
+ bblist.append("basic block {} test get self: ".format(str(bb)) + str(func.get_basic_block_at(bb.start)))
+ return fixOutput(bblist)
+
+ def test_function_low_il_basic_blocks(self):
+ """Function low_il_basic_block list doesnt match"""
+ ilbblist = []
+ for func in self.bv.functions:
+ for bb in func.low_level_il.basic_blocks:
+ ilbblist.append("LLIL basic block {} start: ".format(str(bb)) + hex(bb.start) + ' end: ' + hex(bb.end) + ' outgoing edges: ' + str(len(bb.outgoing_edges)))
+ return fixOutput(ilbblist)
+
+ def test_function_med_il_basic_blocks(self):
+ """Function med_il_basic_block list doesn't match"""
+ ilbblist = []
+ for func in self.bv.functions:
+ for bb in func.medium_level_il.basic_blocks:
+ ilbblist.append("MLIL basic block {} start: ".format(str(bb)) + hex(bb.start) + ' end: ' + hex(bb.end) + ' outgoing_edges: ' + str(len(bb.outgoing_edges)))
+ return fixOutput(ilbblist)
+
+ def test_symbols(self):
+ """Symbols list doesn't match"""
+ return ["Symbol: " + str(i) for i in sorted(self.bv.symbols)]
+
+ def test_strings(self):
+ """Strings list doesn't match"""
+ return fixOutput(["String: " + str(x.value) + ' type: ' + str(x.type) + ' at: ' + hex(x.start) for x in self.bv.strings])
+
+ def test_low_il_instructions(self):
+ """LLIL instructions produced different output"""
+ retinfo = []
+ for func in self.bv.functions:
+ for bb in func.low_level_il.basic_blocks:
+ for ins in bb:
+ retinfo.append("MLIL: " + str(ins.medium_level_il))
+ retinfo.append("Mapped MLIL: " + str(ins.mapped_medium_level_il))
+ retinfo.append("Value: " + str(ins.value))
+ retinfo.append("Possible Values: " + str(ins.possible_values))
+ retinfo.append("Prefix operands: " + str(ins.prefix_operands))
+ retinfo.append("Postfix operands: " + str(ins.postfix_operands))
+ retinfo.append("SSA form: " + str(ins.ssa_form))
+ retinfo.append("Non-SSA form: " + str(ins.non_ssa_form))
+ return fixOutput(retinfo)
+
+ def test_low_il_ssa(self):
+ """LLIL ssa produced different output"""
+ retinfo = []
+ for func in self.bv.functions:
+ func = func.low_level_il
+ for reg_name in self.bv.arch.regs:
+ reg = binja.SSARegister(reg_name, 1)
+ retinfo.append("Reg {} SSA definition: ".format(reg_name) + str(func.get_ssa_reg_definition(reg)))
+ retinfo.append("Reg {} SSA uses: ".format(reg_name) + str(func.get_ssa_reg_uses(reg)))
+ retinfo.append("Reg {} SSA value: ".format(reg_name) + str(func.get_ssa_reg_value(reg)))
+ for flag_name in self.bv.arch.flags:
+ flag = binja.SSAFlag(flag_name, 1)
+ retinfo.append("Flag {} SSA uses: ".format(flag_name) + str(func.get_ssa_flag_uses(flag)))
+ retinfo.append("Flag {} SSA value: ".format(flag_name) + str(func.get_ssa_flag_value(flag)))
+ for bb in func.basic_blocks:
+ for ins in bb:
+ tempind = func.get_non_ssa_instruction_index(ins.instr_index)
+ retinfo.append("Non-SSA instruction index: " + str(tempind))
+ retinfo.append("SSA instruction index: " + str(func.get_ssa_instruction_index(tempind)))
+ retinfo.append("MLIL instruction index: " + str(func.get_medium_level_il_instruction_index(ins.instr_index)))
+ retinfo.append("Mapped MLIL instruction index: " + str(func.get_mapped_medium_level_il_instruction_index(ins.instr_index)))
+ return fixOutput(retinfo)
+
+ def test_med_il_instructions(self):
+ """MLIL instructions produced different output"""
+ retinfo = []
+ for func in self.bv.functions:
+ for bb in func.medium_level_il.basic_blocks:
+ for ins in bb:
+ retinfo.append("Expression type: " + str(ins.expr_type))
+ retinfo.append("LLIL: " + str(ins.low_level_il))
+ retinfo.append("Value: " + str(ins.value))
+ retinfo.append("Possible values: " + str(ins.possible_values))
+ retinfo.append("Branch dependence: " + str(sorted(ins.branch_dependence.items())))
+
+ prefixList = []
+ for i in ins.prefix_operands:
+ if isinstance(i, float) and 'e' in str(i):
+ prefixList.append(str(round(i, 21)))
+ elif isinstance(i, float):
+ prefixList.append(str(round(i, 11)))
+ else:
+ prefixList.append(str(i))
+ retinfo.append("Prefix operands: " + str(sorted(prefixList)))
+ postfixList = []
+ for i in ins.prefix_operands:
+ if isinstance(i, float) and 'e' in str(i):
+ postfixList.append(str(round(i, 21)))
+ elif isinstance(i, float):
+ postfixList.append(str(round(i, 11)))
+ else:
+ postfixList.append(str(i))
+
+ retinfo.append("Postfix operands: " + str(sorted(postfixList)))
+ retinfo.append("SSA form: " + str(ins.ssa_form))
+ retinfo.append("Non-SSA form" + str(ins.non_ssa_form))
+ return fixOutput(retinfo)
+
+ def test_med_il_vars(self):
+ """Function med_il_vars doesn't match"""
+ varlist = []
+ for func in self.bv.functions:
+ func = func.medium_level_il
+ for bb in func.basic_blocks:
+ for instruction in bb:
+ instruction = instruction.ssa_form
+ for var in (instruction.vars_read + instruction.vars_written):
+ if hasattr(var, "var"):
+ varlist.append("SSA var definition: " + str(func.get_ssa_var_definition(var)))
+ varlist.append("SSA var uses: " + str(func.get_ssa_var_uses(var)))
+ varlist.append("SSA var value: " + str(func.get_ssa_var_value(var)))
+ varlist.append("SSA var possible values: " + fixSet(str(instruction.get_ssa_var_possible_values(var))))
+ varlist.append("SSA var version: " + str(instruction.get_ssa_var_version))
+ return fixOutput(varlist)
+
+ def test_function_stack(self):
+ """Function stack produced different output"""
+ funcinfo = []
+ for func in self.bv.functions:
+ func.stack_adjustment = func.stack_adjustment
+ func.reg_stack_adjustments = func.reg_stack_adjustments
+ func.create_user_stack_var(0, binja.Type.int(4), "testuservar")
+ func.create_auto_stack_var(4, binja.Type.int(4), "testautovar")
+
+ sl = func.stack_layout
+ for i in range(len(sl)):
+ funcinfo.append("Stack position {}: ".format(i) + str(sl[i]))
+
+ funcinfo.append("Stack content sample: " + str(func.get_stack_contents_at(func.start + 0x10, 0, 0x10)))
+ funcinfo.append("Stack content range sample: " + str(func.get_stack_contents_after(func.start + 0x10, 0, 0x10)))
+ funcinfo.append("Sample stack var: " + str(func.get_stack_var_at_frame_offset(0, 0)))
+ func.delete_user_stack_var(0)
+ func.delete_auto_stack_var(0)
+ return funcinfo
+
+ def test_function_llil(self):
+ """Function LLIL produced different output"""
+ retinfo = []
+ for func in self.bv.functions:
+ for llilbb in func.llil_basic_blocks:
+ retinfo.append("LLIL basic block: " + str(llilbb))
+ for llilins in func.llil_instructions:
+ retinfo.append("LLIL instruction: " + str(llilins))
+ for mlilbb in func.mlil_basic_blocks:
+ retinfo.append("MLIL basic block: " + str(mlilbb))
+ for mlilins in func.mlil_instructions:
+ retinfo.append("MLIL instruction: " + str(mlilins))
+ for ins in func.instructions:
+ retinfo.append("Instruction: {}: ".format(hex(ins[1])) + ''.join([str(i) for i in ins[0]]))
+ return fixOutput(retinfo)
+
+ def test_functions_attributes(self):
+ """Function attributes don't match"""
+ funcinfo = []
+ for func in self.bv.functions:
+ func.comment = "testcomment " + func.name
+ func.name = func.name
+ func.can_return = func.can_return
+ func.function_type = func.function_type
+ func.return_type = func.return_type
+ func.return_regs = func.return_regs
+ func.calling_convention = func.calling_convention
+ func.parameter_vars = func.parameter_vars
+ func.has_variable_arguments = func.has_variable_arguments
+ func.analysis_skipped = func.analysis_skipped
+ func.clobbered_regs = func.clobbered_regs
+ func.set_user_instr_highlight(func.start, binja.highlight.HighlightColor(red=0xff, blue=0xff, green=0))
+ func.set_auto_instr_highlight(func.start, binja.highlight.HighlightColor(red=0xff, blue=0xfe, green=0))
+
+ for var in func.vars:
+ funcinfo.append("Function {} var: ".format(func.name) + str(var))
+
+ for branch in func.indirect_branches:
+ funcinfo.append("Function {} indirect branch: ".format(func.name) + str(branch))
+ funcinfo.append("Function {} session data: ".format(func.name) + str(func.session_data))
+ funcinfo.append("Function {} analysis perf length: ".format(func.name) + str(len(func.analysis_performance_info)))
+ for cr in func.clobbered_regs:
+ funcinfo.append("Function {} clobbered reg: ".format(func.name) + str(cr))
+ funcinfo.append("Function {} explicitly defined type: ".format(func.name) + str(func.explicitly_defined_type))
+ funcinfo.append("Function {} needs update: ".format(func.name) + str(func.needs_update))
+ funcinfo.append("Function {} global pointer value: ".format(func.name) + str(func.global_pointer_value))
+ funcinfo.append("Function {} comment: ".format(func.name) + str(func.comment))
+ funcinfo.append("Function {} too large: ".format(func.name) + str(func.too_large))
+ funcinfo.append("Function {} analysis skipped: ".format(func.name) + str(func.analysis_skipped))
+ funcinfo.append("Function {} first ins LLIL: ".format(func.name) + str(func.get_low_level_il_at(func.start)))
+ funcinfo.append("Function {} LLIL exit test: ".format(func.name) + str(func.get_low_level_il_exits_at(func.start+0x100)))
+ funcinfo.append("Function {} regs read test: ".format(func.name) + str(func.get_regs_read_by(func.start)))
+ funcinfo.append("Function {} regs written test: ".format(func.name) + str(func.get_regs_written_by(func.start)))
+ funcinfo.append("Function {} stack var test: ".format(func.name) + str(func.get_stack_vars_referenced_by(func.start)))
+ funcinfo.append("Function {} constant reference test: ".format(func.name) + str(func.get_constants_referenced_by(func.start)))
+ funcinfo.append("Function {} first ins lifted IL: ".format(func.name) + str(func.get_lifted_il_at(func.start)))
+ funcinfo.append("Function {} flags read by lifted IL ins: ".format(func.name) + str(func.get_flags_read_by_lifted_il_instruction(0)))
+ funcinfo.append("Function {} flags written by lifted IL ins: ".format(func.name) + str(func.get_flags_written_by_lifted_il_instruction(0)))
+ funcinfo.append("Function {} create graph: ".format(func.name) + str(func.create_graph()))
+ funcinfo.append("Function {} indirect branches test: ".format(func.name) + str(func.get_indirect_branches_at(func.start+0x10)))
+ funcinfo.append("Function {} test instr highlight: ".format(func.name) + str(func.get_instr_highlight(func.start)))
+ for token in func.get_type_tokens():
+ token = str(token)
+ token = remove_low_confidence(token)
+ funcinfo.append("Function {} type token: ".format(func.name) + str(token))
+ return fixOutput(funcinfo)
+
+ def test_BinaryView(self):
+ """BinaryView produced different results"""
+ retinfo = []
+
+ for type in self.bv.types.items():
+ retinfo.append("BV Type: " + str(type))
+ for segment in sorted([str(i) for i in self.bv.segments]):
+ retinfo.append("BV segment: " + str(segment))
+ for section in sorted(self.bv.sections):
+ retinfo.append("BV section: " + str(section))
+ for allrange in self.bv.allocated_ranges:
+ retinfo.append("BV allocated range: " + str(allrange))
+ retinfo.append("Session Data: " + str(self.bv.session_data))
+ for var in self.bv.data_vars:
+ retinfo.append("BV data var: " + str(var))
+ retinfo.append("BV Entry function: " + str(self.bv.entry_function))
+ for i in self.bv:
+ retinfo.append("BV function: " + str(i))
+ retinfo.append("BV entry point: " + hex(self.bv.entry_point))
+ retinfo.append("BV start: " + hex(self.bv.start))
+ retinfo.append("BV length: " + hex(len(self.bv)))
+
+ return fixOutput(retinfo)
+
+
+class TestBuilder(Builder):
+ """ The TestBuilder is for tests that need to be checked againsttest_BinaryView
+ stored oracle data that isn't from a binary. These test are
+ generated on your local machine then run again on the build
+ machine to verify correctness.
+
+ - Function that are tests should start with 'test_'
+ - Function doc string used as 'on error' message
+ - Should return: list of strings
+ """
+
+ def test_BinaryViewType_list(self):
+ """BinaryViewType list doesnt match"""
+ return ["BinaryViewType: " + x.name for x in binja.BinaryViewType.list]
+
+ def test_Architecture_list(self):
+ """Architecture list doesnt match"""
+ return ["Arch name: " + x.name for x in binja.Architecture.list]
+
+ def test_Assemble(self):
+ """unexpected assemble result"""
+ result = []
+ # success cases
+
+ strResult = binja.Architecture["x86"].assemble("xor eax, eax")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("x86 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("x86 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["x86_64"].assemble("xor rax, rax")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("x86_64 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("x86_64 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["mips32"].assemble("move $ra, $zero")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("mips32 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("mips32 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["mipsel32"].assemble("move $ra, $zero")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("mipsel32 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("mipsel32 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["armv7"].assemble("str r2, [sp, #-0x4]!")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("armv7 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("armv7 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["aarch64"].assemble("mov x0, x0")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("aarch64 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("aarch64 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["thumb2"].assemble("ldr r4, [r4]")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("thumb2 assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("thumb2 assembly: " + repr(str(strResult)))
+ strResult = binja.Architecture["thumb2eb"].assemble("ldr r4, [r4]")
+ if sys.version_info.major == 3 and not strResult[0] is None:
+ result.append("thumb2eb assembly: " + "'" + str(strResult)[2:-1] + "'")
+ else:
+ result.append("thumb2eb assembly: " + repr(str(strResult)))
+
+ # fail cases
+ try:
+ strResult = binja.Architecture["x86"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'x86'")
+ try:
+ strResult = binja.Architecture["x86_64"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'x86_64'")
+ try:
+ strResult = binja.Architecture["mips32"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'mips32'")
+ try:
+ strResult = binja.Architecture["mipsel32"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'mipsel32'")
+ try:
+ strResult = binja.Architecture["armv7"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'armv7'")
+ try:
+ strResult = binja.Architecture["aarch64"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'aarch64'")
+ try:
+ strResult = binja.Architecture["thumb2"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'thumb2'")
+ try:
+ strResult = binja.Architecture["thumb2eb"].assemble("thisisnotaninstruction")
+ except ValueError:
+ result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'thumb2eb'")
+ return result
+
+ def test_Architecture(self):
+ """Architecture failure"""
+ if not os.path.exists(os.path.join(os.path.expanduser("~"), '.binaryninja', 'plugins', 'nes.py')):
+ return [""]
+
+ retinfo = []
+ file_name = os.path.join(self.test_store, "..", "pwnadventurez.nes")
+ bv = binja.BinaryViewType["NES Bank 0"].open(file_name)
+
+ for i in bv.platform.arch.calling_conventions:
+ retinfo.append("Custom arch calling convention: " + str(i))
+ for i in bv.platform.arch.full_width_regs:
+ retinfo.append("Custom arch full width reg: " + str(i))
+
+ reg = binja.RegisterValue()
+ retinfo.append("Reg entry value: " + str(reg.entry_value(bv.platform.arch, 'x')))
+ retinfo.append("Reg constant: " + str(reg.constant(0xfe)))
+ retinfo.append("Reg constant pointer: " + str(reg.constant_ptr(0xcafebabe)))
+ retinfo.append("Reg stack frame offset: " + str(reg.stack_frame_offset(0x10)))
+ retinfo.append("Reg imported address: " + str(reg.imported_address(0xdeadbeef)))
+ retinfo.append("Reg return address: " + str(reg.return_address()))
+
+ bv.update_analysis_and_wait()
+ for func in bv.functions:
+ for bb in func.low_level_il.basic_blocks:
+ for ins in bb:
+ retinfo.append("Instruction info: " + str(bv.platform.arch.get_instruction_info(0x10, ins.address)))
+ retinfo.append("Instruction test: " + str(bv.platform.arch.get_instruction_text(0x10, ins.address)))
+ retinfo.append("Instruction: " + str(ins))
+ return retinfo
+
+ def test_Function(self):
+ """Function produced different result"""
+ inttype = binja.Type.int(4)
+ testfunction = binja.Type.function(inttype, [inttype, inttype, inttype])
+ return ["Test_function params: " + str(testfunction.parameters), "Test_function pointer: " + str(testfunction.pointer(binja.Architecture["x86"], testfunction))]
+
+ def test_Struct(self):
+ """Struct produced different result"""
+ retinfo = []
+ inttype = binja.Type.int(4)
+ struct = binja.Structure()
+ struct.a = 1
+ struct.insert(0, inttype)
+ struct.append(inttype)
+ struct.replace(0, inttype)
+ struct.remove(1)
+ for i in struct.members:
+ retinfo.append("Struct member: " + str(i))
+ retinfo.append("Struct width: " + str(struct.width))
+ struct.width = 16
+ retinfo.append("Struct width after adjustment: " + str(struct.width))
+ retinfo.append("Struct alignment: " + str(struct.alignment))
+ struct.alignment = 8
+ retinfo.append("Struct alignment after adjustment: " + str(struct.alignment))
+ retinfo.append("Struct packed: " + str(struct.packed))
+ struct.packed = 1
+ retinfo.append("Struct packed after adjustment: " + str(struct.packed))
+ retinfo.append("Struct type: " + str(struct.type))
+ return retinfo
+
+ def test_Enumeration(self):
+ """Enumeration produced different result"""
+ retinfo = []
+ inttype = binja.Type.int(4)
+ enum = binja.Enumeration()
+ enum.a = 1
+ enum.append("a", 1)
+ enum.append("b", 2)
+ enum.replace(0, "a", 2)
+ enum.remove(0)
+ retinfo.append(str(enum))
+ retinfo.append(str((enum == enum) and not (enum != enum)))
+ return retinfo
+
+ def test_Types(self):
+ """Types produced different result"""
+ file_name = self.unpackage_file("helloworld")
+ bv = binja.BinaryViewType.get_view_of_file(file_name)
+
+ preprocessed = binja.preprocess_source("""
+ #ifdef nonexistant
+ int foo = 1;
+ long long foo1 = 1;
+ #else
+ int bar = 2;
+ long long bar1 = 2;
+ #endif
+ """)
+ source = '\n'.join([i.decode('charmap') for i in preprocessed[0].split(b'\n') if not b'#line' in i and len(i) > 0])
+ typelist = bv.platform.parse_types_from_source(source)
+ inttype = binja.Type.int(4)
+
+ tokens = inttype.get_tokens() + inttype.get_tokens_before_name() + inttype.get_tokens_after_name()
+ namedtype = binja.NamedTypeReference()
+
+ retinfo = []
+ for i in range(len(typelist.variables)):
+ for j in typelist.variables.popitem():
+ retinfo.append("Type: " + str(j))
+ retinfo.append("Named Type: " + str(namedtype))
+
+ retinfo.append("Type equality: " + str((inttype == inttype) and not (inttype != inttype)))
+ return retinfo
+
+ def test_Plugin_bin_info(self):
+ """print_syscalls plugin produced different result"""
+ file_name = self.unpackage_file("helloworld")
+ bin_info_path = os.path.join(os.path.dirname(__file__), '..', 'python', 'examples', 'bin_info.py')
+ result = subprocess.Popen(["python", bin_info_path, file_name], stdout=subprocess.PIPE).communicate()[0]
+ # normalize line endings and path sep
+ return [line for line in result.replace(b"\\", b"/").replace(b"\r\n", b"\n").decode("charmap").split("\n")]
+
+ def test_linear_disassembly(self):
+ """linear_disassembly produced different result"""
+ file_name = self.unpackage_file("helloworld")
+ bv = binja.BinaryViewType['ELF'].open(file_name)
+ disass = bv.linear_disassembly
+ retinfo = []
+ for i in disass:
+ i = str(i)
+ i = remove_low_confidence(i)
+ retinfo.append(i)
+ return retinfo
+
+ def test_partial_register_dataflow(self):
+ """partial_register_dataflow produced different results"""
+ file_name = self.unpackage_file("partial_register_dataflow")
+ result = []
+ reg_list = ['ch', 'cl', 'ah', 'edi', 'al', 'cx', 'ebp', 'ax', 'edx', 'ebx', 'esp', 'esi', 'dl', 'dh', 'di', 'bl', 'bh', 'eax', 'dx', 'bx', 'ecx', 'sp', 'si']
+ bv = binja.BinaryViewType.get_view_of_file(file_name)
+ for func in bv.functions:
+ llil = func.low_level_il
+ for i in range(0, llil.__len__()-1):
+ for x in reg_list:
+ result.append("LLIL:" + str(i).replace('L', '') + ":" + x + ":" + str(llil[i].get_reg_value(x)).replace('L', ''))
+ result.append("LLIL:" + str(i).replace('L', '') + ":" + x + ":" + str(llil[i].get_possible_reg_values(x)).replace('L', ''))
+ result.append("LLIL:" + str(i).replace('L', '') + ":" + x + ":" + str(llil[i].get_reg_value_after(x)).replace('L', ''))
+ result.append("LLIL:" + str(i).replace('L', '') + ":" + x + ":" + str(llil[i].get_possible_reg_values_after(x)).replace('L', ''))
+ bv.file.close()
+ del bv
+ return result
+
+
+ def test_low_il_stack(self):
+ """LLIL stack produced different output"""
+ file_name = self.unpackage_file("jumptable_reordered")
+ bv = binja.BinaryViewType.get_view_of_file(file_name)
+ reg_list = ['ch', 'cl', 'ah', 'edi', 'al', 'cx', 'ebp', 'ax', 'edx', 'ebx', 'esp', 'esi', 'dl', 'dh', 'di', 'bl', 'bh', 'eax', 'dx', 'bx', 'ecx', 'sp', 'si']
+ flag_list = ['c', 'p', 'a', 'z', 's', 'o']
+ retinfo = []
+ for func in bv.functions:
+ for bb in func.low_level_il.basic_blocks:
+ for ins in bb:
+ retinfo.append("LLIL first stack element: " + str(ins.get_stack_contents(0,1)))
+ retinfo.append("LLIL second stack element: " + str(ins.get_stack_contents_after(0,1)))
+ retinfo.append("LLIL possible first stack element: " + str(ins.get_possible_stack_contents(0,1)))
+ retinfo.append("LLIL possible second stack element: " + str(ins.get_possible_stack_contents_after(0,1)))
+ for flag in flag_list:
+ retinfo.append("LLIL flag {} value at: ".format(flag, hex(ins.address)) + str(ins.get_flag_value(flag)))
+ retinfo.append("LLIL flag {} value after {}: ".format(flag, hex(ins.address)) + str(ins.get_flag_value_after(flag)))
+ retinfo.append("LLIL flag {} possible value at {}: ".format(flag, hex(ins.address)) + str(ins.get_possible_flag_values(flag)))
+ retinfo.append("LLIL flag {} possible value after {}: ".format(flag, hex(ins.address)) + str(ins.get_possible_flag_values_after(flag)))
+ return fixOutput(retinfo)
+
+ def test_med_il_stack(self):
+ """MLIL stack produced different output"""
+ file_name = self.unpackage_file("jumptable_reordered")
+ bv = binja.BinaryViewType.get_view_of_file(file_name)
+ reg_list = ['ch', 'cl', 'ah', 'edi', 'al', 'cx', 'ebp', 'ax', 'edx', 'ebx', 'esp', 'esi', 'dl', 'dh', 'di', 'bl', 'bh', 'eax', 'dx', 'bx', 'ecx', 'sp', 'si']
+ flag_list = ['c', 'p', 'a', 'z', 's', 'o']
+ retinfo = []
+ for func in bv.functions:
+ for bb in func.medium_level_il.basic_blocks:
+ for ins in bb:
+ retinfo.append("MLIL stack begin var: " + str(ins.get_var_for_stack_location(0)))
+ retinfo.append("MLIL first stack element: " + str(ins.get_stack_contents(0, 1)))
+ retinfo.append("MLIL second stack element: " + str(ins.get_stack_contents_after(0, 1)))
+ retinfo.append("MLIL possible first stack element: " + str(ins.get_possible_stack_contents(0, 1)))
+ retinfo.append("MLIL possible second stack element: " + str(ins.get_possible_stack_contents_after(0, 1)))
+
+ for reg in reg_list:
+ retinfo.append("MLIL reg {} var at {}: ".format(reg, hex(ins.address)) + str(ins.get_var_for_reg(reg)))
+ retinfo.append("MLIL reg {} value at {}: ".format(reg, hex(ins.address)) + str(ins.get_reg_value(reg)))
+ retinfo.append("MLIL reg {} value after {}: ".format(reg, hex(ins.address)) + str(ins.get_reg_value_after(reg)))
+ retinfo.append("MLIL reg {} possible value at {}: ".format(reg, hex(ins.address)) + fixSet(str(ins.get_possible_reg_values(reg))))
+ retinfo.append("MLIL reg {} possible value after {}: ".format(reg, hex(ins.address)) + fixSet(str(ins.get_possible_reg_values_after(reg))))
+
+ for flag in flag_list:
+ retinfo.append("MLIL flag {} value at: ".format(flag, hex(ins.address)) + str(ins.get_flag_value(flag)))
+ retinfo.append("MLIL flag {} value after {}: ".format(flag, hex(ins.address)) + str(ins.get_flag_value_after(flag)))
+ retinfo.append("MLIL flag {} possible value at {}: ".format(flag, hex(ins.address)) + fixSet(str(ins.get_possible_flag_values(flag))))
+ retinfo.append("MLIL flag {} possible value after {}: ".format(flag, hex(ins.address)) + fixSet(str(ins.get_possible_flag_values(flag))))
+ return fixOutput(retinfo)
+
+ def test_events(self):
+ """Event failure"""
+ file_name = self.unpackage_file("helloworld")
+ bv = binja.BinaryViewType['ELF'].open(file_name)
+ bv.update_analysis_and_wait()
+
+ results = []
+
+ def simple_complete(self):
+ results.append("analysis complete")
+ evt = binja.AnalysisCompletionEvent(bv, simple_complete)
+
+ class NotifyTest(binja.BinaryDataNotification):
+ def data_written(self, view, offset, length):
+ results.append("data written: offset {0} length {1}".format(hex(offset), hex(length)))
+
+ def data_inserted(self, view, offset, length):
+ results.append("data inserted: offset {0} length {1}".format(hex(offset), hex(length)))
+
+ def data_removed(self, view, offset, length):
+ results.append("data removed: offset {0} length {1}".format(hex(offset), hex(length)))
+
+ def function_added(self, view, func):
+ results.append("function added: {0}".format(func.name))
+
+ def function_removed(self, view, func):
+ results.append("function removed: {0}".format(func.name))
+
+ def data_var_added(self, view, var):
+ results.append("data var added: {0}".format(hex(var.address)))
+
+ def data_var_removed(self, view, var):
+ results.append("data var removed: {0}".format(hex(var.address)))
+
+ def string_found(self, view, string_type, offset, length):
+ results.append("string found: offset {0} length {1}".format(hex(offset), hex(length)))
+
+ def string_removed(self, view, string_type, offset, length):
+ results.append("string removed: offset {0} length {1}".format(hex(offset), hex(length)))
+
+ def type_defined(self, view, name, type):
+ results.append("type defined: {0}".format(name))
+
+ def type_undefined(self, view, name, type):
+ results.append("type undefined: {0}".format(name))
+
+ test = NotifyTest()
+ bv.register_notification(test)
+ sacrificial_addr = 0x84fc
+
+ type, name = bv.parse_type_string("int foo")
+ type_id = type.generate_auto_type_id("source", name)
+
+ bv.define_type(type_id, name, type)
+ bv.undefine_type(type_id)
+
+ bv.update_analysis_and_wait()
+
+ bv.insert(sacrificial_addr, b"AAAA")
+ bv.update_analysis_and_wait()
+
+ bv.define_data_var(sacrificial_addr, binja.types.Type.int(4))
+ bv.update_analysis_and_wait()
+
+ bv.write(sacrificial_addr, b"BBBB")
+ bv.update_analysis_and_wait()
+
+ bv.add_function(sacrificial_addr)
+ bv.update_analysis_and_wait()
+
+ bv.remove_function(bv.get_function_at(sacrificial_addr))
+ bv.update_analysis_and_wait()
+
+ bv.undefine_data_var(sacrificial_addr)
+ bv.update_analysis_and_wait()
+
+ bv.remove(sacrificial_addr, 4)
+ bv.update_analysis_and_wait()
+
+ bv.unregister_notification(test)
+
+ return fixOutput(sorted(results))
+
+
+class VerifyBuilder(Builder):
+ """ The VerifyBuilder is for tests that verify
+ Binary Ninja against expected output.
+
+ - Function that are tests should start with 'test_'
+ - Function doc string used as 'on error' message
+ - Should return: boolean
+ """
+
+ def __init__(self, test_store):
+ super(VerifyBuilder, self).__init__(test_store)
+
+ def get_functions(self, bv):
+ return [x.start for x in bv.functions]
+
+ def get_comments(self, bv):
+ return bv.functions[0].comments
+
+ def test_verify_BNDB_round_trip(self):
+ """Binary Ninja Database output doesn't match its input"""
+ # This will test Binja's ability to save and restore databases
+ # By:
+ # - Creating a binary view
+ # - Make modification that impact the database
+ # - Record those modification
+ # - Save the database
+ # - Restore the datbase
+ # - Validate that the modifications are present
+ file_name = self.unpackage_file("helloworld")
+ try:
+ bv = binja.BinaryViewType['ELF'].open(file_name)
+ bv.update_analysis_and_wait()
+ # Make some modifications to the binary view
+
+ # Add a comment
+ bv.functions[0].set_comment(bv.functions[0].start, "Function start")
+ # Add a new function
+ bv.add_function(bv.functions[0].start + 4)
+ temp_name = next(tempfile._get_candidate_names()) + ".bndb"
+
+ comments = self.get_comments(bv)
+ functions = self.get_functions(bv)
+ bv.create_database(temp_name)
+ bv.file.close()
+ del bv
+
+ bv = binja.FileMetadata(temp_name).open_existing_database(temp_name).get_view_of_type('ELF')
+ bv.update_analysis_and_wait()
+ bndb_functions = self.get_functions(bv)
+ bndb_comments = self.get_comments(bv)
+ # force windows to close the handle to the bndb that we want to delete
+ bv.file.close()
+ del bv
+ return [str(functions == bndb_functions and comments == bndb_comments)]
+ finally:
+ os.unlink(temp_name)
diff --git a/themes/dark-blue.theme b/themes/dark-blue.theme
new file mode 100644
index 00000000..b0f83598
--- /dev/null
+++ b/themes/dark-blue.theme
@@ -0,0 +1,108 @@
+{
+ "name": "Dark Blue",
+ "style": "Fusion",
+
+ "//": " Colors are specified as [Red, Green, Blue] values. Colors can be aliased in the 'colors' ",
+ "//": " section. Colors can also be averaged and mixed together using an RPN like notation: ",
+ "//": " '+' indicates 'average' - average the next two colors.",
+ "//": " '~' indicates 'mix' - mix the next two colors with the weight 0->255",
+ "//": " e.g.",
+ "//": " ['+', 'red', 'blue'] - average red and blue",
+ "//": " ['~', 'red', 'blue', 20] - mix a small amount of blue with red",
+ "//": " ['~', 'red', 'blue', 200] - mix a large amount of blue with red",
+ "//": " ['+', '~', 'red', 'blue', 20, 'green'] - mix red and blue with weight 20 then average with green",
+ "//": " The 'palette' section is to specify colors for the QPalette::ColorRole",
+
+ "colors": {
+ "background": [0, 0, 42],
+ "backgroundDark": [0, 0, 30],
+ "backgroundWindow": [0, 0, 80],
+ "backgroundHighlight": [0, 0, 128],
+ "content": [224, 224, 224],
+ "disabled": [144, 144, 144],
+ "selection": [96, 96, 96],
+ "selectionLight": [128, 128, 128],
+ "green": [0, 255, 0],
+ "red": [222, 143, 151],
+ "blue": [128, 198, 233],
+ "cyan": [142, 230, 237],
+ "lightCyan": [176, 221, 228],
+ "orange": [237, 189, 129],
+ "yellow": [237, 223, 179],
+ "magenta": [218, 196, 209]
+ },
+
+ "palette": {
+ "Window": "backgroundWindow",
+ "WindowText": "content",
+ "Base": "backgroundDark",
+ "AlternateBase": "background",
+ "ToolTipBase": "backgroundHighlight",
+ "ToolTipText": "content",
+ "Text": "content",
+ "Button": "backgroundHighlight",
+ "ButtonText": "content",
+ "BrightText": "yellow",
+ "Link": "blue",
+ "Highlight": "blue",
+ "HighlightedText": "backgroundDark",
+ "Light": ["+", "backgroundDark", "content"]
+ },
+
+ "theme-colors": {
+ "addressColor": "green",
+ "modifiedColor": "red",
+ "insertedColor": "blue",
+ "notPresentColor": "disabled",
+ "selectionColor": "selection",
+ "outlineColor": "content",
+ "backgroundHighlightDarkColor": "backgroundDark",
+ "backgroundHighlightLightColor": "backgroundWindow",
+ "boldBackgroundHighlightDarkColor": "backgroundDark",
+ "boldBackgroundHighlightLightColor": "selection",
+ "alphanumericHighlightColor": "blue",
+ "printableHighlightColor": "lightCyan",
+ "graphBackgroundDarkColor": "background",
+ "graphBackgroundLightColor": "background",
+ "graphNodeDarkColor": "backgroundHighlight",
+ "graphNodeLightColor": "backgroundHighlight",
+ "graphNodeOutlineColor": "disabled",
+ "trueBranchColor": "green",
+ "falseBranchColor": "red",
+ "unconditionalBranchColor": "blue",
+ "altTrueBranchColor": "blue",
+ "altFalseBranchColor": "orange",
+ "altUnconditionalBranchColor": "content",
+ "registerColor": "yellow",
+ "numberColor": "green",
+ "codeSymbolColor": "blue",
+ "dataSymbolColor": "cyan",
+ "stackVariableColor": ["+", "green", "content"],
+ "importColor": "orange",
+ "instructionHighlightColor": "selectionLight",
+ "tokenHighlightColor": "red",
+ "annotationColor": "magenta",
+ "opcodeColor": "disabled",
+ "linearDisassemblyFunctionHeaderColor": "backgroundHighlight",
+ "linearDisassemblyBlockColor": "background",
+ "linearDisassemblyNoteColor": ["~", "+", "backgroundDark", "background", "green", 48],
+ "linearDisassemblySeparatorColor": "disabled",
+ "stringColor": "magenta",
+ "typeNameColor": "orange",
+ "fieldNameColor": "lightCyan",
+ "keywordColor": "yellow",
+ "uncertainColor": "disabled",
+ "scriptConsoleOutputColor": "content",
+ "scriptConsoleErrorColor": "red",
+ "scriptConsoleEchoColor": "disabled",
+ "blueStandardHighlightColor": "blue",
+ "greenStandardHighlightColor": "green",
+ "cyanStandardHighlightColor": "cyan",
+ "redStandardHighlightColor": "red",
+ "magentaStandardHighlightColor": "magenta",
+ "yellowStandardHighlightColor": "yellow",
+ "orangeStandardHighlightColor": "orange",
+ "whiteStandardHighlightColor": "content",
+ "blackStandardHighlightColor": [0,0,0]
+ }
+} \ No newline at end of file
diff --git a/themes/high-contrast.theme b/themes/high-contrast.theme
new file mode 100644
index 00000000..ecaf7c7c
--- /dev/null
+++ b/themes/high-contrast.theme
@@ -0,0 +1,107 @@
+{
+ "name": "High Contrast 2",
+ "style": "Fusion",
+
+ "//": "Colors are specified as [Red, Green, Blue] values. Colors can be aliased in the",
+ "//": "'colors' section. Colors can also be averaged and mixed together using an RPN like notation.",
+ "//": "'+' indicates 'average' directs the parser to average the next two colors.",
+ "//": "'~' indicates 'mix' directs the parser to mix the next two colors with the specified weight 0->255",
+ "//": "e.g.",
+ "//": " ['+', 'red', 'blue'] - average red and blue",
+ "//": " ['~', 'red', 'blue', 20] - mix a small amount of blue into red",
+ "//": " ['+', '~', 'red', 'blue', 20, 'green'] - mix red and blue with weight 20 then average with green",
+ "//": "The 'palette' section is to specify colors for the QPalette::ColorRole",
+
+ "colors": {
+ "background": [220, 220, 220],
+ "backgroundDark": [255, 255, 255],
+ "backgroundWindow": [240, 240, 240],
+ "backgroundHighlight": [255, 255, 255],
+ "content": [31, 31, 31],
+ "disabled": [122, 122, 122],
+ "selection": [159, 159, 159],
+ "selectionLight": [128, 128, 128],
+ "green": [48, 130, 13],
+ "red": [191, 38, 36],
+ "blue": [0, 164, 199],
+ "cyan": [39, 140, 173],
+ "lightCyan": [53, 218, 224],
+ "orange": [224, 124, 53],
+ "yellow": [141, 141, 45],
+ "magenta": [32, 54, 53]
+ },
+
+ "palette": {
+ "Window": "backgroundWindow",
+ "WindowText": "content",
+ "Base": "backgroundDark",
+ "AlternateBase": "background",
+ "ToolTipBase": "backgroundHighlight",
+ "ToolTipText": "content",
+ "Text": "content",
+ "Button": "backgroundHighlight",
+ "ButtonText": "content",
+ "BrightText": "magenta",
+ "Link": "blue",
+ "Highlight": "blue",
+ "HighlightedText": "backgroundDark",
+ "Light": ["+", "backgroundDark", "content"]
+ },
+
+ "theme-colors": {
+ "addressColor": "green",
+ "modifiedColor": "red",
+ "insertedColor": "blue",
+ "notPresentColor": "disabled",
+ "selectionColor": "selection",
+ "outlineColor": "content",
+ "backgroundHighlightDarkColor": "backgroundDark",
+ "backgroundHighlightLightColor": "backgroundWindow",
+ "boldBackgroundHighlightDarkColor": "backgroundDark",
+ "boldBackgroundHighlightLightColor": "selection",
+ "alphanumericHighlightColor": "blue",
+ "printableHighlightColor": "lightCyan",
+ "graphBackgroundDarkColor": "background",
+ "graphBackgroundLightColor": "background",
+ "graphNodeDarkColor": "backgroundHighlight",
+ "graphNodeLightColor": "backgroundHighlight",
+ "graphNodeOutlineColor": "disabled",
+ "trueBranchColor": "green",
+ "falseBranchColor": "red",
+ "unconditionalBranchColor": "blue",
+ "altTrueBranchColor": "blue",
+ "altFalseBranchColor": "orange",
+ "altUnconditionalBranchColor": "content",
+ "registerColor": "magenta",
+ "numberColor": "green",
+ "codeSymbolColor": "blue",
+ "dataSymbolColor": "cyan",
+ "stackVariableColor": ["+", "green", "content"],
+ "importColor": "orange",
+ "instructionHighlightColor": "selectionLight",
+ "tokenHighlightColor": "red",
+ "annotationColor": "red",
+ "opcodeColor": "disabled",
+ "linearDisassemblyFunctionHeaderColor": "backgroundHighlight",
+ "linearDisassemblyBlockColor": "background",
+ "linearDisassemblyNoteColor": ["~", "+", "backgroundDark", "background", "green", 48],
+ "linearDisassemblySeparatorColor": "disabled",
+ "stringColor": "magenta",
+ "typeNameColor": "orange",
+ "fieldNameColor": "lightCyan",
+ "keywordColor": "yellow",
+ "uncertainColor": "disabled",
+ "scriptConsoleOutputColor": "content",
+ "scriptConsoleErrorColor": "red",
+ "scriptConsoleEchoColor": "disabled",
+ "blueStandardHighlightColor": "blue",
+ "greenStandardHighlightColor": "green",
+ "cyanStandardHighlightColor": "cyan",
+ "redStandardHighlightColor": "red",
+ "magentaStandardHighlightColor": "magenta",
+ "yellowStandardHighlightColor": "yellow",
+ "orangeStandardHighlightColor": "orange",
+ "whiteStandardHighlightColor": "content",
+ "blackStandardHighlightColor": [0, 0, 0]
+ }
+} \ No newline at end of file
diff --git a/themes/solarized-dark.theme b/themes/solarized-dark.theme
new file mode 100644
index 00000000..5d1860f3
--- /dev/null
+++ b/themes/solarized-dark.theme
@@ -0,0 +1,104 @@
+{
+ "name": "Solarized Dark 2",
+ "style": "Fusion",
+
+ "//": "Colors are specified as [Red, Green, Blue] values. Colors can be aliased in the",
+ "//": "'colors' section. Colors can also be averaged and mixed together using an RPN like notation.",
+ "//": "'+' indicates 'average' directs the parser to average the next two colors.",
+ "//": "'~' indicates 'mix' directs the parser to mix the next two colors with the specified weight 0->255",
+ "//": "e.g.",
+ "//": " ['+', 'red', 'blue'] - average red and blue",
+ "//": " ['~', 'red', 'blue', 20] - mix a small amount of blue into red",
+ "//": " ['+', '~', 'red', 'blue', 20, 'green'] - mix red and blue with weight 20 then average with green",
+ "//": "The 'palette' section is to specify colors for the QPalette::ColorRole",
+
+ "colors": {
+ "background": [0, 43, 54],
+ "backgroundHighlight": [7, 54, 66],
+ "content": [131, 148, 150],
+ "secondary": [88, 110, 117],
+ "emphasis": [147, 161, 161],
+ "yellow": [181, 137, 0],
+ "orange": [203, 75, 22],
+ "red": [220, 50, 47],
+ "magenta": [211, 54, 130],
+ "violet": [108, 113, 196],
+ "blue": [38, 139, 210],
+ "cyan": [42, 161, 152],
+ "green": [133, 153, 0]
+ },
+
+ "palette": {
+ "Window": "background",
+ "WindowText": "content",
+ "Base": "background",
+ "AlternateBase": "backgroundHighlight",
+ "ToolTipBase": "backgroundHighlight",
+ "ToolTipText": "content",
+ "Text": "content",
+ "Button": "backgroundHighlight",
+ "ButtonText": "content",
+ "BrightText": "emphasis",
+ "Link": "emphasis",
+ "Highlight": "backgroundHighlight",
+ "HighlightedText": "content",
+ "Light": ["+", "background", "content"]
+ },
+
+ "theme-colors": {
+ "addressColor": "secondary",
+ "modifiedColor": "red",
+ "insertedColor": "blue",
+ "notPresentColor": "secondary",
+ "selectionColor": ["+", "backgroundHighlight", "secondary"],
+ "outlineColor": "content",
+ "backgroundHighlightDarkColor": "background",
+ "backgroundHighlightLightColor": "backgroundHighlight",
+ "boldBackgroundHighlightDarkColor": "background",
+ "boldBackgroundHighlightLightColor": ["+", "background", "secondary"],
+ "alphanumericHighlightColor": "yellow",
+ "printableHighlightColor": "orange",
+ "graphBackgroundDarkColor": "background",
+ "graphBackgroundLightColor": "background",
+ "graphNodeDarkColor": "backgroundHighlight",
+ "graphNodeLightColor": "backgroundHighlight",
+ "graphNodeOutlineColor": "content",
+ "trueBranchColor": "green",
+ "falseBranchColor": "red",
+ "unconditionalBranchColor": "content",
+ "altTrueBranchColor": "blue",
+ "altFalseBranchColor": "yellow",
+ "altUnconditionalBranchColor": "content",
+ "registerColor": "green",
+ "numberColor": "cyan",
+ "codeSymbolColor": "blue",
+ "dataSymbolColor": "cyan",
+ "stackVariableColor": "violet",
+ "importColor": "orange",
+ "instructionHighlightColor": "secondary",
+ "tokenHighlightColor": ["+", "secondary", "orange"],
+ "annotationColor": "magenta",
+ "opcodeColor": "secondary",
+ "linearDisassemblyFunctionHeaderColor": "backgroundHighlight",
+ "linearDisassemblyBlockColor": ["+", "background", "backgroundHighlight"],
+ "linearDisassemblyNoteColor": ["~", "background", "green", 24],
+ "linearDisassemblySeparatorColor": [0, 0, 0],
+ "stringColor": "magenta",
+ "typeNameColor": "orange",
+ "fieldNameColor": "cyan",
+ "keywordColor": "green",
+ "uncertainColor": "secondary",
+ "scriptConsoleOutputColor": "content",
+ "scriptConsoleErrorColor": "red",
+ "scriptConsoleEchoColor": "secondary",
+ "blueStandardHighlightColor": "blue",
+ "greenStandardHighlightColor": "green",
+ "cyanStandardHighlightColor": "cyan",
+ "redStandardHighlightColor": "red",
+ "magentaStandardHighlightColor": "magenta",
+ "yellowStandardHighlightColor": "yellow",
+ "orangeStandardHighlightColor": "orange",
+ "whiteStandardHighlightColor": ["+", "background", [255, 255, 255]],
+ "blackStandardHighlightColor": "content"
+ }
+} \ No newline at end of file
diff --git a/themes/solarized-light.theme b/themes/solarized-light.theme
new file mode 100644
index 00000000..2799892b
--- /dev/null
+++ b/themes/solarized-light.theme
@@ -0,0 +1,104 @@
+{
+ "name": "Solarized Light 2",
+ "style": "Fusion",
+
+ "//": "Colors are specified as [Red, Green, Blue] values. Colors can be aliased in the",
+ "//": "'colors' section. Colors can also be averaged and mixed together using an RPN like notation.",
+ "//": "'+' indicates 'average' directs the parser to average the next two colors.",
+ "//": "'~' indicates 'mix' directs the parser to mix the next two colors with the specified weight 0->255",
+ "//": "e.g.",
+ "//": " ['+', 'red', 'blue'] - average red and blue",
+ "//": " ['~', 'red', 'blue', 20] - mix a small amount of blue into red",
+ "//": " ['+', '~', 'red', 'blue', 20, 'green'] - mix red and blue with weight 20 then average with green",
+ "//": "The 'palette' section is to specify colors for the QPalette::ColorRole",
+
+ "colors": {
+ "background": [253, 246, 227],
+ "backgroundHighlight": [238, 232, 213],
+ "content": [101, 123, 131],
+ "secondary": [147, 161, 161],
+ "emphasis": [88, 110, 117],
+ "yellow": [181, 137, 0],
+ "orange": [203, 75, 22],
+ "red": [220, 50, 47],
+ "magenta": [211, 54, 130],
+ "violet": [108, 113, 196],
+ "blue": [38, 139, 210],
+ "cyan": [42, 161, 152],
+ "green": [133, 153, 0]
+ },
+
+ "palette": {
+ "Window": "background",
+ "WindowText": "content",
+ "Base": "background",
+ "AlternateBase": "backgroundHighlight",
+ "ToolTipBase": "backgroundHighlight",
+ "ToolTipText": "content",
+ "Text": "content",
+ "Button": "backgroundHighlight",
+ "ButtonText": "content",
+ "BrightText": "emphasis",
+ "Link": "emphasis",
+ "Highlight": "backgroundHighlight",
+ "HighlightedText": "content",
+ "Light": ["+", "background", "content"]
+ },
+
+ "theme-colors": {
+ "addressColor": "secondary",
+ "modifiedColor": "red",
+ "insertedColor": "blue",
+ "notPresentColor": "secondary",
+ "selectionColor": ["+", "backgroundHighlight", "secondary"],
+ "outlineColor": "content",
+ "backgroundHighlightDarkColor": "background",
+ "backgroundHighlightLightColor": "backgroundHighlight",
+ "boldBackgroundHighlightDarkColor": "background",
+ "boldBackgroundHighlightLightColor": ["+", "background", "secondary"],
+ "alphanumericHighlightColor": "yellow",
+ "printableHighlightColor": "orange",
+ "graphBackgroundDarkColor": "background",
+ "graphBackgroundLightColor": "background",
+ "graphNodeDarkColor": "backgroundHighlight",
+ "graphNodeLightColor": "backgroundHighlight",
+ "graphNodeOutlineColor": "content",
+ "trueBranchColor": "green",
+ "falseBranchColor": "red",
+ "unconditionalBranchColor": "content",
+ "altTrueBranchColor": "blue",
+ "altFalseBranchColor": "yellow",
+ "altUnconditionalBranchColor": "content",
+ "registerColor": "green",
+ "numberColor": "cyan",
+ "codeSymbolColor": "blue",
+ "dataSymbolColor": "cyan",
+ "stackVariableColor": "violet",
+ "importColor": "orange",
+ "instructionHighlightColor": "secondary",
+ "tokenHighlightColor": ["+", "secondary", "orange"],
+ "annotationColor": "magenta",
+ "opcodeColor": "secondary",
+ "linearDisassemblyFunctionHeaderColor": "backgroundHighlight",
+ "linearDisassemblyBlockColor": ["+", "background", "backgroundHighlight"],
+ "linearDisassemblyNoteColor": ["~", "background", "green", 24],
+ "linearDisassemblySeparatorColor": [0, 0, 0],
+ "stringColor": "magenta",
+ "typeNameColor": "orange",
+ "fieldNameColor": "cyan",
+ "keywordColor": "green",
+ "uncertainColor": "secondary",
+ "scriptConsoleOutputColor": "content",
+ "scriptConsoleErrorColor": "red",
+ "scriptConsoleEchoColor": "secondary",
+ "blueStandardHighlightColor": "blue",
+ "greenStandardHighlightColor": "green",
+ "cyanStandardHighlightColor": "cyan",
+ "redStandardHighlightColor": "red",
+ "magentaStandardHighlightColor": "magenta",
+ "yellowStandardHighlightColor": "yellow",
+ "orangeStandardHighlightColor": "orange",
+ "whiteStandardHighlightColor": "content",
+ "blackStandardHighlightColor": ["+", "background", [0, 0, 0]]
+ }
+} \ No newline at end of file