Wednesday, July 22, 2009

Virtual memory and paging

Windows Internals: Injecting Code using CreateRemoteThread.

Windows Internals: Injecting Code using CreateRemoteThread.

DLL Injection

This is my old tutorial on dll injection...people have been asking about this topic a bit recently, so...here it is:

Dll Injection Tutorial
by Darawk


Introduction

The CreateRemoteThread method
The SetWindowsHookEx method
The code cave method
Appendix A - Methods of obtaining a process ID
Appendix B - Methods of obtaining a thread ID
Appendix C - Complete CreateRemoteThread example source code
Appendix D - Complete SetWindowsHookEx example source code
Appendix E - Complete code cave example source code


Introduction


In this tutorial i'll try to cover all of the known methods(or at least, those that I know =p) of injecting dll's into a process.
Dll injection is incredibly useful for TONS of stuff(game hacking, function hooking, code patching, keygenning, unpacking, etc..).
Though there are scattered tutorials on these techniques available throughout the web, I have yet to see any complete tutorials detailing
all of them(there may even be more out there than I have here, of course), and comparing their respective strength's and weakness's.
This is precisely what i'll attempt to do for you in this paper. You are free to reproduce or copy this paper, so long as proper
credit is given and you don't modify it without speaking to me first.


The CreateRemoteThread method


I've used this in tons of stuff, and I only recently realized that a lot of people have never seen it, or know how to do it.
I can't take credit for thinking it up...I got it from an article on codeproject, but it's a neat trick that I think more
people should know how to use.

The trick is simple, and elegant. The windows API provides us with a function called CreateRemoteThread(). This allows you
to start a thread in another process. For our purposes, i'll assume you know how threading works, and how to use functions like
CreateThread(if not, you can go here ). The main disadvantage of this method is that it will work only on windows NT and above.
To prevent it from crashing, you should use this function to check to make sure you're on an NT-based system(thanks to CatID for
pointing this out):

Code:

bool IsWindowsNT()
{
// check current version of Windows
DWORD version = GetVersion();
// parse return
DWORD majorVersion = (DWORD)(LOBYTE(LOWORD(version)));
DWORD minorVersion = (DWORD)(HIBYTE(LOWORD(version)));
return (version < 0x80000000);
}



The MSDN definition for CreateRemoteThread is as follows:

Code:

HANDLE CreateRemoteThread( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags,
LPDWORD lpThreadId );


So, it's essentially CreateThread, with an hProcess argument, so that we can tell it in which process to create the new thread.
Now, normally we would want to start the thread executing on some internal function of the process that we are interacting with.
However, to inject a dll, we have to do something a little bit different.

Code:

BOOL InjectDLL(DWORD ProcessID)
{
HANDLE Proc;
char buf[50]={0};
LPVOID RemoteString, LoadLibAddy;

if(!ProcessID)
return false;

Proc = OpenProcess(CREATE_THREAD_ACCESS, FALSE, ProcessID);

if(!Proc)
{
sprintf(buf, "OpenProcess() failed: %d", GetLastError());
MessageBox(NULL, buf, "Loader", NULL);
return false;
}

LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");

RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(Proc, (LPVOID)RemoteString, DLL_NAME,strlen(DLL_NAME), NULL);
CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);

CloseHandle(Proc);

return true;
}


This code, calls CreateRemoteThread() with a lpStartAddress of LoadLibrary(). So, it starts a new thread in the remote process
and executes the LoadLibrary() function. Luckily for us, this function takes only one argument, the name of the dll to load. We can
pass this in the arg field of CreateRemoteThread(). However, there is a minor dilemma. Since this thread will not be executing in
our address space, it won't be able to refer to strings(such as the name of the dll) that are in our address space. So, before calling
CreateRemoteThread(), we have to allocate space in the other process, using VirtualAllocEx(), and write our string there. Finally,
we pass the pointer to the string inside the remote process in the single arg field of CreateRemoteThread(), and voila...Our dll is
now loaded and running smoothly within the remote process. This is the generic loader program I use whenever I need to load a dll.




