吾爱破解 - LCG - LSG |安卓破解|病毒分析|破解软件|bj5208.com

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

搜索
查看: 17568|回复: 261
上一主题 下一主题

[Android 原创] wx支付流程以及加密的分析

    [复制链接]
跳转到指定楼层
楼主
三年三班三井寿 发表于 2020-1-4 21:01 回帖奖励
本帖最后由 三年三班三井寿 于 2020-1-9 18:47 编辑

本贴仅供学习交流,请勿用作其他任何用途

新天镜棋牌_[官网入口]19年底捣鼓了一阵wx协议,但没有相关资料所以摸索了挺久。后来找了一套旧版的协议源码,奈何支付协议是转不了帐的,所以自己就看了一下这个。新天镜棋牌_[官网入口]而有了协议框架,我们只需要去看转账相关的组包逻辑。
准备:
分析工具:xp,frIDA,jadx,IDA               wx版本:都差不多,706,707,708都看过
首先开启wx的日志xlog,直接搜索

然后找到开关isLogcatOpen赋值的地方,修改第五个参数为1即可

当然也可以直接找其上层调用


[JavaScript] 纯文本查看 复制代码
        var XLOG=Java.use("com.tencent.mm.sdk.platformtools.ab");
        //var StringClz=Java.use("java.lang.String");
        XLOG.i.overload('java.lang.String', 'java.lang.String', '[Ljava.lang.Object;').implementation=function(s1,s2,s3){
        if(s3==null){
            console.log("i:"+s1+","+s2);
        }else{
            console.log("i:"+s1+","+s2+s3);
        }
            return this.i(arguments[0],arguments[1],arguments[2]);
        }
        XLOG.f.overload('java.lang.String', 'java.lang.String', '[Ljava.lang.Object;').implementation=function(s1,s2,s3){
        if(s3==null){
            console.log("f:"+s1+","+s2);
        }else{
            console.log("f:"+s1+","+s2+s3);
        }
            return this.f(arguments[0],arguments[1],arguments[2]);
        }


微信组包以及加解密的so文件,LibMMProticalJni.so,其组包函数为pack

我们直接hook其Java层调用

[JavaScript] 纯文本查看 复制代码
   var MMProtocalJni=Java.use("com.tencent.mm.protocal.MMProtocalJni");
[/color][/size][/color][/size][size=5][color=red][size=3][color=black]   MMProtocalJni.pack.implementation=function(){  
       console.log("MMpack:"+bytesToHex(arguments[0]));
       return this.pack(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5],arguments[6],arguments[7],arguments[8],arguments[9],arguments[10],arguments[11],arguments[12],arguments[13]);
   }

首先我们扫付款码,这是之前用xp hook的日志,前面一些基本都是环境设备信息,deviceId,clientVersion之类的,和其他功能组包类似,我们所需要关注的是后面的字符串。明显的是transfer_url就是二维码的字串,进行了简单的编码。WCPaySign是本地计算出来的一个值,而WCPaySign以及channel之间还有一段序列特征,具体是啥也没深入研究,有知道的大佬可以告诉我一下。新天镜棋牌_[官网入口]测试中有时会有encrypt_key以及encrypt_userinfo字段,具体也是由WCPaySign以及channel之间字段决定的。
transfer_url是直接通过java库函数URLEncoder解析得到的:
我们可以在这里替换用户扫描的二维码,使得对方不管扫什么码都会跳到我们自己的二维码上。比较简单的做法就是直接hook URLEncoder,通过收款码特征或者堆栈进行判断过滤,当然也可以自己重写这个w类构造,构造一个hashMap传入
[JavaScript] 纯文本查看 复制代码
 URLEN.encode.overload("java.lang.String").implementation=function(str){
        console.log("URLEN");
        var res=this.encode(str);
        var stack=instance.currentThread().getStackTrace();
        var full_call_stack=where(stack);
        return res.indexOf("wxp%3A%2F%2F")==0&&full_call_stack.indexOf("com.tencent.mm.plugin.remittance.model.w.<init>")?
        "wxp%3A%2F%2Ff2f0NtReekKHV87BM0pY6k3TVjHlljtYL4sQ":res
    }
