4 from collections
import defaultdict
6 from elfesteem
import pe
7 from elfesteem
import cstruct
8 from elfesteem
import *
14 log = logging.getLogger(
'loader_pe')
15 hnd = logging.StreamHandler()
16 hnd.setFormatter(logging.Formatter(
"[%(levelname)s]: %(message)s"))
18 log.setLevel(logging.CRITICAL)
22 import2addr = defaultdict(set)
23 if e.DirImport.impdesc
is None:
25 for s
in e.DirImport.impdesc:
28 libname = s.dlldescname.name.lower()
29 for ii, imp
in enumerate(s.impbynames):
30 if isinstance(imp, pe.ImportByName):
35 import2addr[(libname, funcname)].
add(
36 e.rva2virt(s.firstthunk + e._wsize * ii / 8))
44 for (libname, libfunc), ads
in fa.items():
46 ad_base_lib = runtime_lib.lib_get_add_base(libname)
47 ad_libfunc = runtime_lib.lib_get_add_func(ad_base_lib, libfunc, ad)
50 dyn_funcs[libname_s] = ad_libfunc
53 ad, struct.pack(cstruct.size2type[e._wsize], ad_libfunc))
60 for i
in xrange(0x200):
65 if not (c.isalnum()
or c
in "_.-+*$@&#()[]={}"):
70 return out[:i], out[i + 1:]
76 for i, n
in enumerate(e.DirExport.f_names):
77 addr = e.DirExport.f_address[e.DirExport.f_nameordinals[i].ordinal]
80 out.append((f_name, e.rva2virt(addr.rva)))
83 for i, o
in enumerate(e.DirExport.f_nameordinals):
84 addr = e.DirExport.f_address[o.ordinal]
88 (o.ordinal + e.DirExport.expdesc.base, e.rva2virt(addr.rva)))
92 def vm_load_pe(vm, fdata, align_s=True, load_hdr=True, **kargs):
93 """Load a PE in memory (@vm) from a data buffer @fdata
95 @fdata: data buffer to parse
96 @align_s: (optional) If False, keep gaps between section
97 @load_hdr: (optional) If False, do not load the NThdr in memory
98 Return the corresponding PE instance.
100 Extra arguments are passed to PE instanciation.
101 If all sections are aligned, they will be mapped on several different pages
102 Otherwise, a big page is created, containing all sections
105 pe = pe_init.PE(fdata, **kargs)
109 for section
in pe.SHList:
110 if section.addr & 0xFFF:
118 hdr_len = max(0x200, pe.NThdr.sizeofheaders)
120 min_len = min(pe.SHList[0].addr, 0x1000)
123 pe_hdr = pe.content[:hdr_len] + max(
124 0, (min_len - hdr_len)) *
"\x00"
125 vm.add_memory_page(pe.NThdr.ImageBase, PAGE_READ | PAGE_WRITE,
131 for i, section
in enumerate(pe.SHList[:-1]):
132 new_size = pe.SHList[i + 1].addr - section.addr
133 section.size = new_size
134 section.rawsize = new_size
135 section.data = strpatchwork.StrPatchwork(
136 section.data[:new_size])
137 section.offset = section.addr
140 last_section = pe.SHList[-1]
141 last_section.size = (last_section.size + 0xfff) & 0xfffff000
144 for section
in pe.SHList:
145 data = str(section.data)
146 data +=
"\x00" * (section.size - len(data))
147 vm.add_memory_page(pe.rva2virt(section.addr),
148 PAGE_READ | PAGE_WRITE, data)
153 log.warning(
'PE is not aligned, creating big section')
154 min_addr = 0
if load_hdr
else None
158 for i, section
in enumerate(pe.SHList):
159 if i < len(pe.SHList) - 1:
161 section.size = pe.SHList[i + 1].addr - section.addr
162 section.rawsize = section.size
163 section.offset = section.addr
166 if min_addr
is None or section.addr < min_addr:
167 min_addr = section.addr
168 max_section_len = max(section.size, len(section.data))
169 if max_addr
is None or section.addr + max_section_len > max_addr:
170 max_addr = section.addr + max_section_len
172 min_addr = pe.rva2virt(min_addr)
173 max_addr = pe.rva2virt(max_addr)
174 log.debug(
'Min: 0x%x, Max: 0x%x, Size: 0x%x', min_addr, max_addr,
175 (max_addr - min_addr))
178 vm.add_memory_page(min_addr,
179 PAGE_READ | PAGE_WRITE,
180 (max_addr - min_addr) *
"\x00")
183 for section
in pe.SHList:
184 log.debug(
'Map 0x%x bytes to 0x%x', len(section.data),
185 pe.rva2virt(section.addr))
186 vm.set_mem(pe.rva2virt(section.addr), str(section.data))
192 """Call vm_load_pe on @fname_in and update @libs accordingly
194 @fname_in: library name
195 @libs: libimp_pe instance
196 @lib_path_base: DLLs relative path
197 Return the corresponding PE instance
198 Extra arguments are passed to vm_load_pe
200 fname = os.path.join(lib_path_base, fname_in)
201 with open(fname)
as fstream:
203 libs.add_export_lib(pe, fname_in)
208 """Call vm_load_pe_lib on each @libs_name filename
210 @libs_name: list of str
211 @libs: libimp_pe instance
212 @lib_path_base: (optional) DLLs relative path
213 Return a dictionnary Filename -> PE instances
214 Extra arguments are passed to vm_load_pe_lib
216 return {fname:
vm_load_pe_lib(vm, fname, libs, lib_path_base, **kargs)
217 for fname
in libs_name}
221 patch_vm_imp=
True, **kargs):
222 for e
in lib_imgs.values():
226 def vm2pe(myjit, fname, libs=None, e_orig=None,
227 min_addr=
None, max_addr=
None,
228 min_section_offset=0x1000, img_base=
None,
234 mye = pe_init.PE(wsize=size)
236 if min_addr
is None and e_orig
is not None:
237 min_addr = min([e_orig.rva2virt(s.addr)
for s
in e_orig.SHList])
238 if max_addr
is None and e_orig
is not None:
239 max_addr = max([e_orig.rva2virt(s.addr + s.size)
240 for s
in e_orig.SHList])
243 img_base = e_orig.NThdr.ImageBase
245 mye.NThdr.ImageBase = img_base
246 all_mem = myjit.vm.get_all_memory()
247 addrs = all_mem.keys()
249 mye.Opthdr.AddressOfEntryPoint = mye.virt2rva(myjit.pc)
252 if not min_addr <= ad < max_addr:
254 log.debug(
"0x%x", ad)
256 mye.SHList.add_section(
258 addr=ad - mye.NThdr.ImageBase,
259 data=all_mem[ad][
'data'],
260 offset=min_section_offset)
262 mye.SHList.add_section(
264 addr=ad - mye.NThdr.ImageBase,
265 data=all_mem[ad][
'data'])
268 if added_funcs
is not None:
271 for addr, funcaddr
in added_func:
272 libbase, dllname = libs.fad2info[funcaddr]
273 libs.lib_get_add_func(libbase, dllname, addr)
275 new_dll = libs.gen_new_lib(mye, mye.virt.is_addr_in)
279 log.debug(
'%s', new_dll)
281 mye.DirImport.add_dlldesc(new_dll)
282 s_imp = mye.SHList.add_section(
"import", rawsize=len(mye.DirImport))
283 mye.DirImport.set_rva(s_imp.addr)
284 log.debug(
'%r', mye.SHList)
289 ad = e_orig.NThdr.optentries[pe.DIRECTORY_ENTRY_RESOURCE].rva
290 log.debug(
'dirres 0x%x', ad)
292 mye.NThdr.optentries[pe.DIRECTORY_ENTRY_RESOURCE].rva = ad
293 mye.DirRes = pe.DirRes.unpack(xx, ad, mye)
295 s_res = mye.SHList.add_section(
296 name=
"myres", rawsize=len(mye.DirRes))
297 mye.DirRes.set_rva(s_res.addr)
298 log.debug(
'%r', mye.DirRes)
300 open(fname,
'w').write(str(mye))
307 self.all_exported_lib.append(e)
312 log.debug(
'new lib %s', name)
313 ad = e.NThdr.ImageBase
326 imp_ord_or_name, ad = todo.pop()
332 exp_dname, exp_fname = ret
335 exp_dname = exp_dname +
'.dll'
336 exp_dname = exp_dname.lower()
338 if exp_dname == name:
339 libad_tmp = self.
name2off[exp_dname]
340 if not exp_fname
in self.
lib_imp2ad[libad_tmp]:
342 todo = [(imp_ord_or_name, ad)] + todo
344 elif not exp_dname
in self.
name2off:
345 raise ValueError(
'load %r first' % exp_dname)
347 libad_tmp = self.
name2off[exp_dname]
357 name_inv = dict([(x[1], x[0])
for x
in self.name2off.items()])
359 name_inv[libad], imp_ord_or_name)
361 self.
fad2info[ad] = libad, imp_ord_or_name
364 """Gen a new DirImport description
365 @target_pe: PE instance
366 @flt: (boolean f(address)) restrict addresses to keep
370 for lib_name, ad
in self.name2off.items():
375 for func_name, dst_addresses
in self.
lib_imp2dstad[ad].items():
376 out_ads.update({addr: func_name
for addr
in dst_addresses})
379 all_ads = [addr
for addr
in out_ads.keys()
if flt(addr)]
380 log.debug(
'ads: %s', map(hex, all_ads))
386 for i, x
in enumerate(all_ads):
387 if x
not in [0,
None]:
389 all_ads = all_ads[i:]
395 while (i + 1 < len(all_ads)
and
396 all_ads[i] + target_pe._wsize / 8 == all_ads[i + 1]):
401 funcs = [out_ads[addr]
for addr
in all_ads[:i + 1]]
403 rva = target_pe.virt2rva(othunk)
404 except pe.InvalidOffset:
407 new_lib.append(({
"name": lib_name,
413 all_ads = all_ads[i + 1:]
418 PE_machine = {0x14c:
"x86_32",
424 """Return the architecture specified by the PE container @pe.
425 If unknown, return None"""
426 return PE_machine.get(pe.Coffhdr.machine,
None)
def get_export_name_addr_list
def canon_libname_libfunc
def get_import_address_pe
def vm_fix_imports_pe_libs