转自https://www.freebuf.com/articles/web/156944.html

*本文作者:Manwu91,本文属 FreeBuf 原创奖励计划,未经许可禁止转载

之前用web微信协议做了个自动应答机器人但跑了不长时间就被封了于是转战安卓端。如果自己分析协议难度跟工作量就太大所以决定使用xposed。本文将通过一个完整的实例取得会话列表里的全部联系人讲解如何给微信下钩子。

思路

从开发的角度猜想微信的会话列表会保存在sqlite中在UI加载的时候从sqlite中读取出来并用ListView显示在Activity中。所以这里有两个点可以下钩子

  1. 从sqlite加载会话列表的相关方法。
  2. 通过ListView的adapter取出相关数据。

简单起见笔者决定使用第2个方案。本文使用的是wechat v6.5.8。

解包

微信没有加壳所以用apktool直接解包得到相关资源。并用dex2jar得到相关jar包方便跟源码。

定位过程

在会话列表中长按某个联系人会弹出ContextMenu。

我们就从这个”标为已读“入手在strings.xml中搜索得到

<string name="bpd">标为已读</string>

接着在public.xml中搜索bpd得到

 <public type="string" name="bpd" id="0x7f080d08" />

这个16进制id值就是该字符串在smali代码中的引用值。我们在smali中搜索0x7f080d08得该字符串引用id在代码中的变量名

./smali/com/tencent/mm//R$m.smali:2610:.field public static final eHR:I = 0x7f080d08

这里简单解释下。在开发安卓应用时在strings.xml中创建一个字符串(假设取名为dummy值为hello)在layout或其他xml中可以通过@string/dummy引用到hello但在代码中只能通过Activity#getString(R.string.dummy)取得该字符串。如果没有混淆string是R的inner class所以编译后得到R$string.class但是微信混淆了代码所以string与dummy变量名都被替换了在smali中的引用语法为

Lcom/tencent/mm/R$m;->eHR:I

等价于java语法R.m.eHR。使用grep -Hrn 'R$m;->eHR' ./smali/com/tencent/mm/搜索找到有两个类引用了这个字符串

挨个查看发现类com.tencent.mm.ui.conversation.f实现了View.OnCreateContextMenuListener, AdapterView.OnItemLongClickListener所以我们可以猜测会话列表的Acitvity大致结构

public class ConversationAct extends Activity{private ListView contactsView;public void onCreate(Bundle savedInstanceState) {//初始化UIcontactsView = (ListView)findViewById(R.id.listView);contactsView.setAdapter(loadSqliteContacts2Adapter());f listener = new f(...);contactsView.setOnCreateContextMenuListener(listener); // 设置上下文回调contectsView.setOnItemLongClickListener(listener); // 设置长按回调}
}

f的构造函数

public f(g paramg, ListView paramListView, Activity paramActivity, int[] paramArrayOfInt)
{
...
}

发现入参里有ListView。到这里只要hook这个构造函数拿到paramListView的引用就可以得到它的adapter了。为了分析adapter内的数据继续跟。

对创建上下文菜单的逻辑分析

grep -Hrn 'ui/conversation/f;-><init>' smali/com/tencent/mm/搜索找到

smali/com/tencent/mm//ui/conversation/j.smali:1193:    invoke-direct {v1, v2, v3, v4, v5}, Lcom/tencent/mm/ui/conversation/f;-><init>(Lcom/tencent/mm/ui/conversation/g;Landroid/widget/ListView;Landroid/app/Activity;[I)V

成功定位到会话列表的UI组件com.tencent.mm.ui.conversation.j。这个j是一个Fragment里面ListView的初始化

this.uWH.setAdapter(this.uXk);
this.uWH.setOnItemClickListener(new e(this.uXk, this.uWH, aG()));
this.uWH.setOnItemLongClickListener(new f(this.uXk, this.uWH, aG(), this.uZC));

发现f的构造函数第一个参数就是adapter。这里没有设置OnCreateContextMenuListener于是跟进OnItemLongClickListener发现

new h(this.activity).a(paramView, paramInt, paramLong, this, this.mWS, this.uYc[0], this.uYc[1]);

这条语句内部直接调用onCreateContextMenu方法创建上下文菜单。通过下面的分析发现之所以这样做是为了在onItemLongClick时取得长按item对应的联系人wxid之后在上下文菜单中实现对联系人的相关操作。

动态调试

在f的构造函数中发现将ListView的apater保存到了类的uXk变量中。所以在onItemLongClick回调中下断点观察这个变量就可以得到当前会话列表的内容。用idea载入smali在com.tencent.mm.ui.conversation.f.smali的553行(或onItemLongClick方法的入口)下断点。

adb shell am start -D -n com.tencent.mm/com.tencent.mm.ui.LauncherUI开启调试模式关于动态调试的详细步骤参见smali动态调试。在微信启动后长按会话列表中的一项触发回调代码在断点位置成功挂起。监视p0寄存器inspect uXk实例变量得到会话的wxid与昵称。

这个hashmap的key保存了会话的wxidvalue中的nickName是会话的用户昵称。用同样的方法调试onCreateContextMenu会发现代码

w localw = com.tencent.mm.model.c.wj().Oy(this.fVd);

作用是根据wxid取得用户的全部信息(地区、性别等)。但我这里只需要取昵称与wxid就行了如果想根据wxid查询联系人可以用到这个。

编码下钩子

经过上面的分析我们需要做的有

