首页
社区
课程
招聘
[原创]微信过低版本验证
发表于: 2023-3-21 11:29 9754

[原创]微信过低版本验证

2023-3-21 11:29
9754

目录

微信过低版本限制逆向分析

有些微信机器人使用的协议或者Hook基于较低版本,所以过微信的低版本验证也称为了一种比较常见的需求,并且个人认为学会过版本验证应该是逆向人员应该了解并且掌握的意向基本功,文章比较适合初学者学习。

 

文章如有造成侵权,请及时联系作者处理。

 

文章仅供学习使用,切勿用于非法用途。

微信2.6.2.31下载:链接:https://pan.baidu.com/s/1kTkye-rPv9-byGQvSJd6Lg?pwd=aqzv
提取码:aqzv

供学习使用

一、一些常规的思路

软件实现过低版本检测通常情况下有以下几种思路

  • 软件从重要文件中获取版本信息,即GetFileVersionInfoW,可以尝试找到重要文件使用ResourceHacker(资源修改工具)尝试对版本信息进行修改。或者通过下断GetFileVersionInfoW这类API找到关键位置进行Patch
  • 软件的版本信息通过一些算法生成(后面得出来的结论是,压根没有算法),相对来说比较安全,但是可能不太容易找到突破点的地方
  • 再者,可以尝试找到网络协议中的发送版本信息的位置尝试修改,可想而知,这样做非常不理想。

二、冻手

修改关键文件

WeChatWin.dll对微信的重要程度已经众人皆知了,尝试对GetFileVersionInfoW下断点也给你足够的理由重视它。这里就不再赘述。

 

我们使用resourceHacker中首先找到一个可以正常登录的WeChatWin.dll的版本信息

 

图片描述

 

复制版本信息在低版本中修改,对ResourceHacker了解较少的朋友需要注意替换版本信息的时候要先编译再保存,如下图 图片描述

 

操作完成之后运行发现行不通,意料之中。基本上非常简单的软件可能成功

放弃微信协议突破点

从微信版本算法突破

1)找到突破点

可能一些大型软件会在重要文件保留关于版本信息的字符串,我们尝试在IDA中搜索

 

可以看到有很多相关字符串,我们可以在Xdbg中再搜索字符串,对其全部下段,过滤一些不重要的断点,看看有没有线索

 

在调试器中搜索字符串,注意最好要在WeChatWIn中搜索,因为他是我们的主要关注点,只在WeChatWIn中搜索可以过滤掉很多无用信息。

 

尝试过滤无用信息后,我们注意到一个比较有意思的点,如下图

 

这里有ClientVersion,这给我们足够的里有关注这个函数,但是他却对应了一个非常奇怪的字符串0x6206021C,很可能这就是我们需要关照的点。我们在IDA中转到此位置,RVA:94D907,VA:55AED907,如下图

 

图片描述

 

根据字符串能提供的信息,当前位置应该在腾讯开发的mars组件里,很可能附近涉及协议相关内容,我们先在只能祈求0x6206021C的获取不在协议内部。

 

经过简单的向上溯源,注意到字符串来自于RVA:94D8F0,VA:55AED8F0,如下图

 

图片描述

 

我们在IDA中跟进,奇怪的字符串来自如下所指处:

 

图片描述
我们在xdbg中跟进,来到RVA:2D6940,VA:55476940,如下图

 

图片描述

 

让人兴奋的是字符串未格式化之前来自于一个固定的内存位置0x5618D344,这是我们非常乐意看到的。

 

因为我们想要知道这个内存位置在哪里被写入(找到内容的由来),所以我们尝试0x5618D344下内存写入断点,我们不必关注重定向的问题,xdbg替我们解决了这个问题。

 

对其下内存写入断点,重启微信。成功断下,如下图,RVA:33528,VA:551D3528
图片描述

 

我们在IDA中跟进,如下图

 

图片描述

 

可以看到有一个异或操作,我们对其下断,重启微信发现那个字符串的未格式化形式(在上面的分析中有一个简单的函数将内存中的十六进制数据格式为字符串)就是通过这个简单的异或得到的,那我们的关注点就来到了函数sub_413810(),这个函数返回了一个简单的数据:0x1C,如下图 图片描述

 

0x1C与0x62060200进行异或,我们跟进这个函数。

 

图片描述

 

