本文基于 Android 微信 8.0.3
最近开始做一些软件的逆向学习,记录一下。
本文为微信系列的第一篇,对掷骰子和猜拳功能的分析。
掷骰子和猜拳都会出现随机的结果,所以猜测,应该是通过随机数实现的,后期发现实际上也是如此。
1、 寻找 hook 点#
Java Random 类对应的类名为 java.util.Random,使用 objection 对其进行 watching:
发送骰子的表情,发现 Random 的以下方法被调用:
对 java.util.Random.nextInt 进行 watch,再次掷骰子,dump 出调用栈、参数和返回值:
nextInt (n) : 在方法调用返回介于 0 (含) 和 n (不含) 伪随机,均匀分布的 int 值。
nextInt 的参数为 6,返回值为 1,掷骰子的结果为 2。
其实此处也可以作为 hook 点,但是不够细致。需要 hook 的点仅仅是掷骰子和猜拳,直接 hook Java 工具类的随机数方法,还是比较粗暴。
上溯调用栈,getIntRandom 是 tencent sdk 中的方法,很明显的一个生成随机数的方法。
继续向上,om.tencent.mm.plugin.emoji.e.f.o ,watch 一波这两个方法,看看能得到什么额外的信息。
android hooking watch class_method com.tencent.mm.sdk.platformtools.Util.getIntRandom --dump-args --dump-return
android hooking watch class_method com.tencent.mm.plugin.emoji.e.f.o --dump-args --dump-return
再次掷骰子,这次的结果为 5 点。
e.f.o 方法的参数为:
返回值为:
从这个方法的参数和返回值可以推断出,dice.png 是掷骰子的图片,dice_5.png 是 5 点的骰子。
在本次调用过程中:图片可以看出,getIntRandom 得到的随机数 “0-5”, 对应掷骰子结果的点数 “1-6”
接下来,看了一下猜拳的逻辑,和掷骰子一致。
1.field_name 为 ‘jsb.png’,也就是剪刀石头布的拼音首字母:
2、getIntRandom 的参数为 2,获取 [0,2] 的 int 随机数:
3、返回值中的 field_name 为 jsb_b.png,和猜拳的结果 "布" 一致。
分析到这里,在利用过程中可以根据 e.f.o 的参数来判断当前要获取随机数的是什么表情(猜拳 OR 掷骰子),然后 hook 并修改 getIntRandom 的返回值,来得到想要的结果。
总结一下,可以用来 hook 的点:
com.tencent.mm.plugin.emoji.e.f.o(com.tencent.mm.storage.emotion.EmojiInfo)
com.tencent.mm.sdk.platformtools.Util.getIntRandom(int,int)
2、编写 Frida script#
设定:猜拳只出剪刀,掷骰子只出 6 点。
编写 frida 脚本:
function main() {
Java.perform(function () {
Java.openClassFile("/data/local/tmp/r0gson.dex").load();
const gson = Java.use('com.r0ysue.gson.Gson')
var jsb = 0 // 只出剪刀
var dice = 5 // 只出6点
var efo = Java.use('com.tencent.mm.plugin.emoji.e.f')
efo.o.implementation = function (x) {
var xstr = gson.$new().toJson(x)
if (xstr.search('dice.png') != -1) {
console.log('正在掷骰子')
hookIntRandom(dice)
} else if (xstr.search('jsb.png') != -1) {
console.log("正在猜拳")
hookIntRandom(jsb)
}
var res = this.o(x)
return res
}
})
}
function hookIntRandom(a) {
Java.perform(function () {
var util = Java.use('com.tencent.mm.sdk.platformtools.Util')
util.getIntRandom.implementation = function (int1, int2) {
var res = this.getIntRandom(int1, int2)
return a
}
})
}
setImmediate(main)
注:脚本中使用了肉丝的 Gson 来打印对象,不得不说,好使。
3、参考资料#
参考资料
Frida 打印 [object] 解决 Gson 包重名的问题 - https://bbs.pediy.com/thread-259186.htm