  1. hook com.tencent.mm.ui.conversation.f的构造函数取到adapter的引用
  2. 执行相关操作使被hook的代码执行(这里是打开微信拉起ui)。

示例代码如下

public class XMain implements IXposedHookLoadPackage{public static final String TAG="WxHook ";String targetPackage = "com.tencent.mm";static Object adapterObj;@Overridepublic void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {if(lpparam.packageName.equals(targetPackage)){XposedBridge.log(TAG + ">>process: "+lpparam.processName);if(lpparam.processName.equals(targetPackage)){XposedBridge.log(TAG+">>开始hook微信主进程");// get conversation demoXposedHelpers.findAndHookConstructor("com.tencent.mm.ui.conversation.f",lpparam.classLoader,XposedHelpers.findClass("com.tencent.mm.ui.conversation.g", lpparam.classLoader),ListView.class,Activity.class,int[].class,new XC_MethodHook() {@Overrideprotected void beforeHookedMethod(MethodHookParam param) throws Throwable {// 创建listener时拿到adapter引用adapterObj = param.args[0];XposedBridge.log("成功取得adapter引用: " + adapterObj.getClass().getName());}});XposedHelpers.findAndHookMethod("com.tencent.mm.ui.conversation.j",lpparam.classLoader,"onResume",new XC_MethodHook() {@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {// 在UI渲染后通过反射取得adapter内容。HashMap<String, Object> map = (HashMap)XposedHelpers.getObjectField(adapterObj, "usf");if(map==null || map.isEmpty()){XposedBridge.log("Something went wrong!!!");}Stream.of(map).map(entry -> String.format("wxid: %s, nickname: %s",entry.getKey(),XposedHelpers.getObjectField(entry.getValue(), "nickName"))).forEach(XposedBridge::log);}});}}}
}

安装并激活插件后打开微信在渲染结束后可以看到已经成功拿到了会话列表

这里有个小问题就是在第一次渲染时没有拿到数据。重新打开界面就可以了。其实跟到这里离sqlite层面的查询已经很近了如果拿到sqlite层面的相关方法就不用关心ui是否渲染了。给大家提个线索:adapter内的hashmapuXk.usf内的数据并不是一下就全部加载的而是通过重写了adapter的getView方法实时加载的。有兴趣的可以试下。

下钩子的过程总共就两步:

1. 找到要在哪下钩子;

2. 写钩子。

通过hook可以实现消息收发、朋友圈转发、自动加人等批量操作。市面上也有很多通过xposed实现的“微信营销神器”。其实这些工具没什么神秘的代码拿出来也就是几个钩子。真正有技术含量的是第一步正如斯坦敏茨说的“用粉笔画一条线1美金。知道在那里画线9999美金。”

思路分享 | 看我如何给微信下钩子[转]相关推荐

  1. 安卓Hook微信-计步器、万能骰子、自动回复、反撤回、抢红包思路分享

    此篇博客仅实现的思路分享,不提供最终成品 目录 学完你能收获什么 要求 前置条件 运行环境 成果 最终效果 开发耗时 最终Hook的类 实现 需知 1.选择root或VA 2.反编译代码工具 3.YA ...

  2. 单独的html怎么实现微信分享,html静态页面实现微信分享思路

    微信分享网页的时候,希望分享出来的链接是标题+描述+缩略图,微信开发代码示例里已提供了方法,但只适用于动态页面.由于dedecms是生成了静态文件,其实我想使用ajax获取jssdk参数也能也能实现微 ...

  3. 前端wx-jssdk的使用及企微和微信下分享等功能自定义处理

