Embed your code in the process address space

    Intro


    Embedding your code (dynamically) in other people's processes is quite an interesting thing. This can serve both for good and for evil. Although, the concept of “evil”, in places, is very abstract in the information world, I can’t draw an exact line between what is “bad” and what is “good”, especially if it concerns the implementation of the code ...

    In this article we will create its injector dll. What is it, I think, everyone knows. This method of implementing third-party code is quite popular and convenient.

    We will write DLL Injector in C ++ in the Microsoft Visual Studio 2010 environment. To create a dynamically connected library, you can use any tool that you like. I chose CodeGear RAD Studio 2009, the Delphi language (Object Pascal) to create the library.

    How does DLL Injection work?

    The working scheme of this method is simple:
    1) search and obtain the descriptor of the desired process
    2) allocation of memory in the process and subsequent record of the path in the DLL at the address where the allocation of memory took place
    3) creation of a new thread in the virtual space of the process whose descriptor was received.




    Let's start by creating the DLL.

    As I already said, the Delphi language will be used for this purpose:



    Now let's add some resources to the DLL, namely the form and buttons for control:



    The DLL itself consists of only a few lines of code that will display the created form. You can also delete all comments for a more convenient visual perception of the code:



    Now we program the interface of the DLL form. There are two buttons on the form. The first will “kill” the parent process (that is, the process in which the thread was created in the virtual space, in which, in turn, the DLL code is executed). The second is to draw 10 squares 25x25px in the context of all application windows belonging to the process:

    procedure TForm1.Button1Click(Sender: TObject);
    var _curr_process:DWORD;
        p_handle: THANDLE;
    begin
    // Убиваем родительский процесс
    _curr_process:=GetCurrentProcessId();
    p_handle:=OpenProcess(PROCESS_ALL_ACCESS,false,_curr_process);
    TerminateProcess(p_handle,4);
    end;
    var dw:DWORD;  // PID текущего процесса
    procedure drawGroup(h:HWND);
    var canvas:TBitMap;
    rect:TRect;
    x,y:integer;
    i: Integer;
    begin
    // рисуем 10 квадратов
    for i := 1 to 10 do
    begin
    canvas:=TBitMap.Create();
    canvas.Canvas.Handle:=GetDC(h);  // устанавливаем дескриптор контекста
    randomize;
    canvas.Canvas.Brush.Color:=rgb(random(255),random(255),random(255));
    GetWindowRect(h,rect);
    x:=random(rect.Right-rect.Left-25);
    y:=random(rect.Bottom-rect.Top-25);
    canvas.Canvas.Rectangle(x,y,x+25,y+25);
    end;
    end;
    function func(h:HWND):BOOL;  stdcall;
    var pid:DWORD;
    begin
    GetWindowThreadProcessId(h,pid);
    // запускаем функцию рисования в окне, если оно принадлежит нужному процессу:
    if(pid=dw) then drawGroup(h);
    result:=true;
    end;
    procedure TForm1.Button2Click(Sender: TObject);
    begin
    // Запускаем функцию рисования квадратов
    // ( в перечислителе окон системы )
    dw:=GetCurrentProcessId();
    EnumWindows(@func,0);    // перечисляем окна
    end;
    


    The source code of the interface can be found here .

    Everything is quite simple here.
    So, the dynamic library is written. Now we compile it and at the output we get a compiled file with the extension ".dll", which can be renamed for convenience. I will rename the library to "inj.dll".

    DLL creation is complete.
    It remains only to copy our DLL to the Windows system directory so that any application can find it only by one name.

    We proceed to the development of the injector. Go to Visual Studio and create an Empty project (File-> New-> Project-> Visual C ++ -> General-> Empty Project). All development will be done on a clean WinApi.

    First of all, we will create the simplest visual interface: a form, a button and a text field. It will look something like this:



    As you can see, this application has a minimal design and a simple interface. It contains two text fields designed to enter the name of the process (or its specific part) into which the DLL is to be injected and to enter the name of the DLL itself. The button, accordingly, starts the injection process.

    To inject a DLL into the process address space, you need the following WinApi functions:

    To search for the desired process:
    CreateToolHelp32SnapShot
    Process32First
    Process32Next

    For the injection:

    OpenProcess
    GetProcAddress
    VirtualAllocEx
    WriteProcessMemory
    CreateRemoteThread

    So, we’ll consider how to actually organize a “smart” application architecture that would be clear and simple.
    I suggest starting with handling the click of a button :)

    MSG msg;
        while (GetMessage(&msg,NULL,0,0))
    	{
    		// Button Click
    		if(msg.hwnd==button && msg.message==WM_LBUTTONUP) 
    		{
    			// Getting Process Name
    			GetWindowText(edit_proc,buff,sizeof(buff));
    			strncpy(_p_name,buff,BUFF);
    			// Getting DLL Name
    			ZeroMemory(buff,sizeof(buff));
    			GetWindowText(edit_dll,buff,BUFF);
    			strncpy(_dll_name,buff,BUFF);
    			// Start Injection
    			StartInjection();
    		}
    


    Ok, then go to the implementation of the function
    StartInjection ();
    , which serves to search for a process by its name:

    int StartInjection()
    {
    	// Searching of Process
    	PROCESSENTRY32 pe;
    	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    	if(snapshot==INVALID_HANDLE_VALUE) 
    	{
    		ShowMessage("SnapShot Failed.");
    		return 0;
    	}
    	pe.dwSize = sizeof(PROCESSENTRY32);
    	int curr = Process32First(snapshot,&pe);
    	while(curr)
    	{		
    		CharLowerBuff(pe.szExeFile,lstrlen(pe.szExeFile));
    		if(strstr(pe.szExeFile,_p_name)) {pid = pe.th32ProcessID; break;}
    	    curr = Process32Next(snapshot,&pe);
    	}
    	if(pid==NULL) 
    	{
    		ShowMessage("Searching of process failed.");
    		return 0;
    	}
    	bool result = Inject();
    	if(result==false) 
    	{
    		ShowMessage("Injection failed.");
    		return 0;
    	}
    }
    


    And finally, the function that completes the injection process
    Inject ()
    :

    // Injection
    bool Inject()
    {
    	if(pid==NULL) return false;
    	// Получение дескриптора процесса
    	HANDLE process = OpenProcess(PROCESS_ALL_ACCESS,false,pid);
    	if(process==NULL) return false;
    	// "Вытягивание" функции из системной библиотеки для динамической  
    	// подгрузки DLL в адресное пространство открытого процесса
    	LPVOID fp = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"),"LoadLibraryA");
    	if(fp==NULL) return false;
    	// Выделение участка памяти размером strlen(_dll_name) для последующей 
    	// записи имени библеотеки в память процесса.
    	LPVOID alloc = (LPVOID)VirtualAllocEx(process,0,strlen(_dll_name), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    	if(alloc==NULL) return false;
    	// Запись имени инжектируемой DLL в память
    	BOOL w = WriteProcessMemory(process,(LPVOID)alloc,_dll_name,strlen(_dll_name),0);
    	if(w==NULL) return false;
    	// Создание "удаленного" потока в адресном пространстве
    	// открытого процесса и последующая подгрузка нашей DLL.
    	HANDLE thread = CreateRemoteThread(process,0,0,(LPTHREAD_START_ROUTINE)fp,(LPVOID)alloc,0,0);
    	if(thread==NULL) return false;
    	CloseHandle(process);
    	return true;
    }
    


    The full injector code can be found here .

    Testing injector performance:



    First we inject ourselves into ourselves. When you click on the "Draw" button, 10 squares are drawn. By clicking on “Crash it!” immediate completion of the "parent" process. Now let's try to inject ourselves into something more serious, for example, the Mozilla Firefox browser. To do this, change only the process name in the first text field and click on the button:



    As you can see, the injection was successful. Squares are drawn in all windows that belong to the parent process of the browser. By clicking on the “Crash it!” Button Mozilla FireFox closes immediately.

    Outro


    Why do we need this at all? After all, our main goal is hacking (games, software). So in the future we will probably use this injector to inject our code into someone else's address space. Thanks to this, you can save a lot of time, effort and nerves :)

    Good luck!

    Also popular now: