From a0398e59c06e0c806282dbe944c369403799bd5e Mon Sep 17 00:00:00 2001 From: Jason Hiser <jdhiser@gmail.com> Date: Fri, 17 May 2019 12:58:38 +0000 Subject: [PATCH] support for unpinning data-in-text in case zipr finds a pin over said data --- irdb-libs/ir_builders/fill_in_cfg.cpp | 68 +++++++++++++++++---------- irdb-libs/ir_builders/fix_calls.cpp | 4 ++ zipr_unpin_plugin | 2 +- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/irdb-libs/ir_builders/fill_in_cfg.cpp b/irdb-libs/ir_builders/fill_in_cfg.cpp index ad08cfa0f..6d5e6ed4f 100644 --- a/irdb-libs/ir_builders/fill_in_cfg.cpp +++ b/irdb-libs/ir_builders/fill_in_cfg.cpp @@ -495,11 +495,12 @@ void PopulateCFG::fill_in_scoops(FileIR_t *firp) void PopulateCFG::detect_scoops_in_code(FileIR_t *firp) { // data for this function - auto already_scoopified=set<VirtualOffset_t>(); + auto already_scoopified=map<VirtualOffset_t,DataScoop_t*>(); const auto is_arm64 = firp->getArchitecture()->getMachineType() == admtAarch64; const auto is_arm32 = firp->getArchitecture()->getMachineType() == admtArm32; const auto is_arm_variant = is_arm32 || is_arm64; + const auto do_unpin = is_arm32; // only valid for arm64 if(!is_arm_variant) return; @@ -523,9 +524,13 @@ void PopulateCFG::detect_scoops_in_code(FileIR_t *firp) const auto mem_op = mnemonic[3]=='d' ? d->getOperand(2) : d->getOperand(1); if( !mem_op->isPcrel()) continue; + // if there is an indexing operation, skip this instruction. + if( mem_op->hasIndexRegister()) continue; + // sanity check that it's a memory operation, and extract fields assert(mem_op->isMemory()); const auto referenced_address = mem_op->getMemoryDisplacement() + (is_arm32 ? insn->getAddress()->getVirtualOffset() + 8 : 0); + const auto name = "data_in_text_"+to_hex_string(referenced_address); const auto op0_str = op0->getString(); // if op0 is the PC, the instruction is some switch dispatch that we have to detect in more depth. skip here. see check_arm32_switch... @@ -551,31 +556,42 @@ void PopulateCFG::detect_scoops_in_code(FileIR_t *firp) // check if we've seen this address already const auto already_seen_it = already_scoopified.find(referenced_address); - if(already_seen_it != end(already_scoopified)) continue; - - // not seen, add it - already_scoopified.insert(referenced_address); - - - // find section and sanity check. - const auto sec=exeiop->sections.findByAddress(referenced_address); - if(sec==nullptr) continue; - - // only trying to do this for executable chunks, other code deals with - // scoops not in the .text section. - if(!sec->isExecutable()) continue; - - const auto sec_data=sec->get_data(); - const auto sec_start=sec->get_address(); - const auto the_contents=string(&sec_data[referenced_address-sec_start],referenced_size); - const auto fileid=firp->getFile()->getBaseID(); - auto start_addr=firp->addNewAddress(fileid,referenced_address); - auto end_addr =firp->addNewAddress(fileid,referenced_address+referenced_size-1); - const auto name="data_in_text_"+to_string(referenced_address); - const auto permissions=0x4; /* R-- */ - const auto is_relro=false; - auto newscoop=firp->addNewDataScoop(name, start_addr, end_addr, NULL, permissions, is_relro, the_contents); - (void)newscoop; + if(already_seen_it == end(already_scoopified)) + { + + // find section and sanity check. + const auto sec=exeiop->sections.findByAddress(referenced_address); + if(sec==nullptr) continue; + + // only trying to do this for executable chunks, other code deals with + // scoops not in the .text section. + if(!sec->isExecutable()) continue; + + const auto new_scoop_addr = do_unpin ? VirtualOffset_t(0u) : referenced_address; + const auto sec_data = sec->get_data(); + const auto sec_start = sec->get_address(); + const auto the_contents = string(&sec_data[referenced_address-sec_start],referenced_size); + const auto fileid = firp->getFile()->getBaseID(); + auto new_start_addr = firp->addNewAddress(fileid,new_scoop_addr); + auto new_end_addr = firp->addNewAddress(fileid,new_scoop_addr+referenced_size-1); + const auto permissions = 0x4; /* R-- */ + const auto is_relro = false; + + // create the new scoop + already_scoopified[referenced_address] = firp->addNewDataScoop(name, new_start_addr, + new_end_addr, NULL, permissions, is_relro, the_contents); + } + + auto newscoop = already_scoopified[referenced_address] ; + assert(newscoop); + const auto start_addr = newscoop -> getStart(); + const auto end_addr = newscoop -> getEnd(); + + if(do_unpin) + { + const auto new_addend = -uint32_t(insn->getAddress()->getVirtualOffset()); + (void)firp->addNewRelocation(insn,0,"pcrel",newscoop, new_addend); + } cout << "Allocated data in text segment " << name << "=(" << start_addr->getVirtualOffset() << "-" << end_addr->getVirtualOffset() << ")" diff --git a/irdb-libs/ir_builders/fix_calls.cpp b/irdb-libs/ir_builders/fix_calls.cpp index caca6731f..519810db6 100644 --- a/irdb-libs/ir_builders/fix_calls.cpp +++ b/irdb-libs/ir_builders/fix_calls.cpp @@ -782,6 +782,10 @@ class FixCalls_t : public TransformStep_t if(virt_offset == 0 || virt_offset == (uintptr_t)-1) return; + const auto cur_relocs = insn->getRelocations(); + const auto pcrel_reloc_it = find_if(ALLOF(cur_relocs), [](const Relocation_t* r) { return r->getType()=="pcrel"; }); + if(pcrel_reloc_it != end(cur_relocs)) return; // already exists. + const auto disasm = DecodedInstruction_t::factory(insn); const auto &operands = disasm->getOperands(); for(const auto &op : operands) diff --git a/zipr_unpin_plugin b/zipr_unpin_plugin index 271ae947c..3e6cfdb57 160000 --- a/zipr_unpin_plugin +++ b/zipr_unpin_plugin @@ -1 +1 @@ -Subproject commit 271ae947c0df9fa94a2ee4d2648aeed5fcbfbd05 +Subproject commit 3e6cfdb5739d8f7bc901771408c9f988b9365ba2 -- GitLab