diff --git a/irdb-libs/ir_builders/fill_in_indtargs.cpp b/irdb-libs/ir_builders/fill_in_indtargs.cpp index cc39c346d44b7c9384affcb2f5dbaada223ec376..af796d0245deef88c474e277eca9d3f3b9f11e78 100644 --- a/irdb-libs/ir_builders/fill_in_indtargs.cpp +++ b/irdb-libs/ir_builders/fill_in_indtargs.cpp @@ -37,6 +37,7 @@ #include <list> #include <stdio.h> #include <elf.h> +#include <cctype> #include <exeio.h> #include "check_thunks.hpp" @@ -170,11 +171,11 @@ bool is_possible_target(VirtualOffset_t p, VirtualOffset_t addr) } -EXEIO::section* find_section(VirtualOffset_t addr, EXEIO::exeio *elfiop) +EXEIO::section* find_section(VirtualOffset_t addr, EXEIO::exeio *exeiop) { - for ( int i = 0; i < elfiop->sections.size(); ++i ) + for ( int i = 0; i < exeiop->sections.size(); ++i ) { - EXEIO::section* pSec = elfiop->sections[i]; + EXEIO::section* pSec = exeiop->sections[i]; assert(pSec); if(pSec->get_address() > addr) continue; @@ -309,7 +310,7 @@ bool texttoprintf(FileIR_t *firp,Instruction_t* insn) return false; } -void get_instruction_targets(FileIR_t *firp, EXEIO::exeio* elfiop, const set<VirtualOffset_t>& thunk_bases) +void get_instruction_targets(FileIR_t *firp, EXEIO::exeio* exeiop, const set<VirtualOffset_t>& thunk_bases) { for(auto insn : firp->getInstructions()) @@ -324,22 +325,22 @@ void get_instruction_targets(FileIR_t *firp, EXEIO::exeio* elfiop, const set<Vir if(mt==admtX86_64 || mt==admtI386) { // work for both 32- and 64-bit. - check_for_PIC_switch_table32_type2(firp, insn, *disasm, elfiop, thunk_bases); - check_for_PIC_switch_table32_type3(firp, insn, *disasm, elfiop, thunk_bases); + check_for_PIC_switch_table32_type2(firp, insn, *disasm, exeiop, thunk_bases); + check_for_PIC_switch_table32_type3(firp, insn, *disasm, exeiop, thunk_bases); if (firp->getArchitectureBitWidth()==32) - check_for_PIC_switch_table32(firp, insn, *disasm, elfiop, thunk_bases); + check_for_PIC_switch_table32(firp, insn, *disasm, exeiop, thunk_bases); else if (firp->getArchitectureBitWidth()==64) - check_for_PIC_switch_table64(firp, insn, *disasm, elfiop); + check_for_PIC_switch_table64(firp, insn, *disasm, exeiop); else assert(0); - check_for_nonPIC_switch_table(firp, insn, *disasm, elfiop); - check_for_nonPIC_switch_table_pattern2(firp, insn, *disasm, elfiop); + check_for_nonPIC_switch_table(firp, insn, *disasm, exeiop); + check_for_nonPIC_switch_table_pattern2(firp, insn, *disasm, exeiop); } else if(mt==admtAarch64) { - check_for_arm_switch_type1(firp,insn, *disasm, elfiop); + check_for_arm_switch_type1(firp,insn, *disasm, exeiop); } else throw invalid_argument("Cannot determine machine type"); @@ -638,7 +639,7 @@ void check_for_arm_switch_type1( FileIR_t *firp, Instruction_t* i10, const DecodedInstruction_t &d10, - EXEIO::exeio* elfiop) + EXEIO::exeio* exeiop) { ibt_provenance_t prov=ibt_provenance_t::ibtp_switchtable_type1; @@ -974,7 +975,7 @@ notes: const auto i10_func=i10->getFunction(); // find the section with the jump table - const auto table_section=find_section(cur_table_addr,elfiop); + const auto table_section=find_section(cur_table_addr,exeiop); if(!table_section) continue; // if the section has no data, abort if not found @@ -1115,7 +1116,7 @@ notes: /* * check_for_PIC_switch_table32 - look for switch tables in PIC code for 32-bit code. */ -void check_for_PIC_switch_table32(FileIR_t *firp, Instruction_t* insn, const DecodedInstruction_t& disasm, EXEIO::exeio* elfiop, const set<VirtualOffset_t> &thunk_bases) +void check_for_PIC_switch_table32(FileIR_t *firp, Instruction_t* insn, const DecodedInstruction_t& disasm, EXEIO::exeio* exeiop, const set<VirtualOffset_t> &thunk_bases) { ibt_provenance_t prov=ibt_provenance_t::ibtp_switchtable_type1; @@ -1269,7 +1270,7 @@ I7: 08069391 <_gedit_app_ready+0x91> ret VirtualOffset_t table_base=thunk_base+table_offset; // find the section with the data table - EXEIO::section *pSec=find_section(table_base,elfiop); + EXEIO::section *pSec=find_section(table_base,exeiop); if(!pSec) continue; @@ -1344,7 +1345,7 @@ I7: 08069391 <_gedit_app_ready+0x91> ret -void check_for_PIC_switch_table32_type2(FileIR_t *firp, Instruction_t* insn, const DecodedInstruction_t& disasm, EXEIO::exeio* elfiop, const set<VirtualOffset_t> &thunk_bases) +void check_for_PIC_switch_table32_type2(FileIR_t *firp, Instruction_t* insn, const DecodedInstruction_t& disasm, EXEIO::exeio* exeiop, const set<VirtualOffset_t> &thunk_bases) { ibt_provenance_t prov=ibt_provenance_t::ibtp_switchtable_type2; auto ibtargets = InstructionSet_t(); @@ -1403,7 +1404,7 @@ I5: 0x809900e <text_handler+51>: jmp ecx auto table_base=thunk_base+table_offset; // find the section with the data table - auto pSec=find_section(table_base,elfiop); + auto pSec=find_section(table_base,exeiop); if(!pSec) continue; @@ -1475,7 +1476,7 @@ I5: 0x809900e <text_handler+51>: jmp ecx * * nb: also works for 64-bit. */ -void check_for_PIC_switch_table32_type3(FileIR_t* firp, Instruction_t* insn, const DecodedInstruction_t& disasm, EXEIO::exeio* elfiop, const set<VirtualOffset_t> &thunk_bases) +void check_for_PIC_switch_table32_type3(FileIR_t* firp, Instruction_t* insn, const DecodedInstruction_t& disasm, EXEIO::exeio* exeiop, const set<VirtualOffset_t> &thunk_bases) { uint32_t ptrsize=firp->getArchitectureBitWidth()/8; ibt_provenance_t prov=ibt_provenance_t::ibtp_switchtable_type3; @@ -1505,7 +1506,7 @@ void check_for_PIC_switch_table32_type3(FileIR_t* firp, Instruction_t* insn, con return; // find the section with the data table - EXEIO::section *pSec=find_section(table_base,elfiop); + EXEIO::section *pSec=find_section(table_base,exeiop); if(!pSec) return; @@ -1701,7 +1702,7 @@ void check_for_PIC_switch_table32_type3(FileIR_t* firp, Instruction_t* insn, con * if so, see if we can trace back a few instructions to find a * the start of the table. */ -void check_for_PIC_switch_table64(FileIR_t* firp, Instruction_t* insn, const DecodedInstruction_t& p_disasm, EXEIO::exeio* elfiop) +void check_for_PIC_switch_table64(FileIR_t* firp, Instruction_t* insn, const DecodedInstruction_t& p_disasm, EXEIO::exeio* exeiop) { ibt_provenance_t prov=ibt_provenance_t::ibtp_switchtable_type4; /* here's the pattern we're looking for */ @@ -1824,7 +1825,7 @@ Note: Here the operands of the add are reversed, so lookup code was not finding * This instruction will contain the register names for * the index and the address of the base of the table */ - if(!backup_until("movsxd", I6, I7)) + if(!backup_until("(mov|movsxd)", I6, I7)) return; string lea_string="lea "; @@ -1875,27 +1876,20 @@ Note: Here the operands of the add are reversed, so lookup code was not finding * make sure we match the register, * and allow recursion in the search (last parameter as true). * - */ - - /* * Convert to return set - */ + */ auto found_leas=InstructionSet_t(); - if (I6->getFunction()) + if (backup_until(lea_string.c_str(), I5, I6, "", true)) { - cout << "Using find_in_function method." << endl; - found_leas=find_in_function(lea_string,I6->getFunction()); + found_leas.insert(I5); } - else + else if (I6->getFunction()) { - cout << "Using fallback method." << endl; - if (backup_until(lea_string.c_str(), I5, I6, "", true)) - { - found_leas.insert(I5); - } + cout << "Using find_in_function method." << endl; + found_leas=find_in_function(lea_string,I6->getFunction()); } if (found_leas.empty()) { @@ -1927,8 +1921,14 @@ Note: Here the operands of the add are reversed, so lookup code was not finding VirtualOffset_t D1=strtol(d5.getOperand(1)->getString().c_str(), nullptr, 0); D1+=I5_cur->getAddress()->getVirtualOffset(); + // sometimes the lea only points at the image base, and the displacement field here is used for + // the offset into the image. This is useful if there are multiple switches (or other constructs) + // in the same function which can share register assignment of the image-base register. + // we recod the d6_displ field here + const auto d6_displ = d6->getOperand(1)->getMemoryDisplacement(); + // find the section with the data table - auto pSec=find_section(D1,elfiop); + auto pSec=find_section(D1+d6_displ,exeiop); // sanity check there's a section if(!pSec) @@ -1972,8 +1972,11 @@ Note: Here the operands of the add are reversed, so lookup code was not finding table_size=std::numeric_limits<int>::max(); } + // record the set of ibtargets we find here. auto ibtargets=InstructionSet_t(); - auto offset=D1-pSec->get_address(); + + // offset from address to access - section address + auto offset=D1+d6_displ-pSec->get_address(); auto entry=0U; auto found_table_error = false; do @@ -1985,8 +1988,8 @@ Note: Here the operands of the add are reversed, so lookup code was not finding break; } - const int *table_entry_ptr=(const int*)&(secdata[offset]); - VirtualOffset_t table_entry=*table_entry_ptr; + const auto table_entry_ptr = (const int*)&(secdata[offset]); + const auto table_entry = VirtualOffset_t(*table_entry_ptr); if(!possible_target(D1+table_entry, 0/* from addr unknown */,prov)) { @@ -2021,27 +2024,167 @@ Note: Here the operands of the add are reversed, so lookup code was not finding entry++; } while ( entry<=table_size); + // record the max entry we found + const auto max_valid_table_entry=entry+1; + // valid switch table? may or may not have default: in the switch // table size = 8, #entries: 9 b/c of default - cout << "pic64: detected table size (max_int means no found): 0x"<< hex << table_size << " #entries: 0x" << entry << " ibtargets.size: " << ibtargets.size() << endl; - + cout << "pic64: max-table-entry (max_int means no found): 0x"<< hex << table_size << " #entries: 0x" << entry << " ibtargets.size: " << ibtargets.size() << endl; jmptables[I8].addTargets(ibtargets); + // note that there may be an off-by-one error here as table size depends on whether instruction I2 is a jb or jbe. - if (!found_table_error) + + // If we've successfully found a table with at least 3 things, or we (oddly) found a table with + // less than 3 things but did so 100% effectively, go ahead and mark it a successful analysis + if (!found_table_error || ibtargets.size() > 3) { - cout << "pic64: valid switch table for "<<hex<<I8->getAddress()->getVirtualOffset() - <<"detected ibtp_switchtable_type4" << endl; + cout << "pic64: valid switch table for " << hex << I8->getAddress()->getVirtualOffset() + << " detected ibtp_switchtable_type4" << endl; jmptables[I8].setAnalysisStatus(iasAnalysisComplete); + addSwitchTableScoop(firp,max_valid_table_entry,4,D1+d6_displ,exeiop, I6, D1); + } else { - cout << "pic64: INVALID switch table detected for, " - <<hex<<I8->getAddress()->getVirtualOffset()<<"type=ibtp_switchtable_type4" << endl; + cout << "pic64: INVALID switch table detected for, " << hex + << I8->getAddress()->getVirtualOffset() + << "type=ibtp_switchtable_type4 with L5=" << endl; + // try the next L5. + continue; + } + /* + * Now, check to see if this was a two level table. + * Here's an example from a visual studio compiled program: + * + * cmp eax,0x23 + * ja 0x1400066d3 + * I5_cur: lea rcx,[rip+0xffffffffffff9a7d] # 0x140000000 + * I6_2 movzx eax,BYTE PTR [rcx+rax*1+0x6a50] + * I6: mov edx,DWORD PTR [rcx+rax*4+0x6a34] + * I7: add rdx,rcx + * I8: jmp rdx + * + */ + + // sanity check that I understand the variables of this function properly. + // and grab the index reg + const auto d6_memop = d6->getOperand(1); + assert(I6 && d6 && d6_memop->isMemory()); + + // hack approved by an7s to convert a field from the index register to the actual 32-bit register from RegID_t + const auto ireg_no = RegisterID_t(rn_EAX + d6_memop->getIndexRegister()); + auto ireg_str = registerToString(ireg_no); + transform(ALLOF(ireg_str), begin(ireg_str), ::tolower); + const auto I6_2_opcode_str = string() + "movzx " + ireg_str + ","; + + auto I6_2 = (Instruction_t*)nullptr; + if(backup_until(I6_2_opcode_str, I6_2, I6)) + { + // woo! found a 2 level table + // decode d6_2 and check the memory operand + const auto d6_2 = DecodedInstruction_t::factory(I6_2); + const auto d6_2_memop = d6_2->getOperand(1); + assert(d6_2_memop->isMemory()); + const auto d6_2_displ = d6_2_memop->getMemoryDisplacement(); + + // try next L5 if no 2 level table here + if(d6_2_displ == 0) continue; + + // look up the section and try next L5 if not found + const auto lvl2_table_addr = D1 + d6_2_displ; + const auto lvl2_table_sec=find_section(lvl2_table_addr,exeiop); + if(lvl2_table_sec == nullptr) continue; + + const auto lvl2_table_secdata=pSec->get_data(); + + // if the section has no data, abort + if(lvl2_table_secdata == nullptr) continue; + + // now, scan the lvl2 table, and stop if we find an entry bigger than + // the lvl1 table's size. This will calc the size of the lvl2 table. + // + // offset from address to access - section address + auto lvl2_table_offset=lvl2_table_addr - lvl2_table_sec->get_address(); + auto lvl2_table_entry_no=0U; + do + { + // check that we can still grab a word from this section + if((int)(lvl2_table_offset+sizeof(int)) > (int)lvl2_table_sec->get_size()) + break; + + const auto lvl2_table_entry_ptr = (const uint8_t*)&(lvl2_table_secdata[lvl2_table_offset]); + const auto lvl2_table_entry_val = *lvl2_table_entry_ptr; + + // found an entry that's bigger than our lvl1 table's max element + if(lvl2_table_entry_val > max_valid_table_entry ) + break; + + lvl2_table_offset+=sizeof(uint8_t); + lvl2_table_entry_no++; + } while ( lvl2_table_entry_no <= table_size); /* table_size from original cmp! */ + + // now record the lvl2 table into a scoop + addSwitchTableScoop(firp,lvl2_table_entry_no+1,1,lvl2_table_addr,exeiop, I6_2, D1); } } } + +void addSwitchTableScoop( + FileIR_t* firp, + const size_t num_entries, + const size_t entry_size, + const VirtualOffset_t table_base_addr, + EXEIO::exeio* exeiop, + Instruction_t* I6, + const VirtualOffset_t I5_constant + ) +{ + // make sure we can find the section with the switch table + const auto sec = exeiop->sections.findByAddress(table_base_addr); // section that contains the data + + // and only add if the section is executable. + // data sections already have scoops (consider splitting data scoops?) + if(sec == nullptr) return; + if(!sec->isExecutable()) return; + + const auto start_vo = 0u; // start and end offsets in this file + const auto end_vo = start_vo+num_entries*entry_size; + auto startaddr = firp->addNewAddress(firp->getFile()->getBaseID(), start_vo); // start and end address + auto endaddr = firp->addNewAddress(firp->getFile()->getBaseID(), end_vo); + assert(sec); + const auto sec_data = sec->get_data(); // data + const auto scoop_start_ptr = sec_data+(table_base_addr-sec->get_address()); // relevant start of data + const auto the_contents = string(scoop_start_ptr, end_vo-start_vo+1); + const auto name = string("fii_switch_")+to_hex_string(table_base_addr); // name of new segment + const auto permissions = // permissions and relro bit. + ( sec->isReadable() << 2 ) | + ( sec->isWriteable() << 1 ) | + ( sec->isExecutable() << 0 ) ; + const auto is_relro = false; + + // finally, create the new scoop + const auto switch_tab = firp->addNewDataScoop( name, startaddr, endaddr, NULL, permissions, is_relro, the_contents, max_base_id++ ); + + // and add a relocation so we can later repin the scoop + firp->addNewRelocation(I6, 0, "absoluteptr_to_scoop", switch_tab); + + // now rewrite the + const auto d6 = DecodedInstruction_t::factory(I6); + const auto operands = d6->getOperands(); + const auto the_arg = find_if(ALLOF(operands), [](const shared_ptr<DecodedOperand_t>& arg) { return arg->isMemory(); }); + const auto disp_offset = uint32_t(d6->getMemoryDisplacementOffset(the_arg->get(),I6)); + const auto disp_size = uint32_t((*the_arg)->getMemoryDisplacementEncodingSize()); + const auto file_base = firp->getArchitecture()->getFileBase(); + const auto new_disp = uint32_t(I5_constant-file_base); + const auto new_bits = I6->getDataBits().replace(disp_offset, disp_size, (const char*)&new_disp, disp_size); + I6->setDataBits(new_bits); + + +} + + /* switch table pattern (non-PIC): 40062a: 8d 40 ec lea eax,[rax-0x14] @@ -2055,7 +2198,7 @@ Note: Here the operands of the add are reversed, so lookup code was not finding nb: handles both 32 and 64 bit */ -void check_for_nonPIC_switch_table_pattern2(FileIR_t* firp, Instruction_t* insn, const DecodedInstruction_t& p_disasm, EXEIO::exeio* elfiop) +void check_for_nonPIC_switch_table_pattern2(FileIR_t* firp, Instruction_t* insn, const DecodedInstruction_t& p_disasm, EXEIO::exeio* exeiop) { ibt_provenance_t prov=ibt_provenance_t::ibtp_switchtable_type5; Instruction_t *I1 = nullptr; @@ -2084,7 +2227,7 @@ void check_for_nonPIC_switch_table_pattern2(FileIR_t* firp, Instruction_t* insn, if(!backup_until("cmp", I1, IJ)) { - cout<<"(nonPIC): could not find size of switch table"<<endl; + cout<<"(nonPIC-pattern2): could not find size of switch table"<<endl; return; } @@ -2099,7 +2242,7 @@ void check_for_nonPIC_switch_table_pattern2(FileIR_t* firp, Instruction_t* insn, cout<<"(nonPIC-pattern2): size of jmp table: "<< table_size << endl; // find the section with the data table - auto pSec=find_section(table_offset,elfiop); + auto pSec=find_section(table_offset,exeiop); if(!pSec) { return; @@ -2127,7 +2270,7 @@ void check_for_nonPIC_switch_table_pattern2(FileIR_t* firp, Instruction_t* insn, VirtualOffset_t table_entry=*table_entry_ptr; possible_target(table_entry,0,prov); - Instruction_t *ibtarget = lookupInstruction(firp, table_entry); + auto ibtarget = lookupInstruction(firp, table_entry); if (!ibtarget) { if(getenv("IB_VERBOSE")) cout << "0x" << hex << table_entry << " is not an instruction, invalid switch table" << endl; @@ -2158,7 +2301,7 @@ void check_for_nonPIC_switch_table_pattern2(FileIR_t* firp, Instruction_t* insn, nb: handles both 32 and 64 bit */ -void check_for_nonPIC_switch_table(FileIR_t* firp, Instruction_t* insn, const DecodedInstruction_t& p_disasm, EXEIO::exeio* elfiop) +void check_for_nonPIC_switch_table(FileIR_t* firp, Instruction_t* insn, const DecodedInstruction_t& p_disasm, EXEIO::exeio* exeiop) { ibt_provenance_t prov=ibt_provenance_t::ibtp_switchtable_type6; Instruction_t *I1 = nullptr; @@ -2219,7 +2362,7 @@ void check_for_nonPIC_switch_table(FileIR_t* firp, Instruction_t* insn, const De cout<<"(nonPIC): size of jmp table: "<< table_size << endl; // find the section with the data table - auto pSec=find_section(table_offset,elfiop); + auto pSec=find_section(table_offset,exeiop); if(!pSec) { cout<<hex<<"(nonPIC): could not find jump table in section"<<endl; @@ -2479,7 +2622,7 @@ void process_dynsym(FileIR_t* firp) } -ICFS_t* setup_hellnode(FileIR_t* firp, EXEIO::exeio* elfiop, ibt_provenance_t allowed) +ICFS_t* setup_hellnode(FileIR_t* firp, EXEIO::exeio* exeiop, ibt_provenance_t allowed) { auto hn=firp->addNewICFS(nullptr, {}, iasAnalysisModuleComplete); @@ -2496,13 +2639,13 @@ ICFS_t* setup_hellnode(FileIR_t* firp, EXEIO::exeio* elfiop, ibt_provenance_t al } } - if(hn->size() < 1000 && !elfiop->isDynamicallyLinked()) + if(hn->size() < 1000 && !exeiop->isDynamicallyLinked()) hn->setAnalysisStatus(iasAnalysisComplete); return hn; } -ICFS_t* setup_call_hellnode(FileIR_t* firp, EXEIO::exeio* elfiop) +ICFS_t* setup_call_hellnode(FileIR_t* firp, EXEIO::exeio* exeiop) { ibt_provenance_t allowed= ibt_provenance_t::ibtp_data | @@ -2541,14 +2684,14 @@ ICFS_t* setup_call_hellnode(FileIR_t* firp, EXEIO::exeio* elfiop) * ibt_provenance_t::ibtp_switchtable_type10 */ - auto ret=setup_hellnode(firp,elfiop,allowed); + auto ret=setup_hellnode(firp,exeiop,allowed); cout<<"# ATTRIBUTE fill_in_indtargs::call_hellnode_size="<<dec<<ret->size()<<endl; return ret; } -ICFS_t* setup_jmp_hellnode(FileIR_t* firp, EXEIO::exeio* elfiop) +ICFS_t* setup_jmp_hellnode(FileIR_t* firp, EXEIO::exeio* exeiop) { ibt_provenance_t allowed= ibt_provenance_t::ibtp_data | @@ -2585,14 +2728,14 @@ ICFS_t* setup_jmp_hellnode(FileIR_t* firp, EXEIO::exeio* elfiop) * ibt_provenance_t::ibtp_switchtable_type10 */ - auto ret=setup_hellnode(firp,elfiop,allowed); + auto ret=setup_hellnode(firp,exeiop,allowed); cout<<"# ATTRIBUTE fill_in_indtargs::jmp_hellnode_size="<<dec<<ret->size()<<endl; return ret; } -ICFS_t* setup_ret_hellnode(FileIR_t* firp, EXEIO::exeio* elfiop) +ICFS_t* setup_ret_hellnode(FileIR_t* firp, EXEIO::exeio* exeiop) { ibt_provenance_t allowed= ibt_provenance_t::ibtp_stars_ret | // stars says a return goes here, and this return isn't analyzeable. @@ -2634,7 +2777,7 @@ ICFS_t* setup_ret_hellnode(FileIR_t* firp, EXEIO::exeio* elfiop) * ibt_provenance_t::ibtp_gotplt */ - auto ret_hell_node=setup_hellnode(firp,elfiop,allowed); + auto ret_hell_node=setup_hellnode(firp,exeiop,allowed); cout<<"# ATTRIBUTE fill_in_indtargs::basicret_hellnode_size="<<dec<<ret_hell_node->size()<<endl; cout<<"# ATTRIBUTE fill_in_indtargs::fullret_hellnode_size="<<dec<<ret_hell_node->size()<<endl; @@ -2678,7 +2821,7 @@ void print_icfs(FileIR_t* firp) } } -void setup_icfs(FileIR_t* firp, EXEIO::exeio* elfiop) +void setup_icfs(FileIR_t* firp, EXEIO::exeio* exeiop) { int total_ibta_set=0; @@ -2700,9 +2843,9 @@ void setup_icfs(FileIR_t* firp, EXEIO::exeio* elfiop) // setup calls, jmps and ret hell nodes. - auto call_hell = setup_call_hellnode(firp,elfiop); - auto jmp_hell = setup_jmp_hellnode(firp,elfiop); - auto ret_hell = setup_ret_hellnode(firp,elfiop); + auto call_hell = setup_call_hellnode(firp,exeiop); + auto jmp_hell = setup_jmp_hellnode(firp,exeiop); + auto ret_hell = setup_ret_hellnode(firp,exeiop); // for each instruction for(auto insn : firp->getInstructions()) @@ -3502,7 +3645,7 @@ void find_all_arm_unks(FileIR_t* firp) /* * fill_in_indtargs - main driver routine for */ -void fill_in_indtargs(FileIR_t* firp, exeio* elfiop, int64_t do_unpin_opt) +void fill_in_indtargs(FileIR_t* firp, exeio* exeiop, int64_t do_unpin_opt) { calc_preds(firp); @@ -3518,12 +3661,12 @@ void fill_in_indtargs(FileIR_t* firp, exeio* elfiop, int64_t do_unpin_opt) lookupInstruction_init(firp); - int secnum = elfiop->sections.size(); + int secnum = exeiop->sections.size(); int secndx=0; /* look through each section and record bounds */ for (secndx=0; secndx<secnum; secndx++) - get_executable_bounds(firp, elfiop->sections[secndx]); + get_executable_bounds(firp, exeiop->sections[secndx]); /* import info from stars */ read_stars_xref_file(firp); @@ -3534,7 +3677,7 @@ void fill_in_indtargs(FileIR_t* firp, exeio* elfiop, int64_t do_unpin_opt) /* look through each section and look for target possibilities */ for (secndx=0; secndx<secnum; secndx++) - infer_targets(firp, elfiop->sections[secndx]); + infer_targets(firp, exeiop->sections[secndx]); handle_scoop_scanning(firp); @@ -3543,14 +3686,14 @@ void fill_in_indtargs(FileIR_t* firp, exeio* elfiop, int64_t do_unpin_opt) possible_target(pin, 0, ibt_provenance_t::ibtp_user); /* look through the instructions in the program for targets */ - get_instruction_targets(firp, elfiop, thunk_bases); + get_instruction_targets(firp, exeiop, thunk_bases); /* mark the entry point as a target */ - possible_target(elfiop->get_entry(),0,ibt_provenance_t::ibtp_entrypoint); + possible_target(exeiop->get_entry(),0,ibt_provenance_t::ibtp_entrypoint); /* Read the exception handler frame so that those indirect branches are accounted for */ /* then now process the ranges and mark IBTs as necessarthat have exception handling */ - read_ehframe(firp, elfiop); + read_ehframe(firp, exeiop); process_ranges(firp); /* now, find the .GOT addr and process any pc-rel things for x86-32 ibts. */ @@ -3572,7 +3715,7 @@ void fill_in_indtargs(FileIR_t* firp, exeio* elfiop, int64_t do_unpin_opt) cout<<"========================================="<<endl; // try to setup an ICFS for every IB. - setup_icfs(firp, elfiop); + setup_icfs(firp, exeiop); // do unpinning of well analyzed ibts. if(do_unpin_opt!=(int64_t)-1) @@ -3662,6 +3805,7 @@ int parseArgs(const vector<string> step_args) return 0; } +DatabaseID_t max_base_id=BaseObj_t::NOT_IN_DATABASE; int executeStep() { @@ -3698,15 +3842,18 @@ int executeStep() firp->setBaseIDS(); firp->assembleRegistry(); + // record the max base id, in case we add objects + max_base_id=firp->getMaxBaseID(); + // read the executeable file int elfoid=firp->getFile()->getELFOID(); pqxx::largeobject lo(elfoid); lo.to_file(pqxx_interface->getTransaction(),"readeh_tmp_file.exe"); - auto elfiop=unique_ptr<EXEIO::exeio>(new EXEIO::exeio); - elfiop->load(string("readeh_tmp_file.exe")); + auto exeiop=unique_ptr<EXEIO::exeio>(new EXEIO::exeio); + exeiop->load(string("readeh_tmp_file.exe")); // find all indirect branch targets - fill_in_indtargs(firp, elfiop.get(), do_unpin_opt); + fill_in_indtargs(firp, exeiop.get(), do_unpin_opt); if(split_eh_frame_opt) split_eh_frame(firp); diff --git a/irdb-libs/ir_builders/fix_calls.cpp b/irdb-libs/ir_builders/fix_calls.cpp index c66480b7e4f6f7416cb8edd8ec0ce4e57fd0cd3a..536452710b5cb6fa738821ba6d5a8db9f2747b89 100644 --- a/irdb-libs/ir_builders/fix_calls.cpp +++ b/irdb-libs/ir_builders/fix_calls.cpp @@ -46,6 +46,8 @@ extern void read_ehframe(FileIR_t* firp, EXEIO::exeio* ); class FixCalls_t : public TransformStep_t { + const bool opt_fix_no_func_target=false; + const bool opt_fix_no_target = false; public: @@ -148,10 +150,10 @@ bool call_needs_fix(Instruction_t* insn) return false; } - auto target=insn->getTarget(); - auto fallthru=insn->getFallthrough(); + const auto target=insn->getTarget(); + const auto fallthru=insn->getFallthrough(); - string pattern; +// string pattern; // this used to work because fill_in_indirects would mark IBTs // while reading the ehframe, which perfectly corresponds to when @@ -173,8 +175,8 @@ bool call_needs_fix(Instruction_t* insn) return true; } - auto addr=fallthru->getAddress()->getVirtualOffset(); - auto rangeiter=eh_frame_ranges.find(Range_t(addr,addr)); + const auto addr=fallthru->getAddress()->getVirtualOffset(); + const auto rangeiter=eh_frame_ranges.find(Range_t(addr,addr)); if(rangeiter != eh_frame_ranges.end()) // found an eh_frame addr entry for this call { in_ehframe++; @@ -192,7 +194,7 @@ bool call_needs_fix(Instruction_t* insn) if(!target) { /* call 0's aren't to real locations */ - auto disasm=DecodedInstruction_t::factory(insn); + const auto disasm=DecodedInstruction_t::factory(insn); if(disasm->getOperand(0)->isConstant() && disasm->getAddress()==0) { return false; @@ -207,17 +209,19 @@ bool call_needs_fix(Instruction_t* insn) cout<<"Needs fix: No target instruction"<< " address=" <<hex<<addr<<": "<<insn->getDisassembly()<<endl; } - /* then we need to fix it */ - return true; + // then we might need to fix it + // but typically, we don't fix it because it's not really a valid isntruction. + return opt_fix_no_target; } - /* if the location after the call is marked as an IBT, then + /* + * if the location after the call is marked as an IBT, then * this location might be used for walking the stack */ - auto func=target->getFunction(); + const auto func=target->getFunction(); /* if there's no function for this instruction */ if(!func) @@ -232,7 +236,7 @@ bool call_needs_fix(Instruction_t* insn) } target_not_in_function++; /* we need to fix it */ - return true; + return opt_fix_no_func_target; }