pefileとpydasm

pythonのライブラリ pefilepydasmの日本語情報があんまり見つからなかったんで紹介記事書いてみるテスト。

まず、何ができるの?

pefileはWindowsの実行形式Portable Executableの解析を手助けしてくれるライブラリ。
pydasmはx86の逆アセンブルができるライブラリ。
この二つを組み合わせることで簡単にリバースエンジニアリングができちゃたりなんかするのです。

PEファイルのロード

モジュールをインポートして、ファイルをパースする

import pefile
pe =  pefile.PE(‘/path/to/pefile.exe’)

fast_loadをTrueで指定するとDirectoryを無視してパースするので、高速になる。

import pefile
pe =  pefile.PE(‘/path/to/pefile.exe’, fast_load=True)

あとでfull_load()メソッドを呼べば失われてる情報をパースできる。

生のPEデータをロードすることもできる。

pe = pefile.PE(data=str_object_with_pe_file_data)

ヘッダーメンバーの読み書き

PEファイルのパースが成功したら、PEインスタンスの属性を扱える。

pe.OPTIONAL_HEADER.AddressOfEntryPoint
pe.OPTIONAL_HEADER.ImageBase
pe.FILE_HEADER.NumberOfSections

writeメソッドでPEファイルに書き込むこともできる。

pe.write(filename='file_to_write.exe')

セクションのイテレート

PEインスタンスにはsectionsという属性がある。

for section in pe.sections:
  print (section.Name, hex(section.VirtualAddress),
    hex(section.Misc_VirtualSize), section.SizeOfRawData )

Output

('.text', '0x1000L', '0x6D72L', 28160L)
('.data', '0x8000L', '0x1BA8L', 1536L)
('.rsrc', '0xA000L', '0x8948L', 35328L)

インポートされたシンボルをリストアップ

for entry in pe.DIRECTORY_ENTRY_IMPORT:
  print entry.dll
  for imp in entry.imports:
    print '\t', hex(imp.address), imp.name

Output

comdlg32.dll
0x10012A0L PageSetupDlgW
0x10012A4L FindTextW
0x10012A8L PrintDlgExW
[snip]
SHELL32.dll
0x1001154L DragFinish

エクスポートされたシンボルをリストアップ

for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols:
  print hex(pe.OPTIONAL_HEADER.ImageBase + exp.address), exp.name, exp.ordinal

Output

0x7ca0ab4f SHUpdateRecycleBinIcon 336
0x7cab44c0 SHValidateUNC 173
0x7ca7b0aa SheChangeDirA 337
0x7ca7b665 SheChangeDirExA 338
0x7ca7b3e1 SheChangeDirExW 339
0x7ca7aec6 SheChangeDirW 340
0x7ca8baae SheConvertPathW 341

エントリーポイント付近のバイトを取り出す

pydasmをインポートして、pefileと組み合わせる。
エントリーポイントアドレスをフェッチして、そこから100バイト取り出して逆アセンブルしていく。

ep = pe.OPTIONAL_HEADER.AddressOfEntryPoint
ep_ava = ep+pe.OPTIONAL_HEADER.ImageBase
data = pe.get_memory_mapped_image()[ep:ep+100]
offset = 0
while offset < len(data):
  i = pydasm.get_instruction(data[offset:], pydasm.MODE_32)
  print pydasm.get_instruction_string(i, pydasm.FORMAT_INTEL, ep_ava+offset)
  offset += i.length

Output

push byte 0x70
push dword 0x1001888
call 0x1006ca8
xor ebx,ebx
push ebx
mov edi,[0x100114c]
call edi
cmp word [eax],0x5a4d
jnz 0x1006b1d
mov ecx,[eax+0x3c]
add ecx,eax
cmp dword [ecx],0x4550
jnz 0x1006b1d
movzx eax,[ecx+0x18


ま、こんな感じで簡単にPEファイルを取り扱って逆アセンブルしたりできるわけです。
面白いね!