研究SandHook
SandHook的实现介绍:
Android ART Hook 实现 - SandHook_ganyao939543405的博客-CSDN博客_sandhook
SandHook/doc.md at master · asLody/SandHook
其中有一个重要的点就是,android内部实现java对象的时候会有一个mirror的镜像对象,有一些虚拟机比较在意的类型,例如 Class,Method 这些 Art 内部所需要的类型,他们在 mirror 中是有对应的类型的。
ART在进行JIT/AOT的时候,会对dex代码进行二次编译的过程,也就是将原本的java class、method全都转化成mirror:class、mirror:method。
AOSP源码:https://android.googlesource.com/platform/art/+/8db4a405fe283d8769d5f38299d8692c009feb1a/runtime/mirror
这篇文章说的比较详细:脱了马甲我也认识你: 聊聊 Android 中类的真实形态 - 掘金
Sandhook 作者写的文章:
SandHook 第三弹 - 性能优化 & Xposed 模块 & 阻止 VM Inline_ganyao939543405的博客-CSDN博客
他遇到的一个问题就是VM Inline会将一定阈值内的代码进行优化,这样就会阻碍sandhook的hook过程,他的解决方法也是通过调整这个阈值来做处理。那我们来考虑,我们能不能实现改阈值将该优化的都优化了,导致他hook失败呢。
跳转图:
非root注入:
https://github.com/ganyao114/SandBoxHookPlugin
沙箱环境的一种注入,是不是跟这个黑产工具类似呢。
整个的攻击逻辑就是将apk下载到本地,黑产工具对他进行二次打包和插入dex指令集代码(或者不用插入,直接sandhook修改就行。),但是apk中安装到手机上的是存在sandhook的,不知道是为什么,可能跟下面这段代码一样吧,就是对某一个类进行hook操作(那么这个操作可能是对人脸识别的)。
SandHookConfig.libSandHookPath = soNewPath;
try {
SandHook.addHookClass(ActivityHooker.class);
} catch (HookErrorException e) {
e.printStackTrace();
}
我觉得最主要的就是对sandhook的检测,他暴露很多特征,诸如修改那个阈值为0来做到组织inline的优化,还有类似的(如果可以的话,我们自己动手去修改这个值,再去检测这个值,或者直接检测这个值,如果这个值为0,那么就判断为存在hook的情况[sandhook],sandhook中并没有使用这个,其中关键特征_ZN3art3jit3Jit20jit_compiler_handle_E
并没有使用,https://github.com/asLody/SandHook/blob/16a59fa0eef011ca202814311b362a8a3bcda412/hooklib/src/main/cpp/utils/hide_api.cpp#L93)
其次就是他的跳转逻辑中会mmap一段可执行的区域,那么能不能通过之前写的判断smaps中的信息来做到检测呢(这部分验证需要自己写一个sandhook的demo来做)。
其中对_ZN3art3jit3Jit20jit_compiler_handle_E做处理的是这些函数:
globalJitCompileHandlerAddr = reinterpret_cast(getSymCompat(art_lib_path, "_ZN3art3jit3Jit20jit_compiler_handle_E"));
art::jit::JitCompiler* getGlobalJitCompiler() {
if (SDK_INT < ANDROID_N)
return nullptr;
if (globalJitCompileHandlerAddr == nullptr)
return nullptr;
return *globalJitCompileHandlerAddr;
}
art::CompilerOptions* getGlobalCompilerOptions() {
return getCompilerOptions(getGlobalJitCompiler());
}
art::CompilerOptions* getCompilerOptions(art::jit::JitCompiler* compiler) {
if (compiler == nullptr)
return nullptr;
return compiler->compilerOptions.get();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_swift_sandhook_SandHook_disableVMInline(JNIEnv *env, jclass type) {
if (SDK_INT < ANDROID_N)
return JNI_FALSE;
replaceUpdateCompilerOptionsQ();
art::CompilerOptions* compilerOptions = getGlobalCompilerOptions();
if (compilerOptions == nullptr)
return JNI_FALSE;
return static_cast(disableJitInline(compilerOptions));
}
bool disableJitInline(art::CompilerOptions* compilerOptions) {
if (compilerOptions == nullptr)
return false;
size_t originOptions = compilerOptions->getInlineMaxCodeUnits();
//maybe a real inlineMaxCodeUnits
if (originOptions > 0 && originOptions <= 1024) {
compilerOptions->setInlineMaxCodeUnits(0);
return true;
} else {
return false;
}
}
// 通过dlsym进行拿到获取。dlsym可能会被hook,还是需要自己实现一套。