对 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;
}
//getMeid
TelephonyManager.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;
}
//getImei
TelephonyManager.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)
}
}