Method Profiling:使用 DDMS 获取触摸微信骰子按钮后所调用的函数并修改点数

原文URL : https://www.52pojie.cn/thread-773691-1-1.html

备用URL : https://blog.csdn.net/qfanmingyiq/article/details/81254913

以下是对以上链接的复制,作为个人参考:

备注:BuildProp Enhancer 是一个Xposed软件,可以让apk在不开启debugable的时候进行动态调试在你无从下手的时候我使用DDMS中的traceView工具来帮助我们减少工作量。


打开微信界面

<ignore_js_op>


打开DDMS,在divices对应的启动应用列表中选择腾讯微信对应包名(com.tencent.mm


<ignore_js_op>


如果列表太多,可以使用adb shell dumpsys activity top 查看当前android手机最前面的界面的pid和一些信息


<ignore_js_op>


然后在回到ddms顺着pid查找即可如果在这里看不到应用,是因为app没有在清单文件打开debugable=true,在这里你可以选择以下两种方式。

1 使用apktools反编译 修改清单文件 在装回去(微信没有加壳,就算加了估计大家也可以在网上找到对应退壳教程)

过程略

2 使用 BuildProp Enhancer ,装载xposed开启后,在其启动界面勾选和配置如下
<ignore_js_op>
 
记得重启手机


3 刷机修改android系统源码中的 ro.debugable=1和ro.secure=1(不推荐)正式开始使用traceView工具(我发现很多人居然不知道这个工具的名字= =但却使用过。)
<ignore_js_op>


鼠标点击Start Method Profiling(开始方法性能分析,对应上图红色箭头按钮)。
然后弹出一个界面,这个界面就是要问你要不要设置采样率(每隔多少毫秒进行一次方法堆栈记录(就是记录方法的使用过程时间信息)统计)


<ignore_js_op>


然后点击微信界面摇骰子

<ignore_js_op>


再次点击右上角按钮

<ignore_js_op>


完成后


<ignore_js_op>


我们这里点击了一个骰子对吧?那必然触发android点击事件回调。关于事件分发机制这里不做过多讲解 ,我们在界面最下方的filter 输入click





然后发现其Children有两个分别 是self ********performItemClick(Landroid/view/View;IJ)Z**





根据分析只能是第二个选项然后点击********performItemClick(Landroid/view/View;IJ)Z**








我们发现有两个函数 占用cpu时间,所以我们需要跳去两个函数的父函数进行静态分析。这里我们用JEB2.2进行反编译成java源文件导入Android Studio( 后续下文简称AS








如果提示 JAVA heap 之类的错误 修改jeb目录下 bin/jeb.ini





jeb3.0+请修改批处理文件xxx.bat然后导入AS





接下来再回过头来看看我们要跳到父函数()





按下CTRL+SHIFT+N 输入对应类文件即可






在这里可以查看类结构。我们这里选择前面分析父函数



 
可不看部分:方法前面有个synthetic注释 。内部类私有属性或者方法被外部类访问时会成成synthetic类或者synthetic方法。比如你会看access$001等。
如何证明? 反射机制就有这个相关api
Method method;
method.isSynthetic()

为什么圈出两个函数?因为我们前面tracView不是说显示两个函数占用Cpu时间之和为100%嘛(肯定有喷子说不是还有其他函数调用吗为什么没有显示占用CPU?答不在采样频率窗口期)。又因为后一个函数要使用前面一个的返回值,所以很用可能前面才是关键。
所以我们这里跳转到实现c函数处,在AS双击c函数只会跳转到接口或者抽象类((c) g.n(c.class)).getProvider().c(emojiInfo);
实现类可以在tracview看到了




如法炮制跳转到c函数实现




Traceview攻击点击这个函数继续向下分析







同理有三个子函数分别占用cpu时间比,那么在AS跳转到父函数 ****emoji.e.g.c*****


先分析第一个方法返回Cursor对象,这个对象大家在做撸码DAO层的时候应该不陌生把?很明显跟这个没关系,第二个方法同理Du.getCount(),那么我们最后肯定落在第三个方法上
第一个方法:  
Cursor Du = i.aEA().igx.Du(bi.getInt(emojiInfo.getContent(), 0))
第二个方法
Du.getCount()
第三个方法
int eF = bi.eF(Du.getCount() - 10);
点击进入eF函数




分析到这里发现一个断言和一个用于生成随机数的函数。我们假设是不是用这里随机函数生成塞子点数呢?我们继续返回****emoji.e.g.c*****这个函数回头看看





如何证明我们说的呢?

我们在eF函数加入两个函数,一个log,和一个打印方法堆栈函数
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
public static int eF(int i, int i2) {
 
       Thread.dumpStack();
 
       Assert.assertTrue(i > i2);
       int rel = new Random(System.currentTimeMillis()).nextInt((i - i2) + 1) + i2;
 
       Log.d("FMY", "eF() called with: i = [" + i + "], i2 = [" + i2 + "] ,rel =["+rel+"]" );
       return rel;
   }




对应smali:
[Asm] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
.method public static eF(II)I
    .registers 6
    .param p0, "i"    # I
    .param p1, "i2"    # I
 
    .prologue
 
    invoke-static {}, Ljava/lang/Thread;->dumpStack()V
 
 
    if-le p0, p1, :cond_4f
 
    const/4 v1, 0x1
 
    :goto_6
    invoke-static {v1}, Ljunit/framework/Assert;->assertTrue(Z)V
 
 
    new-instance v1, Ljava/util/Random;
 
    invoke-static {}, Ljava/lang/System;->currentTimeMillis()J
 
    move-result-wide v2
 
    invoke-direct {v1, v2, v3}, Ljava/util/Random;-><init>(J)V
 
    sub-int v2, p0, p1
 
    add-int/lit8 v2, v2, 0x1
 
    invoke-virtual {v1, v2}, Ljava/util/Random;->nextInt(I)I
 
    move-result v1
 
    add-int v0, v1, p1
 
 
    .local v0, "rel":I
    const-string v1, "FMY"
 
    new-instance v2, Ljava/lang/StringBuilder;
 
    invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V
 
    const-string v3, "eF() called with: i = ["
 
    invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
 
    move-result-object v2
 
    invoke-virtual {v2, p0}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
 
    move-result-object v2
 
    const-string v3, "], i2 = ["
 
    invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
 
    move-result-object v2
 
    invoke-virtual {v2, p1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
 
    move-result-object v2
 
    const-string v3, "] ,rel =["
 
    invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
 
    move-result-object v2
 
    invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
 
    move-result-object v2
 
    const-string v3, "]"
 
    invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
 
    move-result-object v2
 
    invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
 
    move-result-object v2
 
    invoke-static {v1, v2}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
 
 
    return v0
 
 
    .end local v0    # "rel":I
    :cond_4f
    const/4 v1, 0x0
 
    goto :goto_6
.end method


smali删除所有java2smali工具生成的行号 就的.line xxx


这里我用apkkiller修改反编译回去即可。然后在安装回手机点击 查看日志




在这里打log是为了大家后面方便改塞子和猜拳代码的观察和修改最后大家生活愉快。
另一种思路:全局搜索 Ramdom 关键字然后逐个分析,但是我不推荐,前提是你知道他们开发者使用了这个函数用来生成塞子关键代码修改后的微信APK请稍等。。。
<ignore_js_op>
原文地址:https://www.cnblogs.com/codex/p/13062859.html