# 1 Android 模拟器按进程捕包准备

## 1.1 adb

### 1.1.1 adb简介

Android 调试桥 (adb) 是一种功能多样的命令行工具，可与设备进行通信，所有 adb 客户端均使用端口 5037 与 adb 服务器通信。

## 1.1.2 adb安装

推荐使用模拟器相同的adb.exe进行连接，打开模拟器安装路径，找到adb.exe，并将其路径添加到系统path中。

或官网下载adb进行安装并将其添加到系统path中。（不推荐 可能因为adb版本问题导致连接异常）
https://dl.google.com/android/repository/platform-tools-latest-windows.zip

## 1.2 Android模拟器

常用模拟器及其端口

模拟器名称 | 端口
--- | ---
网易MuMu安卓模拟器 | 7555
夜神安卓模拟器 | 62001
逍遥安卓模拟器 | 21503
雷电安卓模拟器 | 5555
天天安卓模拟器 | 5037
安卓模拟器大师 | 54001

## 1.2.1 获取模拟器adb连接地址

启动模拟器，终端运行
`adb devices`
获取该模拟器端口（适用于本机有多个模拟器或使用多开器时）

## 1.2.2 adb连接

连接设备
`adb connect [ip：prot]`
断开连接的设备
`adb disconnect`
查看连接列表
`adb devices -l`

## 1.2.3 adb常用操作

将文件从本地capy到Android内
`adb push [src_path] [dst_path]`
将文件从Android内capy到本地
`"adb -s [指定连接] pull [src_path] [dst_path]`
Android内使用shell命令
`adb shell`
指定adb连接并获取root权限
`adb -s [ip：prot] root`

## 1.3 获取目标App包名

获取全部app包名列表
`adb shell pm list packages`
获取第三方app包名列表
`adb shell pm list packages -3`

## 1.4 获取目标App类名

获取当前运行的App类名
`adb shell dumpsys activity activities`

## 1.5 模拟器开启root权限及开发者模式

### 1.5.1 root设置

一般在模拟器设置选项中

### 1.5.2 开发者模式

一般点击系统版本号5次进入开发者模式

# 2 捕包类"CapturePacket"

## 2.1 类构造

`app_package_name` ：App包名
`app_class_name` ：App类名
`simulator_ip_port` ：模拟器连接端口及地址
`pcap_file_ID：pacp` ：文件编号
`pcap_src_file_path` : pcap文件导出路径

        def __init__(self, app_package_name, app_class_name, simulator_ip_port, capture_packet_mode):
            self._app_package_name = app_package_name
            self._app_class_name = app_class_name
            self._simulator_ip_port = simulator_ip_port
            self._capture_packet_mode = capture_packet_mode
            # 杀死本地adb进程。防止在循环多次执行过程中adb进程阻塞
            os.system('taskkill /f /im %s' % 'adb.exe')
            # 建立连接
            time.sleep(1)
            command_str = "adb connect " + self._simulator_ip_port
            os.system(command_str)
            time.sleep(1)
            # 获取root权限
            command_str = "adb -s " + self._simulator_ip_port + " root"
            os.system(command_str)
            time.sleep(1)
            # 自动获取安卓系统wlan0 IP地址
            command_str = "adb -s " + self._simulator_ip_port + " shell ip addr show wlan0"
            ip_str_src = re.sub(r"\s+", " ", os.popen(command_str).read().splitlines()[2])
            # print(ip_str_src)
            ip_str = ip_str_src.split(' ')[2].split('/')[0]
            self._ip = str(ip_str)
            print("System Wlan0 IP : ", self._ip)
            # 自动获取APP的userID
            command_str = "adb -s " + self._simulator_ip_port + " shell \"cat /data/system/packages.xml | grep " + self._app_package_name
            userID = os.popen(command_str).read()
            for i in userID.split(' ') :
                if "userId" in i:
                    userID = i.split('"')[1]
            self._userID = str(userID)
            print("APP User ID : ", self._userID)
            time.sleep(1)
            # 清空规则
            command_str = "adb -s " + self._simulator_ip_port + " shell iptables -F"
            os.popen(command_str)
            time.sleep(2)
            # 添加规则
            # 把OUTPUT数据包里面，用户ID是userID的流打上userID的流标签
            command_str = "adb -s " + self._simulator_ip_port + " shell iptables -A OUTPUT -m owner --uid-owner " + self._userID + " -j CONNMARK --set-mark "+ self._userID
            os.popen(command_str)
            time.sleep(2)
            # 把入站流中带有userID标签的数据包放到nflog消息池中，消息池的标号为userID
            command_str = "adb -s " + self._simulator_ip_port + " shell iptables -A INPUT -m connmark --mark " + self._userID + " -j NFLOG --nflog-group " + self._userID
            os.popen(command_str)
            time.sleep(2)
            # 把出站流中带有userID标签的数据包放到nflog消息池中，消息池的标号为userID
            command_str = "adb -s " + self._simulator_ip_port + " shell iptables -A OUTPUT -m connmark --mark "+ self._userID + " -j NFLOG --nflog-group " + self._userID
            os.popen(command_str)
            # 系统反应慢休息休息
            time.sleep(10)

