Results 1 to 2 of 2
  1. #1
    the-no-name
    the-no-name is offline
    New member
    Join Date
    2010 May
    Posts
    8
    Thanks Thanks Given 
    9
    Thanks Thanks Received 
    1
    Thanked in
    1 Post
    Rep Power
    0

    [C++] Внедрение в чужой процесс

    Внедрение в чужой процесс

    В этой статье я расскажу немного про память процессов, а так же покажу простейший способ внедрения своего кода в работающую программу, например explorer.exe.

    Откроем в отладчике любую программу под Windows и рассмотрим диапазон адресов, в которых она находится. Обычно этот диапазон расположен в адресах 0х0400000 – 0х04ххххх (но, может быть и другим, в частности для системных процессов). Откроем другую программу, она располагается в том же самом диапазоне адресов. У мало знакомого с оперативной памятью человека возникнет логичный вопрос: как возможно, что бы разные программы занимали одни и те же же адреса? Дело вот в чем: для каждой запущенной программы ОС выделяет свое виртуальное адресное пространство, которое начинающееся с адреса 00000000h и заканчивается адресом FFFFFFFFh, размер равен 4 Гб (мы говорим про 32-битные системы). Тут стоит отметить, что 4Гб виртуальной памяти это не тоже что и 4Гб памяти физической. Об этом чуть подробнее:

    Виртуальная память разбита на страницы (размер страницы определяется типом ОС, в нашем случае это 4 кб). При запуске программы эти страницы выделены под сам исполняемый код, данные нашего приложения, стек и т.д. Эти страницы виртуальной памяти уже потом проецируются на физическую память. Подробнее про это лучше почитать у Джеффри Рихтера (у него про работу с памятью есть практически все). Если мы откроем диспетчер задач и посмотрим закладку «процессы», то увидим все процессы, которые запущены в данный момент. Они располагаются в своих виртуальных адресных пространствах (ВАП).

    ВАП каждого процесса (каждой программы) изолировано, т.е. не затрагивает ВАП другого процесса, и управляется оно функциями ядра операционной системы. На деле же при необходимости, память другого процесса можно читать и редактировать. Что нам даст внедрение в процесс (process injection)? В отличии от работы с памятью средствами своей программы, внедренный процесс не будет виден ни в диспетчере задач, ни в любой другой программе. Такое глобальное внедрение позволит осуществить перехват вызовов API функций или, например, внедрение в браузер для обхода файрвола. Суть метода заключается в выделении области памяти строго заданного размера в чужом процессе, копировании туда побайтно кода нашего процесса по тем же адресам и запуске удаленного потока.

    Реализацию можно разбить на составляющие:

    * подбираем программу, в которую будем внедряться
    * выделяем в ее адресном пространстве память для нашего процесса
    * копируем код нашего процесса в выделенную область
    * осуществляем запуск удаленного потока


    Функция для поиска процесса принимает в параметрах строку, в которой содержится название искомого процесса (например explorer.exe) и возвращает его ID (уникальный идентификатор):
    Code:
     DWORD GetProcessID(char* lpNameProcess)
    {
    HANDLE snap;
    PROCESSENTRY32 pentry32;
    snap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    if(snap==INVALID_HANDLE_VALUE) return 0;
    pentry32.dwSize=sizeof(PROCESSENTRY32);
    if(!Process32First(snap,&pentry32)) {CloseHandle(snap);return 0;}
    do
    {
    if(!lstrcmpi(lpNameProcess,&pentry32.szExeFile[0]))
    {
    CloseHandle(snap);
    return pentry32.th32ProcessID;
    }
    }while(Process32Next(snap,&pentry32));
    CloseHandle(snap);
    return 0;
    }
    Далее зарезервируем в чужом пространстве область памяти, необходимую для размещения нашего кода. Сразу возникает вопрос: сколько памяти выделять? Необходимый размер лучше определить программно, как продемонстрировано ниже. В качестве первого параметра наша функция принимает Handle чужого процесса, в качестве второго – указатель на функцию, которая будет запущена в чужом адресном пространстве (точка входа в поток). В переменной size вычисляется размер области памяти (в которую мы будем копировать код). Получив величину size, с помощью функции VirtualAllocEx мы выделяем в адресном пространстве чужого процесса необходимую нам область памяти. Сама операция копирования осуществляется функцией WriteProcessMemory:
    Code:
     BOOL Inject(HANDLE hProc,DWORD(WINAPI* func)(LPVOID))
    {
    DWORD id;
    DWORD ByteOfWriten;
    HMODULE hModule = GetModuleHandle(NULL);
    DWORD size=((PIMAGE_OPTIONAL_HEADER)((LPVOID)((BYTE*)(hModule)+((PIMAGE_DOS_HEADER)(hModule))->e_lfanew+sizeof(DWORD)+sizeof(IMAGE_FILE_HEADER))))->SizeOfImage;
    char* hNewModule = (char*)VirtualAllocEx(hProc,hModule,size, MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
    if(hNewModule==NULL) return false;
    WriteProcessMemory(hProc,hNewModule,hModule,size,&ByteOfWriten);
    if(ByteOfWriten!=size){return false;}
    HANDLE hThread=CreateRemoteThread(hProc,NULL,0,func,(LPVOID)hNewModule,0,&id);
    if(hThread==0) return false;
    return true;
    }
    Надо отметить, что копирование может не удаться, если в пространстве explorer.exe уже содержатся его данные по нашим адресам памяти. Чтобы избежать этого, сдвигаем образ нашего процесса максимально дальше с помощью директивы компилятора:
    Code:
     #pragma comment(linker,"/BASE:0x13140000")
    Далее производим запуск удаленного потока (содержащего нашу функцию) с помощью функции CreateRemoteThread с точки входа func. func — именно та функция, которая будет работать в чужом адресном пространстве. Возьмем простейший вариант с выводом окошка с сообщением, вот полный код:
    Code:
     #include <windows.h>
    #include <tlhelp32.h>
    
    #pragma comment(linker,"/BASE:0x13140000") // сдвигаем базу нашего процесса
    
    // ------- объявляем функции --------
    
    DWORD GetProcessID(char*);
    BOOL Inject(HANDLE,DWORD(WINAPI* func)(LPVOID));
    DWORD WINAPI func(LPVOID);
    
    //-------- главная функция ---------
    
    int WINAPI WinMain(HINSTANCE,HINSTANCE,LPTSTR,int)
    {
    if(!Inject(OpenProcess(PROCESS_ALL_ACCESS,false,GetProcessID("explorer.exe")),&func)) return false;
    return true;
    }
    
    //-------- функция, которая будет выполняться в чужом процессе -------
    
    DWORD WINAPI func(LPVOID)
    {
    LoadLibrary("kernel32.dll");
    LoadLibrary("user32.dll");
    MessageBox(0,"Hello from addres area of explorer","title",0);
    return true;
    }
    
    //-------- поиск процесса ---------
    
    DWORD GetProcessID(char* lpNameProcess) // в параметре - имя процесса для внедрения
    {
    HANDLE snap;
    PROCESSENTRY32 pentry32;
    snap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    if(snap==INVALID_HANDLE_VALUE) return 0;
    pentry32.dwSize=sizeof(PROCESSENTRY32);
    if(!Process32First(snap,&pentry32)) {CloseHandle(snap);return 0;}
    do
    {
    if(!lstrcmpi(lpNameProcess,&pentry32.szExeFile[0]))
    {
    CloseHandle(snap);
    return pentry32.th32ProcessID;
    }
    }
    while(Process32Next(snap,&pentry32));
    CloseHandle(snap);
    return 0;
    }
    
    //-------- функция внедрения в чужой процесс -------------------
    
    BOOL Inject(HANDLE hProc,DWORD(WINAPI* func)(LPVOID))
    {
    DWORD id;
    DWORD ByteOfWriten;
    HMODULE hModule = GetModuleHandle(NULL);
    DWORD size=((PIMAGE_OPTIONAL_HEADER)((LPVOID)((BYTE*)(hModule)+((PIMAGE_DOS_HEADER)(hModule))->e_lfanew+sizeof(DWORD)+sizeof(IMAGE_FILE_HEADER))))->SizeOfImage;
    char* hNewModule = (char*)VirtualAllocEx(hProc,hModule,size,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
    if(hNewModule==NULL) return false;
    WriteProcessMemory(hProc,hNewModule,hModule,size,&ByteOfWriten);
    if(ByteOfWriten!=size){return false;}
    HANDLE hThread=CreateRemoteThread(hProc,NULL,0,func,(LPVOID)hNewModule,0,&id);
    if(hThread==0) return false;
    return true;
    }
    (C) veveve

  2. #2
    ADACH
    ADACH is offline
    Member-in-training ADACH's Avatar
    Join Date
    2010 May
    Posts
    170
    Thanks Thanks Given 
    25
    Thanks Thanks Received 
    168
    Thanked in
    46 Posts
    Rep Power
    14

    Re: [C++] Внедрение в чужой процесс

    Работать будет) Правда не везде и не всегда.
    Явные недостатки метода:
    Не обрабатываются релоки (нет возможности загрузить модуль по произвольному адресу).
    Не правится таблица импорта (в Висте вряд-ли отработает, т-к image base kernel32.dll в каждом процессе разный).

    P.S. Метод оригинальный, но слишком неудобен для использования в game-хаке.
    P.S.S. Когда-то встречал аналогичный метод инжекта в одном из троев.
    Шлите мыло зухелем

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •