xposed微信长视频转发_Xposed微信之发送文件-程序员宅基地

技术标签: xposed微信长视频转发  

本帖最后由 randompath 于 2019-8-27 16:34 编辑

本文主要介绍通过静态分析微信发送文件的逻辑,并通过xposed实现文件自动发送。分析的微信版本为当前最新版(v7.0.6),分析工具jadx+AS。

分析过程

选择文件

点击文件,使用hierachyViewer查看选择文件界面是com.tencent.mm.pluginsdk.ui.tools.NewFileExplorerUI类。我们知道安卓Activity间发送数据主要是通过Intent,所以在NewFileExplorerUI中查找new Intent,找到以下代码

newFileExplorerUI.wOI.a(new com.tencent.mm.ui.widget.b.c.a.b() {

public final void bEL() {

AppMethodBeat.i(28179);

Intent intent = new Intent();

intent.setClass(NewFileExplorerUI.this.getContext(), NewFileExplorerUI.class);

intent.putExtra("explorer_mode", 1);

intent.putStringArrayListExtra("selected_file_lst", NewFileExplorerUI.this.wOF.dxa());

intent.putStringArrayListExtra("key_select_video_list", NewFileExplorerUI.this.wOF.dxc());

intent.putStringArrayListExtra("CropImage_OutputPath_List", NewFileExplorerUI.this.wOF.dxb());

intent.putExtra("GalleryUI_ToUser", NewFileExplorerUI.this.toUserName);

NewFileExplorerUI.this.startActivityForResult(intent, 0);

AppMethodBeat.o(28179);

}

});

newFileExplorerUI.wOI.Nc(R.string.u5).a(new com.tencent.mm.pluginsdk.ui.applet.q.a() {

public final void a(boolean z, String str, int i) {

AppMethodBeat.i(28180);

NewFileExplorerUI.this.hideVKB();

if (z) {

Intent intent = new Intent();

intent.putStringArrayListExtra("selected_file_lst", NewFileExplorerUI.this.wOF.dxa());

intent.putStringArrayListExtra("key_select_video_list", NewFileExplorerUI.this.wOF.dxc());

intent.putStringArrayListExtra("CropImage_OutputPath_List", NewFileExplorerUI.this.wOF.dxb());

intent.putExtra("GalleryUI_ToUser", NewFileExplorerUI.this.toUserName);

intent.putExtra("with_text_content", str);

NewFileExplorerUI.this.setResult(-1, intent);

NewFileExplorerUI.this.finish();

}

AppMethodBeat.o(28180);

}

}).gQP.show();

猜测这两个匿名内部类至少有一个是发送button的回调,而且其回调方法的逻辑很相似。发送时如果选择的文件中有图片,会把文件与图片分开发送,所以我们猜测

selected_file_lst是选择的待上传文件路径

CropImage_OutputPath_List是选择的图片路径

with_text_content 是发送文件时捎带的留言

发送文件

在源码中搜索selected_file_lst关键字, 定位到类com/tencent/mm/ui/chatting/p。

在文件最后找到发送代码

static /* synthetic */ void a(p pVar, com.tencent.mm.ui.chatting.d.a aVar, int i, Intent intent) {

AppMethodBeat.i(156138);

if (i == -1 && intent != null) {

int om;

String str;

((aa) aVar.aU(aa.class)).g(217, i, intent);

ArrayList stringArrayListExtra = intent.getStringArrayListExtra("selected_file_lst");

if (aVar.dRl()) {

om = com.tencent.mm.model.n.om(pVar.AiD);

} else {

om = 0;

}

Iterator it = stringArrayListExtra.iterator();

while (it.hasNext()) {

// 准备文件对象

String str2 = (String) it.next();

WXFileObject wXFileObject = new WXFileObject();

// 文件路径

wXFileObject.setFilePath(str2);

WXMediaMessage wXMediaMessage = new WXMediaMessage();

wXMediaMessage.mediaObject = wXFileObject;

File file = new File(str2);

// 文件名称

wXMediaMessage.title = file.getName();

// 文件大小

wXMediaMessage.description = bo.hw(file.length());

// 发送文件

com.tencent.mm.pluginsdk.model.app.l.a(wXMediaMessage, "", "", pVar.AiD, 4, null);

int lastIndexOf = file.getName().lastIndexOf(".");

str = "";

if (lastIndexOf >= 0 && lastIndexOf < file.getName().length() - 1) {

str = file.getName().substring(lastIndexOf + 1);

}

h hVar = h.rdc;

Object[] objArr = new Object[5];

objArr[0] = Long.valueOf(file.length());

objArr[1] = Integer.valueOf(0);

objArr[2] = Integer.valueOf(aVar.dRl() ? 1 : 0);

objArr[3] = Integer.valueOf(om);

objArr[4] = str;

hVar.e(14986, objArr);

}

str = intent.getStringExtra("with_text_content");

if (!bo.isNullOrNil(str)) {

com.tencent.mm.plugin.messenger.a.g.bWU().ft(str, pVar.AiD);

}

}

AppMethodBeat.o(156138);

}

在准备文件对象时只有bo.hw(file.length())的含义不明,跟进去发现这个方法将文件大小转为字符串,简单翻译后代码如下

private String getFileDesc(long filesize) {

long j = filesize;

if ((j >> 30) > 0) {

// GB

return (((double) Math.round((((double) j) * 10.0d) / 1.073741824E9d)) / 10.0d) + " GB";

}

if ((j >> 20) > 0) {

// MB

return (((double) Math.round((((double) j) * 10.0d) / 1048576.0d)) / 10.0d) + " MB";

}

if ((j >> 9) <= 0) {

return j + " B";

}

return (((double) Math.round((((double) j) * 10.0d) / 1024.0d)) / 10.0d) + " KB";

}

com.tencent.mm.pluginsdk.model.app.l.a(wXMediaMessage, "", "", pVar.AiD, 4, null); 就是发送文件的调用。发送文件需要两个必要参数:文件对象与接收者的微信id,所以猜测pVar.AiD就是接收方的微信id,对于发送对象可以通过反射构建。分析到这里就可以了,接下来试着编写发送文件的代码

public class AttachSendingHook {

Class IMediaObject;

Class mediaMsgSenderClz, fileObjectClz, mediaMessageClz;

public AttachSendingHook(XC_LoadPackage.LoadPackageParam lpparam) {

ClassLoader cl = lpparam.classLoader;

IMediaObject = XposedHelpers.findClass("com.tencent.mm.opensdk.modelmsg.WXMediaMessage$IMediaObject", cl);

fileObjectClz = XposedHelpers.findClass("com.tencent.mm.opensdk.modelmsg.WXFileObject", cl);

mediaMessageClz = XposedHelpers.findClass("com.tencent.mm.opensdk.modelmsg.WXMediaMessage", cl);

mediaMsgSenderClz = XposedHelpers.findClass("com.tencent.mm.pluginsdk.model.app.l", cl);

}

public void sendAttach(String recvr, String filePath) {

File file = new File(filePath);

if (file.exists() && file.isFile()) {

debug("向 %s 发送文件: %s", recvr, filePath);

Object fileObject = XposedHelpers.newInstance(fileObjectClz);

XposedHelpers.callMethod(fileObject, "setFilePath", filePath);

Object mediaObject = XposedHelpers.newInstance(mediaMessageClz);

XposedHelpers.setObjectField(mediaObject, "mediaObject", IMediaObject.cast(fileObject));

XposedHelpers.setObjectField(mediaObject, "title", file.getName());

XposedHelpers.setObjectField(mediaObject, "description", getFileDesc(file.length()));

// com.tencent.mm.pluginsdk.model.app.l.a(wXMediaMessage, "", "", pVar.xVs, 4, null);

XposedHelpers.callStaticMethod(mediaMsgSenderClz, "a", mediaObject, "", "", recvr, 4, null);

} else {

error("文件不存在,无法发送 %s", filePath);

}

}

private String getFileDesc(long filesize) {

long j = filesize;

if ((j >> 30) > 0) {

// GB

return (((double) Math.round((((double) j) * 10.0d) / 1.073741824E9d)) / 10.0d) + " GB";

}

if ((j >> 20) > 0) {

// MB

return (((double) Math.round((((double) j) * 10.0d) / 1048576.0d)) / 10.0d) + " MB";

}

if ((j >> 9) <= 0) {

return j + " B";

}

return (((double) Math.round((((double) j) * 10.0d) / 1024.0d)) / 10.0d) + " KB";

}

}

测试发送成功,效果如下

对于发送文件的分析思路大体就是这样,而发送图片与短视频的分析过程与此类似,这里就不再赘述,有兴趣的自己研究下吧。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39870092/article/details/111541647

智能推荐

JSON百科全书:学习JSON看这一篇就够了-程序员宅基地

文章浏览阅读2.8k次,点赞10次,收藏51次。JSON 对象包含两个方法:用于解析 JavaScript Object Notation(JSON)的 parse() 方法,以及将对象/值转换为 JSON 字符串的 stringify() 方法。除了这两个方法,JSON 这个对象本身并没有其他作用,也不能被调用或者作为构造函数调用。_json

【电子基础】总结·嵌入式硬件基础_哈佛j80c电源板-程序员宅基地

