ok this one is pretty crazy, and not really for beginners, but I figured Id post cuz I thought it was cool... I wanted to make an api monitor using userland silliness think... sysinternals file/reg mon without a driver im gonna explain the whole thing in one post, then post the whole code in another if people wanna play so here we go first we got our includes Code: #include #include #include next we got a function that gets the base address given a ProcessID and name, this parses modules so it can get the base address of a process, and all its dlls it imports lets go over it a bit Code: DWORD GetBaseAddress( DWORD dwPID, char* name ) { HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32; start of function and some variables Code: hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID ); if( hModuleSnap == INVALID_HANDLE_VALUE ) { printf( "CreateToolhelp32Snapshot (of modules)" ); return( 0 ); } this gets a snapshot of the system at the time you call the function, it has all sorts of goodies in there the line right after it checks to make sure it worked, if not... quit Code: me32.dwSize = sizeof( MODULEENTRY32 ); if( !Module32First( hModuleSnap, &me32 ) ) { printf( "Module32First" ); CloseHandle( hModuleSnap ); return( 0 ); } this sets up our variable and checks that we can get the first module, if not quit! Code: do { if (strstr(me32.szModule,name)) return((DWORD) me32.modBaseAddr); } while( Module32Next( hModuleSnap, &me32 ) ); CloseHandle( hModuleSnap ); return( 1 ); this checks if our parameter "name" is present in the module we're looking at, if it is return that base address. If not, keep going untill you're at the end. The next part is a function I threw together probably because Im stupid... I bet there is an easier way to convert 2 chars (representing hex) to its ascii equivilant. Code: char hexToAscii(char first, char second) { char hex[5], *stop; sprintf(hex,"0x%c%c",first,second); return strtol(hex, &stop, 16); } ok, so here comes the magic. The hook function does some cool stuffs Code: int hook(DWORD proc_id, DWORD base, HWND sendHere, DWORD signal) { char address[10]; HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, proc_id); if(!hProcess) { printf("Cannot open process!\n"); return 0; } start the function, make some variables, open the process that was given to us, if it doesnt exist quit Code: byte data[] = {0xE9,0xAA,0xAA,0xAA,0xAA}; DWORD dataSize = sizeof(data),jump,retn; HANDLE hModule = VirtualAllocEx( hProcess, 0, 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); this declares our first patch, its size, and makes some wiggle room for us in memory. data is the machine code for a jump to somewhere, right now its just a's because we have to figure out where we want to go. We want to go to the wiggle room we just made with VirtualAllocEx. This allocates memory in another program. Code: jump=(DWORD)hModule-base-0x5; sprintf(address,"%08x",jump); this gets where we want to go. When the computer sees the jump command "e9" it then takes the next 4 bytes, and goes that far. So we need the "distance" to where we wanna go. we have the start (that is given as an argument) and we have the end (hModule returned from VirtualAllocEx) so just subtract the two, and subtract 5 (because our command took up 5 bytes. the sprintf is converting the variable jump, to a cstring Code: for (int i=0; i<4; i++) data[1+i]=hexToAscii(address[8-((i+1)*2)],address[8-((i*2)+1)]); this thing looks scary, and it kinda is, heres what it does it takes the last 2 chars, converts them to ONE hex byte, and places it first, then the third, then second then first etc this is because addresses are stored backwards in assembly so jmp 12345678 would look like e9 78563412 kinda silly, kinda complicated. but you get used to it. All we really need to take away from this part is that, we just made some data that when executed will jump to our wiggle room. Then we write that data to the address we were given Code: WriteProcessMemory(hProcess, (LPVOID)base, &data, dataSize, NULL); Code: unsigned char data2[] = "\x60\x6A\x00\x6A\x00\x68\x37\x04\x00\x00" "\x68\xFF\xFF\xFF\xFF\xB8\x21\x43\x65\x87\xFF\xD0\x61\x8B" "\xFF\x55\x8B\xEC\xE9\x57\x56\xAD\x11"; DWORD dataSize2 = sizeof(data2); This is the second bit of code nastiness here is what the code does Code: 00170000 60 PUSHAD 00170001 6A 00 PUSH 0 00170003 6A 00 PUSH 0 00170005 68 45040000 PUSH 445 0017000A 68 48100C00 PUSH 0C1048 0017000F B8 59048575 MOV EAX,USER32.SendMessageA 00170014 FFD0 CALL EAX 00170016 61 POPAD 00170017 8BFF MOV EDI,EDI 00170019 55 PUSH EBP 0017001A 8BEC MOV EBP,ESP 0017001C -E9 E157E800 JMP notepad.00FF5802 HOLY SCARY! nah... Code: 00170000 60 PUSHAD saves all the cpu registers on the stack (so we dont break the program we're meddling in Code: 00170001 6A 00 PUSH 0 00170003 6A 00 PUSH 0 00170005 68 45040000 PUSH 445 0017000A 68 48100C00 PUSH 0C1048 These are the parameters for send message it would look like this SendMessage(0C1048,445,0,0); Code: 0017000F B8 59048575 MOV EAX,USER32.SendMessageA 00170014 FFD0 CALL EAX This is calling sendmessage, we need to FIND sendmessage though, because of how silly vista is, we'll do that later Code: 00170016 61 POPAD This pops the cpu registers back from the stack Code: 00170017 8BFF MOV EDI,EDI 00170019 55 PUSH EBP 0017001A 8BEC MOV EBP,ESP 0017001C -E9 E157E800 JMP notepad.00FF5802 This is the standard (since sp2) function starting code, because of our jump in the beginning, we overwrote these... so we need todo them or the program will crash. JUST BEING COURTEOUS!!! Then it jumps back to where we came from. So basically. our 2nd function will live in the wiggle room, and will send a message then go back to doing what it was doing before. Code: sprintf(address,"%08x",sendHere); for (int i=0; i<4; i++) data2[11+i]=hexToAscii(address[8-((i+1)*2)],address[8-((i*2)+1)]); This is converting the place we want to send our messages to, into hex, and adding it to our 2nd function Code: DWORD sendMessage=(DWORD)GetProcAddress(GetModuleHandle("User32"), "SendMessageA"); sprintf(address,"%08x",sendMessage); for (int i=0; i<4; i++) data2[16+i]=hexToAscii(address[8-((i+1)*2)],address[8-((i*2)+1)]); This is getting the address to sendmessage, converting it to hex, and adding it to our function Code: retn=base-(DWORD)hModule-0x1C; sprintf(address,"%08x",retn); for (int i=0; i<4; i++) data2[29+i]=hexToAscii(address[8-((i+1)*2)],address[8-((i*2)+1)]); This is calculating the distance from where we are, to where we came from, so we can jump back, then converting to hex, and adding to the function Code: signal=0x400+signal; sprintf(address,"%08x",signal); for (int i=0; i<4; i++) data2[6+i]=hexToAscii(address[8-((i+1)*2)],address[8-((i*2)+1)]); This is converting the messsage we want to send to hex and adding it to the function Code: WriteProcessMemory(hProcess, (LPVOID)hModule, &data2, dataSize2, NULL); CloseHandle(hProcess); This writes our second function and closes the handle Code: LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: PostQuitMessage (0); break; default: if (message>=0x400 && message<=0x7FFF) printf("%x %x %x\n",message,wParam,lParam); return DefWindowProc (hwnd, message, wParam, lParam); } return 0; } This is our secret message handler, it basically quits, when it gets a quit message, and if it gets any message in between 0x400 and 0x7fff it prints it out Code: int WINAPI WinMain (HINSTANCE hThis,HINSTANCE hPrev,LPSTR lpszArg,int nFunsterStil) { DWORD hookthis,proc_id,base; HWND Found; HWND hWnd = FindWindow("Notepad", NULL); if(hWnd == NULL) { printf("Error cannot find window!\n"); return 0; } else { GetWindowThreadProcessId(hWnd, &proc_id); base=GetBaseAddress(proc_id,"notepad.exe"); } This is our main function, it makes some variables, and looks for the window called "notepad" if it doesnt find it, it quits, if it does... it gets its processid, and its baseaddress using our function we made above! Code: DWORD CreateF=(DWORD)GetProcAddress(GetModuleHandle("Kernel32"), "CreateFileW"); DWORD ROpenK=(DWORD)GetProcAddress(GetModuleHandle("Advapi32"), "RegOpenKeyExW"); hookthis=GetBaseAddress(proc_id,"notepad.exe"); hookthis=hookthis+0x57FD; These are the things we wanna hook, I picked createfileW, regopenkeyexW, and a special place in notepad that is executed when you hit "saveas" just for fun Code: HWND hwnd; MSG messages; WNDCLASSEX wincl; wincl.hInstance = hThis; wincl.lpszClassName = "Hook Phone Home"; wincl.lpfnWndProc = WindowProcedure; wincl.style = CS_DBLCLKS; wincl.cbSize = sizeof (WNDCLASSEX); wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor (NULL, IDC_ARROW); wincl.lpszMenuName = NULL; wincl.cbClsExtra = 0; wincl.cbWndExtra = 0; wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; if (!RegisterClassEx (&wincl)) return 0; hwnd = CreateWindowEx (0,"Hook Phone Home","Find me",0, CW_USEDEFAULT,CW_USEDEFAULT,230,100,HWND_DESKTOP,NULL,hThis,NULL); while ((Found = FindWindowEx(NULL,NULL,"Hook Phone Home","Find me"))==NULL) Sleep(500); ShowWindow (hwnd, SW_HIDE); This makes a hidden window with the class "hook phone home" and the title "find me" Code: hook(proc_id,CreateF,Found,0x37); hook(proc_id,ROpenK,Found,0x13); hook(proc_id,hookthis,Found,0x69); Execute our hooks! Code: while (GetMessage (&messages, 0, 0, 0)) { TranslateMessage(&messages); DispatchMessage(&messages); } sit back and watch for messages! so basically after running this, you can see 437=createfile 413= regopenkey and 469=saveas function play around!