Как я могу получить адрес точки входа в процесс - PullRequest
6 голосов
/ 01 декабря 2011

Я создаю приостановленный процесс test.exe, например:

CreateProcess(
    TEXT( "C:\\Documents and Settings\\willy\\桌面\\project\\test.exe" ), 
    TEXT( "test.exe" ),
    NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi
);

Как получить точку входа / начальный / главный адрес для процесса test.exe после его создания?

Стоит ли искать информацию в PE-файле или использовать API, например ReadProcessMemory() или VirtualQueryEx()

Ответы [ 2 ]

7 голосов
/ 01 декабря 2011

ОК, я взломал 32-битное решение, которое получает базовый адрес образа из процесса PEB.

Файл EntryPt.c :

#include <windows.h>
#include <tchar.h>
#include <psapi.h>
#include <stdio.h>
#include <stddef.h>

// To ensure correct resolution of symbols, add Psapi.lib to TARGETLIBS
// and compile with -DPSAPI_VERSION=1

NTSTATUS (NTAPI *pNtQueryInformationProcess)(HANDLE, /*enum _PROCESSINFOCLASS*/DWORD, PVOID, ULONG, PULONG) = NULL;

extern PVOID GetPeb(HANDLE ProcessHandle);

// PEB definition comes from winternl.h. This is a 32-bit PEB.
typedef struct _PEB
{
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged;
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2]; // Reserved3[1] points to PEB
/*
  PPEB_LDR_DATA                 Ldr;
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  BYTE                          Reserved4[104];
  PVOID                         Reserved5[52];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved6[128];
  PVOID                         Reserved7[1];
  ULONG                         SessionId;
*/
} PEB, *PPEB;

int main(int argc, TCHAR* argv[])
{
    STARTUPINFO StartupInfo;
    PROCESS_INFORMATION ProcessInfo;

    PPEB pPeb;
    PVOID pImage, pEntry;
    PIMAGE_NT_HEADERS pNtHeaders;
    LONG e_lfanew;
    SIZE_T NumberOfBytesRead;

    pNtQueryInformationProcess = (NTSTATUS(NTAPI*)(HANDLE, /*enum _PROCESSINFOCLASS*/DWORD, PVOID, ULONG, PULONG))
        GetProcAddress(
            GetModuleHandle(TEXT("ntdll.dll")), 
            TEXT("NtQueryInformationProcess"));

    if (pNtQueryInformationProcess == NULL)
    {
        printf("GetProcAddress(ntdll.dll, NtQueryInformationProcess) failed with error 0x%08X\n",
               GetLastError());
        return -1;
    }

    memset(&StartupInfo, 0, sizeof(StartupInfo));
    memset(&ProcessInfo, 0, sizeof(ProcessInfo));

    if (!CreateProcess(
      NULL,
      (argc > 1) ? argv[1] : argv[0],
      NULL,
      NULL,
      FALSE,
      CREATE_SUSPENDED,
      NULL,
      NULL,
      &StartupInfo,
      &ProcessInfo))
    {
        printf("CreateProcess() failed with error 0x%08X\n", GetLastError());
        return -1;
    }

    printf("Current process:\n");
    pPeb = GetPeb(GetCurrentProcess());
    printf("PEB: 0x%08X\n", pPeb);
    pImage = pPeb->Reserved3[1];
    printf("Image base: 0x%08X\n", pImage);
    pNtHeaders = (PIMAGE_NT_HEADERS)((PCHAR)pImage + ((PIMAGE_DOS_HEADER)pImage)->e_lfanew);
    pEntry = (PVOID)((PCHAR)pImage + pNtHeaders->OptionalHeader.AddressOfEntryPoint);
    printf("Image entry point: 0x%08X\n", pEntry);

    printf("\n");

    printf("Child process:\n");
    pPeb = GetPeb(ProcessInfo.hProcess);
    printf("PEB: 0x%08X\n", pPeb);

    if (!ReadProcessMemory(
      ProcessInfo.hProcess,
      &pPeb->Reserved3[1],
      &pImage,
      sizeof(pImage),
      &NumberOfBytesRead) || NumberOfBytesRead != sizeof(pImage))
    {
        printf("ReadProcessMemory(&pImage) failed with error 0x%08X\n", GetLastError());
        goto End;
    }
    printf("Image base: 0x%08X\n", pImage);

    if (!ReadProcessMemory(
      ProcessInfo.hProcess,
      (PCHAR)pImage + offsetof(IMAGE_DOS_HEADER, e_lfanew),
      &e_lfanew,
      sizeof(e_lfanew),
      &NumberOfBytesRead) || NumberOfBytesRead != sizeof(e_lfanew))
    {
        printf("ReadProcessMemory(&e_lfanew) failed with error 0x%08X\n", GetLastError());
        goto End;
    }
    pNtHeaders = (PIMAGE_NT_HEADERS)((PCHAR)pImage + e_lfanew);

    if (!ReadProcessMemory(
      ProcessInfo.hProcess,
      (PCHAR)pNtHeaders + offsetof(IMAGE_NT_HEADERS, OptionalHeader.AddressOfEntryPoint),
      &pEntry,
      sizeof(pEntry),
      &NumberOfBytesRead) || NumberOfBytesRead != sizeof(pEntry))
    {
        printf("ReadProcessMemory(&pEntry) failed with error 0x%08X\n", GetLastError());
        goto End;
    }
    pEntry = (PVOID)((PCHAR)pImage + (SIZE_T)pEntry);
    printf("Image entry point: 0x%08X\n", pEntry);

End:

    TerminateProcess(ProcessInfo.hProcess, 0);
    CloseHandle(ProcessInfo.hThread);
    CloseHandle(ProcessInfo.hProcess);

    return 0;
}