新天镜棋牌_[官网入口]不过如果这样做有一个问题,就是不管是扫谁的二维码,都会跳转到自己的付款页面。
那么能不能实现,扫谁的码就出现给谁付款的页面,但实际转账却并不是给他转?换句话说就是页面上显示的一切都是正常的,但实际却转给了另一个人?当然是可以的,不过我们需要先进行模拟扫我们码的操作,然后获取到返回的openid,ticket等。之后在后面付款的时候将正常的这些字段替换成我们的就可以了。扯远了,下面进行定位,寻找WCPaySign的算法。调用堆栈如下,直接调用函数为com.tencent.mm.ak.t.a
这个函数比较长,jadx反编译的有问题需要修改设置选项,也可以用jd直接查看调用位置
接着找参数赋值的地方,由一个成员变量req实例化为l.b类型后,进行了序列化
而req的初始化在t构造函的数中
同样的方法hook其构造函数,调用堆栈如下

前两个不用看了,u的构造参数qVar.getReqObj也是t的构造参数,而u的构造是在com.tencent.mm.ak.m.dispatch中,构造参数是它的第二个参数q.getReqObj()的返回值。
也是com.tencent.mm.wallet_core.c.u.dispatch的第二个参数

具体赋值的地方在com.tencent.mm.wallet_core.tenpay.model.m.doScene中的rr
这里的rr,之前的q,以及最初的req,他们的类型其实都不一样。rr实际上是com.tencent.mm.wallet_core.tenpay.model.m所继承的父类的成员,该类也正是我们所需要找的,赋值的地方在setRequestData中的最后。在此之前,正是计算了WCPaySign。
getEncryptUrl是q中一个抽象的方法,实现如下
从名称看就是一个3DES(md5(str))的算法,实际上也确实如此
其md5计算只是在Java层调用的标准库
3DES算法Java层调用接口为encrypt,前一个参数是key,没有则默认
除此之外,接口类q中提供了getUri接口,其返回值是post的cgi目录,在com.tencent.mm.wallet_core.c.u onGYNetEnd中的第四个参数传入了q的实例
通过反射获取到post接口为/cgi-bin/mmpay-bin/transferscanqrcode
接下来进入so层
调用的so为libtenpay_utils.so,也是标准生成的C函数
在encrypt中很容易发现默认密钥
但用这key尝试了几种加密方式,结果都不正确
可能并非标准的算法,看了一下置换表也没发现有什么变化,直接将其算法抠出来
Des3Str就是分组加密函数,Des3进行了单个分组加密
流程就是3DES的加密方式:EK3(Dk2(Ek1(P)))
DES_Encode:
代码太长就不贴了,当时用的IDA6.8,其反编译的还是多多少少有些坑的,现在用的7.0但也懒得去这部分反编译是不是一样的。
注意内存结构就行,然后再用frida对so中的调用依次hook定位问题函数,动态调试即可。这里提一点,sub_D86C函数中反编译的代码中有很多__PAIR__,如果直接用网上ida头文件中的宏定义的话会有问题。而且这个问题并非语法问题,而是ida反编译得不够准确,只能通过调试或看反汇编解决
仔细一点观察,就会发现其伪代码逻辑比较奇怪,实际汇编代码如下:
可以将那句伪代码直接用x86内联汇编给替代了
[Asm] 纯文本查看 复制代码
push eax;
mov eax,r5;
sub eax,1;
sbb r5,eax;
shl r5,1;
mov eax,r5;
mov v21,eax;
pop eax;
其实稍作分析,其真实逻辑只是在判断r5是否为0,可以将伪代码改成:
v21=(BYTE2(v49)&0x20)?2:0;到此,paysign算出的结果总算正确了。
再通过有源码的协议进行封包发送及解包,可以获取到返回的各字段
[C] 纯文本查看 复制代码
{{
  "retcode": "0",
  "retmsg": "",
  "user_name": "wxid_7vf3tr41v3g921",
  "true_name": "**鹏",
  "fee": "0",
  "desc": "",
  "scene": "32",
  "transfer_qrcode_id": "aOqTgOotZtAyyz2gsfUHWPV9hsUkxMEHkCVpM5OynlvT6Q2fy6Cwv1ffb7NLyPf9PNB-CY1mWSZW0YqQjo39TbJJWLdpPDnX2EROxb1aHTx1FKd6jqZf1wgFS98q0D32",
  "rcvr_ticket": "Y4pH5nL20VA7CcRPboeyg-4PBk3ma7_U_vksGZzWTBYE4ioVEcz_v6PrG_ZS1QtY",
  "get_pay_wifi": 1,
  "receiver_openid": "oX2-vjvhwAutxXTxz85dJeSzzG-k",
  "scan_scene": 1,
  "favor_list": [],
  "amount_remind_bit": 4
}}
不过12月开始好像就不返回wxid了,也就是user_name返回的是空""
类似的,在转账的时候,还有一个密码的算法,快速地说一下,还是一样的通过调用栈去找
hook com.tencent.mm.plugin.wallet.pay.a.a.b构造
密码是第一个参数authen的成员变量
com.tencent.mm.plugin.wallet.pay.a.a.a同理也是一样
con.tencent.mm.plugin.wallet.pay.a.a.e里有post地址,当然之前paysign里面那个hook也能获取到:
再上一层调用:
Authen为cZw()返回值
密码通过成员变量hef进行赋值
hef赋值的地方
再往上找密码字串
又找到一个字段vfo
密码加密后字符串由getText()得到,具体是com.tencent.mm.wallet_core.ui.formview.c.a.a的返回值
跟进去看到,payu和tenpay有两种返回值
我们好友转账,扫码转账,包括708新加入的手机号转账走的都是tenpay,i大概是触发的类型,确定交易时是1,输入金额时是100,其实现部分
新天镜棋牌_[官网入口]当输入金额时,返回的就是输入的明文数字,其他类型会进行加密。实际上com.tencent.mm.wallet_core.ui.formview.WalletFormView以及com.tencent.mm.wallet_core.ui.formview.EditHintPasswdView的两个getText实现分别返回了输入的金额以及密此码明文,通过此可以修改转账金额,再将生成订单金额还原成之前的金额,即可控制实际转账金额
[JavaScript] 纯文本查看 复制代码
        var WalletOpenViewProxyUI=Java.use("com.tencent.mm.wallet_core.ui.e");
        var old="";
        WalletOpenViewProxyUI.e.overload("double","java.lang.String").implementation=function(a1,a2){
            //var uPn=Java.cast(Authen.class,clazz).getDeclaredField("uPn");
            //uPn.setAccessible(true);
            //send("uPn:"+uPn.get(a1));
            if(a1==0.02)//显示原有金额
                a1=Number(old) ;
            var res=this.e(a1,a2);
            send("a1:"+a1.toString()+",res:"+res);
            var stack=instance.currentThread().getStackTrace();
            var full_call_stack=where(stack);
            //console.log(full_call_stack);
            return res;
        }
        var wwww=Java.use("com.tencent.mm.wallet_core.ui.formview.WalletFormView");
        wwww.getText.implementation=function(){
            old=this.getText();
            return "0.02";//设置实际转账金额
        }


