Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a cross-process function pointer

I have a Visual Studio 2008 C++ project for Windows Mobile 6 with two processes. Both of which I would like to have access to the same function which is contained in process1.

That function is Buzz:

struct TEST_STRUCT
{
    int bar;
    WCHAR foo[ 20 ];
};

typedef int( *pfn_Buzz )( TEST_STRUCT* );

int Buzz( TEST_STRUCT* info );

Process1 contains the definition for Buzz and creates a function pointer for it in a memory-mapped file:

int Buzz( TEST_STRUCT* info )
{
    info->bar = 1;
    wsprintf( info->foo, L"Hello!" );
    return 100;
}

int _tmain( int argc, _TCHAR* argv[] )
{
    // create a memory-mapped file shared memory space that can be read by any process
    HANDLE mapping = ::CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof( pfn_Buzz ) , NULL );
    LPVOID buzz_addr = ::MapViewOfFile( mapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof( pfn_Buzz ) );

    // find our process' memory offset
    DWORD offset = ::GetCurrentProcessIndex() + 0x02000000;

    // copy the complete function address to the shared memory space
    buzz_addr = ( LPVOID )( ( DWORD )&Buzz + offset );

    // convert the function address to a string to send to process2.exe
    WCHAR address[ 9 ] = { 0 };
    wsprintf( address, L"%x", ( ( DWORD )buzz_addr ) );

    // start process2.exe and wait for it to finish
    PROCESS_INFORMATION pi = { 0 };
    ::CreateProcess( L"\\test_user.exe", address, NULL, NULL, FALSE, 0, NULL, NULL, NULL, &pi );
    ::WaitForSingleObject( pi.hProcess, INFINITE );

    ::UnmapViewOfFile( buzz_addr );
    ::CloseHandle( mapping );

    return 0;
}

Process2 receives the address for Buzz from Process1, casts it to the pfn_Buzz function pointer, and executes it.

// process2.exe
int _tmain( int argc, _TCHAR* argv[] )
{
    // get the address of the Buzz() function pointer
    WCHAR* wszAddr = argv[ 1 ];
    WCHAR* wszAddrEnd = &argv[ 1 ][ 8 ];
    DWORD address = wcstol( wszAddr, &wszAddrEnd, 16 );
    pfn_Buzz PFNBuzz = ( pfn_Buzz )address;

    // execute buzz
    TEST_STRUCT test = { 0 };
    PFNBuzz( &test );

    return 0;
}

Unfortunately, I get an Illegal Instruction exception in process2 when I try to execute the PFNBuzz function.

Can anybody suggest what I could change to get the functionality I'm after?

Thanks, PaulH

like image 819
PaulH Avatar asked Dec 21 '22 21:12

PaulH


2 Answers

You can simply export the function using __declspec(dllexport) and then load it using GetProcAddress() using it's name. If in C++, just remember to extern "C" the declaration to disable name mangling. Consider:

extern "C" int __declspec(dllexport) Buzz( TEST_STRUCT* info ) { ... }
int main ( int, char ** )
{
    pfn_Buzz buzz = GetProcAddress(GetModuleHandle(NULL), "Buzz");
    // ...
}

Then, pass the function name using the IPC method of your choice.

like image 32
André Caron Avatar answered Dec 24 '22 10:12

André Caron


Your problem arises from the fact that Process A (Which starts Process B) have 2 totally different virtual address spaces. You can pass a function pointer to Process A but seeeing as their address spaces are different any pointer you pass will be meaining less to another process. this is one of the huge bonuses of processes.

If you wish to communicate between processes then you will need to use some form of Inter-Process Communication (IPC).

There are several ways of doing IPC under windows. In my opinion the most versatile method is by using sockets. Sockets give you the advantage that you can seperate the machines running Process A and Process B and still get the functionality you want. Equally there is nothing stopping both processes running on the same machine. The flexibility it provides is very useful though.

So assuming you choose a socket based method of IPC then what you are effectively doing is a Remote Procedure Call (RPC).

There are, as you can probably imagine, loads of different ways of doing RPC. You could use DCOM or Corba. Raknet is a third party library that supports RPC. There are numerous other solutions as well. I strongly recommend doing a load of research into the matter. The links and keywords I've provided you with should give you a good starting point :)

like image 102
Goz Avatar answered Dec 24 '22 10:12

Goz