home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

日記/2010/05/31/PEファイルをメモリ上に「仮」ロードするPython(作りかけ)

日記/2010/05/31/PEファイルをメモリ上に「仮」ロードするPython(作りかけ)

日記 / 2010 / 05 / 31 / PEファイルをメモリ上に「仮」ロードするPython(作りかけ)
id: 665 所有者: msakamoto-sf    作成日: 2010-05-31 23:38:07
カテゴリ: Python Windows 

作りかけ。

に出てくる、PEヘッダー情報を基にして、実際にPEイメージがロードされた時と同様なレイアウトで、ヘッダーやセクションデータをメモリ上にコピーする箇所だけとりあえず作ってみようとした。

foo.py:

import sys, logging, struct, ctypes
 
# {{{ data structure definitions
 
BYTE = ctypes.c_ubyte
WORD = ctypes.c_ushort
LONG = ctypes.c_long
DWORD = ctypes.c_ulong
 
class IMAGE_DOS_HEADER(ctypes.Structure):
  _fields_ = [
      ('e_magic', WORD), # Magic number
      ('e_cblp', WORD), # Bytes on last page of file
      ('e_cp', WORD), # Pages in file
      ('e_crlc', WORD), # Relocations
      ('e_cparhdr', WORD), # Size of header in paragraphs
      ('e_minalloc', WORD), # Minimum extra paragraphs needed
      ('e_maxalloc', WORD), # Maximum extra paragraphs needed
      ('e_ss', WORD), # Initial (relative) SS value
      ('e_sp', WORD), # Initial SP value
      ('e_csum', WORD), # Checksum
      ('e_ip', WORD), # Initial IP value
      ('e_cs', WORD), # Initial (relative) CS value
      ('e_lfarlc', WORD), # File address of relocation table
      ('e_ovno', WORD), # Overlay number
      ('e_res', WORD * 4), # Reserved words
      ('e_oemid', WORD), # OEM identifier (for e_oeminfo)
      ('e_oeminfo', WORD), # OEM information; e_oemid specific
      ('e_res2', WORD * 10), # Reserved words
      ('e_lfanew', LONG), # File address of new exe header
      ]
 
class IMAGE_FILE_HEADER(ctypes.Structure):
  _fields_ = [
      ('Machine', WORD),
      ('NumberOfSections', WORD),
      ('TimeDateStamp', DWORD),
      ('PointerToSymbolTable', DWORD),
      ('NumberOfSymbols', DWORD),
      ('SizeOfOptionalHeader', WORD),
      ('Characteristics', WORD),
      ]
 
class IMAGE_DATA_DIRECTORY(ctypes.Structure):
  _fields_ = [
      ('VirtualAddress', DWORD),
      ('Size', DWORD),
      ]
 
IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16
 
class IMAGE_OPTIONAL_HEADER(ctypes.Structure):
  _fields_ = [
      ('Magic', WORD),
      ('MajorLinkerVersion', BYTE),
      ('MinorLinkerVersion', BYTE),
      ('SizeOfCode', DWORD),
      ('SizeOfInitializedData', DWORD),
      ('SizeOfUninitializedData', DWORD),
      ('AddressOfEntryPoint', DWORD),
      ('BaseOfCode', DWORD),
      ('BaseOfData', DWORD),
      ('ImageBase', DWORD),
      ('SectionAlignment', DWORD),
      ('FileAlignment', DWORD),
      ('MajorOperatingSystemVersion', WORD),
      ('MinorOperatingSystemVersion', WORD),
      ('MajorImageVersion', WORD),
      ('MinorImageVersion', WORD),
      ('MajorSubsystemVersion', WORD),
      ('MinorSubsystemVersion', WORD),
      ('Win32VersionValue', DWORD),
      ('SizeOfImage', DWORD),
      ('SizeOfHeaders', DWORD),
      ('CheckSum', DWORD),
      ('Subsystem', WORD),
      ('DllCharacteristics', WORD),
      ('SizeOfStackReserve', DWORD),
      ('SizeOfStackCommit', DWORD),
      ('SizeOfHeapReserve', DWORD),
      ('SizeOfHeapCommit', DWORD),
      ('LoaderFlags', DWORD),
      ('NumberOfRvaAndSizes', DWORD),
      ('DataDirectory', IMAGE_DATA_DIRECTORY * IMAGE_NUMBEROF_DIRECTORY_ENTRIES ),
      ]
 
