0

    微信小程序源码分析技巧

    2023.07.07 | admin | 125次围观

    注:本文涉及内容均已脱敏,无真实漏洞披露,分析对象均为正常功能点,所涉数据均遵从国家法律法规。

    No.1 前言

    时间过得好快,由于忙着谈恋爱笔者已经有快一年没有写过完整的技术文章了。再回看笔者去年写的《微信小程序测试五脉》一文,文章中还是有许多可以改进和不准确的地方,也有因为当时自身思维局限而没有突破的地方。《微信小程序测试五脉》中的许多技术手段已经过时,编写的脚本也因微信版本升级需要修改之后才能使用,但其中抽象的思路仍是十分有价值的。笔者希望自己的每一遍文章都能给读者带来独到的测试技巧及深入思维的测试逻辑,文章中的例子会过时、文章中的手段会被更新,但其中的”魂“是不会变的。

    笔者最近遇到了一个小程序,需要在电梯中扫描小程序生成的二维码才能去对应楼层的电梯。二维码是动态生成且数据被进行了加密,此外小程序还有防截屏功能不让你截屏分享给他人,若多次截屏将会禁用当前账户。但笔者的手机信号不太好老是刷新不出来二维码,于是想弄一个不需要依托网络及小程序的离线电梯二维码工具。笔者发现在分析这个小程序的过程中,几乎用到了所有针对小程序分析的技巧,这些技巧都很有价值且是《微信小程序测试五脉》中没有展开详将的内容,于是便有了今天这篇笔者自认为不错的技术文章想分享给大家。本文看似是在讲一个实实在在的例子,却有许多抽象的技巧蕴含其中。

    No.2调试前准备

    首先我们需要一台已经root的安卓手机或是已经越狱的IOS手机,在手机内运行目标小程序并在如下目录中找到以.wxapkg结尾的微信小程序包将其拉取至我们的电脑上(小程序包命名随机,可更具时间顺序推测出对应的包):

    安卓保存路径:

    /data/data/com.tencent.mm/MicroMsg/{用户ID}/appbrand/pkg/

    IOS保存路径:

    /var/mobile/Containers/Data/Application/{程序UUID}/Library/WechatPrivate/{用户ID}/WeApp/LocalCache/release/{小程序ID}/

    在提取到微信小程序包之后只需使用wxappUnpacker工具,项目地址:

    将其解包即可,如下图所示该工具会自动分析小程序包并还原对应的文件:

    还原结束之后我们便可以在当前目录下看到目标小程序的所有原始代码和资源文件:

    在拿到了还原之后的文件我们就可以把其作为一个正常的项目源码在微信开发者工具中使用,我们在微信开发者工具中选择 “导入项目”功能,选择对应的小程序存放目录。在AppID一栏可以使用自己的小程序AppID或者微信分配的测试号AppID均可。

    来到微信小程序开发界面之后,我们还有许多工作要做,由于微信的安全策略限制在默认情况下所有不在小程序白名单之中的域名都是无法被请求的,会被微信直接拦截。我们需要在“详情”、“本地设置”中勾选“不校验合法域名”一栏的选项。此外若对应的小程序使用了npm则需开启“开启npm模块”功能,“ES5转ES6”和“增强编译”两个功能可以按照需求进行关闭或打开操作,具体评判标准为只要小程序能正常运行即可。

    当一切基本设置都结束之后,我们来到调试器Console界面,发现程序抛出了严重错误,提示:Error: This application has not registered any plugins yet.通过报错内容我们可以猜测小程序在某个位置引入了一个微信小程序插件,但是因为我们没有注册对应的插件导致插件内容无法导入,导致程序无法继续运行。

    根据提示:at Bluekey.js? [sm]:1我们知道具体的问题代码位于Bluekey.js文件的第一行处,我们点击对应的超链接查看对应的报错代码。

    可以看到在代码内小程序使用了requirePlugin函数来引用对应的插件,此时我们有两种处理方式:1. 在app.json配置文件中添加对应插件的引用;2.若插件对本次分析不重要可以直接使用require(js文件地址)函数将所有的引用替换为引用一个本地js文件。

    在解决了外部插件引用问题之后,我们看到Console抛出了“渲染层错误”的异常的错误:Connot delete property 'WeixinJSBridge' of #。

    出现此类错误意味着非代码本身存在问题,而是微信开发者工具出现了兼容性错误,我们可以选择更新至最新版本的微信开发者工具或在本地设置中选择不同版本的调试基础库即可解决此类异常。

    修改完调试基础库版本之后等待小程序重新渲染,此时在Console内已无影响程序正常运行的报错,剩下的一些都是系统提示:

    随后便可以在开发者工具内随意调试小程序的全部内容,调试前准备到此结束。

    No.3内容逻辑分析

    来到微信小程序的主页,点击下方tab栏中的“开门”按钮,前往我们要分析的对应页面。

    当我们来到对应页面时,微信小程序立刻跳转到了登录页面:

    这时需要我们来到调试器窗口切换到“Wxml”选卡,查看当前页面渲染之后的原始页面源码。可以看到如下图当前页面嵌入了一个webview形式的h5的登录页面,所有的登录操作都在h5页面内完成。

    遇到这种情况常规的解决思路很简单,我们只需要输入自己的账户登录即可。按照这个思路,我们在登录页面输入账号密码进行登录操作登录,随后我们发现系统提示跳转到了人脸识别验证模块,但由于此时在微信开发者工具内是无法在h5页面内唤起摄像头的,我们便也无法完成人脸识别操作进行微信小程序的登录,常规的解决思路在这里并不可行。

    此时我们只能从小程序源码入手,找到小程序对应的登录判断方式来绕过全局登录校验进行下一步分析操作。来到app.json配置文件中,所有的tab栏配置均在tabBar的json列表内,可以看到对应的“开门”模块位于/pages/miniCode/minicode页面中。

    来到对应页面的js文件中,在第78行处我们发现存在跳转至登录页面的代码:

    可以看到小程序跳转到登录页面是因为在第76行处函数调用出现异常触发了catch功能自动执行了跳转的代码。我们向上追溯发现所调用的函数位于第44行处为s.getAppminiCode。

    来到getAppminiCode函数中微信小程序url传值,我们发现函数首先会将全局数据中的e.globalApi.getQrCode的url地址传入a中作为api请求地址,接着创建一个ajax请求去触发对应的api,然后通过if函数判断http的响应码是否为200,若为200则先判断手机时间是否存在误差并将获取到的返回包中的token和qr值保存在本地的Strage中。

    接着我们进入ajax函数继续进行分析,可以看到函数会将当前用户的openid赋值给uniqueId变量放置在o变量中,接着会将o变量内容与小程序的http请求头内容合并传入a变量中,最后在wx.requesthttp请求函数内将a作为当前http的请求头。至此我可以判断出当前小程序的所有api都是通过请求头内的openid参数值来进行身份校验的。

    在常规思路中,我们只需要在调试器的Storage模块中新建一个openid的key然后将自己的openid存入即让成功进入登录状态。

    但在笔者的测试过程中,此小程序在每次重新启动的时候会触发一个http的请求去重新获取用户的openid值导致每次Storage中的openid值被清空。

    当遇到这种情况时,我们可以去寻找对应触发openid参数修改的函数或是通过全局查找的方式将所有需要通过wx.getStorageSync函数获取openid值的代码直接替换为使用我们固定的openid内容:

    替换完成之后微信开发者工具会重新渲染小程序,稍等片刻便可看到微信小程序已经是登录状态,我们成功获取到开门二维码:

    我们在调试器的network模块中观察对应的API请求的返回包内容,看到有两个比较关键的参数:token和userId。

    随后我们点击谷歌开发者工具祖传的小鼠标按钮:

    将鼠标移动到对应的二维码上面,我么可以很清晰的看见当前二维码的class为qr-image:

    之后在调试器的审查元素模块中可以看到对应图片的地址为本地缓存目录:

    之后我们在开发者工具的编辑器窗口中打开对应页面的原始wxml,搜索classqr-image我们找到了原始的图片地址为{{imagePath}}变量的值:

    随后我们来到页面所属的js文件内,搜索imagePath变量被赋值的位置,成功搜索到位于canvasToTempFilePath函数中。

    继续追溯canvasToTempFilePath被调用的位置,我们来到了createQrcode函数中。

    接着继续进行追溯操作,最终我们来到第51行代码处为最初调用createQrcode函数的位置。往上研究,我们发现二维码的内容存储在46行的qrcodeUrl之中,而qrcodeUrl的内容正是通过之前API调用获取到的两个参数值userId和token经过e.default处理后产生的数据。

    之后我们将鼠标放置于e.default之上,开发者工具会为我们自动显示对应内容的引用地址,我们看到对应的地址为utils/pocsirCode。

    我们来到pocsirCode.js文件中,在第一行的e函数内便可以看到一个使用crypto-jsnpm库的标准aes加密函数,当前加密采用cbc模式不使用填充。e为待加密内容,r为加密密码,s为加密向量,最终的加密结果使用base64编码之后返回。

    可以推测出e函数是一个非常关键的函数,我们可以先开始调试e函数,直接使用console.log命令输出函数传入的所有变量值。重新运行小程序后我们看到控制台输出了三个被crypto-jshex处理之后的内容:

    接着我们改进我们输出的方式,将所有被hex处理过的函数使用.toString()的办法转换为字符串之后再次输出。重新回到控制台,我们发现待加密内容和加密密码已经成功以字符串的形式输出,加密向量则由于是object类型的变量无法被输出。我们观察待加密内容,发现开头部分好像是当前系统的时间,后面接的两段则是传入的userId变量和token变量的变量值。

    结束完e函数的分析之后回到default的分析,我们来到文件末尾在第42行处找到了对应执行的函数。函数首先会将userID的值赋值给a,随后将token的值拼接000000赋值给o,随后将所有的内容通过01 + 年年月月日日分分秒秒当前日期 + 00 + a + o + 00的格式赋值给u。随后调用先前的e加密函数传入u作为待加密内容、传入s作为加密密码、传入n作为加密向量进行加密并返回加密之后的结果。

    接着来到文件中间部分,我们发现了加密密码s变量和加密向量n变量的内容。n变量的值为:{sigBytes: 16, words: [1735354213, 1852405107, 825373492, 892745528]},s变量值的内容为r变量值的SHA256值,r变量的值为:{sigBytes: 8, words: [1735354213, 1852405107]},由于上述变量的值均为固定值,我们的加密分析到此结束,我们完成了所有必要的分析操作。

    No.4验证及利用

    知道了加密方式及加密流程之后我们便可以开始进行利用,这里推荐使用node.js编写POC脚本,很多微信小程序的函数可以直接复制过来使用特别的方便。首先引入crypyo-js模块作为CryptoJS使用。随后将userId和token内容按照设置格式进行拼接,形成最终的待加密内容。最后在Encrypt函数中将待加密内容进行HEX处理,然后进行加密操作,返回最终的加密结果。

    编写完毕脚本之后,在控制台运行微信小程序url传值,成功输出加密之后的内容:

    至此,我们便可以随时随地不依托于网络及微信小程序生成自己的电梯二维码了。

    RECRUITMENT

    招聘启事

    安恒雷神众测SRC运营(实习生)

    ————————

    【职责描述】

    1. 负责SRC的微博、微信公众号等线上新媒体的运营工作,保持用户活跃度,提高站点访问量;

    2. 负责白帽子提交漏洞的漏洞审核、Rank评级、漏洞修复处理等相关沟通工作,促进审核人员与白帽子之间友好协作沟通;

    3. 参与策划、组织和落实针对白帽子的线下活动,如沙龙、发布会、技术交流论坛等;

    4. 积极参与雷神众测的品牌推广工作,协助技术人员输出优质的技术文章;

    5. 积极参与公司媒体、行业内相关媒体及其他市场资源的工作沟通工作。

    【任职要求】

    1. 责任心强,性格活泼,具备良好的人际交往能力;

    2. 对网络安全感兴趣,对行业有基本了解;

    3. 良好的文案写作能力和活动组织协调能力。

    简历投递至

    bountyteam@dbappsecurity.com.cn

    设计师(实习生)

    ————————

    【职位描述】

    负责设计公司日常宣传图片、软文等与设计相关工作,负责产品品牌设计。

    【职位要求】

    1、从事平面设计相关工作1年以上,熟悉印刷工艺;具有敏锐的观察力及审美能力,及优异的创意设计能力;有 VI 设计、广告设计、画册设计等专长;

    2、有良好的美术功底,审美能力和创意,色彩感强;

    3、精通photoshop/illustrator/coreldrew/等设计制作软件;

    4、有品牌传播、产品设计或新媒体视觉工作经历;

    【关于岗位的其他信息】

    企业名称:杭州安恒信息技术股份有限公司

    办公地点:杭州市滨江区安恒大厦19楼

    学历要求:本科及以上

    工作年限:1年及以上,条件优秀者可放宽

    简历投递至

    bountyteam@dbappsecurity.com.cn

    安全招聘

    ————————

    公司:安恒信息

    岗位:Web安全 安全研究员

    部门:战略支援部

    薪资:13-30K

    工作年限:1年+

    工作地点:杭州(总部)、广州、成都、上海、北京

    工作环境:一座大厦,健身场所,医师,帅哥,美女,高级食堂…

    【岗位职责】

    1.定期面向部门、全公司技术分享;

    2.前沿攻防技术研究、跟踪国内外安全领域的安全动态、漏洞披露并落地沉淀;

    3.负责完成部门渗透测试、红蓝对抗业务;

    4.负责自动化平台建设

    5.负责针对常见WAF产品规则进行测试并落地bypass方案

    【岗位要求】

    1.至少1年安全领域工作经验;

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    发表评论