Jump to content
Tuts 4 You

Cross process calling?


high6

Recommended Posts

Posted (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|Dll

Process2|Dll

Process1 calls AnExport

AnExport(called from Process1) calls a callback in Process2

Is this possible?

Edited by high6
Posted (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 by Killboy
Posted

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).

Posted

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);
}
Posted (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 by high6
Posted

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.aspx

Dunno exactly though as it wouldn't validate and copy the data then anymore :/

  • 3 weeks later...
Posted (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 by britedream
  • 7 months later...
Posted

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.

Posted

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

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...