Файл GetPeb.c :

#include <ntddk.h>

extern NTSTATUS (NTAPI *pNtQueryInformationProcess)(
  HANDLE ProcessHandle,
  PROCESSINFOCLASS ProcessInformationClass,
  PVOID ProcessInformation,
  ULONG ProcessInformationLength,
  PULONG ReturnLength);

PVOID GetPeb(HANDLE ProcessHandle)
{
  NTSTATUS status;
  PROCESS_BASIC_INFORMATION pbi;
  PVOID pPeb;

  memset(&pbi, 0, sizeof(pbi));

  status = pNtQueryInformationProcess(
    ProcessHandle,
    ProcessBasicInformation,
    &pbi,
    sizeof(pbi),
    NULL);

  pPeb = NULL;

  if (NT_SUCCESS(status))
  {
    pPeb = pbi.PebBaseAddress;
  }

  return pPeb;
}

Скомпилировано с Open Watcom 1.9 через этот пакетный файл:

set INCLUDE=%INCLUDE%;%WATCOM%\H\NT;%WATCOM%\H\NT\DDK;
wcl386 /we /wx /q /d2 -DPSAPI_VERSION=1 EntryPt.c GetPeb.c %WATCOM%\lib386\nt\psapi.lib

Вывод (работает в Windows XP):

>EntryPt.exe

Current process:
PEB: 0x7FFDD000
Image base: 0x00400000
Image entry point: 0x004013E8

Child process:
PEB: 0x7FFDC000
Image base: 0x00400000
Image entry point: 0x004013E8

>EntryPt.exe calc.exe
Current process:
PEB: 0x7FFDC000
Image base: 0x00400000
Image entry point: 0x004013E8

Child process:
PEB: 0x7FFDB000
Image base: 0x01000000
Image entry point: 0x01012475

Этот код использует NtQueryInformationProcess () , который может измениться в будущих версиях ОС. Он также использует недокументированное определение из PEB . Этот код не будет работать в 64-битной Windows, если не будет изменен соответствующим образом (возможно, с учетом WOW64 ), и он может не работать с будущими версиями Windows.

1 голос
/ 01 декабря 2011

Когда вы выполняете процесс с CREATE_SUSPENDED, он запускается в коде инициализации ntdll.Это бесполезно для поиска точки входа .exe;Вы должны проверить заголовки исполняемого файла непосредственно для этого:

#include <Windows.h>
#include <WinNT.h>

DWORD FindEntryPointAddress(_TCHAR *exeFile)
{
    BY_HANDLE_FILE_INFORMATION bhfi;
    HANDLE hMapping;
    char *lpBase;
    HANDLE hFile = CreateFile(exeFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        fail("Opening exe file", GetLastError());

    if (!GetFileInformationByHandle(hFile, &bhfi))
        fail("GetFileInformationByHandle", GetLastError());

    hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, bhfi.nFileSizeHigh, bhfi.nFileSizeLow, NULL);
    if (!hMapping)
        fail("CreateFileMapping", GetLastError());
    lpBase = (char *)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, bhfi.nFileSizeLow);
    if (!lpBase)
        fail("MapViewOfFile", GetLastError());

    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)lpBase;
    if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
        fail("bad dos header signature", 0);

    PIMAGE_NT_HEADERS32 ntHeader = (PIMAGE_NT_HEADERS32)(lpBase + dosHeader->e_lfanew);
    if (ntHeader->Signature != IMAGE_NT_SIGNATURE)
        fail("bad nt header signature", 0);

    DWORD pEntryPoint = ntHeader->OptionalHeader.ImageBase + ntHeader->OptionalHeader.AddressOfEntryPoint;

    UnmapViewOfFile((LPCVOID)lpBase);
    CloseHandle(hMapping);
    CloseHandle(hFile);

    return pEntryPoint;
}

Обратите внимание, что этот адрес относится к первому коду, который выполняется после завершения инициализации DLL.Он не может быть (и обычно не) равен адресу main или WinMain;обычно это какой-то код запуска библиотеки C, статически связанный с EXE-файлом.

Также обратите внимание, что произойдет сбой, если EXE перемещается и ASLR включен, поскольку EXE-файл может быть загружен по другому базовому адресу.Вам нужно будет найти базовый адрес EXE и использовать его вместо ntHeader->OptionalHeader.ImageBase в этом случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...