当然你有兴趣也可以把转账成功信息给改了,那么用户很可能都不清楚自己转账金额已经被篡改了,好像又扯远了。
我们继续分析加密函数getEncryptDataWithHash,另一个加密get3DesEncryptData不知是什么情况下进行的,getInputText()能获取到密码明文,紧接着会判断mlEncrypt有没有实现,该成员类型是一个接口类



具体实现在com.tenpay.android.wechat.TenpaySecureEncrypt.encryptPasswd,str就是传入的密码明文,先计算了一下md5。str2传入的是时间戳,时间戳是com.tenpay.android.wechat.TenpaySecureEditText的setSalt方法设置的

接下来进入so层还原其算法即可,算法为RSA2048。毕竟密码位数太短,取md5后也很容易被爆破,在加密之前还需要加盐,盐是时间戳以及随机数填充的。
代码太长也就不贴了,同样在IDA6.8中存在一些错误,提一点encrypt_pass1函数中有这三个变量取了同一个地址


然而事实并非这样,通过汇编可以看到在赋值前先抬高了sp,虽然每次都是取的var_6C位置,但前后栈顶已经不一样了:

也就是说只要操作sp的地方,伪代码都是有些问题的,比如这个else里面的v9=&res,res是传入的参数,这种逻辑一看就是有问题的:

通过反汇编看到这里也是通过sp去索引的变量,实际上sp已经抬高了三次,这里真实的索引不是参数res,而是在局部变量s中:

新天镜棋牌_[官网入口]密码加密算法还原后我们就能模拟其支付协议了。不管是好友转账,扫码转账或者手机号转账最后都是需要req_key的,差不多就是个订单号的意思


好友转账可以通过CGI_TENPAY直接传对方wxid然后返回req_key,扫码比较麻烦些,之前WCPaySign那步获取到openid,ticket,qrcode_id等字段,再通过这些字段去生成订单走/cgi-bin/mmpay-bin/busif2fplaceorder获取到req_key。但在12月之前,扫码仍有wxid返回时,可以投机走旧版的协议/cgi-bin/micromsg-bin/tenpay,逻辑与之前setRequestData找的一样,大概就是将map中元素拼接成字符串,最后再计算一个paysign,而map中元素也就是扫码返回的数据

