Add new def + pe_parse with remotectypes test

This commit is contained in:
Clement Rouault
2015-09-03 12:57:15 +02:00
parent a133254c6b
commit 7ddcb492ed
3 changed files with 186 additions and 30 deletions
+88 -27
View File
@@ -1,8 +1,11 @@
import sys
import ctypes
import struct
import windows
import windows.hooks as hooks
from windows.generated_def.winstructs import *
import windows.remotectypes as rctypes
# This must go to windefs
IMAGE_DIRECTORY_ENTRY_EXPORT = 0
@@ -22,8 +25,27 @@ def RedefineCtypesStruct(struct, replacement):
def transform_ctypes_fields(struct, replacement):
return [(name, replacement.get(name, type)) for name, type in struct._fields_]
def PEFile(baseaddr):
if windows.current_process.bitness == 32:
def PEFile(baseaddr, target=None):
proc_bitness = windows.current_process.bitness
if target is None:
targetedbitness = proc_bitness
else:
targetedbitness = target.bitness
if targetedbitness == 32 and proc_bitness == 64:
raise NotImplementedError("Parse 32bits PE with 64bits current_process")
elif targetedbitness == 64 and proc_bitness == 32:
ctypes_structure_transformer = rctypes.transform_type_to_remote64bits
def create_structure_at(structcls, addr):
return rctypes.transform_type_to_remote64bits(structcls)(addr, target)
elif targetedbitness == proc_bitness: # Does not handle remote of same bitness..
ctypes_structure_transformer = lambda x: x
def create_structure_at(structcls, addr):
return structcls.from_address(addr)
else:
raise NotImplementedError("Parsing {0} PE from {1} Process".format(targetedbitness, proc_bitness))
if targetedbitness == 32:
IMAGE_ORDINAL_FLAG = IMAGE_ORDINAL_FLAG32
else:
IMAGE_ORDINAL_FLAG = IMAGE_ORDINAL_FLAG64
@@ -32,14 +54,30 @@ def PEFile(baseaddr):
@property
def addr(self):
return baseaddr + self.value
def __repr__(self):
return "<DWORD {0} (RVA to '{1}')>".format(self.value, hex(self.addr))
#class RVA(ctypes.Structure):
# _fields_ = [("Whatever", DWORD)]
# @property
# def addr(self):
# return baseaddr + self.Whatever
#
# def __repr__(self):
# return "<DWORD {0} (RVA to '{1}')>".format(self.Whatever, hex(self.addr))
class StringRVa(RVA):
@property
def str(self):
return ctypes.c_char_p(self.addr).value.decode()
if proc_bitness == 32 and ctypes_structure_transformer == rctypes.transform_type_to_remote64bits:
@property
def str(self):
#return rctypes.rctypes.Remote_c_char_p64.from_buffer_with_target(struct.pack("<Q", self.addr), target)
return rctypes.Remote_c_char_p64(self.addr, target=target).value
#return ctypes_structure_transformer(ctypes.c_char_p)(self.addr, target).value.decode()
else:
@property
def str(self):
return ctypes.c_char_p(self.addr).value.decode()
def __repr__(self):
return "<DWORD {0} (String RVA to '{1}')>".format(self.value, self.str)
@@ -47,7 +85,6 @@ def PEFile(baseaddr):
def __int__(self):
return self.value
class IMPORT_BY_NAME(ctypes.Structure):
_fields_ = [
("Hint", WORD),
@@ -66,7 +103,7 @@ def PEFile(baseaddr):
@classmethod
def create(cls, addr, ord, name):
self = cls.from_address(addr)
self = create_structure_at(cls, addr)
self.addr = addr
self.ord = ord
self.name = name
@@ -95,7 +132,7 @@ def PEFile(baseaddr):
self.baseaddr = baseaddr
def get_DOS_HEADER(self):
return IMAGE_DOS_HEADER.from_address(baseaddr)
return create_structure_at(IMAGE_DOS_HEADER, baseaddr)
def get_NT_HEADER(self):
return self.get_DOS_HEADER().get_NT_HEADER()
@@ -111,12 +148,15 @@ def PEFile(baseaddr):
if import_datadir.VirtualAddress == 0:
return []
import_descriptor_addr = RVA(import_datadir.VirtualAddress).addr
current_import_descriptor = self.IMAGE_IMPORT_DESCRIPTOR.from_address(import_descriptor_addr)
current_import_descriptor = create_structure_at(self.IMAGE_IMPORT_DESCRIPTOR, import_descriptor_addr)
#current_import_descriptor = self.IMAGE_IMPORT_DESCRIPTOR.from_address(import_descriptor_addr)
res = []
while current_import_descriptor.FirstThunk:
print(current_import_descriptor.FirstThunk)
res.append(current_import_descriptor)
import_descriptor_addr += ctypes.sizeof(self.IMAGE_IMPORT_DESCRIPTOR)
current_import_descriptor = self.IMAGE_IMPORT_DESCRIPTOR.from_address(import_descriptor_addr)
#current_import_descriptor = self.IMAGE_IMPORT_DESCRIPTOR.from_address(import_descriptor_addr)
current_import_descriptor = create_structure_at(self.IMAGE_IMPORT_DESCRIPTOR, import_descriptor_addr)
return res
def get_EXPORT_DIRECTORY(self):
@@ -124,7 +164,8 @@ def PEFile(baseaddr):
if export_directory_rva == 0:
return None
export_directory_addr = baseaddr + export_directory_rva
return self._IMAGE_EXPORT_DIRECTORY.from_address(export_directory_addr)
return create_structure_at(self._IMAGE_EXPORT_DIRECTORY, export_directory_addr)
#return self._IMAGE_EXPORT_DIRECTORY.from_address(export_directory_addr)
@property
@@ -147,7 +188,8 @@ def PEFile(baseaddr):
IAT = import_descriptor.get_IAT()
if INT is not None:
for iat_entry, (ord, name) in zip(IAT, INT):
iat_entry.name = name.decode()
# str(name.decode()) -> python2 and python3 compatible for str result
iat_entry.name = str(name.decode()) if name else name
iat_entry.ord = ord
res.setdefault(import_descriptor.Name.str.lower(),[]).extend(IAT)
return res
@@ -157,30 +199,44 @@ def PEFile(baseaddr):
_fields_ = transform_ctypes_fields(IMAGE_IMPORT_DESCRIPTOR, {"Name" : StringRVa, "OriginalFirstThunk" : RVA, "FirstThunk" : RVA})
def get_INT(self):
if not self.OriginalFirstThunk.value:
return None
int_addr = self.OriginalFirstThunk.addr
int_entry = THUNK_DATA.from_address(int_addr)
#int_entry = THUNK_DATA.from_address(int_addr)
int_entry = create_structure_at(THUNK_DATA, int_addr)
res = []
while int_entry.Ordinal:
if int_entry.Ordinal & IMAGE_ORDINAL_FLAG:
res += [(int_entry.Ordinal & 0x7fffffff, None)]
else:
import_by_name = IMPORT_BY_NAME.from_address(baseaddr + int_entry.AddressOfData)
name = ctypes.c_char_p(ctypes.addressof(import_by_name) + IMPORT_BY_NAME.Name.offset).value
#import_by_name = IMPORT_BY_NAME.from_address(baseaddr + int_entry.AddressOfData)
import_by_name = create_structure_at(IMPORT_BY_NAME, baseaddr + int_entry.AddressOfData)
if proc_bitness == 32 and ctypes_structure_transformer == rctypes.transform_type_to_remote64bits:
name = rctypes.Remote_c_char_p64(baseaddr + int_entry.AddressOfData + type(import_by_name).Name.offset, target=target).value
#name = rctypes.Remote_c_char_p64.from_buffer_with_target(bytearray(struct.pack("<Q", baseaddr + int_entry.AddressOfData + type(import_by_name).Name.offset)), target=target).value
else:
name = ctypes.c_char_p(ctypes.addressof(import_by_name) + IMPORT_BY_NAME.Name.offset).value # FIXIT
res.append((import_by_name.Hint, name))
int_addr += ctypes.sizeof(THUNK_DATA)
int_entry = THUNK_DATA.from_address(int_addr)
int_addr += ctypes.sizeof(type(int_entry))
#int_entry = THUNK_DATA.from_address(int_addr)
int_entry = create_structure_at(THUNK_DATA, int_addr)
return res
def get_IAT(self):
iat_addr = self.FirstThunk.addr
iat_entry = THUNK_DATA.from_address(iat_addr)
#iat_entry = THUNK_DATA.from_address(iat_addr)
iat_entry = create_structure_at(THUNK_DATA, iat_addr)
res = []
while iat_entry.Ordinal:
res.append(IATEntry.create(iat_addr, -1, "??"))
iat_addr += ctypes.sizeof(THUNK_DATA)
iat_entry = THUNK_DATA.from_address(iat_addr)
iat_addr += ctypes.sizeof(type(iat_entry))
#iat_entry = THUNK_DATA.from_address(iat_addr)
iat_entry = create_structure_at(THUNK_DATA, iat_addr)
return res
# Will be usable as `self._IMAGE_EXPORT_DIRECTORY`
@@ -188,10 +244,13 @@ def PEFile(baseaddr):
_fields_ = transform_ctypes_fields(IMAGE_EXPORT_DIRECTORY, {"Name" : StringRVa, "AddressOfFunctions" : RVA, "AddressOfNames" : RVA, "AddressOfNameOrdinals": RVA})
def get_exports(self):
NameOrdinals = (WORD * self.NumberOfNames).from_address(self.AddressOfNameOrdinals.addr)
#NameOrdinals = (WORD * self.NumberOfNames).from_address(self.AddressOfNameOrdinals.addr)
NameOrdinals = create_structure_at((WORD * self.NumberOfNames), self.AddressOfNameOrdinals.addr)
NameOrdinals = list(NameOrdinals)
Functions = (RVA * self.NumberOfFunctions).from_address(self.AddressOfFunctions.addr)
Names = (StringRVa * self.NumberOfNames).from_address(self.AddressOfNames.addr)
#Functions = (RVA * self.NumberOfFunctions).from_address(self.AddressOfFunctions.addr)
Functions = create_structure_at((RVA * self.NumberOfFunctions), self.AddressOfFunctions.addr)
#Names = (StringRVa * self.NumberOfNames).from_address(self.AddressOfNames.addr)
Names = create_structure_at((StringRVa * self.NumberOfNames), self.AddressOfNames.addr)
res = []
for nb,func in enumerate(Functions):
if nb in NameOrdinals:
@@ -227,9 +286,11 @@ def PEFile(baseaddr):
]
def get_NT_HEADER(self):
if windows.current_process.bitness == 32:
return IMAGE_NT_HEADERS32.from_address(baseaddr + self.e_lfanew)
return IMAGE_NT_HEADERS64.from_address(baseaddr + self.e_lfanew)
if targetedbitness == 32:
return create_structure_at(IMAGE_NT_HEADERS32, baseaddr + self.e_lfanew)
return create_structure_at(IMAGE_NT_HEADERS64, baseaddr + self.e_lfanew)
#return IMAGE_NT_HEADERS64.from_address(baseaddr + self.e_lfanew)
return current_pe