1.建立adb连接

    command_str = "adb connect " + self._simulator_ip_port
    os.system(command_str)

2.根据App包名自动获取userID获取

    command_str = "adb -s " + self._simulator_ip_port + " shell \"cat /data/system/packages.xml | grep " + self._app_package_name
    userID = os.popen(command_str).read()
    for i in userID.split(' ') :
        if "userId" in i:
            userID = i.split('"')[1]
    self._userID = str(userID)

3.进行iptables配置

    # 清空规则
    command_str = "adb -s " + self._simulator_ip_port + " shell iptables -F"
    os.popen(command_str)
    # 添加规则
    # 把OUTPUT数据包里面，用户ID是userID的流打上userID的流标签
    command_str = "adb -s " + self._simulator_ip_port + " shell iptables -A OUTPUT -m owner --uid-owner " + self._userID + " -j CONNMARK --set-mark "+ self._userID
    os.popen(command_str)
    # 把入站流中带有userID标签的数据包放到nflog消息池中，消息池的标号为userID
    command_str = "adb -s " + self._simulator_ip_port + " shell iptables -A INPUT -m connmark --mark " + self._userID + " -j NFLOG --nflog-group " + self._userID
    os.popen(command_str)
    # 把出站流中带有userID标签的数据包放到nflog消息池中，消息池的标号为userID
    command_str = "adb -s " + self._simulator_ip_port + " shell iptables -A OUTPUT -m connmark --mark "+ self._userID + " -j NFLOG --nflog-group " + self._userID
    os.popen(command_str)

## 2.2 析构

1.恢复iptables配置

    # 删除规则
    command_str = "adb -s " + self._simulator_ip_port + " shell iptables -F"
    os.popen(command_str)

2.断开adb连接

    # 关闭adb连接
    os.system('adb disconnect')
    # 杀死本地adb进程。防止在循环多次执行过程中adb进程阻塞
    os.system('taskkill /f /im %s' % 'adb.exe')

