Merge pull request #30 from kelvinBen/v1.0.9.1

add "识别到壳后自动进行脱壳处理"
master
kelvinBen 2 years ago committed by GitHub
commit b8a2aa0c3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 61
      app.py
  2. 19
      libs/core/__init__.py
  3. 348
      libs/task/android_task.py
  4. 2
      requirements.txt
  5. BIN
      tools/unpacker/aapt.exe
  6. BIN
      tools/unpacker/adb.exe
  7. BIN
      tools/unpacker/hexl-server-arm32
  8. BIN
      tools/unpacker/hexl-server-arm64

@ -13,19 +13,28 @@ from libs.task.base_task import BaseTask
def cli(): def cli():
pass pass
# 创建Android任务 # 创建Android任务
@cli.command(help="Get the key information of Android system.") @cli.command(help="Get the key information of Android system.")
@click.option("-i", "--inputs", required=True, type=str, help="Please enter the APK file or DEX file to be scanned or the corresponding APK download address.") @click.option("-i", "--inputs", required=True, type=str,
@click.option("-r", "--rules", required=False, type=str, default="", help="Please enter a rule for temporary scanning of file contents.") help="Please enter the APK file or DEX file to be scanned or the corresponding APK download address.")
@click.option("-s", "--sniffer", is_flag=True, default=False, help="Enable the network sniffer function. It is on by default.") @click.option("-r", "--rules", required=False, type=str, default="",
@click.option("-n", '--no-resource', is_flag=True, default=False, help="Ignore all resource files, including network sniffing. It is not enabled by default.") help="Please enter a rule for temporary scanning of file contents.")
@click.option("-a", '--all', is_flag=True, default=False, help="Output the string content that conforms to the scan rules.It is on by default.") @click.option("-s", "--sniffer", is_flag=True, default=False,
@click.option("-t", '--threads', required=False, type=int, default=10, help="Set the number of concurrency. The larger the concurrency, the faster the speed. The default value is 10.") help="Enable the network sniffer function. It is on by default.")
@click.option("-n", '--no-resource', is_flag=True, default=False,
help="Ignore all resource files, including network sniffing. It is not enabled by default.")
@click.option("-a", '--all', is_flag=True, default=False,
help="Output the string content that conforms to the scan rules.It is on by default.")
@click.option("-t", '--threads', required=False, type=int, default=10,
help="Set the number of concurrency. The larger the concurrency, the faster the speed. The default value is 10.")
@click.option("-o", '--output', required=False, type=str, default=None, help="Specify the result set output directory.") @click.option("-o", '--output', required=False, type=str, default=None, help="Specify the result set output directory.")
@click.option("-p", '--package', required=False, type=str, default="", help="Specifies the package name information that needs to be scanned.") @click.option("-p", '--package', required=False, type=str, default="",
def android(inputs: str, rules: str, sniffer: bool, no_resource: bool, all: bool, threads: int, output, package: str) -> None: help="Specifies the package name information that needs to be scanned.")
def android(inputs: str, rules: str, sniffer: bool, no_resource: bool, all: bool, threads: int, output,
package: str) -> None:
try: try:
bootstrapper = Bootstrapper(__file__, output, all, no_resource) bootstrapper = Bootstrapper(__file__, output, all, no_resource)
bootstrapper.init() bootstrapper.init()
@ -36,12 +45,18 @@ def android(inputs: str, rules: str, sniffer: bool, no_resource: bool, all: bool
@cli.command(help="Get the key information of iOS system.") @cli.command(help="Get the key information of iOS system.")
@click.option("-i", "--inputs", required=True, type=str, help="Please enter IPA file or ELF file to scan or corresponding IPA download address. App store is not supported at present.") @click.option("-i", "--inputs", required=True, type=str,
@click.option("-r", "--rules", required=False, type=str, default="", help="Please enter a rule for temporary scanning of file contents.") help="Please enter IPA file or ELF file to scan or corresponding IPA download address. App store is not supported at present.")
@click.option("-s", "--sniffer", is_flag=True, default=False, help="Enable the network sniffer function. It is on by default.") @click.option("-r", "--rules", required=False, type=str, default="",
@click.option("-n", '--no-resource', is_flag=True, default=False, help="Ignore all resource files, including network sniffing. It is not enabled by default.") help="Please enter a rule for temporary scanning of file contents.")
@click.option("-a", '--all', is_flag=True, default=False, help="Output the string content that conforms to the scan rules.It is on by default.") @click.option("-s", "--sniffer", is_flag=True, default=False,
@click.option("-t", '--threads', required=False, type=int, default=10, help="Set the number of concurrency. The larger the concurrency, the faster the speed. The default value is 10.") help="Enable the network sniffer function. It is on by default.")
@click.option("-n", '--no-resource', is_flag=True, default=False,
help="Ignore all resource files, including network sniffing. It is not enabled by default.")
@click.option("-a", '--all', is_flag=True, default=False,
help="Output the string content that conforms to the scan rules.It is on by default.")
@click.option("-t", '--threads', required=False, type=int, default=10,
help="Set the number of concurrency. The larger the concurrency, the faster the speed. The default value is 10.")
@click.option("-o", '--output', required=False, type=str, default=None, help="Specify the result set output directory.") @click.option("-o", '--output', required=False, type=str, default=None, help="Specify the result set output directory.")
def ios(inputs: str, rules: str, sniffer: bool, no_resource: bool, all: bool, threads: int, output: str) -> None: def ios(inputs: str, rules: str, sniffer: bool, no_resource: bool, all: bool, threads: int, output: str) -> None:
try: try:
@ -54,12 +69,18 @@ def ios(inputs: str, rules: str, sniffer: bool, no_resource: bool, all: bool, th
@cli.command(help="Get the key information of Web system.") @cli.command(help="Get the key information of Web system.")
@click.option("-i", "--inputs", required=True, type=str, help="Please enter the site directory or site file to scan or the corresponding site download address.") @click.option("-i", "--inputs", required=True, type=str,
@click.option("-r", "--rules", required=False, type=str, default="", help="Please enter a rule for temporary scanning of file contents.") help="Please enter the site directory or site file to scan or the corresponding site download address.")
@click.option("-s", "--sniffer", is_flag=True, default=False, help="Enable the network sniffer function. It is on by default.") @click.option("-r", "--rules", required=False, type=str, default="",
@click.option("-n", '--no-resource', is_flag=True, default=False, help="Ignore all resource files, including network sniffing. It is not enabled by default.") help="Please enter a rule for temporary scanning of file contents.")
@click.option("-a", '--all', is_flag=True, default=False, help="Output the string content that conforms to the scan rules.It is on by default.") @click.option("-s", "--sniffer", is_flag=True, default=False,
@click.option("-t", '--threads', required=False, type=int, default=10, help="Set the number of concurrency. The larger the concurrency, the faster the speed. The default value is 10.") help="Enable the network sniffer function. It is on by default.")
@click.option("-n", '--no-resource', is_flag=True, default=False,
help="Ignore all resource files, including network sniffing. It is not enabled by default.")
@click.option("-a", '--all', is_flag=True, default=False,
help="Output the string content that conforms to the scan rules.It is on by default.")
@click.option("-t", '--threads', required=False, type=int, default=10,
help="Set the number of concurrency. The larger the concurrency, the faster the speed. The default value is 10.")
@click.option("-o", '--output', required=False, type=str, default=None, help="Specify the result set output directory.") @click.option("-o", '--output', required=False, type=str, default=None, help="Specify the result set output directory.")
def web(inputs: str, rules: str, sniffer: bool, no_resource: bool, all: bool, threads: int, output: str) -> None: def web(inputs: str, rules: str, sniffer: bool, no_resource: bool, all: bool, threads: int, output: str) -> None:
try: try:

@ -16,6 +16,16 @@ backsmali_path = ""
# apktool 所在路径 # apktool 所在路径
apktool_path = "" apktool_path = ""
# adb 所在路径
adb_path = ""
# frida server 所在路径
frida32_path = ""
frida64_path = ""
# aapt 所在路径
aapt_apth = ""
# 系统类型 # 系统类型
os_type = "" os_type = ""
@ -28,12 +38,17 @@ download_flag = False
# excel 起始行号 # excel 起始行号
excel_row = 1 excel_row = 1
class Bootstrapper(object): class Bootstrapper(object):
def __init__(self, path, out_path, all=False, no_resource=False): def __init__(self, path, out_path, all=False, no_resource=False):
global smali_path global smali_path
global backsmali_path global backsmali_path
global apktool_path global apktool_path
global adb_path
global frida32_path
global frida64_path
global aapt_apth
global os_type global os_type
global output_path global output_path
global script_root_dir global script_root_dir
@ -76,6 +91,10 @@ class Bootstrapper(object):
backsmali_path = os.path.join(tools_dir, "baksmali.jar") backsmali_path = os.path.join(tools_dir, "baksmali.jar")
apktool_path = os.path.join(tools_dir, "apktool.jar") apktool_path = os.path.join(tools_dir, "apktool.jar")
adb_path = os.path.join(tools_dir + '\\unpacker', "adb.exe")
frida32_path = os.path.join(tools_dir + '\\unpacker', "hexl-server-arm32")
frida64_path = os.path.join(tools_dir + '\\unpacker', "hexl-server-arm64")
aapt_apth = os.path.join(tools_dir + '\\unpacker', "aapt.exe")
download_path = os.path.join(out_dir, "download") download_path = os.path.join(out_dir, "download")
txt_result_path = os.path.join(out_dir, "result_" + str(create_time) + ".txt") txt_result_path = os.path.join(out_dir, "result_" + str(create_time) + ".txt")
xls_result_path = os.path.join(out_dir, "result_" + str(create_time) + ".xlsx") xls_result_path = os.path.join(out_dir, "result_" + str(create_time) + ".xlsx")

@ -2,10 +2,16 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Author: kelvinBen # Author: kelvinBen
# Github: https://github.com/kelvinBen/AppInfoScanner # Github: https://github.com/kelvinBen/AppInfoScanner
import json
import os import os
import re import re
import shutil
import subprocess
import config import config
import hashlib import hashlib
import zipfile
import platform
from queue import Queue from queue import Queue
import libs.core as cores import libs.core as cores
@ -21,14 +27,279 @@ class AndroidTask(object):
self.comp_list = [] self.comp_list = []
self.file_identifier = [] self.file_identifier = []
self.permissions = [] self.permissions = []
self.files = []
self.protect_flag = """{
"360加固": [
"assets/.appkey",
"assets/libjiagu.so",
"libjiagu.so",
"libjiagu_art.so",
"libjiagu_x86.so",
"libprotectClass.so",
".appkey",
"1ibjgdtc.so",
"libjgdtc.so",
"libjgdtc_a64.so",
"libjgdtc_art.so",
"libjgdtc_x64.so",
"libjgdtc_x86.so",
"libjiagu_a64.so",
"libjiagu_ls.so",
"libjiagu_x64.so"
],
"APKProtect": [
"libAPKProtect.so"
],
"UU安全": [
"libuusafe.jar.so",
"libuusafe.so",
"libuusafeempty.so",
"assets/libuusafe.jar.so",
"assets/libuusafe.so",
"lib/armeabi/libuusafeempty.so"
],
"apktoolplus": [
"assets/jiagu_data.bin",
"assets/sign.bin",
"jiagu_data.bin",
"lib/armeabi/libapktoolplus_jiagu.so",
"libapktoolplus_jiagu.so",
"sign.bin"
],
"中国移动加固": [
"assets/mogosec_classes",
"assets/mogosec_data",
"assets/mogosec_dexinfo",
"assets/mogosec_march",
"ibmogosecurity.so",
"lib/armeabi/libcmvmp.so",
"lib/armeabi/libmogosec_dex.so",
"lib/armeabi/libmogosec_sodecrypt.so",
"lib/armeabi/libmogosecurity.so",
"libcmvmp.so",
"libmogosec_dex.so",
"libmogosec_sodecrypt.so",
"mogosec_classes",
"mogosec_data",
"mogosec_dexinfo",
"mogosec_march"
],
"几维安全": [
"assets/dex.dat",
"lib/armeabi/kdpdata.so",
"lib/armeabi/libkdp.so",
"lib/armeabi/libkwscmm.so",
"libkwscmm.so",
"libkwscr.so",
"libkwslinker.so"
],
"启明星辰": [
"libvenSec.so",
"libvenustech.so"
],
"网秦加固": [
"libnqshield.so"
],
"娜迦加固": [
"libchaosvmp.so",
"libddog.so",
"libfdog.so"
],
"娜迦加固(新版2022)": [
"assets/maindata/fake_classes.dex",
"lib/armeabi/libxloader.so",
"lib/armeabi-v7a/libxloader.so",
"lib/arm64-v8a/libxloader.so",
"libxloader.so"
],
"娜迦加固(企业版)": [
"libedog.so"
],
"梆梆安全(企业版)": [
"libDexHelper-x86.so",
"libDexHelper.so",
"1ibDexHelper.so"
],
"梆梆安全": [
"libSecShell.so",
"libsecexe.so",
"libsecmain.so",
"libSecShel1.so"
],
"梆梆安全(定制版)": [
"assets/classes.jar",
"lib/armeabi/DexHelper.so"
],
"梆梆安全(免费版)": [
"assets/secData0.jar",
"lib/armeabi/libSecShell-x86.so",
"lib/armeabi/libSecShell.so"
],
"海云安加固": [
"assets/itse",
"lib/armeabi/libitsec.so",
"libitsec.so"
],
"爱加密": [
"assets/af.bin",
"assets/ijiami.ajm",
"assets/ijm_lib/X86/libexec.so",
"assets/ijm_lib/armeabi/libexec.so",
"assets/signed.bin",
"ijiami.dat",
"lib/armeabi/libexecmain.so",
"libexecmain.so"
],
"爱加密企业版": [
"ijiami.ajm"
],
"珊瑚灵御": [
"assets/libreincp.so",
"assets/libreincp_x86.so",
"libreincp.so",
"libreincp_x86.so"
],
"瑞星加固": [
"librsprotect.so"
],
"百度加固": [
"libbaiduprotect.so",
"assets/baiduprotect.jar",
"assets/baiduprotect1.jar",
"baiduprotect1.jar",
"lib/armeabi/libbaiduprotect.so",
"libbaiduprotect_art.so",
"libbaiduprotect_x86.so"
],
"盛大加固": [
"libapssec.so"
],
"网易易盾": [
"libnesec.so"
],
"腾讯": [
"libexec.so",
"libshell.so"
],
"腾讯加固": [
"lib/armeabi/mix.dex",
"lib/armeabi/mixz.dex",
"lib/armeabi/libshella-xxxx.so",
"lib/armeabi/libshellx-xxxx.so",
"tencent_stub"
],
"腾讯乐固(旧版)": [
"libtup.so",
"mix.dex",
"liblegudb.so",
"libshella",
"mixz.dex",
"libshel1x"
],
"腾讯乐固": [
"libshellx"
],
"腾讯乐固(VMP)": [
"lib/arm64-v8a/libxgVipSecurity.so",
"lib/armeabi-v7a/libxgVipSecurity.so",
"libxgVipSecurity.so"
],
"腾讯云": [
"assets/libshellx-super.2021.so",
"lib/armeabi/libshell-super.2019.so",
"lib/armeabi/libshell-super.2020.so",
"lib/armeabi/libshell-super.2021.so",
"lib/armeabi/libshell-super.2022.so",
"lib/armeabi/libshell-super.2023.so",
"tencent_sub"
],
"腾讯云移动应用安全": [
"0000000lllll.dex",
"00000olllll.dex",
"000O00ll111l.dex",
"00O000ll111l.dex",
"0OO00l111l1l",
"o0oooOO0ooOo.dat"
],
"腾讯云移动应用安全(腾讯御安全)": [
"libBugly-yaq.so",
"libshell-super.2019.so",
"libshellx-super.2019.so",
"libzBugly-yaq.so",
"t86",
"tosprotection",
"tosversion",
"000000011111.dex",
"000000111111.dex",
"000001111111",
"00000o11111.dex",
"o0ooo000oo0o.dat"
],
"腾讯御安全": [
"libtosprotection.armeabi-v7a.so",
"libtosprotection.armeabi.so",
"libtosprotection.x86.so",
"assets/libtosprotection.armeabi-v7a.so",
"assets/libtosprotection.armeabi.so",
"assets/libtosprotection.x86.so",
"assets/tosversion",
"lib/armeabi/libTmsdk-xxx-mfr.so",
"lib/armeabi/libtest.so"
],
"腾讯Bugly": [
"lib/arm64-v8a/libBugly.so",
"libBugly.so"
],
"蛮犀": [
"assets/mxsafe.config",
"assets/mxsafe.data",
"assets/mxsafe.jar",
"assets/mxsafe/arm64-v8a/libdSafeShell.so",
"assets/mxsafe/x86_64/libdSafeShell.so",
"libdSafeShell.so"
],
"通付盾": [
"libNSaferOnly.so",
"libegis.so"
],
"阿里加固": [
"assets/armeabi/libfakejni.so",
"assets/armeabi/libzuma.so",
"assets/classes.dex.dat",
"assets/dp.arm-v7.so.dat",
"assets/dp.arm.so.dat",
"assets/libpreverify1.so",
"assets/libzuma.so",
"assets/libzumadata.so",
"dexprotect"
],
"阿里聚安全": [
"aliprotect.dat",
"libdemolish.so",
"libfakejni.so",
"libmobisec.so",
"libsgmain.so",
"libzuma.so",
"libzumadata.so",
"libdemolishdata.so",
"libpreverify1.so",
"libsgsecuritybody.so"
],
"顶像科技": [
"libx3g.so",
"lib/armeabi/libx3g.so"
]
}"""
def start(self): def start(self):
# 检查java环境是否存在 # 检查java环境是否存在
if os.system("java -version") != 0: if os.system("java -version") != 0:
raise Exception("Please install the Java environment!") raise Exception("Please install the Java environment!")
# 检查Frida环境是否存在
if os.system("frida --version") != 0:
raise Exception("Please install the Frida environment!")
input_file_path = self.path input_file_path = self.path
if os.path.isdir(input_file_path): if os.path.isdir(input_file_path):
self.__decode_dir__(input_file_path) self.__decode_dir__(input_file_path)
else: else:
@ -36,7 +307,68 @@ class AndroidTask(object):
raise Exception( raise Exception(
"Retrieval of this file type is not supported. Select APK file or DEX file.") "Retrieval of this file type is not supported. Select APK file or DEX file.")
return {"comp_list": self.comp_list, "shell_flag": self.shell_flag, "file_queue": self.file_queue, "packagename": self.packagename, "file_identifier": self.file_identifier, "permissions": self.permissions} return {"comp_list": self.comp_list, "shell_flag": self.shell_flag, "file_queue": self.file_queue,
"packagename": self.packagename, "file_identifier": self.file_identifier,
"permissions": self.permissions}
def __detect_protect__(self, file_path):
markNameMap = json.loads(self.protect_flag)
markNameMap = dict(markNameMap)
zip_stream = zipfile.ZipFile(file_path) # 默认模式r,读
flag = ''
for zippath in zip_stream.namelist():
if 'lib' in zippath:
for key, value in markNameMap.items():
for mark in value:
if mark in zippath:
print("detect 【{}】 protector\nspecific code:{}->{}\n".format(key, zippath, mark))
flag += ("detect 【{}】 protector\nspecific code:{}->{}\n".format(key, zippath, mark))
if len(flag) > 0:
self.__android_unpack__()
# so库文件模式找不到就全量匹配
for zippath in zip_stream.namelist():
for key, value in markNameMap.items():
for mark in value:
if mark in zippath:
print("detect 【{}】 protector\nspecific code:{}->{}\n".format(key, zippath, mark))
flag += ("detect 【{}】 protector\nspecific code:{}->{}\n".format(key, zippath, mark))
if len(flag) > 0:
self.__android_unpack__()
print("We can't detect protect")
def __android_unpack__(self):
print('[*] unpacking')
cmd_str = ('%s install %s') % (str(cores.adb_path), str(self.path))
print('[*] Install the APK')
if os.system(cmd_str) == 0:
print("Push Frida Server")
cmd_str = ('%s push %s /data/local/tmp') % (str(cores.adb_path), str(cores.frida32_path))
cmd_str1 = ('%s push %s /data/local/tmp') % (str(cores.adb_path), str(cores.frida64_path))
cmd_str2 = ('%s shell su -c "chmod 777 /data/local/tmp/hexl-server-arm64"') % (str(cores.adb_path))
cmd_str3 = ('%s shell su -c "setenforce 0"') % (str(cores.adb_path))
cmd_str4 = ('%s shell su -c "./data/local/tmp/hexl-server-arm64 &"') % (str(cores.adb_path))
print("[*] Running Frida Server")
if os.system(cmd_str) == 0 and os.system(cmd_str1) == 0 and os.system(cmd_str2) == 0 \
and os.system(cmd_str3) == 0 and os.system(cmd_str4) == 0:
print("[*] Frida Server started")
else:
print("[-] Running failed, please check the error in terminal")
exit()
else:
print("[-] We can't install the APP")
exit()
get_info_command = "%s dump badging %s" % (cores.aapt_apth, self.path)
pip = os.popen(get_info_command)
output = pip.buffer.read().decode('utf-8', 'ignore')
if output == "":
raise Exception("can't get the app info")
match = re.compile("package: name='(\S+)'").match(
output) # 通过正则匹配,获取包名
print(match.group(1))
cmd_str = ('frida-dexdump -U -f %s') % (str(match.group(1)))
if os.system(cmd_str) != 0:
print("An error occurred in the unpack")
exit()
def __decode_file__(self, file_path): def __decode_file__(self, file_path):
apktool_path = str(cores.apktool_path) apktool_path = str(cores.apktool_path)
@ -45,6 +377,9 @@ class AndroidTask(object):
filename = os.path.basename(file_path) filename = os.path.basename(file_path)
suffix_name = filename.split(".")[-1] suffix_name = filename.split(".")[-1]
if suffix_name == "apk":
self.__detect_protect__(file_path)
if suffix_name == "apk" or suffix_name == "hpk": if suffix_name == "apk" or suffix_name == "hpk":
name = filename.split(".")[0] name = filename.split(".")[0]
output_path = os.path.join(base_out_path, name) output_path = os.path.join(base_out_path, name)
@ -84,7 +419,8 @@ class AndroidTask(object):
self.__shell_test__(output_path) self.__shell_test__(output_path)
self.__scanner_file_by_apktool__(output_path) self.__scanner_file_by_apktool__(output_path)
else: else:
print("[-] Decompilation failed, please submit error information at https://github.com/kelvinBen/AppInfoScanner/issues") print(
"[-] Decompilation failed, please submit error information at https://github.com/kelvinBen/AppInfoScanner/issues")
raise Exception(file_path + ", Decompilation failed.") raise Exception(file_path + ", Decompilation failed.")
# 分解dex # 分解dex
@ -94,7 +430,8 @@ class AndroidTask(object):
if os.system(cmd_str) == 0: if os.system(cmd_str) == 0:
self.__get_scanner_file__(output_path) self.__get_scanner_file__(output_path)
else: else:
print("[-] Decompilation failed, please submit error information at https://github.com/kelvinBen/AppInfoScanner/issues") print(
"[-] Decompilation failed, please submit error information at https://github.com/kelvinBen/AppInfoScanner/issues")
raise Exception(file_path + ", Decompilation failed.") raise Exception(file_path + ", Decompilation failed.")
# 初始化检测文件信息 # 初始化检测文件信息
@ -119,7 +456,8 @@ class AndroidTask(object):
if os.path.isdir(dir_file_path): if os.path.isdir(dir_file_path):
self.__get_scanner_file__(dir_file_path, scanner_file_suffixs) self.__get_scanner_file__(dir_file_path, scanner_file_suffixs)
else: else:
if ("." not in dir_or_file) or (len(dir_or_file.split(".")) < 1) or (dir_or_file.split(".")[-1] not in scanner_file_suffixs): if ("." not in dir_or_file) or (len(dir_or_file.split(".")) < 1) or (
dir_or_file.split(".")[-1] not in scanner_file_suffixs):
continue continue
self.file_queue.put(dir_file_path) self.file_queue.put(dir_file_path)
for component in config.filter_components: for component in config.filter_components:

@ -1,3 +1,5 @@
requests requests
click click
openpyxl openpyxl
frida-tools==11.0.0
frida-dexdump

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.
Loading…
Cancel
Save