none
Exporting functions from .exe RRS feed

  • Question

  • Hello ,

                I am trying to export a function from .exe .Is it possible?If yes how to do it?

    Thanks in advance!

    Tuesday, July 23, 2019 10:30 AM

All replies

  • >            I am trying to export a function from .exe .Is it possible?If yes how to do it?

    See if this helps:
    https://www.codeguru.com/cpp/w-p/dll/article.php/c3649/Calling-an-Exported-Function-in-an-EXE-from-Within-a-DLL.htm

    ... though why you'd want to do it is questionable.

    Dave

    Tuesday, July 23, 2019 11:02 AM
  • Hi

             Actually i was just trying new things. Also i want use this function from .exe to another .exe and not a dll.

    Thanks


    Tuesday, July 23, 2019 11:13 AM
  • > Also i want use this function from .exe to another .exe and not a dll.

    In that case, pull the code from the EXE into a DLL and have both EXEs use the DLL - that's how things are intended to be done.

    Dave

    • Proposed as answer by Sumedh Kamble Thursday, July 25, 2019 9:48 AM
    • Unproposed as answer by Sumedh Kamble Thursday, July 25, 2019 9:48 AM
    Tuesday, July 23, 2019 11:43 AM
  • The biggest problem about calling functions from one executable from another is that executables are in different virtual address spaces.

    This means that any memory that this function uses are in a different address space, so you can't really just pass in variables. If the function returns something, this also just can't be passed back too.

    Calling a function in another executable means that you need to communicate across the process boundary. This means that you would need to transfer any input variables across using IPC, call the function in the other processes address space and then transfer the return from the other back to the calling process using IPC. This can be quite hard to do yourself.

    Windows does have facilities to do this, Remote Procedure Call and COM.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Tuesday, July 23, 2019 1:06 PM
  • In addition to what Darran said, another big problem is if your program is directly calling a function in another exe then the other exe does not have the opportunity to initialize itself. It does not allocate memory that it needs nor does it initialize that memory and it does not load libraries and it does not open files such as standard input and standard output. For a DLL there are functions that are automatically executed when the DLL is loaded but that does not happen for an exe. If you have access to the other exe source code then you might be able to set it up so it can be used as a DLL but you probably need to learn a lot before you can do that.


    Sam Hobbs
    SimpleSamples.Info

    Tuesday, July 23, 2019 7:06 PM
  • Hello everyone,

                           I found the solution i just exported a function from 1 .exe normally as we do in case of dll. And imported it in another .exe. This works.

    Thanks!

    • Proposed as answer by Sumedh Kamble Thursday, July 25, 2019 9:48 AM
    Thursday, July 25, 2019 5:58 AM
  • As everyone tried to explain here, it isn't as easy as that.

    A .exe file is meant to be executed on its own, not loaded into another process. If you do this, sure it seems like it will work, but it immediately dies if you try to do anything beyond returning a single value.

    This is expected because when the Windows executable loader loads a dynamic link library, it looks for a certain flag in the executable header.

    Dump of file envdll.dll
    
    PE signature found
    
    File Type: DLL
    
    FILE HEADER VALUES
                8664 machine (x64)
                   7 number of sections
            5D399FB0 time date stamp Thu Jul 25 13:25:20 2019
                   0 file pointer to symbol table
                   0 number of symbols
                  F0 size of optional header
                2022 characteristics
                       Executable
                       Application can handle large (>2GB) addresses
                       DLL

    Compare this to an executable file's header:

    Dump of file dllenv.exe
    
    PE signature found
    
    File Type: EXECUTABLE IMAGE
    
    FILE HEADER VALUES
                8664 machine (x64)
                   7 number of sections
            5D399FB1 time date stamp Thu Jul 25 13:25:21 2019
                   0 file pointer to symbol table
                   0 number of symbols
                  F0 size of optional header
                  22 characteristics
                       Executable
                       Application can handle large (>2GB) addresses

    If you notice, the first is seen as a DLL where the second is seen as an executable image. This is vitally important because Windows treats executables and DLLs differently when you load them as a DLL (using LoadLibrary or via compile time dynamic linking).

    When you load a DLL, Windows will resolve dependencies and then call the entry point. When you load an executable, Windows will not do any of this.

    This means that any global variables don't work correctly and calls to any external modules will fail. Two examples of such failures are:

    #include <cstdio>
    
    int calculate_val()
    {
    	return 500;
    }
    
    int value = calculate_val();
    
    extern"C"
    __declspec(dllexport)
    int fun1()
    {
    	return value;
    }
    
    extern"C"
    __declspec(dllexport)
    int fun2()
    {
    	wprintf(L"%d\n", value);
    }

    Since fun1 requires a global variable, this will not work as expected. Since fun2 requires the dependencies to be resolved, this will end up causing an access violation (even if the C Runtime is loaded due to other modules loading it). If we put the above into an executable and then use:

    #include <Windows.h>
    #include <cstdio>
    
    extern"C"
    __declspec(dllexport)
    int fun1();
    
    extern"C"
    __declspec(dllexport)
    void fun2();
    
    int wmain()
    {
    	int v = fun1();
    	bool except = false;
    	wprintf(L"%d\n", v);
    	wprintf(L"This is initialised to 500 in the other executable\n");
    
    	__try
    	{
    		fun2();
    	}
    	__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
    	{
    		except = true;
    	}
    
    	if (except)
    	{
    		wprintf(L"Getting here means that we had an access violation\n");
    	}
    
    	return 0;
    }

    to call into it, we get the output:

    0
    This is initialised to 500 in the other executable
    Getting here means that we had an access violation

    Everything that could go wrong went wrong. Since the global variable is initialised during the executable's startup code, this is never executed because loading an executable this way skips any kind of initialisation.

    The access violation occurs when you call fun2 because the underlying __acrt_iob_func function that wprintf uses is exported from a DLL (ucrtbase.dll in this case). Since Windows doesn't resolve any DLL references, the import address table will still contain the RVA and not the actual address of the function.

    The behaviour of the Windows executable loader is the same as if you used LoadLibraryEx and passed in the LOAD_LIBRARY_AS_IMAGE_RESOURCE value to the dwFlags parameter.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Edited by Darran Rowe Thursday, July 25, 2019 4:30 PM
    • Proposed as answer by Sumedh Kamble Friday, July 26, 2019 5:32 AM
    Thursday, July 25, 2019 12:50 PM
  • As a little addition, I obtained the address of the function that it was meant to be executing (using GetProcAddress) and then used the exception record to get the information on what address it was actually executing.

    The full output for the application was:

    0
    This is initialised to 500 in the other executable
    C Runtime Base Address: 0x00007FFA521E0000
    Address of __acrt_iob_func: 0x00007FFA52298C40
    Exception Flags: 0
    Exception at 0x0000000000021848
    The memory at 0x0000000000021848 could not be executed
    Getting here means that we had an access violation

    Do you notice how the address that it tried to execute is so different to what it should be?

    As I stated in my previous post, the executable loader first resolves dependencies when it loads a library. What it does is that it loads, or finds currently loaded copies of DLLs that it depends on, and then goes through the import address table of the library and fills in the actual address of the function based upon the export address table of the library that it just loaded.

    If this isn't a valid address after the base address of the DLL then this means that the resolving of the DLLs that the module depends on never occurred.

    If we do this the proper way and use a DLL, then a simple application like:

    //dll_fun.cpp
    #include <Windows.h>
    
    #ifdef _DEBUG
    const wchar_t library[] = L"ucrtbased.dll";
    #else
    const wchar_t library[] = L"ucrtbase.dll";
    #endif
    
    extern"C"
    __declspec(dllexport)
    void *get_address()
    {
    	HMODULE hm = GetModuleHandleW(library);
    
    	FARPROC fp = GetProcAddress(hm, "__acrt_iob_func");
    
    	return reinterpret_cast<void *>(fp);
    }

    //exe_main.cpp
    #include <Windows.h>
    #include <cstdio>
    
    #ifdef _DEBUG
    const wchar_t library[] = L"ucrtbased.dll";
    #else
    const wchar_t library[] = L"ucrtbase.dll";
    #endif
    
    extern"C"
    __declspec(dllimport)
    void *get_address();
    
    int wmain()
    {
    	HMODULE hm = GetModuleHandleW(library);
    
    	FARPROC fp = GetProcAddress(hm, "__acrt_iob_func");
    
    	wprintf(L"Base address of C Runtime: 0x%p\n", hm);
    	wprintf(L"Address of __acrt_iob_func: 0x%p\n", fp);
    	wprintf(L"DLL version: 0x%p\n", get_address());
    
    	return 0;
    }

    Will output:

    Base address of C Runtime: 0x00007FFA4C160000
    Address of __acrt_iob_func: 0x00007FFA4C218C40
    DLL version: 0x00007FFA4C218C40

    Notice how the addresses obtained from the executable and the DLL are the same? This can never work if you try to do the same with an executable loading an executable.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Thursday, July 25, 2019 1:51 PM
  • Yes exactly, i got an access violation and was not able to use printf() .I was just able to return a local variable. This is exactly what i was looking for. Thank you for the explanation.
    Friday, July 26, 2019 5:35 AM