Сначала я новичок в c ++ и отлаживаю. Я использую API CreateProcess с параметром DEBUG_ONLY_THIS_PROCESS, затем жду CREATE_PROCESS_DEBUG_EVENT. Когда получено, я проверяю регистр Eip, чтобы получить адрес точки. И я подумал, что этот пункт является адресом главной функции.
Чтобы проверить эту идею, я использовал ollydbg, чтобы увидеть начальный адрес exe. Но это не было с моим. Тот, который я нашел с отладочным apis, это 0x77a364d8, но олли говорит, что это 0x00401000. Тогда я не остановился и проверил адрес 0x77a364d8 в Олли. Я нашел адрес и установил там точку останова.
Затем я перезагрузил olly и увидел, что olly сначала идет по адресу 0x77a364d8 и загружает процесс, а затем переходит по адресу 0x00401000 и ждет там. Адрес 0x77a364d8 указывает на некоторые функции ntdll для загрузки процесса в память, как я вижу.
Если это правда, как я могу получить адрес 0x00401000 по коду (c ++, я новичок и прошу вас пересечь :)), и это адрес основной функции или как?
После того как вы получите CREATE_PROCESS_DEBUG_EVENT
Вы должны иметь доступ к CREATE_PROCESS_DEBUG_INFO
член союза. У него есть член под названием lpStartAddress
,
Ваш цикл событий отладки должен выглядеть примерно так:
DWORD dwContinueDebugStatus = DBG_CONTINUE;
while(dwContinueDebugStatus)
{
DEBUG_EVENT debugEvt;
WaitForDebugEvent(&debugEvt, INFINITE);
switch(debugEvt.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT:
// Grab the main thread entry point.
LPTHREAD_START_ROUTINE exentry = debugEvt.u.CreateProcessInfo.lpStartAddress;
break;
/* Handle the rest of your debug events here. */
}
ContinueDebugEvent(debugEvt.dwProcessId, debugEvt.dwThreadId, dwContinueDebugStatus);
}
Редактировать:
Несколько вещей, которые я забыл упомянуть …
Получение точки входа любым из этих способов, вероятно, будет функцией CRT, которая вызывает ваш main()
, Не существует надежного способа получить main()
без поиска символов в использовании dbghelp.dll
,
Также книга Отладка приложений Джон Роббинс имеет главу о создании небольшого отладчика с примером кода. Вероятно, это лучшая документация / пример, который я нашел (но я бы хотел, чтобы это было лучше). Это может быть довольно дешево, поэтому стоит посмотреть.
Точка входа будет не (по крайней мере, нормально) быть таким же, как main
, Подпись для точки входа void entrypoint(void);
, Для этого нужно извлечь командную строку, разобрать ее на отдельные аргументы и т. Д. При подготовке к вызову main
(и есть совершенно отдельный, который извлекает довольно разные «вещи», необходимые перед вызовом WinMain
в программе с графическим интерфейсом).
Если вы хотите фактический адрес main
вы можете хотя бы попробовать использовать SymFromName
для имен _main
и / или _wmain
(или, если вы имеете дело с программой с графическим интерфейсом, WinMain
/wWinmain
) чтобы получить код, который действительно является частью целевой программы, а не чего-то из библиотечного модуля, который почти никто даже не видел.
Это все из памяти, поэтому может содержать несколько ошибок.
Чтобы найти адрес точки входа EXE в новом процессе, необходимо прочитать поле PEB этого процесса. ImageBaseAddress
, PEB всегда находится по фиксированному адресу, но это зависит от того, является ли ваш EXE-файл 32-битным или 64-битным, что вы должны определить заранее (есть 32-битный PEB для WOW64, но я думаю, что он еще не может быть инициализирован в таком случае).
Обратите внимание, что вы не можете просто извлечь это из EXE, потому что это может быть перемещено из-за ASLR. Как только вы это сделаете, вы можете прочитать PE заголовок EXE, используя ReadProcessMemory
и получить AddressOfEntryPoint
поле из IMAGE_OPTIONAL_HEADER
структура. Это RVA, поэтому добавьте его к найденному ранее базовому адресу, и вуаля, у вас есть адрес точки входа.