The SetWindowsHookEx method


The SetWindowsHookEx method is a little bit more intrusive than the first, and creates more of a commotion in the injected
process, which we normally don't want. However, it is a little bit easier to use than the first, and does have it's own advantages
(like being able to inject into every process on the system in one shot). The SetWindowsHookEx() function is designed to allow you
to "hook" windows messages for a given thread. This requires that you inject a dll into that process's address space, so
SetWindowsHookEx() handles all that for us. The dll must have a function for the hook that it created though, otherwise it will
crash.

Code:

HHOOK SetWindowsHookEx(

int idHook,
HOOKPROC lpfn,
HINSTANCE hMod,
DWORD dwThreadId
);


idHook is just that, the ID of the message that we want to hook. There are many of them(for a complete list, go
here ), however we'll want to use one that's as unintrusive as possible, and has the least likelihood of causing alarm bells to
go off in any AV software(SetWindowsHookEx is the staple of all ring3 keyloggers). The WH_CBT message seems innocuous enough.


Quote:

WH_CBT
Installs a hook procedure that receives notifications useful to a computer-based training (CBT) application. For more information,
see the CBTProc hook procedure.

--MSDN


So, we'll need to create a placebo CBT hook proc in our dll, so that when the hook is called, we can handle it properly.

Code:

LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
return CallNextHookEx(0, nCode, wParam, lParam);
};


All we're doing is calling the next hook in the chain of hooks that exist for this message. Getting back to the SetWindowsHookEx()
function, the next parameter we see is lpfn. lpfn is exactly as it sounds "long pointer to function". That's a pointer to our CBT
hook proc function. So, to get this, we'll have to either hardcode the address, or load the dll first ourselves. Hardcoding anything
is a bad idea, so we'll load the dll using LoadLibrary(), and use GetProcAddress() to get the address of our function.

Code:

HMODULE hDll;
unsigned long cbtProcAddr;

hDll = LoadLibrary("injected.dll");
cbtProcAddr = GetProcAddress(hDll, "CBTProc");


Now, in cbtProcAddr we have the address of our function. Parameter 3, of SetWindowsHookEx() is a handle to our dll, we've
already obtained this in the process of getting the address of CBTProc(hDll is a handle to our dll, returned by LoadLibrary). Now,
there is only one parameter left in the SetWindowsHookEx() function, the dwThreadId parameter. If you want to inject your dll into
every process on the system(useful for global function hooks, keyloggers, trojans, rootkits, etc..) you can simply specify 0 for
this parameter. If you want to target a specific process, you'll need to get the ID of one of it's threads. There are many ways
of doing this, and i'll try to enumerate as many as I can think of in Appendix B. So,
to put it all together into one neat little function:


Code:

BOOL InjectDll(char *dllName)
{
HMODULE hDll;
unsigned long cbtProcAddr;

hDll = LoadLibrary(dllName);
cbtProcAddr = GetProcAddress(hDll, "CBTProc");

SetWindowsHookEx(WH_CBT, cbtProcAddr, hDll, GetTargetThreadIdFromWindow("targetApp"));

return TRUE;
}



The code cave method

Instead of exploiting a windows API function to force the process to load our Dll, this time we'll allocate a little chunk
memory inside the target application, and inject a little stub that loads our dll. The advantage of this approach is that it
will work on any version of windows, and it's also the least detectable of any of the methods mentioned thus far. Our stub will
look like this:

Code:

__declspec(naked) loadDll(void)
{
_asm{
// Placeholder for the return address
push 0xDEADBEEF

// Save the flags and registers
pushfd
pushad

// Placeholder for the string address and LoadLibrary
push 0xDEADBEEF
mov eax, 0xDEADBEEF

// Call LoadLibrary with the string parameter
call eax

// Restore the registers and flags
popad
popfd

// Return control to the hijacked thread
ret
}
}


