Android微信逆向

您所在的位置:网站首页 朋友圈如何发纯文字动态图片 Android微信逆向

Android微信逆向

2024-05-24 08:19| 来源: 网络整理| 查看: 265

0x0 前言

最近一直在研究Windows逆向的东西,想着快要把Android给遗忘了。所以就想利用工作之余来研究Android相关的技术,来保持对Android热情。调用微信代码来发送朋友圈动态一直是自己想实现的东西,研究了一下,果然实现了,遂写下本文当作记录。本文主要分析发送纯文字朋友圈动态和发送图片朋友圈动态。

0x1 朋友圈动态类型分析

本文用到的工具如下:

PC 一台可以调试微信进程的Android手机 微信7.0.11 ddms(用于跟踪调用过程) uiautomatorviewer(用于定位控件id) jadx(用于对微信apk静态分析) frida(用于hook微信,获得相关信息,发布朋友圈)

在分析代码之前,首先要定位到与之相近的地方,我们首先想到的肯定是发朋友圈动态那个界面,如何查看发朋友圈动态的界面是哪个Activity呢?很简单,先在手机上打开发表朋友圈动态的界面

把手机连接电脑,打开USB调试,在PC的cmd窗口中执行以下命令:

adb shell dumpsys activity top

可以看到发朋友圈动态的Activity就是com.tencent.mm.plugin.sns.ui.SnsUploadUI

虽然找到了Activity,但还是不能高兴太早,想要通过Activity知道哪部分是发朋友圈的动态代码还是比较费力的。于是我们就想到从“发表”按钮入手,找出发表朋友圈动态的相关代码。点击“发表”按钮会发生什么?发表是一个动态的行为,我们可以通过跟踪点击“发表”按钮时的调用过程,来找到有用的信息。跟踪调用过程,可以使用ddms工具来完成。打开ddms,选中微信进程,在手机中打开发表朋友圈界面,然后在ddms中点击下图圈出的图标开始跟踪:

将朋友圈动态发出,再点一次上图圈出的图标停止跟踪。ddms会生成跟踪结果,对于跟踪结果,怎么找到按钮事件相关的信息呢,学过Android的朋友就会想到onClick方法,那我们就在ddms的搜索结果中搜索这个名称:

成功的定位到了onClick的位置,但是比起这条onClick结果,更加令人引人注目的是它的上一条结果,因为它包含了我们刚才找到的Activity的类名:

知道这个方法被调用,我们去看看com.tencent.mm.plugin.sns.ui.SnsUploadUI类里的OnMemuItemClick究竟是什么。

用jadx打开微信apk,定位到com.tencent.mm.plugin.sns.ui.SnsUploadUI类,在类中搜索onMemuItemClick,结果不多,看起来比较像的就是这个onMemuItemClick了:

在onMemuItemClick方法中看到了:

String unused2 = SnsUploadUI.this.desc = SnsUploadUI.this.tQN.getText().toString();

这行代码有什么特别的呢,在我看来,有两个特别的地方:

desc是描述(description)的英文单词的缩写 this.desc被赋予this.tQN.getText().toString()

我们发朋友圈动态时候,是要写动态的描述的,所以这个desc可能就是发朋友圈动态的描述,如果是描述,我们就可以根据这个描述,顺藤摸瓜找到发朋友圈动态的地方。而且this.desc的值又来自于this.tQN.getText().toString(),即this.tQN很有可能就是我们填写动态描述的文本框。我们来看看this.tQN赋值的地方,它在onCreate方法被赋值:

可以知道它的id是d41,那么d41是哪个控件?打开uiautomatorviewer,对发朋友圈界面截图分析,点击截图中的文本框,uiautomatorviewer右侧跳转到了相应的位置,果然,d41就是发动态时填写描述文本框的id

好了,现在知道this.desc就是发表朋友圈动态时的描述,跟上他应该就可以找到发朋友圈动态的地方。继续往onMemuItemClick方法下部分析,可以看到this.desc被传入了SnsUploadUI.this.tQO.a方法:

SnsUploadUI.this.tQO.a方法定义在接口com.tencent.mm.plugin.sns.ui.z中:

知道它定义在哪个接口并不能解决问题,毕竟接口没有实质性代码,要找还得找接口的的实现类,在com.tencent.mm.plugin.sns.ui.SnsUploadUI类中寻找this.tQO在哪里会被赋值。最终,我们在com.tencent.mm.plugin.sns.ui.SnsUploadUI类的ag方法中看到了许多给this.tQO赋值的地方:

由此,可见this.tQO被赋予什么值是根据this.tMY来决定的,this.tMY是一个int类型的数据,那我们hook com.tencent.mm.plugin.sns.ui.SnsUploadUI类的ag方法就可以知道this.tMY是什么值。在这里,我用frida来hook,frida的javascript部分代码如下:

