前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >微信骰子随机数流程

微信骰子随机数流程

作者头像
网e渗透安全部
发布2020-03-26 14:26:36
1.6K0
发布2020-03-26 14:26:36
举报
文章被收录于专栏:白安全组白安全组

首先.准备工作,jadx反编译wx708另存为as源码 点击骰子表情,通过monitor从onclick开始追踪定位到关键函数com.tencent.mm.sdk.platformtools.bo.ii,jadx反混淆后为函数m13717ii,简单观察函数

准备工作,jadx反编译wx708另存为as源码

首先,通过monitor方法回溯从 performClick往下追踪,寻找到关键函数com.tencent.mm.sdk.platformtools.bo.ii,在jadx反混淆后为函数m13717ii

public static int m13717ii(int i, int i2) { AppMethodBeat.m3378i(52299); Assert.assertTrue(i > i2); int nextInt = new Random(System.currentTimeMillis()).nextInt((i - i2) + 1) + i2; AppMethodBeat.m3379o(52299); return nextInt; }

hook此函数,修改返回值,容易判断:

玩骰子时i=5,i2=0,返回0-5对应1-6点

玩石头剪刀布时i=2,i2=0,返回0-2对应石头剪刀布

var bo = Java.use('com.tencent.mm.sdk.platformtools.bo');

bo.ii.overload('int','int').implementation=function(a1,a2)

{ console.log("hook ii start");

console.log("a1:"+a1);

console.log("a2:"+a2);

var rtn= this.ii(5,0);

console.log("rtn:"+rtn);

var threadef = Java.use('java.lang.Thread');

var threadinstance = threadef.$new();

var stack = threadinstance.currentThread().getStackTrace();

function Where(stack){

for(var i = 0; i < stack.length; ++i){

console.log(stack[i].toString());

}

}

console.log("Full call stack:" + Where(stack));

return rtn

}

打印堆栈结果如下

com.tencent.mm.sdk.platformtools.bo.ii(Native Method) m13717ii

com.tencent.mm.plugin.emoji.e.f.n(SourceFile:93) mo46299n

com.tencent.mm.bz.a.n(SourceFile:316) mo46299n

com.tencent.mm.emoji.panel.a.d.a(SourceFile:55) mo46720a

com.tencent.mm.emoji.panel.a.q$1.onClick(SourceFile:27)

android.view.View.performClick(View.java:6294)

android.view.View$PerformClick.run(View.java:24770)

android.os.Handler.handleCallback(Handler.java:790)

android.os.Handler.dispatchMessage(Handler.java:99)

android.os.Looper.loop(Looper.java:164)

android.app.ActivityThread.main(ActivityThread.java:6494)

java.lang.reflect.Method.invoke(Native Method)

com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:440)

com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

首先,通过抛异常然后调用Exception的run方法的方式 反射调用main方法

然后,开启loop循环消息队列处理message

进入 PerformClick触发方法com.tencent.mm.emoji.panel.a.q$1.onClick,后面就进入到关键的逻辑了

我们倒着看

public final EmojiInfo mo46299n(EmojiInfo emojiInfo) { AppMethodBeat.m3378i(52890); if (emojiInfo.field_catalog == EmojiGroupInfo.BmT && emojiInfo.field_type == EmojiInfo.Bur && emojiInfo.getContent().length() > 0 && EmojiInfo.m66104Qp(C9015bo.getInt(emojiInfo.getContent(), 0))) { Cursor Qu = C33825j.getEmojiStorageMgr().BkN.mo55784Qu(C9015bo.getInt(emojiInfo.getContent(), 0));

这个 Cursor Qu的getCount()得到的数值就是最大点数,如果是骰子则为6 if (Qu != null && Qu.getCount() > 1) { int ii = C9015bo.m13717ii(Qu.getCount() - 1, 0); 这一句调用random产生骰子或划拳结果 emojiInfo = new EmojiInfo(); Qu.moveToPosition(ii); 更新变动表情为确定点数表情 emojiInfo.convertFrom(Qu); } if (Qu != null) { Qu.close(); } } AppMethodBeat.m3379o(52890); return emojiInfo; }

传入参数是 EmojiInfo类,表情类Lcom/tencent/mm/storage/emotion/EmojiInfo,可以简单看一下这个类的数据结构

public final Cursor mo55784Qu(int i) { AppMethodBeat.m3378i(62821); Cursor query = this.f15356db.query("EmojiInfo", null, "catalog=? and temp=?", new String[]{String.valueOf(i), AppEventsConstants.EVENT_PARAM_VALUE_NO}, null, null, null); AppMethodBeat.m3379o(62821); return query; }

这里是query 函数用法query(table,columns, selection, selectionArgs, groupBy, having, orderBy, limit)

很清晰,query通过查询 EmojiInfo表的 catalog 目录和temp应该是当前索引表情定位到具体表情属性,返回到上层函数通过getCount()获取子表情,如骰子应该是6个

com.tencent.mm.bz.a.n(SourceFile:316)