0xDEADBEEF is just there to mark addresses that we can't know beforehand, and have to patch-in at runtime. Ok, let's make a list
of the things that we need to do to make this work:


    - Allocate space for the stub
    - Allocate space for the name of the dll
    - Suspend the main thread of our target
    - Get the address of the next instruction to be executed(need this for the next step)
    - Patch the proper address to return to in the stub
    - Patch the address of the dll name
    - Patch the address of LoadLibrary
    - Set the address of the next instruction to be executed in our target's thread, to the address of the beginning of our stub
    - Resume the target's thread



To allocate space inside the target, we'll use VirtualAllocEx(). We'll need to open a handle to the process
with the VM_OPERATION privelege specified, in order to do this. For our dllName string, we'll only need read and write priveleges.
For the stub however, we'll need read, write, and execute priveleges. Then we'll write in our dllName string, so that we can reference
it from the stub once it's inserted.

Code:

void *dllString, *stub;
unsigned long wowID;
HANDLE hProcess

//See Appendix A for
//this function
wowID = GetTargetProcessIdFromProcname(PROC_NAME);

hProcess = OpenProcess((PROCESS_VM_WRITE | PROCESS_VM_OPERATION), false, wowID);

dllString = VirtualAllocEx(hProcess, NULL, (strlen(DLL_NAME) + 1), MEM_COMMIT, PAGE_READWRITE);
stub = VirtualAllocEx(hProcess, NULL, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, dllString, DLL_NAME, strlen(DLL_NAME), NULL);


To accomplish our next few tasks, we'll need a handle to one of our target's threads. We can use the functions from Appendix B

to get the ID of one such thread, and then use the OpenThread API to get a handle. We'll need to be able to get and set context, and
also suspend and resume the thread.

Code:

unsigned long threadID;
HANDLE hThread;

threadID = GetTargetThreadIdFromProcname(PROC_NAME);
hThread = OpenThread((THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME), false, threadID);


Now, we need to pause the thread in order to get it's "context". The context of a thread is the current state of all of it's
registers, as well as other peripheral information. However, we're mostly concerned with the EIP register, which points to the
next instruction to be executed. So, if we don't suspend the thread before retrieving its context information, it'll continue
executing and by the time we get the information, it'll be invalid. Once we've paused the thread, we'll retrieve it's context
information using the GetThreadContext() function. We'll grab the value
of the current next instruction to be executed, so that we know where our stub should return to. Then it's just a matter of
patching up the stub to have all of the proper pointers, and forcing the thread to execute it:

Code:

SuspendThread(hThread);

ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(hThread, &ctx);
oldIP = ctx.Eip;

//Set the EIP of the context to the address of our stub
ctx.Eip = (DWORD)stub;
ctx.ContextFlags = CONTEXT_CONTROL;

//Right now loadDll is code, which isn't writable. We need
//to change that.
VirtualProtect(loadDll, stubLen, PAGE_EXECUTE_READWRITE, &oldprot);

//Patch the first push instruction
memcpy((void *)((unsigned long)loadDll + 1), &oldIP, 4);
//Patch the 2nd push instruction
memcpy((void *)((unsigned long)loadDll + 8), &dllString, 4);
//Patch the mov eax, 0xDEADBEEF to mov eax, LoadLibrary
memcpy((void *)((unsigned long)loadDll + 13), &loadLibAddy, 4);

WriteProcessMemory(hProcess, stub, loadDll, stubLen, NULL); //Write the stub into the target
//Set the new context of the target's thread
SetThreadContext(hThread, &ctx);
//Let the target thread continue execution, starting at our stub
ResumeThread(hThread);



