Determining main thread id of extern process (ReadProcessMemory - Err 299) - c++

I tried to get the main thread id of a another process, like it was suggested here:
https://stackoverflow.com/a/8058710/1386873
DWORD GetMainThreadId(DWORD dwPid)
{
LPCVOID lpTid;
_asm
{
mov eax, fs:[18h]
add eax, 36
mov lpTid, eax
}
HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, dwPid);
if (hProcess == NULL)
return NULL;
int dwTid = 0;
if (ReadProcessMemory(hProcess, lpTid, (LPVOID)&dwTid, sizeof(int), NULL) == FALSE)
{
CloseHandle(hProcess);
return NULL;
}
CloseHandle(hProcess);
return (DWORD)dwTid;
}
But this does not work: ReadProcessMemory always returns a 299 Code from GetLastError(), which means "ERROR_PARTIAL_COPY - Only part of a ReadProcessMemory or WriteProcessMemory request was completed.". Well the error message is pretty clear, but why does this happen? BytesRead are also always 0.
I get the process id like this:
unsigned long GetTargetProcessIdFromWindow(LPCWSTR className, LPCWSTR windowName)
{
unsigned long processID = 0;
HWND targetWnd;
targetWnd = FindWindow(className, windowName);
GetWindowThreadProcessId(targetWnd, &processID);
return processID;
}
which seems to be working fine. What might cause this? I tried different applications (Calculator, Notepad etc.). My application is build for Win32, my operating system is Windows 64bit.
Does this have to do with the TIB? As far as i understand it, as long as i build it for Win32 the way i do it should be fine, shouldn't it.
Thanks for any tips.

Consider Toolhlp functions instead - CreateToolhelp32Snapshot() and Thread32First().

Related

Why EnumProcessModules is return FALSE value and 299 code error?

I looked through similar questions, but did not find a solution to my problem.
Exception class:
class Exception{
public:
Exception(LPCWSTR text){
QMessageBox::information(0, "Catch",
QString::fromWCharArray(text) + ", Code: " +
QString::number(GetLastError()));
//EnumModules is return FALSE in function getHinstance, Code: 299
}
}
And main code:
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, TRUE, 7068); //PID of opened calculator
if(handle == INVALID_HANDLE_VALUE)
throw Exception(L"invalid handle in function getHinstance");
int hNeeded = 1024;
HINSTANCE hModules[hNeeded];
DWORD bNeeded = 0;
PWSTR fileName = new WCHAR[512];
if(!EnumProcessModulesEx(handle, hModules, sizeof(hModules), &bNeeded, LIST_MODULES_ALL))
throw Exception(L"EnumModules is return FALSE in function getHinstance");
for(int i = 0; i < bNeeded / sizeof(HINSTANCE); ++i){
GetModuleBaseNameW(handle, hModules[i], fileName, sizeof(WCHAR) * 512);
if(lstrcmpW(fileName, moduleName) == 0){
delete [] fileName;
return hModules[i];
}
}
handle is a valid value of handle process
This code executes in a 64 bit process to enum modules in a 64 bit process
I can reproduce ERROR_PARTIAL_COPY (299) error when running the following code as a 64 bit process.
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 17152); //PID of opened notepad.exe
DWORD errCode = GetLastError();
HMODULE hModules[100];
DWORD bNeeded = 0;
EnumProcessModulesEx(handle, hModules, sizeof(hModules), &bNeeded, LIST_MODULES_ALL);
errCode = GetLastError();
And solve the error when use LIST_MODULES_64BIT instead of LIST_MODULES_ALL.
My notepad.exe is a 64 bit process.
So it seems you need use LIST_MODULES_64BIT for enumerating the modules of a 64-bit process when use EnumProcessModulesEx.
Or you can use EnumProcessModules:
EnumProcessModules(handle, hModules, sizeof(hModules), &bNeeded);
I solve my problem:
CreateProcess is returns without waiting for the creation process
My fault is that I did not let the community understand the real context of the program, but provided only a small piece of code that was not related to the problem. Thank you all for the comments, I will try to ask more detailed questions

Detours: Prevent task kill of my software via another software