public final EmojiInfo mo46299n(EmojiInfo emojiInfo) { boolean z; AppMethodBeat.m3378i(62615); if (((C2666h) C2700g.aaW().aaw()).abR()) { EmojiInfo n = ((C33772d) C2700g.m5024ae(C33772d.class)).getEmojiMgr().mo46299n(emojiInfo); AppMethodBeat.m3379o(62615); return n; } Bundle bundle = new Bundle(EmojiInfo.class.getClassLoader()); bundle.putParcelable("emoji", emojiInfo); Bundle call = C8960ah.getContext().getContentResolver().call(Uri.parse("content://com.tencent.mm.storage.provider.emotion/"), "getRandomEmoji", null, bundle); if (call == null) { C8953ab.m13552e("MicroMsg.EmotionStorageResolver", "[getRandomEmoji] bunndle is null! "); AppMethodBeat.m3379o(62615); return null; } call.setClassLoader(EmojiInfo.class.getClassLoader()); if (call.containsKey("data")) { EmojiInfo emojiInfo2 = (EmojiInfo) call.getParcelable("data"); AppMethodBeat.m3379o(62615); return emojiInfo2; } String str = "MicroMsg.EmotionStorageResolver"; String str2 = "[getRandomEmoji] bundle is null?"; Object[] objArr = new Object[1]; if (call == null) { z = true; } else { z = false; } objArr[0] = Boolean.valueOf(z); C8953ab.m13553e(str, str2, objArr); AppMethodBeat.m3379o(62615); return null; }

我们正常情况下直接走第一个if通过query查询数据库得到 emojiInfo对象

而下面通过bundle传递emojiInfo对象,通过ContentProvider的 getRandomEmoji也获得了一个emojiInfo对象返回,应该是另一个实现random筛子的机制,熟悉四大组件ContentProvider的同学很容易就能看懂,这里我们不在深入跟踪了

public final void mo46720a(Context context, int i, C32002y yVar) { EmojiInfo emojiInfo; String string; AppMethodBeat.m3378i(178705); C0748k.m2427m(context, "context"); C8953ab.m13556i(C32114f.TAG, "onClick: " + i + ", " + yVar); if (yVar == null) { AppMethodBeat.m3379o(178705); return; } switch (yVar.type) { case 0: C31981h hVar = (C31981h) yVar; EmojiInfo emojiInfo2 = hVar.fja; EmojiInfo emojiInfo3 = hVar.fja; if (emojiInfo3.getGroup() == EmojiGroupInfo.BmT) { C2658a ae = C2700g.m5024ae(C33772d.class); C0748k.m2426l(ae, "MMKernel.plugin(IPluginEmoji::class.java)"); EmojiInfo n = ((C33772d) ae).getProvider().mo46299n(emojiInfo3); C0748k.m2426l(n, "MMKernel.plugin(IPluginE…er.getRandomEmoji(toSend)"); emojiInfo = n; } else { emojiInfo = emojiInfo3; } C32015d.m54248Yj().mo46658b(i, emojiInfo2.field_md5, "", emojiInfo2.field_designerID, emojiInfo2.field_activityid); C38218j jVar = this.fmq; if (jVar != null) { jVar.mo36093y(emojiInfo); AppMethodBeat.m3379o(178705); return; } AppMethodBeat.m3379o(178705); return; //后面的case与表情无关,省略 }

这个函数我们直接进入yVar.type =0的case0执行,看他的字符串也很容易看出来 这里可以简单看一下C31981h

(com.tencent.mm.emoji.a.a.h)类的数据结构,

通过hVar.fja属性取出EmojiInfo赋值给emojiInfo2和emojiInfo3

如果emojiInfo3.getGroup() == EmojiGroupInfo.BmT,猜测是判断是否属于筛子或者猜拳表情组

如果属于,调用mo46299n()获取emojiInfo,如果不属于,直接赋值

猜测C32015d.m54248Yj().mo46658b(i, emojiInfo2.field_md5, "", emojiInfo2.field_designerID, emojiInfo2.field_activityid)这一句功能是在界面上显示出EmojiInfo图像,如果是筛子,就是变动的筛子画面

下一句jVar.mo36093y(emojiInfo)显示出固定点数的EmojiInfo图像,然后返回

再往上就是onclick方法了

结尾,我们顺序梳理一下流程 1.系统函数调用,略过 2.点击触发com.tencent.mm.emoji.panel.a.q$1.onClick方法,内部调用mo46720a(com.tencent.mm.emoji.panel.a.d.a)方法 3.进入mo46720a,yVar.type=0直接进入case0,判断表情属于EmojiGroupInfo.BmT组后,调用mo46299n(com.tencent.mm.bz.a.n)方法4.进入mo46299n(com.tencent.mm.bz.a.n)方法,进入第一个if分支,调用mo46299n(com.tencent.mm.plugin.emoji.e.f.n)方法 5.进入mo46299n(com.tencent.mm.plugin.emoji.e.f.n)方法,通过query查询数据库EmojiInfo表的catalog 目录和temp当前索引表情定位到具体表情属性,存储在Qu里,调用com.tencent.mm.sdk.platformtools.bo.ii 6.进入m13717ii(com.tencent.mm.sdk.platformtools.bo.ii)方法,以当前时间戳为种子,通过random产生随机数

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 白安全组 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档