All that's left now, is to cleanup the evidence. Before we do that though, we should pause the injector for a bit, to be sure
that the target has time to execute our stub(don't want any nasty race conditions). We'll use Sleep() to pause for 8 seconds before
unmapping the memory that we allocated, and exiting the injector.

Code:

Sleep(8000);
VirtualFreeEx(hProcess, dllString, strlen(DLL_NAME), MEM_DECOMMIT);
VirtualFreeEx(hProcess, stub, stubLen, MEM_DECOMMIT);
CloseHandle(hProcess);
CloseHandle(hThread);


This method should work on any version of windows, and should be the least likely to trigger any A/V alarms or cause the program
to malfunction. If you can understand it and implement it properly, this is definitely the best of the three methods.




Appendix A - Methods of obtaining a process ID

If the process you're targeting has a window, you can use the FindWindow function, in conjunction with GetWindowThreadProcessId,
as shown here:


Code:

unsigned long GetTargetProcessIdFromWindow(char *className, char *windowName)
{
unsigned long procID;
HWND targetWnd;

targetWnd = FindWindow(className, windowName);
GetWindowThreadProcessId(targetWnd, &procId);

return procID;
}


If you only know the name of the executable file or it just doesn't have a window:

Code:

unsigned long GetTargetProcessIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot;
BOOL retval, ProcFound = false;

thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}

pe.dwSize = sizeof(PROCESSENTRY32);

retval = Process32First(thSnapshot, &pe);

while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}

retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}

return pe.th32ProcessID;
}




Appendix B - Methods of obtaining a thread ID

If the process you're targeting has a window, you can use the FindWindow function, in conjunction with GetWindowThreadProcessId
and the toolhelp API, as shown here:


Code:

unsigned long GetTargetThreadIdFromWindow(char *className, char *windowName)
{
HWND targetWnd;
HANDLE hProcess
unsigned long processId, pTID, threadID;

targetWnd = FindWindow(className, windowName);
GetWindowThreadProcessId(targetWnd, &processId);


_asm {
mov eax, fs:[0x18]
add eax, 36
mov [pTID], eax
}

hProcess = OpenProcess(PROCESS_VM_READ, false, processID);
ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL);
CloseHandle(hProcess);

return threadID;
}


If you only know the name of the executable of your target, then you can use this code to locate it:

Code:

unsigned long GetTargetThreadIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot, hProcess;
BOOL retval, ProcFound = false;
unsigned long pTID, threadID;

thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}

pe.dwSize = sizeof(PROCESSENTRY32);

retval = Process32First(thSnapshot, &pe);

while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}

retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}

CloseHandle(thSnapshot);

_asm {
mov eax, fs:[0x18]
add eax, 36
mov [pTID], eax
}

hProcess = OpenProcess(PROCESS_VM_READ, false, pe.th32ProcessID);
ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL);
CloseHandle(hProcess);

return threadID;
}



Appendix C - CreateRemoteThread complete example source code

Code:

#include
#include
#include
#include

#define PROCESS_NAME "target.exe"
#define DLL_NAME "injected.dll"


//I could just use PROCESS_ALL_ACCESS but it's always best to use the absolute bare minimum of priveleges, so that your code works in as
//many circumstances as possible.
#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)

BOOL WriteProcessBYTES(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize);

BOOL LoadDll(char *procName, char *dllName);
BOOL InjectDLL(DWORD ProcessID, char *dllName);
unsigned long GetTargetProcessIdFromProcname(char *procName);

bool IsWindowsNT()
{
// check current version of Windows
DWORD version = GetVersion();
// parse return
DWORD majorVersion = (DWORD)(LOBYTE(LOWORD(version)));
DWORD minorVersion = (DWORD)(HIBYTE(LOWORD(version)));
return (version < 0x80000000);
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
if(IsWindowsNT())
LoadDll(PROCESS_NAME, DLL_NAME);
else
MessageBox(0, "Your system does not support this method", "Error!", 0);

return 0;
}


BOOL LoadDll(char *procName, char *dllName)
{
DWORD ProcID = 0;

ProcID = GetProcID(procName);

if(!(InjectDLL(ProcID, dllName)))
MessageBox(NULL, "Process located, but injection failed", "Loader", NULL);

return true;
}

