资讯动态

Python实现手机号查QQ号:TEA加密与协议拆解

发布时间:2026/9/20 6:41:11 来源:尧图企业网站定制
手机号与QQ号的绑定关系查询是很多做账号运营、社群管理、数据核验的朋友都会碰到的一个实际需求。比如手里拿到一批注册手机号想确认哪些号码绑过QQ、绑的是哪个号又或者做老客户召回时需要把手机号和QQ号对应起来做触达。市面上号称能查的工具一大把但真正能跑通、不收费、还能自己掌控数据的基本都得靠自己动手。这篇就围绕一个用Python实现的手机号查询QQ号工具把背后的协议逻辑、加密算法、代码实现和踩坑经验完整拆一遍。需要先把话说在前面这类查询本质上依赖的是公开的账号绑定校验接口只能用于查询你自己有权处理的号码比如你自己名下的、或者已经获得对方明确授权的数据。未经授权批量查询他人隐私信息既不合规也容易出事这一点在动手之前必须想清楚。下面讲的所有内容都建立在合法合规使用的前提下。1. 先搞清楚这个工具到底在查什么很多人一上来就问有没有现成的软件其实在写代码之前更该弄明白的是手机号查QQ号这件事技术上到底是怎么实现的。搞懂了原理你才知道哪些工具是靠谱的哪些是骗人的。1.1 绑定关系的本质是一个校验接口QQ号在注册和使用的过程中可以绑定手机号作为安全验证方式。这个绑定关系存在服务端的数据库里普通用户是拿不到原始数据的。但是在登录、找回密码、账号验证等流程中系统需要判断这个手机号是否绑定了某个QQ号于是就有了对应的校验接口。这个接口的典型逻辑是你提交一个手机号服务端返回这个号码当前是否关联了QQ账号以及在特定条件下返回关联账号的部分信息。它不是数据库直连查询而是通过官方校验流程反推绑定关系。理解这一点非常关键因为它决定了这个工具的边界——它只能查到接口愿意告诉你的信息查不到的就是查不到任何号称能拖库的全能工具都是忽悠。1.2 为什么这类工具大多活不长做过这类工具的朋友应该都有体会今天还能用的接口明天可能就改了。原因很简单服务端会不断调整风控策略增加验证码、限制请求频率、变更参数签名方式。所以一个终极免费工具如果宣称永久有效那基本可以判定是假的。真正靠谱的做法是把核心的协议逻辑和加密算法掌握在自己手里。接口变了改几行参数就能跟上风控严了调整请求节奏就行。这也是为什么我建议用Python自己写而不是去下载来路不明的exe。自己写的代码逻辑透明出了问题能定位数据也不会经过第三方服务器。1.3 这个工具适合谁用从实际场景来看主要适合三类人一是做私域运营、需要核验客户联系方式的从业者二是做数据清洗、要把手机号和社交账号对齐的技术人员三是对网络协议、加密算法感兴趣想通过一个真实案例练手的Python学习者。如果你属于第三类那这个项目其实是个非常好的练手素材——它涉及HTTP请求、参数构造、TEA加密、字节流处理麻雀虽小五脏俱全。下面我会把每个环节都拆开讲。2. 环境准备别在第一步就卡住我见过太多人卡在环境配置上代码还没跑就先放弃了。这一节把Python环境、依赖库、编辑器配置一次性讲清楚照着做就行。2.1 Python版本与安装推荐使用Python 3.8到3.11之间的版本。太老的版本3.6以下有些库不支持太新的版本3.12偶尔会有第三方库兼容问题。安装的时候有个关键点一定要勾选Add Python to PATH否则后面在命令行里敲python会提示找不到命令。Windows用户去官网下载安装包双击一路下一步即可。Mac用户如果装了Homebrew直接brew install python3.11更省事。Linux用户注意很多发行版自带的是python2需要显式安装python3命令类似sudo apt install python3 python3-pip。安装完成后验证一下python --version pip --version如果两条命令都能正常输出版本号环境就没问题了。如果提示python was not found八成是PATH没配好重新装一遍并勾选PATH选项或者手动把Python安装目录加到系统环境变量里。2.2 需要安装的第三方库这个项目用到的库不多核心就几个pip install requests pip install pycryptodomerequests负责发HTTP请求是Python里最常用的网络库比自带的urllib好用太多。pycryptodome提供加密算法支持虽然TEA算法我们可以手写但用成熟库更稳妥。如果你还想做个可视化界面可以再加一个pip install fletflet是近几年比较火的跨平台UI库用Python就能写出桌面和移动端界面比tkinter美观比PyQt轻量。不过第一版建议先跑通命令行版本界面后面再加。2.3 编辑器与调试环境VSCode是目前最顺手的选择。装好之后再装一个Python扩展Microsoft官方那个然后在设置里把Python解释器指向你刚装的那个版本。如果你用PyCharm新建项目时注意选择正确的解释器别选到系统自带的旧版本上。调试的时候善用print和断点。网络请求这类代码最怕的就是参数拼错了却看不出来。我的习惯是在发请求之前先把完整的URL和参数字典打印出来肉眼核对一遍再发出去。提示如果你在公司网络环境下某些请求可能会被网关拦截。遇到连接超时先别怀疑代码换个网络环境试试能排除一大半问题。3. 核心协议拆解请求是怎么构造的这一节是整篇的重点。理解了协议你才能自己维护这个工具而不是每次接口一变就抓瞎。3.1 请求的基本结构整个查询流程可以拆成三步第一步构造一个包含手机号的请求参数第二步对参数做加密和编码第三步把加密后的数据发到服务端解析返回结果。请求通常是一个POST请求Content-Type是application/x-www-form-urlencoded或者application/octet-stream具体取决于接口设计。参数里一般包含手机号、时间戳、以及一个经过加密的签名字段。服务端收到后先验签再查绑定关系最后返回结果。这里有个容易忽略的点时间戳。很多接口会用时间戳做防重放攻击如果你的请求时间戳和服务端时间差太多比如超过几分钟请求会被直接拒绝。所以代码里取时间戳一定要用当前时间别写死。3.2 参数编码的坑手机号本身是明文的但提交前往往要做一次编码转换。常见的有两种一种是直接作为字符串拼接另一种是转成字节流再处理。如果接口要求的是字节流你就得用struct.pack或者bytes相关的方法把数字转成二进制。我踩过的一个坑是手机号转字节的时候字节序搞反了。大端和小端在本地测试时可能看不出问题但一到服务端就返回错误。解决办法是先用一个已知能查到的号码做测试确认字节序正确后再批量处理。3.3 返回结果的解析服务端返回的数据通常是加密的需要先解密再解析。解密后的内容可能是JSON也可能是自定义的二进制格式。如果是JSON直接用json.loads就行如果是二进制就得按约定的字段长度逐个读取。返回结果里一般包含几个关键字段状态码表示查询是否成功、绑定标志表示该手机号是否绑定了QQ、以及QQ号本身在成功的情况下。注意有些接口出于隐私保护只返回是否绑定而不返回具体号码这种情况下工具就只能做到核验而不能做到反查。注意解析返回数据时一定要做异常处理。服务端返回格式可能因为版本更新而变化如果代码里写死了字段位置一旦格式变了就会直接崩溃。用try-except包起来出错时打印原始返回内容方便排查。4. TEA加密算法这个项目的技术核心标题里提到的TEA加密算法是这个项目最值得深挖的部分。搞懂它你不仅能用在这个工具上以后遇到其他需要加密的场景也能举一反三。4.1 TEA算法是什么TEA全称Tiny Encryption Algorithm中文叫微型加密算法1994年由剑桥大学的两位学者提出。它的特点是实现简单、速度快、安全性在当时足够用。整个算法核心代码不到二十行非常适合嵌入到各种协议里。它的基本结构是把数据分成64位一组用128位的密钥进行多轮迭代加密。每一轮做的是移位、异或、加法这些基本运算配合一个叫做delta的魔数0x9E3779B9来增加混淆。轮数一般是32轮轮数越多越安全但速度越慢。用生活化的类比来说TEA就像一台搅拌机你把明文数据丢进去加上密钥这个配方搅拌32次出来的就是密文。没有配方的人很难从搅拌结果反推出原始材料。4.2 TEA的加密流程标准的TEA加密流程是这样的输入8字节的明文和16字节的密钥输出8字节的密文。具体步骤把8字节明文拆成两个32位整数v0和v1。把16字节密钥拆成四个32位整数k0、k1、k2、k3。初始化sum为0delta为0x9E3779B9。循环32轮每轮更新sum并对v0、v1做一系列运算。最后把v0、v1拼回8字节输出。用Python实现的话核心逻辑大概是这样import struct def tea_encrypt(plaintext, key): delta 0x9E3779B9 sum_val 0 v0, v1 struct.unpack(2I, plaintext) k0, k1, k2, k3 struct.unpack(4I, key) for _ in range(32): sum_val (sum_val delta) 0xFFFFFFFF v0 (v0 (((v1 4) k0) ^ (v1 sum_val) ^ ((v1 5) k1))) 0xFFFFFFFF v1 (v1 (((v0 4) k2) ^ (v0 sum_val) ^ ((v0 5) k3))) 0xFFFFFFFF return struct.pack(2I, v0, v1)注意这里的 0xFFFFFFFF是为了保证结果始终是32位无符号整数。Python的整数是任意精度的如果不做这个掩码运算结果会越来越大最后完全不对。这是新手最容易踩的坑之一。4.3 密钥和填充的处理TEA的密钥是16字节但实际协议里给的密钥可能长度不一。如果密钥不足16字节需要做填充如果超过需要截断。填充方式常见的有补零和循环填充两种具体用哪种要看协议约定。数据长度方面TEA一次处理8字节如果明文不是8的倍数需要先填充到8的倍数。填充的字节值也有讲究有的协议用0x00填充有的用PKCS#7标准填充。填充错了解密出来的数据尾部就是乱码。我在实际调试时发现很多接口的密钥是固定的直接硬编码在客户端里。你可以通过分析请求和响应的对应关系反推出密钥。当然这个过程需要一些耐心和逆向经验。4.4 加密之外还要注意什么光有加密还不够。很多接口在加密数据之外还会加一层Base64编码或者十六进制编码方便在网络中传输。所以完整的处理链路往往是明文 - TEA加密 - Base64编码 - 发送。解密的时候反过来接收 - Base64解码 - TEA解密 - 明文。每一步都不能少顺序也不能错。我见过有人把Base64和TEA的顺序搞反了结果怎么都解不出来排查了半天才发现是顺序问题。提示调试加密相关代码时建议先用一组固定的输入和已知的输出做单元测试。确认加密函数本身没问题再去对接网络请求。这样能把加密错误和网络错误两类问题分开排查效率高很多。5. 完整代码实现与逐段讲解前面讲了原理这一节把完整代码串起来。我会按模块拆解每段都说明为什么这么写。5.1 请求模块的编写先写一个负责发请求的函数。核心是把参数构造好、加密好、发出去、拿回结果。import requests import time import struct import base64 def build_request(phone, key): timestamp int(time.time()) payload struct.pack(Q, int(phone)) struct.pack(I, timestamp) encrypted tea_encrypt(payload, key) encoded base64.b64encode(encrypted).decode() return { data: encoded, ts: timestamp }这里把手机号和时间戳打包成字节流再加密编码。手机号用8字节无符号整数Q存储时间戳用4字节I。注意表示大端序这个必须和服务端约定一致。5.2 发送与接收构造好参数后用requests发POST请求def query_qq(phone, key, url): params build_request(phone, key) headers { User-Agent: Mozilla/5.0, Content-Type: application/x-www-form-urlencoded } try: resp requests.post(url, dataparams, headersheaders, timeout10) resp.raise_for_status() return parse_response(resp.content, key) except requests.RequestException as e: print(f请求失败: {e}) return None超时时间设10秒比较合理太短容易误判太长会拖慢批量处理。raise_for_status会在HTTP状态码非200时抛异常方便统一处理。5.3 响应解析拿到响应后先Base64解码再TEA解密最后按字段解析def parse_response(content, key): try: decoded base64.b64decode(content) decrypted tea_decrypt(decoded, key) status struct.unpack(I, decrypted[:4])[0] if status 0: qq struct.unpack(Q, decrypted[4:12])[0] return qq else: return None except Exception as e: print(f解析失败: {e}) return None解密函数是加密函数的逆过程逻辑对称只是运算顺序反过来。这里同样要注意掩码和字节序。5.4 批量处理与限速单个查询跑通后如果要批量处理必须加限速。原因很简单请求太密集会触发风控轻则返回错误重则IP被临时限制。import random def batch_query(phones, key, url): results {} for phone in phones: qq query_qq(phone, key, url) results[phone] qq time.sleep(random.uniform(1.5, 3.5)) return results每次请求之间随机休眠1.5到3.5秒模拟人工操作的节奏。这个间隔不是拍脑袋定的是实测下来既能保证效率又不容易触发风控的区间。如果号码量特别大建议分批处理每批之间再休息几分钟。注意批量查询一定要控制规模并且只处理你有权限处理的号码。大规模、高频次的查询行为无论出于什么目的都容易触碰合规红线。6. 实测中遇到的那些坑代码能跑通只是第一步真正上线用起来坑还多着呢。这一节把我踩过的坑和解决办法都列出来能帮你省不少时间。6.1 加密结果对不上最常见的问题本地加密出来的结果和服务端期望的不一致。排查思路是逐层对比——先确认明文打包的字节序对不对再确认密钥长度和内容对不对最后确认轮数和delta值对不对。我遇到过一次问题出在密钥上。协议文档里给的密钥是字符串形式我直接拿字符串去加密了实际上需要先转成字节再按16字节处理。字符串和字节在Python里是两回事这个坑很隐蔽。6.2 返回乱码或解析失败如果解密出来的数据是乱码八成是填充或者字节序的问题。可以先把解密结果用十六进制打印出来看看前几个字节是否符合预期。如果前几个字节是对的后面乱那就是长度或填充问题如果从头就乱那就是密钥或算法问题。还有一种情况是服务端返回了错误页面的HTML而不是预期的二进制数据。这时候Base64解码会直接失败。解决办法是在解析前先判断Content-Type如果不是预期的类型直接打印原始内容排查。6.3 请求被拒绝请求被拒绝的表现有很多返回403、返回空、返回验证码页面、或者直接超时。原因可能是请求头不对、参数缺失、频率过高、或者IP被标记。排查顺序建议是先检查请求头是否完整特别是User-Agent和Referer再检查参数是否齐全然后降低频率重试最后考虑换网络环境。我一般会准备一个最小可用请求就是只保留最核心的参数确认能通之后再逐步加回其他参数这样能快速定位是哪个参数导致的拒绝。6.4 号码格式问题手机号在传入之前一定要做格式校验。有的号码带国际区号有的带空格或横线有的位数不对。如果不做清洗直接传轻则查不到重则报错。import re def clean_phone(phone): phone re.sub(r\D, , str(phone)) if len(phone) 11 and phone.startswith(1): return phone return None这个函数把非数字字符全部去掉然后校验是否为11位且以1开头。不符合的直接返回None跳过处理。别小看这一步实际数据里脏数据的比例往往比你想象的高。7. 关于合规与安全的几点实在话技术本身是中性的但怎么用决定了它的性质。这一节不讲大道理就说几个实际操作中必须守住的底线。第一只查你有权查的号码。你自己名下的、客户明确授权你核验的这些没问题。来路不明的号码批量查询不管工具多好用都别碰。第二数据不要落地存储。查完即用用完即弃。把查询结果存成数据库一旦泄露责任全在你。如果业务上确实需要留存也要做脱敏和加密。第三控制查询频率。哪怕你有授权高频查询也会给对方服务器造成压力容易被判定为异常行为。慢一点稳一点比什么都强。第四工具自己留着用就好。这类代码一旦公开传播很容易被滥用。分享技术原理可以但完整的、可直接批量运行的成品还是谨慎为妙。8. 想继续深入可以往哪走如果你把这个项目跑通了其实还有不少可以扩展的方向。比如把命令行版本改成带界面的工具用flet做个简单的输入框加结果展示打包成exe或apk自己用起来更方便。flet的好处是同一套代码能同时出桌面端和移动端学习成本也低。再比如把TEA算法换成其他加密方式练手像AES、RC4这些对比一下不同算法的实现难度和性能差异。这对理解加密协议的整体设计思路很有帮助。还有一个方向是做请求的可视化监控把每次请求的参数、耗时、返回结果都记录下来做成图表。这样接口一旦有变化你能第一时间发现。用Python的matplotlib或者plotly都能做数据量不大的话直接存CSV就行。我个人在实际操作中的体会是这类工具的价值不在于能查到什么而在于你理解了背后的协议是怎么运转的。接口会变风控会升级但底层的加密原理、请求构造逻辑、异常处理思路是通用的。把这套东西吃透以后遇到任何类似的协议分析任务你都能快速上手。最后再提醒一句工具是死的人是活的怎么用、用到什么程度心里得有杆秤。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价