对 Android 应用进行 hook 常见的有 Xposed、Frida 等,Xposed 有时候可能不尽人意,或许您可以试试 Frida ~
frida -U -f com.primer.gamecerter -l hookStartActivity.js
TODO
- 后续是否可以对检测数据(堆栈、类名、方法名、参数、返回值)进行收集和统计,数据经过进一步处理后格式化输出更好~
/*** 时间:2024年2月22日12:17:44* 作者:村长* 描述:合规检测 hook* * * 如何使用:* 1、确保设备启动 frida-service* adb shell* su 需要 root 设备* cd data/local/tmp/ firda-service 可执行文件存放位置* ./frida-service*** & 后台运行* frida -U -f 【包名】 -l 【脚本路径】 注入脚本启动应用 * *///全局配置
var runConfig = {"permission": false,"startActivity": false,"deviceId": true,"file": false,"ipAddress": false,"location": false,"other": false,"systemProperties": false,"packageList": false,"enablePrintStackTrace": false,
}Java.perform(function x() {console.log(" --------- 启动检测 ----------");if (runConfig.permission) {checkPermission();}if (runConfig.startActivity) {checkStartActivity();}if (runConfig.deviceId) {checkAndroidId();checkIMEI();checkOtherId()}if (runConfig.file) {checkExternalFileRW();}if (runConfig.ipAddress) {checkIPAddress();}if (runConfig.location) {checkLocation();}if (runConfig.other) {checkOther();}if (runConfig.systemProperties) {checkSystemProperties();}if (runConfig.packageList) {checkPackageList();}console.log(" --------- 结束检测 ----------");
})///function log() {if (runConfig.enablePrintStackTrace) {console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));}
}function checkPackageList() {console.log("----------- 应用安装列表检查 -----------")var ApplicationPackageManager = Java.use("android.app.ApplicationPackageManager")ApplicationPackageManager.getInstalledPackages.implementation = function (flags) {var list = this.getInstalledPackages(flags)console.log("ApplicationPackageManager 获取安装列表 " + list)log();return list;}ApplicationPackageManager.getPackageInfo.overload('java.lang.String', 'int').implementation = function (pkg, flags) {var info = this.getPackageInfo(pkg, flags)console.log("ApplicationPackageManager 获取包名信息 " + info)log();return info;}ApplicationPackageManager.getPackageInfo.overload('android.content.pm.VersionedPackage', 'int').implementation = function (pkg, flags) {var info = this.getPackageInfo(pkg, flags)console.log("ApplicationPackageManager 获取包名信息 " + info)log();return info;}ApplicationPackageManager.getLaunchIntentForPackage.implementation = function (pkg) {var intent = this.getLaunchIntentForPackage(pkg)console.log("ApplicationPackageManager 获取启动 intent: " + intent)log();return intent;}
}function checkSystemProperties() {console.log("----------- 系统属性检查 -----------")var SystemProperties = Java.use("android.os.SystemProperties")SystemProperties.get.overload('java.lang.String').implementation = function (key) {var val = this.get(key)console.log("SystemProperties 获取系统属性 " + key + " -> " + val)log();return val;}SystemProperties.get.overload('java.lang.String', 'java.lang.String').implementation = function (key, def) {var val = this.get(key, def)console.log("SystemProperties 获取系统属性 " + key + " -> " + val + " " + def)log();return val;}
}function checkOther() {console.log("----------- 剪切板检查 -----------")var ClipboardManager = Java.use("android.content.ClipboardManager")ClipboardManager.getPrimaryClip.implementation = function () {var val = this.getPrimaryClip()console.log("ClipboardManager 1 获取短信 " + val)log();return val;}ClipboardManager.getPrimaryClipDescription.implementation = function () {var val = this.getPrimaryClipDescription()console.log("ClipboardManager 1 获取短信 " + val)log();return val;}console.log("----------- 网络信息检查 -----------")var ConnectivityManager = Java.use("android.net.ConnectivityManager")ConnectivityManager.getActiveNetworkInfo.implementation = function () {var val = this.getActiveNetworkInfo()console.log("ConnectivityManager 获取网络信息 " + val)log();return val;}
}/**
* 未完善,需要解析 content 判断属于哪一种类型
*/
function checkContentResolve() {var ContentResolver = Java.use("android.content.ContentResolver")ContentResolver.query.overload('android.net.Uri', '[Ljava.lang.String;', 'android.os.Bundle', 'android.os.CancellationSignal').implementation = function (uri, strs, bundle, signal) {var val = this.query(uri, strs, bundle, signal)console.log("ContentResolver 1 获取短信 " + val)log();return val;}ContentResolver.query.overload('android.net.Uri', '[Ljava.lang.String;', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String').implementation = function (uri, strs, str1, strs2, str3) {var val = this.query(uri, strs, str1, strs2, str3)console.log("ContentResolver 2 获取短信 " + val)log();return val;}ContentResolver.query.overload('android.net.Uri', '[Ljava.lang.String;', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String', 'android.os.CancellationSignal').implementation = function (uri, strs1, str2, strs3, str4, signal) {var val = this.query(uri, strs1, str2, strs3, str4, signal)console.log("ContentResolver 3 获取短信 " + val)log();return val;}
}function checkLocation() {console.log("----------- 定位检查 -----------")var LocationManager = Java.use("android.location.LocationManager")LocationManager.getLastLocation.implementation = function () {var location = this.getLastLocation()console.log("LocationManager 获取定位 " + location)log();return location;}LocationManager.getLastKnownLocation.implementation = function () {var location = this.getLastKnownLocation()console.log("LocationManager 获取定位 " + location)log();return location;}
}function checkIPAddress() {console.log("----------- IP 地址检查 -----------")var NetworkInterface = Java.use("java.net.NetworkInterface")NetworkInterface.getInterfaceAddresses.implementation = function () {var addessList = this.getInterfaceAddresses()console.log("NetworkInterface 获取 IP 地址 " + addessList)log();return addessList;}var Inet4Address = Java.use("java.net.Inet4Address")Inet4Address.getHostAddress.implementation = function () {var address = this.getHostAddress()console.log("Inet4Address 获取主机地址 " + address)log();return address;}var Inet6Address = Java.use("java.net.Inet6Address")Inet6Address.getHostAddress.implementation = function () {var address = this.getHostAddress()console.log("Inet6Address 获取主机地址 " + address)log();return address;}
}function checkExternalFileRW() {console.log("----------- 外部文件读写检查 -----------")var ContextImpl = Java.use("android.app.ContextImpl")ContextImpl.getExternalFilesDirs.implementation = function (type) {var files = this.getExternalFilesDirs(type)console.log("ContextImpl 获取外部文件目录 " + type)log();return files;}ContextImpl.getExternalMediaDirs.implementation = function () {var files = this.getExternalMediaDirs()console.log("ContextImpl 获取媒体文件目录")log();return files;}ContextImpl.getExternalCacheDirs.implementation = function () {var files = this.getExternalCacheDirs()console.log("ContextImpl 获取缓存目录")log();return files;}var Environment = Java.use("android.os.Environment")Environment.getExternalStorageDirectory.implementation = function () {var file = this.getExternalStorageDirectory()console.log("ContextImpl 获取外部存储目录")log();return file;}}function checkIMEI() {console.log("----------- imei 检查 -----------")var TelephonyManager = Java.use("android.telephony.TelephonyManager")//getDeviceId TelephonyManager.getDeviceId.overload("int").implementation = function (slotIndex) {var iemi = this.getDeviceId(slotIndex)console.log("TelephonyManager 获取 IMEI getDeviceId slotIndex = " + slotIndex + " iemi = " + iemi)log();return iemi;}TelephonyManager.getDeviceId.overload().implementation = function () {var iemi = this.getDeviceId()console.log("TelephonyManager 获取 getDeviceId IMEI = " + iemi)log();return iemi;}//getMeidTelephonyManager.getMeid.overload("int").implementation = function (slotIndex) {var iemi = this.getMeid(slotIndex)console.log("TelephonyManager 获取 IMEI getMeid slotIndex = " + slotIndex + " iemi = " + iemi)log();return iemi;}TelephonyManager.getMeid.overload().implementation = function () {var iemi = this.getMeid()console.log("TelephonyManager 获取 getMeid IMEI = " + iemi)log();return iemi;}//getImeiTelephonyManager.getImei.overload("int").implementation = function (slotIndex) {var iemi = this.getImei(slotIndex)console.log("TelephonyManager 获取 IMEI getImei slotIndex = " + slotIndex + " iemi = " + iemi)log();return iemi;}TelephonyManager.getImei.overload().implementation = function () {var iemi = this.getImei()console.log("TelephonyManager 获取 getImei IMEI = " + iemi)log();return iemi;}}function checkOtherId() {console.log("----------- mac 检查 -----------")var NetworkInterface = Java.use("java.net.NetworkInterface")NetworkInterface.getHardwareAddress.implementation = function () {var mac = this.getHardwareAddress()console.log("NetworkInterface 获取 MAC = " + mac)log();return mac;}var WifiInfo = Java.use("android.net.wifi.WifiInfo")WifiInfo.getMacAddress.implementation = function () {var mac = this.getMacAddress()console.log("WifiInfo 获取 MAC = " + mac)log();return mac;}console.log("----------- SSID 检查 -----------")WifiInfo.getSSID.implementation = function () {var ssid = this.getSSID()console.log("WifiInfo 获取 ssid = " + ssid)log();return ssid;}console.log("----------- oaid 检查 -----------")var OAID_LIST = ["com.bun.supplier.IdSupplier","com.bun.miitmdid.provider.DefaultProvider","com.bun.miitmdid.supplier.IdSupplier","com.bun.miitmdid.interfaces.IdSupplier"]for (let index in OAID_LIST) {try {var oaid = Java.use(OAID_LIST[index])oaid.getOAID.implementation = function () {var result = this.getOAID()console.log('获取 oaid = ' + result);log();return result}} catch (e) {}}console.log("----------- IMSI 检查 -----------")var TelephonyManager = Java.use("android.telephony.TelephonyManager")TelephonyManager.getSubscriberId.overload().implementation = function () {var imsi = this.getSubscriberId()console.log("TelephonyManager 获取 imsi = " + imsi)log();return imsi;}TelephonyManager.getSubscriberId.overload('int').implementation = function (index) {var imsi = this.getSubscriberId(index)console.log("TelephonyManager 获取 1 imsi = " + imsi)log();return imsi;}console.log("----------- SN 检查 -----------")var Build = Java.use("android.os.Build")Build.getSerial.implementation = function () {var sn = this.getSerial()console.log("TelephonyManager 获取 sn = " + sn)log();return sn;}
}function checkAndroidId() {console.log("----------- android id检查 -----------")var ANDROID_ID = "android_id"var Secure = Java.use("android.provider.Settings$Secure")Secure.getString.implementation = function (resolver, name) {var result = this.getString(resolver, name);console.log("getString name = " + name + " val =" + result)if (ANDROID_ID == name) {console.log("getString 获取 androidID")log();}return result;}Secure.getStringForUser.implementation = function (resolver, name, userHandle) {var result = this.getStringForUser(resolver, name, userHandle);console.log("getStringForUser name = " + name + " val =" + result)if (ANDROID_ID == name) {console.log("Secure getStringForUser 获取 androidID")log();}return result;}var SecureSystem = Java.use("android.provider.Settings$System")SecureSystem.getStringForUser.implementation = function (resolver, name, userHandle) {var result = this.getStringForUser(resolver, name, userHandle);console.log("System getStringForUser name = " + name + " val =" + result)if (ANDROID_ID == name) {console.log("System getStringForUser 获取 androidID")log();}return result;}
}function checkPermission() {console.log("----------- 权限检查 -----------")var ActivityCompat = Java.use("android.app.Activity")ActivityCompat.requestPermissions.overload("[Ljava.lang.String;", "int").implementation = function (permissions, requestCode) {console.log("requestPermissions 2 requestCode = " + requestCode + " permissions = " + permissions)log();this.requestPermissions(permissions, requestCode)}var Fragment = Java.use("android.app.Fragment")Fragment.requestPermissions.implementation = function (permissions, code) {console.log('权限申请 android permissions = ' + permissions + " code = " + code);log();this.requestPermissions(permissions, code)}var Fragmentx = Java.use("androidx.fragment.app.Fragment")Fragmentx.requestPermissions.implementation = function (permissions, code) {console.log('权限申请 androidx permissions = ' + permissions + " code = " + code);log();this.requestPermissions(permissions, code)}
}function checkStartActivity() {console.log("----------- startActivity 检查 -----------")var Instrumentation = Java.use('android.app.Instrumentation');Instrumentation.execStartActivity.overload('android.content.Context','android.os.IBinder','android.os.IBinder','android.app.Activity','android.content.Intent','int','android.os.Bundle').implementation =function (who, contextThread, token, target, intent, requestCode, options) {console.log('【当前应用 1 Instrumentation】 启动 execStartActivity intent = ' +intent);var pkg = intent.getPackage()console.log('pkg = ' + pkg)if (pkg != undefined && pkg != NULL && pkg == 'com.xiaomi.market') {intent.setPackage('com.heytap.market')}log();return this.execStartActivity(who, contextThread, token, target, intent, requestCode, options);}Instrumentation.execStartActivity.overload('android.content.Context','android.os.IBinder','android.os.IBinder',"java.lang.String",'android.content.Intent','int','android.os.Bundle').implementation =function (who, contextThread, token, target, intent, requestCode, options) {console.log('【当前应用 2 Instrumentation】 启动 execStartActivity intent = ' +intent);var pkg = intent.getPackage()console.log('pkg = ' + pkg)if (pkg != undefined && pkg != NULL && pkg == 'com.xiaomi.market') {intent.setPackage('com.heytap.market')}log();return this.execStartActivity(who, contextThread, token, target, intent, requestCode, options);}Instrumentation.execStartActivity.overload('android.content.Context','android.os.IBinder','android.os.IBinder',"java.lang.String",'android.content.Intent','int','android.os.Bundle',"android.os.UserHandle").implementation =function (who, contextThread, token, resultWho, intent, requestCode, options, user) {console.log('【当前应用 3 Instrumentation】 启动 execStartActivity intent = ' +intent);var pkg = intent.getPackage()console.log('pkg = ' + pkg)if (pkg != undefined && pkg != NULL && pkg == 'com.xiaomi.market') {intent.setPackage('com.heytap.market')}log();return this.execStartActivity(who, contextThread, token, resultWho, intent, requestCode, options, user)}Instrumentation.checkStartActivityResult.implementation = function (res, intent) {console.log('【checkStartActivityResult 启动 intent = ' + intent);log();return this.checkStartActivityResult(res, intent)}
}