||| 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:
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:
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:
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:
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:
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:
#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:
#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)
#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.