Thread: CreateRemoteThread() for subclassing

  1. #1
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401

    CreateRemoteThread() for subclassing

    Against Kyle Marsh of MSDN's advice, I am trying to subclass a foreign window using CreateRemoteThread(). I'm having trouble working out how to use this function. I have a few questions.

    1. Do I create the thread function in my process space, then WriteProcessMemory() to get it to the target process?

    2. How do I get my window procedure to the target process space?

    3. Once I have the thread there, how can I locate the window I was trying to subclass? I was thinking of passing the HWND through as the parameter, but I'm not sure.

    I've never created extra threads before, let alone sent them to other processes, so this is all new to me.
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  2. #2
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    >>1. Do I create the thread function in my process space, then WriteProcessMemory() to get it to the target process?

    Jeff Prosise wrote a book in the late 90s and devoted the last chapeter to exactly what you are doing.

    He tried various things including writing assembler code that can execute at any point.......but finally settled on a bit of genious -

    Create your code in a dll......Call LoadLibrary for Kernel32.dll and get the process address for LoadLibraryA. Now write the name of you dll as a string into the remote process. Call CreateRemoteThread, but for the lpStartAddress param pass your address for LoadLibraryA and for the lpParameter pass the address of the string in the other address space. The code should then load your dll and the code you put in the DllMain proc will execute in the remote process.

    The reason this works is that the function definition for LoadLibrary is the same as the ThreadProc pointer that you pass to CreateRemoteThread

    DWORD WINAPI ThreadProc(LPVOID);
    HMODULE LoadLibrary(LPCTSTR);

    Both use STDCALL and both pass 4 bytes and return 4 bytes (under 32bit windows anyway)

    Also, there's a sort of guarantee that Kernel32.dll is loaded at the same address in all processes - so it seems to work.

    I've never tried this myself, but I understand how it can work


    >>2. How do I get my window procedure to the target process space?

    See Above

    >>3. Once I have the thread there, how can I locate the window I was trying to subclass? I was thinking of passing the HWND through as the parameter, but I'm not sure.

    No that HWND will not be applicable to another process. Once you are executing in the remote process, use FindWindow to locate the window

  3. #3
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    I think I understand. Although this means I have to split my code up between my application and a dll. Is there any way I can put the subclass code into the dll, but keep the window procedure in my application, using WriteProcessMemory() to get it over there?
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  4. #4
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Originally posted by bennyandthejets
    I think I understand. Although this means I have to split my code up between my application and a dll. Is there any way I can put the subclass code into the dll, but keep the window procedure in my application, using WriteProcessMemory() to get it over there?
    Doubtfull.... unless you want to write it all in assembler

  5. #5
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    What aspect of the procedure requires the use of assembler?
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  6. #6
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Sorry, I misread your post...

    There would be ways of doing this I suppose, but as you are crossing the process boundry for each windows message, then itwould slow the "hooked" window to a crawl. Especially if you are using WriteMemory!

    Tell me what you want to do with this hooked window and I might be able to answer better.

  7. #7
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    I'm basically trying to increase the functionality of another program, to customize it for my needs, let's say. I want to subclass the window procedure of a list view control to detect when new items are created, and similar kinds of things.

    I was thinking, I would write the window procedure in my application but then write it into the other process using WriteProcessMemory(). Then I would inject the DLL, which would subclass the window with a pointer to that window procedure.

    One problem I can think of is that the DLL won't know the address of the window procedure. But surely there is a way.
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  8. #8
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Originally posted by bennyandthejets
    I'm basically trying to increase the functionality of another program, to customize it for my needs, let's say. I want to subclass the window procedure of a list view control to detect when new items are created, and similar kinds of things.

    I was thinking, I would write the window procedure in my application but then write it into the other process using WriteProcessMemory(). Then I would inject the DLL, which would subclass the window with a pointer to that window procedure.

    One problem I can think of is that the DLL won't know the address of the window procedure. But surely there is a way.
    Writing executable code from 1 process to another is very difficult to do. Code might be written to exist in 1 place in memory......you would need to allocate extra room for the variables your code accesses.......then you would need to change the machine code of your code to reference the new area allocated for the variables...also, there's the hazard that the code accesses another function in a library that isnt loaded into the remote process!.

    All of these concerns are taken care of if you house the code into a dll - it's relocatable, it allocates room for it's own variables and it resolves to/loads any libraries it needs - all automatically.

    Your best bet is to house the window procedure in a dll, and use a names pipe or mailslot to send information found (IE new additions to a list view) back to your app......

  9. #9
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Also....hang on a minute!

    Have you considered SetWindowsHook? That's much easier & safer to use for your purposes than CreateRemoteThread/WriteMemory etc....

  10. #10
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    I have looked at hooks, but I really can't understand how they are used. Could you give me an example?
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  11. #11
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    I'm really overwhelmed here. I've made a DLL with a window procedure in it, and in another project I've attempted to use CreateRemoteThread() to load the library into the other process. It simply won't work. I'll try to debug it myself, but in the meantime, here's a bit of my code:

    Dll main file:
    Code:
    #include <windows.h>
    #define DLL_EXPORT
    #include "bfSubClass.h"
    
    BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
    {
    	switch (fdwReason)
    	{
    	case DLL_PROCESS_ATTACH:
    		{
    			HWND hList;
    			
    			hList=FindListView();
    
    			SubClass(hList,ListProc);
    
    			MessageBox(NULL,"Dll loaded","Notify",MB_OK);
    		}
    	case DLL_PROCESS_DETACH:
    		{
    			HWND hList;
    
    			hList=FindListView();
    
    			SendMessage(hList,WM_USER+1,2,0);
    		}
    	default:
    		break;
    	}
    
    	return TRUE;
    }
    
    HWND FindListView(void)
    {
    	DWORD dwProcId;
    	DWORD dwGetProcId;
    	HWND hFind=NULL;
    	HWND hChildFind=NULL;
    
    	dwProcId=GetCurrentProcessId();
    
    	hFind=FindWindow("DC++",NULL);
    	GetWindowThreadProcessId(hFind,&dwGetProcId);
    
    	if (dwGetProcId==dwProcId)
    		hChildFind=FindWindowEx(hFind,NULL,"SysListView32",NULL);
    	
    	return hChildFind;
    }
    
    BOOL DS SubClass(HWND hSub,WNDPROC lpfnWndProc)
    {
    	WNDPROC oldProc;
    
    	oldProc=(WNDPROC)SetWindowLong(hSub,GWL_WNDPROC,(LONG)lpfnWndProc);
    	
    	SendMessage(hSub,WM_USER+1,1,(LPARAM)oldProc);
    
    	return TRUE;
    }
    
    LRESULT CALLBACK ListProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
    {
    	static WNDPROC oldProc;
    
    	switch (msg)
    	{
    	case (WM_USER+1):
    		if ( (wParam==1) && (lParam) )
    			oldProc=(WNDPROC)lParam;
    		if ( (wParam==2) && (!lParam) )
    			SetWindowLong(hwnd,GWL_WNDPROC,(LONG)oldProc);
    	
    	case WM_LBUTTONUP:
    		MessageBox(NULL,"YO BUTTON CLICKED","NOTIFY",MB_OK);
    		break;
    
    	default:
    		break;
    	}
    
    	return CallWindowProc(oldProc,hwnd,msg,wParam,lParam);
    }
    Dll header:
    Code:
    #ifndef bfSCH
    #define bfSCH
    
    #ifndef DLL_EXPORT
    #define DS __declspec(dllimport) 
    #else 
    #define DS __declspec(dllexport)
    #endif
    
    HWND DS FindListView(void);
    BOOL DS SubClass(HWND,WNDPROC);
    LRESULT CALLBACK DS ListProc(HWND,UINT,WPARAM,LPARAM);
    
    #endif
    Is there anything wrong with that?
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  12. #12
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    Actually, maybe I'll just work through what I did, in the other application, not the dll.

    1. I found the list view control I wanted to subclass
    2. I got the process ID (GetWindowThreadProcessId())
    3. I opened the process, successfully, for PROCESS_ALL_ACCESS
    4. I got the ProcAddress for LoadLibraryA:
    Code:
    WNDPROC LLProc=(WNDPROC)GetProcAddress(GetModuleHandle("kernel32.dll"),"LoadLibraryA");
    5. I allocated some memory over there with VirtualAllocEx, and wrote a string containing the dll module name:
    Code:
    chModParam=VirtualAllocEx(hProc,NULL,64,MEM_COMMIT,PAGE_READWRITE);
    		WriteProcessMemory(hProc,chModParam,(LPVOID)"bfSubClass.dll",15,NULL);
    6. I attempted it.
    Code:
    hThread=CreateRemoteThread(hProc,NULL,NULL,(LPTHREAD_START_ROUTINE)LLProc,&chModParam,NULL,&dwThread);
    7. Nothing happened.
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  13. #13
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Hooks are a lengthy example and there are plenty across the web an a few on this board.

    But as I did suggest how to use the LoadLibrary/CreateRemoteThread method, I will help you with it.

    In my example I'm going to hook "calc.exe".......so calc must be running for it to work....also CreateRemoteThread will return without error even if LoadLibrary didn load your dll - that caught me for a minute until I realised that my dll has to be in a folder where dll are looked for (Windows,Windows\System32)...so remember to copy the dll into one of those places before trying

    Here's the loader code

    Code:
    #include <windows.h>
    #include <iostream>
    #include <string>
    
    const std::string strMod = "InjectionDll.dll";
    
    int main()
    {
    	HWND hWnd = FindWindow(0,"Calculator");
    	if(hWnd == 0)
    	{
    		std::cout << "Unable to find Calculator";
    		return 0;
    	}
    
    	DWORD dwProc;
    	
    	GetWindowThreadProcessId(hWnd,&dwProc);
    
    	HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProc);
    	if(hProc == 0)
    	{
    		std::cout << "Unable to open process";
    		return 0;
    	}
    
    	HMODULE hKern = GetModuleHandle("kernel32.dll");
    	if(hKern == 0)
    	{
    		std::cout << "Unable to get Kernel32 Handle";
    		return 0;
    	}
    
    	WNDPROC lpfLoadLibraryA = reinterpret_cast<WNDPROC>
    		(GetProcAddress(hKern,"LoadLibraryA"));
    	if(lpfLoadLibraryA == 0)
    	{
    		std::cout << "Unable to get LoadLibrary Func";
    		return 0;
    	}
    
    	LPVOID lpMemAddress = VirtualAllocEx(hProc,0,strMod.length() + 1,
    		MEM_COMMIT,PAGE_READWRITE);
    	if(lpMemAddress == 0)
    	{
    		std::cout << "Unable to alloc memory";
    		return 0;
    	}	
    	
    	SIZE_T stBytesWritten;
    	if(!WriteProcessMemory(hProc,lpMemAddress,strMod.c_str(),
    		strMod.length() + 1,&stBytesWritten))
    	{
    		std::cout << "Unable to write memory";
    		return 0;
    	}	 
    
    	DWORD dwThreadID;
    	HANDLE hRemThread = CreateRemoteThread(hProc,0,0,
    		reinterpret_cast<LPTHREAD_START_ROUTINE>(lpfLoadLibraryA),
    		lpMemAddress,0,&dwThreadID);
    	if(hRemThread == 0)
    	{
    		std::cout << "Unable to create thread";
    		return 0;
    	}
    
    	std::cout << "Running hook..." << std::endl;
    
    	WaitForSingleObject(hRemThread,INFINITE);
    
    	std::cout << "Hook ended" << std::endl;
    
    
    }
    Here's the dll code

    Code:
    #include <windows.h>
    
    BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
    {
    	if(fdwReason == DLL_PROCESS_ATTACH)
    	{
    		MessageBox(HWND_DESKTOP,"Attached","Hooker",MB_OK);
    	}
    	return TRUE;
    }
    Works perfectly on mine

  14. #14
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Oh...and in my first thread I said Jeff Prosise....I meant Jeff Richter......DOH!

  15. #15
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    My compiler (VC++ 6.0) flagged an error for the following:

    Code:
    if(!WriteProcessMemory(hProc,lpMemAddress,strMod.c_str(),
    		strMod.length() + 1,&stBytesWritten))
    Parameter 3 should have been LPVOID, so I just type cast it. I assume you use a compiler that allows your method.

    As for all the casting, do I need to use those advanced casts? Can't I just type cast the old-fashioned way?
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. CreateRemoteThread in a child process
    By electrohippi in forum Windows Programming
    Replies: 7
    Last Post: 11-24-2008, 10:15 AM
  2. CreateRemoteThread in suspended app problem
    By doy2001 in forum Windows Programming
    Replies: 5
    Last Post: 08-15-2008, 07:31 AM
  3. createremotethread and writeprocessmemory problems
    By Hawkin in forum Windows Programming
    Replies: 3
    Last Post: 01-19-2008, 09:33 AM
  4. createremotethread and writeprocessmemory problems
    By cloudy in forum C++ Programming
    Replies: 1
    Last Post: 07-03-2005, 05:06 PM
  5. Detecting CreateRemoteThread
    By IcyDeath in forum Windows Programming
    Replies: 1
    Last Post: 12-25-2004, 12:31 PM