国内某知名风控SDK,本地从Java层和Native层收集大量设备信息,上传至服务器后生成设备指纹。SDK混淆非常严重,Java层的字符串加密可以被JEB自动解密,影响不大,但是类名和变量名全是0和O只能硬着头皮看
native层则是使用了ollvm和字符串加密
对付ollvm这里我使用了hluwa大佬了obpo-plugin,对我的帮助很大。然后根据静态分析找到字符串解密的函数,使用frida主动调用或者用unidbg的主动调用来进行字符串解密即可。
SDK的工作流程大概是先从服务器端请求一个配置文件,然后根据这个配置文件分别从Java层和Native层收集设备信息的dict,最后在上传之前将dict的每个key替换成a1、a2之类的无意义的key,防止被人从key中理解到信息的含义。最后加密dict并上传至服务器。替换key名称使用了注解的方式,如下:
代码大致如下:
if(!field.getName().equals("serialVersionUID")) {
field.setAccessible(true);
Object value = field.get(arg8);
CostumSerializable mCostumSerializable = (CostumSerializable)field.getAnnotation(CostumSerializable.class);
if(mCostumSerializable == null) {
v1.put(field.getName(), value);
}
else if(value != null || (mCostumSerializable.enableReplaceName())) {
boolean v7 = mCostumSerializable.isMap();
String v0_2 = mCostumSerializable.keyname();
if(v7) {
v1.put(v0_2, Util.costumSerialize(value));
}
else {
v1.put(v0_2, Util.normalize(field, value));
}
}
}
Config的内容如下
{"all_atamper":true,"core_atamper":true,"hook_java_switch":true,"hook_switch":false,
"risk_apps":[
{"xposed":{"pn":"de.robv.android.xposed.installer","uri":""}},
{"controllers":{"pn":"com.soft.controllers","uri":""}},
{"apk008v":{"pn":"com.soft.apk008v","uri":""}},
{"apk008Tool":{"pn":"com.soft.apk008Tool","uri":""}},
{"ig":{"pn":"com.doubee.ig","uri":""}},
{"anjian":{"pn":"com.cyjh.mobileanjian","uri":""}},
{"rktech":{"pn":"com.ruokuai.rktech","uri":""}},
{"magisk":{"pn":"com.topjohnwu.magisk","uri":""}},
{"kinguser":{"pn":"com.kingroot.kinguser","uri":""}},
{"substrate":{"pn":"com.saurik.substrate","uri":""}},
{"touchsprite":{"pn":"com.touchsprite.android","uri":""}},
{"scriptdroid":{"pn":"com.stardust.scriptdroid","uri":""}},
{"toolhero":{"pn":"com.mobileuncle.toolhero","uri":""}},
{"huluxia":{"pn":"com.huluxia.gametools","uri":""}},
{"apkeditor":{"pn":"com.gmail.heagoo.apkeditor.pro","uri":""}},
{"xposeddev":{"pn":"com.sollyu.xposed.hook.model.dev","uri":""}},
{"anywhere":{"pn":"com.txy.anywhere","uri":""}},
{"burgerzwsm":{"pn":"pro.burgerz.wsm.manager","uri":""}},
{"vdloc":{"pn":"com.virtualdroid.loc","uri":""}},
{"vdtxl":{"pn":"com.virtualdroid.txl","uri":""}},
{"vdwzs":{"pn":"com.virtualdroid.wzs","uri":""}},
{"vdkit":{"pn":"com.virtualdroid.kit","uri":""}},
{"vdwxg":{"pn":"com.virtualdroid.wxg","uri":""}},
{"vdgps":{"pn":"com.virtualdroid.gps","uri":""}},
{"a1024mloc":{"pn":"top.a1024bytes.mockloc.ca.pro","uri":""}},
{"drhgz":{"pn":"com.deruhai.guangzi.noroot2","uri":""}},
{"yggb":{"pn":"com.mcmonjmb.yggb","uri":""}},
{"xsrv":{"pn":"xiake.xserver","uri":""}},
{"fakeloc":{"pn":"com.dracrays.fakeloc","uri":""}},
{"ultra":{"pn":"net.anylocation.ultra","uri":""}},
{"locationcheater":{"pn":"com.wifi99.android.locationcheater","uri":""}},
{"dwzs":{"pn":"com.dingweizshou","uri":""}},
{"mockloc":{"pn":"top.a1024bytes.mockloc.ca.pro","uri":""}},
{"anywhereclone":{"pn":"com.txy.anywhere.clone","uri":""}},
{"fakelocc":{"pn":"com.dracrays.fakelocc","uri":""}},
{"mockwxlocation":{"pn":"com.tandy.android.mockwxlocation","uri":""}},
{"anylocation":{"pn":"net.anylocation","uri":""}},
{"totalcontrol":{"pn":"com.sigma_rt.totalcontrol","uri":""}},
{"ipjl2":{"pn":"com.chuangdian.ipjl2","uri":""}}],"risk_dirs":[{"008Mode":{"dir":".system/008Mode","type":"sdcard"}},
{"008OK":{"dir":".system/008OK","type":"sdcard"}},
{"008system":{"dir":".system/008system","type":"sdcard"}},
{"iGrimace":{"dir":"iGrimace","type":"sdcard"}},
{"touchelper":{"dir":"/data/data/net.aisence.Touchelper","type":"absolute"}},
{"elfscript":{"dir":"/mnt/sdcard/touchelf/scripts/","type":"absolute"}},
{"spritelua":{"dir":"/mnt/sdcard/TouchSprite/lua","type":"absolute"}},
{"spritelog":{"dir":"/mnt/sdcard/TouchSprite/log","type":"absolute"}},
{"assistant":{"dir":"/data/data/com.xxAssistant","type":"absolute"}},
{"assistantscript":{"dir":"/mnt/sdcard/com.xxAssistant/script","type":"absolute"}},
{"mobileanjian":{"dir":"/data/data/com.cyjh.mobileanjian","type":"absolute"}}
],
"risk_file_switch":true,"risk_files":"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",
"sensitive.ainfo":true,
"sensitive.apps":true,
"sensitive.aps":true,
"sensitive.bssid":true,
"sensitive.camera":true,
"sensitive.cell":true,
"sensitive.gps":false,
"sensitive.iccid":true,
"sensitive.imsi":true,
"sensitive.mac":true,
"sensitive.ssid":true,
"sensitive.tel":false,
"white_apps":[]}
其中risk_file被加密了,在配置文件传入Native层后由Native进行解密,解密后内容如下:
[{"key":"cputemp","type":"file","path":"file:///sys/class/thermal/thermal_zone0/temp","option":"upload"},
{"key":"voltage1","type":"file","path":"file:///sys/class/power_supply/battery/batt_vol_now","option":"upload"},
{"key":"voltage2","type":"file","path":"file:///sys/class/power_supply/battery/voltage_now","option":"upload"},
{"key":"maps","type":"file","path":"file:///proc/self/maps","option":"match_ic","words":["com.bly.dkplat","com.excelliance.dualaid","com.bfire.da.nui","com.svm.proteinbox_multi","com.boly.wxnewcopy","com.juying.Jixiaomi.fenshen","com.qihoo.magic","com.godinsec.godinsec_private_space","com.sellapk.goapp","com.yizhi.ftd","com.qihoo.magic.xposed","com.excean.dualaid","com.shiyue.avatarlauncher","com.excean.masaid","com.rinzz.avatar","info.red.virtual","com.depu.wxfs","com.sheep2.xyfs","cn.nineox.pupfish","com.shaker.wxxh.moli.fs","com.fssq.weichat","com.smallyin.Avaassis","com.meta.app.fenshen","com.yxd.shpk_multi","com.xiandong.fst","com.xunrui.duokai_box","com.felix.shuangkai","com.dbhydbhy.duokai","com.xuanmutech.fenkai","com.felix.duokai","com.magic.app.reader01","com.cxhcxh.duokai","com.dongguaququ.duokai","com.felix.fenshen","com.nox.mopen.app","com.boly.wxmultopen","com.tyzhzxl.dkwxzs","com.chufa.skzs","com.lbe.parallel","dkmodel","io.virtualapp","com.coloros.oppomultiapp","com.lbe.parallel.intl","com.jumobile.multiapp","com.jumobile.smartapp","info.cloneapp.mochat.in.goast","com.excelliance.multiaccounts","com.ludashi.dualspace","cn.lapstudio.weiduokai","com.parallel.space.lite","com.jiubang.commerce.gomultiple","cn.lapstudio.aid","com.arc.multi","com.nox.mopen.app","io.virtualapp.luohe","com.ludashi.superboost","com.zhushou.weichat","zc.wormhole","com.lanrun.yxjl","com.ivymobi.multiaccount.free","cloner.parallel.space.multiple.accounts.twoface","com.lylm.dkzs","com.rinzz.avatar","com.ludashi.multspace","com.trigtech.privateme","com.jun.virtual","com.pldasoft.dualapp","com.youxi.shuangkai.help","com.jumobile.multiapp.pro","com.applisto.appcloner","multiple.multiple.parallel.accounts.cloner.mochat","com.bba.vma","com.rinzz.wdf"]},
{"key":"virtio","type":"dir","path":"file:///sys/bus/virtio","option":"exists"},
{"key":"wlan0","type":"dir","path":"file:///sys/class/net/wlan0","option":"exists"},
{"key":"eth0","type":"dir","path":"file:///sys/class/net/eth0","option":"exists"},
{"key":"interrupts","type":"file","path":"file:///proc/interrupts","option":"match","words":["hypervisor","goldfish"]},
{"key":"iomem","type":"file","path":"file:///proc/iomem","option":"match","words":["qemu-pipe","goldfish","vbox"]},
{"key":"ioports","type":"file","path":"file:///proc/ioports","option":"match","words":["virtio","goldfish"]},
{"key":"misc","type":"file","path":"file:///proc/misc","option":"match","words":["vbox","qemu"]},
{"key":"kallsyms","type":"file","path":"file:///proc/kallsyms","option":"match","words":["vbox","qemu","goldfish"]},
{"key":"arp","type":"file","path":"file:///proc/net/arp","option":"match","words":["eth"]},
{"key":"route","type":"file","path":"file:///proc/net/route","option":"match","words":["eth"]}]
另外config中有个hook_java_switch,会对Java层的函数进行hook,其中需要hook的类和函数硬编码在native层,就是文章开头的那一串魔改base64,主动调用解密后内容如下:
[{"key":"element","clazz":"dalvik/system/DexPathList$Element","method":"toString","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"insPkg","clazz":"android/app/ApplicationPackageManager","method":"getInstalledPackages","sig":"(I)Ljava/util/List;","param":["int"],"type":1},
{"key":"spget1","clazz":"android/os/SystemProperties","method":"get","sig":"(Ljava/lang/String;)Ljava/lang/String;","param":["java.lang.String"],"type":2},
{"key":"spget2","clazz":"android/os/SystemProperties","method":"get","sig":"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;","param":["java.lang.String","java.lang.String"],"type":2},
{"key":"secget","clazz":"android/provider/Settings$Secure","method":"getString","sig":"(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;","param":["android.content.ContentResolver","java.lang.String"],"type":2},
{"key":"dev1","clazz":"android/telephony/TelephonyManager","method":"getDeviceId","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"dev2","clazz":"android/telephony/TelephonyManager","method":"getDeviceId","sig":"(I)Ljava/lang/String;","param":["int"],"type":1},
{"key":"native","clazz":"java/lang/reflect/Modifier","method":"isNative","sig":"()Z","param":[],"type":2},
{"key":"debug","clazz":"android/os/Debug","method":"isDebuggerConnected","sig":"()Z","param":[],"type":2},
{"key":"globalget","clazz":"android/provider/Settings$Global","method":"getInt","sig":"(Landroid/content/ContentResolver;Ljava/lang/String;)I","param":["android.content.ContentResolver","java.lang.String"],"type":2},
{"key":"runpro","clazz":"android/app/ActivityManager","method":"getRunningAppProcesses","sig":"()Ljava/util/List;","param":[],"type":1},
{"key":"runtask","clazz":"android/app/ActivityManager","method":"getRunningTasks","sig":"(I)Ljava/util/List;","param":["int"],"type":1},
{"key":"runservice","clazz":"android/app/ActivityManager","method":"getRunningServices","sig":"(I)Ljava/util/List;","param":["int"],"type":1},
{"key":"appinfo","clazz":"android/app/ApplicationPackageManager","method":"getApplicationInfo","sig":"(Ljava/lang/String;I)Landroid/content/pm/ApplicationInfo;","param":["java.lang.String","int"],"type":1},
{"key":"pkginfo","clazz":"android/app/ApplicationPackageManager","method":"getPackageInfo","sig":"(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;","param":["java.lang.String","int"],"type":1},
{"key":"insapp","clazz":"android/app/ApplicationPackageManager","method":"getInstalledApplications","sig":"(I)Ljava/util/List;","param":["int"],"type":1},
{"key":"exec","clazz":"java/lang/Runtime","method":"exec","sig":"(Ljava/lang/String;)Ljava/lang/Process;","param":["java.lang.String"],"type":1},
{"key":"ppdeviceid","clazz":"com/android/internal/telephony/PhoneProxy","method":"getDeviceId","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"gsmdeviceid","clazz":"com/android/internal/telephony/gsm/GSMPhone","method":"getDeviceId","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"psubdeviceid","clazz":"com/android/internal/telephony/PhoneSubInfo","method":"getDeviceId","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"imei1","clazz":"android/telephony/TelephonyManager","method":"getImei","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"imei2","clazz":"android/telephony/TelephonyManager","method":"getImei","sig":"(I)Ljava/lang/String;","param":["int"],"type":1},
{"key":"btmac","clazz":"android/bluetooth/BluetoothAdapter","method":"getAddress","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"cellloc","clazz":"android/telephony/TelephonyManager","method":"getCellLocation","sig":"()Landroid/telephony/CellLocation;","param":[],"type":1},
{"key":"cellchange","clazz":"android/telephony/PhoneStateListener","method":"onCellLocationChanged","sig":"(Landroid/telephony/CellLocation;)V","param":["android.telephony.CellLocation"],"type":1},
{"key":"tel1","clazz":"android/telephony/TelephonyManager","method":"getLine1Number","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"tel2","clazz":"android/telephony/TelephonyManager","method":"getLine1Number","sig":"(I)Ljava/lang/String;","param":["int"],"type":1},
{"key":"iccid1","clazz":"android/telephony/TelephonyManager","method":"getSimSerialNumber","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"iccid2","clazz":"android/telephony/TelephonyManager","method":"getSimSerialNumber","sig":"(I)Ljava/lang/String;","param":["int"],"type":1},
{"key":"netop1","clazz":"android/telephony/TelephonyManager","method":"getNetworkOperator","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"netop2","clazz":"android/telephony/TelephonyManager","method":"getNetworkOperator","sig":"(I)Ljava/lang/String;","param":["int"],"type":1},
{"key":"netopname1","clazz":"android/telephony/TelephonyManager","method":"getNetworkOperatorName","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"netopname2","clazz":"android/telephony/TelephonyManager","method":"getNetworkOperatorName","sig":"(I)Ljava/lang/String;","param":["int"],"type":1},
{"key":"simop1","clazz":"android/telephony/TelephonyManager","method":"getSimOperator","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"simop2","clazz":"android/telephony/TelephonyManager","method":"getSimOperator","sig":"(I)Ljava/lang/String;","param":["int"],"type":1},
{"key":"simopname1","clazz":"android/telephony/TelephonyManager","method":"getSimOperatorName","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"simopname2","clazz":"android/telephony/TelephonyManager","method":"getSimOperatorName","sig":"(I)Ljava/lang/String;","param":["int"],"type":1},
{"key":"imsi1","clazz":"android/telephony/TelephonyManager","method":"getSubscriberId","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"imsi2","clazz":"android/telephony/TelephonyManager","method":"getSubscriberId","sig":"(I)Ljava/lang/String;","param":["int"],"type":1},
{"key":"phcount","clazz":"android/telephony/TelephonyManager","method":"getPhoneCount","sig":"()I","param":[],"type":1},
{"key":"wmac","clazz":"android/net/wifi/WifiInfo","method":"getMacAddress","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"ssid","clazz":"android/net/wifi/WifiInfo","method":"getSSID","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"rssi","clazz":"android/net/wifi/WifiInfo","method":"getRssi","sig":"()I","param":[],"type":1},
{"key":"netid","clazz":"android/net/wifi/WifiInfo","method":"getNetworkId","sig":"()I","param":[],"type":1},
{"key":"bssid","clazz":"android/net/wifi/WifiInfo","method":"getBSSID","sig":"()Ljava/lang/String;","param":[],"type":1},
{"key":"nettype","clazz":"android/net/NetworkInfo","method":"getType","sig":"()I","param":[],"type":1},
{"key":"netsubtype","clazz":"android/net/NetworkInfo","method":"getSubtype","sig":"()I","param":[],"type":1},
{"key":"neicell","clazz":"android/telephony/TelephonyManager","method":"getNeighboringCellInfo","sig":"()Ljava/util/List;","param":[],"type":1},
{"key":"allcell","clazz":"android/telephony/TelephonyManager","method":"getAllCellInfo","sig":"()Ljava/util/List;","param":[],"type":1},
{"key":"scanre","clazz":"android/net/wifi/WifiManager","method":"getScanResults","sig":"()Ljava/util/List;","param":[],"type":1},
{"key":"wifistate","clazz":"android/net/wifi/WifiManager","method":"getWifiState","sig":"()I","param":[],"type":1},
{"key":"wifienable","clazz":"android/net/wifi/WifiManager","method":"isWifiEnabled","sig":"()Z","param":[],"type":1},
{"key":"getlat","clazz":"android/location/Location","method":"getLatitude","sig":"()D","param":[],"type":1},
{"key":"getlon","clazz":"android/location/Location","method":"getLongitude","sig":"()D","param":[],"type":1},
{"key":"lastknownloc","clazz":"android/location/LocationManager","method":"getLastKnownLocation","sig":"(Ljava/lang/String;)Landroid/location/Location;","param":["java.lang.String"],"type":1},
{"key":"providers","clazz":"android/location/LocationManager","method":"getProviders","sig":"(Z)Ljava/util/List;","param":["boolean"],"type":1},
{"key":"bestprov","clazz":"android/location/LocationManager","method":"getBestProvider","sig":"(Landroid/location/Criteria;Z)Ljava/lang/String;","param":["android.location.Criteria","java.lang.String"],"type":1},
{"key":"addlis","clazz":"android/location/LocationManager","method":"addGpsStatusListener","sig":"(Landroid/location/GpsStatus$Listener;)Z","param":["android.location.GpsStatus$Listener"],"type":1},
{"key":"gpsstat","clazz":"android/location/LocationManager","method":"getGpsStatus","sig":"(Landroid/location/GpsStatus;)Landroid/location/GpsStatus;","param":["android.location.GpsStatus"],"type":1},
{"key":"addnmea","clazz":"android/location/LocationManager","method":"addNmeaListener","sig":"(Landroid/location/OnNmeaMessageListener;)Z","param":["android.location.OnNmeaMessageListener"],"type":1},
{"key":"addnmea","clazz":"android/location/LocationManager","method":"requestLocationUpdates","sig":"(Landroid/location/LocationRequest;Landroid/location/LocationListener;Landroid/os/Looper;Landroid/app/PendingIntent;)V","param":["android.location.LocationRequest","android.location.LocationListener","android.os.Looper","android.app.PendingIntent"],"type":1},
{"key":"txloc","clazz":"com/tencent/mapapi/service/LocationManager","method":"getLocationInfo","sig":"()Landroid/location/Location;","param":[],"type":1},
{"key":"file1","clazz":"java/io/File","method":"<init>","sig":"(Ljava/lang/String;)V","param":["java.lang.String"],"type":3},
{"key":"file2","clazz":"java/io/File","method":"<init>","sig":"(Ljava/lang/String;Ljava/lang/String;)V","param":["java.lang.String","java.lang.String"],"type":3},
{"key":"probuild1","clazz":"java/lang/ProcessBuilder","method":"<init>","sig":"([Ljava/lang/String;)V","param":["java.lang.String"],"type":3},
{"key":"probuild2","clazz":"java/lang/ProcessBuilder","method":"<init>","sig":"(Ljava/util/List;)V","param":["java.util.List"],"type":3}] //type3为构造函数
总结一下大概收集了哪些信息,具体收集的方式见下文。
key | value |
---|---|
电池 | status、level、scale、temperature、voltage |
android.os.Build | board、model、serial、brand、manufacturer、fingerprint、cpu_abi、cpu_abi2 |
CPU | vendor_id、model_name、count、cpuMHz |
memory | totalmem |
MediaDrm | 通过4个uuid生成uniqueid |
xposed | 是否加载xposedBridge.jar、hook的函数名、fieldCache、methodCache、constructorCache |
Accessibility | isEnabled、EnabledAccessibilityServiceList |
输入法 | 已安装输入法列表 |
服务商 | locateServiceName、phoneServiceName |
模拟器检测 | 特征文件、DeviceID、服务商名、prop中的字段 |
TelephoneService | DeviceID、服务商、subscribeID、SimSerialNumber |
权限 | READ_PHONE_STATE、WRITE_EXTERNAL_STORAGE、WRITE_SETTINGS、ACCESS_WIFI_STATE、ACCESS_NETWORK_STATE、ACCESS_FINE_LOCATION、ACCESS_COARSE_LOCATION |
蓝牙 | getAddress、IPC操作readString |
network | SSID、BSSID、MAC、IP、type、NetworkInterface、Proxy、isConnected |
位置信息 | BSSID、celllocation |
签名 | 反射packageManager获取SubjectDN |
已安装应用 | 白名单app、系统app、用户app、自身是否为系统app、自身包名、版本 |
屏幕 | 分辨率、亮度 |
sd卡 | AvailableBytes、FreeBytes、TotalBytes |
传感器 | 动态特征:gravity、gryo、light;其他传感器类型和厂商信息 |
ContentResolver | android_id、mock_location |
系统启动时间 | System.currentTimeMillis() - SystemClock.elapsedRealtime() |
进程 | 自身进程名 |
systemProp | “ro.debuggable”、”ro.boot.serialno”、”gsm.network.type”、”gsm.sim.state”、”persist.sys.country”、”persist.sys.language”、”sys.usb.state”、”ro.serialno”;”net.dns1”、”net.dns2”、”net.dns3”、”net.dns4” |
virtualApp检测 | 貌似是通过收集与自身的UID相同的进程列表来检测的 |
key | value |
---|---|
_system_property_get | ro.kernel.qemu、ro.debuggable、ro.secure、ro.build.version.release、ro.build.version.sdk、ro.build.display.id、ro.product.model、ro.product.board、ro.product.brand、ro.product.name、ro.product.manufacturer、ro.boot.baseband、ro.boot.bootloader、ro.serialno、ro.build.fingerprint |
UUID | /proc/sys/kernel/random/uuid |
libc plt hook | open、stat、access、fopen、printf、read、mmap、socket、rename |
root检查 | /sbin/su、/system/xbin/su、/system/bin/su |
iotcl | 0x8912、0x8913、0x8927 |
cpu ABI | 从/system/bin/ls中解析获取 |
HW address | /proc/net/arp |
boot_id | /proc/sys/kernel/random/boot_id |
cpu温度 | /sys/class/thermal/thermal_zone0/temp |
电池电压 | /sys/class/power_supply/battery/batt_vol_now;/sys/class/power_supply/battery/voltage_now |
双开应用检测 | 读取/proc/self/maps检测包名 |
可疑文件是否存在 | /sys/bus/virtio;/sys/class/net/wlan0;/sys/class/net/eth0 |
虚拟机检测 | 字符串匹配:/proc/iomem、/proc/ioports、/proc/misc、/proc/kallsyms、/proc/net/arp、/proc/net/route |
特定目录文件 | 遍历文件夹下所有文件,并计算指纹:/vendor/lib、/system/framework、/system/fonts、/vendor/firmware、/system/bin、/data/system |
public Map getBatteryInfo() {
HashMap v0 = new HashMap();
Context v1 = com.ishumei.common.Context.ctx;
if(v1 != null) {
try {
Intent v1_2 = v1.registerReceiver(null, new IntentFilter("android.intent.action.BATTERY_CHANGED"));
if(v1_2 != null) {
int v2 = v1_2.getIntExtra("status", 0);
int v3 = v1_2.getIntExtra("level", 0);
int v4 = v1_2.getIntExtra("scale", 100);
int v5 = v1_2.getIntExtra("temperature", 0);
int v1_3 = v1_2.getIntExtra("voltage", 0);
v0.put("status", Integer.valueOf(v2));
v0.put("level", Integer.valueOf(v3));
v0.put("scale", Integer.valueOf(v4));
v0.put("temp", Integer.valueOf(v5));
v0.put("vol", Integer.valueOf(v1_3));
return v0;
}
}
catch(Exception v1_1) {
return v0;
}
}
return v0;
}
fields = ReflactUtil.getDeclaredFieldsByClassName("android.os.Build");
//Serial 特判
Object Serial = ReflactUtil.invoke("android.os.Build", "getSerial");
//其他内容,通过反射获取
board,model,serial,brand,manufacturer,fingerprint,cpu_abi,cpu_abi2
读取/proc/cpuinfo
if((TextUtils.equals("hardware", key)) || (TextUtils.equals("vendor_id", key)))
if(!TextUtils.equals("Processor", key) && !TextUtils.equals("model name", key))
通过fileInputStream读取
/sys/devices/system/cpu/possible
/sys/devices/system/cpu/present
或者列出所有以cpu开头的文件数量
new File("/sys/devices/system/cpu/possible").listFiles(this.fileFilter).length;
CPU频率
File cpuinfo_max_freq = new File("/sys/devices/system/cpu/cpu" + cpuIndex + "/cpufreq/cpuinfo_max_freq");
读取/proc/cpuinfo中记录的“cpu MHz”值
fis1 = new FileInputStream("/proc/cpuinfo");
cpuMHz = this.readInt("cpu MHz", fis1);
int v3_1 = cpuMHz * 1000;
Build.VERSION.SDK_INT >= 16
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
((ActivityManager)this.ctx.getSystemService("activity")).getMemoryInfo(memoryInfo);
return memoryInfo == null ? -1L : memoryInfo.totalMem;
读取/proc/meminfo
fis = new FileInputStream("/proc/meminfo");
v0_2 = this.readInt("MemTotal", fis);
long result = ((long)v0_2) * 0x400L;
public String getDeviceUniqueIdFromDrm() {
if(Build.VERSION.SDK_INT < 23) {
return "";
}
StringBuilder data = new StringBuilder();
try {
Class MediaDrm = Class.forName("android.media.MediaDrm");
Constructor UUIDConstructor = UUID.class.getConstructor(Long.TYPE, Long.TYPE);
Constructor MediaDrmConstructor = MediaDrm.getConstructor(UUID.class);
Method getPropertyByteArray = MediaDrm.getMethod("getPropertyByteArray", String.class);
data.append(this.deviceUniqueId(MediaDrmConstructor, getPropertyByteArray, UUIDConstructor.newInstance(((long)0xEDEF8BA979D64ACEL), ((long)-6645017420763422227L)))).append("_");
data.append(this.deviceUniqueId(MediaDrmConstructor, getPropertyByteArray, UUIDConstructor.newInstance(((long)0x1077EFECC0B24D02L), ((long)0xACE33C1E52E2FB4BL)))).append("_");
data.append(this.deviceUniqueId(MediaDrmConstructor, getPropertyByteArray, UUIDConstructor.newInstance(((long)0xE2719D58A985B3C9L), ((long)0x781AB030AF78D30EL)))).append("_");
data.append(this.deviceUniqueId(MediaDrmConstructor, getPropertyByteArray, UUIDConstructor.newInstance(((long)0x9A04F07998404286L), ((long)0xAB92E65BE0885F95L))));
}
catch(Throwable v1) {
}
return data.toString();
}
private String deviceUniqueId(Constructor MediaDrm, Method getPropertyByteArray, Object UUID) {
try {
return Base64.encodeToString(((byte[])getPropertyByteArray.invoke(MediaDrm.newInstance(UUID), "deviceUniqueId")), 2);
}
catch(Throwable v0) {
return "";
}
}
private boolean checkXposed(ClassLoader classloader, String keyword) {
if(classloader == null) {
return false;
}
if(!(classloader instanceof BaseDexClassLoader)) {
return false;
}
try {
Class DexPathList = Class.forName("dalvik.system.DexPathList");
Method toString = Class.forName("dalvik.system.DexPathList$Element").getMethod("toString", null);
Field dexElements = DexPathList.getDeclaredField("dexElements");
dexElements.setAccessible(true);
Field pathList = BaseDexClassLoader.class.getDeclaredField("pathList");
pathList.setAccessible(true);
Object[] v0_2 = (Object[])dexElements.get(pathList.get(classloader));
int v4;
for(v4 = 0; true; ++v4) {
label_37:
if(v4 >= v0_2.length) {
return false;
}
String v1_2 = (String)toString.invoke(v0_2[v4], null);
if(v1_2 != null) {
boolean v1_3 = v1_2.contains(keyword);
break;
}
}
}
catch(Throwable v0) {
return false;
}
if(v1_3) {
return true;
}
++v4;
goto label_37;
}
public boolean hasXposed(String arg4) {
try {
ClassLoader v1 = ClassLoader.getSystemClassLoader();
if(!this.checkXposed(v1, arg4) && !this.checkXposed(v1.getParent(), arg4)) {
ClassLoader v1_1 = this.getClass().getClassLoader();
if(this.checkXposed(v1_1, arg4)) {
return true;
}
boolean v1_2 = this.checkXposed(v1_1.getParent(), arg4);
return v1_2;
}
return true;
}
catch(Exception v0) {
return false;
}
}
public Set getXposedCache() {
HashSet result = new HashSet();
try {
Class xposed = ClassLoader.getSystemClassLoader().loadClass("de.robv.android.xposed.XposedHelpers");
this.getFieldNames(xposed, "fieldCache", result);
this.getFieldNames(xposed, "methodCache", result);
this.getFieldNames(xposed, "constructorCache", result);
}
catch(Throwable v1) {
}
return result;
}
public Map xposed() {
Object[] v2_4;
HashSet v6_3;
Class v8;
Method v7_1;
int v2_1;
Field field;
HashMap v3 = new HashMap();
try {
Field[] fields = ClassLoader.getSystemClassLoader().loadClass("de.robv.android.xposed.XposedBridge").getDeclaredFields();
int index = 0;
while(index < fields.length) {
field = fields[index];
if("sHookedMethodCallbacks".equals(field.getName())) {
v2_1 = 0;
goto label_33;
}
if("hookedMethodCallbacks".equals(field.getName())) {
v2_1 = 1;
goto label_33;
}
++index;
}
v2_1 = 0;
field = null;
label_33:
if(field == null) {
return v3;
}
field.setAccessible(true);
Map v1_1 = (Map)field.get(null);
if(v2_1 == 0) {
Class clz = ClassLoader.getSystemClassLoader().loadClass("de.robv.android.xposed.XposedBridge$CopyOnWriteSortedSet");
Method getSnapshot = clz.getDeclaredMethod("getSnapshot");
getSnapshot.setAccessible(true);
v7_1 = getSnapshot;
v8 = clz;
}
else {
v7_1 = null;
v8 = null;
}
Iterator v9 = v1_1.entrySet().iterator();
label_61:
while(v9.hasNext()) {
Object v2_3 = v9.next();
String v6_2 = ((Map.Entry)v2_3).getKey().toString();
HashSet v1_2 = (Set)v3.get(v6_2);
if(v1_2 == null) {
HashSet v1_3 = new HashSet();
v3.put(v6_2, v1_3);
v6_3 = v1_3;
}
else {
v6_3 = v1_2;
}
Object v1_4 = ((Map.Entry)v2_3).getValue();
if(v8 != null && (v8.isInstance(v1_4))) {
v2_4 = (Object[])v7_1.invoke(v1_4);
}
else if(TreeSet.class.isInstance(v1_4)) {
Object[] v1_5 = ((TreeSet)v1_4).toArray();
v2_4 = v1_5;
}
else {
v2_4 = null;
}
if(v2_4 == null) {
continue;
}
int v10 = v2_4.length;
int v1_6 = 0;
while(true) {
if(v1_6 >= v10) {
continue label_61;
}
v6_3.add(v2_4[v1_6].getClass().getName());
++v1_6;
}
}
}
catch(Exception v1) {
}
return v3;
}
public Map getAccessibilityInfo() {
HashMap v3 = new HashMap();
Object v1 = com.ishumei.common.Context.ctx.getSystemService("accessibility");
Method v2 = v1.getClass().getDeclaredMethod("isEnabled");
Method v4 = v1.getClass().getDeclaredMethod("getEnabledAccessibilityServiceList", Integer.TYPE);
Object v2_1 = v2.invoke(v1);
ArrayList v4_1 = new ArrayList();
for(Object v6: ((List)v4.invoke(v1, ((int)-1)))) {
Object v1_1 = v6.getClass().getDeclaredMethod("getId").invoke(v6);
if(v1_1 == null) {
Object v1_2 = v6.getClass().getDeclaredMethod("getResolveInfo").invoke(v6);
v4_1.add((v1_2 == null ? v6.toString() : v1_2.toString()));
continue;
}
v4_1.add(((String)v1_1));
}
v3.put("enable", (((Boolean)v2_1).booleanValue() ? "1" : "0"));
v3.put("service", v4_1);
v3.put("suc", "1");
return v3;
}
public String LocationAndPhoneServiceName() {
StringBuilder data = new StringBuilder();
try {
Method getService = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
getService.setAccessible(true);
Object LocationService = getService.invoke(null, "location");
Object PhoneService = getService.invoke(null, "phone");
data.append("locateServiceName:").append(LocationService.getClass().getName()).append("|");
data.append("phoneServiceName:").append(PhoneService.getClass().getName());
}
catch(Throwable v1) {
}
return data.toString();
}
//firmware
/dev/socket/qemud
/dev/qemu_pipe
//firmware2
/sys/qemu_trace
/system/bin/qemu-props
读取/proc/tty/drivers,判断内容中是否有“goldfish”
v3 = new File("/proc/tty/drivers");
比较DeviceID是否为”000000000000000” DeviceID获取方式见下文
检查SimOperator是否为“android” SimOperator获取方式见下文
"unknown".equals(Build.BOARD)
"unknown".equals(Build.BOOTLOADER)
"generic".equals(Build.BRAND)
"generic".equals(Build.DEVICE)
"sdk".equals(Build.MODEL)
"sdk".equals(Build.PRODUCT)
"goldfish".equals(Build.HARDWARE)
this.phoneService = ReflactUtil.invoke(com.ishumei.common.Context.ctx, "getSystemService", new Class[]{String.class}, new Object[]{"phone"});
deviceId = (String)ReflactUtil.invoke(this.phoneService, "getDeviceId");
(String)ReflactUtil.invoke(this.phoneService, "getDeviceId", new Class[]{Integer.TYPE}, new Object[]{((int)arg8)});
从上到下依次尝试
this.phoneService = ReflactUtil.invoke(com.ishumei.common.Context.ctx, "getSystemService", new Class[]{String.class}, new Object[]{"phone"});
result = (String)ReflactUtil.invoke(this.phoneService, "getSimOperator");
result = (String)ReflactUtil.invoke(this.phoneService, "getNetworkOperatorName");
v0_2 = (String)ReflactUtil.invoke(this.phoneService, "getSubscriberId");
v0_2 = (String)ReflactUtil.invoke(this.phoneService, "getSimSerialNumber");
Object[] v6 = {((int)this.isTrue(((boolean)(ctx.checkSelfPermission("android.permission.READ_PHONE_STATE") == 0 ? 1 : 0)))), ((int)this.isTrue(((boolean)(ctx.checkSelfPermission("android.permission.WRITE_EXTERNAL_STORAGE") == 0 ? 1 : 0)))), ((int)this.isTrue(((boolean)(ctx.checkSelfPermission("android.permission.WRITE_SETTINGS") == 0 ? 1 : 0)))), ((int)this.isTrue(((boolean)(ctx.checkSelfPermission("android.permission.ACCESS_WIFI_STATE") == 0 ? 1 : 0)))), ((int)this.isTrue(((boolean)(ctx.checkSelfPermission("android.permission.ACCESS_NETWORK_STATE") == 0 ? 1 : 0)))), ((int)this.isTrue(((boolean)(ctx.checkSelfPermission("android.permission.ACCESS_FINE_LOCATION") == 0 ? 1 : 0)))), null};
if(ctx.checkSelfPermission("android.permission.ACCESS_COARSE_LOCATION") != 0) {
v1 = 0;
}
v6[6] = (int)this.isTrue(((boolean)v1));
return String.format(CHINA, "%d%d%d%d%d%d%d", v6);
public String getBluetoothInfo() {
String v0_7;
Parcel v2_1;
Parcel v1_3;
IBinder v0_5;
try {
BluetoothAdapter v0_1 = BluetoothAdapter.getDefaultAdapter();
Field v1 = BluetoothAdapter.class.getDeclaredField("mService");
v1.setAccessible(true);
Object v1_1 = v1.get(v0_1);
if(v1_1 == null) {
throw new Exception();
}
Object v0_2 = Class.forName("android.bluetooth.IBluetooth$Stub$Proxy").getMethod("getAddress", null).invoke(v1_1, null);
if(v0_2 != null && ((v0_2 instanceof String))) {
return (String)v0_2;
}
throw new Exception();
}
catch(Exception v0) {
try {
Class v0_4 = Class.forName("android.os.ServiceManager");
Class.forName("android.bluetooth.IBluetoothManager");
Class v1_2 = Class.forName("android.bluetooth.IBluetoothManager$Stub");
Field v2 = v1_2.getField("FIRST_CALL_TRANSACTION");
v0_5 = (IBinder)v0_4.getMethod("getService", String.class).invoke(null, "bluetooth_manager");
v2.getInt(v1_2);
v1_3 = Parcel.obtain();
v2_1 = Parcel.obtain();
}
catch(Exception v0_3) {
return "";
}
try {
v1_3.writeInterfaceToken("android.bluetooth.IBluetoothManager");
if(Build.VERSION.SDK_INT >= 21) {
v0_5.transact(5, v1_3, v2_1, 0);
}
else {
v0_5.transact(10, v1_3, v2_1, 0);
}
v2_1.readException();
v0_7 = v2_1.readString();
goto label_87;
}
catch(Throwable v0_6) {
}
try {
v2_1.recycle();
v1_3.recycle();
throw v0_6;
label_87:
v2_1.recycle();
v1_3.recycle();
return v0_7 == null ? "" : v0_7;
}
catch(Exception v0_3) {
}
return "";
}
this.wifiService = ReflactUtil.invoke(this.ctx, "getSystemService", new Class[]{String.class}, new Object[]{"wifi"});
this.mConnectionInfo = ReflactUtil.invoke(this.wifiService, "getConnectionInfo"); SSID
String v0_1 = (String)ReflactUtil.invoke(this.mConnectionInfo, "getSSID");bBSSID
String v0_1 = (String)ReflactUtil.invoke(this.mConnectionInfo, "getBSSID");
String v0_1 = (String)ReflactUtil.invoke(this.mConnectionInfo, "getMacAddress");
String v0_1 = Formatter.formatIpAddress(((Integer)ReflactUtil.invoke(this.mConnectionInfo, "getIpAddress")).intValue());
//先检查权限
v0_1.checkPermission("android.permission.ACCESS_FINE_LOCATION", this.ctx.getPackageName()) != 0 && v0_1.checkPermission("android.permission.ACCESS_COARSE_LOCATION", this.ctx.getPackageName()) != 0
for(Object v0_2: ((List)ReflactUtil.invoke(this.wifiService, "getScanResults"))) {
ScanResult v0_3 = (ScanResult)v0_2;
v2.add(Util.replaceMaoHao(((String)ReflactUtil.getValue(v0_3, "BSSID"))) + "," + ((int)(((Integer)ReflactUtil.getValue(v0_3, "level")))));
}
private String _getNetworkType() {
try {
NetworkInfo networkInfo = ((ConnectivityManager)this.ctx.getSystemService("connectivity")).getActiveNetworkInfo();
if(networkInfo != null && (networkInfo.isAvailable()) && (networkInfo.isConnected())) {
int type = networkInfo.getType();
if(type == 1) {
return "wifi";
}
return type != 0 ? "unknown" : NetworkInfoCollector.getNetworkType(((TelephonyManager)this.ctx.getSystemService("phone")).getNetworkType());
}
return "nil";
}
catch(Exception v0) {
LogUtil.printStackTrace(v0);
return "unknown";
}
return "unknown";
}
//NetworkInfoCollector.getNetworkType
public static String getNetworkType(int arg4) {
switch(arg4) {
case -101: {
return "wifi";
}
case -1: {
return "nil";
}
case 0: {
return "unknown";
}
case 1: {
return "2g.gprs";
}
case 2: {
return "2g.edge";
}
case 3: {
return "3g.umts";
}
case 4: {
return "2g.cdma";
}
case 5: {
return "3g.evdo_0";
}
case 6: {
return "3g.evdo_a";
}
case 7: {
return "2g.1xrtt";
}
case 8: {
return "3g.hsdpa";
}
case 9: {
return "3g.hsupa";
}
case 10: {
return "3g.hspa";
}
case 11: {
return "2g.iden";
}
case 12: {
return "3g.evdo_b";
}
case 13: {
return "4g.lte";
}
case 14: {
return "3g.ehrpd";
}
case 15: {
return "3g.hspap";
}
default: {
return String.format("%d", ((int)arg4));
}
}
}
public List getNetwordIFaceAddrs() {
String v1_1;
ArrayList v6 = new ArrayList();
try {
Object mNetworkInterfaces = ReflactUtil.invoke("java.net.NetworkInterface", "getNetworkInterfaces");
Method hasMoreElements = Enumeration.class.getDeclaredMethod("hasMoreElements");
hasMoreElements.setAccessible(true);
Method nextElement = Enumeration.class.getDeclaredMethod("nextElement");
nextElement.setAccessible(true);
while(((Boolean)hasMoreElements.invoke(mNetworkInterfaces, new Object[0])).booleanValue()) {
NetworkInterface networkInterface = (NetworkInterface)nextElement.invoke(mNetworkInterfaces);
if(networkInterface.isLoopback()) {
continue;
}
String hostAddress = "";
String otherAddr = "";
byte[] hardwareAddress = networkInterface.getHardwareAddress();
String hardwareAddressString = hardwareAddress != null && hardwareAddress.length > 0 ? Util.replaceMaoHao(Util.getHexString(hardwareAddress)) : "";
if((hardwareAddressString.isEmpty()) || (hardwareAddressString.equals("000000000000"))) {
continue;
}
Enumeration inetAddresses = networkInterface.getInetAddresses();
while(inetAddresses.hasMoreElements()) {
InetAddress inetAddress = (InetAddress)inetAddresses.nextElement();
if(inetAddress.isLoopbackAddress()) {
v1_1 = otherAddr;
}
else {
String tmp = inetAddress.getHostAddress();
if(tmp.trim().length() < 17) {
v1_1 = otherAddr;
hostAddress = tmp;
}
else {
v1_1 = tmp;
}
}
otherAddr = v1_1;
}
v6.add(networkInterface.getDisplayName() + "," + hostAddress + "," + hardwareAddressString + "," + otherAddr);
}
}
catch(Exception v0) {
}
return v6;
}
String proxyHost = System.getProperty("http.proxyHost");
String proxyPort = System.getProperty("http.proxyPort");
proxyHost = Proxy.getHost(ctx);
proxyPort = String.valueOf(Proxy.getPort(ctx));
NetworkInfo v0_1 = ((ConnectivityManager)com.ishumei.common.Context.ctx.getSystemService("connectivity")).getActiveNetworkInfo();
return v0_1.isConnected();
this.packageManager = ReflactUtil.invoke(this.ctx, "getPackageManager");
Object v0_1 = ReflactUtil.invoke(this.packageManager, "getPackageInfo", new Class[]{String.class, Integer.TYPE}, new Object[]{this.ctx.getPackageName(), ((int)0x40)});
Object[] signatures = (Object[])ReflactUtil.getValue(v0_1, "signatures");
byte[] v0_1 = (byte[])ReflactUtil.invoke(signatures[0], "toByteArray");
return ((X509Certificate)CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(v0_1))).getSubjectDN().toString();
有一个whiteapp列表 根据applicationInfo.flags来区分是否为系统app,以及自身是否debuggable
List installedPackages = (List)ReflactUtil.invoke(packageManager, "getInstalledPackages", new Class[]{Integer.TYPE}, new Object[]{((int)0)});
PackageInfo pkgInfo = (PackageInfo)installedPackages.get(index);
String packageName = pkgInfo.packageName;
int appFlag = applicationInfo.flags;
String pkgName = Build.VERSION.SDK_INT < 29 ? applicationInfo.loadLabel(((PackageManager)packageManager)).toString() : "";
appInfoList.add("" + pkgInfo.firstInstallTime + "," + packageName + "," + pkgName + "," + isUsrApp + "," + pkgInfo.versionCode + "," + pkgInfo.versionName + "," + pkgInfo.lastUpdateTime);
String v0 = this.ctx.getPackageManager().getPackageInfo("", 0).versionName;
String PackageName = (String)ReflactUtil.invoke(this.ctx, "getPackageName");
String v0_1 = (String)ReflactUtil.invoke(ReflactUtil.getValue(ReflactUtil.invoke(this.packageManager, "getPackageInfo", new Class[]{String.class, Integer.TYPE}, new Object[]{com.ishumei.common.Context.ctx.getPackageName(), ((int)0)}), "applicationInfo"), "loadLabel", new Class[]{PackageManager.class}, new Object[]{this.packageManager});
public int isDebuggable() {
return (com.ishumei.common.Context.ctx.getApplicationInfo().flags & 2) <= 0 ? 0 : 1;
}
private CellLocation getCellLocationData(List cellInfoList) {
int v3_4;
int v0_7;
GsmCellLocation v2_3;
int v3_3;
int v0_5;
CdmaCellLocation v0_4;
Object mCellIdentity;
boolean v0_1;
int type;
Class CellInfoCdma;
Class CellInfoLte;
Class CellInfoWcdma;
Class CellInfoGsm;
if(cellInfoList == null || (cellInfoList.isEmpty())) {
return null;
}
ClassLoader clsLoader = ClassLoader.getSystemClassLoader();
GsmCellLocation mGsmCellLocation = null;
CdmaCellLocation mCdmaCellLocation = null;
int v0 = 0;
int index = 0;
while(index < cellInfoList.size()) {
Object v2 = cellInfoList.get(index);
if(v2 != null) {
try {
CellInfoGsm = clsLoader.loadClass("android.telephony.CellInfoGsm");
CellInfoWcdma = clsLoader.loadClass("android.telephony.CellInfoWcdma");
CellInfoLte = clsLoader.loadClass("android.telephony.CellInfoLte");
CellInfoCdma = clsLoader.loadClass("android.telephony.CellInfoCdma");
boolean v7 = CellInfoGsm.isInstance(v2);
if(v7) {
type = 1;
}
else if(CellInfoWcdma.isInstance(v2)) {
type = 2;
}
else if(CellInfoLte.isInstance(v2)) {
type = 3;
}
else {
v0_1 = CellInfoCdma.isInstance(v2);
goto label_44;
}
goto label_49;
}
catch(Exception v2_1) {
}
int v3_1 = v0;
goto label_160;
label_44:
type = v0_1 ? 4 : 0;
label_49:
if(type > 0) {
Object mCellInfoGsm = null;
if(type == 1) {
try {
mCellInfoGsm = CellInfoGsm.cast(v2);
goto label_67;
label_55:
if(type == 2) {
mCellInfoGsm = CellInfoWcdma.cast(v2);
}
else if(type == 3) {
mCellInfoGsm = CellInfoLte.cast(v2);
}
else if(type == 4) {
mCellInfoGsm = CellInfoCdma.cast(v2);
}
label_67:
mCellIdentity = this.invoke(mCellInfoGsm, "getCellIdentity", new Object[0]);
if(mCellIdentity == null) {
v0 = type;
goto label_168;
}
if(type != 4) {
goto label_116;
}
v0_4 = new CdmaCellLocation();
goto label_79;
}
catch(Exception v0_3) {
v3_1 = type;
goto label_160;
}
}
else {
goto label_55;
}
goto label_67;
try {
label_79:
int SystemId = this.invoke2(mCellIdentity, "getSystemId", new Object[0]);
int NetworkId = this.invoke2(mCellIdentity, "getNetworkId", new Object[0]);
int BasestationId = this.invoke2(mCellIdentity, "getBasestationId", new Object[0]);
int Longitude = this.invoke2(mCellIdentity, "getLongitude", new Object[0]);
v0_4.setCellLocationData(BasestationId, this.invoke2(mCellIdentity, "getLatitude", new Object[0]), Longitude, SystemId, NetworkId);
return type == 4 ? v0_4 : mGsmCellLocation;
}
catch(Exception v1_1) {
}
v3_1 = type;
mCdmaCellLocation = v0_4;
goto label_160;
label_116:
if(type == 3) {
try {
v0_5 = this.invoke2(mCellIdentity, "getTac", new Object[0]);
v3_3 = this.invoke2(mCellIdentity, "getCi", new Object[0]);
v2_3 = new GsmCellLocation();
}
catch(Exception v0_3) {
v3_1 = type;
goto label_160;
}
try {
v2_3.setLacAndCid(v0_5, v3_3);
return type == 4 ? mCdmaCellLocation : v2_3;
}
catch(Exception v0_6) {
}
}
else {
try {
v0_7 = this.invoke2(mCellIdentity, "getLac", new Object[0]);
v3_4 = this.invoke2(mCellIdentity, "getCid", new Object[0]);
v2_3 = new GsmCellLocation();
goto label_154;
}
catch(Exception v0_3) {
}
v3_1 = type;
goto label_160;
try {
label_154:
v2_3.setLacAndCid(v0_7, v3_4);
return type == 4 ? mCdmaCellLocation : v2_3;
}
catch(Exception v0_8) {
}
}
v3_1 = type;
mGsmCellLocation = v2_3;
label_160:
v0 = v3_1;
}
else {
v0 = type;
}
}
label_168:
++index;
}
return v0 == 4 ? mCdmaCellLocation : mGsmCellLocation;
}
DisplayMetrics v0_2 = ctx.getResources().getDisplayMetrics();
return String.format(Locale.CHINA, "%d,%d,%d", ((int)v0_2.widthPixels), ((int)v0_2.heightPixels), ((int)v0_2.densityDpi));
StatFs mStatFs = new StatFs(Environment.getExternalStorageDirectory().getPath());
mStatFs.getAvailableBytes()
mStatFs.getFreeBytes()
mStatFs.getTotalBytes()
public List getSensorsTypeAndVendor() {
ArrayList array = new ArrayList();
try {
for(Object sensor: this.mSensorManager.getSensorList(-1)) {
Sensor sensor = (Sensor)sensor;
array.add(sensor.getType() + "," + sensor.getVendor());
}
}
catch(Exception v0) {
}
return array;
}
对重力传感器、光照传感器和陀螺仪进行若干次数据采集。
Object[] v4 = {this.ctx.getContentResolver(), "android_id"};
String android_id = (String)ReflactUtil.invoke("android.provider.Settings$Secure", "getString", new Class[]{ContentResolver.class, String.class}, v4);
return System.currentTimeMillis() - SystemClock.elapsedRealtime();
public String getSelfProcName() {
String procName;
String result = "";
try {
int selfPid = Process.myPid();
if(this.ctx != null) {
Iterator RunningAppProcesses = ((ActivityManager)this.ctx.getSystemService("activity")).getRunningAppProcesses().iterator();
while(true) {
label_10:
if(!RunningAppProcesses.hasNext()) {
return result;
}
Object running = RunningAppProcesses.next();
ActivityManager.RunningAppProcessInfo procInfo = (ActivityManager.RunningAppProcessInfo)running;
if(procInfo.pid == selfPid) {
procName = procInfo.processName;
goto label_20;
}
else {
procName = result;
result = procName;
goto label_10;
}
result = procName;
}
}
}
catch(Exception v0) {
}
return result;
label_20:
if(procName == null) {
procName = "";
result = procName;
goto label_10;
}
result = procName;
goto label_10;
}
Object[] screen_brightness = {this.ctx.getContentResolver(), "screen_brightness"};
return (int)(((Integer)ReflactUtil.invoke("android.provider.Settings$System", "getInt", new Class[]{ContentResolver.class, String.class}, screen_brightness)));
return Settings.Secure.getInt(v2.getContentResolver(), "mock_location", 0) == 0 ? 0 : 1;
Class v0_1 = Context.class.getClassLoader().loadClass("android.os.SystemProperties");
Method v2 = v0_1.getMethod("get", String.class);
"ro.debuggable"
"ro.boot.serialno"
"gsm.network.type"
"gsm.sim.state"
"persist.sys.country"
"persist.sys.language"
"sys.usb.state"
"ro.serialno"单独做md5处理
Class v3 = Context.class.getClassLoader().loadClass("android.os.SystemProperties");
Method v4 = v3.getMethod("get", String.class);
v4.setAccessible(true);
String[] v5 = {"net.dns1", "net.dns2", "net.dns3", "net.dns4"};
private String get_pw_name(int uid) {
if(Build.VERSION.SDK_INT > 27) {
return String.format(Locale.CHINA, "u0_a%d", ((int)(uid - 10000)));
}
try {
Field v1 = Class.forName("libcore.io.Libcore").getDeclaredField("os");
if(!v1.isAccessible()) {
v1.setAccessible(true);
}
Object v1_1 = v1.get(null);
if(v1_1 != null) {
Method getpwuid = v1_1.getClass().getMethod("getpwuid", Integer.TYPE);
if(getpwuid != null) {
if(!getpwuid.isAccessible()) {
getpwuid.setAccessible(true);
}
Object v1_2 = getpwuid.invoke(v1_1, ((int)uid));
if(v1_2 != null) {
Field v0_1 = v1_2.getClass().getDeclaredField("pw_name");
if(!v0_1.isAccessible()) {
v0_1.setAccessible(true);
}
return (String)v0_1.get(v1_2);
}
}
}
}
catch(Exception v0) {
return String.format(Locale.CHINA, "u0_a%d", ((int)(uid - 10000)));
}
return null;
}
private String get_pw_name() {
int uid = 0;
try {
String cgroup = this.execShell("cat /proc/self/cgroup");
if(!TextUtils.isEmpty(cgroup)) {
int v3 = cgroup.lastIndexOf("uid");
int v1_1 = cgroup.lastIndexOf("/pid");
if(v3 >= 0) {
if(v1_1 <= 0) {
v1_1 = cgroup.length();
}
String uid = cgroup.substring(v3 + 4, v1_1).replaceAll("\n", "");
if(this.checkValidDigit(uid)) {
uid = (int)Integer.valueOf(uid);
}
}
}
}
catch(Exception v1) {
}
if(uid == 0) {
Context ctx = com.ishumei.common.Context.ctx;
if(ctx != null) {
uid = ctx.getApplicationInfo().uid;
}
}
return uid == 0 ? null : this.get_pw_name(uid);
}
private void _setVirtualAppInfo(DeviceInfoData arg13) {
int isVirtualApp = 1;
try {
String pw_name = this.get_pw_name();
if(!TextUtils.isEmpty(pw_name)) {
String psResult = this.execShell("ps");
if(TextUtils.isEmpty(psResult)) {
goto label_80;
}
String[] lines = psResult.split("\n");
if(lines.length <= 0) {
goto label_80;
}
ArrayList array = new ArrayList();
int index = 0;
int count = 0;
while(index < lines.length) {
if(lines[index].contains(pw_name)) {
int v3 = lines[index].lastIndexOf(" ");
String v8 = lines[index];
String pkgName = v8.substring((v3 > 0 ? v3 + 1 : 0), lines[index].length());
if(!TextUtils.isEmpty(pkgName) && (new File(String.format("/data/data/%s", new Object[]{pkgName})).exists())) {
array.add(pkgName);
++count;
}
}
++index;
}
Locale CHINA = Locale.CHINA;
Object[] v6_1 = new Object[1];
if(count <= 1) {
isVirtualApp = 0;
}
v6_1[0] = (int)this.isTrue(((boolean)isVirtualApp));
arg13.setIsVirtualApp(String.format(CHINA, "%d", v6_1));
arg13.setVirtualAppProcCount(String.format(Locale.CHINA, "%d", ((int)count)));
arg13.setVirtualAppPwName(pw_name);
arg13.setVirtualAppPkgNames(array);
return;
}
label_80:
}
catch(Exception v0) {
}
}
fopen读取/proc/sys/kernel/random/uuid 读取失败则设置为default_id,最终结果中会有一个根据UUID生成的Key,作用不明,应该是用来内容加密。
通过_system_property_get函数获取
ro.kernel.qemu
ro.debuggable
ro.secure
ro.build.version.release
ro.build.version.sdk
ro.build.display.id
ro.product.model
ro.product.board
ro.product.brand
ro.product.name
ro.product.manufacturer
ro.boot.baseband
ro.boot.bootloader
ro.serialno
ro.build.fingerprint
从/proc/self/map中获取libc地址范围并检查以下关键函数地址是否在libc范围内(用于检测frida?),使用unidbg跑出来的结果时false,用frida跑出来的结果是true
open
stat
access
fopen
printf
read
mmap
socket
rename
获取网卡信息,首先调用ioctl SIOCGIFCONF找到所有网卡,另外调用ioctl SIOCGIFFLAGS查看网卡是否开启,然后调用ioctl SIOCGIFHWADDR查找网卡MAC地址(高系统版本非root环境下不会获取到),最后还会通过是否有tun网卡判断VPN,是否有ppp判断拨号网卡
#include <cstdio>
#include <cstring>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <zconf.h>
#define MAX_IFS 64
int main(int argc, char **argv) {
struct ifreq *ifr, *ifend;
struct ifreq ifreq{};
struct ifconf ifc{};
struct ifreq ifs[MAX_IFS];
int sockfd;
int on;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
ifc.ifc_len = sizeof(ifs);
ifc.ifc_req = ifs;
ioctl(sockfd, SIOCGIFCONF, &ifc);
ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
if (ifr->ifr_addr.sa_family == AF_INET) {
strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
ioctl(sockfd, SIOCGIFHWADDR, &ifreq);
ioctl(sockfd, SIOCGIFFLAGS, &ifreq);
on = (ifreq.ifr_flags & IFF_UP) != 0;
if (strncmp("wlan", ifreq.ifr_name, 4u) == 0) {
printf("wlan %d\n", on);
} else if (strncmp("tun", ifreq.ifr_name, 3u) == 0) {
printf("tun %d\n", on);
} else {
continue;
}
printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
(int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[0],
(int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[1],
(int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[2],
(int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[3],
(int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[4],
(int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[5]
);
}
}
close(sockfd);
return 0;
}
通过access函数检查文件是否存在
/sbin/su
/system/xbin/su
/system/bin/su
通过open打开/system/bin/ls,然后用pread读取文件头特定偏移值来判断文件abi
通过读取/proc/net/arp来读取HW address,貌似先对ip的最后一位进行判断,若为1则读取硬件地址并全局保存
cat /proc/sys/kernel/random/boot_id
["com.bly.dkplat","com.excelliance.dualaid","com.bfire.da.nui","com.svm.proteinbox_multi","com.boly.wxnewcopy","com.juying.Jixiaomi.fenshen","com.qihoo.magic","com.godinsec.godinsec_private_space","com.sellapk.goapp","com.yizhi.ftd","com.qihoo.magic.xposed","com.excean.dualaid","com.shiyue.avatarlauncher","com.excean.masaid","com.rinzz.avatar","info.red.virtual","com.depu.wxfs","com.sheep2.xyfs","cn.nineox.pupfish","com.shaker.wxxh.moli.fs","com.fssq.weichat","com.smallyin.Avaassis","com.meta.app.fenshen","com.yxd.shpk_multi","com.xiandong.fst","com.xunrui.duokai_box","com.felix.shuangkai","com.dbhydbhy.duokai","com.xuanmutech.fenkai","com.felix.duokai","com.magic.app.reader01","com.cxhcxh.duokai","com.dongguaququ.duokai","com.felix.fenshen","com.nox.mopen.app","com.boly.wxmultopen","com.tyzhzxl.dkwxzs","com.chufa.skzs","com.lbe.parallel","dkmodel","io.virtualapp","com.coloros.oppomultiapp","com.lbe.parallel.intl","com.jumobile.multiapp","com.jumobile.smartapp","info.cloneapp.mochat.in.goast","com.excelliance.multiaccounts","com.ludashi.dualspace","cn.lapstudio.weiduokai","com.parallel.space.lite","com.jiubang.commerce.gomultiple","cn.lapstudio.aid","com.arc.multi","com.nox.mopen.app","io.virtualapp.luohe","com.ludashi.superboost","com.zhushou.weichat","zc.wormhole","com.lanrun.yxjl","com.ivymobi.multiaccount.free","cloner.parallel.space.multiple.accounts.twoface","com.lylm.dkzs","com.rinzz.avatar","com.ludashi.multspace","com.trigtech.privateme","com.jun.virtual","com.pldasoft.dualapp","com.youxi.shuangkai.help","com.jumobile.multiapp.pro","com.applisto.appcloner","multiple.multiple.parallel.accounts.cloner.mochat","com.bba.vma","com.rinzz.wdf"]
匹配文件中是否存在字符串
hypervisor
goldfish
qemu-pipe
goldfish
vbox
virtio
goldfish
vbox
qemu
vbox
qemu
goldfish
eth
eth
遍历文件夹下所有文件,并计算指纹
/vendor/lib
/system/framework
/system/fonts
/vendor/firmware
/system/bin
/data/system