    前端wx-jssdk的使用及企微和微信下分享等功能自定义处理 一.前端wx-jssdk的使用 wx-jssdk使用需要微信公众平台内进行设置(进入公众号设置的"功能设置"里填写&q ...

  4. 《渗透测试》一次“上车”不给车费的思路分享

    一次"上车"不给车费的思路分享 0x01 师傅们都知道,Q群加的多.好多东西就会越多. 东西多要来干什么?当然是本着分享的原则 但是,软件就不分享了.在这里分享一下思路. 下载AP ...

  5. (第三方平台)开发相关,解除80端口占用,微信公众号分享jssdk实现,微信开放平台登录接口接入,2022微信分享接入本地调试,微信分享定制

    一.开发相关 1.平台地址 微信开放平台 QQ互联平台SDK 2.文章收集 来自CSDN兄台的QQ登录使用的教程 微信网站应用开发的详细流程和引导 VueJs单页应用实现微信网页授权及微信分享功能 [ ...

  6. 【知识分享】如何把一个微信公众号运营到可以养活自己?

    做自媒体两年,微信公众号两万粉,知乎三万三,视频号初步试水六百多粉丝.在认识许多厉害博主的同时,也积累起五六千的私域流量,拥有了一些社交资本. 一路走过来可以说是全靠自己摸索,过程艰难,特别是初期摸爬 ...

  7. 微信是如何飞起来的(延伸阅读:性,微信下的机会?一个超级用户的自白:移动社交那点事类kik手机通信录互动应用前景探讨)

    与腾讯的发展史一样,微信在骂声中飞快成长--虽然既非原创,又不具备首发优势,但仅仅一年,微信竟远远超越对手们,拥有了5000万用户. 它的风行,既依托于腾讯源源不断的弹药支援,又源自其持续改进的细节拿 ...

  8. uni-app分享小程序卡片给微信好友

    一.前言 最近有这样一个需求,使用APP将一个小程序的页面分享给微信好友,起初一脸问号,APP分享小程序的页面,两个不相干的东西怎么关联分享?于是乎抱着实现不了的心态在网上看帖子,最后终于在uni-a ...

  9. 第一届华数杯A题完整思路分享

    A题完整思路分享 第一问: 要想问题做的好,美图肯定少不了.这道题,建模时不但要用数学公式把模型说清楚,还要一些图来帮助别人理解,让别人一眼就看懂你写的东西,话不多说,我们先放一张类似下面的图,记得说 ...

最新文章

  1. 使用多尺度空间注意力的语义分割方法
  2. 计算机科学与应用论文的素材,计算机专业学位论文范文最新资料汇集
  3. sonar 6.2 安装配置properties文件
  4. Docker中数据管理
  5. netstat查看linux运行的端口,查看哪些端口被打开 netstat -anp
  6. ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘192.168.1.165‘ (113)
  7. 优达学城深度学习之一——Anaconda
  8. docker从C盘迁移到E盘
  9. 用C#来播放.wav格式的音频文件
  10. mysql 约束 和索引_Mysql中索引和约束的示例语句
  11. 深度学习经典论文翻译合集Deep Learning Papers Translation(CV)
  12. ubuntu18.04播放mp4提示需要安装MPEG-4 AAC解码器和H.264解码器的解决办法
  13. 数据字典中的数据类型与ABAP中的中数据类型对应关系
  14. Navicat安装教程(超详细)
  15. 工程项目管理工作流程图大全(打包带走)
  16. java getbytes 乱码_深入解析java String中getBytes()的编码问题
  17. 为什么有的程序员干不到30岁就转行了?
  18. iOS高德地图去logo
  19. 苹果设计可变色Apple Watch表带,智能穿戴玩法多
  20. vscode常用插件-Auto Close Tag

热门文章

  1. Android移动应用开发教程笔记①
  2. 宿舍管理系统 住宿管理系统 寝室管理系统源码 java项目jsp web项目
  3. 百度竞价点击器_【竞价推广100问】百度竞价点击怎么收费,有计算公式吗?
  4. 蓝桥杯竞赛指南及经验分享
  5. 资策会发布RFID感测式衣架、虚拟试衣机,打造智慧试衣间
  6. 共推人工智能创新发展 校企合作协同育人
  7. 连续合数猜想(格林姆猜想)-突破性进展
  8. 微型计算机音乐发生器,音乐发生器论文.doc
  9. 【毕业设计】基于stm32的智能电子秤系统 - 物联网 嵌入式 单片机
  10. cnzz统计检测浏览器原理(跨浏览器开发实用源码)