Is there a way to find the C++ mangled name to use

2020-03-03 09:34发布

The common "solution" to use GetProcAddress with C++ is "extern "C", but that breaks overloading. Name mangling allows multiple functions to co-exist, as long as their signature differs. But is there a way to find these mangled names for GetProcAddress?

3条回答
▲ chillily
2楼-- · 2020-03-03 09:49

The VC++ compiler knows its own name mangling scheme, so why not use that? Inside template<typename T> T GetProcAddress(HMODULE h, const char* name), the macro __FUNCDNAME__ contains the mangled name of GetProcAddress. That includes the T part. So, inside GetProcAddress<void(*)(int), we have a substring with the mangled name of void(*)(int). From that, we can trivially derive the mangled name of void foo(int);

This code relies on the VC++ macro __FUNCDNAME__. For MinGW you'd need to base this on __PRETTY_FUNCTION__ instead.

FARPROC GetProcAddress_CppImpl(HMODULE h, const char* name, std::string const& Signature)
{
    // The signature of T appears twice in the signature of T GetProcAddress<T>(HMODULE, const char*) 
    size_t len = Signature.find("@@YA");
    std::string templateParam = Signature.substr(0, len);
    std::string returnType    = Signature.substr(len+4);
    returnType.resize(templateParam.size()); // Strip off our own arguments (HMODULE and const char*)
    assert(templateParam == returnType); 
    // templateParam and returnType are _pointers_ to functions (P6), so adjust to function type (Y)
    std::string funName = "?" + std::string(name) + "@@Y" + templateParam.substr(2);
    return ::GetProcAddress(h, funName.c_str());
}

template <typename T>
T GetProcAddress(HMODULE h, const char* name)
{
    // Get our own signature. We use `const char* name` to keep it simple.
    std::string Signature = __FUNCDNAME__ + 18; // Ignore prefix "??$GetProcAddress@"
    return reinterpret_cast<T>(GetProcAddress_CppImpl(h, name, Signature));
}

// Showing the result

struct Dummy { };

__declspec(dllexport) void foo( const char* s)
{
    std::cout << s;
}

__declspec(dllexport) void foo( int i, Dummy )
{
    std::cout << "Overloaded foo(), got " << i << std::endl;
}

__declspec(dllexport) void foo( std::string const& s )
{
    std::cout << "Overloaded foo(), got " << s << std::endl;
}

__declspec(dllexport) int foo( std::map<std::string, double> volatile& )
{
    std::cout << "Overloaded foo(), complex type\n";
    return 42;
}

int main()
{
    HMODULE h = GetModuleHandleW(0);
    foo("Hello, ");
    auto pFoo1 = GetProcAddress<void (*)( const char*)>(h, "foo");
    // This templated version of GetProcAddress is typesafe: You can't pass 
    // a float to pFoo1. That is a compile-time error.
    pFoo1(" world\n");
    auto pFoo2 = GetProcAddress<void (*)( int, Dummy )>(h, "foo");
    pFoo2(42, Dummy()); // Again, typesafe.
    auto pFoo3 = GetProcAddress<void (*)( std::string const& )>(h, "foo");
    pFoo3("std::string overload\n");
    auto pFoo4 = GetProcAddress<int (*)( std::map<std::string, double> volatile& )>(h, "foo");
    // pFoo4 != NULL, this overload exists.
    auto pFoo5 = GetProcAddress<void (*)( float )>(h, "foo");
    // pFoo5==NULL - no such overload.
}
查看更多
够拽才男人
3楼-- · 2020-03-03 09:53

Use dumpbin /exports 'file.dll' to get the decorated / undecorated name of all the symbols.

查看更多
三岁会撩人
4楼-- · 2020-03-03 09:54

It's impossible to do it just by using GetProcAddress. However, one way to do it would be to enumerate all the exported functions for that particular module, and do a pattern matching to find all the mangled names.

More specifically, refer to this answer here. The only change you will need to make would be to pass in TRUE for MappedAsImage parameter and the return value of GetModuleHandle for Base parameter to ImageDirectoryEntryToData function call.

void EnumerateExportedFunctions(HMODULE hModule, vector<string>& slListOfDllFunctions)
{
    DWORD *dNameRVAs(0);
    _IMAGE_EXPORT_DIRECTORY *ImageExportDirectory;
    unsigned long cDirSize;
    _LOADED_IMAGE LoadedImage;
    string sName;
    slListOfDllFunctions.clear();

    ImageExportDirectory = (_IMAGE_EXPORT_DIRECTORY*)
        ImageDirectoryEntryToData(hModule,
        TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &cDirSize);
    if (ImageExportDirectory != NULL)
    {
        dNameRVAs = (DWORD *)ImageRvaToVa(LoadedImage.FileHeader, 
            LoadedImage.MappedAddress,
        ImageExportDirectory->AddressOfNames, NULL);
        for(size_t i = 0; i < ImageExportDirectory->NumberOfNames; i++)
        {
            sName = (char *)ImageRvaToVa(LoadedImage.FileHeader, 
                    LoadedImage.MappedAddress,
                   dNameRVAs[i], NULL);
         slListOfDllFunctions.push_back(sName);
        }
    }
}
查看更多
登录 后发表回答