// DC 05/10/2006: // Downloaded from http://www.codeproject.com/threads/winspy.asp. // This code is based on the WinSpy_Src\InjCode.* files // Module must be compiled without /GZ or /RTC1 (in VC8). // Therefore, it cannot be compiled with precompiled headers, which // are built with these switches. #include "stdafx.h" #include #include #include #include "SendMessageRemote.h" // Increase as needed #define MAX_BUF_SIZE (512) //--------------------------------------------------------------------- // INJDATA // Notice: The data structure being injected. // typedef LRESULT (WINAPI *SENDMESSAGE)(HWND,UINT,WPARAM,LPARAM); typedef struct { SENDMESSAGE fnSendMessage; // pointer to user32!SendMessage HWND hwnd; UINT msg; WPARAM wParam; BYTE arrLPARAM[MAX_BUF_SIZE]; } INJDATA, *PINJDATA; //--------------------------------------------------------------------- // ThreadFunc // Notice: - the code being injected; // - the remote copy of this function retrieves the password; // // Return value: password length // static DWORD WINAPI ThreadFunc (INJDATA *pData) { // There must be less than a page-worth of local // variables used in this function. return pData->fnSendMessage( pData->hwnd, pData->msg, pData->wParam, (LPARAM) pData->arrLPARAM ); } // This function marks the memory address after ThreadFunc. // int cbCodeSize = (PBYTE) AfterThreadFunc - (PBYTE) ThreadFunc. static void AfterThreadFunc (void) { } int SendMessageRemote (DWORD dwProcessId, HWND hwnd, UINT msg, WPARAM wParam, LPVOID pLPARAM, size_t sizeLParam) { HANDLE hProcess = NULL; // the handle of the remote process HINSTANCE hUser32; INJDATA *pDataRemote; // the address (in the remote process) where INJDATA will be copied to; DWORD *pCodeRemote; // the address (in the remote process) where ThreadFunc will be copied to; HANDLE hThread = NULL; // the handle to the thread executing the remote copy of ThreadFunc; DWORD dwThreadId = 0; DWORD dwNumBytesXferred = 0; // number of bytes written/read to/from the remote process; LRESULT lSendMessageReturn = 0xFFFFFFFF; __try { hUser32 = GetModuleHandle(__TEXT("user32")); if (hUser32 == NULL) __leave; // Initialize INJDATA INJDATA DataLocal = { (SENDMESSAGE) GetProcAddress(hUser32, "SendMessageW"), hwnd, msg, wParam }; if( DataLocal.fnSendMessage == NULL ) __leave; _ASSERTE ( sizeLParam <= MAX_BUF_SIZE ); memcpy ( DataLocal.arrLPARAM, pLPARAM, sizeLParam ); // Copy INJDATA to Remote Process hProcess = OpenProcess ( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwProcessId); if ( !hProcess ) __leave; // 1. Allocate memory in the remote process for INJDATA // 2. Write a copy of DataLocal to the allocated memory pDataRemote = (INJDATA*) VirtualAllocEx( hProcess, 0, sizeof(INJDATA), MEM_COMMIT, PAGE_READWRITE ); if (pDataRemote == NULL) __leave; WriteProcessMemory( hProcess, pDataRemote, &DataLocal, sizeof(INJDATA), (SIZE_T *)&dwNumBytesXferred ); // Calculate the number of bytes that ThreadFunc occupies const int cbCodeSize = ((LPBYTE) AfterThreadFunc - (LPBYTE) ThreadFunc); // 1. Allocate memory in the remote process for the injected ThreadFunc // 2. Write a copy of ThreadFunc to the allocated memory pCodeRemote = (PDWORD) VirtualAllocEx( hProcess, 0, cbCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); if (pCodeRemote == NULL) __leave; WriteProcessMemory( hProcess, pCodeRemote, &ThreadFunc, cbCodeSize, (SIZE_T *)&dwNumBytesXferred ); // Start execution of remote ThreadFunc hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) pCodeRemote, pDataRemote, 0 , &dwThreadId); if (hThread == NULL) __leave; WaitForSingleObject(hThread, INFINITE); // Copy LPARAM back (result is in it) ReadProcessMemory( hProcess, pDataRemote->arrLPARAM, pLPARAM, sizeLParam, (SIZE_T *)&dwNumBytesXferred); } __finally { if ( pDataRemote != 0 ) VirtualFreeEx( hProcess, pDataRemote, 0, MEM_RELEASE ); if ( pCodeRemote != 0 ) VirtualFreeEx( hProcess, pCodeRemote, 0, MEM_RELEASE ); if ( hThread != NULL ) { GetExitCodeThread(hThread, (PDWORD) &lSendMessageReturn); CloseHandle(hThread); } if ( hProcess ) CloseHandle (hProcess); } return lSendMessageReturn; }