获取到req_key,最终完成转账操作,bank_type和bind_serial是绑定银行卡的类型id,都为CFT时使用零钱,获取bind_serial也很简单,这里就不讨论了。
708新增的通过手机号转账也是分为三步,通过/cgi-bin/mmpay-bin/transferphonegetrcvr获取到openid等信息,再通过/cgi-bin/mmpay-bin/transferphoneplaceorder生成订单,获取到req_key,最后再由/cgi-bin/mmpay-bin/tenpay/sns_tf_authen确认订单完成转账。组包中的金额好像进行了一种序列化之类的操作,但还是很容易看得出来的,其算法我们可以自己实现:
[C#] 纯文本查看 复制代码
        private int Pow(int x, int n)
        {
            int res = 1;
            while (n > 0)
            {
                if ((n & 1) == 1) res = res * x;//转化为二进制
                x = x * x;//将x平方
                n >>= 1;
            }
            return res;
        }
        public string getFee(int money,bool isfirst=false,int sign=-1)
        {
            if (money < 0x80 && isfirst == true)
                return String.Format("{0:X2}", money);
            int i = 0;
            int temp = (int)money;
            while ((temp /= 0x80)>=1)
                i++;//递归次数
            if (isfirst == true) sign = i;
            int pow= Pow(128, i);//128 i次方
            int dwRes = (pow==1)? money:money/pow;
            money = (pow == 1) ?0: money-dwRes * pow;
            if (isfirst == false) dwRes += 0x80;
            string res = String.Format("{0:X2}", dwRes);
            return sign == 0?res: getFee(money, false, --sign)+res;
        }

手机转账其实并没有分析很多,很多数据没有分析,只是写死的,但也是能实现手机转账的功能。
太晚了不写了,其实也就初探了下微信支付的流程,加密的算法。当然后续还需要进一步的封包压缩加密,但这都有现成的协议代码。虽然wx是一款社交软件,但其加密强度目前来看也是很高的,但在本地上,我们仍能做很多有趣的事情,所以建议大家不要使用wx模块之类的插件



图片1.png (16.25 KB, 下载次数: 52)

图片1.png

免费评分

参与人数 146吾爱币 +131 热心值 +136 收起 理由
keke66 + 1 + 1 热心回复!
苏苏啊 + 1 + 1 牛逼 大佬
升升欧巴 + 1 + 1 我很赞同!
大宇宙飘小地球 + 1 我很赞同!
陆生默默 + 1 + 1 我很赞同!
alanmei + 1 鼓励转贴优秀软件安全工具和文档!
TomoriNao + 1 + 1 大佬
月六点年一倍 + 1 我很赞同!
WAPJNB + 1 + 1 谢谢@Thanks!
meino + 1 + 1 热心回复!
Undefine + 1 用心讨论,共获提升!
jianwu2020 + 1 感谢对于技术热爱以及分享
DZWLJSZWAS + 1 谢谢@Thanks!
7uannengwang + 1 我很赞同!
CaptainZ + 1 我很赞同!
jacky81 + 1 我很赞同!
北冥丶 + 1 + 1 我很赞同!
Coptis_china + 1 用心讨论,共获提升!
StaRY_271 + 1 + 1 我操 无情
1638954969 + 1 + 1 我很赞同!
52pojie52proji + 1 + 1 666
remtos123 + 1 + 1 虽然看不太懂,希望以后通过学习能收获
idying + 1 + 1 用心讨论,共获提升!
wangkvn123 + 1 我很赞同!
草丛里的妲己 + 1 热心回复!
琦开得胜 + 1 + 1 E
revolt + 1 + 1 用心讨论,共获提升!
全场最佳赵山河 + 1 + 1 谢谢@Thanks!
foxhack + 1 用心讨论,共获提升!
盖浇饭君 + 1 很强,学习一下
kppp888q + 1 + 1 用心讨论,共获提升!
brIckZ + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
撸冰花 + 1 + 1 热心回复!
asylm + 1 + 1 谢谢@Thanks!
jnez112358 + 1 + 1 谢谢@Thanks!
jzdmy + 1 用心讨论,共获提升!
彤哥来啦 + 1 + 1 用心讨论,共获提升!
deliverance + 1 + 1 用心讨论,共获提升!
cao2630996 + 1 用心讨论,共获提升!
LLForever + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
moritenw + 1 用心讨论,共获提升!
庚^溯 + 1 精辟
ou2375904954 + 1 + 1 用心讨论,共获提升!
5omggx + 1 + 1 用心讨论,共获提升!
lmjg520 + 1 + 1 热心回复!
misan + 1 + 1 用心讨论,共获提升!
Snha + 1 + 1 我很赞同!
红烧排骨 + 1 热心回复!
相逝相逝 + 1 + 1 热心回复!
dzj0821 + 1 + 1 谢谢@Thanks!
FASTBLUE + 1 + 1 我很赞同!
4everlove + 1 + 1 谢谢@Thanks!
diseven + 1 + 1 热心回复!
gmleeben + 1 + 1 鼓励转贴优秀软件安全工具和文档!
xiong_online + 1 + 1 用心讨论,共获提升!
Mouse + 1 + 1 热心回复!
CN911 + 1 + 1 受教了
life091303 + 1 + 1 热心回复!
乐观的阿斯顿 + 1 用心讨论,共获提升!
雄13 + 1 + 1 热心回复!
lalala17 + 1 + 1 谢谢@Thanks!
jacky520510 + 2 + 1 热心回复!
taozhi + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
keluo + 1 + 1 我很赞同!
wapj3871 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
000000 + 2 + 1 牛逼
a不卑不亢 + 1 + 1 厉害了
baihua + 1 + 1 大神请收下我的膝盖
yuweb + 1 + 1 热心回复!
hgfty1 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
52pojie666z + 1 + 1 用心讨论,共获提升!
雨呱 + 1 + 1 用心讨论,共获提升!
953124452 + 1 热心回复!
Cyber + 1 看不懂 给个热心 希望大神多多分享
ws101929 + 1 + 1 我很赞同!
布鲁斯.H + 1 热心回复!
hanyufeng + 1 + 1 虽然看不懂,但看到扫别人码付款给自己,这个牛逼克拉斯
jimy125 + 1 + 1 我很赞同!
唐建威 + 1 + 1 我很赞同!
liphily + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
baixiuxiu + 1 + 1 谢谢@Thanks!
博林爱学 + 1 谢谢@Thanks!
q5q1234567 + 2 + 1 用心讨论,共获提升!
yunshang + 1 + 1 我很赞同!
lyslxx + 1 + 1 我很赞同!
hexiaomo + 1 + 1 热心回复!
yixi + 1 + 1 谢谢@Thanks!
kentish + 1 + 1 用心讨论,共获提升!
海之彼岸 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
zzzain46 + 3 + 1 用心讨论,共获提升!
福仔 + 2 + 1 谢谢@Thanks!
bugof52pj + 1 + 1 谢谢@Thanks!
zh954756 + 1 + 1 用心讨论,共获提升!
quandu + 1 + 1 我很赞同!
xinlixue + 1 鼓励转贴优秀软件安全工具和文档!
howsk + 1 + 1 这是真的,我刚才转了1元,到账10万元
lolo666666 + 1 + 1 膜拜大神,对大神扯远了的事情,非常震惊。
愈来记挂 + 1 + 1 太牛逼了
抱歉、 + 1 用心讨论,共获提升!
gaosld + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
xiong1992 发表于 2020-1-6 10:09
是不是可以理解为我买了东西当对方面去扫对方的微X二维码,显示支付成功后结果却是我给我的另外一个号转钱过去了;或者是2元的东西,显示成功支付2元后,实际上我只支付了1元;或者是别人给我转账,转1元,显示成功支付1元,但是实际上我却收到了他转的2元。这个如果给不法分子利用就麻烦了。
推荐
努力的T先生 发表于 2020-1-5 00:03
看不懂,不知道大神能不能给个变得跟你一样优秀的思路,至少把这个看得懂
推荐
 楼主| 三年三班三井寿 发表于 2020-1-8 12:43 <
5#
ccc800 发表于 2020-1-4 21:33
大神。路过 看的眼花
6#
ebacn 发表于 2020-1-4 21:33
感谢,学习了!
7#
股票亏损员 发表于 2020-1-4 21:37
感觉看到是天书
8#
52pojieggh 发表于 2020-1-4 21:46
天书一本
9#
linfengtai2008 发表于 2020-1-4 21:50
厉害,学习了
10#
冷月残星 发表于 2020-1-4 21:52
大神。。。
11#
88491354@qq.com 发表于 2020-1-4 21:59
大哥厉害,之后买兰博基尼就靠你了。&#128516;
12#
nshark 发表于 2020-1-4 22:03
看着都迷糊
13#
winson365 发表于 2020-1-4 22:09
大神,望尘莫及啊
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2020-2-18 05:09

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表

页面底部区域 foot.htm