短汇编指令inline hook
目标函数:
安卓9.0 __system_property_get
因为inline hook原理是通过修改目标方法的汇编指令的开始处的几个字节的代码(Substrate中为12个字节),用一段跳转指令来完成目标方法的hook替换,因此inline hook的最大缺点为需要目标方法足够大,否则会导致替换跳板指令后后续指令紊乱。
为了验证这个猜想,从手机中将/system/lib/libc.so中pull了下来并拖到了IDA中打开,查找__system_property_ge方法的汇编指令,发现果然小于12字节,同时与安卓8.0中的libc.so中进行对比,确实是安卓9.0进行了优化导致的。
既然该方法短到了substrate无法进行 inline hook,那么此时的解决方案其实有两种,一个是采用方法入口替换的PLT表 Hook(爱奇艺的XHook),另一个则是采用所需长度更小的SandInstHook。
SandInstHook本质上仍然是inline hook,但是所需的字节更短,仅需4字节。使用方法如下:
#include "sandhook_native.h"
void* SandSingleInstHook(void* origin, void* replace);
void* SandSingleInstHookSym(const char* so, const char* symb, void* replace);
源码在native-hook的lib下,由于与容器在两个模块即两个so中,因此若要使用SandInstHook的源代码,需要对容器的CMakeLists.txt进行一定的改造。
先编译native-hook得到不同abi架构下的so文件
容器CMakeLists.txt中设置根据不同abi架构引入不同native-hook的so文件
容器CMakeLists.txt引入Sandhook_native头文件
容器CMakeLists.txt关联native-hook的so文件
引入SandInstHook之后,下一步便是开始Hook,SandInstHook的API与Substrate稍有不一致,因此需要一定转化,SandInstHook仅需要目标Hook方法的地址,以及替换的新方法地址,对于原方法的backup则通过返回值得到,开始不清楚参数 和 返回值的含义甚至导致误以为遇到了SandInstHook对32位arm不支持的thumb指令。
小Tips:C++函数指针的强转
由于需要在hook后替换的方法中调用原方法,因此
1.先声明了原方法的函数指针
2.然后将hook完成之后得到的原方法的backup地址赋值给先前声明 的函数指针
3.由于C++不允许将char强转为void,所以 这里可以使用reinterpret_cast进行强转。
4.完整代码:
int (*origin_system_property_get)(const char *name, char *value);
int new_system_property_get(const char *name, char *value) {
int len = origin_system_property_get(name, value);
string sname = string(name);
if (fakeProperties.find(sname) == fakeProperties.end()) {
return len;
}
// 替换value时长度最多不会超过原value长度
string fake_value = fakeProperties[sname];
if (strlen(value) > 0) {
memcpy(value, (char *) fake_value.c_str(), strlen(value));
}
ALOGI("hook native system_property_get, key:%s,fake value:%s,length:%d", name, value, len);
return len;
}
void FingerPrintFaker::hook_system_property_get(map<string, string> fakeProps) {
fakeProperties = fakeProps;
void *handle = fake_dlopen("libc.so", RTLD_NOW);
void *symbol = fake_dlsym(handle, "__system_property_get");
// 安卓9.0该函数汇编代码长度过短不满足12字节导致substrate inline hook崩溃
// 因此使用SandHook SingleInstHook,只需要4字节
if (SDK_INT < 28) {
MSHookFunction(symbol, (void *) &new_system_property_get,
(void **) &origin_system_property_get);
} else {
void *origin_back_up_method = SandSingleInstHook(symbol,
(void *) &new_system_property_get);
ALOGI("sand single inst hook libc __system_property_get :%d",
origin_back_up_method == nullptr);
if (origin_back_up_method == nullptr) {
ALOGE("sand single inst hook libc __system_property_get failed!!!");
} else {
origin_system_property_get = reinterpret_cast<int (*)(const char *,char *)>(origin_back_up_method);
}
}
fake_dlclose(handle);
}