本文は Android の WeChat 8.0.3 に基づいています。
最近、逆向きの学習を始めましたので、メモしておきます。
この記事は WeChat シリーズの第 1 回で、サイコロとじゃんけんの機能について分析します。
サイコロとじゃんけんはどちらもランダムな結果が出るため、おそらくランダムな数値を使用していると推測されます。後で実際に確認したところ、その通りでした。
1、フックポイントの探索#
Java の Random クラスに対応するクラス名は java.util.Random であり、objection を使用してウォッチします:
サイコロの絵文字を送信すると、以下の Random メソッドが呼び出されることがわかります:
java.util.Random.nextInt をウォッチし、再度サイコロを振ると、呼び出しスタック、パラメータ、および返り値をダンプします:
nextInt (n): メソッド呼び出しは、0(含む)から n(含まない)の間の擬似乱数を一様に分布させた int 値を返します。
nextInt のパラメータは 6 で、返り値は 1 であり、サイコロの結果は 2 です。
実際には、ここでもフックポイントとして使用できますが、細かすぎるという問題があります。フックする必要があるのは、サイコロとじゃんけんだけであり、Java ユーティリティクラスのランダム数値メソッドを直接フックするのはやや乱暴です。
呼び出しスタックをさらに追跡すると、getIntRandom は tencent sdk のメソッドであり、明らかなランダム数値生成メソッドです。
さらに上に進み、om.tencent.mm.plugin.emoji.e.f.o をウォッチして、追加の情報を取得できるか確認します。
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」に対応しています。
次に、じゃんけんのロジックを見てみると、サイコロと同じです。
- field_name は 'jsb.png' であり、じゃんけんのピンインの頭文字です:
- getIntRandom のパラメータは 2 で、[0,2] の int のランダムな数値を取得します:
- 返り値の field_name は jsb_b.png であり、じゃんけんの結果「布」と一致しています。
ここまで分析した結果、使用中に e.f.o のパラメータを使用して、現在取得するランダム数値がどの絵文字(じゃんけんまたはサイコロ)を取得するかを判断し、getIntRandom の返り値をフックして変更することで、望む結果を得ることができます。
まとめると、フックできるポイントは次のとおりです:
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 スクリプトの作成#
設定:じゃんけんははさみしか出さない、サイコロは 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