From 409de0f7804a49b6dcc9c8a14307de2be29ecd60 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 10 Sep 2018 20:31:23 -0400 Subject: Add callee saved registers on calling conventions to specify which registers are assumed to be preserved (used in heuristics to avoid incomplete data flow cloberring these registers) --- binaryninjaapi.h | 3 +++ binaryninjacore.h | 2 ++ callingconvention.cpp | 31 +++++++++++++++++++++++++++++++ python/callingconvention.py | 26 ++++++++++++++++++++++++++ 4 files changed, 62 insertions(+) diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 901ea65d..b3f1c87a 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -3597,6 +3597,7 @@ namespace BinaryNinja static void FreeCallback(void* ctxt); static uint32_t* GetCallerSavedRegistersCallback(void* ctxt, size_t* count); + static uint32_t* GetCalleeSavedRegistersCallback(void* ctxt, size_t* count); static uint32_t* GetIntegerArgumentRegistersCallback(void* ctxt, size_t* count); static uint32_t* GetFloatArgumentRegistersCallback(void* ctxt, size_t* count); static void FreeRegisterListCallback(void* ctxt, uint32_t* regs); @@ -3624,6 +3625,7 @@ namespace BinaryNinja std::string GetName() const; virtual std::vector GetCallerSavedRegisters(); + virtual std::vector GetCalleeSavedRegisters(); virtual std::vector GetIntegerArgumentRegisters(); virtual std::vector GetFloatArgumentRegisters(); @@ -3650,6 +3652,7 @@ namespace BinaryNinja CoreCallingConvention(BNCallingConvention* cc); virtual std::vector GetCallerSavedRegisters() override; + virtual std::vector GetCalleeSavedRegisters() override; virtual std::vector GetIntegerArgumentRegisters() override; virtual std::vector GetFloatArgumentRegisters() override; diff --git a/binaryninjacore.h b/binaryninjacore.h index 0916112f..90d0ec2b 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1455,6 +1455,7 @@ extern "C" void (*freeObject)(void* ctxt); uint32_t* (*getCallerSavedRegisters)(void* ctxt, size_t* count); + uint32_t* (*getCalleeSavedRegisters)(void* ctxt, size_t* count); uint32_t* (*getIntegerArgumentRegisters)(void* ctxt, size_t* count); uint32_t* (*getFloatArgumentRegisters)(void* ctxt, size_t* count); void (*freeRegisterList)(void* ctxt, uint32_t* regs); @@ -3228,6 +3229,7 @@ extern "C" BINARYNINJACOREAPI BNArchitecture* BNGetCallingConventionArchitecture(BNCallingConvention* cc); BINARYNINJACOREAPI char* BNGetCallingConventionName(BNCallingConvention* cc); BINARYNINJACOREAPI uint32_t* BNGetCallerSavedRegisters(BNCallingConvention* cc, size_t* count); + BINARYNINJACOREAPI uint32_t* BNGetCalleeSavedRegisters(BNCallingConvention* cc, size_t* count); BINARYNINJACOREAPI uint32_t* BNGetIntegerArgumentRegisters(BNCallingConvention* cc, size_t* count); BINARYNINJACOREAPI uint32_t* BNGetFloatArgumentRegisters(BNCallingConvention* cc, size_t* count); diff --git a/callingconvention.cpp b/callingconvention.cpp index a56b8f11..9e162ed9 100644 --- a/callingconvention.cpp +++ b/callingconvention.cpp @@ -36,6 +36,7 @@ CallingConvention::CallingConvention(Architecture* arch, const string& name) cc.context = this; cc.freeObject = FreeCallback; cc.getCallerSavedRegisters = GetCallerSavedRegistersCallback; + cc.getCalleeSavedRegisters = GetCalleeSavedRegistersCallback; cc.getIntegerArgumentRegisters = GetIntegerArgumentRegistersCallback; cc.getFloatArgumentRegisters = GetFloatArgumentRegistersCallback; cc.freeRegisterList = FreeRegisterListCallback; @@ -77,6 +78,19 @@ uint32_t* CallingConvention::GetCallerSavedRegistersCallback(void* ctxt, size_t* } +uint32_t* CallingConvention::GetCalleeSavedRegistersCallback(void* ctxt, size_t* count) +{ + CallingConvention* cc = (CallingConvention*)ctxt; + vector regs = cc->GetCalleeSavedRegisters(); + *count = regs.size(); + + uint32_t* result = new uint32_t[regs.size()]; + for (size_t i = 0; i < regs.size(); i++) + result[i] = regs[i]; + return result; +} + + uint32_t* CallingConvention::GetIntegerArgumentRegistersCallback(void* ctxt, size_t* count) { CallingConvention* cc = (CallingConvention*)ctxt; @@ -234,6 +248,12 @@ vector CallingConvention::GetCallerSavedRegisters() } +vector CallingConvention::GetCalleeSavedRegisters() +{ + return vector(); +} + + vector CallingConvention::GetIntegerArgumentRegisters() { return vector(); @@ -336,6 +356,17 @@ vector CoreCallingConvention::GetCallerSavedRegisters() } +vector CoreCallingConvention::GetCalleeSavedRegisters() +{ + size_t count; + uint32_t* regs = BNGetCalleeSavedRegisters(m_object, &count); + vector result; + result.insert(result.end(), regs, ®s[count]); + BNFreeRegisterList(regs); + return result; +} + + vector CoreCallingConvention::GetIntegerArgumentRegisters() { size_t count; diff --git a/python/callingconvention.py b/python/callingconvention.py index 6b906184..f4349816 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -34,6 +34,7 @@ from binaryninja import range class CallingConvention(object): name = None caller_saved_regs = [] + callee_saved_regs = [] int_arg_regs = [] float_arg_regs = [] arg_regs_share_index = False @@ -56,6 +57,7 @@ class CallingConvention(object): self._cb = core.BNCustomCallingConvention() self._cb.context = 0 self._cb.getCallerSavedRegisters = self._cb.getCallerSavedRegisters.__class__(self._get_caller_saved_regs) + self._cb.getCalleeSavedRegisters = self._cb.getCalleeSavedRegisters.__class__(self._get_callee_saved_regs) self._cb.getIntegerArgumentRegisters = self._cb.getIntegerArgumentRegisters.__class__(self._get_int_arg_regs) self._cb.getFloatArgumentRegisters = self._cb.getFloatArgumentRegisters.__class__(self._get_float_arg_regs) self._cb.freeRegisterList = self._cb.freeRegisterList.__class__(self._free_register_list) @@ -90,6 +92,15 @@ class CallingConvention(object): core.BNFreeRegisterList(regs, count.value) self.__dict__["caller_saved_regs"] = result + count = ctypes.c_ulonglong() + regs = core.BNGetCalleeSavedRegisters(self.handle, count) + result = [] + arch = self.arch + for i in range(0, count.value): + result.append(arch.get_reg_name(regs[i])) + core.BNFreeRegisterList(regs, count.value) + self.__dict__["callee_saved_regs"] = result + count = ctypes.c_ulonglong() regs = core.BNGetIntegerArgumentRegisters(self.handle, count) result = [] @@ -171,6 +182,21 @@ class CallingConvention(object): count[0] = 0 return None + def _get_callee_saved_regs(self, ctxt, count): + try: + regs = self.__class__.callee_saved_regs + count[0] = len(regs) + reg_buf = (ctypes.c_uint * 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) + return result.value + except: + log.log_error(traceback.format_exc()) + count[0] = 0 + return None + def _get_int_arg_regs(self, ctxt, count): try: regs = self.__class__.int_arg_regs -- cgit v1.3.1 From 2d0c2b83fbf7b08dde00bd541cac374f4a8e8e76 Mon Sep 17 00:00:00 2001 From: Ryan Snyder Date: Mon, 17 Sep 2018 15:29:23 -0400 Subject: api: fix read beyond bounds of basic block --- python/basicblock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/basicblock.py b/python/basicblock.py index 353771d9..c98794cb 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -303,7 +303,7 @@ class BasicBlock(object): idx = start while idx < end: - data = self.view.read(idx, self.arch.max_instr_length) + data = self.view.read(idx, min(self.arch.max_instr_length, end - idx)) inst_info = self.arch.get_instruction_info(data, idx) inst_text = self.arch.get_instruction_text(data, idx) -- cgit v1.3.1 From 1fc4e3eaffa0aa5dfb5f2c70bc350e95c9232bde Mon Sep 17 00:00:00 2001 From: Ryan Snyder Date: Mon, 17 Sep 2018 15:44:08 -0400 Subject: api: switch testcase submodule url to https:// --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 35327f04..f3489ad4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/Vector35/asmx86.git [submodule "suite/binaries"] path = suite/binaries - url = git@github.com:Vector35/BinaryTestCases.git + url = https://github.com/Vector35/BinaryTestCases.git -- cgit v1.3.1 From 536908c5d4ba2f919765b41a050269669c800a75 Mon Sep 17 00:00:00 2001 From: Ryan Snyder Date: Tue, 18 Sep 2018 12:25:44 -0400 Subject: python: make BasicBlocks iterate over disassembly lines, not instrs In certain situations Architecture implementations can return different lengths in get_instruction_info and get_instruction_text (e.g. pseudo-instructions). Since BasicBlock's __iter__ method returns disassembly lines, we should advance by the length returned by that callback instead of get_instruction_info, which could be different. --- python/basicblock.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/python/basicblock.py b/python/basicblock.py index c98794cb..8f16f71a 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -304,13 +304,11 @@ class BasicBlock(object): idx = start while idx < end: data = self.view.read(idx, min(self.arch.max_instr_length, end - idx)) - inst_info = self.arch.get_instruction_info(data, idx) inst_text = self.arch.get_instruction_text(data, idx) - - if inst_info is None: + if inst_text[1] == 0: break yield inst_text - idx += inst_info.length + idx += inst_text[1] def mark_recent_use(self): core.BNMarkBasicBlockAsRecentlyUsed(self.handle) -- cgit v1.3.1