class IMAGE_NT_HEADERS(ctypes.Structure):
  _fields_ = [
      ('Signature', DWORD),
      ('FileHeader', IMAGE_FILE_HEADER),
      ('OptionalHeader', IMAGE_OPTIONAL_HEADER),
      ]
 
IMAGE_SIZEOF_SHORT_NAME = 8
 
class IMAGE_SECTION_HEADER_MISC(ctypes.Union):
  _fields_ = [
      ('PhysicalAddress', DWORD),
      ('VirtualSize', DWORD),
      ]
 
class IMAGE_SECTION_HEADER(ctypes.Structure):
  _fields_ = [
      ('Name', BYTE * IMAGE_SIZEOF_SHORT_NAME),
      ('Misc', IMAGE_SECTION_HEADER_MISC),
      ('VirtualAddress', DWORD),
      ('SizeOfRawData', DWORD),
      ('PointerToRawData', DWORD),
      ('PointerToRelocations', DWORD),
      ('PointerToLinenumbers', DWORD),
      ('NumberOfRelocations', WORD),
      ('NumberOfLinenumbers', WORD),
      ('Characteristics', DWORD),
      ]
 
# }}}
 
if 2 != len(sys.argv):
  print 'usage: python %s filename' % sys.argv[0]
  quit()
 
file_name = sys.argv[1]
 
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s %(name)s %(levelname)s %(message)s',
    )
log = logging.getLogger('main')
 
try:
  f = open(file_name, 'rb')
except IOError, e:
  log.error("open(%s) faileed." % file_name)
  log.error(e)
  raise e
 
#  read IMAGE_DOS_HEADER
 
f.seek(0, 0)
sz = ctypes.sizeof(IMAGE_DOS_HEADER)
data = f.read(sz)
dos_header = IMAGE_DOS_HEADER()
fit = min(len(data), sz)
ctypes.memmove(ctypes.addressof(dos_header), data, fit)
 
#  read IMAGE_NT_HEADERS
 
f.seek(dos_header.e_lfanew, 0)
sz = ctypes.sizeof(IMAGE_NT_HEADERS)
data = f.read(sz)
pe_header = IMAGE_NT_HEADERS()
fit = min(len(data), sz)
ctypes.memmove(ctypes.addressof(pe_header), data, fit)
 
file_header = pe_header.FileHeader
opt_header = pe_header.OptionalHeader
 
section_headers = []
#  dump IMAGE_SECTION_HEADERs
 
section_header_sz = ctypes.sizeof(IMAGE_SECTION_HEADER)
for i in range(file_header.NumberOfSections):
  data = f.read(section_header_sz)
  section_header = IMAGE_SECTION_HEADER()
  fit = min(len(data), sz)
  ctypes.memmove(ctypes.addressof(section_header), data, fit)
  section_headers.append(section_header)
 
# load to memory
f.seek(0, 0)
file_bytes = f.read() # read all file contents
# "SizeOfImage"分のcharバッファを確保
image_buf = ctypes.create_string_buffer(opt_header.SizeOfImage)
ctypes.memset(image_buf, 0, opt_header.SizeOfImage)
image_buf_ptr = ctypes.addressof(image_buf)
 
# copy headers
ctypes.memmove(
    image_buf_ptr, 
    file_bytes,
    opt_header.SizeOfHeaders
    )
 
# copy section datas
for h in section_headers:
  section_virtual_addr = h.VirtualAddress
  pointer_to_rawdata = h.PointerToRawData
  size_of_rawdata = h.SizeOfRawData
  if pointer_to_rawdata :
    ctypes.memmove(
        image_buf_ptr + section_virtual_addr,
        file_bytes[pointer_to_rawdata:pointer_to_rawdata + size_of_rawdata],
        size_of_rawdata)
 
# とりあえずhexダンプ
# New Line flag
nl = 0
# Offset (= RVA)
offset = 0
for i in xrange(len(image_buf)):
  if nl == 0:
    print "%08X - %08X " % (offset, offset + 16), 
  print "%02X" % ord(image_buf[i]),
  nl = nl + 1
  offset = offset + 1
  if nl > 15:
    nl = 0
    print

実際にデバッガのmemory dumpと付き合わせたり、バイナリエディタの表示と見比べたところ、大凡問題ないように見える。
もうちょっと作り込んで、インポート情報周りをダンプ表示出来るようにしたい。


プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2010-05-31 23:44:03
md5:53384ffd555b60cc357dab521a3d58c5
sha1:0b294893e72cbdd724245f30f13c6fa4470b03b4
コメント
コメントを投稿するにはログインして下さい。