文章浏览阅读1.8k次,点赞2次,收藏9次。嵌入式系统硬件基础By 成鹏致远第一章 常用硬件——>嵌入式系统常用的硬件器件,主要包括分立器件、光电半导体、逻辑IC、模拟IC以及存储器共五大类——>分立器件主要有:二极管、三极管、电阻、电容、电感以及场效应管等——>二极管的主要特性是单向导电性——>二极管按其用途可分为:整流二极管、稳压二极管、开关二极管、发光二极管等——>整流二级管是一种将交流电转变为直流电的半导体器件,主要用于各种低频整流_哈佛j80c电源板

组件三大属性,state,props,refs_组件自带的属性-程序员宅基地

文章浏览阅读673次。一,组件实例三大属性(1)state查看状态:在写好的组件实例上有一个属性,state,就代表这个组件的状态。接下来我们写一个有状态的组件:<body> <div id="test"></div> <script type="text/babel"> // 创建组件 class Component extends React.Component { // 初始化,调_组件自带的属性

yii2框架-yii2的组件和服务定位器(四)_yii2 unknown component id: db-程序员宅基地

文章浏览阅读4.4k次,点赞3次,收藏4次。上一节主要是分析了yii2的自动加载函数,下面在分析一下yii2的核心组件与服务定位器。其实yii2的核心组件主要有以下://日志组件'log' => ['class' => 'yii\log\Dispatcher'],//视图组件,这个组件代表视图文件中的$this'view' => ['class' => 'yii\web\View'],//格式化组件,将一些输出按照一_yii2 unknown component id: db

SystemVerilog总结_systemverilog语法-程序员宅基地

文章浏览阅读6.9k次,点赞24次,收藏315次。基于SV绿皮书的systemverilog总结_systemverilog语法

2024 EasyRecovery三分钟帮你恢复 电脑硬盘格式化-程序员宅基地

文章浏览阅读1.5k次,点赞43次,收藏13次。在格式化过程中,硬盘上的所有数据并没有被擦除,而是被标记为可覆盖状态,这意味着只要数据没有被新数据完全覆盖,仍然有可能各种技术手段对其进行恢复性操作。需要注意的是,在对硬盘进行恢复性操作之前,我们需要让硬盘保持刚刚格式化的数据状态,不要再做任何删除或者存储的动作,以免对原数据产生覆盖。如果遇到电脑硬盘被格式化后,第一步要做的是暂停对该硬盘的使用,其次是搜索并下载一款专业性强且口碑不错的数据恢复软件自主恢复数据。4.等待软件扫描结束,从扫描结果中选择需要被恢复的数据后单击“恢复”即可找回丢失的数据。_easyrecovery

随便推点

gflags的交叉编译_manually-specified variables were not used by the -程序员宅基地

文章浏览阅读2.6k次,点赞2次,收藏9次。gflags版本:gflags 2.2.2目录编译动态库的编译cmakelbw@DESKTOP-LBW22:/mnt/d/ref/gflags-master/_build$ cmake .. -DGFLAGS_NAMESPACE=gflags -DCMAKE_CXX_FLAGS=-fPIC -DBUILD_SHARED_LIBS=ON -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-li._manually-specified variables were not used by the project:

SpringBoot mysql 时区问题总结_servertimezone=gmt+8-程序员宅基地

文章浏览阅读1.6k次。寻找原因后端开发中经常mysql8.x的jdbc升级了,增加了时区(serverTimezone)属性,并且不允许为空。_servertimezone=gmt+8

5000字超干货,新中国成立70年人口流动迁移的特征与趋势可视化!-程序员宅基地

文章浏览阅读1.2k次。‍‍来源:城市数据派转自:上海数据分析‍‍大家好,我是小z今天给大家分享一篇新中国成立70年人口流动迁移的文章1 改革开放前的人口流动迁移特征改革开放前,我国人口迁移规模较改革开放后而言,..._国内人口迁移数据挖掘与可视化

快手app抓包方案常见的初探_快手抓包无网络-程序员宅基地

文章浏览阅读9k次,点赞3次,收藏14次。作为一个快手资深用户,每天使用快手app看老铁直播,出于兴趣,曾经对快手接口进行过简单研究,年前写过一个小玩意发送弹幕发送跟老铁互喷!前两天想看下是否好使,发现快手app新版本限制抓包了,那就先研究一下快手app抓包吧!经过一下午的研究,发现可以通过一下三种方式,对app就行http抓包!使用的工具: charles, root过的安卓手机一台 不同版本的快手apk1,降低apk版本[快手版本6.8]进过测试,发现降低版本可以进行抓包,测试版本6.8.0抓包通过!但缺点也很明显,apk过于老旧,_快手抓包无网络

万能数据恢复大师官方版_数据恢复大师新版-程序员宅基地

文章浏览阅读1.2k次。万能数据恢复大师是非常强大的数据恢复软件。它能够恢复误删除、误格式化、U盘\手机储存卡、分区丢失后的数据,及时拯救您宝贵的数据。_数据恢复大师新版