Переключение потоков в PyDbg
Я попытался опубликовать это в обмене стеками с обратным инжинирингом, но я решил сделать кросс-публикацию здесь для большей наглядности.
У меня проблемы с переключением с одного потока на другой в pydbg. У меня нет большого опыта работы с многопоточностью, поэтому я надеюсь, что мне не хватает чего-то очевидного.
По сути, я хочу приостановить все потоки, а затем начать пошаговое выполнение одного потока. В моем случае есть две темы.
Сначала я приостановил все темы. Затем я установил точку останова в том месте, где будет EIP, когда поток 2 возобновится. (Это местоположение подтверждается с помощью IDA). Затем я включаю пошаговое выполнение, как в любом другом контексте, и возобновляю поток 2.
Однако pydbg, похоже, не улавливает исключение точки останова! Кажется, что поток 2 возобновляется, и хотя он ДОЛЖЕН попасть по этому адресу, нет никаких признаков того, что pydbg перехватывает исключение точки останова. Я включил "print "HIT BREAKPOINT"во внутренний обработчик точки останова pydbg, и это, кажется, никогда не вызывается после возобновления потока 2.
Я не слишком уверен, куда идти дальше, поэтому любые предложения приветствуются!
dbg.suspend_all_threads()
print dbg.enumerate_threads()[0]
oldcontext = dbg.get_thread_context(thread_id=dbg.enumerate_threads()[0])
if (dbg.disasm(oldcontext.Eip) == "ret"):
print disasm_at(dbg,oldcontext.Eip)
print "Thread EIP at a ret"
addrstr = int("0x"+(dbg.read(oldcontext.Esp + 4,4))[::-1].encode("hex"),16)
print hex(addrstr)
dbg.bp_set(0x7C90D21A,handler=Thread_Start_bp_Handler)
print dbg.read(0x7C90D21A,1).encode("hex")
dbg.bp_set(oldcontext.Eip + dbg.instruction.length,handler=Thread_Start_bp_Handler)
dbg.set_thread_context(oldcontext,thread_id=dbg.enumerate_threads()[0])
dbg.context = oldcontext
dbg.resume_thread(dbg.enumerate_threads()[0])
dbg.single_step(enable=True)
return DBG_CONTINUE
Извините за "магические числа", но, насколько я могу судить, они верны.
1 ответ
Одна из ваших проблем заключается в том, что вы пытаетесь пошагово пройти через Thread2, и вы ссылаетесь только на Thread1 в своем коде:
dbg.enumerate_threads()[0] # <--- Return handle to the first thread.
Кроме того, код, который вы разместили, не отражает полную структуру вашего скрипта, что затрудняет оценку, есть ли у вас другие ошибки или нет. Вы также пытаетесь установить точку останова внутри вспомогательной ветви, которая разбирает ваши инструкции, что не имеет большого смысла для меня логически. Позвольте мне попытаться объяснить, что я знаю, и изложить это организованно. Таким образом, вы можете оглянуться на свой код, переосмыслить и исправить его.
Давайте начнем с базовой инфраструктуры отладки приложения с помощью pydbg:
- Создать экземпляр отладчика
- Атташе к процессу
- Установить точки останова
- Запустить его
- Точка останова получает удар - справиться с этим.
Вот как это может выглядеть:
from pydbg import *
from pydbg.defines import *
# This is maximum number of instructions we will log
MAX_INSTRUCTIONS = 20
# Address of the breakpoint
func_address = "0x7C90D21A"
# Create debugger instance
dbg = pydbg()
# PID to attach to
pid = int(raw_input("Enter PID: "))
# Attach to the process with debugger instance created earlier.
# Attaching the debugger will pause the process.
dbg.attach(pid)
# Let's set the breakpoint and handler as thread_step_setter,
# which we will define a little later...
dbg.bp_set(func_address, handler=thread_step_setter)
# Let's set our "personalized" handler for Single Step Exception
# It will get triggered if execution of a thread goes into single step mode.
dbg.set_callback(EXCEPTION_SINGLE_STEP, single_step_handler)
# Setup is done. Let's run it...
dbg.run()
Теперь, имея базовую структуру, давайте определим наши персонализированные обработчики для точки останова и пошагового выполнения. Фрагмент кода ниже определяет наши "пользовательские" обработчики. Что произойдет, когда точки останова достигнут, мы будем перебирать потоки и устанавливать их в одношаговый режим. Это, в свою очередь, вызовет одношаговое исключение, которое мы обработаем и разберем в MAX_INSTRUCTIONS количестве инструкций:
def thread_step_setter(dbg):
dbg.suspend_all_threads()
for thread_id in dbg.enumerate_threads():
print "Single step for thread: 0x%08x" % thread_id
h_thread = dbg.open_thread(thread_id)
dbg.single_step(True, h_thread)
dbg.close_handle(h_thread)
# Resume execution, which will pass control to step handler
dbg.resume_all_threads()
return DBG_CONTINUE
def single_step_handler(dbg):
global total_instructions
if instructions == MAX_INSTRUCTION:
dbg.single_step(False)
return DBG_CONTINUE
else:
# Disassemble the instruction
current_instruction = dbg.disasm(dbg.context,Eip)
print "#%d\t0x%08x : %s" % (total_instructions, dbg.context.Eip, current_instruction)
total_instructions += 1
dbg.single_step(True)
return DBG_CONTINUE
Discloser: я не гарантирую, что приведенный выше код будет работать, если скопировать и вставить. Я напечатал это и не проверял это. Однако, если базовое понимание получено, небольшая синтаксическая ошибка может быть легко исправлена. Я заранее прошу прощения, если у меня есть. В настоящее время у меня нет средств или времени, чтобы проверить это.
Я действительно надеюсь, что это поможет вам.