BOOL InjectDLL(DWORD ProcessID, char *dllName)
{
HANDLE Proc;
char buf[50]={0};
LPVOID RemoteString, LoadLibAddy;

if(!ProcessID)
return false;

Proc = OpenProcess(CREATE_THREAD_ACCESS, FALSE, ProcessID);

if(!Proc)
{
sprintf(buf, "OpenProcess() failed: %d", GetLastError());
MessageBox(NULL, buf, "Loader", NULL);
return false;
}

LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");

RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(Proc, (LPVOID)RemoteString, dllName, strlen(dllName), NULL);
CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);

CloseHandle(Proc);

return true;
}

unsigned long GetTargetProcessIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot;
BOOL retval, ProcFound = false;

thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}

pe.dwSize = sizeof(PROCESSENTRY32);

retval = Process32First(thSnapshot, &pe);

while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}

retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}

return pe.th32ProcessID;
}




Appendix D - SetWindowsHookEx complete example source code

Code:

#include
#include

#define PROC_NAME "target.exe"
#define DLL_NAME "injected.dll"

void LoadDll(char *procName, char *dllName);
unsigned long GetTargetThreadIdFromProcname(char *procName);

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
LoadDll(PROC_NAME, DLL_NAME);

return 0;
}

void LoadDll(char *procName, char *dllName)
{
HMODULE hDll;
unsigned long cbtProcAddr;

hDll = LoadLibrary(dllName);
cbtProcAddr = GetProcAddress(hDll, "CBTProc");

SetWindowsHookEx(WH_CBT, cbtProcAddr, hDll, GetTargetThreadIdFromProcName(procName));

return TRUE;
}

unsigned long GetTargetThreadIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot, hProcess;
BOOL retval, ProcFound = false;
unsigned long pTID, threadID;

thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}

pe.dwSize = sizeof(PROCESSENTRY32);

retval = Process32First(thSnapshot, &pe);

while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}

retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}

CloseHandle(thSnapshot);

_asm {
mov eax, fs:[0x18]
add eax, 36
mov [pTID], eax
}

hProcess = OpenProcess(PROCESS_VM_READ, false, pe.th32ProcessID);
ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL);
CloseHandle(hProcess);

return threadID;
}



Appendix E - Code cave example source code

Code:

#include
#include
#include

#define PROC_NAME "target.exe"
#define DLL_NAME "injected.dll"

unsigned long GetTargetProcessIdFromProcname(char *procName);
unsigned long GetTargetThreadIdFromProcname(char *procName);

__declspec(naked) loadDll(void)
{
_asm{
// Placeholder for the return address
push 0xDEADBEEF

// Save the flags and registers
pushfd
pushad

// Placeholder for the string address and LoadLibrary
push 0xDEADBEEF
mov eax, 0xDEADBEEF

// Call LoadLibrary with the string parameter
call eax

// Restore the registers and flags
popad
popfd

// Return control to the hijacked thread
ret
}
}

__declspec(naked) loadDll_end(void)
{
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
void *dllString;
void *stub;
unsigned long wowID, threadID, stubLen, oldIP, oldprot, loadLibAddy;
HANDLE hProcess, hThread;
CONTEXT ctx;

stubLen = (unsigned long)loadDll_end - (unsigned long)loadDll;

loadLibAddy = (unsigned long)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");

wowID = GetTargetProcessIdFromProcname(PROC_NAME);
hProcess = OpenProcess((PROCESS_VM_WRITE | PROCESS_VM_OPERATION), false, wowID);

dllString = VirtualAllocEx(hProcess, NULL, (strlen(DLL_NAME) + 1), MEM_COMMIT, PAGE_READWRITE);
stub = VirtualAllocEx(hProcess, NULL, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, dllString, DLL_NAME, strlen(DLL_NAME), NULL);

threadID = GetTargetThreadIdFromProcname(PROC_NAME);
hThread = OpenThread((THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME), false, threadID);
SuspendThread(hThread);

ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(hThread, &ctx);
oldIP = ctx.Eip;
ctx.Eip = (DWORD)stub;
ctx.ContextFlags = CONTEXT_CONTROL;

VirtualProtect(loadDll, stubLen, PAGE_EXECUTE_READWRITE, &oldprot);
memcpy((void *)((unsigned long)loadDll + 1), &oldIP, 4);
memcpy((void *)((unsigned long)loadDll + 8), &dllString, 4);
memcpy((void *)((unsigned long)loadDll + 13), &loadLibAddy, 4);

WriteProcessMemory(hProcess, stub, loadDll, stubLen, NULL);
SetThreadContext(hThread, &ctx);

ResumeThread(hThread);

Sleep(8000);

VirtualFreeEx(hProcess, dllString, strlen(DLL_NAME), MEM_DECOMMIT);
VirtualFreeEx(hProcess, stub, stubLen, MEM_DECOMMIT);
CloseHandle(hProcess);
CloseHandle(hThread);

return 0;
}


