前言
有一次安全部门出了一份隐私合规报告,基础技术牵头配合整改,报告形式如下: 报告对系统方法Settings$Secure.getStringForUser做了hook,并拿到了调用堆栈。
这么小的一个技术也可以做成收费的商业服务,可见科学技术是第一生产力。
1、思考
三方的检测机构可未获取我们的源码,仅仅通过一个apk就能做到;一时间我也比较诧异, 想着自己尚有全部的源码,能否在有源码的条件下做到类似三方检测结构的hook手段呢? 答案当然是可以,让我们来实践一把。
1、大名鼎鼎的xposed其实实用性不高,因为需要root权限的手机而且近几年用的人少了,
稳定性也未知;
2、在此基础上发展起来的epic(https://github.com/tiann/epic);
因为表现的太好,走了闭源商业化的路子,开源的版本稳定性有点问题,
各位看官根据自己的工程实际试用下开源的版本;
3、最后用的是SandHook(https://github.com/asLody/SandHook);
试用下来跟工程的冲突比较少,而且确实拿到了结果。
2、编码实现
参考文档 https://github.com/asLody/SandHook/blob/master/doc/doc.md
在build.gradle文件添加依赖
implementation 'com.swift.sandhook:hooklib:4.2.1'
implementation 'com.swift.sandhook:xposedcompat:4.2.1'
hook获取mac地址的系统方法getMacAddress举例
public class MacAddressHooker {
private static final String TAG = "MacAddressHooker";
@HookMethodBackup("getMacAddress")
@MethodParams({})
static Method getMacAddressMethod;
@HookMethod("getMacAddress")
@MethodParams({})
public static Object getMacAddress(Object thiz) throws Throwable {
StackTraceElement[] traceElements = new Throwable().getStackTrace();
for (StackTraceElement element : traceElements){
Log.e(TAG, " --getMacAddress-- \n"+element.toString());
}
PermissionUtils.INSTANCE.checkCallPermission("MacAddress");
return SandHook.callOriginByBackup(getMacAddressMethod, thiz);
}
}
hook获取设备序列号举例
@HookReflectClass("android.os.Build")
public class SerialHooker {
private static final String TAG = "getSerialHooker";
@HookMethodBackup("getSerial")
@SkipParamCheck
static Method getSerialMethod;
@HookMethod("getSerial")
@MethodParams({})
public static void getSerial() throws Throwable {
StackTraceElement[] traceElements = new Throwable().getStackTrace();
for (StackTraceElement element : traceElements){
Log.e(TAG, " --getSerial-- \n"+element.toString());
}
PermissionUtils.INSTANCE.checkCallPermission("getSerial");
getSerialMethod.invoke(null,null);
}
}
初始化调用
object PermissionHooker {
fun init() {
if (Build.VERSION.SDK_INT == 29 && getPreviewSDKInt() > 0) {
// Android R preview
SandHookConfig.SDK_INT = 30
}
SandHook.disableVMInline()
SandHook.tryDisableProfile(context.packageName)
SandHook.disableDex2oatInline(false)
if (SandHookConfig.SDK_INT >= Build.VERSION_CODES.P) {
SandHook.passApiCheck()
}
SandHook.addHookClass(MacAddressHooker::class.java)
SandHook.addHookClass(SerialHooker::class.java)
}
private fun getPreviewSDKInt(): Int {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
try {
return Build.VERSION.PREVIEW_SDK_INT
} catch (e: Throwable) {
// ignore
}
}
return 0
}
}
3、打印日志查看
hook获取mac地址的系统方法getMacAddres的日志如下:
hook获取设备序列号的日志如下:
hook文件删除方法的日志如下:
总结
- SandHook也是参考了xposed以及epic的实现原理做的,适合在测试环境做集成;
- 不论是SandHook还是epic,越往底层走越需要掌握Jni编程;
- Javassit,AspectJ,Asm主要用来hook项目工程的代码,其中ASM基本配合gradle插件使用,注意其中差异。