1.写在前面
让我们想象这样一个场景
一天,你在用着电脑。你想登录一个网站,但是网站必须要手机验证码登录。好吧,你可能懒得拿手机,又或者因为一些情况,你现在拿不到手机。
没有手机怎么拿验证码?好吧,为什么我们不用FRP加ADB来读取手机短信呢?
2.整体思路
ChatGPT
ADB(Android Debug Bridge,安卓调试桥)是一个多功能的命令行工具,它允许用户与安卓设备进行通信和操作。ADB 提供了对安卓设备的各种操作,包括应用安装、系统调试和设备管理等。以下是关于 ADB 的详细解释:
ADB 的主要功能
应用管理:
安装和卸载应用:通过 ADB,用户可以安装(adb install
)和卸载(adb uninstall
)应用,而无需通过设备的图形界面。
设备管理:
设备连接:ADB 可以连接到实际的安卓设备或安卓模拟器。它支持通过 USB 线或无线网络连接设备。
查看设备状态:使用adb devices
命令可以查看当前连接的设备列表及其状态。
文件传输:
推送文件:adb push <local> <remote>
可以将文件从本地电脑传输到安卓设备。
拉取文件:adb pull <remote> <local>
可以将文件从安卓设备传输到本地电脑。
调试和日志:
日志输出:adb logcat
命令可以查看安卓设备的系统日志,帮助开发者调试应用。
调试会话:通过 ADB,可以启动一个与设备的交互式 shell 会话(adb shell
),允许用户执行设备上的命令。
系统操作:
重启设备:adb reboot
命令可以重启安卓设备。
进入引导加载程序模式:adb reboot bootloader
可以使设备进入引导加载程序模式,用于刷写设备固件。
ADB 的使用场景
开发和调试:开发者使用 ADB 来安装测试版应用、查看调试日志和执行调试命令。
设备管理:用户可以使用 ADB 管理设备上的应用和文件,进行批量操作。
刷机和系统维护:高级用户和开发者使用 ADB 进入引导加载程序或恢复模式,进行系统更新和维护。
FRP(Fast Reverse Proxy)是一款用于内网穿透的工具,主要用于将内网服务暴露到外网,使得外网可以访问内网中的服务。它在需要访问内网服务、进行远程调试、部署Web应用等场景中非常有用。
FRP 的基本原理
FRP 的工作原理基于客户端和服务器端的协同工作,通过在内网和外网之间建立连接,代理内网服务,使外网能够访问这些服务。
FRP 的主要组件
FRP 服务器(frps):
部署在外网的服务器,负责接受来自客户端的连接请求,并将请求转发到相应的内网服务。
FRP 客户端(frpc):
部署在内网的机器上,与外网的 FRP 服务器建立连接,将内网的服务映射到外网端口上。
使用场景
内网 Web 服务公开: 将内网的 Web 服务(如本地开发的 Web 应用)暴露到外网,方便外部用户访问和测试。
远程桌面访问: 通过 FRP 实现对内网机器的远程桌面连接,方便远程管理和维护。
数据库访问: 将内网数据库服务映射到外网,方便外部应用访问和操作数据库。
ADB可是个好东西,因为ADB允许远程连接,所以我们要利用FRP把手机的ADB端口映射到公网服务器上。
3.有WIFI配置
首先在服务器下载frps包
下载后在服务器解压,进入目录后会看到frpc、frps等文件。服务端需要的是frps。
编辑frps.toml,我这里有个配置示例
bindAddr = "0.0.0.0" bindPort = 7000 #FRPS服务端口 auth.method = "token" auth.token = "连接token" #这里你可以随便输入几个字母,相当于密码。等一下在客户端也输入相同的就行了 webServer.addr = "0.0.0.0" webServer.port = 7500 #web服务的端口,访问这个端口可以看到目前映射了哪些端口 webServer.user = "用户名" #访问web服务时的用户名 webServer.password = "密码" #访问web服务的密码,这两个是设置访问web服务的用户名和密码的
写好配置文件后,就可以输入命令启动了。
chmod 777 * ./frps
这样,服务端的配置就完成了。
然后,在你的手机安装这个软件。
进入手机设置,找到关于手机,连续点击版本号,打开开发者设置。
然后在更多设置这里,进入开发者设置。
把这些设置打开
打开刚刚安装的软件
点击右上角的笔,编辑配置。
[common] server_addr = 服务器IP server_port = 7000 token = 服务器token [my_tcp] type = tcp local_ip = 127.0.0.1 #改成无线调试的IP local_port = 本地端口 #开发者设置里无线调试的端口 remote_port = 远程端口 #映射到服务器的端口
写好后,点击右下角的启动按钮。
在你的电脑准备adb工具,cmd输入adb connect 服务器IP:远程端口就行了
记得在服务器防火墙开放7000和远程端口
4.无WIFI配置
因为设置的无线调试只能在连接 WIFI的情况下开启,没有WIFI只有流量连接的情况下可以用termux启动无线调试。
安装后打开,输入su获取root权限,执行下面的命令。
setprop service.adb.tcp.port <端口> #自行设置监听端口 stop adbd start adbd
然后,使用下面的FRPC配置。
[common] server_addr = 服务器IP server_port = 7000 token = 服务器token [my_tcp] type = tcp local_ip = 127.0.0.1 #这里不需要改 local_port = 本地端口 #上面设置的端口 remote_port = 远程端口
记得在服务器防火墙开放7000和远程端口
5.获取短信
有adb连接的情况下可以执行这个命令获取短信
adb shell content query --uri content://sms/
但是,会输出一大堆不必要的东西,短信也很难找。
所以我让ChatGPT用Python写了一个小程序,让连接和获取短信方便些。
这是安卓的SDK工具,程序要在有adb的目录下运行,所以我干脆一起整合了。
Python源码:
import os import subprocess import time from datetime import datetime def connect_to_server(ip, port): try: command = f"adb.exe connect {ip}:{port}" result = subprocess.run(command, shell=True, capture_output=True, text=True, encoding='utf-8') if "connected" in result.stdout: return True else: print(result.stdout) return False except Exception as e: print(f"连接失败: {e}") return False def query_sms(): try: command = "adb.exe shell content query --uri content://sms/" result = subprocess.run(command, shell=True, capture_output=True, text=True, encoding='utf-8') if result.returncode == 0: return result.stdout else: print(result.stdout) return None except Exception as e: print(f"获取短信失败: {e}") return None def parse_sms(sms_data): sms_list = sms_data.strip().split("Row: ") parsed_sms = [] for sms in sms_list[1:]: sms_dict = {} lines = sms.split(", ") for line in lines: if '=' in line: key, value = line.split("=", 1) sms_dict[key.strip()] = value.strip() address = sms_dict.get("address", "N/A") date_sent = sms_dict.get("date_sent", "N/A") date = sms_dict.get("date", "N/A") body = sms_dict.get("body", "N/A") sim_id = sms_dict.get("sim_id", "N/A") date_sent_fmt = datetime.fromtimestamp(int(date_sent) / 1000).strftime('%Y-%m-%d %H:%M:%S') if date_sent.isdigit() else "N/A" date_fmt = datetime.fromtimestamp(int(date) / 1000).strftime('%Y-%m-%d %H:%M:%S') if date.isdigit() else "N/A" parsed_sms.append({ "发送方号码": address, "发送时间": date_sent_fmt, "接收时间": date_fmt, "短信内容": body, "SIM卡ID": sim_id }) parsed_sms.sort(key=lambda x: x["接收时间"]) return parsed_sms def display_sms(parsed_sms): for sms in parsed_sms: print(f"发送方号码: {sms['发送方号码']}") print(f"发送时间: {sms['发送时间']}") print(f"接收时间: {sms['接收时间']}") print(f"短信内容: {sms['短信内容']}") print(f"SIM卡ID: {sms['SIM卡ID']}") print("-" * 40) def main(): try: while True: ip = input("请输入服务器IP: ") port = input("请输入服务器端口: ") if connect_to_server(ip, port): print("连接成功!按回车键获取短信...") input() while True: sms_data = query_sms() if sms_data: parsed_sms = parse_sms(sms_data) display_sms(parsed_sms) else: print("未获取到短信。") choice = input("是否重新获取短信?(y/n): ").strip().lower() if choice == 'n': break elif choice == 'q': break if choice == 'q': break else: choice = input("连接失败,是否重新连接?(y/n): ").strip().lower() if choice == 'n': break except KeyboardInterrupt: print("\n检测到 Ctrl+C,退出程序中...") subprocess.run("adb.exe disconnect", shell=True) print("已断开连接。") if __name__ == "__main__": main()