unsigned long GetTargetProcessIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot;
BOOL retval, ProcFound = false;

thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}

pe.dwSize = sizeof(PROCESSENTRY32);

retval = Process32First(thSnapshot, &pe);

while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}

retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}

CloseHandle(thSnapshot);
return pe.th32ProcessID;
}

unsigned long GetTargetThreadIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot, hProcess;
BOOL retval, ProcFound = false;
unsigned long pTID, threadID;

thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}

pe.dwSize = sizeof(PROCESSENTRY32);

retval = Process32First(thSnapshot, &pe);

while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}

retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}

CloseHandle(thSnapshot);

_asm {
mov eax, fs:[0x18]
add eax, 36
mov [pTID], eax
}

hProcess = OpenProcess(PROCESS_VM_READ, false, pe.th32ProcessID);
ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL);
CloseHandle(hProcess);

return threadID;
}

Friday, July 17, 2009

Thursday, July 16, 2009

Operating System Design

This comes from an old alt.os.development news thread. The part that has the ">" on each line was written by Ian Nottingham. The rest of it was written by Alistair J. R. Young.

> Hey...I've been trying to get started on a kernel for awhile now, but
> all the examples i look at are so far beyond the extreme early stages
> that i can't figure out where to start and what exactally to do when
> it does....anybody have an example of this early stage of development?
> or perhaps a guide or list of what needs to be done?

The first thing I'd say you need to take into account is that there is
*no* whole subsystem to start with. One of the most fun things about
kernels, I find, is the way that everything has a half-dozen
dependencies on everything else - so you're left with developing
little chunks of a half-dozen subsystems simultaneously.

If you are starting from flat scratch, probably the first thing you
need to develop are a bunch of little macros and functions to put a
prettier face on the more messy bits of the x86 architecture. If
you're really ambitious, you can try and make it a portable or at
least semi-portable face. :)

(I really believe in cheating when it comes to these boring minutiae -
if you're not all that interested in writing lots of low-level
PC-hardware-bashing assembler code, I suggest you get the Utah Oskit
{just released in v. 0.96, woo!} where that bit's all been done for
you.)

You'll also need a bunch of library functions for the kernel (no
strcmp(), no strcpy(), no malloc(), etc. of course, so...?) - plus
debugging functions along the lines of assert() and panic().

At the same time, you *really* need to make your major design
decisions now, otherwise you'll end up in the same situation as I was
- and having to rip the thing out and do it over again is a *major*
pain.

The first big one's the memory model. Segmentation and/or paging? It
seems, these days, that most people go for paging w/o segmentation -
both because the flat memory model's neater, and because paging's
generally portable and segmentation isn't.

And where do you put the kernel in it? Do you allow a separate address
space for each process, or all mixed together? Virtual memory?

Then there's multitasking/threading, if you decide to have
them. Perhaps most crucially at the start, is it possible your code
will ever be running on a SMP machine? If so, put in all the spinlocks
and other synchronisation stuff you'll need right from the start -
doing it in retrospect is an *incredible* nightmare.

