Author Topic: Injecting code in another process  (Read 3264 times)

0 Members and 1 Guest are viewing this topic.

Offline ca0s

  • VIP
  • Sir
  • *
  • Posts: 432
  • Cookies: 53
    • View Profile
    • ka0labs #
Injecting code in another process
« on: January 21, 2011, 07:20:08 pm »
|||   Inyecting code into another process   |||
|||                      by ca0s                          |||

|| 0x01 - Intro
|| 0x02 - Required APIs
|| 0x03 - Inyecting with DLL
|| 0x04 - Inyecting without DLL
|| 0x05 - Links
|| 0x06 - Bye

----
0x01
----
Hia.
I am going to write a small tutorial about how to inyect own code in a running process. I will explain two methods: with a DLL and without DLL.

----
0x02
----
First of all, we need some Windows APIs:

OpenProcess:
Code: [Select]
HANDLE WINAPI OpenProcess(
  __in  DWORD dwDesiredAccess,
  __in  BOOL bInheritHandle,
  __in  DWORD dwProcessId
);
Opens a process given its PID with desider access privileges, and returns a handle to it. Return when failure: NULL.

VirtualAllocEx:
Code: [Select]
LPVOID WINAPI VirtualAllocEx(
  __in      HANDLE hProcess,
  __in_opt  LPVOID lpAddress,
  __in      SIZE_T dwSize,
  __in      DWORD flAllocationType,
  __in      DWORD flProtect
);
It reserves memory in the desired process' memory, starting in lpAddress (if NULL, OS selects an empty place), of size dwSize, with the desired page protection (we will use onli PAGE_EXECUTE_READWRITE). Return when failure: NULL.

WriteProcessMemory:
Code: [Select]
BOOL WINAPI WriteProcessMemory(
  __in   HANDLE hProcess,
  __in   LPVOID lpBaseAddress,
  __in   LPCVOID lpBuffer,
  __in   SIZE_T nSize,
  __out  SIZE_T *lpNumberOfBytesWritten
);
Writes in the given address lpBaseAddress of hProcess opened process the data pointed by lpBuffer, number of bytes given in nSize. Return when failure: FALSE. It puts number of bytes written in lpNumberOfBytesWritten.

CreateRemoteThread:
Code: [Select]
HANDLE WINAPI CreateRemoteThread(
  __in   HANDLE hProcess,
  __in   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in   SIZE_T dwStackSize,
  __in   LPTHREAD_START_ROUTINE lpStartAddress,
  __in   LPVOID lpParameter,
  __in   DWORD dwCreationFlags,
  __out  LPDWORD lpThreadId
);
Starts a thread in the given process, giving the thread's start address in lpStartAddress and parameters in lpParameter.

Also, we will use Tlhelp32.h to determine the process PID giving the process name:
Code: [Select]
    HANDLE processList=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pInfo;
    BOOL st=TRUE;
    pInfo.dwSize=sizeof(PROCESSENTRY32);
    Process32First(processList, &pInfo);
    int myPid=0;
    do
    {
        if(strcmp(pInfo.szExeFile, "test.exe")==0)
        {
            myPid=pInfo.th32ProcessID;
            break;
        }
        Process32Next(lista, &pInfo);
    }
    while(st!=FALSE);
I wont explain this in detail becouse it is appart of the topic. See MSDN.

----
0x04
----
First we need a DLL to load in the desired process. An example one would be something like this:
Code: [Select]
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
BOOL APIENTRY DllMain (HINSTANCE hInst     /* Library instance handle. */ ,
                       DWORD reason        /* Reason this function is being called. */ ,
                       LPVOID reserved     /* Not used. */ )
{
    switch (reason)
    {
      case DLL_PROCESS_ATTACH:
        MessageBoxA(NULL, "Hi!", "Hey!", 0);
        break;
    }
    return TRUE;
}

Then we have to make a process load this DLL. For that, we will do the following:
- Open the process, reserve some memory and write there the name of the DLL.
- Get address of LoadLibrary API. As it is in Kernel32.dll and that should be loaded in every windows process, and windows processes load winAPI in the same directions, we can use its address in our inyector in the inyected process.
- Create remote thread in the process, giving LoadLibrary's direction as start address and our previously reserved and written string containing our DLL's name as argument.

That would be done like this:
Code: [Select]
#include <stdio.h>
#include <windows.h>
#include <Tlhelp32.h>

