支付宝「自定义」消息发送
实际上不能发送自定义消息,只是通过修改特定类型消息的本地数据,实现类似自定义消息的效果。
支付宝内能转发的消息类型很少,文字、链接、小程序等可以转发。红包、转账卡片等类型的消息不能转发。
消息的类型由templateCode字段确定,消息内容由templateData字段确定,跳转链接由link字段确定。
支付宝消息的数据是加密的,可以通过hook的方式操作数据库。数据库路径中包含关键词chatmsgdb。
每个会话都有一张表,表的结构:
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
| localId clientMsgId createTime bizType bizMemo bizIcon templateCode templateData side link appId msgId egg extendData mediaState errorCode errorMemo sendingState loadingState recent countAsUnread atMe isResourceUploaded action bizRemind isEggRead scene msgIndex
|
修改数据的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
| SQLiteDatabase.rawQuery.overload('java.lang.String', '[Ljava.lang.String;').implementation = function (arg_0, arg_1) { if(this.getPath().indexOf('chatmsgdb') > -1){ if(arg_0.indexOf('`personal_chat_2088212830461913`') > -1){ arg_0 = 'update personal_chat_2088212830461913 set templateData=replace(templateData, "小程序", " ") where localId="1695536846469"; ' } console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) var result = this.rawQuery(arg_0, arg_1); result.moveToFirst() console.log('localId:' , result.getString((result.getColumnIndex('localId')))) console.log('bizType:' , result.getString((result.getColumnIndex('bizType')))) console.log('bizMemo:' , result.getString((result.getColumnIndex('bizMemo')))) console.log('templateCode:' , result.getString((result.getColumnIndex('templateCode')))) console.log('templateData:' , result.getString((result.getColumnIndex('templateData')))) send(result.getString(9)) send(result.getString(13)) result.moveToFirst() return result } return this.rawQuery(arg_0, arg_1) }
|
最终效果:


数据库解密
阿里系都是用的相同的数据库加密方案。
类名:com.alibaba.sqlcrypto.sqlite.SQLiteDatabase
数据的加解密是在native层做的

使用frida获取密钥
| Interceptor.attach(Module.findExportByName("libdatabase_sqlcrypto.so", "aes_decrypt"), { onEnter: function (args) { console.log(hexdump(args[2], { offset: 0, length: 0x10, header: true, ansi: true })); console.log("aes_decrypt...") }, onLeave: function (retval) { } });
|

解密数据库:
| from Crypto.Cipher import AES
key = b'N4VwrNPjzQbs0WZl' cryptos = AES.new(key, AES.MODE_ECB) data = open('chatmsgdb2088202871367592.db', 'rb').read() plain = cryptos.decrypt(data) with open('database.db', 'wb') as fo: fo.write(plain)
|

参考资料
http://www.javashuo.com/article/p-rnjmxrmi-hd.html
http://www.fenlog.com/?mod=wap&act=View&id=113