Python3でリバースエンジニアリング その4

今回は3.2章。

32bitならraw_input()やprint文を変更するだけで大丈夫です。64bitの場合、スレッドIDは取得できるのですが、レジスタの値が取得できないので変更する必要があります。

 

それっぽい値は出力できるけど間違っていると思います。参考までに。

my_debugger.py

  1. ...
  2.     def get_thread_context(self, thread_id=None, h_thread=None):
  3.         ...
  4.         if kernel32.GetThreadContext(h_thread, byref(context)):
  5.             kernel32.CloseHandle(h_thread)
  6.             kernel32.RtlCaptureContext(byref(context))
  7.             return context

 64bitではRtlCaptureContext関数を使うと簡単にレジスタの値が取得できるらしい。

 

 

my_debugger_defines.py

  1. ...
  2. DWORD     = c_ulong
  3. DWORD64   = c_ulonglong
  4. ...
  5. class CONTEXT(Structure):
  6.     _fields_ = [
  7.  
  8.         ("ContextFlags", DWORD),
  9.         ("Dr0", DWORD),
  10.         ("Dr1", DWORD),
  11.         ("Dr2", DWORD),
  12.         ("Dr3", DWORD),
  13.         ("Dr6", DWORD),
  14.         ("Dr7", DWORD),
  15.         ("FloatSave", FLOATING_SAVE_AREA),
  16.         ("SegGs", DWORD),
  17.         ("SegFs", DWORD),
  18.         ("SegEs", DWORD),
  19.         ("SegDs", DWORD),
  20.         ("Rdi", DWORD64),
  21.         ("Rsi", DWORD64),
  22.         ("Rbx", DWORD64),
  23.         ("Rdx", DWORD64),
  24.         ("Rcx", DWORD64),
  25.         ("Rax", DWORD64),
  26.         ("Rbp", DWORD64),
  27.         ("Rip", DWORD64),
  28.         ("SegCs", DWORD),
  29.         ("EFlags", DWORD),
  30.         ("Rsp", DWORD64),
  31.         ("SegSs", DWORD),
  32.         ("ExtendedRegisters", BYTE * 512),
  33. ]

winnt.hを参考にしながらレジスタの型を変更

 

 

my_test.py

  1. ...
  2.     print("[*] Dumping registers for thread ID: 0x{0:08x}".format(thread))
  3.     print("[**] RIP: 0x{0:016x}".format(thread_context.Rip))
  4.     print("[**] RSP: 0x{0:016x}".format(thread_context.Rsp))
  5.     print("[**] RBP: 0x{0:016x}".format(thread_context.Rbp))
  6.     print("[**] RAX: 0x{0:016x}".format(thread_context.Rax))
  7.     print("[**] RBX: 0x{0:016x}".format(thread_context.Rbx))
  8.     print("[**] RCX: 0x{0:016x}".format(thread_context.Rcx))
  9.     print("[**] RDX: 0x{0:016x}".format(thread_context.Rdx))
  10.     print("[*] END DUMP")

 レジスタの名前を変更。

 

 

検索してもよくわからなかったのでそのまま次へ進みます。

Python3でリバースエンジニアリング その3

今回は3.1章の後半。raw_input()をinput()へ変更する必要があります。print文の変更は省略します。

 

my_debugger.py

  1. ...
  2.     def get_debug_event(self):
  3.         ...
  4.         if kernel32.WaitForDebugEvent(byref(debug_event), INFINITE):
  5.             input("Press a key to continue...")

 

my_test.py

  1. pid = input("Enter the PID of the process to attach to: ")

 

Python3でリバースエンジニアリング その2

前回リバースエンジニアリング ―Pythonによるバイナリ解析技法の続きで、今回は3.1章の前半。

 

my_debugger.py

  1. ...
  2.     def load(self, path_to_exe):
  3.         ...
  4.         if kernel32.CreateProcessA(path_to_exe.encode('utf-8'),
  5.                                    None,
  6.                                    None,
  7.                                    None,
  8.                                    None,
  9.                                    creation_flags,
  10.                                    None,
  11.                                    None,
  12.                                    byref(startupinfo),
  13.                                    byref(process_information)):
  14.             ...
  15.             print("[*] PID: {0}".format(process_information.dwProcessId))
  16.         else:
  17.             print("[*] Error: 0x{0:08x}".format(kernel32.GetLastError()))

 

 

 

