diff --git a/include/arch/arch_arm32.hpp b/include/arch/arch_arm32.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3b6c3f45e52369d52b53ed6e969e2a88c7ca3101 --- /dev/null +++ b/include/arch/arch_arm32.hpp @@ -0,0 +1,38 @@ +#ifndef ARCHARM32_HPP +#define ARCHARM32_HPP + +class ZiprArchitectureHelperARM32_t : public ZiprArchitectureHelperBase_t +{ + public: + ZiprArchitectureHelperARM32_t(Zipr_SDK::Zipr_t* p_zipr_obj) : ZiprArchitectureHelperBase_t(p_zipr_obj) + { + } + + virtual IRDB_SDK::Instruction_t* createNewJumpInstruction(IRDB_SDK::FileIR_t *p_firp, IRDB_SDK::Instruction_t* p_existing) override + { + // An arm32 brand in binary is: cond 1 0 1 L signed_immed_24 + // + // where cond is the 4-bit condition field. for an uncond branch, we want cond=0b1110 + // and L is whether the link register is set. + // + // so, bytes = 0b11101010 0b00000000 0b00000000 0b00000000 + // + const auto bits =string("\x00\x00\x00\x0ea",4); + auto ret=IRDB_SDK::addNewDataBits(p_firp, p_existing, bits); + const auto d=IRDB_SDK::DecodedInstruction_t::factory(ret); + assert(d->valid()); + return ret; + } + + virtual IRDB_SDK::Instruction_t* createNewHaltInstruction(IRDB_SDK::FileIR_t *p_firp, IRDB_SDK::Instruction_t* p_existing) override + { + // for arm32, we are using a mov pc, #0 as a halt insn. + // 0xe3a0f000 + const auto bits =string("\x00\xf0\xa0\xe3",4); + auto ret=IRDB_SDK::addNewDataBits(p_firp, p_existing, bits); + const auto d=IRDB_SDK::DecodedInstruction_t::factory(ret); + assert(d->valid()); + return ret; + } +}; +#endif diff --git a/include/patcher/patcher_arm32.hpp b/include/patcher/patcher_arm32.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2e455c788bd97cc5b332817f1d9ab48ee562f724 --- /dev/null +++ b/include/patcher/patcher_arm32.hpp @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (c) 2014 Zephyr Software LLC. All rights reserved. + * + * This software is furnished under a license and/or other restrictive + * terms and may be used and copied only in accordance with such terms + * and the inclusion of the above copyright notice. This software or + * any other copies thereof may not be provided or otherwise made + * available to any other person without the express written consent + * of an authorized representative of Zephyr Software LCC. Title to, + * ownership of, and all rights in the software is retained by + * Zephyr Software LCC. + * + * Zephyr Software LLC. Proprietary Information + * + * Unless otherwise specified, the information contained in this + * directory, following this legend, and/or referenced herein is + * Zephyr Software LLC. (Zephyr) Proprietary Information. + * + * CONTACT + * + * For technical assistance, contact Zephyr Software LCC. at: + * + * + * Zephyr Software, LLC + * 2040 Tremont Rd + * Charlottesville, VA 22911 + * + * E-mail: jwd@zephyr-software.com + **************************************************************************/ + + + +#ifndef PATCHER_ARM32 +#define PATCHER_ARM32 + +class ZiprPatcherARM32_t : public ZiprPatcherBase_t +{ + // data + zipr::ZiprImpl_t* m_parent; + IRDB_SDK::FileIR_t* m_firp; + Zipr_SDK::MemorySpace_t &memory_space; + + std::map<RangeAddress_t, RangeAddress_t> redirect_map; + + + public: + + ZiprPatcherARM32_t(Zipr_SDK::Zipr_t* p_parent); + void ApplyNopToPatch(RangeAddress_t addr) override; + void ApplyPatch(RangeAddress_t from_addr, RangeAddress_t to_addr) override; + void PatchJump(RangeAddress_t at_addr, RangeAddress_t to_addr) override; + void PatchCall(RangeAddress_t at_addr, RangeAddress_t to_addr) override; + void CallToNop(RangeAddress_t at_addr) override; + + +}; +#endif diff --git a/include/patcher/patcher_arm64.hpp b/include/patcher/patcher_arm64.hpp index 00127da04256f8886768a8eec9a2c185d7f7ebcf..96f38f92d02acb921b8eabd9d4f2dbc3a611f3e5 100644 --- a/include/patcher/patcher_arm64.hpp +++ b/include/patcher/patcher_arm64.hpp @@ -30,8 +30,8 @@ -#ifndef PATCHER_ARM -#define PATCHER_ARM +#ifndef PATCHER_ARM64 +#define PATCHER_ARM64 class ZiprPatcherARM64_t : public ZiprPatcherBase_t { diff --git a/include/patcher/patcher_base.hpp b/include/patcher/patcher_base.hpp index 25e11af6d47efc756409331b231dfc8898d939f1..1609b3deae6a08d73682e32b16aa85de443e7b31 100644 --- a/include/patcher/patcher_base.hpp +++ b/include/patcher/patcher_base.hpp @@ -34,7 +34,10 @@ class ZiprPatcherBase_t { + protected: + ZiprPatcherBase_t(){} public: + virtual ~ZiprPatcherBase_t() { } static unique_ptr<ZiprPatcherBase_t> factory(Zipr_SDK::Zipr_t* p_parent); virtual void ApplyNopToPatch(RangeAddress_t addr)=0; virtual void ApplyPatch(RangeAddress_t from_addr, RangeAddress_t to_addr)=0; diff --git a/include/pinner/pinner_arm32.hpp b/include/pinner/pinner_arm32.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0a598d5c96c7d3d175fa18560718c54cbe9ac0e1 --- /dev/null +++ b/include/pinner/pinner_arm32.hpp @@ -0,0 +1,22 @@ +#ifndef ZIPR_PINNER_ARM32 +#define ZIPR_PINNER_ARM32 + +class ZiprPinnerARM32_t : public ZiprPinnerBase_t +{ + public: + ZiprPinnerARM32_t(Zipr_SDK::Zipr_t* p_parent); + virtual void doPinning() override; + + private: + zipr::ZiprImpl_t* m_parent; + IRDB_SDK::FileIR_t* m_firp; + Zipr_SDK::MemorySpace_t &memory_space; + Zipr_SDK::DollopManager_t &m_dollop_mgr; + Zipr_SDK::PlacementQueue_t &placement_queue; + + + +}; + + +#endif diff --git a/include/pinner/pinner_base.hpp b/include/pinner/pinner_base.hpp index e894ae4ee33be4750bfd2df856ab97683e6efa03..81ca40b1b0ef5fb3646b9fdace5fc8dce6eb781e 100644 --- a/include/pinner/pinner_base.hpp +++ b/include/pinner/pinner_base.hpp @@ -3,9 +3,12 @@ class ZiprPinnerBase_t { + protected: + ZiprPinnerBase_t() { } public: virtual void doPinning()=0; static unique_ptr<ZiprPinnerBase_t> factory(Zipr_SDK::Zipr_t* parent); + virtual ~ZiprPinnerBase_t() { } }; diff --git a/include/sizer/sizer_arm32.hpp b/include/sizer/sizer_arm32.hpp new file mode 100644 index 0000000000000000000000000000000000000000..82950bf2e6b5fd7abe6f1c5e850234b312edd1ec --- /dev/null +++ b/include/sizer/sizer_arm32.hpp @@ -0,0 +1,17 @@ +#ifndef SIZERARM32_HPP +#define SIZERARM32_HPP + +class ZiprSizerARM32_t : public ZiprSizerBase_t +{ + private: + RangeAddress_t TBZPlopDollopEntryWithTarget (Zipr_SDK::DollopEntry_t *entry, RangeAddress_t override_place, RangeAddress_t override_target) const; + RangeAddress_t DefaultPlopDollopEntryWithTarget(Zipr_SDK::DollopEntry_t *entry, RangeAddress_t override_place, RangeAddress_t override_target) const; + + public: + ZiprSizerARM32_t(Zipr_SDK::Zipr_t* p_zipr_obj); + size_t DetermineInsnSize(IRDB_SDK::Instruction_t*, bool account_for_jump = true) const override; + virtual RangeAddress_t PlopDollopEntryWithTarget(Zipr_SDK::DollopEntry_t *entry, RangeAddress_t override_place, RangeAddress_t override_target) const override; + + +}; +#endif diff --git a/include/sizer/sizer_base.hpp b/include/sizer/sizer_base.hpp index 2dbbe71de064edfb4dec52f3e59dfbf3bcc5b3b0..93069e25a762218a51276496fa3e24e7328e1d5d 100644 --- a/include/sizer/sizer_base.hpp +++ b/include/sizer/sizer_base.hpp @@ -16,6 +16,7 @@ class ZiprSizerBase_t ZiprMemorySpace_t &memory_space; ZiprImpl_t &m_zipr_obj; public: + virtual ~ZiprSizerBase_t() {} // methods /** Calculate entire size of a dollop and it's fallthroughs. * diff --git a/src/SConscript b/src/SConscript index 62933245754cc635f57b5735a8cf0942f91e02f1..73bef2a6f57ae86b57f00a1d6e2d3a73a38dad69 100644 --- a/src/SConscript +++ b/src/SConscript @@ -27,14 +27,17 @@ files= ''' ehwrite.cpp arch_base.cpp pinner_arm64.cpp + pinner_arm32.cpp pinner_base.cpp pinner_x86.cpp patcher_arm64.cpp + patcher_arm32.cpp patcher_base.cpp patcher_x86.cpp sizer_base.cpp sizer_x86.cpp sizer_arm64.cpp + sizer_arm32.cpp range.cpp ''' diff --git a/src/arch_base.cpp b/src/arch_base.cpp index 4bc17ecb32e72c038ceefe85c791092a096ac2fd..5c724289efde676fc3dc01934d2963fc691b7ba3 100644 --- a/src/arch_base.cpp +++ b/src/arch_base.cpp @@ -6,6 +6,7 @@ namespace zipr { #include <arch/arch_x86.hpp> #include <arch/arch_arm64.hpp> +#include <arch/arch_arm32.hpp> } #include <memory> @@ -27,6 +28,7 @@ unique_ptr<ZiprArchitectureHelperBase_t> ZiprArchitectureHelperBase_t::factory(Z auto ret= l_firp->getArchitecture()->getMachineType() == admtX86_64 ? (ZiprArchitectureHelperBase_t*)new ZiprArchitectureHelperX86_t (p_zipr_obj) : l_firp->getArchitecture()->getMachineType() == admtI386 ? (ZiprArchitectureHelperBase_t*)new ZiprArchitectureHelperX86_t (p_zipr_obj) : l_firp->getArchitecture()->getMachineType() == admtAarch64 ? (ZiprArchitectureHelperBase_t*)new ZiprArchitectureHelperARM64_t(p_zipr_obj) : + l_firp->getArchitecture()->getMachineType() == admtArm32 ? (ZiprArchitectureHelperBase_t*)new ZiprArchitectureHelperARM32_t(p_zipr_obj) : throw domain_error("Cannot init architecture"); return unique_ptr<ZiprArchitectureHelperBase_t>(ret); diff --git a/src/patcher_arm32.cpp b/src/patcher_arm32.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf27ee2f108664988cb65458411733eafdaf013d --- /dev/null +++ b/src/patcher_arm32.cpp @@ -0,0 +1,111 @@ +/*************************************************************************** + * Copyright (c) 2014 Zephyr Software LLC. All rights reserved. + * + * This software is furnished under a license and/or other restrictive + * terms and may be used and copied only in accordance with such terms + * and the inclusion of the above copyright notice. This software or + * any other copies thereof may not be provided or otherwise made + * available to any other person without the express written consent + * of an authorized representative of Zephyr Software LCC. Title to, + * ownership of, and all rights in the software is retained by + * Zephyr Software LCC. + * + * Zephyr Software LLC. Proprietary Information + * + * Unless otherwise specified, the information contained in this + * directory, following this legend, and/or referenced herein is + * Zephyr Software LLC. (Zephyr) Proprietary Information. + * + * CONTACT + * + * For technical assistance, contact Zephyr Software LCC. at: + * + * + * Zephyr Software, LLC + * 2040 Tremont Rd + * Charlottesville, VA 22911 + * + * E-mail: jwd@zephyr-software.com + **************************************************************************/ + +#include <zipr_all.h> +namespace zipr +{ +#include "patcher/patcher_arm32.hpp" +} +#include <irdb-core> +#include <iostream> +#include <stdlib.h> +#include <string.h> +#include <map> +#include <assert.h> +#include <sys/mman.h> +#include <ctype.h> +#include <iostream> // std::cout +#include <string> // std::string, std::to_string +#include <fstream> + +#define ALLOF(a) begin(a),end(a) + +using namespace IRDB_SDK; +using namespace std; +using namespace zipr; + +ZiprPatcherARM32_t::ZiprPatcherARM32_t(Zipr_SDK::Zipr_t* p_parent) : + m_parent(dynamic_cast<zipr::ZiprImpl_t*>(p_parent)), // upcast to ZiprImpl + m_firp(p_parent->getFileIR()), + memory_space(*p_parent->getMemorySpace()) + +{ +} + +void ZiprPatcherARM32_t::ApplyNopToPatch(RangeAddress_t addr) +{ assert(0); } + +void ZiprPatcherARM32_t::ApplyPatch(RangeAddress_t from_addr, RangeAddress_t to_addr) +{ + + const auto first_byte = (uint8_t)memory_space[from_addr+3]; + const auto new_offset = (int32_t)((to_addr) - (from_addr+8)) >> 2; + + // A Branch in binary is: op= cond4 1010 imm24=00 00000000 00000000 00000000 + // it includes a 24-bit immediate, which is +/- 32mb, which should be a good enough "jump anywhere" + // for now. + const auto mask3 = (0b111); + const auto is_branch = ((first_byte >> 1) & mask3) == (0b101); // any type of branch. + + if(is_branch) + { + // cout<<"Applying uncond branch patch from "<<hex<<from_addr<<" to "<<to_addr<<endl; + const auto non_imm_bits = 32U-24U; // 32 bits - imm24 + // assert there's no overflow. + assert((int64_t)(new_offset << non_imm_bits) == ((int64_t)new_offset) << non_imm_bits); + // or in opcode for first byte. set remaining bytes. + const auto mask24 = ((1<<24)-1); + const auto trimmed_offset = new_offset & mask24; + memory_space[from_addr+0] = (trimmed_offset>> 0)&0xff; + memory_space[from_addr+1] = (trimmed_offset>> 8)&0xff; + memory_space[from_addr+2] = (trimmed_offset>>16)&0xff; + // no need to write 4th byte. + } + else + assert(0); + +} + +void ZiprPatcherARM32_t::PatchJump(RangeAddress_t at_addr, RangeAddress_t to_addr) +{ + return this->ApplyPatch(at_addr,to_addr); +} +void ZiprPatcherARM32_t::PatchCall(RangeAddress_t at_addr, RangeAddress_t to_addr) +{ + assert(0); +} + + +void ZiprPatcherARM32_t::CallToNop(RangeAddress_t at_addr) +{ + assert(0); +} + + diff --git a/src/patcher_base.cpp b/src/patcher_base.cpp index 769a01f9e7a98f2f73ec538d0c37110a7849e9e2..9a0f32f5eaafe3d2e42ace89ed3738e937ff3d79 100644 --- a/src/patcher_base.cpp +++ b/src/patcher_base.cpp @@ -32,6 +32,7 @@ namespace zipr { +#include "patcher/patcher_arm32.hpp" #include "patcher/patcher_arm64.hpp" #include "patcher/patcher_x86.hpp" } @@ -60,6 +61,7 @@ unique_ptr<ZiprPatcherBase_t> ZiprPatcherBase_t::factory(Zipr_SDK::Zipr_t* p_par auto ret= l_firp->getArchitecture()->getMachineType() == admtX86_64 ? (ZiprPatcherBase_t*)new ZiprPatcherX86_t (p_parent) : l_firp->getArchitecture()->getMachineType() == admtI386 ? (ZiprPatcherBase_t*)new ZiprPatcherX86_t (p_parent) : l_firp->getArchitecture()->getMachineType() == admtAarch64 ? (ZiprPatcherBase_t*)new ZiprPatcherARM64_t(p_parent) : + l_firp->getArchitecture()->getMachineType() == admtArm32 ? (ZiprPatcherBase_t*)new ZiprPatcherARM32_t(p_parent) : throw domain_error("Cannot init architecture"); return unique_ptr<ZiprPatcherBase_t>(ret); diff --git a/src/pinner_arm32.cpp b/src/pinner_arm32.cpp new file mode 100644 index 0000000000000000000000000000000000000000..806b0b5842dda92d7eeceba61befebce6f46f452 --- /dev/null +++ b/src/pinner_arm32.cpp @@ -0,0 +1,58 @@ +#include <zipr_all.h> + +namespace zipr +{ +#include <pinner/pinner_arm32.hpp> +} +#include <memory> + +using namespace std; +using namespace IRDB_SDK; +using namespace zipr; + +ZiprPinnerARM32_t::ZiprPinnerARM32_t(Zipr_SDK::Zipr_t* p_parent) : + m_parent(dynamic_cast<zipr::ZiprImpl_t*>(p_parent)), // upcast to ZiprImpl + m_firp(p_parent->getFileIR()), + memory_space(*m_parent->getMemorySpace()), + m_dollop_mgr(*p_parent->getDollopManager()), + placement_queue(*p_parent->getPlacementQueue()) + +{ +} + +void ZiprPinnerARM32_t::doPinning() +{ + + + // deal with unpinned IBTs by putting them in the placement queue. + for(auto &insn : m_firp->getInstructions()) + { + if(insn->getIndirectBranchTargetAddress()==nullptr) + continue; + + if(insn->getIndirectBranchTargetAddress()->getVirtualOffset()==0) + { + // Unpinned IBT. Create dollop and add it to placement + // queue straight away--there are no pinning considerations. + auto newDoll=m_dollop_mgr.addNewDollops(insn); + placement_queue.insert({newDoll, 0}); + continue; + } + + auto ibta_addr=(RangeAddress_t)insn-> getIndirectBranchTargetAddress()-> getVirtualOffset(); + + // put unconditional branch with 24-bit offset in memory + // 1110 1010 0000 0000 0000 0000 0000 0000 + uint8_t bytes[]={'\x00','\x00','\x00',uint8_t('\xea')}; + for(auto i=0U;i<sizeof(bytes);i++) + { + assert(memory_space.find(ibta_addr+i) == memory_space.end() ); + memory_space[ibta_addr+i]=bytes[i]; + memory_space.splitFreeRange(ibta_addr+i); + } + // insert a patch to patch the branch later. + const auto patch=Patch_t(ibta_addr, UnresolvedType_t::UncondJump_rel26); + const auto uu=UnresolvedUnpinned_t(insn); + m_parent->AddPatch(uu,patch); + } +} diff --git a/src/pinner_base.cpp b/src/pinner_base.cpp index 534ffebd51c333d05b118f4f2f0a6d85663b15e4..e14dd0215035ca146d9239b4e80b13994977064f 100644 --- a/src/pinner_base.cpp +++ b/src/pinner_base.cpp @@ -3,6 +3,7 @@ namespace zipr { #include <pinner/pinner_x86.hpp> +#include <pinner/pinner_arm32.hpp> #include <pinner/pinner_arm64.hpp> } #include <memory> @@ -16,6 +17,7 @@ unique_ptr<ZiprPinnerBase_t> ZiprPinnerBase_t::factory(Zipr_SDK::Zipr_t *p_paren auto ret= p_parent->getFileIR()->getArchitecture()->getMachineType() == admtX86_64 ? (ZiprPinnerBase_t*)new ZiprPinnerX86_t (p_parent) : p_parent->getFileIR()->getArchitecture()->getMachineType() == admtI386 ? (ZiprPinnerBase_t*)new ZiprPinnerX86_t (p_parent) : p_parent->getFileIR()->getArchitecture()->getMachineType() == admtAarch64 ? (ZiprPinnerBase_t*)new ZiprPinnerARM64_t(p_parent) : + p_parent->getFileIR()->getArchitecture()->getMachineType() == admtArm32 ? (ZiprPinnerBase_t*)new ZiprPinnerARM32_t(p_parent) : throw domain_error("Cannot init architecture"); return unique_ptr<ZiprPinnerBase_t>(ret); diff --git a/src/sizer_arm32.cpp b/src/sizer_arm32.cpp new file mode 100644 index 0000000000000000000000000000000000000000..40f57f9300601209b367331f0592714edefa9634 --- /dev/null +++ b/src/sizer_arm32.cpp @@ -0,0 +1,40 @@ +#include <zipr_all.h> + +namespace zipr +{ +#include <sizer/sizer_arm32.hpp> +} + + +using namespace zipr ; +using namespace IRDB_SDK; + + +ZiprSizerARM32_t::ZiprSizerARM32_t(Zipr_SDK::Zipr_t* p_zipr_obj) : ZiprSizerBase_t(p_zipr_obj,4,4,4,4,4) +{ +} + +size_t ZiprSizerARM32_t::DetermineInsnSize(Instruction_t* insn, bool account_for_jump) const +{ + // need 4 bytes for insn, plus 4 bytes for a jump + const auto size = 4u; + const auto jmp_size = account_for_jump ? 4 : 0; + return size + jmp_size; +} + +RangeAddress_t ZiprSizerARM32_t::PlopDollopEntryWithTarget( + Zipr_SDK::DollopEntry_t *entry, + RangeAddress_t override_place, + RangeAddress_t override_target) const +{ + const auto addr = (override_place == 0) ? entry->getPlace() : override_place; + const auto target_addr = (override_target == 0) ? entry->getTargetDollop()->getPlace() : override_target; + const auto insn = entry->getInstruction(); + + // plop instruction an d make it target the right address. + memory_space.PlopBytes(addr, insn->getDataBits().c_str(), 4); + m_zipr_obj.GetPatcher()->ApplyPatch(addr, target_addr); + + return addr+4; +} + diff --git a/src/sizer_base.cpp b/src/sizer_base.cpp index 1d5847c4c0c7b509d53430c0cf623900995f0e3b..792eba582db34d0368dde30968f7423a3e379581 100644 --- a/src/sizer_base.cpp +++ b/src/sizer_base.cpp @@ -6,6 +6,7 @@ namespace zipr { #include <sizer/sizer_x86.hpp> #include <sizer/sizer_arm64.hpp> +#include <sizer/sizer_arm32.hpp> } #include <memory> @@ -20,6 +21,7 @@ unique_ptr<ZiprSizerBase_t> ZiprSizerBase_t::factory(Zipr_SDK::Zipr_t* p_zipr_ob auto ret= l_firp->getArchitecture()->getMachineType() == admtX86_64 ? (ZiprSizerBase_t*)new ZiprSizerX86_t (p_zipr_obj) : l_firp->getArchitecture()->getMachineType() == admtI386 ? (ZiprSizerBase_t*)new ZiprSizerX86_t (p_zipr_obj) : l_firp->getArchitecture()->getMachineType() == admtAarch64 ? (ZiprSizerBase_t*)new ZiprSizerARM64_t(p_zipr_obj) : + l_firp->getArchitecture()->getMachineType() == admtArm32 ? (ZiprSizerBase_t*)new ZiprSizerARM32_t(p_zipr_obj) : throw domain_error("Cannot init architecture"); return unique_ptr<ZiprSizerBase_t>(ret);