## 2.3 类成员函数

        def StartCapturePacket(self, pcap_file_ID, pcap_src_file_path, network_cord_name):
            # 安进程抓包
            if self._capture_packet_mode & 0b0001:
                print("模拟器安进程抓包")
                command_str = "adb -s " + self._simulator_ip_port + " shell tcpdump -i nflog:" + self._userID +" -w  /sdcard/Pictures/simulator_uid_" + self._userID + "_" + str(pcap_file_ID) +".pcap &"
                os.popen(command_str)

            # 全系统抓包
            if self._capture_packet_mode & 0b0010:
                print("模拟器全系统抓包")
                command_str = "adb -s " + self._simulator_ip_port + " shell tcpdump -w  /sdcard/Pictures/simulator_all_" + str(pcap_file_ID) +".pcap &"
                os.popen(command_str)

            if self._capture_packet_mode & 0b0100:
                print("Host机按模拟器IP抓包")
                command = tshark_file_path + ' -i \"' + network_cord_name + '\"  -w ' + pcap_src_file_path + 'host_' + self._ip + '_' + str(pcap_file_ID)  + '.pcap -T text host ' + self._ip + ' > NUL'
                print(command)
                subprocess.Popen(command, shell=True)

            if self._capture_packet_mode & 0b1000:
                print("Host机全系统抓包")
                command = tshark_file_path + ' -i \"' + network_cord_name + '\"  -w ' + pcap_src_file_path + 'host_all_' + str(pcap_file_ID)  + '.pcap' + ' -T text > NUL'
                print(command)
                subprocess.Popen(command, shell=True)
            return

        def StopCapturePacket(self, pcap_file_ID, pcap_src_file_path):
            if self._capture_packet_mode & 0b0001:
                print("停止模拟器安进程抓包")
                command_str = "adb -s " + self._simulator_ip_port + " shell killall tcpdump"
                os.popen(command_str)
                # 查看保存的pcap包
                command_str = "adb -s " + self._simulator_ip_port + " shell ls -l /sdcard/Pictures/simulator_uid_" + self._userID + "_" + str(pcap_file_ID) +".pcap"
                return_str = os.popen(command_str).read()
                print(return_str)
                # pull pcap包 到本地
                command_str = "adb -s " + self._simulator_ip_port + " pull /sdcard/Pictures/simulator_uid_" + self._userID + "_" + str(pcap_file_ID) + ".pcap " + pcap_src_file_path
                return_str = os.popen(command_str).read()
                # 等待pcap包拷贝
                time.sleep(10)
                print(return_str)
                # 删除Android内保存的pcap包
                command_str = "adb -s " + self._simulator_ip_port + " shell rm /sdcard/Pictures/simulator_uid_"  + self._userID + "_" + str(pcap_file_ID) +".pcap"
                os.popen(command_str)

            if self._capture_packet_mode & 0b0010:
                print("停止模拟器全系统抓包")
                command_str = "adb -s " + self._simulator_ip_port + " shell killall tcpdump"
                os.popen(command_str)
                # 查看保存的pcap包
                command_str = "adb -s " + self._simulator_ip_port + " shell ls -l /sdcard/Pictures/simulator_all_" + str(pcap_file_ID) +".pcap &"
                return_str = os.popen(command_str).read()
                print(return_str)
                # pull pcap包 到本地
                command_str = "adb -s " + self._simulator_ip_port + " pull /sdcard/Pictures/simulator_all_" + str(pcap_file_ID) +".pcap " + pcap_src_file_path
                return_str = os.popen(command_str).read()
                # 等待pcap包拷贝
                time.sleep(10)
                print(return_str)
                # 删除Android内保存的pcap包
                command_str = "adb -s " + self._simulator_ip_port + " shell rm /sdcard/Pictures/simulator_all_" + str(pcap_file_ID) +".pcap"
                os.popen(command_str)

            if self._capture_packet_mode & 0b0100:
                print("停止Host机按模拟器IP抓包")
                process_name = 'tshark.exe'
                pid = os.popen('tasklist /fi "imagename eq %s"' % process_name).readlines()[3].split()[1]
                os.system('taskkill /F /PID %s' % pid)

            if self._capture_packet_mode & 0b1000:
                print("停止Host系统系统抓包")
                process_name = 'tshark.exe'
                pid = os.popen('tasklist /fi "imagename eq %s"' % process_name).readlines()[3].split()[1]
                os.system('taskkill /F /PID %s' % pid)
            return

        def StartAPP(self):
            command_str = "adb -s " + self._simulator_ip_port + " shell am start -n " + self._app_package_name + self._app_class_name
            ret = os.popen(command_str).read()
            if not 'Starting' in ret:
                return -1
            return 1

        def StopAPP(self):
            command_str = "adb -s " + self._simulator_ip_port + " shell am force-stop " + self._app_package_name
            print(os.popen(command_str).read())
            return

        def WgetFile(self, file_url):
            command_str = "adb -s " + self._simulator_ip_port + " shell wget " + file_url + " -O /sdcard/Pictures/wgetfile"
            print(os.popen(command_str).read())
            return

        def CurlFile(self, file_url):
            command_str = "adb -s " + self._simulator_ip_port + " shell curl -k " + file_url
            os.popen(command_str).read()
            return

        def GetPublicIP(self):
            command_str = "adb -s " + self._simulator_ip_port + " shell curl ifconfig.me/ip "
            string = os.popen(command_str).read()
            public_ip = string[string.rfind('\n') + 1:]
            return public_ip

        def GetLocation(self, ip):
            try:
                response = requests.get(f'https://ipinfo.io/{ip}/json')
                location_data = response.json()
                return location_data
            except Exception as e:
                print(f"Error: {e}")
                return None

        def SendDataByUdp(self, ip, port, file):
            # 拷贝文件到安卓模拟器
            for i in range(100):
                command_str = "adb -s " + self._simulator_ip_port + " shell \"echo 'Hello Word !!!' | busybox nc " + ip + " " + port + "\""
                string = os.popen(command_str).read()
            return string