var SnsUploadUI= Java.use('com.tencent.mm.plugin.sns.ui.SnsUploadUI'); var ag = SnsUploadUI.ag.overload("android.os.Bundle"); //get sns type ag.implementation=function(bundle){ var ret = ag.call(this,bundle); send("sns type = " + this.tMY.value); return ret; }

hook之后,每当我们在手机上打开发布朋友圈动态的界面,ag方法被调用,控制台就会输出相应的数字。经过我的测试,这个数字是发表朋友圈动态的类型。朋友圈类型和其对应类如下:

0 带图片的动态,对应:com.tencent.mm.plugin.sns.ui.ai 9 纯文字动态,对应:com.tencent.mm.plugin.sns.ui.ae

这些类都直接或间接的实现了上面讲到的com.tencent.mm.plugin.sns.ui.z接口。这样一来,就知道this.tQO会根据朋友圈的动态类型进行初始化,那么,上面的SnsUploadUI.this.tQO.a方法很有可能就是发朋友圈动态的方法。接下来,我们根据不同的朋友圈动态所对应的类来分别分析

0x2 文字动态分析

文字动态分析起来应该比图片动态来说简单一些,我们就先来分析它。上面讲到,这类动态对应类是com.tencent.mm.plugin.sns.ui.ae,这个类里我们主要看a方法,在看a方法之前,先看它传入什么参数,为了看清楚,这就要回看上文onMenuItemClick方法调用a方法的地方:

public final boolean onMenuItemClick(MenuItem menuItem) { String unused2 = SnsUploadUI.this.desc = SnsUploadUI.this.tQN.getText().toString(); int pasterLen = SnsUploadUI.this.tQN.getPasterLen(); int privated = SnsUploadUI.this.tKm.getPrivated(); int syncFlag2 = SnsUploadUI.this.tKm.getSyncFlag(); ...... PInt pInt = new PInt(); if (SnsUploadUI.this.tQO instanceof a) { Bundle bundle = new Bundle(); bundle.putInt("param_is_privated", privated); bundle.putString("param_description", SnsUploadUI.this.desc); bundle.putStringArrayList("param_with_list", new ArrayList(SnsUploadUI.this.uij.getAtList())); bundle.putInt("param_paste_len", pasterLen); try { bundle.putByteArray("param_localtion", SnsUploadUI.this.uik.getLocation().toByteArray()); } catch (IOException e2) { ab.printErrStackTrace("MicroMsg.SnsUploadUI", e2, "parse location error", new Object[0]); } bundle.putBoolean("param_is_black_group", SnsUploadUI.this.tQS); bundle.putStringArrayList("param_group_user", SnsUploadUI.this.tQR); bundle.putInt("param_contact_tag_count", SnsUploadUI.this.tOk); bundle.putInt("param_temp_user_count", SnsUploadUI.this.tOl); pInt.value = ((a) SnsUploadUI.this.tQO).getContentType(); z unused4 = SnsUploadUI.this.tQO; } else { SnsUploadUI.this.tQO.a(privated, syncFlag2, SnsUploadUI.this.tKm.getTwitterAccessToken(), SnsUploadUI.this.desc, SnsUploadUI.this.uij.getAtList(), SnsUploadUI.this.uik.getLocation(), (LinkedList) null, pasterLen, SnsUploadUI.this.tQS, SnsUploadUI.this.tQR, pInt, SnsUploadUI.this.tOj, SnsUploadUI.this.tOk, SnsUploadUI.this.tOl); } }

这就是a方法调用的地方,根据这段代码和编写hook a方法的代码来推出它的参数。hook代码如下:

var ae = Java.use('com.tencent.mm.plugin.sns.ui.ae'); var ae_a = ae.a.overload("int","int","org.b.d.i","java.lang.String","java.util.List","com.tencent.mm.protocal.protobuf.bdi","java.util.LinkedList","int","boolean","java.util.List","com.tencent.mm.pointers.PInt","java.lang.String","int","int"); ae_a.implementation = function(isPrivate,syncFlag2,twitterAccessToken,desc,atList,location,list1,pasterLen,bool1,list2,pint1,str1,num1,num2){ var ret = ae_a.call(this,isPrivate,syncFlag2,twitterAccessToken,desc,atList,location,list1,pasterLen,bool1,list2,pint1,str1,num1,num2); console.log("************Basic Info************"); console.log("isPrivate = " + isPrivate); console.log("syncFlag2 = " + syncFlag2); console.log("twitterAccessToken = " + twitterAccessToken); console.log("desc = " + "'" + desc + "'"); if(atList.size()>0){ for(var i=0;i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3