「グレイハットパイソン」を読んでいます。
プロセスのスレッドを取得し、すべてのレジスタ値をダンプする例があります。
本からソースをコピーしましたが、うまくいきません。
ここに私が問題だと思うソースの一部があります。
def run(self):
# Now we have to poll the debuggee for debugging events
while self.debugger_active == True:
self.get_debug_event()
def get_debug_event(self):
debug_event = DEBUG_EVENT()
continue_status = DBG_CONTINUE
if kernel32.WaitForDebugEvent(byref(debug_event), INFINITE):
# We aren't going to build any event handlers
# just yet. Let's just resume the process for now.
# raw_input("Press a key to continue...")
# self.debugger_active = False
kernel32.ContinueDebugEvent(debug_event.dwProcessId, debug_event.dwThreadId, continue_status)
これらの 2 行は前の例で使用され、この例ではコメント化されています。
# raw_input("Press a key to continue...")
# self.debugger_active = False
これらの 2 行はコメントアウトされています。問題は、self.debugger_active が True の場合、WaitForDebugEvent と ContinueDebugEvent を介して実行されることです。
ただし、スレッドなどを開かないでください。理由がわかりませんが、39回実行されます。
これが完全なソースです。
from ctypes import *
from my_debugger_defines import *
kernel32 = windll.kernel32
class debugger():
def __init__(self):
self.h_process = None
self.pid = None
self.debugger_active = False
def load(self, path_to_exe):
# dwCreation flag determines how to create the process
# set creation_flags = CREATE_NEW_CONSOLE if you want
# to see the calculator GUI
creation_flags = DEBUG_PROCESS
# instantiate the structs
startupinfo = STARTUPINFO()
process_information = PROCESS_INFORMATION()
# The following two options allow the started process
# to be shown as a separate window. This also illustrates
# how different settings in the STARTUPINFO struct can affect the debuggee
startupinfo.dwFlags = 0x1
startupinfo.wShowWindow = 0x0
# We then initialize the cb variable in the STARTUPINFO struct
# which is just the size of the struct itself
startupinfo.cb = sizeof(startupinfo)
if kernel32.CreateProcessA(path_to_exe,
None,
None,
None,
None,
creation_flags,
None,
None,
byref(startupinfo),
byref(process_information)):
print "[*] We have successfully launched the process!"
print "[*] PID: %d" % process_information.dwProcessId
# Obtain a valid handle to the newly created process
# and store it for future access
self.h_process = self.open_process(process_information.dwProcessId)
else:
print "[*] Error: 0x%08x." % kernel32.GetLastError()
def open_process(self, pid):
h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, pid, False)
return h_process
def attach(self, pid):
self.h_process = self.open_process(pid)
# We attempt to attach to the process
# if this fails we exit the call
if kernel32.DebugActiveProcess(pid):
self.debugger_active = True
self.pid = int(pid)
self.run()
else:
print "[*] Unable to attach to the process. Error: 0x%08x." % kernel32.GetLastError()
def run(self):
# Now we have to poll the debuggee for debugging events
self.count = 1;
while self.debugger_active == True:
self.get_debug_event()
def get_debug_event(self):
debug_event = DEBUG_EVENT()
continue_status = DBG_CONTINUE
if kernel32.WaitForDebugEvent(byref(debug_event), INFINITE):
# We aren't going to build any event handlers
# just yet. Let's just resume the process for now.
# raw_input("Press a key to continue...")
# self.debugger_active = False
kernel32.ContinueDebugEvent(debug_event.dwProcessId, debug_event.dwThreadId, continue_status)
print "Just finished ContinueDebugEvent %d" % self.count
self.count += 1
def detach(self):
if kernel32.DebugActiveProcessStop(self.pid):
print "[*] Finished debugging. Exiting..."
return True
else:
print "There was an error finishing debugging"
return False
def open_thread(self, thread_id):
print "open_thread"
h_thread = kernel32.OpenThread(THREAD_ALL_ACCESS, None, thread_id)
if h_thread is not None:
return h_thread
else:
print "[*] Could not obtain a valid thread handle."
return False
def enumerate_threads(self):
print "enumerate_threads"
thread_entry = THREADENTRY32()
thread_list = []
snapshot = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, self.pid)
if snapshot is not None:
# You have to set the size of the struct
# or the call will fail
thread_entry.dwSize = sizeof(thread_entry)
success = kernel32.Thread32First(snapshot, byref(thread_entry))
while success:
if thread_entry.th32OwnerProcessID == self.pid:
thread_list.append(thread_entry.th32ThreadID)
success = kernel32.Thread32Next(snapshot, byref(thread_entry))
kernel32.CloseHandle(snapshot)
return thread_list
else:
return False
def get_thread_context(self, thread_id):
print "get_thread_context"
context = CONTEXT()
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS
# Obtain a handle to the thread
h_thread = self.open_thread(thread_id)
if kernel32.GetThreadContext(h_thread, byref(context)):
kernel32.CloseHandle(h_thread)
return context
else:
return False
追加した
これを少しデバッグしたところ、get_thread_context
が呼び出されると常に false が返されることがわかりました。
また、 の最後ではContinueDebugEvent
、 を呼び出しませんEXIT_THREAD_DEBUG_EVENT
。を呼び出した直後にプログラムを終了するだけEXEPTION_DEBUG_EVENT
です。
これら2つが関連しているかどうかはわかりませんが、更新として。
どうもありがとうございました。
パーツソリューション
コードに 1 つの大きなエラーが見つかりました。
本に何らかの編集版があるかどうかはわかりません。
とにかく、私の問題の 1 つは、それget_thread_context
がうまくいかないことでした。
ソースは次のように変更する必要があります
def get_thread_context(self, h_thread):
context = CONTEXT()
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS
if kernel32.GetThreadContext(h_thread, byref(context)):
kernel32.CloseHandle(h_thread)
return context
else:
return False
どういうわけか本のソースでは、スレッド ハンドルが のパラメータとして指定されていましたopen_thread
。すでにスレッド ハンドルを取得しており、それを のパラメータとして指定していますget_thread_context
。したがって、その必要はありません。
=============== 他のエラーの解決策はまだ見つかりません。で終わらContinueDebugEvent
ないものEXIT_THREAD_DEBUG_EVENT
。