PC 端微信技术研究之保存聊天语言

本文作者:anhkgg(信安之路病毒分析小组成员 & 个人公众号:汉客儿

虽然一直知道 CE,也用过一段时间,但一直用不好,可能太笨。

最近又学习了某位大佬用 CE 的方法,大佬的一句话有点醍醐灌顶,然后有了新的感觉,然后开始尝试实践这篇文章。

自己总结一下 CE 用法的核心思路:通过各种技巧搜索找到内存中关键数据,然后结合动态调试找到操作数据的函数。

准备工具:

Cheat Engine,OllyDbg,IDA。

了解 CE

官网:

https://www.cheatengine.org/

看看来自百科的介绍:

Cheat Engine 是一款内存修改编辑工具 ,它允许你修改你的游戏或软件内存数据,以得到一些其他功能。它包括16进制编辑,反汇编程序,内存查找工具。与同类修改工具相比,它具有强大的反汇编功能,且自身附带了外挂制作工具,可以用它直接生成外挂。

在我看来,CE 做的最好的就是各种策略的内存搜索能力。

1、支持准确数据(整数、字符串、十六进制、浮点数、字节数组等等)搜索,针对目标数据明确效果显著,比如金币数。

2、支持数据范围的搜索,比如大于某个值,小于某个值等等。比如想找到没有显示数值的血量数据。

3、支持多组数据同时搜索,针对数据结构复杂的情况

4、支持搜索结果的多次过滤(图中框选的Next Scan),最终找到目标数据。比如血量未知时,通过加血、减血多次搜索最终找到血量地址。

说到底 CE 内存搜索的能力就是通过各种策略帮助你找到游戏中需要修改的数据(比如血量、分数、金币等等),然后通过内存修改能力(直接改血量)打破游戏平衡,外挂制作工具生成外挂,助你超神!

更多CE的高级应用可以访问:

https://blog.csdn.net/cgs___/article/details/77799091

https://blog.csdn.net/zhaobisheng1/article/details/79259460

分析

进入正题,本文是要拿到微信聊天的语音消息,然后 dump 保存下来。

要按以前我的思路,会通过网络通信找到接受消息的函数,然后找到语音数据,看起来很简单,但是有点难。

因为函数真的很多,网络消息也会受到很多干扰。

现在用 CE 了,应该怎么办呢?

找到关键数据

关键数据肯定是语音消息了,但是怎么搜索呢,肯定搜语音内容不现实,所以转了弯,先看看文字消息,找到接受文字消息处理函数之后,猜测语音处理函数会相同或者在不同分支

接着,如何搜索文字消息呢?已经收到的显示在聊天窗口的内容当然可以通过CE找到,但是没用啊,它和接受文字消息处理函数已经没关系了,流程已经处理完成了。

那么在测试中肯定知道发送的消息内容,通过CE来搜索可以吗?

额,我觉得不行,还没收到消息呢,内存中也没有这个文字消息,搜索不到(如果可以,请大佬指点一下)。

能想到的是,在接受到消息某一点通过调试器断下来,然后 CE 搜索,这样可以,但是这个断点找不到阿,放弃。

那怎么办呢?

看到左侧聊天列表中显示的最新一条消息,有了新的思路。

每次收到新消息后,都会在列表中显示最新消息内容(图中绿框指示位置、注意是 unicode 字符)。

那么,先用 CE(First Scan)搜索当前搜到的消息内容,找到可能的内存地址。多次接受不同消息后,Next Scan按钮搜索每次新的消息内容,最终确定聊天列表中显示的最新消息内容的内存地址。

多次刷选之后,留下两个地址,通过 CE 修改内容,在界面中查看是否改变,最终确认第二个地址就是我们的目标,暂把该地址记录为 MsgAddr。

分析消息接收函数

关键数据地址已经找到,下面的工作复杂也不复杂,就看微信是如何实现的了。

猜测微信实现消息显示的流程是这样的:

1、recv 收到消息,组装完整包后,分发给消息处理函数

2、根据 wxid 找到要显示消息的列表项,如果不在已聊天消息列表,就新建一个项

3、在列表中显示消息,如果是表情显示[文字],语音显示为[语音],消息插入 wxid 对应消息队列,或者存入数据库

步骤 3 中肯定要写前面找到的 MsgAddr 内存,把最新消息显示到界面中,这个流程肯定在消息处理函数内部。

So,通过 OD 对 MsgAddr 下内存写入断点,回溯堆栈就可以找到消息处理函数。

具体操作如下:

OD 挂载 Wechat.exe 进程后,在左下角内存窗口处 Ctrl+G,输入找到的 MsgAddr(11A11F34)回车,定位到该数据,然后再 HEX 数据处,右键弹出菜单,选择断点->内存写入:

断点设置完成后,测试发送文字消息,OD 断住,代码窗口显示的就是修改 MsgAddr 的代码位置,如上图 10CE412C 处。

Alt+K 查看当前堆栈:

调用堆栈

看到这个调用栈是不是感觉好少,分析起来肯定简单。但,其实是 OD 显示的并不全,此时真的很想用 windbg。

在 OD 的右下角堆栈窗口,可以看到当前调用栈的参数和预览数据。F8 单步(或者 Alt+F8 执行到返回)逐步的回溯每层堆栈。关注 MsgAddr 的数据是如何生成的,也就是找到数据来源,然后找到消息处理函数。

跟踪过程不赘述(需要熟悉汇编知识),直到看到的最顶层的 WeChatWi.10206460 处,发现是界面操作函数把收到的消息内容显示到聊天列表处的一个功能函数。

那这里不是可以拿到消息了吗,是的,普通文字消息已经可以拿到,但是语音内容不行。

通过观察内存窗口的数据,整理 WeChatWi.10206460 处的关于消息参数的大致结构。

//聊天列表框信息

struct chat_list_msg {

DWORD unk;//

wstring wxid;//

//wchar_t* wxid;//4

//int len;//8

//int maxlen;//c

DWORD unk1;//10

DWORD unk2;//14

wstring name;

//wchar_t* name;//18微信名

//int len;//1c

//int maxlen;//20

…

wstring msg; //

//wchar_t* msg;//3c

//int len;//

//int maxlen;

}

wstring msg 字段就是文字消息内容,而语音消息则是预览中看到的[语音]两字,并没有实际能够听到的语音数据,所以还得继续往前找。

继续往上回溯了 3 层左右,进入了 102DDC50,找到了语音消息的新信息:

struct msg_xx

{

char unk[0x40];//

wstring wxid1;//40

wstring wxid2;//4c

char unk1[0x10];//58

wstring msg;//68 

char unk2[0x10];//74

;//84

}

在 wstring msg 处就是普通文字消息内容,而语音消息并不是我想象的就是直接语音的数据,而是...如下:

<msg><voicemsg endflag="1" cancelflag="0" forwardflag="0" voiceformat="4" voicelength="1176" length="1334" bufid="147445261304397871" clientmsgid="416261363964373964444633636200230013013119fdd53b1f494102" fromusername="wxid_xxxxxxxxx" /></msg>

真是一波三折,还不是语音的数据,而是关于语音信息的 xml,有语音的大小,来自谁,在语音缓冲区中的id(bufid)等等信息。

继续往前找呗,最后回溯到了所有消息处理的分发函数 10323FF0 中。这个函数处理逻辑很复杂,我并没有很快就找到如何生成语音消息的 xml,以及处理语音数据的函数。

一度卡住,重复分析了很多次。

后来又回神想到了逆向神器 IDA,xml 中数据如 voicemsg 肯定是模块中会在代码中用到,看看有没有有用的信息。

用 IDA 打开 Wechatwin.dll,shift+F12 分析出所有字符串,Ctrl+F 找到关键字 voicemsg,看来有戏。

真的是柳暗花明又一村。

点击字符串跳到代码窗口,按下 x,跳到引用该数据的位置。

找到了解析语音 xml 数据和解码语音数据的关键函数。

函数 103148E0 解析 xml 拿到几个字段的内容,返回上层函数调用一个语音解码的函数进行处理,而这个解码函数就会直接操作语音数据。

函数 103148E0 回溯再看看,进入了分发函数 10323FF0 中,在一个循环中处理了多种流程,包括显示界面最新消息的流程和解码语音的流程。所以前面找的方向并没有问题,只是缺少认真分析数据和代码的耐心。

不过,目的都达到了,找到了数据处理函数,最后通过 hook 这个函数就能拿到语音数据。

另外可以看到语音数据中包含 SILK_V3 的字符,这种编码音频格式是 Skpye 曾经使用的一种编码方式,后来开源了。目前播放器并不能直接播放该编码音频文件,所以需要转码为 MP3 等格式。不过可喜的是已经有大佬完成了这个工作,并开源了工具 silk-v3-decoder:

https://github.com/kn007/silk-v3-decoder

所以把代码拿来整合一下,就可以完整的实现实时 dump 语音聊天数据,转换为 mp3 进行保存,完美。

总结

这是第一次比较成功的应用 CE,整个看来,确实省下来很多定位数据和函数的工作。

但CE并不是万能的,要找对方法,找对目标数据才可能成功,对于某些没有明显数据的功能,可能也是无能为力。

最终还是得提高对大型软件的逆向能力,总体实现思路的猜测以及调试验证。

最后,由于时间仓促,还没有把保存语音的功能加入到 SuperWeChatPC 项目中,后续会慢慢加入,欢迎持续关注:

https://github.com/anhkgg/SuperWeChatPC

本文分享自微信公众号 - 信安之路(xazlsec)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-02-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编程微刊

小程序云开发全套实战教程(最全)

在学习云开发的时候将自己的学习过程记录下来了,放在了网上,收获了一波好评,今天下午在办公室没有事情,也发现之前有人在博客里面评论,你这个教程还有一半哩,可能是c...

7.9K90
来自专栏Java那些事

世上最污技术解读,我竟然秒懂了。

假设你是一位女性,你有一位男朋友,于此同时你和另外一位男生暧昧不清,比朋友好,又不是恋人。你随时可以甩了现任男友,另外一位马上就能补上。这是冷备份。

16920
来自专栏即时通讯技术

同为IM社交产品中的王者,QQ与微信到底有什么区别

本文由人人都是产品经理专栏作家马璐原创发表,原题为《不谈历史谈当下,QQ与微信的区别是什么》,有改动。

18430
来自专栏程序员的知识天地

中国最有名的8个程序员:不只雷军、张小龙,其中3人都当过首富!

1.雷军:毕业于武汉大学计算机系,大三的时候就帮人写程序,成了百万富翁。1991年进入金山软件做程序员,一做就是7年。后来他成为金山总经理,又创办了小米。

17420
来自专栏编程微刊

小程序读取几种不同格式json数据(小程序json解析)

1:解析这个json:http://www.intmote.com/myproject/test/new_file.json

3K30
来自专栏SeanCheney的专栏

张小龙微信公开课(2019年1月)续

下面一个点是我从来没有谈过的点。对我们微信的本源、微信最基础的东西没有聊过,所以我这里准备花一点时间聊一下关于“社交”的话题。

14030
来自专栏云市场·精选汇

非常实用的25个小程序知识,看完记得收藏!

在运营公众号过程中,经常收到用户对小程序方面问题的反馈,针对用户经常提到的问题,虎哥今天整理出25条,以方便大家解决小程序在日常应用中遇到的问题。

9.6K60
来自专栏编程微刊

小程序右上角的胶囊颜色怎么修改?

在群里看到这样的一个问题,小程序右上角的胶囊颜色怎么修改?给小程序设置了头部背景之后,右上角的胶囊颜色却是透明的,和别人的相比:

69120
来自专栏SeanCheney的专栏

张小龙微信公开课(2019年1月)

刚刚我们在下面看了一下这些吐槽,非常好,因为我每天都在听到这样的声音,都已经习惯了。我觉得在中国来说,每天都有5亿人说我们做得不好,每天还有1亿人想教我怎么样做...

21030
来自专栏吾真本

作为QA,你会把测试的重点放在复杂的功能上吗?

今天,想用苹果的家庭共享功能,给13岁的孩子用他的苹果账号,在mac上登录后找我审批。

9720

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励