小程序动态调试-解密加密数据与签名校验

简介: 本文主要讲解微信小程序加密、验签的情况下如何进行动态调试已获取签名以及加密信息

前言

微信小程序的加密与验签早前大多数情况,要么就是逆向获取源码而后拿到加密秘钥,要么就是逆向拿到源码后使用腾讯自带的小程序开发者功能进行动态调试模拟,今天介绍一款志远大佬的开源工具---WeChatOpenDevTool

工具下载地址: 链接


正文:

首先运行脚本,而后打开微信小程序,注意先后顺序,打开小程序后,打开调试器

图片.png

图片.png

图片.png

本次使用的依然是PC端微信进行小程序抓包,抓包使用的工具就是fiddler+burpsuite ,具体使用方式上文有过介绍,此处不再进行赘述

图片.png

大家可以看到,首先请求参数是加密的,并且请求头包含nonce、timestamp、signature信息,若是看过笔者的第一篇加密解密文章就知道,这里是一个签名校验,绝大多数的签名校验都是利用以上信息结合body进行加密,少数的还会带上uri或者是一些其他参数,那么我们今天要做的就是获取他请求包包体加密的方式以及签名校验的生成方法


老规矩,直接在开发者调试里面全局搜索requestData参数,这是最快定位的方法,当然了也可以利用网络信息进行断点调试

图片.png

我们很快就找到了关键信息requestData: n.encrypt(o, r),一眼丁真

图片.png

通过单步步过,我们可以获知n = require(t(219))为加密函数,所以需要进去看一下加密方法,,F9步入后发现其实是sm4国密算法,sm4大家可以理解为改良版的aes加密

图片.png

继续进行步过(F10),结果如下:

图片.png

图片.png

图片.png

经过测试,这里面的sm4秘钥是写死的,直接用就行

图片.png

在获取了加密算法与秘钥的情况下,我们继续调试,幸运的是在进行下断点的时候,看到了这个签名校验的函数

图片.png

图片.png

疑似signature

图片.png

图片.png

跟进函数l(u, i, n, v)

图片.png

F9进入到l()函数内,此时函数变为l(e, t, n, r),这里面的e,t,n,r 就相当于u, i, n, v ,这里面就是一个形参,而传入进去的u, i, n, v才是真正的实参

图片.png

我们可以看到,函数最后一行s(p + e + c + u) ,这里其实才是最终输出的值,所以我们需要关注p/e/c/u这四个参数是怎么来的,s()这个函数做了什么

首先,p这个参数其实是一个三元运算结果,我们传入的r参数此时是-1,他会做一个比较,大于等于0和小于0的时候去输出不同的p值

r >= 0 ? p = [(o = a)(345), o(230), o(211), "RhYqRedo=K7JvcuyjpbyppnZr7qQGs21JQsTNSp5TJm", o(269), "Tyrcs"][o(343)](1, 5)[o(215)]("") : p = d();

由于此时是-1,所以p=d(),大家可以步入d()函数,但是其实无论是大于还是小于,结果都是写死的哈

图片.png

r >=0 的时候,