What's your process model? Just the basic two-level
processes-owning-threads, or something more sophisticated? (I'm using
a three-level InteractiveSession/Job/Facility owns Process owns Thread
model, myself.) When you do the task-switching, are you going to write
your own code to do it, or use the Intel-provided TSSes to do it. If
the latter, are you going to go the whole way and have one TSS per
thread, or have two and swap the appropriate information into and out
of the inactive one before and after every task switch?

System calls. How do you do them? Several possibilities - Linux, et
al. seem to use software interrupts, so that's quite popular. Other
options - call gates to let a user-mode program directly call the
appropriate kernel functions. Or just have one call to send messages
to IPC ports, or some such, and run all communication even with the
kernel over IPC.

And speaking of IPC - Message ports? Named pipes? Queues? Local
sockets? All of the above? Best to think about it now, because it can
influence the rest of the design quite a bit - you may want to have
one fundamental one and implement everything else in terms of it (in
Laura, for example, everything's pretty much a derivative of the basic
message port - which influences the design of the TCP/IP stack
(networking - something else to think about).

Ich. Device drivers - how do you talk to them? And the
filesystem. This is all one muxed-up topic, really. Simplistically,
there's always the Unix model where you treat everything as a file and
access it all through the filesystem. Or there are more exotic options
waiting out there - again to use my own kernel as an example, the
Laura model has a 'namespace manager' which lists every object on the
system - devices, filesystems and their files, etc., etc. To access
anything, device, file, whatever, you ask the namespace manager and it
gives you back an (harking back to above) an IPC port for that object
- and each registered thing can support a totally customised set of
actions, not just the standard open(), close(), read(), write(),
ioctl()...

Security! If you're going to have any, think about it now. It's almost
worse than SMP to retrofit, at least if you want to avoid having
security holes everywhere. And there are so many different ways to do
it - mine uses object ACLs validated against a possible three
different tokens depending on what the relevant thread, task and
session are doing.

Well, that's all design stuff, but that's the most important in my
book. Getting it done first, I mean. Otherwise, you end up spending a
lot of time ripping out and rewriting.

Once you actually start putting code to keyboard... well, (unless
you're using something that gives you one), about the first thing you
need is a crude console driver. It almost certainly won't be the one
you use to drive the console in the final revision, but trying to
debug anything without printf() is an absolute bastard...

Then - let me see. It depends a lot on how your OS is laid out (design
again :) ) and what the dependencies are. The first thing you need,
obviously, is code that boots the kernel (if you use the MultiBoot
boot loader, or something similar, this is rather less painful than
otherwise. It might be an idea to use something like it to start with
even if you plan to write your own boot-loader later) and does the
most basic setup (get the segments set right, allocate a kernel heap
and stack to work with, and so on and so forth.)

Then, my first step was to write something that displayed a startup
banner and halt (so I could actually see something happening - always
a plus!). Then, building on that - let's see, my first step was to
rewrite that to display the banner and then enter the system idle loop
(the loop that will eventually become the idle thread, that is). That
*is* actually more complicated than just 'for (;;) ;' - as I think
it's a good idea to halt the processor during it to avoid burning too
much power, but...

I think the next thing that's probably a good idea to get working is
trap handling - even though, at this stage, about all that you can do
is display a message, dump state, and panic the kernel (this should,
IMO, be your default handler for everything). The messages will come
in handy when debugging later (much more useful than just a crash),
and it's a sight quicker to implement the real handlers when you've
already got a framework.

The same thing goes for interrupt handling, which I think is probably
the next thing that needs to go on the list. I wouldn't panic on an
unexpected interrupt, though.

After that - well, after that it gets very dependent on the kernel
you're doing. My next step was to get a handler running for the timer
interrupt - just about everything uses the system timer for
*something*, so it's pretty essential. And, also, I need that
working for the scheduler to work, so...
The Utah OSKit can be found at http://www.cs.utah.edu/flux/oskit/