high6 Posted March 9, 2009 Posted March 9, 2009 (edited) So the other day I learned about shared memory in dlls. I was wondering can a dll call a function in an external process that has the dll?Process1|DllProcess2|DllProcess1 calls AnExportAnExport(called from Process1) calls a callback in Process2Is this possible? Edited March 9, 2009 by high6
Killboy Posted March 9, 2009 Posted March 9, 2009 (edited) You can do that using CreateRemoteThread.However, it only takes one additional param for the thread.So you'll have to use a stub that takes a pointer to a struct with all the needed params.The stub calls the actual function with the params taken from the struct.Something like this:DWORD Function1(DWORD Param1, DWORD Param2, DWORD Param3){ return 0;}DWORD __stdcall SuperStub(Func1Struct * F1S){ return Function1(F1S->Param1, F1S->Param2, F1S->Param3);}Then you'll load the DLL into your own process (that requires an empty DllMain or a check for which process it's in) and get the address of the exported stub.What's left is adjusting the address to take the different module base in the second process into account.modProc2 = GetLoadedModuleBase(hProcess2, "my.dll");mod = LoadLibrary("my.dll");ULONG_PTR SuperStubAddr = (ULONG_PTR)GetProcAddress(mod, "SuperStub") - (ULONG_PTR)mod + modProc2;Func1Struct F1S;F1S.Param1 = 0;F1S.Param2 = 2;F1S.Param3 = 222;mem = VirtualAllocEx(hProcess2, 0, sizeof(Func1Struct), ....);WriteProcessMemory(hProcess2, mem, sizeof(Func1Struct), &F1S, ...);Thread = CreateRemoteThread(hProcess2, ...., SuperStubAddress, mem);if(WAIT_0 == WaitForSingleObject(Thread, INFINITE)){ DWORD Exitcode; GetExitCodeThread(Thread, &Exitcode); // Return value // Success}GetLoadedModuleBase could be implemented using CreateToolhelpSnapshot or psapi functions, there should be enough on google. Edited March 9, 2009 by Killboy
high6 Posted March 9, 2009 Author Posted March 9, 2009 Just wondering if you can without CreateRemoteThread because if you were to call the function a lot, creating/destroying tons of threads doesn't seem effective.I was thinking about Just having a thread loop and it checks a vector of callbacks and when there is a callback it calls it and removes it from the vector. Only problem with that personally is I don't know how to structure the loop.while(true){ if (!TheVector.Empty()) { //etc } sleep(1);}How do you properly do that loop? (That loop right there uses 10-20% of the cpu while idling).
Killboy Posted March 9, 2009 Posted March 9, 2009 You might wanna look into using WM_COPYDATA.You just have to create an empty window in the Dll, create a message loop and in the window proc check for WM_COPYDATA.Some example code:Process1 Event = CreateEvent(0, true, false, EventName); if(!Event) return false; if(!InjectDll(hProcess, DllPath)){ return false; } if(WAIT_OBJECT_0 != WaitForSingleObject(Event, 5000)){ CloseHandle(Event); return false; } CloseHandle(Event); DllWindow = FindWindow(WindowName, NULL); if(!DllWindow){ return false; } CallbackDataStruct CallbackData; CallbackData.Address = 0x1212363; // ... COPYDATASTRUCT CDS; CDS.dwData = CALLBACK_ID; CDS.cbData = sizeof(CallbackData); CDS.lpData = &CallbackData; RetVal = SendMessage(DllWindow, WM_COPYDATA, (WPARAM)WndMain, (LPARAM)&CDS);In the Dll in Process2:BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, void * lpReserved){ switch(fdwReason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hModule); HANDLE hThread; hThread = CreateThread(0, 0, WindowThread, 0, 0, 0); CloseHandle(hThread); break; } return true;}DWORD CALLBACK WindowThread(void *){HANDLE Event;MSG msg; EmptyWindow = CreateEmptyWindow(WindowName, WndProc); if(!EmptyWindow) return false; Event = OpenEvent(EVENT_MODIFY_STATE, false, EventName); SetEvent(Event); CloseHandle(Event); while(GetMessage(&msg, NULL, 0, 0) == TRUE) { DispatchMessage(&msg); } return 0;}HWND CreateEmptyWindow(char * Name, WNDPROC WndProc){ WNDCLASS wc = {0}; wc.lpfnWndProc = WndProc; wc.lpszClassName = Name; RegisterClass(&wc); return CreateWindow(Name, Name, WS_DISABLED, 0, 0, 0, 0, NULL, NULL, NULL, NULL);}LRESULT CALLBACK WndProc(HWND Window, UINT Message, WPARAM wParam, LPARAM lParam){COPYDATASTRUCT * cds; switch(Message){ case WM_COPYDATA: cds = (COPYDATASTRUCT *)lParam; switch(cds->dwData) { case CALLBACK_ID: if(cds->cbData == sizeof(CallbackDataStruct)){ CallbackDataStruct CB; CB = *(CallbackDataStruct *)cds->lpData; return CB.Address(CB.Param1, ...); } break; } break; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(Window, Message, wParam, lParam);}
high6 Posted March 9, 2009 Author Posted March 9, 2009 (edited) I always have trouble with WM_COPYDATA not working between C#/C++.Also in an older thread I was told not to use it.I guess I could use shared memory and SendMessage. Edited March 9, 2009 by high6
Killboy Posted March 9, 2009 Posted March 9, 2009 There shouldn't be any difference between WM_COPYDATA and a self-implemented version using SendMessage.No idea why it doesn't work with C++/C# though, maybe a security issue.If you're on Vista, this might work:http://msdn.microsoft.com/en-us/library/ms632675.aspxDunno exactly though as it wouldn't validate and copy the data then anymore :/
britedream Posted March 27, 2009 Posted March 27, 2009 (edited) I just want you to note that applications are not syncronized in windows, sendmessage directly from 1 to 2 then from 2 to 1 is a recipe to lock your applications. Edited March 27, 2009 by britedream
genuine_ Posted November 13, 2009 Posted November 13, 2009 Have you looked into Named Pipes for IPC? Namd pipes are very effective and quick, You could also use IPC with Registry Keys, but thats not good for what you want since you plan on transferring data.
atom0s Posted November 14, 2009 Posted November 14, 2009 With injection though, I would suggest staying away from pipes for extreme cases for data transfer between two processes. For work related testing, I put MMF and Named Pipes through some stress tests to see what their limits were, pipes died and locked up constantly as the data size pushed between the processes grew. MMF, if created and wrapped around your own handler, worked flawlessly. You will need to do a bit more work if you use MMFs though compared to pipes. (Just a suggestion.)You could also try using WM_USER with SendMessage/PostMessage for handling specific messages between your processes, but for this topics purpose, calling shared memory, I would go with CreateRemoteThread with injected code to get the job done quickly.If you use the WM_USER message method, check this API out for more info:/>http://msdn.microsoft.com/en-us/library/ms644947(VS.85).aspx
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now