void error(char *err);

HANDLE myProc=NULL;

int main(int argc, char *argv[])
{

    HANDLE processList=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pInfo;
    BOOL st=TRUE;
    pInfo.dwSize=sizeof(PROCESSENTRY32);
    Process32First(processList, &pInfo);
    int myPid=0;
    do
    {
        if(strcmp(pInfo.szExeFile, "test.exe")==0)
        {
            myPid=pInfo.th32ProcessID;
            break;
        }
        Process32Next(processList, &pInfo);
    }
    while(st!=FALSE);

    // Open process
    printf("[+] Opening process %i\n", myPid);
    myProc=OpenProcess(PROCESS_ALL_ACCESS, FALSE, myPid);
    if(myProc==NULL) error("[-] Error opening process.\n");
    else printf("[+] Process opened.\n");
   
    // Reserve memory for argument (our DLL's name)
    char thData[]="dll.dll";
    LPVOID dirToArg=VirtualAllocEx(myProc, NULL, strlen(thData), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if(dirToArg==NULL) error("[-] Error allocating arg memory.\n");
    else printf("[+] Arg memory reserved (%i bytes).\n", strlen(thData)); 
    // Write dll's name in reserved memory
    SIZE_T written=0;
    if(WriteProcessMemory(myProc, dirToArg, (LPVOID)&thData, strlen(thData), &written)==0) error("[-] Error writing memory.\n");
    else printf("[+] Memory successfuly written (arg %i bytes).\n", written);
   
    // Create thread in LoadLibrary()'s address
    HANDLE rThread=CreateRemoteThread(myProc, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(LoadLibrary("Kernel32.dll"), "LoadLibraryA"), dirToArg, 0, NULL);
    if(rThread==NULL) error("[-] Error creating remote thread.\n");
    else printf("[+] Remote thread created.\n");
   
    CloseHandle(myProc);
}

void error(char *err)
{
     if(myProc!=NULL) CloseHandle(myProc);
     printf("%s", err);
     exit(0);
}
Note that the DLL must be in a folder the inyected process is supposed to look for in it.

----
0x04
----
This is a little bit more difficult than inyecting a DLL. Main differences are:
- Now you can not use text strings as arguments to function directly. We will see about this later.
- Now you can not call to any function that you don't load run-time with LoadLibrary and GetProcAddress. Those are in Kernel32 and are loaded in every program in the same directions, so a pointer to them in our inyector will work in the inyected process.
- You have to write the whole function's code in the inyected process' memory.
- You will need to give more data as argument to the thread. We'll see.

The process is like that:
- Create a struct including every single one text string you will need in the thread, and a pointer to LoadLibrary and GetProcAddress.
- Open the process.
- Reserve memory for the argument structure. Write it.
- Reserve memory for our function. Write it.
- Launch the remote thread, giving our written code address as start point and our written arg structure address as argument.

The code would be like this: (it inyects a function with a MessageBoxA, which is included in User32.dll)
Code: [Select]
#include <stdio.h>
#include <windows.h>
#include <Tlhelp32.h>

void error(char *err);
static DWORD WINAPI myFunc(LPVOID data);

HANDLE myProc=NULL;

// This two let us load function pointers in our argument structure
typedef int (WINAPI *datLoadLibrary)(LPCTSTR);
typedef int (WINAPI *datGetProcAddress)(HMODULE, LPCSTR);

int main(int argc, char *argv[])
{
    if(argc<2) error("Usage: hook.exe PROCESO\n");
    // This is our argument structure.
    struct {
       char lnUser32[50];                                 // Will contain "User32.dll"
       char fnMessageBoxA[50];                      // Will contain "MessageBoxA"
       datLoadLibrary apiLoadLibrary;               // Pointer to API LoadLibrary
       datGetProcAddress apiGetProcAddress;  // Pointer to API GetProcAddress
       char Msg[50];                                       // Some text we'll use in MessageBoxA
       } thData;
    strcpy(thData.lnUser32, "User32.dll");
    strcpy(thData.fnMessageBoxA, "MessageBoxA");
    strcpy(thData.Msg, "Hola!");
    thData.apiLoadLibrary=GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
    thData.apiGetProcAddress=GetProcAddress(GetModuleHandle("kernel32.dll"), "GetProcAddress");
   
    int funcSize=600; // Our function size. Could be calculated, but this works for the example.

    HANDLE processList=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pInfo;
    BOOL st=TRUE;
    pInfo.dwSize=sizeof(PROCESSENTRY32);
    Process32First(processList, &pInfo);
    int myPid=0;
    do
    {
        if(strcmp(pInfo.szExeFile, argv[1])==0)
        {
            myPid=pInfo.th32ProcessID;
            break;
        }
        Process32Next(processList, &pInfo);
    }
    while(st!=FALSE);
   
    // Open process
    printf("[+] Opening process %i\n", myPid);
    myProc=OpenProcess(PROCESS_ALL_ACCESS, FALSE, myPid);
    if(myProc==NULL) error("[-] Error opening process.\n");
    else printf("[+] Process opened.\n");
   
    // Reserve memory for argument
    LPVOID dirToArg=VirtualAllocEx(myProc, NULL, sizeof(thData), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if(dirToArg==NULL) error("[-] Error allocating arg memory.\n");
    else printf("[+] Arg memory reserved (%i bytes).\n", sizeof(thData)); 
    // Write arguments
    SIZE_T written=0;
    if(WriteProcessMemory(myProc, dirToArg, (LPVOID)&thData, sizeof(thData), &written)==0) error("[-] Error writting args memory.\n");
    else printf("[+] Memory written (arg %i bytes).\n", written);
     
    // Reserve memory for our function
    LPVOID dirToWrite=VirtualAllocEx(myProc, NULL, funcSize, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if(dirToWrite==NULL) error("[-] Error reserving memory for code.\n");
    else printf("[+] Memory reserved for code (%i bytes).\n", funcSize);   
    // Write our function's code
    if(WriteProcessMemory(myProc, dirToWrite, (LPVOID)myFunc, funcSize, &written) == 0) error("[-] Error writing memory.\n");
    else printf("[+] Memoria written (code).\n");
   
    // Launch thread to our code
    HANDLE rThread=CreateRemoteThread(myProc, NULL, 0, (LPTHREAD_START_ROUTINE)dirToWrite, dirToArg, 0, NULL);
    if(rThread==NULL) error("[-] Error launching thread.\n");
    else printf("[+] Thread launched.\n");
    CloseHandle(myProc);
   
    return 0;
}
   
void error(char *err)
{
     if(myProc!=NULL) CloseHandle(myProc);
     printf("%s", err);
     exit(0);
}

static DWORD WINAPI myFunc(LPVOID data)
{
    // We load our data in this structure
     struct {
         char lnUser32[50];
         char fnMessageBoxA[50];
         datLoadLibrary apiLoadLibrary;
         datGetProcAddress apiGetProcAddress;
         char MSG[50];
     } *thData;
     thData=data;
     // I can get any API with this two, being its name in thData structure
     void *apiDir=(void *)thData->apiGetProcAddress((HANDLE)thData->apiLoadLibrary(thData->lnUser32), thData->fnMessageBoxA);
     // This is a function pointer with prototype similar to MessageBoxA
     INT WINAPI (*myMessageBox)(HWND, LPCSTR, LPCSTR, UINT);
     myMessageBox=apiDir;
     myMessageBox(NULL, thData->MSG, thData->MSG, 0);
     return;
}     

----
0x05
----
MSDN - http://msdn.microsoft.com/en-us/library \\ I learnt everything about this here
foro.elhacker.net \\ Well, not everything. Nice coders here (spanish)

----
0x06
----
I think everything is commented and explained. If not, reply and I will try to explain it better. Hope this is helpful to someone.
Bytez.
« Last Edit: February 22, 2011, 11:14:11 am by ande »

Offline xassiz

  • /dev/null
  • *
  • Posts: 11
  • Cookies: 1
  • xassiz@ka0-labs #
    • View Profile
Re: Inyecting code in another process
« Reply #1 on: January 22, 2011, 12:17:20 am »
The best I've read bro ;D

Congratulations ca0s!

Offline r00t

  • Serf
  • *
  • Posts: 43
  • Cookies: -4
  • i'm not a hacker
    • View Profile
Re: Injecting code in another process
« Reply #2 on: March 25, 2011, 10:12:28 am »
nice bro. keep sharing.
« Last Edit: March 25, 2011, 10:15:51 am by r00t »
' if you want To catch a thief you must think like a thief '