I have found a code that promises to intercept and detour calls to the TerminateProcess function and thus prevent my software from being killed directly from other program.
But this code is not working and I am still able to kill my process via other program.
Here is the last my attempt with a code I have found in this YouTube video:
PS: victim.exe is the killer program.
DLL
// DllRedirectAPI.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include <Windows.h>
BYTE MOV[10] = { 0x48, 0xB8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
BYTE JMP_RAX[2] = { 0xFF, 0xE0 };
#define BuffSizeX64 (sizeof(MOV) + sizeof(JMP_RAX))
BOOL Hook_Det_x64(char LibName[], char API_Name[], LPVOID NewFun) {
DWORD OldProtect;
DWORD64 OrgAddress = (DWORD64)GetProcAddress(LoadLibraryA(LibName), API_Name);
if (OrgAddress == NULL) return 0;
memcpy(&MOV[2], &NewFun, 8);
VirtualProtect((LPVOID)OrgAddress, BuffSizeX64, PAGE_EXECUTE_READWRITE, &OldProtect);
memcpy((LPVOID)OrgAddress, MOV, sizeof(MOV));
memcpy((LPVOID)(OrgAddress + sizeof(MOV)), JMP_RAX, sizeof(JMP_RAX));
VirtualProtect((LPVOID)OrgAddress, BuffSizeX64, OldProtect, &OldProtect);
return 1;
}
int WINAPI MessageBoxAX(
HWND hWnd,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType) {
MessageBoxExA(0, "Hooked ...", "Mahmoud", 0, 0);
return 999;
}
BOOL WINAPI DllMain(HMODULE hModule, DWORD Call_Reason, LPVOID lpReserved) {
switch (Call_Reason) {
case DLL_PROCESS_ATTACH:
Hook_Det_x64("Kernel32.dll", "TerminateProcess", MessageBoxAX);
}
return 1;
}
INJECTOR
// Injector.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#include <conio.h>
#include <stdio.h>
#include <comdef.h>
#define WIN32_LEAN_AND_MEAN
#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)
BOOL Inject(DWORD pID, const char * DLL_NAME);
DWORD GetTargetThreadIDFromProcName(const char * ProcName);
int main(int argc, char * argv[])
{
//############### CHANGE HERE ONLY ###################
char *Target_Process = "victim.exe"; //###
//#######################################################
char *buf;
DWORD pID = GetTargetThreadIDFromProcName(Target_Process);
buf = "DllRedirectAPI.dll";
if (!Inject(pID, buf))
{
printf("DLL Not Loaded!");
}
else{
printf("DLL is Injected in torget Process");
}
_getch();
return 0;
}
BOOL Inject(DWORD pID, const char * DLL_NAME)
{
HANDLE Proc;
char buf[50] = { 0 };
LPVOID RemoteString, LoadLibAddy;
if (!pID)
return false;
Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
if (!Proc)
{
sprintf_s(buf, "OpenProcess() failed: %d", GetLastError());
printf(buf);
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle(TEXT("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;
}
DWORD GetTargetThreadIDFromProcName(const char * ProcName)
{
PROCESSENTRY32 pe;
HANDLE thSnapShot;
BOOL retval, ProcFound = false;
thSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (thSnapShot == INVALID_HANDLE_VALUE)
{
printf("Error: Unable create toolhelp snapshot!");
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapShot, &pe);
while (retval)
{
if (_bstr_t(pe.szExeFile) == _bstr_t(ProcName))
{
return pe.th32ProcessID;
}
retval = Process32Next(thSnapShot, &pe);
}
return 0;
}
Can someone help me, telling me where I'm making a mistake?
My system is Windows 7 Ultimate 64 Bits.
Thanks in advance.
(Wanted to write a comment, but it got quite long...)
As #AndrewMedico says in the comment: You need to hook the TerminateProcess of the Task Manager process to prevent the Task Manager from terminating anything.
I suggest you the following approach:
Try a simple DLL injection
a/ Make a DLL which prints some text in its DllMain, e.g. printf("I am here\n"); fflush(stdout);
b/ Try to inject it into some other command line process using the process hacker's Miscellaneous>Inject DLL...
c/ Verify your DLL was executed inside the target process by checking it's standard output
Try a simple API hook:
a/ Make a command line application which waits for a key and then terminates itself using some variant of TerminateProcess(GetCurrentProcess(), 1);. Add code to print some text after the TerminateProcess call.
b/ Run this application to verify the text after calling the TerminateProcess is not printed.
c/ Hook the TerminateProcess before waiting for the key using, e.g. mhook. Print some text in the replacement function and then return. Do not call the original TerminateProcess here.
d/ Run this application to verify the text inside the hook is printed and the text after the TerminateProcess call is printed as well (i.e. verify the process termination was suppressed).
Combine the results of previous steps to reach your goal:
a/ Put the hooking code from from step 2 into the DLL from step 1
b/ Inject it into the application from step 2b (i.e. the one without the hook) while it is waiting for the key and verify the text after TerminateProcess is printed.
c/ Enjoy (or debug/blame me)
Good luck!
EDIT>
OK, here is my view of what we have here:
Code in the question:
(Is an application very similar to what I suggest in "2b")
Hooks the TerminateProcess and shows a message box instead.
Should display a message box when executed
(Looks like it is a 32-bit only version)
YouTube video
Shows an application "Terminate process.exe" which terminates process given by name
After the "Injector.exe" is executed the application ceases to terminate the process and displays a message box instead (IMHO the "Injector.exe" injects a "DllFile.dll" into the running "Terminate process.exe")
Source code for the injector in the YouTube comments
This code injects DLL "C:\DllRedirectAPI.dll" into the first process with name "victim.exe" it finds
(It does not inject into "Terminate process.exe", it does not use "DllFile.dll")
Source code for the DLL in the YouTube comments
This code hooks function MessageBoxA that it shows a different message box instead. It is worth noting that the hook code itself calls the original MessageBoxA and takes the approach that it reverts the modification it did during the hooking, calls the original function and then re-applies the hook.
(It does not hook 'TerminateProcess' at all)
(Looks like it is a 32-bit only version)
64-bit version excerpts
Destructive hook of MessageBoxA (i.e. does not backup the original code)
The hook uses MessageBoxExA (which is intact) to display a different message box instead (i.e. it does not use the overwritten MessageBoxA)
(It does not hook 'TerminateProcess' at all)
(It is a 64-bit version)
Disclaimer: I am not that proficient with the topic to be 100% sure, feel free to correct/clarify me.
For the actual hooking I personally recommend to use the mhook library, which worked for me. It's documentation is worth reading as well.
See e.g. this for some alternatives (I have not tried any of them)...
EDIT>
This one works for me on Win XP inside VirtualBox:
#include <windows.h>
#include <stdio.h>
#include <mhook.h>
static BOOL WINAPI
(*_TerminateProcess)(
_In_ HANDLE hProcess,
_In_ UINT uExitCode
) = NULL;
BOOL WINAPI
TerminateProcessImpl(
_In_ HANDLE hProcess,
_In_ UINT uExitCode) {
printf("\nBlocked\n"); fflush(stdout);
return 0;
}
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD Reason, LPVOID Reserved) {
if(Reason==DLL_PROCESS_ATTACH) {
printf("\nDLL attached!\n"); fflush(stdout);
HMODULE h = LoadLibrary("Kernel32");
if(h!=NULL) {
printf("\nGot Kernel32!\n"); fflush(stdout);
_TerminateProcess=(void*)GetProcAddress(h,"TerminateProcess");
if(_TerminateProcess!=NULL) {
printf("\nAbout to hook...\n"); fflush(stdout);
if(Mhook_SetHook((void*)&_TerminateProcess, &TerminateProcessImpl)) {
printf("\nHooked OK!\n"); fflush(stdout);
} else {
printf("\nHook failed!\n"); fflush(stdout);
}
}
}
}
return TRUE;
}

How to change currently selected date in TDateTimePicker control in another process by its HWND handle?

I'm writing a custom module to work with a proprietary software. (That software has been discontinued and I do not have its source code.) My module will run as a separate process. Its goal is to automate an operation via this proprietary software. To do that I need to be able to select a specific date in the TDateTimePicker control. I know it's a Delphi control, but that's as far as my knowledge of Delphi/Pascal goes. I can find the HWND handle for this control though.
So my question -- is there a way to set a date in that control only by its handle from an outside process (using WinAPIs)?
You can send a DTM_SETSYSTEMTIME message to the DTP's HWND. However, that message takes a pointer to a SYSTEMTIME record as a parameter, and that pointer MUST be valid in the address space of the process that owns the DTP control.
DTM_SETSYSTEMTIME is NOT auto-marshaled by Windows when sent across process boundaries, so if you take a pointer to a SYSTEMTIME owned by the sending process and send it as-is into the DTP process, that will not work. You MUST manually marshal the SYSTEMTIME data to the DTP process, for example:
uses
..., CommCtrl;
var
Wnd: HWND;
Pid: DWORD;
hProcess: THandle;
ST: TSystemTime;
PST: PSystemTime;
Written: SIZE_T;
begin
Wnd := ...; // the HWND of the DateTimePicker control
DateTimeToSystemTime(..., ST); // the desired date/time value
// open a handle to the DTP's owning process...
GetWindowThreadProcessId(Wnd, Pid);
hProcess := OpenProcess(PROCESS_VM_WRITE or PROCESS_VM_OPERATION, FALSE, Pid);
if hProcess = 0 then RaiseLastOSError;
try
// allocate a SYSTEMTIME record within the address space of the DTP process...
PST := PSystemTime(VirtualAllocEx(hProcess, nil, SizeOf(ST), MEM_COMMIT, PAGE_READWRITE));
if PST = nil then RaiseLastOSError;
try
// copy the SYSTEMTIME data into the DTP process...
if not WriteProcessMemory(hProcess, PST, #ST, SizeOf(ST), Written) then RaiseLastOSError;
// now send the DTP message, specifying the memory address that belongs to the DTP process...
SendMessage(Wnd, DTM_SETSYSTEMTIME, GDT_VALID, LPARAM(PST));
finally
// free the SYSTEMTIME memory...
VirtualFreeEx(hProcess, PST, SizeOf(ST), MEM_DECOMMIT);
end;
finally
// close the process handle...
CloseHandle(hProcess);
end;
end;
Now, with that said, there is another problem related specifically to TDateTimePicker (not to DTP controls in general). TDateTimePicker does not use the DTM_GETSYSTEMTIME message to retrieve the currently selected date/time. Its Date/Time properties simply return the current value of an internal TDateTime variable that gets updated when:
the TDateTimePicker is initially created, where the date/time is set to Now().
its Date/Time property is assigned by the app, either in code or DFM streaming.
it receives a DTN_DATETIMECHANGE notification with a new date/time value.
In this situation, you want #3 to happen. However, DTN_DATETIMECHANGE (which is based on WM_NOTIFY) is not generated automatically by DTM_SETSYSTEMTIME, so you have to fake it, but WM_NOTIFY cannot be sent across process boundaries (Windows will not allow it - Raymond Chen explains a bit why). This is documented on MSDN:
For Windows 2000 and later systems, the WM_NOTIFY message cannot be sent between processes.
So, you would have to inject some custom code into the DTP's owning process to send the DTN_DATETIMECHANGE within the same process as the DTP. And injecting code into another process is not trivial to implement. However, in this particular case, there is a fairly simply solution, courtesy of David Ching:
https://groups.google.com/d/msg/microsoft.public.vc.mfc/QMAHlPpEQyM/Nu9iQycmEykJ
As others have pointed out, the pointer in LPARAM needs to reside in the same process as the thread that created hwnd ... I have created a SendMessageRemote() API which uses VirtualAlloc, ReadProcessMemory, WriteProcessMemory, and CreateRemoteThread to do the heavy lifting ...
http://www.dcsoft.com/private/sendmessageremote.h
http://www.dcsoft.com/private/sendmessageremote.cpp
It is based on a great CodeProject article:
http://www.codeproject.com/threads/winspy.asp.
Here is a Delphi translation of his code. Note, I have tested it in 32-bit and it works, but I have not tested it in 64-bit. You may have to tweak it when sending a message from a 32bit process to a 64bit process or vice versa, or if the target DTP is using an Ansi window instead of a Unicode window:
const
MAX_BUF_SIZE = 512;
type
LPFN_SENDMESSAGE = function(Wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
PINJDATA = ^INJDATA;
INJDATA = record
fnSendMessage: LPFN_SENDMESSAGE; // pointer to user32!SendMessage
hwnd: HWND;
msg: UINT;
wParam: WPARAM;
arrLPARAM: array[0..MAX_BUF_SIZE-1] of Byte;
end;
function ThreadFunc(pData: PINJDATA): DWORD; stdcall;
begin
Result := pData.fnSendMessage(pData.hwnd, pData.msg, pData.wParam, LPARAM(#pData.arrLPARAM));
end;
procedure AfterThreadFunc;
begin
end;
function SendMessageRemote(dwProcessId: DWORD; hwnd: HWND; msg: UINT; wParam: WPARAM; pLPARAM: Pointer; sizeLParam: size_t): LRESULT;
var
hProcess: THandle; // the handle of the remote process
hUser32: THandle;
DataLocal: INJDATA;
pDataRemote: PINJDATA; // the address (in the remote process) where INJDATA will be copied to;
pCodeRemote: Pointer; // the address (in the remote process) where ThreadFunc will be copied to;
hThread: THandle; // the handle to the thread executing the remote copy of ThreadFunc;
dwThreadId: DWORD;
dwNumBytesXferred: SIZE_T; // number of bytes written/read to/from the remote process;
cbCodeSize: Integer;
lSendMessageResult: DWORD;
begin
Result := $FFFFFFFF;
hUser32 := GetModuleHandle('user32');
if hUser32 = 0 then RaiseLastOSError;
// Initialize INJDATA
#DataLocal.fnSendMessage := GetProcAddress(hUser32, 'SendMessageW');
if not Assigned(DataLocal.fnSendMessage) then RaiseLastOSError;
DataLocal.hwnd := hwnd;
DataLocal.msg := msg;
DataLocal.wParam := wParam;
Assert(sizeLParam <= MAX_BUF_SIZE);
Move(pLPARAM^, DataLocal.arrLPARAM, sizeLParam);
// Copy INJDATA to Remote Process
hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_QUERY_INFORMATION or PROCESS_VM_OPERATION or PROCESS_VM_WRITE or PROCESS_VM_READ, FALSE, dwProcessId);
if hProcess = 0 then RaiseLastOSError;
try
// 1. Allocate memory in the remote process for INJDATA
// 2. Write a copy of DataLocal to the allocated memory
pDataRemote := PINJDATA(VirtualAllocEx(hProcess, nil, sizeof(INJDATA), MEM_COMMIT, PAGE_READWRITE));
if pDataRemote = nil then RaiseLastOSError;
try
if not WriteProcessMemory(hProcess, pDataRemote, #DataLocal, sizeof(INJDATA), dwNumBytesXferred) then RaiseLastOSError;
// Calculate the number of bytes that ThreadFunc occupies
cbCodeSize := Integer(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 := VirtualAllocEx(hProcess, nil, cbCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if pCodeRemote = nil then RaiseLastOSError;
try
if not WriteProcessMemory(hProcess, pCodeRemote, #ThreadFunc, cbCodeSize, dwNumBytesXferred) then RaiseLastOSError;
// Start execution of remote ThreadFunc
hThread := CreateRemoteThread(hProcess, nil, 0, pCodeRemote, pDataRemote, 0, dwThreadId);
if hThread = 0 then RaiseLastOSError;
try
WaitForSingleObject(hThread, INFINITE);
// Copy LPARAM back (result is in it)
if not ReadProcessMemory(hProcess, #pDataRemote.arrLPARAM, pLPARAM, sizeLParam, dwNumBytesXferred) then RaiseLastOSError;
finally
GetExitCodeThread(hThread, lSendMessageResult);
CloseHandle(hThread);
Result := lSendMessageResult;
end;
finally
VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
end;
finally
VirtualFreeEx(hProcess, pDataRemote, 0, MEM_RELEASE);
end;
finally
CloseHandle(hProcess);
end;
end;
Now the code to manipulate the DTP becomes much simpler:
uses
..., CommCtrl;
var
Wnd: HWND;
Pid: DWORD;
nm: TNMDateTimeChange;
begin
Wnd := ...; // the HWND of the DateTimePicker control
// get PID of DTP's owning process
GetWindowThreadProcessId(Wnd, Pid);
// prepare DTP message data
nm.nmhdr.hwndFrom := Wnd;
nm.nmhdr.idFrom := GetDlgCtrlID(Wnd); // VCL does not use CtrlIDs, but just in case
nm.nmhdr.code := DTN_DATETIMECHANGE;
nm.dwFlags := GDT_VALID;
DateTimeToSystemTime(..., nm.st); // the desired date/time value
// now send the DTP messages from within the DTP process...
if SendMessageRemote(Pid, Wnd, DTM_SETSYSTEMTIME, GDT_VALID, #nm.st, SizeOf(nm.st)) <> 0 then
SendMessageRemote(Pid, GetParent(Wnd), WM_NOTIFY, nm.nmhdr.idFrom, #nm, sizeof(nm));
end;
If all goes well, the TDateTimePicker will now update its internal TDateTime variable to match the SYSTEMTIME that you send to it.
Just to expand on Remy Lebeau's post, which pretty much gives a solution.
There are two issues with his ThreadFunc, or the thread procedure that will be called in remote process:
Most certainly AfterThreadFunc method will be optimized out of the Release build, so the size of ThreadFunc procedure will not be set correctly.
Many compilers doing a Debugger build will add additional debugger checks to methods, which will most certainly make ThreadFunc crash in the injected remote process.
I thought of the easiest way to address what I stated above, but unfortunately there seems to be no better way other than to use assembler. Obviously, due to that, the following applies only to 32-bit processes.
Here's my C implementation of Remy Lebeau's solution (sorry, I don't use Delphi.)
First struct definitions:
#define MAX_BUF_SIZE (512)
typedef LRESULT (WINAPI *SENDMESSAGE)(HWND,UINT,WPARAM,LPARAM);
struct INJDATA
{
//IMPORTANT: If ANY of this struct members are changed, you will need to
adjust the assembler code below!
SENDMESSAGE fnSendMessage; // pointer to user32!SendMessage
HWND hwnd;
UINT msg;
WPARAM wParam;
BYTE arrLPARAM[MAX_BUF_SIZE];
};
Then collect static pointers once when the app starts, no need to do it every time our method is invoked. For that move them all into its own struct:
struct SENDMSG_INJ_INFO{
SENDMESSAGE fnSendMessageRemote;
int ncbSzFnSendMessageRemote; //Size of 'fnSendMessageRemote' in BYTEs
HMODULE hUser32;
SENDMESSAGE pfnSendMessage; //SendMessage API pointer
SENDMSG_INJ_INFO() :
fnSendMessageRemote(NULL)
, ncbSzFnSendMessageRemote(0)
{
hUser32 = ::LoadLibrary(L"user32");
pfnSendMessage = hUser32 ? (SENDMESSAGE)GetProcAddress(hUser32, "SendMessageW") : NULL;
int ncbSz = 0;
SENDMESSAGE pfn = NULL;
__asm
{
//Get sizes & offsets
mov eax, lbl_code_begin
mov dword ptr [pfn], eax
mov eax, lbl_code_after
sub eax, lbl_code_begin
mov dword ptr [ncbSz], eax
jmp lbl_code_after
lbl_code_begin:
//Thread proc that will be executed in remote process
mov eax,dword ptr [esp+4]
mov edx,dword ptr [eax+0Ch]
lea ecx,[eax+10h]
push ecx
mov ecx,dword ptr [eax+8]
push edx
mov edx,dword ptr [eax+4]
mov eax,dword ptr [eax]
push ecx
push edx
call eax
ret
lbl_code_after:
}
ncbSzFnSendMessageRemote = ncbSz;
fnSendMessageRemote = pfn;
}
~SENDMSG_INJ_INFO()
{
if(hUser32)
{
::FreeLibrary(hUser32);
hUser32 = NULL;
}
}
};
Now the question for people that don't know assembler is how to get that procedure in asm. It's actually pretty easy. Put the following method into your Release build (note Release, it's important) and then set a debugger breakpoint on prototypeThreadFuncSendMsg call and copy the asm from it:
//.h hile
LRESULTDWORD __declspec(noinline) prototypeThreadFuncSendMsg(INJDATA *pData);
//.cpp file
LRESULT prototypeThreadFuncSendMsg(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 );
}
The important point is to make compiler not to inline it. For Visual Studio I added __declspec(noinline) for that.
Then we need a global variable to store our pointers:
//Define on a global scope
SENDMSG_INJ_INFO sii;
And now the method that calls it all (just a slightly adjusted code from the original post -- I just added a couple of error checks & a timeout):
//.h file
static BOOL SendMessageTimeoutRemote(DWORD dwProcessId, HWND hwnd, UINT msg, WPARAM wParam, LPVOID pLPARAM, size_t sizeLParam, DWORD dwmsMaxWait = 5 * 1000, LRESULT* plOutSendMessageReturn = NULL);
//.cpp file
BOOL SendMessageTimeoutRemote(DWORD dwProcessId, HWND hwnd, UINT msg, WPARAM wParam, LPVOID pLPARAM, size_t sizeLParam, DWORD dwmsMaxWait, LRESULT* plOutSendMessageReturn)
{
//'dwmsMaxWait' = max number of ms to wait for result, or INFINITE to wait for as long as needed
//'plOutSendMessageReturn' = if not NULL, will receive the value returned from calling SendMessage API in remote process
//RETURN:
// = TRUE if message was sent successfully (check returned value in 'plOutSendMessageReturn')
BOOL bRes = FALSE;
HANDLE hProcess = NULL; // the handle of the remote process
HINSTANCE hUser32 = NULL;
INJDATA *pDataRemote = NULL; // the address (in the remote process) where INJDATA will be copied to;
DWORD *pCodeRemote = NULL; // 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
{
if (sii.pfnSendMessage == NULL)
__leave;
if(sizeLParam < 0 ||
sizeLParam > MAX_BUF_SIZE)
{
//Too much data
ASSERT(NULL);
__leave;
}
// Initialize INJDATA
INJDATA DataLocal =
{
sii.pfnSendMessage,
hwnd, msg, wParam
};
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;
if(!WriteProcessMemory( hProcess, pDataRemote, &DataLocal, sizeof(INJDATA), (SIZE_T *)&dwNumBytesXferred ) ||
dwNumBytesXferred != sizeof(INJDATA))
__leave;
// Calculate the number of bytes that ThreadFunc occupies
int cbCodeSize = sii.ncbSzFnSendMessageRemote;
if(cbCodeSize <= 0)
__leave;
if(!sii.fnSendMessageRemote)
__leave;
// 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;
if(!WriteProcessMemory( hProcess, pCodeRemote, sii.fnSendMessageRemote, cbCodeSize, (SIZE_T *)&dwNumBytesXferred ) ||
dwNumBytesXferred != cbCodeSize)
__leave;
// Start execution of remote ThreadFunc
hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE) pCodeRemote,
pDataRemote, 0 , &dwThreadId);
if (hThread == NULL)
__leave;
//Wait for thread to finish
DWORD dwR = WaitForSingleObject(hThread, dwmsMaxWait);
if(dwR == WAIT_OBJECT_0)
{
//Get return value
if(GetExitCodeThread(hThread, (PDWORD)&lSendMessageReturn))
{
// Copy LPARAM back (result is in it)
if(ReadProcessMemory( hProcess, pDataRemote->arrLPARAM, pLPARAM, sizeLParam, (SIZE_T *)&dwNumBytesXferred) &&
dwNumBytesXferred == sizeLParam)
{
//Done
bRes = TRUE;
}
}
}
}
__finally
{
//Clean up
if ( pDataRemote != 0 )
{
VirtualFreeEx( hProcess, pDataRemote, 0, MEM_RELEASE );
pDataRemote = NULL;
}
if ( pCodeRemote != 0 )
{
VirtualFreeEx( hProcess, pCodeRemote, 0, MEM_RELEASE );
pCodeRemote = NULL;
}
if ( hThread != NULL )
{
CloseHandle(hThread);
hThread = NULL;
}
if ( hProcess )
{
CloseHandle (hProcess);
hProcess = NULL;
}
}
if(plOutSendMessageReturn)
*plOutSendMessageReturn = lSendMessageReturn;
return bRes;
}
And finally my requested method to set the date/time:
BOOL SetDateCtrlRemote(HWND hWnd, SYSTEMTIME* pSt)
{
//Set date/time in the DateTimePicker control with 'hWnd' in another process
//'pSt' = local date/time to set
//RETURN:
// = TRUE if done
BOOL bRes = FALSE;
NMDATETIMECHANGE dtc = {0};
if(hWnd &&
pDt &&
pSt)
{
memcpy(&dtc.st, pSt, sizeof(*pSt));
//Get process ID for Digi
DWORD dwProcID = 0;
::GetWindowThreadProcessId(hWnd, &dwProcID);
if(dwProcID)
{
int nCntID = ::GetDlgCtrlID(hWnd);
if(nCntID)
{
HWND hParentWnd = ::GetParent(hWnd);
if(hParentWnd)
{
dtc.dwFlags = GDT_VALID;
dtc.nmhdr.hwndFrom = hWnd;
dtc.nmhdr.code = DTN_DATETIMECHANGE;
dtc.nmhdr.idFrom = nCntID;
LRESULT lRes = 0;
//First change the control itself -- use 2 sec timeout
if(SendMessageTimeoutRemote(dwProcID, hWnd, DTM_SETSYSTEMTIME, GDT_VALID, &dtc.st, sizeof(dtc.st), 2 * 1000, &lRes) &&
lRes != 0)
{
//Then need to send notification to the parent too!
if(SendMessageTimeoutRemote(dwProcID, hParentWnd, WM_NOTIFY, dtc.nmhdr.idFrom, &dtc, sizeof(dtc), 2 * 1000))
{
//Done
bRes = TRUE;
}
}
}
}
}
}
return bRes;
}
I know it's a lot of code, but once you do it once, it will all work and you can reuse that method for other calls.
Again, thanks to Remy Lebeau!

c++ Run-Time Check Failure #0 - The value of ESP was not properly saved across ... Points to check for simple worker thread

I have a dialog. in this dialog ::OnInitDialog() I create a thread AfxBeginThread((AFX_THREADPROC)MyThreadProc, NULL); It crashes when I close the dialog with run time check failure, and it is pointing to thrdcore.cpp file (Microsoft Foundation Classes C++ library)
// first -- check for simple worker thread
DWORD nResult = 0;
if (pThread->m_pfnThreadProc != NULL)
{
nResult = (*pThread->m_pfnThreadProc)(pThread->m_pThreadParams);
ASSERT_VALID(pThread);
}
I have a code to kill the thread OnClose function, but it doesn't solve the issue. Can some help, what I am missing? My code for
HANDLE m_hExit;
DWORD dwResult = 0;
unsigned threadID = 0;
...
OnInitDialog()
{...
m_hExit = (HANDLE)AfxBeginThread((AFX_THREADPROC)MyThreadProc, NULL);
}
OnClose()
{
dwResult = WaitForSingleObject(m_hExit, 0);
if (dwResult == WAIT_TIMEOUT)
{
printf("The thread is still running...\n");
}
else
{
printf("The thread is no longer running...\n");
}
Sleep(10000);
dwResult = WaitForSingleObject(m_hExit, 0);
if (dwResult == WAIT_TIMEOUT)
{
printf("The thread is still running...\n");
}
else
{
printf("The thread is no longer running...\n");
}
CDialog::OnClose();
}
thread function is very big((((
AfxBeginThread is documented as requiring the threadproc to be
UINT __cdecl MyControllingFunction( LPVOID pParam );
Your comment says your function is
UINT WINAPI MyThreadProc( LPVOID pParam )
WINAPI is defined as _stdcall (see here)
So you have a mismatch of calling conventions. As others already commented, the cast is suspicious. In fact, that's the only reason your code is compiling. If you remove the cast, the compiler should show an error.
The solution is to remove the cast and then fix the calling convention of your function. Once that code compiles correctly without the cast, it should run properly without corrupting the stack.

Error while Trying to Hook "TerminateProcess" Function. Target Process crashes. Can anyone help me?

Debugging with visual studio 2005 The following Error Displayed :
Unhandled exception at 0x00000000 in procexp.exe: 0xC0000005: Access
violation reading location 0x00000000.
And Thread Information:
2704 Win32 Thread 00000000 Normal 0
extern "C" VDLL2_API BOOL WINAPI MyTerminateProcess(HANDLE hProcess,UINT uExitCode)
{
SetLastError(5);
return FALSE;
}
FARPROC HookFunction(char *UserDll,FARPROC pfn,FARPROC HookFunc)
{
DWORD dwSizeofExportTable=0;
DWORD dwRelativeVirtualAddress=0;
HMODULE hm=GetModuleHandle(NULL);
FARPROC pfnOriginalAddressToReturn;
PIMAGE_DOS_HEADER pim=(PIMAGE_DOS_HEADER)hm;
PIMAGE_NT_HEADERS pimnt=(PIMAGE_NT_HEADERS)((DWORD)pim +
(DWORD)pim->e_lfanew);
PIMAGE_DATA_DIRECTORY
pimdata=(PIMAGE_DATA_DIRECTORY)&(pimnt->OptionalHeader.DataDirectory);
PIMAGE_OPTIONAL_HEADER pot=&(pimnt->OptionalHeader);
PIMAGE_DATA_DIRECTORY
pim2=(PIMAGE_DATA_DIRECTORY)((DWORD)pot+(DWORD)104);
dwSizeofExportTable=pim2->Size;
dwRelativeVirtualAddress=pim2->VirtualAddress;
char *ascstr;
PIMAGE_IMPORT_DESCRIPTOR
pimexp=(PIMAGE_IMPORT_DESCRIPTOR)(pim2->VirtualAddress + (DWORD)pim);
while(pimexp->Name)
{
ascstr=(char *)((DWORD)pim + (DWORD)pimexp->Name);
if(strcmpi(ascstr,UserDll) == 0)
{
break;
}
pimexp++;
}
PIMAGE_THUNK_DATA
pname=(PIMAGE_THUNK_DATA)((DWORD)pim+(DWORD)pimexp->FirstThunk);
LPDWORD lpdw=&(pname->u1.Function);
DWORD dwError=0;
DWORD OldProtect=0;
while(pname->u1.Function)
{
if((DWORD)pname->u1.Function == (DWORD)pfn)
{
lpdw=&(pname->u1.Function);
VirtualProtect((LPVOID)lpdw,sizeof(DWORD),PAGE_READWRITE,&OldProtect);
pname->u1.Function=(DWORD)HookFunc;
VirtualProtect((LPVOID)lpdw,sizeof(DWORD),PAGE_READONLY,&OldProtect);
return pfn;
}
pname++;
}
return (FARPROC)0;
}
FARPROC CallHook(void)
{
HMODULE hm=GetModuleHandle(TEXT("Kernel32.dll"));
FARPROC fp=GetProcAddress(hm,"TerminateProcess");
HMODULE hm2=GetModuleHandle(TEXT("vdll2.dll"));
FARPROC fpHook=GetProcAddress(hm2,"MyTerminateProcess");
dwAddOfTerminateProcess=HookFunction("Kernel32.dll",fp,fpHook);
if(dwAddOfTerminateProcess == 0)
{
MessageBox(NULL,TEXT("Unable TO Hook Function."),TEXT("Parth"),MB_OK);
}
else
{
MessageBox(NULL,TEXT("Success Hooked."),TEXT("Parth"),MB_OK);
}
return 0;
}
Thanks in advance for any help.
004118AC mov esi,esp
004118AE push 0
004118B0 mov eax,dword ptr [hProc]
004118B3 push eax
004118B4 call dword ptr[__imp__TerminateProcess#8(4181E4h)]
004118BA cmp esi,esp
esi returned zero. why ?
What is VDLL2_API defined as? It may be interfering with the calling convention (which is meant to be WINAPI for this function, as you write it later on the same line).
Stack problems on exit (ESI, ESP) usually indicate that you have your calling conventions mixed up. You appear to have used FARPROC consistently everywhere else, but since you know the exact prototype of the function, try typedef-ing that as the type to use instead:
typedef BOOL (WINAPI *TERMINATEPROCESS_PROC)(HANDLE, UINT);
Now use TERMINATEPROCESS_PROC everywhere instead of FARPROC.
Don't write this kind of code yourself. Use the Detours library from Microsoft Research.