研究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操作(那么这个操作可能是对人脸识别的)。

1
2
3
4
5
6
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做处理的是这些函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
globalJitCompileHandlerAddr = reinterpret_cast<art::jit::JitCompiler **>(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<jboolean>(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,还是需要自己实现一套。