From ca453a26485c0db6f61a608ac2d2822004c63b3a Mon Sep 17 00:00:00 2001 From: codervibe <3507557934@qq.com> Date: Wed, 22 Jan 2025 13:50:30 +0800 Subject: [PATCH 01/12] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/task/web_task.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/libs/task/web_task.py b/libs/task/web_task.py index b47e882..7f31df7 100644 --- a/libs/task/web_task.py +++ b/libs/task/web_task.py @@ -34,15 +34,28 @@ def start(self): return {"comp_list": [], "shell_flag": False, "file_queue": self.file_queue, "packagename": None, "file_identifier": self.file_identifier, "permissions": self.permissions} def __get_scanner_file__(self, scanner_dir, file_suffix): + """ + 递归扫描指定目录下的所有文件,特别是处理特定后缀的文件。 + + :param scanner_dir: 需要扫描的目录路径 + :param file_suffix: 关注的文件后缀名列表 + """ + # 获取目录下的所有文件和子目录 dir_or_files = os.listdir(scanner_dir) for dir_file in dir_or_files: + # 构造完整的文件或目录路径 dir_file_path = os.path.join(scanner_dir, dir_file) + # 如果是目录,则递归调用自身 if os.path.isdir(dir_file_path): self.__get_scanner_file__(dir_file_path, file_suffix) else: + # 如果文件有后缀名 if len(dir_file.split(".")) > 1: + # 如果文件后缀名在关注的后缀名列表中 if dir_file.split(".")[-1] in file_suffix: + # 打开文件,计算并获取MD5值 with open(dir_file_path,'rb') as f: dex_md5 = str(hashlib.md5().update(f.read()).hexdigest()).upper() self.file_identifier.append(dex_md5) - self.file_queue.put(dir_file_path) + # 将文件路径放入队列中 + self.file_queue.put(dir_file_path) \ No newline at end of file From 64f1cdb52116561c93139957958307be4638d054 Mon Sep 17 00:00:00 2001 From: codervibe <3507557934@qq.com> Date: Wed, 22 Jan 2025 13:51:15 +0800 Subject: [PATCH 02/12] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/task/web_task.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/libs/task/web_task.py b/libs/task/web_task.py index 7f31df7..bec0443 100644 --- a/libs/task/web_task.py +++ b/libs/task/web_task.py @@ -20,17 +20,36 @@ def __init__(self, path): self.permissions = [] def start(self): + """ + 根据配置和路径初始化扫描参数。 + + 此方法首先检查配置中的网页文件后缀列表是否为空。如果为空,则使用默认的后缀列表。 + 如果指定路径是目录,则递归扫描该目录下的文件。如果路径是文件,检查其后缀是否在后缀列表中。 + 如果文件后缀不在列表中,抛出异常;否则,将文件路径加入待处理队列。 + + Returns: + dict: 包含扫描参数的字典,如组件列表、是否包含shell脚本标志、文件队列等。 + """ + # 检查配置中的网页文件后缀列表是否为空 if len(config.web_file_suffix) <= 0: scanner_file_suffix = ["html", "js", "html", "xml"] + else: + scanner_file_suffix = config.web_file_suffix - scanner_file_suffix = config.web_file_suffix + # 判断路径是否为目录 if os.path.isdir(self.path): + # 如果是目录,则调用私有方法扫描目录下的文件 self.__get_scanner_file__(self.path, scanner_file_suffix) else: + # 如果不是目录,检查文件后缀是否在后缀列表中 if not (self.path.split(".")[-1] in scanner_file_suffix): + # 如果文件后缀不在列表中,构造错误信息并抛出异常 err_info = ("Retrieval of this file type is not supported. Select a file or directory with a suffix of %s" % ",".join(scanner_file_suffix)) raise Exception(err_info) + # 将符合条件的文件路径加入文件队列 self.file_queue.put(self.path) + + # 返回包含扫描参数的字典 return {"comp_list": [], "shell_flag": False, "file_queue": self.file_queue, "packagename": None, "file_identifier": self.file_identifier, "permissions": self.permissions} def __get_scanner_file__(self, scanner_dir, file_suffix): From b8718ca0ff03ef526b7245fe4a3e9630a49ad137 Mon Sep 17 00:00:00 2001 From: codervibe <3507557934@qq.com> Date: Wed, 22 Jan 2025 13:56:30 +0800 Subject: [PATCH 03/12] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/task/ios_task.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/libs/task/ios_task.py b/libs/task/ios_task.py index c99e397..c006704 100644 --- a/libs/task/ios_task.py +++ b/libs/task/ios_task.py @@ -23,17 +23,36 @@ def __init__(self, path): self.permissions = [] def start(self): + """ + 启动文件处理流程。 + + 本函数根据文件类型(ipa或Mach-o)来执行相应的处理流程。 + 它首先检查文件扩展名,然后根据文件内容或类型进行解码或扫描。 + + Returns: + dict: 包含处理结果的字典,包括shell_flag、file_queue等信息。 + """ + # 获取文件路径 file_path = self.path + + # 判断文件是否为ipa文件 if file_path.split(".")[-1] == 'ipa': + # 对ipa文件进行解码 self.__decode_ipa__(cores.output_path) + # 扫描解码后的ipa文件 self.__scanner_file_by_ipa__(cores.output_path) - elif self.__get_file_header__(file_path): - self.file_queue.put(file_path) else: - raise Exception( - "Retrieval of this file type is not supported. Select IPA file or Mach-o file.") - return {"shell_flag": self.shell_flag, "file_queue": self.file_queue, "comp_list": [], "packagename": None, "file_identifier": self.file_identifier, "permissions": self.permissions} + # 判断文件是否为Mach-o文件 + if self.__get_file_header__(file_path): + # 将文件路径放入文件队列中 + self.file_queue.put(file_path) + else: + # 抛出异常,提示不支持的文件类型 + raise Exception( + "Retrieval of this file type is not supported. Select IPA file or Mach-o file.") + # 返回包含处理结果的字典 + return {"shell_flag": self.shell_flag, "file_queue": self.file_queue, "comp_list": [], "packagename": None, "file_identifier": self.file_identifier, "permissions": self.permissions} def __get_file_header__(self, file_path): hex_hand = 0x0 macho_name = os.path.split(file_path)[-1] From e6d0d02b65a8ae39e9b2590f8ba5986f5a0a24c0 Mon Sep 17 00:00:00 2001 From: codervibe <3507557934@qq.com> Date: Wed, 22 Jan 2025 13:57:41 +0800 Subject: [PATCH 04/12] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/task/ios_task.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/libs/task/ios_task.py b/libs/task/ios_task.py index c006704..976020d 100644 --- a/libs/task/ios_task.py +++ b/libs/task/ios_task.py @@ -54,17 +54,43 @@ def start(self): # 返回包含处理结果的字典 return {"shell_flag": self.shell_flag, "file_queue": self.file_queue, "comp_list": [], "packagename": None, "file_identifier": self.file_identifier, "permissions": self.permissions} def __get_file_header__(self, file_path): + """ + 获取文件头信息并判断是否为Mach-O文件。 + + 参数: + file_path (str): 文件路径。 + + 返回: + bool: 如果文件是Mach-O格式,则返回True,否则返回False。 + """ + # 初始化文件头位置指针 hex_hand = 0x0 + + # 提取文件名作为文件标识符 macho_name = os.path.split(file_path)[-1] self.file_identifier.append(macho_name) + + # 打开二进制文件以读取文件头信息 with open(file_path, "rb") as macho_file: + # 移动文件读取指针到文件头 macho_file.seek(hex_hand, 0) + + # 读取并转换文件头4字节为十六进制表示 magic = binascii.hexlify(macho_file.read(4)).decode().upper() + + # 定义Mach-O文件的魔数列表 macho_magics = ["CFFAEDFE", "CEFAEDFE", "BEBAFECA", "CAFEBABE"] + + # 检查文件头魔数是否匹配Mach-O文件格式 if magic in macho_magics: + # 如果是Mach-O文件,调用私有方法进行进一步处理 self.__shell_test__(macho_file, hex_hand) + + # 关闭文件并返回True表示处理成功 macho_file.close() return True + + # 如果不是Mach-O文件,关闭文件并返回False macho_file.close() return False From 0f6367c3ceee593fe886de53c4b3d97df9344969 Mon Sep 17 00:00:00 2001 From: codervibe <3507557934@qq.com> Date: Wed, 22 Jan 2025 14:00:09 +0800 Subject: [PATCH 05/12] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/task/ios_task.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/libs/task/ios_task.py b/libs/task/ios_task.py index 976020d..331168b 100644 --- a/libs/task/ios_task.py +++ b/libs/task/ios_task.py @@ -95,17 +95,34 @@ def __get_file_header__(self, file_path): return False def __shell_test__(self, macho_file, hex_hand): + """ + 检测给定的macho文件是否包含特定的加密信息,以判断是否具有特定的shell功能。 + + 参数: + - macho_file: 文件对象,指向待检测的macho文件。 + - hex_hand: int,文件内部的初始读取位置指针。 + + 该方法通过读取和解析macho文件的特定部分,判断文件是否具有特定的加密标识, + 从而确定文件是否包含shell功能。这一过程涉及对文件的二进制内容进行解析,并根据 + 解析结果更新类实例的属性。 + """ while True: + # 读取文件的前4字节并将其转换为十六进制字符串,用于判断文件类型 magic = binascii.hexlify(macho_file.read(4)).decode().upper() if magic == "2C000000": + # 当文件类型匹配时,重置文件读取位置到指定的加密信息位置 macho_file.seek(hex_hand, 0) + # 读取并转换加密信息命令的24字节到十六进制字符串 encryption_info_command = binascii.hexlify( macho_file.read(24)).decode() + # 提取加密信息命令的最后8个字符,用于判断加密标识 cryptid = encryption_info_command[-8:len( encryption_info_command)] if cryptid == "01000000": + # 当加密标识匹配时,设置shell标志为True,表示文件包含shell功能 self.shell_flag = True break + # 如果当前文件类型不匹配,移动文件读取位置指针,继续搜索 hex_hand = hex_hand + 4 def __scanner_file_by_ipa__(self, output): From fc05867a7b44f8d06b9457c869cc8b84138cb224 Mon Sep 17 00:00:00 2001 From: codervibe <3507557934@qq.com> Date: Wed, 22 Jan 2025 14:01:05 +0800 Subject: [PATCH 06/12] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/task/ios_task.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/libs/task/ios_task.py b/libs/task/ios_task.py index 331168b..13dd971 100644 --- a/libs/task/ios_task.py +++ b/libs/task/ios_task.py @@ -126,8 +126,25 @@ def __shell_test__(self, macho_file, hex_hand): hex_hand = hex_hand + 4 def __scanner_file_by_ipa__(self, output): + """ + 根据IPA文件扫描特定后缀的文件。 + + 本函数关注于从IPA文件解压后的输出目录中,扫描特定后缀的文件。 + 这些文件可能包含敏感信息或需要进一步处理。 + + 参数: + - output: 解压IPA文件后的输出目录路径。 + + 返回: + 无直接返回值。但通过调用`self.__get_scanner_file__`函数处理扫描结果。 + """ + # 定义需要扫描的文件后缀列表,这些文件类型可能包含需要分析的内容 scanner_file_suffix = ["plist", "js", "xml", "html"] + + # 构造扫描目录路径,"Payload"是IPA解压后包含应用数据的目录 scanner_dir = os.path.join(output, "Payload") + + # 调用内部函数处理具体的文件扫描逻辑 self.__get_scanner_file__(scanner_dir, scanner_file_suffix) def __get_scanner_file__(self, scanner_dir, file_suffix): From 85b58b2a4aa094fc9c7ff7f5195605e08512a49e Mon Sep 17 00:00:00 2001 From: codervibe <3507557934@qq.com> Date: Wed, 22 Jan 2025 14:01:57 +0800 Subject: [PATCH 07/12] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/task/ios_task.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libs/task/ios_task.py b/libs/task/ios_task.py index 13dd971..6e1a1ca 100644 --- a/libs/task/ios_task.py +++ b/libs/task/ios_task.py @@ -148,21 +148,35 @@ def __scanner_file_by_ipa__(self, output): self.__get_scanner_file__(scanner_dir, scanner_file_suffix) def __get_scanner_file__(self, scanner_dir, file_suffix): + """ + 递归获取指定目录下的特定后缀文件。 + + :param scanner_dir: 需要扫描的目录路径 + :param file_suffix: 需要获取的文件后缀名列表 + """ + # 获取目录下的所有文件和子目录 dir_or_files = os.listdir(scanner_dir) for dir_file in dir_or_files: + # 构造完整的文件或目录路径 dir_file_path = os.path.join(scanner_dir, dir_file) + # 如果是目录,则递归调用自身 if os.path.isdir(dir_file_path): + # 如果目录名以.app结尾,提取 ELF 文件名 if dir_file.endswith(".app"): self.elf_file_name = dir_file.replace(".app", "") self.__get_scanner_file__(dir_file_path, file_suffix) else: + # 如果文件名与ELF文件名相同,获取文件头信息并加入处理队列 if self.elf_file_name == dir_file: self.__get_file_header__(dir_file_path) self.file_queue.put(dir_file_path) continue + # 如果资源标志为真,对文件后缀进行处理 if cores.resource_flag: dir_file_suffix = dir_file.split(".") + # 对有后缀的文件进行判断 if len(dir_file_suffix) > 1: + # 如果文件后缀在指定的后缀列表中,获取文件头信息并加入处理队列 if dir_file_suffix[-1] in file_suffix: self.__get_file_header__(dir_file_path) self.file_queue.put(dir_file_path) From dbb804ac0ff27c5e531047b736e571b54f3b8721 Mon Sep 17 00:00:00 2001 From: codervibe <3507557934@qq.com> Date: Wed, 22 Jan 2025 14:03:34 +0800 Subject: [PATCH 08/12] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/task/ios_task.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/libs/task/ios_task.py b/libs/task/ios_task.py index 6e1a1ca..29a4152 100644 --- a/libs/task/ios_task.py +++ b/libs/task/ios_task.py @@ -228,10 +228,30 @@ def __decode_ipa__(self, output_path): shutil.rmtree(old_ext_path) def __get_parse_dir__(self, output_path, file_path): + """ + 根据给定的文件路径和输出路径,获取解析后的目录路径。 + + 该方法首先定位到文件路径中的 "Payload/" 目录和 ".app" 后缀的位置, + 然后根据操作系统对路径进行相应的处理,最后拼接输出路径和处理后的路径, + 返回解析后的目录路径。 + + 参数: + output_path (str): 解析结果的输出路径。 + file_path (str): 需要解析的文件的路径。 + + 返回: + str: 解析后的目录路径。 + """ + # 定位到 "Payload/" 目录的起始位置 start = file_path.index("Payload/") + # 定位到 ".app" 后缀的结束位置 end = file_path.index(".app") + # 提取根目录路径 root_dir = file_path[start:end] + # 如果是 Windows 系统,则将路径中的斜杠替换为反斜杠 if platform.system() == "Windows": root_dir = root_dir.replace("/", "\\") - old_root_dir = os.path.join(output_path, root_dir+".app") + # 拼接输出路径和处理后的根目录路径 + old_root_dir = os.path.join(output_path, root_dir + ".app") + # 返回解析后的目录路径 return old_root_dir From 68a06a2e288a0c0ce907c5e173ef99561f547643 Mon Sep 17 00:00:00 2001 From: codervibe <3507557934@qq.com> Date: Wed, 22 Jan 2025 18:19:14 +0800 Subject: [PATCH 09/12] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/task/ios_task.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libs/task/ios_task.py b/libs/task/ios_task.py index 29a4152..94e03d5 100644 --- a/libs/task/ios_task.py +++ b/libs/task/ios_task.py @@ -182,6 +182,21 @@ def __get_scanner_file__(self, scanner_dir, file_suffix): self.file_queue.put(dir_file_path) def __decode_ipa__(self, output_path): + """ + 解压IPA文件到指定的输出路径。 + + 该函数首先将IPA文件(实际上是一个zip文件)解压到输出路径中。 + 然后它会尝试根据文件名的编码问题进行处理,以确保文件名正确显示。 + 接着,函数会检查解压出来的文件,特别是位于"Payload"目录下的文件, + 并根据需要对它们进行重命名和移动,以确保文件结构与预期一致。 + 最后,函数会清理解压过程中产生的临时目录,以保持文件系统的整洁。 + + 参数: + output_path (str): IPA文件解压后的输出路径。 + + 返回: + 无 + """ with zipfile.ZipFile(self.path, "r") as zip_files: zip_file_names = zip_files.namelist() zip_files.extract(zip_file_names[0], output_path) From 9ee001546171d1abe8001650f8e6fe6685626fba Mon Sep 17 00:00:00 2001 From: codervibe <3507557934@qq.com> Date: Wed, 22 Jan 2025 18:35:35 +0800 Subject: [PATCH 10/12] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/core/net.py | 111 ++++++++++++++++++++++++++++++----------------- 1 file changed, 72 insertions(+), 39 deletions(-) diff --git a/libs/core/net.py b/libs/core/net.py index 52b3a2d..8d0f141 100644 --- a/libs/core/net.py +++ b/libs/core/net.py @@ -52,46 +52,79 @@ def __get_Http_info__(self, threadLock): self.lock.release() - def __get_request_result__(self, url): - result = {"status": "", "server": "", "cookie": "", - "cdn": "", "des_ip": "", "sou_ip": "", "title": ""} - cdn = "" - try: - with requests.get(url, timeout=5, stream=True) as rsp: - status_code = rsp.status_code - result["status"] = status_code - headers = rsp.headers - if "Server" in headers: - result["server"] = headers['Server'] - if "Cookie" in headers: - result["cookie"] = headers['Cookie'] - if "X-Via" in headers: - cdn = cdn + headers['X-Via'] - if "Via" in headers: - cdn = cdn + headers['Via'] - result["cdn"] = cdn - sock = rsp.raw._connection.sock + class SomeClass: + """ + 一个示例类,用于演示如何添加注释。 + """ - if sock: - des_ip = sock.getpeername()[0] - sou_ip = sock.getsockname()[0] - if des_ip: - result["des_ip"] = des_ip - if sou_ip: - result["sou_ip"] = sou_ip - sock.close() - html = rsp.text - title = re.findall('