这篇文章上次修改于 1252 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
好久没有更新公众号了,为庆祝牛郎织女明天相会,水一篇文章刷下存在感。废话不多说开始正文。
操作环境:Pycharm 的Python console 工具里操作的
Androguard
官方文档: https://androguard.readthedocs.io/en/latest/index.html
APK基础信息
此处AnalyzeAPK
类初始化的时间取决于APK的大小,通常APK越大初始化分析时间就越长。
a.get_package()
Out[71]: 'com.tencent.qqmusic'
a.get_max_sdk_version()
a.get_main_activity()
Out[74]: 'com.tencent.qqmusic.activity.AppStarterActivity'
a.get_app_name()
Out[104]: 'QQ音乐'
APK申请的权限
获取APP静态申请的系统权限:
a.get_permissions()
Out[78]:
['android.permission.RECORD_AUDIO',
'android.permission.WRITE_EXTERNAL_STORAGE',
'com.tencent.qqmusic.permission.C2D_MESSAGE',
'com.tencent.qqmusic.permission.MMOAUTH_CALLBACK',
'android.permission.WRITE_SETTINGS',
'android.permission.BROADCAST_STICKY',
'android.permission.MOUNT_UNMOUNT_FILESYSTEMS',
'com.android.launcher.permission.INSTALL_SHORTCUT',
'android.permission.RECEIVE_BOOT_COMPLETED',
'android.permission.ACCESS_BACKGROUND_LOCATION',
'android.permission.GET_TASKS',
'android.permission.READ_PHONE_STATE',
'com.huawei.android.launcher.permission.WRITE_SETTINGS',
'android.permission.REORDER_TASKS',
'android.permission.FOREGROUND_SERVICE',
'com.asus.msa.SupplementaryDID.ACCESS',
'com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA',
'com.huawei.android.launcher.permission.READ_SETTINGS',
'com.tencent.qqmusic.permission.MIPUSH_RECEIVE',
'android.permission.READ_LOGS',
'android.permission.BLUETOOTH',
'android.permission.REQUEST_INSTALL_PACKAGES',
'android.permission.MODIFY_AUDIO_SETTINGS',
'com.android.launcher.permission.READ_SETTINGS',
'android.permission.INTERNET',
'android.permission.WRITE_MEDIA_STORAGE',
'android.permission.ACCESS_WIFI_STATE',
'android.permission.ACCESS_FINE_LOCATION',
'android.permission.CHANGE_WIFI_STATE',
'android.permission.ACTIVITY_RECOGNITION',
'android.permission.QUERY_ALL_PACKAGES',
'com.coloros.mcs.permission.RECIEVE_MCS_MESSAGE',
'android.permission.qqmusic.qqcbdm',
'android.permission.BLUETOOTH_ADMIN',
'android.permission.READ_EXTERNAL_STORAGE',
'com.android.launcher.permission.UNINSTALL_SHORTCUT',
'com.meizu.c2dm.permission.RECEIVE',
'com.oppo.launcher.permission.WRITE_SETTINGS',
'com.tencent.qqmusic.permission.MM_MESSAGE',
'android.permission.ACCESS_NETWORK_STATE',
'android.permission.VIBRATE',
'android.permission.DISABLE_KEYGUARD',
'android.permission.EXPAND_STATUS_BAR',
'android.permission.CHANGE_WIFI_MULTICAST_STATE',
'android.permission.CHANGE_NETWORK_STATE',
'com.tencent.qqmusic.permission.PROCESS_PUSH_MSG',
'com.android.launcher.permission.WRITE_SETTINGS',
'android.permission.ACCESS_COARSE_LOCATION',
'android.permission.WRITE_CALENDAR',
'android.permission.SYSTEM_ALERT_WINDOW',
'com.heytap.mcs.permission.RECIEVE_MCS_MESSAGE',
'com.tencent.qqmusic.WNS_PUSH_BROADCAST',
'com.tencent.qqmusic.push.permission.MESSAGE',
'android.permission.ACCESS_LOCATION_EXTRA_COMMANDS',
'com.huawei.android.launcher.permission.CHANGE_BADGE',
'com.tencent.qqmusic.permission.SEND_BROADCAST_PERMISSION',
'com.tencent.qqmusic.permission.PUSH_PROVIDER',
'android.permission.CAMERA',
'com.oppo.launcher.permission.READ_SETTINGS',
'android.permission.READ_CALENDAR',
'com.meizu.flyme.push.permission.RECEIVE',
'android.permission.RESTART_PACKAGES',
'com.tencent.qqmusic.theme.permission',
'android.permission.WAKE_LOCK']
# 该函数能够获取permission的描述信息
a.get_details_permissions()
APK 组件相关
限于篇幅不再贴出四大组件的结果,直接给出相应方法:
Activity相关方法
Service相关方法,就一个:
Content Providers方法就一个
Broadcast Receiver方法也就一个
这些方法我们只能获取组件名称无法对其进行细粒度的判断,需要将AndroidManifest.xml
转换为字典便于分析。
导入依赖包
import json
import xmltodict
from androguard.misc import AnalyzeAPK
from lxml import etree
转换成字典的方法如下
def manifest_xml2dict(a):
manifest_xml = a.get_android_manifest_xml()
manifest_txt = xmltodict.parse(etree.tostring(manifest_xml))
json_object = json.dumps(manifest_txt)
manifest_dict = json.loads(json_object)
return manifest_dict
接下来按照解析字典方式对要分析的组件进行解析按照自定义规则进行安全检测。
APK 签名相关
例如我们判断APK文件是否存在Janus漏洞,若只有signed_v1则存在该风险。
a.is_signed_v1()
Out[75]: True
a.is_signed_v2()
Out[76]: True
a.is_signed_v3()
Out[77]: True
证书相关操作方法
a.get_signature_names()
Out[88]: ['META-INF/ANDROIDR.RSA']
a.get_signature_names()
Out[89]: ['META-INF/ANDROIDR.RSA']
a.get_signatures()
Out[90]: [b'0\x82\x03\xa0\x06\t*\x86H\x86\xf7\r\x01\x07\x02\xa0\x82\x03\x910\x82\x03\x8d\x02\x01\x011\x0f0\r\x06\t`\x86H\x01e\x03\x04\x02\x01\x05\x000\x0b\x06\t*\x86H\x86\xf7\r\x01\x07\x01\xa0\x82\x02K0\x82\x02G0\x82\x01\xb0\xa0\x03\x02\x01\x02\x02\x04L\xc5D\x9d0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x05\x05\x000g1\x0b0\t\x06\x03U\x04\x06\x13\x02861\x100\x0e\x06\x03U\x04\x08\x13\x07Beijing1\x100\x0e\x06\x03U\x04\x07\x13\x07Beijing1\x100\x0e\x06\x03U\x04\n\x13\x07Tencent1\x100\x0e\x06\x03U\x04\x0b\x13\x07Tencent1\x100\x0e\x06\x03U\x04\x03\x13\x07Tencent0 \x17\r101025084933Z\x18\x0f20601012084933Z0g1\x0b0\t\x06\x03U\x04\x06\x13\x02861\x100\x0e\x06\x03U\x04\x08\x13\x07Beijing1\x100\x0e\x06\x03U\x04\x07\x13\x07Beijing1\x100\x0e\x06\x03U\x04\n\x13\x07Tencent1\x100\x0e\x06\x03U\x04\x0b\x13\x07Tencent1\x100\x0e\x06\x03U\x04\x03\x13\x07Tencent0\x81\x9f0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x81\x8d\x000\x81\x89\x02\x81\x81\x00\x8b\x9a[\xb7v\r\x14\x88\xdc\xc4|\x1d\x9a\xda.K?\t\x8d9`\xb3\x13\xf7Sw\x0e\xa9{\x90R\x89\x8aC\xc7 !72\x01\xf8I5\xe9\xaf\xf6?LUSM\xedb\x02X\xa6Y\xcae\n\x03o\x83\xc8\xfc\xd19;\xe3\x86\xd1\x0c\xa7\x14M\xc2\x04DG\xf9*\xf3\\\xc4\x06\xf7\x9e1o\xdb\xb6\xac7\x19\xbeQ3\xfakM\xf3\xf6T\xa1\x00\t\x99\xdf\tCm<\x14K}\xac*\xa4\xfd\x0fL2\xaf,\x05\x16\xb4\x1f\x02\x03\x01\x00\x010\r\x06\t*\x86H\x86\xf7\r\x01\x01\x05\x05\x00\x03\x81\x81\x00PZ<\xf4\x8a\xff\xde>{\xd9/\xb9icG\xab\xaeg@\x08\xde4\xb74\xce\x04\xd1Z\xab2\x0ft\x1c\x15\xde&O6dFV\xfb\x85-\x00\xa7G\xf5\xab\x0f\xb0\xb0&l\x9b\x9c\xdf\xe3\xb82\xc6\x01B\x15>\xbf\xae\xdf\x02\xb4\x1e6\xe2\x95n\x07\x0fv%\x1f\xbce\xd0\xf1-\xf8\x8d\xf6&o\x19N\xb1\xd7[\x892\x11\x94e-\xf2;l\xba\x18~\xdc\r\x9c\xdd{\x1e\xf7\x84\xa9<\xa7q\xdc^;\x87\x14$\x95;\xa91\x82\x01\x190\x82\x01\x15\x02\x01\x010o0g1\x0b0\t\x06\x03U\x04\x06\x13\x02861\x100\x0e\x06\x03U\x04\x08\x13\x07Beijing1\x100\x0e\x06\x03U\x04\x07\x13\x07Beijing1\x100\x0e\x06\x03U\x04\n\x13\x07Tencent1\x100\x0e\x06\x03U\x04\x0b\x13\x07Tencent1\x100\x0e\x06\x03U\x04\x03\x13\x07Tencent\x02\x04L\xc5D\x9d0\r\x06\t`\x86H\x01e\x03\x04\x02\x01\x05\x000\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x04\x81\x80z\x1f\xd9\x9d\xcc\x190\xbc\xa9\x7f\xfd\x8aU\xe4\x89\x17\x02\xcf5K!\x15\x94\x19\r>\x9e\t+H\xd8y\x05f$\xdc)\xa67\xbaW\xad\xb8u\x81J\xa8H$\xd3\x10\x14\xc9\xdf\x8cLA\xca9\x7f\xc0\xc4\x10\xa7\xb4e\x0cuf\xe5(1\xcc\xbb\xb8$\xd4A\xf5\xc2\xd7\x1a\xef\xb8\xc2\x85\x80\xc7\xb1\x82\xc8.\x0e\x8dt\xd0y\xf2#\xb384K\xad\xf1\x00\xac\x80\xd3:1N\xc7\xe5\xa0\xaa.\xff\x9b\xdc\xfc\x92\x08\xe3\x96V\xbd\x07']
a.get_signature_name()
Out[91]: 'META-INF/ANDROIDR.RSA'
a.get_certificates_v1()
Out[92]: [<asn1crypto.x509.Certificate 16372686800 b'0\x82\x02G0\x82\x01\xb0\xa0\x03\x02\x01\x02\x02\x04L\xc5D\x9d0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x05\x05\x000g1\x0b0\t\x06\x03U\x04\x06\x13\x02861\x100\x0e\x06\x03U\x04\x08\x13\x07Beijing1\x100\x0e\x06\x03U\x04\x07\x13\x07Beijing1\x100\x0e\x06\x03U\x04\n\x13\x07Tencent1\x100\x0e\x06\x03U\x04\x0b\x13\x07Tencent1\x100\x0e\x06\x03U\x04\x03\x13\x07Tencent0 \x17\r101025084933Z\x18\x0f20601012084933Z0g1\x0b0\t\x06\x03U\x04\x06\x13\x02861\x100\x0e\x06\x03U\x04\x08\x13\x07Beijing1\x100\x0e\x06\x03U\x04\x07\x13\x07Beijing1\x100\x0e\x06\x03U\x04\n\x13\x07Tencent1\x100\x0e\x06\x03U\x04\x0b\x13\x07Tencent1\x100\x0e\x06\x03U\x04\x03\x13\x07Tencent0\x81\x9f0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x81\x8d\x000\x81\x89\x02\x81\x81\x00\x8b\x9a[\xb7v\r\x14\x88\xdc\xc4|\x1d\x9a\xda.K?\t\x8d9`\xb3\x13\xf7Sw\x0e\xa9{\x90R\x89\x8aC\xc7 !72\x01\xf8I5\xe9\xaf\xf6?LUSM\xedb\x02X\xa6Y\xcae\n\x03o\x83\xc8\xfc\xd19;\xe3\x86\xd1\x0c\xa7\x14M\xc2\x04DG\xf9*\xf3\\\xc4\x06\xf7\x9e1o\xdb\xb6\xac7\x19\xbeQ3\xfakM\xf3\xf6T\xa1\x00\t\x99\xdf\tCm<\x14K}\xac*\xa4\xfd\x0fL2\xaf,\x05\x16\xb4\x1f\x02\x03\x01\x00\x010\r\x06\t*\x86H\x86\xf7\r\x01\x01\x05\x05\x00\x03\x81\x81\x00PZ<\xf4\x8a\xff\xde>{\xd9/\xb9icG\xab\xaeg@\x08\xde4\xb74\xce\x04\xd1Z\xab2\x0ft\x1c\x15\xde&O6dFV\xfb\x85-\x00\xa7G\xf5\xab\x0f\xb0\xb0&l\x9b\x9c\xdf\xe3\xb82\xc6\x01B\x15>\xbf\xae\xdf\x02\xb4\x1e6\xe2\x95n\x07\x0fv%\x1f\xbce\xd0\xf1-\xf8\x8d\xf6&o\x19N\xb1\xd7[\x892\x11\x94e-\xf2;l\xba\x18~\xdc\r\x9c\xdd{\x1e\xf7\x84\xa9<\xa7q\xdc^;\x87\x14$\x95;\xa9'>]
导入依赖包
from asn1crypto import x509, keys
from oscrypto import asymmetric
import binascii
进行一系列的处理
def get_sign(a):
sign_info = {}
try:
certs = set(
a.get_certificates_der_v3() + a.get_certificates_der_v2() + [a.get_certificate_der(x) for x in
a.get_signature_names()])
pkeys = set(a.get_public_keys_der_v3() +
a.get_public_keys_der_v2())
for cert in certs:
x509_cert = x509.Certificate.load(cert)
sign_info['sign_v1'] = str(a.is_signed_v1()).lower()
sign_info['sign_v2'] = str(a.is_signed_v2()).lower()
sign_info['sign_v3'] = str(a.is_signed_v3()).lower()
sign_info['serial_Number'] = hex(x509_cert.serial_number)
sign_info['hash_algorithm'] = x509_cert.hash_algo
sign_info['signature_algorithm'] = x509_cert.signature_algo
sign_info['valid_not_before'] = str(
x509_cert['tbs_certificate']['validity']['not_before'].native)
sign_info['valid_not_after'] = str(
x509_cert['tbs_certificate']['validity']['not_after'].native)
if len(certs) > 0:
print("Found {} unique public keys associated with the certs".format(len(pkeys)))
for public_key in pkeys:
x509_public_key = asymmetric.load_public_key(public_key)
sign_info['issuer'] = x509_public_key.algorithm
sign_info['bit_size'] = str(x509_public_key.bit_size)
sign_info['fingerprint'] = binascii.hexlify(
x509_public_key.fingerprint).decode('utf-8')
except Exception as e:
print(e)
return sign_info
# 调用演示
sign=get_sign(a)
Found 1 unique public keys associated with the certs
sign
Out[103]:
{'sign_v1': 'true',
'sign_v2': 'true',
'sign_v3': 'true',
'serial_Number': '0x4cc5449d',
'hash_algorithm': 'sha1',
'signature_algorithm': 'rsassa_pkcs1v15',
'valid_not_before': '2010-10-25 08:49:33+00:00',
'valid_not_after': '2060-10-12 08:49:33+00:00',
'issuer': 'rsa',
'bit_size': '1024',
'fingerprint': '036bed21f5938817b0e0bdd4bf066d748660b5494aaab83c93889e79e4104812'}
APK 交叉引用分析
获取所有的类:dx.get_classes()
获取所有的方法:dx.get_methods()
获取所有的字符串:dx.get_strings()
可以获取某个方法的调用链。例如分析获取剪切板内容
函数的调用分析
for method in dx.find_methods(classname='Landroid/content/ClipboardManager;', methodname='getPrimaryClip'):
for call in method.get_xref_from():
print(call[1].__str__().split('@')[0])
# 若想打印 代码块可以使用如下方法
# print(call[1].get_source())
Lcom/tencent/qqmusic/clipboard/b;->a()Ljava/lang/String; [access_flags=private final]
Lcom/tencent/mobileqq/webviewplugin/plugins/d;->a(Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; [Ljava/lang/String;)Z [access_flags=protected varargs]
Lcom/tencent/qqmusic/business/timeline/post/mention/MentionEditText;->a(Ljava/lang/String;)I [access_flags=private final]
Lcom/tencent/mtt/hippy/modules/nativemodules/clipboard/ClipboardModule;->getString(Lcom/tencent/mtt/hippy/modules/Promise;)V [access_flags=public]
Lcom/tencent/qqmusic/business/timeline/post/mention/MentionEditText;->getClipboardAndClipStr()Lkotlin/Pair; [access_flags=public final]
Lcom/tencent/qqmusic/business/timeline/post/mention/MentionEditText;->a(Ljava/lang/String;)I [access_flags=private final]
Lcom/tencent/qqmusic/redpacket/d;->a(Lcom/tencent/qqmusic/activity/baseactivity/BaseActivity;)V [access_flags=public final]
Lcom/tencent/qqmusic/clipboard/b;->a()Ljava/lang/String; [access_flags=private final]
Ljackpal/androidterm/emulatorview/a/g;->a()Ljava/lang/CharSequence; [access_flags=public]
Lcom/tencent/mtt/hippy/modules/nativemodules/clipboard/ClipboardModule;->getString(Lcom/tencent/mtt/hippy/modules/Promise;)V [access_flags=public]
Ljackpal/androidterm/emulatorview/a/g;->b()Z [access_flags=public]
检测到11处调用该方法。
对漏洞的检测只要更新类名和方法名即可。重要的是检测规则。
小结
1.库的使用很简单,有时候库中方法的输出达不到我们的预期输出,则需要查看一下代码,我们重新改写下即可。
2.库的交叉引用很方便的查找到目标方法的调用链、调用代码块。其实对APK漏洞的检测只要替换类名和方法名即可。替换为存在安全问题的类和相应类中方法即可。
3.Androguard 也不是没有缺点。目前对内部类,接口实现类的调用链检测不太友好。
只有一条评论 (QwQ)
很不错