I have some binary .fic
files in a proprietary format , I have a wd250hf64.so
from this vendor that contains a C++ method CComposanteHyperFile::HExporteXML(wchar_t* const path)
that I can see using nm
$ nm --demangle wd250hf64.so --defined-only
0000000000118c90 t CComposanteHyperFile::HExporteXML(wchar_t const*)
the unmangled version _ZN20CComposanteHyperFile11HExporteXMLEPKw
is identical to what I have using my local g++ version
readelf gives
readelf -Ws wd250hf64.so | grep _ZN20CComposanteHyperFile11HExporteXMLEPK
19684: 0000000000118c90 119 FUNC LOCAL DEFAULT 11 _ZN20CComposanteHyperFile11HExporteXMLEPKw
now I try writing a very simple program
class CComposanteHyperFile {
public:
static void HExporteXML(wchar_t const*);
};
int main() {
CComposanteHyperFile::HExporteXML(L"file.fic");
return 0;
}
but when I compile it with g++ toto.cpp -L. -l:wd250hf64.so
I got toto.cpp:(.text+0x10): undefined reference to 'CComposanteHyperFile::HExporteXML(wchar_t const*)'
I don't have more luck with dlopen
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int
main(int argc, char **argv)
{
void *handle;
void (*exportXML)(wchar_t const*);
char *error;
handle = dlopen("wd250hf64.so", RTLD_LAZY);
*(void **) (&exportXML) = dlsym(handle, "_ZN20CComposanteHyperFile11HExporteXMLEPKw");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
dlclose(handle);
exit(EXIT_SUCCESS);
}
gcc -rdynamic -o foo toto.c -ldl
./foo
wd250hf64.so: undefined symbol: _ZN20CComposanteHyperFile11HExporteXMLEPKw
I understand that as it is not shown by nm with --extern-only
it may be that this symbol is not "exported" and so it's not supposed to work normally
my question is
What is the hackish way of making the program to compile, by all means, even if it means manually patching the .so file ?
If you really want to be able to get at that symbol in any way possible, you could try to get its address relative to that of a known exported symbol, assuming that they're in the same section. For example, I made a simple dummy library with one exported function and one non-exported function.
0x0000000000003890 12 FUNC GLOBAL DEFAULT 16 function_we_exported
0x00000000000038a0 12 FUNC LOCAL HIDDEN 16 function_we_forgot_to_export
Because this library was contrived just for this answer, the non-exported function happens to be right next to it, 0x10
after function_we_exported
. Using this information, we can hackily do this.
const auto address = reinterpret_cast<char*>(dlsym(library, "function_we_exported"));
reinterpret_cast<your_function_type>(address + 0x10)(...);
As you can probably tell, this is pretty hacky, but if you have no other choice, I suppose this can be a way. Another way may be to patch the library and forcibly export it. Considering that they show up as GLOBAL
/LOCAL
and DEFAULT
/HIDDEN
, it's probably a flip of a flag or something, but I don't know how to do that at the moment. I'll update this answer if I do.