Monday, June 28, 2004

Programming #2 - The making of a Debugger, Part #1

Yep.
Since I have some good knowledge in computer programming and I'm still reading a lot on this topic (between "Book of Illusions" from Paul Auster and "The Sigma Protocol" from Robert Ludlum).

Lately I've checked the "Undocumented Windows 2000 Secrets: A Programmers Cookbook" from Sven Schreiber. Excellent book for those who want to know the inside of windows even more. Maybe a review on my web site (when I've rebooted my stupid machine). And I've come to the idea of making a debugger. So I'll make a little simple one for the windows platform (I may come later for a solution on *x platforms).

The first part of this big project will deal with inserting your program into a remote process. Doing this is tricky but necessary. You've maybe seen the IsDebuggerPresent function I explained earlier. The standard method could be a problem when a program (may be malicious) checks for IsDebuggerPresent and kill ourselves or the process we try to debug (again, it would be even worse if it removes itself from memory, incapacipating our goal to check it). Using the standard windows api methods trigger normally this flag and so IsDebuggerPresent returns true....

So what can we do to insert into a process?
Note: You cannot use this kind of techniques you need to have administrator rights.


We can always create a thread into a remote process with this function:
// Returns the handle of the new thread.

// Don't forget that everything about memory is in the other process.
// #1 - Start Address and the Parameter are in another process, so for now we cannot access
// them directly. We'll see what we can do later.

HANDLE CreateRemoteThread(
HANDLE hProcess, // Process to create thread into.
LPSECURITY_ATTRIBUTES lpThreadAttributes, // Thread attributes, normally NULL.
SIZE_T dwStackSize, // Default size of the stack, normally 0.
LPTHREAD_START_ROUTINE lpStartAddress, // See #1.
LPVOID lpParameter, // See #2.
DWORD dwCreationFlags, // Creation Flags, default is ok.
LPDWORD lpThreadId ); // ID Thread container.


Most things are possible with this method. For now, I'll give you this code, that uses many functions, and receives two parameters: the name and path for an EXE file that will be executed, and the name of a DLL to load. I'll come back on this code later. For now, just check it out:

#define VC_EXTRALEAN

#include <windows.h>
#include <stdio.h>

int main(int argc, char** argv)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
void* pToDllName;
HANDLE hKernel32 = LoadLibrary( "kernel32.dll" );

if (argc < 3) return -1;

ZeroMemory( &pi, sizeof(pi) );
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
CreateProcess( argv[1], NULL, NULL, NULL, FALSE, 0, 0, 0, &si, &pi );

pToDllName = VirtualAllocEx( pi.hProcess, NULL, 513,
MEM_COMMIT,
PAGE_READWRITE );

WriteProcessMemory( pi.hProcess, pToDllName, argv[2], 512, NULL );
CreateRemoteThread( pi.hProcess,
NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress( hKernel32, "LoadLibraryA" ),
pToDllName, 0, NULL );

printf("Press any key to end remote process and current program.\n");
getc( stdin );
TerminateProcess( pi.hProcess, 0 );
return 0;
}

0 Comments:

Post a Comment

<< Home