NDK需要使用gnustl_static std::string而不是std::_ndk1::string。

3
我正在挂钩一个现有的库,该库使用 gnustl 编译而不是 libc++。如果我尝试设置或访问这些字符串,我只会得到垃圾值。在我的 hook 应用程序中,如何将我的 std::string 转换为 std::_ndk1::string,反之亦然?
我无法使用“-DANDROID_STL=gnustl_shared”编译我的 hook,因为它已不再存在,并且其他正在使用的库需要 libc++。
文档提到了这一点:“各种 STL 不兼容。例如,在 libc++ 中,std::string 的布局与 gnustl 中的布局不同”,这正是问题所在。https://developer.android.com/ndk/guides/cpp-support
2个回答

4
要使用 gnustl,您可以使用 NDK r.17 或更早版本编译所有本地代码。这是一条危险的路径,因为自那时以来已经修复了许多重要的错误,包括安全相关的错误。
另一种不受支持(也不建议)的处理该问题的方法是从 NDK r.17 获取 gnustl 源代码,并使用最新的 NDK 版本进行编译。
您最好的选择是使用最新版本的 NDK 及其 c++_shared 运行时库重新构建所有依赖项。

不幸的是,当处理挂钩现有应用程序时,我被困在他们编译的古老 NDK 上。我在上面发布了我的解决方案。 - Neo

1

这是我目前想到的(并不是很理想):

StringsProxy.cc

#include "StringsProxy.h"
#include <iostream>
#include <string>

using namespace std;

__attribute__((visibility("default")))
extern "C" StringsProxy::StringsProxy(const char* contents)
{
    set_string = std::string(contents);
}
__attribute__((visibility("default")))
extern "C" StringsProxy::StringsProxy(uintptr_t str) {
    set_string = *reinterpret_cast<proxy_string*>(str);
}
__attribute__((visibility("default")))
extern "C" const char* StringsProxy::c_str() {
    return set_string.c_str();
}
__attribute__((visibility("default")))
extern "C" const uintptr_t* StringsProxy::ptr() {
    return reinterpret_cast<uintptr_t *>(&set_string);
}
__attribute__((visibility("default")))
extern "C" StringsProxy::~StringsProxy() {
}

StringsProxy.h

#ifndef __STRINGSPROXY_H__
#define __STRINGSPROXY_H__
#include <string>

typedef std::basic_string<char> proxy_string;

class StringsProxy
{
public:
  /* Initialize StringsProxy with a pointer to an existing string */
  StringsProxy(uintptr_t str);
  /* Initialize StringsProxy with a new string */
  StringsProxy(const char* str);
  /* Get C string */
  virtual const char* c_str();
  /* Get pointer to string for injection */
  const virtual uintptr_t* ptr();

private:
  proxy_string set_string;
};
#endif

使用旧版 NDK 编译为共享对象,使用 -DCMAKE_ANDROID_STL_TYPE=gnustl_static

然后将此共享对象链接到挂钩程序中(在 CMakeLists 中):target_link_libraries(${TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/abiproxy/build/armeabi-v7a/libabiproxy.so)

然后在挂钩程序中,可以这样使用:

#include "abiproxy/StringsProxy.h"
void *setUriDebug(uintptr_t a1, uintptr_t stri) {

    auto y = StringsProxy(stri);
    LOGI("URI CALLED %s", y.c_str());

    return setUriDebugOld(a1, stri);
}

或者反过来:

StringsProxy assetNameBaseProxy = StringsProxy("https://example.com/");
void setResourceUrl(uintptr_t* a1, int a2) {    
    *(a1 + 1) = *assetNameBaseProxy.ptr();
}

这绝不是一个“好”的解决方案,但它适用于我的使用情况。

这样可以将gnustl字符串与您的代码隔离开来。看起来还不错,但为什么不使用gnustl和旧版NDK重新构建整个代码呢? - Alex Cohn
旧版NDK存在固有的TEXT_RELOCATION问题,而现代Android系统会拒绝加载带有TEXT_RELOCATION的库文件,这一点你应该知道。 - Shark
@AlexCohn 与钩子库存在一些不兼容性。 - Neo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接