p=NBMExPe9iO{WXsAxZMRhYqRedo=K7JvcuyjpbyppnZr7qQGs21JQsTNSp5TJmczO

r <0 的时候,

p=EvAucyQXqhNrXB23hw8wPw73xHzAHNqipmBFKJTHGzBXTsHpNxR9PGyMhErNEvAu


e的值其实就是个uuid,我们一会进行介绍;

c = e[i(202)](5)  ,我们可以看一下[i(202)](5) 做了什么

图片.png

我们通过控制台调试,不难发现,其实i(202)是一个substring字符串截取工具,而e[i(202)](5)其实就是对e下标为5的位置开始截取字符串


下面就是u了,u = s(JSON[i(286)](n))

我们看JSON[i(286)](n) ,就能大概知道咋回事了,实际上就是把传进来的明文参数进行了json转换

图片.png

但是s()这个函数是干什么呢,实际上笔者一开始也是一脸懵,笔者进入函数调试的时候,发现首先会将json转换后的参数进行ascii编码,然后计算length长度后进行一系列复杂的运算最后生成一个32长度的字符串,最后再进行取值,这里笔者完全是懵逼的,大概精简的代码如下

function l(r) {

       var n = 8 * r.length

         , t = n % 512;

       t = t >= 448 ? 512 - t % 448 - 1 : 448 - t - 1;

       for (var e = new Array((t - 7) / 8), o = 0, a = e.length; o < a; o++)

           e[o] = 0;

       var c = [];

       n = n.toString(2);

       for (var u = 7; u >= 0; u--)

           if (n.length > 8) {

               var l = n.length - 8;

               c[u] = parseInt(n.substr(l), 2),

               n = n.substr(0, l)

           } else

               n.length > 0 ? (c[u] = parseInt(n, 2),

               n = "") : c[u] = 0;

       for (var i = [].concat(r, [128], e, c), s = i.length / 64, v = [115, 128, 22, 111, 73, 20, 178, 185, 23, 36, 66, 215, 218, 138, 6, 0, 169, 111, 48, 188, 22, 49, 56, 170, 227, 141, 238, 77, 176, 251, 14, 78], h = 0; h < s; h++) {

           var g = 64 * h;

           v = f(v, i.slice(g, g + 64))

       }

       return v

}


其实在这里笔者就卡主了,不会了,完全看不出来是什么,这也不是sha1-256,因为笔者去试过了,但是柳暗花明的就是,笔者在第二天清晨看到了这个

图片.png

山重水复疑无路,柳暗花明又一村,原来是SM3

图片.png

图片.png

所以此时问题迎刃而解

图片.png

s(p + e + c + u)  这个函数就是把p + e + c + u四个参数串起来,然后进行SM3编码


上次说到,e的值其实就是个uuid,所以我们回到上面,看一下e是怎么来的

图片.png

进入c()函数

function c() {

       for (var e = a, t = [], n = e(306), r = 0; r < 36; r++)

           t[r] = n[e(234)](Math.floor(16 * Math[e(346)]()), 1);

       return t[14] = "4",

       t[19] = n[e(234)](3 & t[19] | 8, 1),

       t[8] = t[13] = t[18] = t[23] = "-",

       t[e(215)]("")[e(268)]("-", "")

}


图片.png

大家不需要完全看得懂,我们只需要知道,他是由啥组成的,在什么位置有横杠就行

图片.png

这个 JavaScript 函数的作用是生成一个符合 UUID(Universally Unique Identifier)规范的字符串。UUID 是一种用于标识信息或对象的唯一标识符。


现在让我们分解这个 JavaScript 函数的工作原理:


使用一个名为 a 的函数作为参数传入(在这里被省略了)。

创建一个空数组 t,用于存储生成的 UUID。

通过调用函数 e(306) 获取一个随机数生成器。

循环执行 36 次以下操作:

生成一个 0 到 15 之间的随机整数,然后转换为十六进制字符。

将生成的字符存储到数组 t 中。

修改数组中的特定索引位置,使得生成的 UUID 符合 UUID 版本 4 的规范:

将第 15 个字符设置为 "4"(UUID 版本号)。

将第 20 个字符的高 4 位设置为 "8", "9", "a" 或 "b"(UUID 变体)。

将数组中的特定索引位置设置为连字符 "-"。

使用 join() 方法将数组中的元素连接成一个字符串,并移除其中的连字符 "-",最终得到 UUID。

下面是相应的 Python 代码:


python


import random

def generate_uuid():

   characters = '0123456789abcdef'

   uuid_list = [random.choice(characters) for _ in range(36)]

   uuid_list[14] = '4'  # UUID version 4

   uuid_list[19] = random.choice('89ab')  # Variant

   uuid_list[8] = uuid_list[13] = uuid_list[18] = uuid_list[23] = '-'

   return ''.join(uuid_list)


测试生成的 UUID

print(generate_uuid())

这个 Python 函数与 JavaScript 函数的实现类似,使用了 random.choice() 函数来从指定的字符集中随机选择字符,并通过字符串操作和列表操作生成 UUID。


最后总结一下,这个如果写脚本的话,一个接口就需要一个脚本,有点不值了,建议能力强的写个ipython写进burp里,只是难度有点......


相关文章
|
1月前
|
小程序 JavaScript
【微信小程序】-- 自定义组件 - 数据监听器 (三十四)
【微信小程序】-- 自定义组件 - 数据监听器 (三十四)
|
1月前
|
存储 小程序 JavaScript
【微信小程序】-- 自定义组件 -- 数据、方法和属性(三十三)
【微信小程序】-- 自定义组件 -- 数据、方法和属性(三十三)
|
1月前
|
弹性计算 前端开发 小程序
微信小程序上传文件至阿里云OSS直传(java后端签名+前端直传)
当前的通用文件上传方式是通过前端上传到服务器,再由服务器转存至对象存储。这种方式在处理小文件时效率尚可,但大文件上传因受限于服务器带宽,速度较慢。例如,一个100MB的文件在5Mbps带宽的阿里云ECS上上传至服务器需160秒。为解决此问题,可以采用后端签名的方式,使微信小程序直接上传文件到阿里云OSS,绕过服务器中转。具体操作包括在JAVA后端引入相关依赖,生成签名,并在微信小程序前端使用这个签名进行文件上传,注意设置正确的请求头和formData参数。这样能提高大文件上传的速度。
|
1月前
|
小程序
【微信小程序】-- 自定义组件 - 数据监听器 - 案例 (三十五)
【微信小程序】-- 自定义组件 - 数据监听器 - 案例 (三十五)
|
1月前
|
小程序 前端开发 程序员
【微信小程序】-- 网络数据请求(十九)
【微信小程序】-- 网络数据请求(十九)
|
1月前
|
存储 小程序 数据库
零基础开发小程序第五课-修改数据
零基础开发小程序第五课-修改数据
|
15天前
|
小程序 前端开发 API
小程序全栈开发中的多端适配与响应式布局
【4月更文挑战第12天】本文探讨了小程序全栈开发中的多端适配与响应式布局。多端适配涉及平台和设备适应,确保统一用户体验;响应式布局利用媒体查询和弹性布局维持不同设备的布局一致性。实践中,开发者可借助跨平台框架实现多平台开发,运用响应式布局技术适应不同设备。同时,注意兼容性、性能优化和用户体验,以提升小程序质量和用户体验。通过这些方法,开发者能更好地掌握小程序全栈开发。
|
15天前
|
小程序 前端开发 API
微信小程序全栈开发中的异常处理与日志记录
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的异常处理和日志记录,强调其对确保应用稳定性和用户体验的重要性。异常处理涵盖前端(网络、页面跳转、用户输入、逻辑异常)和后端(数据库、API、业务逻辑)方面;日志记录则关注关键操作和异常情况的追踪。实践中,前端可利用try-catch处理异常,后端借助日志框架记录异常,同时采用集中式日志管理工具提升分析效率。开发者应注意安全性、性能和团队协作,以优化异常处理与日志记录流程。
|
15天前
|
小程序 安全 数据安全/隐私保护
微信小程序全栈开发中的身份认证与授权机制
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的身份认证与授权机制。身份认证包括手机号验证、微信登录和第三方登录,而授权机制涉及角色权限控制、ACL和OAuth 2.0。实践中,开发者可利用微信登录获取用户信息,集成第三方登录,以及实施角色和ACL进行权限控制。注意点包括安全性、用户体验和合规性,以保障小程序的安全运行和良好体验。通过这些方法,开发者能有效掌握小程序全栈开发技术。
|
15天前
|
小程序 前端开发 安全
小程序全栈开发中的跨域问题及其解决方案
【4月更文挑战第12天】本文探讨了小程序全栈开发中的跨域问题及其解决方案。跨域问题源于浏览器安全策略,主要体现在前后端分离、第三方服务集成和数据共享上。为解决此问题,开发者可采用CORS、JSONP、代理服务器、数据交换格式和域名策略等方法。实践中需注意安全性、兼容性和性能。通过掌握这些解决方案,开发者能更好地处理小程序的跨域问题,提升用户体验。