diff options
| -rw-r--r-- | Makefile | 75 | ||||
| -rw-r--r-- | basicblock.cpp | 4 | ||||
| -rw-r--r-- | python/__init__.py | 6 | ||||
| -rw-r--r-- | python/architecture.py | 13 | ||||
| -rw-r--r-- | python/binaryview.py | 9 | ||||
| -rw-r--r-- | python/databuffer.py | 28 | ||||
| -rw-r--r-- | python/demangle.py | 4 | ||||
| -rw-r--r-- | python/generator.cpp | 179 | ||||
| -rw-r--r-- | python/log.py | 1 | ||||
| -rw-r--r-- | python/lowlevelil.py | 1 | ||||
| -rw-r--r-- | python/mediumlevelil.py | 54 | ||||
| -rw-r--r-- | python/metadata.py | 9 | ||||
| -rw-r--r-- | python/setting.py | 6 | ||||
| -rw-r--r-- | python/types.py | 2 |
14 files changed, 275 insertions, 116 deletions
@@ -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) @@ -38,8 +40,73 @@ $(TARGET).a: $(OBJECTS) json.o: ./json/jsoncpp.cpp ./json/json.h ./json/json-forwards.h $(CC) $(CFLAGS) -I. -c -o $@ $< -clean: +install: generate $(TARGET).a + @echo "Installing binaryninja API."; + cp -r python/* $(INSTALLPATH)/python/binaryninja + cp $(TARGETDIR)/$(TARGET).a $(INSTALLPATH) + +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: python/_binaryninjacore.py python/enums.py + @echo "Copying libs to needed locations..." + @cp $(INSTALLPATH)/libbinaryninjacore.so.1 . + @cp $(INSTALLPATH)/libcurl.so.4 . + @cp $(INSTALLPATH)/libcrypto.so.1.0.2 . + @cp $(INSTALLPATH)/libssl.so.1.0.2 . + + @mkdir -p api/python/examples + @cp python/examples/bin_info.py api/python/examples/ + @cp $(INSTALLPATH)/libbinaryninjacore.so.1 api/python/ + @cp $(INSTALLPATH)/libcurl.so.4 api/python/ + @cp $(INSTALLPATH)/libcrypto.so.1.0.2 api/python/ + @cp $(INSTALLPATH)/libssl.so.1.0.2 api/python/ + + @echo "Building 'binaryninja' Packages..." + @mkdir -p suite/binaryninja/ + @cp -r python/* suite/binaryninja/ + @mkdir -p api/python/examples/binaryninja/ + @cp -r python/* api/python/examples/binaryninja/ + + @echo "Copying Architectures Over..." + @cp -r $(INSTALLPATH)/types/ . + @cp -r $(INSTALLPATH)/plugins/ . + @cp -r $(INSTALLPATH)/plugins/ api/python/ + +environment_clean: + @echo "Removing 'binaryninja' Packages..." + @rm -r suite/binaryninja/ + @rm -r api/ + -@rm suite/*.pyc + + @echo "Removing libs..." + @rm lib* + + @echo "Removing Architectures..." + @rm -r types/ + @rm -r 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/basicblock.cpp b/basicblock.cpp index 33f57d40..13b3e7a8 100644 --- a/basicblock.cpp +++ b/basicblock.cpp @@ -245,8 +245,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/python/__init__.py b/python/__init__.py index a3ba0453..2f7cc5a0 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -118,10 +118,8 @@ class PluginManagerLoadPluginCallback(object): def __init__(self): self.cb = ctypes.CFUNCTYPE( ctypes.c_bool, - core.compatstring, - core.compatstring, - # ctypes.c_char_p, - # ctypes.c_char_p, + ctypes.c_char_p, + ctypes.c_char_p, ctypes.c_void_p)(self._load_plugin) def _load_plugin(self, repo_path, plugin_path, ctx): diff --git a/python/architecture.py b/python/architecture.py index b99da184..521c750a 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -1073,7 +1073,6 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, 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)) @@ -2294,7 +2293,6 @@ 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): @@ -2322,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) @@ -2359,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))() @@ -2449,7 +2445,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)) @@ -2471,7 +2466,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)) @@ -2492,7 +2486,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)) @@ -2516,7 +2509,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)) @@ -2538,7 +2530,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)) @@ -2558,7 +2549,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)): @@ -2585,7 +2575,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)): @@ -2613,7 +2602,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)): @@ -2637,7 +2625,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): diff --git a/python/binaryview.py b/python/binaryview.py index ac08ad76..b1bc4822 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -372,12 +372,12 @@ class BinaryViewType(with_metaclass(_BinaryViewTypeMetaclass, object)): @property def name(self): """BinaryView name (read-only)""" - return core.BNGetBinaryViewTypeName(self.handle).decode('utf8') + return core.BNGetBinaryViewTypeName(self.handle) @property def long_name(self): """BinaryView long name (read-only)""" - return core.BNGetBinaryViewTypeLongName(self.handle).decode('utf8') + return core.BNGetBinaryViewTypeLongName(self.handle) def __repr__(self): return "<view type: '%s'>" % self.name @@ -423,6 +423,9 @@ class BinaryViewType(with_metaclass(_BinaryViewTypeMetaclass, 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 @@ -1740,7 +1743,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): """ diff --git a/python/databuffer.py b/python/databuffer.py index bf366750..1b29a7eb 100644 --- a/python/databuffer.py +++ b/python/databuffer.py @@ -26,6 +26,13 @@ from binaryninja import _binaryninjacore as core 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 +51,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 +66,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 +86,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 +114,27 @@ 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 + if type(buf.raw) is str: + return buf.raw + else: + return buf.raw.decode("charmap") - 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 ceb1e48b..90a19761 100644 --- a/python/demangle.py +++ b/python/demangle.py @@ -65,7 +65,7 @@ def demangle_ms(arch, mangled_name): names = [] if core.BNDemangleMS(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize)): for i in range(outSize.value): - names.append(outName[i]) + names.append(outName[i].decode('charmap')) core.BNFreeDemangledName(ctypes.byref(outName), outSize.value) return (types.Type(handle), names) return (None, mangled_name) @@ -79,7 +79,7 @@ def demangle_gnu3(arch, mangled_name): names = [] if core.BNDemangleGNU3(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize)): for i in range(outSize.value): - names.append(outName[i]) + names.append(outName[i].decode('charmap')) core.BNFreeDemangledName(ctypes.byref(outName), outSize.value) if not handle: return (None, names) diff --git a/python/generator.cpp b/python/generator.cpp index 8fc415b0..2da856ff 100644 --- a/python/generator.cpp +++ b/python/generator.cpp @@ -121,10 +121,8 @@ void OutputType(FILE* out, Type* type, bool isReturnType = false, bool isCallbac { if (isReturnType) fprintf(out, "ctypes.POINTER(ctypes.c_byte)"); - else { - //fprintf(out, "compatstring"); + else fprintf(out, "ctypes.c_char_p"); - } break; } else if (type->GetChildType()->GetClass() == FunctionTypeClass) @@ -175,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; @@ -190,7 +188,6 @@ int main(int argc, char* argv[]) fprintf(out, "import platform\n"); fprintf(out, "core = None\n"); fprintf(out, "_base_path = None\n"); - fprintf(out, "ctypes.set_conversion_mode('utf-8', 'strict')\n"); fprintf(out, "if platform.system() == \"Darwin\":\n"); fprintf(out, "\t_base_path = os.path.join(os.path.dirname(__file__), \"..\", \"..\", \"..\", \"MacOS\")\n"); fprintf(out, "\tcore = ctypes.CDLL(os.path.join(_base_path, \"libbinaryninjacore.dylib\"))\n\n"); @@ -202,40 +199,12 @@ int main(int argc, char* argv[]) 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, "class compatstring(ctypes.c_char_p):\n"); - // fprintf(out, "\tdef __init__(self, value=None):\n"); - // fprintf(out, "\t\tsuper(compatstring, self).__init__()\n"); - // fprintf(out, "\t\tif value is not None:\n"); - // fprintf(out, "\t\t\tself.value = value\n"); - // fprintf(out, "\t@classmethod\n"); - // fprintf(out, "\tdef from_param(cls, value):\n"); - // fprintf(out, "\t\tif not isinstance(value, bytes):\n"); - // fprintf(out, "\t\t\treturn super(compatstring, cls).from_param(value.encode('utf8'))\n"); - // fprintf(out, "\t\treturn super(compatstring, cls).from_param(value)\n\n"); - // fprintf(out, "\t@property\n"); - // fprintf(out, "\tdef value(self, value):\n"); - // fprintf(out, "\t\tif not isinstance(value, bytes):\n"); - // fprintf(out, "\t\t\treturn super(compatstring, cls).from_param(value.encode('utf8'))\n"); - // fprintf(out, "\t\treturn super(compatstring, cls).from_param(value)\n\n"); - fprintf(out, "class compatstring(ctypes.c_char_p):\n"); - fprintf(out, " @classmethod\n"); - fprintf(out, " def from_param(cls, obj):\n"); - fprintf(out, " if (obj is not None) and (not isinstance(obj, cls)):\n"); - fprintf(out, " if not isinstance(obj, basestring):\n"); - fprintf(out, " raise TypeError('parameter must be a string type instance')\n"); - fprintf(out, " if not isinstance(obj, unicode):\n"); - fprintf(out, " obj = unicode(obj)\n"); - fprintf(out, " obj = obj.encode('utf-8')\n"); - fprintf(out, " return ctypes.c_char_p.from_param(obj)\n"); - fprintf(out, "\n"); - fprintf(out, " def decode(self):\n"); - fprintf(out, " if self.value is None:\n"); - fprintf(out, " return None\n"); - fprintf(out, " return self.value.decode('utf-8')\n"); - fprintf(out, " @property\n"); - fprintf(out, " def value(self, c_void_p=ctypes.c_void_p):\n"); - fprintf(out, " addr = c_void_p.from_buffer(self).value\n"); - fprintf(out, " return \n"); + + fprintf(out, "def cstr(arg):\n"); + fprintf(out, "\tif isinstance(arg, str):\n"); + fprintf(out, "\t\treturn arg.encode('charmap')\n"); + fprintf(out, "\telse:\n"); + fprintf(out, "\t\treturn arg\n\n"); // Create type objects fprintf(out, "# Type definitions\n"); @@ -248,7 +217,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 self._%s.decode('charmap')\n", arg.name.c_str(), arg.name.c_str()); + fprintf(out, "\t@%s.setter\n\tdef %s(self, value):\n\t\tself._%s = value.encode('charmap')\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) { @@ -313,7 +298,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"); } @@ -347,6 +340,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") { @@ -358,7 +367,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()); @@ -391,8 +400,30 @@ int main(int argc, char* argv[]) { // 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(ctypes.cast(result, ctypes.c_char_p).value.decode('charmap'))\n"); fprintf(out, "\tBNFreeString(result)\n"); fprintf(out, "\treturn string\n"); } @@ -400,11 +431,58 @@ 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"); @@ -413,6 +491,17 @@ int main(int argc, char* argv[]) fprintf(out, "\t\treturn ctypes.cast(value, ctypes.POINTER(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/log.py b/python/log.py index e7cd956d..d4d87019 100644 --- a/python/log.py +++ b/python/log.py @@ -21,6 +21,7 @@ # Binary Ninja components -- additional imports belong in the appropriate class from binaryninja import _binaryninjacore as core +from binaryninja.enums import LogLevel _output_to_log = False diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 333bb5a1..272b2474 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -722,7 +722,6 @@ class LowLevelILFunction(object): LLFC_NO !overflow No overflow ======================= ========== =============================== """ - from binaryninja import mediumlevelil def __init__(self, arch, handle = None, source_func = None): self.arch = arch self.source_function = source_func diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 707915d7..f7e9951a 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -21,10 +21,13 @@ import ctypes import struct -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components 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 six.moves import range @@ -208,9 +211,6 @@ class MediumLevelILInstruction(object): } def __init__(self, func, expr_index, instr_index=None): - from binaryninja import function - from binaryninja import types - from binaryninja import lowlevelil instr = core.BNGetMediumLevelILByIndex(func.handle, expr_index) self.function = func self.expr_index = expr_index @@ -241,14 +241,14 @@ class MediumLevelILInstruction(object): elif operand_type == "intrinsic": value = lowlevelil.ILIntrinsic(func.arch, instr.operands[i]) elif operand_type == "var": - value = binaryninja.function.Variable.from_identifier(self.function.source_function, instr.operands[i]) + value = function.Variable.from_identifier(self.function.source_function, instr.operands[i]) elif operand_type == "var_ssa": - var = binaryninja.function.Variable.from_identifier(self.function.source_function, instr.operands[i]) + var = function.Variable.from_identifier(self.function.source_function, instr.operands[i]) version = instr.operands[i + 1] i += 1 value = SSAVariable(var, version) elif operand_type == "var_ssa_dest_and_src": - var = binaryninja.function.Variable.from_identifier(self.function.source_function, instr.operands[i]) + var = function.Variable.from_identifier(self.function.source_function, instr.operands[i]) dest_version = instr.operands[i + 1] src_version = instr.operands[i + 2] i += 2 @@ -349,14 +349,14 @@ class MediumLevelILInstruction(object): def value(self): """Value of expression if constant or a known value (read-only)""" value = core.BNGetMediumLevelILExprValue(self.function.handle, self.expr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = 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.BNGetMediumLevelILPossibleExprValues(self.function.handle, self.expr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = function.PossibleValueSet(self.function.arch, value) core.BNFreePossibleValueSet(value) return result @@ -454,7 +454,7 @@ class MediumLevelILInstruction(object): return [] result = [] for operand in self.operands: - if (isinstance(operand, binaryninja.function.Variable)) or (isinstance(operand, SSAVariable)): + if (isinstance(operand, function.Variable)) or (isinstance(operand, SSAVariable)): result.append(operand) elif isinstance(operand, MediumLevelILInstruction): result += operand.vars_read @@ -477,7 +477,7 @@ class MediumLevelILInstruction(object): var_data.index = ssa_var.var.index var_data.storage = ssa_var.var.storage value = core.BNGetMediumLevelILPossibleSSAVarValues(self.function.handle, var_data, ssa_var.version, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = function.PossibleValueSet(self.function.arch, value) core.BNFreePossibleValueSet(value) return result @@ -491,88 +491,88 @@ class MediumLevelILInstruction(object): def get_var_for_reg(self, reg): reg = self.function.arch.get_reg_index(reg) result = core.BNGetMediumLevelILVariableForRegisterAtInstruction(self.function.handle, reg, self.instr_index) - return binaryninja.function.Variable(self.function.source_function, result.type, result.index, result.storage) + return function.Variable(self.function.source_function, result.type, result.index, result.storage) def get_var_for_flag(self, flag): flag = self.function.arch.get_flag_index(flag) result = core.BNGetMediumLevelILVariableForFlagAtInstruction(self.function.handle, flag, self.instr_index) - return binaryninja.function.Variable(self.function.source_function, result.type, result.index, result.storage) + return function.Variable(self.function.source_function, result.type, result.index, result.storage) def get_var_for_stack_location(self, offset): result = core.BNGetMediumLevelILVariableForStackLocationAtInstruction(self.function.handle, offset, self.instr_index) - return binaryninja.function.Variable(self.function.source_function, result.type, result.index, result.storage) + return function.Variable(self.function.source_function, result.type, result.index, result.storage) def get_reg_value(self, reg): reg = self.function.arch.get_reg_index(reg) value = core.BNGetMediumLevelILRegisterValueAtInstruction(self.function.handle, reg, self.instr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = 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.BNGetMediumLevelILRegisterValueAfterInstruction(self.function.handle, reg, self.instr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = 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.BNGetMediumLevelILPossibleRegisterValuesAtInstruction(self.function.handle, reg, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = 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.BNGetMediumLevelILPossibleRegisterValuesAfterInstruction(self.function.handle, reg, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = 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.BNGetMediumLevelILFlagValueAtInstruction(self.function.handle, flag, self.instr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = 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.BNGetMediumLevelILFlagValueAfterInstruction(self.function.handle, flag, self.instr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = 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.BNGetMediumLevelILPossibleFlagValuesAtInstruction(self.function.handle, flag, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = 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.BNGetMediumLevelILPossibleFlagValuesAfterInstruction(self.function.handle, flag, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = function.PossibleValueSet(self.function.arch, value) core.BNFreePossibleValueSet(value) return result def get_stack_contents(self, offset, size): value = core.BNGetMediumLevelILStackContentsAtInstruction(self.function.handle, offset, size, self.instr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = function.RegisterValue(self.function.arch, value) return result def get_stack_contents_after(self, offset, size): value = core.BNGetMediumLevelILStackContentsAfterInstruction(self.function.handle, offset, size, self.instr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = function.RegisterValue(self.function.arch, value) return result def get_possible_stack_contents(self, offset, size): value = core.BNGetMediumLevelILPossibleStackContentsAtInstruction(self.function.handle, offset, size, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = function.PossibleValueSet(self.function.arch, value) core.BNFreePossibleValueSet(value) return result def get_possible_stack_contents_after(self, offset, size): value = core.BNGetMediumLevelILPossibleStackContentsAfterInstruction(self.function.handle, offset, size, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = function.PossibleValueSet(self.function.arch, value) core.BNFreePossibleValueSet(value) return result @@ -905,7 +905,7 @@ class MediumLevelILFunction(object): var_data.index = ssa_var.var.index var_data.storage = ssa_var.var.storage value = core.BNGetMediumLevelILSSAVarValue(self.handle, var_data, ssa_var.version) - result = binaryninja.function.RegisterValue(self.arch, value) + result = function.RegisterValue(self.arch, value) return result def get_low_level_il_instruction_index(self, instr): diff --git a/python/metadata.py b/python/metadata.py index 64080060..fed8bdaa 100644 --- a/python/metadata.py +++ b/python/metadata.py @@ -43,7 +43,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) @@ -147,7 +147,10 @@ class Metadata(object): result = core.BNMetadataGetValueStore(self.handle) try: for i in range(result.contents.size): - yield result.contents.keys[i] + if type(result.contents.keys[i]) is bytes: + yield str(result.contents.keys[i].decode('charmap')) + else: + yield result.contents.keys[i] finally: core.BNFreeMetadataValueStore(result) else: @@ -172,7 +175,7 @@ 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 diff --git a/python/setting.py b/python/setting.py index 16d943e7..fea06140 100644 --- a/python/setting.py +++ b/python/setting.py @@ -58,11 +58,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 range(length.value): - out_list.append(result[i]) + out_list.append(result[i].decode('charmap')) core.BNFreeStringList(result, length) return out_list @@ -113,7 +113,7 @@ class Setting(object): length.value = len(value) default_list = (ctypes.c_char_p * len(value))() for i in range(len(value)): - default_list[i] = str(value[i]) + default_list[i] = value[i].encode('utf-8') return core.BNSettingSetStringList(self.plugin_name, name, default_list, length, auto_flush) diff --git a/python/types.py b/python/types.py index 857f67e6..2ad8d2c2 100644 --- a/python/types.py +++ b/python/types.py @@ -39,7 +39,7 @@ class QualifiedName(object): elif isinstance(name, QualifiedName): self.name = name.name else: - self.name = name + self.name = [i.decode('utf-8') for i in name] def __str__(self): return "::".join(self.name) |
