如何修补第 3 方 .so 文件以访问非导出符号 (C++)

all*_*mon 8 c++ reverse-engineering ld readelf nm

我有一些.fic专有格式的二进制文件,我有一个wd250hf64.so来自该供应商的包含 C++ 方法的文件 CComposanteHyperFile::HExporteXML(wchar_t* const path)

我可以使用 nm 看到

$ nm  --demangle   wd250hf64.so  --defined-only 


0000000000118c90 t CComposanteHyperFile::HExporteXML(wchar_t const*)
Run Code Online (Sandbox Code Playgroud)

未损坏的版本_ZN20CComposanteHyperFile11HExporteXMLEPKw与我使用本地 g++ 版本的版本相同

雷德夫给出

readelf -Ws wd250hf64.so  | grep _ZN20CComposanteHyperFile11HExporteXMLEPK

 19684: 0000000000118c90   119 FUNC    LOCAL  DEFAULT   11 _ZN20CComposanteHyperFile11HExporteXMLEPKw

Run Code Online (Sandbox Code Playgroud)

现在我尝试编写一个非常简单的程序

$ nm  --demangle   wd250hf64.so  --defined-only 


0000000000118c90 t CComposanteHyperFile::HExporteXML(wchar_t const*)
Run Code Online (Sandbox Code Playgroud)

但是当我用它编译时g++ toto.cpp -L. -l:wd250hf64.so

我有toto.cpp:(.text+0x10): undefined reference to 'CComposanteHyperFile::HExporteXML(wchar_t const*)'

我没有更多的运气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);
}
Run Code Online (Sandbox Code Playgroud)
gcc -rdynamic -o foo toto.c -ldl
./foo
wd250hf64.so: undefined symbol: _ZN20CComposanteHyperFile11HExporteXMLEPKw

Run Code Online (Sandbox Code Playgroud)

我明白,因为 nm 没有显示--extern-only它,所以这个符号可能没有“导出”,所以它不应该正常工作

我的问题是

无论如何,即使这意味着手动修补 .so 文件,使程序编译的黑客方法是什么?

Mon*_*nad 2

如果您确实希望能够以任何可能的方式获取该符号,您可以尝试获取其相对于已知导出符号的地址,假设它们位于同一部分。例如,我制作了一个简单的虚拟库,其中包含一个导出函数和一个非导出函数。

0x0000000000003890    12 FUNC    GLOBAL DEFAULT    16 function_we_exported
0x00000000000038a0    12 FUNC    LOCAL  HIDDEN     16 function_we_forgot_to_export
Run Code Online (Sandbox Code Playgroud)

因为这个库是为了这个答案而设计的,所以非导出函数恰好就在它旁边,0x10function_we_exported. 使用这些信息,我们可以轻松地做到这一点。

const auto address = reinterpret_cast<char*>(dlsym(library, "function_we_exported"));
reinterpret_cast<your_function_type>(address + 0x10)(...);
Run Code Online (Sandbox Code Playgroud)

正如您可能会说的那样,这非常hacky,但如果您没有其他选择,我想这可能是一种方法。另一种方法可能是修补库并强制导出它。考虑到它们显示为GLOBAL/LOCALDEFAULT/ HIDDEN,这可能是翻转旗帜或其他东西,但我目前不知道该怎么做。如果我这样做,我会更新这个答案。