xposed实现支付宝微信个人收款免签支付方案
我的个人网站如何实现支付功能?
想必很多程序员都有过想开发一个自己的网站来获得一些额外的收入,但做这件事会遇到支付这个问题。目前个人网站是无法实现支付功能的。
今天我就给大家分享一下我的实现方案:《基于xposed逆向微信、支付宝、云闪付来实现个人免签支付方案》
测试页面(点我) http://pay.changu.net
接下来给大家简单分享一下实现过程,这个过程其实是非常复杂的,关键点在于如何逆向微信支付宝云闪付这些App,找到核心函数钩子,然后写一个hook程序来模拟调用这些方法,来实现根据服务端传过来的金额,订单号自动调用微信支付宝生成支付二维码的函数得到相对应的支付二维码再传给服务端,然后监听微信支付宝的支付成功消息最终回调给服务端实现支付成功通知。这里面用到的核心技术点有:xposed逆向框架、apk反编译,网络抓包,apk动态调试等技术。
像微信支付宝这些apk反编译后的代码基本上都是天书一样的,严重混淆过的代码。想从中找到核心代码并非易事,下面我贴一些核心代码吧。
hook微信二维码生成函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | private void hookQRCreat( final ClassLoader appClassLoader, final Context context) { Class<?> clazz = XposedHelpers.findClass( "com.tencent.mm.plugin.collect.b.s" , appClassLoader); XposedBridge.hookAllMethods(clazz, "a" , new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { } @Override protected void afterHookedMethod(MethodHookParam param) { try { LogUtils.log( "hookQRCreat start:" ); QrBean qrBean = new QrBean(); qrBean.setChannel(QrBean.WECHAT); Field moneyField = XposedHelpers.findField(param.thisObject.getClass(), "kcp" ); Double money = (Double) moneyField.get(param.thisObject); LogUtils.log( "hookQRCreat money:" +money.toString()); Field markField = XposedHelpers.findField(param.thisObject.getClass(), "desc" ); String mark = (String) markField.get(param.thisObject); LogUtils.log( "hookQRCreat mark:" +mark); Field payurlField = XposedHelpers.findField(param.thisObject.getClass(), "kco" ); String payurl = (String) payurlField.get(param.thisObject); LogUtils.log( "hookQRCreat payurl:" +payurl); qrBean.setMark_sell(mark); qrBean.setUrl(payurl); LogUtils.log( "com.tencent.mm.plugin.collect.b.s qrBean:" + JSON.toJSONString(qrBean)); Intent broadCastIntent = new Intent(); broadCastIntent.putExtra( "data" , qrBean.toString()); broadCastIntent.setAction(HookMain.RECEIVE_QR_WECHAT); // broadCastIntent.setComponent( new ComponentName( "com.sjk.tpay" , // "com.sjk.tpay.ReceiverMain") ); context.sendBroadcast(broadCastIntent); LogUtils.log( "hookQRCreat end:" +JSON.toJSONString(param)); } catch (Exception e){ LogUtils.log( "hookQRCreat exception:" +Log.getStackTraceString(e)); } } }); } |
hook支付宝二维码生成函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | private void hookQRCreat( final ClassLoader appClassLoader, final Context context) { XposedHelpers.findAndHookMethod( "com.alipay.mobile.payee.ui.PayeeQRSetMoneyActivity" , appClassLoader, "a" , XposedHelpers.findClass( "com.alipay.transferprod.rpc.result.ConsultSetAmountRes" , appClassLoader), new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { Field moneyField = XposedHelpers.findField(param.thisObject.getClass(), "g" ); String money = (String) moneyField.get(param.thisObject); Field markField = XposedHelpers.findField(param.thisObject.getClass(), "c" ); Object markObject = markField.get(param.thisObject); String mark = (String) XposedHelpers.callMethod(markObject, "getUbbStr" ); Object consultSetAmountRes = param.args[ 0 ]; Field consultField = XposedHelpers.findField(consultSetAmountRes.getClass(), "qrCodeUrl" ); String payurl = (String) consultField.get(consultSetAmountRes); Field consultField2 = XposedHelpers.findField(consultSetAmountRes .getClass(), "printQrCodeUrl" ); String payurloffline = (String) consultField2.get(consultSetAmountRes); QrBean qrBean = new QrBean(); qrBean.setChannel(QrBean.ALIPAY); qrBean.setMark_sell(mark); qrBean.setUrl(payurl); Intent broadCastIntent = new Intent() .putExtra( "data" , qrBean.toString()) .setAction(RECEIVE_QR_ALIPAY); context.sendBroadcast(broadCastIntent); } }); } |
hook云闪付二维码生成函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | public static void GenQrCode( final String paramString1, final String paramString2, final String bankName, final String bankNo) { new Thread( new Runnable() { public void run() { try { Object obj1 = paramString2; Object obj2 = new BigDecimal(paramString1); obj2 = ((BigDecimal) obj2).setScale( 2 , RoundingMode.HALF_UP).toPlainString().replace( "." , "" ); // LogUtils.getInstance().saveLog("GenQrCode begin :" + obj1 + obj2); Object obj3 = new StringBuilder(); ((StringBuilder) obj3).append( "https://pay.95516.com/pay-web/restlet/qr/p2pPay/applyQrCode?txnAmt=" ); ((StringBuilder) obj3).append(MainHook.Enc((String) obj2)); ((StringBuilder) obj3).append( "&cityCode=" ); ((StringBuilder) obj3).append(MainHook.Enc(MainHook.getcityCd())); ((StringBuilder) obj3).append( "&comments=" ); ((StringBuilder) obj3).append(MainHook.Enc((String) obj1)); ((StringBuilder) obj3).append( "&virtualCardNo=" ); // ((StringBuilder) obj3).append(MainHook.encvirtualCardNo); CardInfo cardInfo = getEncvirtualCardNo(bankName, bankNo); if (cardInfo == null ) { throw new Exception( "找不到对应的下单卡" ); } cardInfo.setAccount(ysfAccount); ((StringBuilder) obj3).append(Enc(cardInfo.getVirtualCardNo())); obj1 = ((StringBuilder) obj3).toString(); obj2 = HttpHelper.getInstance().getOkHttpClient(); obj3 = new okhttp3.Request.Builder(); Request.Builder localBuilder = ((Request.Builder) obj3).url((String) obj1).header( "X-Tingyun-Id" , MainHook.getXTid()); // LogUtils.getInstance().saveLog("GenQrCode url:" + obj1); obj3 = new StringBuilder(); ((StringBuilder) obj3).append( "0;" ); ((StringBuilder) obj3).append(System.currentTimeMillis()); obj3 = ((OkHttpClient) obj2).newCall(localBuilder.header( "X-Tingyun-Lib-Type-N-ST" , ((StringBuilder) obj3).toString()) .header( "sid" , MainHook.getSid()).header( "urid" , MainHook.geturid()).header( "cityCd" , MainHook.getcityCd()) .header( "locale" , "zh-CN" ).header( "User-Agent" , "Android CHSP" ).header( "dfpSessionId" , MainHook.getDfpSessionId()) .header( "gray" , MainHook.getgray()).header( "key_session_id" , "" ).header( "Host" , "pay.95516.com" ).build()).execute().body().string(); obj1 = MainHook.Dec((String) obj3); obj2 = new StringBuilder(); ((StringBuilder) obj2).append( "GenQrCode RSP=>" ); ((StringBuilder) obj2).append((String) obj1); MainHook.mlog(obj2.toString()); try { obj2 = new JSONObject((String) obj1); String certificate = ((JSONObject) obj2).getJSONObject( "params" ).getString( "certificate" ); QRInfo qrInfo = new QRInfo(certificate, paramString2); qrInfo.setRemark(JSON.toJSONString(cardInfo)); String body = JSON.toJSONString(qrInfo); Intent localIntent = new Intent( "websocket.sendmsg" ); localIntent.putExtra( "data" , "qr:" + body); MainHook.getContext().sendBroadcast(localIntent); } catch (Exception ex) { LogUtils.getInstance().saveLog( "二维码广播发送异常:" + ex.getMessage()); } return ; } catch (Exception ex) { LogUtils.getInstance().saveLog( "GenQrCode异常:" + ex.getMessage()); } } }).start(); } |
有问题的朋友可以给我留言或者加我Q好友
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?