Jump to content
Tuts 4 You

Cross process calling?


Recommended Posts

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 calls AnExport

AnExport(called from Process1) calls a callback in Process2

Is this possible?

Edited by high6
Link to comment

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 by Killboy
Link to comment

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.



if (!TheVector.Empty())






How do you properly do that loop? (That loop right there uses 10-20% of the cpu while idling).

Link to comment

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:


	Event = CreateEvent(0, true, false, EventName);
return false; if(!InjectDll(hProcess, DllPath)){
return false;
} if(WAIT_OBJECT_0 != WaitForSingleObject(Event, 5000)){
return false;
CloseHandle(Event); DllWindow = FindWindow(WindowName, NULL);
return false;
} CallbackDataStruct CallbackData; CallbackData.Address = 0x1212363;
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)
HANDLE hThread;
hThread = CreateThread(0, 0, WindowThread, 0, 0, 0);
} return true;
}DWORD CALLBACK WindowThread(void *){
MSG msg; EmptyWindow = CreateEmptyWindow(WindowName, WndProc);
return false; Event = OpenEvent(EVENT_MODIFY_STATE, false, EventName);
CloseHandle(Event); while(GetMessage(&msg, NULL, 0, 0) == TRUE)
} 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){
cds = (COPYDATASTRUCT *)lParam;
if(cds->cbData == sizeof(CallbackDataStruct)){
CallbackDataStruct CB;
CB = *(CallbackDataStruct *)cds->lpData;
return CB.Address(CB.Param1, ...);
return 0;
} return DefWindowProc(Window, Message, wParam, lParam);
Link to comment

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 by high6
Link to comment
  • 3 weeks later...

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 by britedream
Link to comment
  • 7 months later...

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.

Link to comment

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:

Link to comment

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Create New...