吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 10067|回复: 31
收起左侧

[Android 原创] Xposed微信之发送文件

  [复制链接]
randompath 发表于 2019-8-27 16:29
本帖最后由 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";

    }
}

测试发送成功,效果如下
自动发送文件效果

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

免费评分

参与人数 8威望 +1 吾爱币 +16 热心值 +8 收起 理由
IMRE + 1 + 1 用心讨论,共获提升!
qtfreet00 + 1 + 9 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
萌萌哒胖次 + 1 + 1 我很赞同!
linwenhui + 1 + 1 谢谢@Thanks!
微若清风 + 1 + 1 谢谢@Thanks!
小小简 + 1 + 1 谢谢@Thanks!
陈世界 + 1 + 1 我很赞同!
sinceo + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

我根号四你 发表于 2020-3-9 18:47
楼主你好,你能把发送图片的部分补上嘛?我根据你的思路 发现 WXFileObject 之外 还有一个 WXImageObject 对象,有一个 setImagePath 方法,我把 WXFileObject 修改为 WXImageObject 测试后,发现无法把图片发出去,显示 感叹号。还有我 hook  
[Java] 纯文本查看 复制代码
com.tencent.mm.pluginsdk.model.app.l.a
  a 方法 在发送图片的时候 都没有调用,只有在发送文件的时候才调用了。思路到这里就断了。感谢&#128591;,希望楼主回复我。
 楼主| randompath 发表于 2019-8-29 13:29
快没时间了 发表于 2019-8-29 10:04
楼主能弄过发送语音吗,还有楼主有研究过修过Xposed包名吗

发语音没做过,不过我可以跟你说下思路,你可以从录音的相关api入手,在录音结束后肯定有发送音频文件的接口,直接调这个接口就行了。微信的语音文件是slk,如果要发送mp3需要先编码。简单的改包名只要改manifest文件后重打包就行了,但如果原包有签名检测就麻烦了。
XiaoYuGan0103 发表于 2019-8-27 17:31
lizhipei78 发表于 2019-8-27 17:56
微信不是直接可以发文件的吗?
丶那年如此年少o 发表于 2019-8-27 18:06
楼主,视频也可以调用这个接口发吗?
BlueTears_ 发表于 2019-8-27 18:32
感谢楼主分享
airborne 发表于 2019-8-27 19:04
感谢楼主分享,抽空好好研究一下
qwe124040 发表于 2019-8-27 19:16
学习,。感谢分享
icehappin 发表于 2019-8-27 20:51
感谢楼主分享,抽空好好研究
dxlulu 发表于 2019-8-27 20:53
学习,。感谢分享
简讯丶 发表于 2019-8-27 23:12
好厉害的样子
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 18:40

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表