307 lines
9.8 KiB
C++
307 lines
9.8 KiB
C++
#ifndef _PE_LDR_COMMON_H_
|
|
#define _PE_LDR_COMMON_H_
|
|
|
|
#include <netnode.hpp>
|
|
#include <idp.hpp>
|
|
#include <loader.hpp>
|
|
#include <diskio.hpp>
|
|
|
|
#define PAGE_SIZE 0x1000
|
|
//------------------------------------------------------------------------
|
|
struct pe_section_visitor_t
|
|
{
|
|
virtual int idaapi visit_section(const pesection_t &, off_t /*file_offset*/) { return 0; }
|
|
virtual int idaapi load_all() { return 0; }
|
|
virtual ~pe_section_visitor_t(void) {}
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
//-V:pe_import_visitor_t:730 not all members of a class are initialized inside the constructor
|
|
struct pe_import_visitor_t
|
|
{
|
|
bool withbase;
|
|
int elsize; // initialized by process_import_table()
|
|
peimpdir_t id;
|
|
dimpdir_t did;
|
|
|
|
pe_import_visitor_t(void) : withbase(false) {}
|
|
virtual int idaapi visit_module(const char * /*dll*/, ea_t /*iat_start*/, ea_t /*int_rva*/) { return 0; }
|
|
virtual int idaapi leave_module(uint32 /*nprocessed_imports*/) { return 0; }
|
|
// buf==NULL:by ordinal
|
|
virtual int idaapi visit_import(ea_t impea, uint32 ordinal, const char *buf) = 0;
|
|
virtual int idaapi impdesc_error(off_t /*file_offset*/) { return 0; }
|
|
virtual ~pe_import_visitor_t(void) {}
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
struct pe_export_visitor_t
|
|
{
|
|
// this function will be called once at the start.
|
|
// it must return 0 to continue
|
|
virtual int idaapi visit_expdir(const peexpdir_t & /*ed*/, const char * /*modname*/) { return 0; }
|
|
// this function is called for each export. name is never NULL, forwarder may point to the forwarder function
|
|
// it must return 0 to continue
|
|
virtual int idaapi visit_export(uint32 rva, uint32 ord, const char *name, const char *forwarder) = 0;
|
|
virtual ~pe_export_visitor_t(void) {}
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
class pe_loader_t
|
|
{
|
|
int process_import_table(
|
|
linput_t *li,
|
|
ea_t atable,
|
|
ea_t ltable,
|
|
pe_import_visitor_t &piv);
|
|
template <class T>
|
|
T varead(linput_t *li, uint32 rva, bool *ok)
|
|
{
|
|
T x = 0;
|
|
bool _ok = vseek(li, rva) && qlread(li, &x, sizeof(x)) == sizeof(x);
|
|
if ( ok != NULL )
|
|
*ok = _ok;
|
|
return x;
|
|
}
|
|
public:
|
|
struct transl_t
|
|
{
|
|
ea_t start;
|
|
ea_t end;
|
|
off_t pos;
|
|
size_t psize;
|
|
};
|
|
typedef qvector<transl_t> transvec_t;
|
|
transvec_t transvec;
|
|
union
|
|
{
|
|
exehdr exe;
|
|
teheader_t te;
|
|
};
|
|
peheader_t pe;
|
|
peheader64_t pe64; // original 64bit header, should not be used
|
|
// because all fields are copied to pe
|
|
// nb: imagebase is truncated during the copy!
|
|
ea_t load_imagebase; // imagebase used during loading; initialized from the PE header but can be changed by the user
|
|
off_t peoff; // offset to pe header
|
|
bool link_ulink; // linked with unilink?
|
|
|
|
// low level functions
|
|
|
|
//------------------------------------------------------------------------
|
|
// NB! We need to walk the mapping backwards, because
|
|
// the later sections take priority over earlier ones
|
|
//
|
|
// e.g. consider
|
|
// section 0: start=1000, end=5000, pos=1000
|
|
// section 1: start=3000, end=4000, pos=5000
|
|
// for byte at RVA 3500:
|
|
// section 0 maps it from the file offset 3500
|
|
// but section 1 overrides it with the byte from file offset 5500!
|
|
//
|
|
inline ea_t map_ea(ea_t rva, const transl_t **tl=NULL)
|
|
{
|
|
for ( ssize_t i=transvec.size()-1; i >= 0; i-- )
|
|
{
|
|
const transl_t &trans = transvec[i];
|
|
if ( trans.start <= rva && trans.end > rva )
|
|
{
|
|
if ( tl != NULL )
|
|
*tl = &trans;
|
|
return rva-trans.start + trans.pos;
|
|
}
|
|
}
|
|
return BADADDR;
|
|
}
|
|
ea_t get_imagebase(void) const { return load_imagebase; }
|
|
void set_imagebase(ea_t newimagebase) { load_imagebase=newimagebase; }
|
|
virtual bool vseek(linput_t *li, uint32 rva);
|
|
inline uint16 vashort(linput_t *li, uint32 addr, bool *ok) { return varead<uint16>(li, addr, ok); }
|
|
inline uint32 valong(linput_t *li, uint32 addr, bool *ok) { return varead<uint32>(li, addr, ok); }
|
|
inline uint64 vaint64(linput_t *li, uint32 addr, bool *ok) { return varead<uint64>(li, addr, ok); }
|
|
char *asciiz(linput_t *li, uint32 rva, char *buf, size_t bufsize, bool *ok);
|
|
char *asciiz2(linput_t *li, uint32 rva, char *buf, size_t bufsize, bool *ok);
|
|
int process_sections(linput_t *li, off_t fist_sec_pos, int nojbs, pe_section_visitor_t &psv);
|
|
int process_sections(linput_t *li, pe_section_visitor_t &psv);
|
|
// If 'zero_bad_data==true' (i.e., the default), extra 'directories'
|
|
// in the pe/pe64 headers will be set to zero.
|
|
bool read_header(linput_t *li, off_t _peoff, bool silent, bool zero_bad_data = true);
|
|
|
|
// high level functions
|
|
bool read_header(linput_t *li, bool silent=false, bool zero_bad_data = true);
|
|
int process_sections(linput_t *li);
|
|
|
|
int process_delayed_imports(linput_t *li, pe_import_visitor_t &il);
|
|
int process_imports(linput_t *li, pe_import_visitor_t &piv);
|
|
int process_exports(linput_t *li, pe_export_visitor_t &pev);
|
|
bool vmread(linput_t *li, uint32 rva, void *buf, size_t sz);
|
|
|
|
bool read_strtable(qstring *out, linput_t *li);
|
|
|
|
virtual ~pe_loader_t(void) {}
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
struct import_loader_t : public pe_import_visitor_t
|
|
{
|
|
struct dllinfo_t
|
|
{
|
|
qstring orig_name;
|
|
qstring name;
|
|
netnode node; // will be used by import_module()
|
|
bool imported_module;
|
|
|
|
dllinfo_t()
|
|
: imported_module(false)
|
|
{}
|
|
};
|
|
typedef qvector<dllinfo_t> dllinfo_vec_t;
|
|
|
|
processor_t &ph;
|
|
peheader_t &pe;
|
|
dllinfo_vec_t dlls; // visited modules
|
|
range_t imprange;
|
|
ea_t astart;
|
|
ea_t last_imp;
|
|
ea_t int_rva;
|
|
int ndid; // number of delayed import dirs
|
|
bool displayed;
|
|
bool got_new_imports;
|
|
bool delayed_imports;
|
|
|
|
inline void preprocess(void);
|
|
inline bool has_module(const char *mod) const
|
|
{
|
|
size_t ndlls = dlls.size();
|
|
for ( size_t i = 0; i < ndlls; i++ )
|
|
if ( !stricmp(dlls[i].orig_name.c_str(), mod) )
|
|
return true;
|
|
return false;
|
|
}
|
|
int idaapi visit_module(const char *dll, ea_t iat_start, ea_t _int_rva) override;
|
|
int idaapi visit_import(ea_t impea, uint32 ordinal, const char *buf) override;
|
|
int idaapi leave_module(uint32 nprocessed_imports) override;
|
|
int idaapi impdesc_error(off_t off) override;
|
|
inline void postprocess(void);
|
|
|
|
import_loader_t(processor_t &_ph, peheader_t &_pe, bool di)
|
|
: ph(_ph), pe(_pe), astart(BADADDR), last_imp(BADADDR), int_rva(0),
|
|
ndid(0),
|
|
displayed(false), got_new_imports(false), delayed_imports(di)
|
|
{
|
|
imprange.start_ea = BADADDR;
|
|
imprange.end_ea = 0;
|
|
}
|
|
};
|
|
|
|
#ifdef __EA64__
|
|
|
|
struct function_entry_x64
|
|
{
|
|
uint32 BeginAddress;
|
|
uint32 EndAddress;
|
|
uint32 UnwindData;
|
|
bool operator<(const function_entry_x64 &r) const { return BeginAddress < r.BeginAddress; }
|
|
bool operator!=(const function_entry_x64 &r) const
|
|
{
|
|
return BeginAddress != r.BeginAddress
|
|
|| EndAddress != r.EndAddress
|
|
|| UnwindData != r.UnwindData;
|
|
}
|
|
};
|
|
|
|
struct unwind_info_x64
|
|
{
|
|
uint8 Version_Flags;
|
|
uint8 SizeOfProlog; //lint -e754 local structure member not referenced
|
|
uint8 CountOfCodes;
|
|
uint8 FrameRegister_Offset;
|
|
};
|
|
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------
|
|
struct ida_loader_t : public pe_loader_t
|
|
{
|
|
processor_t &ph;
|
|
eavec_t asked_eas;
|
|
import_loader_t imploader; // used in load_imports()
|
|
import_loader_t didloader; // used in load_delayed_imports()
|
|
eavec_t imp_fixups; // fixups to the import tables,
|
|
// they will be updated after a creation of
|
|
// the .idata segment
|
|
bool loaded_header = false;
|
|
bool vseek_asked = false;
|
|
bool has_embedded_pdb = false;
|
|
|
|
virtual bool vseek(linput_t *li, uint32 rva) override
|
|
{
|
|
ea_t fpos;
|
|
if ( get_linput_type(li) == LINPUT_PROCMEM )
|
|
{
|
|
fpos = rva;
|
|
}
|
|
else
|
|
{
|
|
fpos = map_ea(rva);
|
|
if ( fpos == BADADDR && rva < peoff+pe.allhdrsize )
|
|
fpos = rva;
|
|
}
|
|
if ( fpos != BADADDR )
|
|
{
|
|
qoff64_t p2 = qlseek(li, qoff64_t(fpos));
|
|
return p2 != -1;
|
|
}
|
|
if ( !vseek_asked
|
|
&& ask_yn(ASKBTN_YES,
|
|
"HIDECANCEL\n"
|
|
"Can't find translation for relative virtual address %08X, continue?",
|
|
rva) <= ASKBTN_NO )
|
|
{
|
|
loader_failure();
|
|
}
|
|
vseek_asked = true;
|
|
qlseek(li, rva, SEEK_SET);
|
|
return false;
|
|
}
|
|
ida_loader_t(void) //lint !e1401 non-static data member 'pe_loader_t::*' not initialized by constructor
|
|
: ph(PH),
|
|
imploader(ph, pe, false),
|
|
didloader(ph, pe, true) {}
|
|
|
|
void setup_entry_and_dgroup(linput_t *li, sel_t dgroup);
|
|
bool make_beginning_loaded(linput_t *li, ea_t begin);
|
|
sel_t load_sections(linput_t *li, bool aux, const qstring *strtable=nullptr);
|
|
void load_tls(linput_t *li);
|
|
void load_exports(linput_t *li);
|
|
void load_imports(linput_t *li);
|
|
void load_delayed_imports(linput_t *li);
|
|
void read_and_save_fixups(linput_t *li);
|
|
bool has_imports_by_ordinal(linput_t *li);
|
|
void load_cli_module(linput_t *_li);
|
|
void load_pdata(linput_t *li);
|
|
void pe_convert_idata();
|
|
void comment_impexp(linput_t *li);
|
|
void load_loadconfig(linput_t *li);
|
|
void load_header_section(linput_t *li, bool visible);
|
|
void load_debug_info(linput_t *li);
|
|
void remember_imp_fixup(ea_t fixup_ea, ea_t target)
|
|
{
|
|
for ( const auto &impldr : { imploader, didloader } )
|
|
{
|
|
if ( impldr.imprange.contains(target) )
|
|
{
|
|
imp_fixups.add(fixup_ea);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
bool has_ntdll() const { return imploader.has_module("ntdll.dll"); }
|
|
#ifdef __EA64__
|
|
int check_chained_uw(linput_t *li, uint32 rva, function_entry_x64 *chained, int nest_count = 0);
|
|
void load_pdata_x64(linput_t *li, uint32 pdata_rva, asize_t psize);
|
|
bool has_bad_uwopcodes(linput_t *li, uint32 uw_rva, ea_t funcstart);
|
|
#endif
|
|
};
|
|
|
|
#endif
|