リバースエンジニアリング ―Pythonによるバイナリ解析技法

『みんなのPython』をひと通り読み終えたので、一緒に借りてきた『リバースエンジニアリングPythonによるバイナリ解析技法』を読んでいきます。

非常に面白い本なのですが、少し古くPython2.5を前提に書かれているので、Python3に対応させつつ読んでいくつもりです。基本的にはprint文をprint関数へ、辞書型メソッドの変更をしていくだけです。

 

chapter1-printf.py

  1. ...
  2.     msvcrt = cdll.msvcrt
  3.     message_string = "Hello world!\n"
  4.     msvcrt.printf("Testing: {0}".format(message_string).encode('utf-8'))

 

python3からbytes型とstr型の自動変換が行われなくなったのでencodeが必要。

ちなみに4行目は

  1. msvcrt.wprintf("Testing: {0}".format(message_string))

 や

  1. msvcrt.printf(b"Testing: Hello world!\n")

 でも動作します。

 

 

cx_Freezeでpython3.2を実行形式(.exe)にする


pythonスクリプトをexeにするには、cx_Freeze / py2exe / PyInstallerと方法がいろいろあります。今回はcx_Freezeを使う方法を試してみたいと思います。

環境はWindows 7 Home Premium(64bit)。Python、PySideのインストールは前回の記事を参考にして下さい。

 

インストールするもの


cx_Freeze-4.2.3.win-amd64-py3.2.msi

 

・実行形式(.exe)に変換


test.py

  1. import sys
  2. from PySide.QtCore import *
  3. from PySide.QtGui import *
  4.  
  5. def main():
  6.     app = QApplication(sys.argv)
  7.     # Create a Label and show it
  8.    label = QLabel("Hello World")
  9.     label.show()
  10.     # Enter Qt application main loop
  11.    app.exec_()
  12.     sys.exit()
  13.  
  14. if __name__ == '__main__':
  15.     main()

 

setup.py

  1. from cx_Freeze import setup, Executable
  2.  
  3. setup(
  4.     name = "test",
  5.     version = "0.1",
  6.     description = "test",
  7.     executables = [Executable("test.py")])

 

上記スクリプトを同じ場所に保存して、コマンドプロンプトで次のコマンドを実行します。

  1. setup.py build

 

問題点


・パスに日本語を含む場所で実行すると「Fatal Python error: cannot get zipimporter instance」とエラーになる。

・64bitで作成したファイルは32bitで実行できない?

・簡単なプログラムでも結構な容量になる。

Python+PySideでGUIプログラミング


PyQtではじめるGUIプログラミングが面白そうだったのでメモ。

OSはWindows 7 Home Premium(64bit)。インストールするPythonのバージョンは、現時点で最新の3.2.3にしました。

 

インストールするもの


python-3.2.3.amd64.msiPython本体)

PySide-1.1.0qt474.win-amd64-py3.2.exeGUIライブラリ)

PyScripter-v2.5.3-x64-Setup.exe統合開発環境

 

ドキュメント


python3.2.3

python2.7.2ja(参考)

PySide

 

インストール


デフォルトの位置にインストールすれば、設定などは特にしなくて大丈夫だと思います。

 

ウィンドを表示


PyScripterを起動して以下を保存して実行。Hello Worldと書かれたウィンドが表示されると思います。

  1. import sys
  2. from PySide.QtCore import *
  3. from PySide.QtGui import *
  4.  
  5. def main():
  6.     app = QApplication(sys.argv)
  7.     # Create a Label and show it
  8.    label = QLabel("Hello World")
  9.     label.show()
  10.     # Enter Qt application main loop
  11.    app.exec_()
  12.     sys.exit()
  13.  
  14. if __name__ == '__main__':
  15.     main()

 

割と楽にGUIアプリが作れそうです。