前言

看成了QQ号查手机号点了进来的请自觉关掉,避免“然并卵”!春节逛BBS无意看到一款小软件【手机号2QQ号】,起初是想能不能实现批量,于是写了个python3版的测试(Linux党,没办法),理想总是美好的。。。

设置手机号查找
  • PC端

这里写图片描述

  • 移动端

这里写图片描述

这里写图片描述

手机号登录

PC端与移动端的设置没有必然关系,比如通讯录启用在移动端可使用手机号查找,在PC端不能,手机号登录启用其他全部关闭的情况下是不能通过手机号查找到QQ的,这里实现的是在开启手机号登录(手机端开启/辅助帐号绑定)功能的情况下提取QQ号。

实现

PCQQ登录过程
  1. 发送握手包
  2. 返回握手状态码
  3. 发送密码包
  4. 返回登录状态,由于登录方式不是QQ号,QQ会很返回真实QQ号更新数据包
  5. ……

用wireshark抓PCQQ登录数据包前4条报文(0825与0826指令)

这里写图片描述

看这4次(2发2收)数据交互的抓包,长度分别是213、161、632、249,减去包头,那么数据bytes长度分别是:271、119、590、207

TEA算法

QQTEA 算法建立在标准 TEA算法的基础上,使用16轮的加密,由于需要加密不定长的数据,所以使用了一些常规的填充办法和交织算法。【详细戳这里】

0825指令

发送的数据包(假设为data)

02  # 包头,通讯都是以02开口

35 55 # QQ版本,6.7

08 25 # 指令

00 00 # 随机,2位十六进制

00 00 00 00 # QQ号HEX,因用手机号登录,这里直接填00

03 00 00 00 01 01 01 00 00 67 42 00 00 00 00 # 固定

77 92 39 4f 1a fd 3b bf a9 00 6b c8 07 bc f2 3b  # key,直接用抓包的就行

TEA加密段(假设以下为txt)

00 18 00 16 00 01

00 00 04 4b 00 00 00 01 00 00 15 09  # 固定

00 00 00 00 00 00 00 00

00 04 00 0f 00 00 00 0b

30 30 30 30 30 30 30 30 30 30 30  # 手机号分解,每位前面加上3

03 09

00 08

00 01 00 00 00 00 00 04

00 36 00 12

00 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00

01 14 00 1d 01 02 00 19

02 51 ca 4a ab 66 e8 0a e4 d2 79 92 1a ce 3c 3d fe e2 37 88 15 1f 45 36 8d  # HDKey

将以上数据包加密后与前面数据包拼接在尾部补上03形成一段完整的交互数据包

data += b2a_hex(tea.encrypt(bytes.fromhex(txt), bytes.fromhex(key0825))).decode()
data += '03'
data  = a2b_hex(data)

发包,通讯协议是UDP,直接socket然后接收数据

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(data, ('183.60.56.100', 8000))
recvPack = sock.recv(1024)
sock.close()

在0826登录中需要令牌、服务器IP、时间这三个参数将从返回的数据包中获取

解包,去掉14位头部为数据包加密段

recvData = b2a_hex(tea.decrypt(recvPack[14:-1], bytes.fromhex(key0825))).decode()

TEA解码后的数据有多种情况,比如不以’00’开头的会多偏移8位十六进制(暂时没发现其他偏移),具体获取如下

if(recvData[:2]!='00'):
    recvData = recvData[16:]

if(recvData[:2]=='00'):
    token0825  = recvData[10:122]   # "00 38 "" 00 17 00 0E 00 01" 之间的是token
    serverTime = recvData[134:142]
    serverIP   = recvData[166:174]
else:
    print('0825 error!')

获取成功后就可以封装0826的登录验证数据包了

0826指令

0826登录验证数据包封装过程跟0825差不多,就不贴数据包了,大致说下过程

data  = '02'
......
txt   = '01 12 00 38'
......

密码密文,密码随意,并不真正要登录

pwd = md5('123456')
pwd  += '00 00 00 00'
pwd  += '00 00 00 00'  # QQ Hex,用0填从

封装密码后是密钥加密,将密码密文作为key进行TEA加密

txt  += b2a_hex(tea.encrypt(bytes.fromhex(keyTxt), bytes.fromhex(pwd))).decode()

接下来是一段CRC值封装

txt  = '00 15 00 30 00 00'
......
txt += b2a_hex(tea.encrypt(bytes.fromhex(mcrc), bytes.fromhex(key0826))).decode()
......
txt += '62 e1 72 e6 14 21 fe 8c 85 0c 62 89 1e fc f7 f9 3a 19 b8 92'

最后封装成数据包

data += b2a_hex(tea.encrypt(bytes.fromhex(txt), bytes.fromhex(keyCode))).decode()
data += '03'
data  = a2b_hex(data)

具体实现看源码,发包,然后接收解码,和0825过程一致,剩下到解码后获取QQ号了,QQ号用4位十六进制保存,通常解码后以06开头是偏移3位十六进制,fc开头偏移7位十六进制,如果尝试批量的时候,返回的数据包就比较诡异了,这需要进一步分析

if recvData[:2]=='06':
    qq = str(int(recvData[6:14], 16))
else:
    recvData = recvData[8:]
    if recvData[:2].lower()=='fc':
        qq = str(int(recvData[14:22], 16))
    else:
        qq = False

if qq: print(qq)

效果

单个IP对单个服务器可以小许批量(可能访问频繁,被防火墙干掉了,几十到几百个查找后返回了另一种状态码,PC端还是可以正常登录)

这里写图片描述

效果并不理想,如果有兴趣,可以继续研究,比如来个异步/多线程+多代理对多服务器遍历。。。

以上仅供学习交流,造成一切后果与本人无关!

参考

【源码戳这里(Github)】

ps:手机号可以查到某些私人QQ,最后祝大家:新年快乐!

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