我们可以大概了解这个函数的行为,大概就是获取WeChatWIn.dll的版本信息,然后从版本信息的开始查找,然后经过简单的运算v6 = *((unsigned __int16 *)lpBuffer + 6);,并将v6返回,下面将简单解释:

 

我们在上图VerQueryValueW位置下断点,重启断下后如下图:

 

图片描述

 

对比IDA中,VerQueryValueW的第一个参数对应的是GetFileVersionInfoW返回的版本信息,我们查看VerQueryValueW的函数签名如下图:
图片描述

 

第二个参数为\,便是从根块查询资源信息,那么我们查看VS_FIXEDFILEINFO的结构,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef struct tagVS_FIXEDFILEINFO {
  DWORD dwSignature;
  DWORD dwStrucVersion;
  DWORD dwFileVersionMS;
  DWORD dwFileVersionLS;
  DWORD dwProductVersionMS;
  DWORD dwProductVersionLS;
  DWORD dwFileFlagsMask;
  DWORD dwFileFlags;
  DWORD dwFileOS;
  DWORD dwFileType;
  DWORD dwFileSubtype;
  DWORD dwFileDateMS;
  DWORD dwFileDateLS;
} VS_FIXEDFILEINFO;

在xbg中的v6中(即版本信息块中)对比找到结构,根据成员dwSignature可以很快的定位结构,其有以下特征:

 

图片描述

 

图片描述

 

我们再次在IDA中关注v6 = *((unsigned __int16 *)lpBuffer + 6);,v6作为返回值,来自lpBuffer 也即来自VS_FIXEDFILEINFO结构,需要注意到的是lpBuffer被强转为(unsigned __int16 *),则lpBuffer+6即lpBuffer向后寻址12字节,对应下图

 

图片描述

 

对应结构中的DWORD dwFileVersionLS;字段,是文件版本的低32位,如下图

 

图片描述

 

对应的,因为之前笔者对wechatwin.dll的文件信息做了更改,改为3.9.0.28,转为版本号形式:0003 0009 0000 001C,

 

0x1C 对应的就是28,所以我们可以得出结论,微信的版本计算用版本号的最后一字节的值来异或一个固定的值得到结果。

 

那么问题又来了,既然之前笔者已经成功替换了版本信息,这里的最后一个字节也已经变化,为什么版本验证没有成功呢。读者可以猜到,问题就出在那个固定值0x62060200,为了验证,笔者从微信版本3.9.0.28中找到版本验证的位置比较,在对应版本中,我们发现如下特征:

 

图片描述

 

我们比较0x620602000x63090000,发现3.9是我们分析的比较新的微信主版本号,而2.6是我们分析的旧微信的主版本号,所以之所以修改wechatwin的版本信息后并没有通过验证的原因大致我们也可以推测,因为主版本号仍是旧版本,异或之后得到的版本信息仍然是以旧主版本信息为主,所以验证会不通过,我们尝试在旧版本中修改主版本号信息来验证:

 

图片描述

 

运行,成功通过验证并登录,如下图:

 

图片描述

2)Patch

这种情况下过验证比较简单的方法就是修改WeChatWin.dll的版本信息并且Patch那个主版本号信息,修改WeChatWIn.dll的流程不再赘述,下面在dbg中:

 

图片描述

 

图片描述

 

图片描述

 

保存后替换原WeChatWIn.dll即可实现过版本验证

三、总结

  • 字符串搜索ClientVersion,可以找到关于版本信息调用。
  • 微信的版本号计算方式是:0x60000000^主版本号^版本号最后一个字节(本例中的0x1C)

非常简单

 

后来从网上查阅相关文章,发现 揰掵佲 师傅在21年就已经对相关内容做了总结,只不过大佬用的是从系统API下手,也是完全可行的,也是常见的追版本信息的方式,并且微信对版本验证做了一点微乎其微的加强:

 

在 揰掵佲 师傅的文章中,版本信息通过在内存中动态的计算0x0x60000000^主版本号^版本号最后一个字节,来计算版本信息,而主版本号是运行时获取的,所以修改wechatwin.dll的版本信息很容易就能达到绕过版本验证,在这里有一点安全性加强,只能说聊胜于无。

 

下面给出 揰掵佲 师傅的文章

微信低版本的分析 - 『脱壳破解区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 5
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//