发新帖

微信红包辅助实现分析

[复制链接]
14050 4
本文作者为七少月,此次为github上一个项目,微信抢红包辅助,本文主要是以此为例,先对其进行逆向,再进行分析。一方面讲述微信抢红包辅助的基本实现原理,另一方面也提高通过dex2jar获得的java伪代码的分析能力,并体现java伪代码与真实代码的不同。本文仅用于教学目地,不得用于任何商业和非法用途,否则与本人无关。
前言:
  首先,新年之际,祝大家新年快乐,感谢所有支持我的朋友,在新的一年里,万事如意。在上篇文章《某微信红包辅助插件破解分析》中,很多朋友表示比较感兴趣。但很抱歉的说,我做的是逆向安全,当时那篇文章目地更多是在逆向,而不是微信辅助。由于上段时间比较忙,一直没有发什么帖子,最近过年,大牛他们也需要休息,而我学艺不精,在现在基本忙完后,准备陆续发一些技术贴。思来想去,决定从大家比较感兴趣且最为简单的微信红包辅助入手,也当补充了我上一篇文章。
教材说明:
这次教材为他人在github上一个项目,项目源码:https://github.com/geeeeeeeeek/WeChatLuckyMoney。项目已经将软件更新到了2.0,但本文主要是讲解实现的基本原理,所以使用了1.3版本,把一些非关键性代码进行删除,只保留关键性代码。在本文最后,会有资料,资料中包含样本和详细的java伪代码的分析,几乎分析了每一句,每一个关键点,同时包括了使用的视频演示。
微信红包辅助实现的三种方法:
微信红包辅助的实现大概有三种方法,这里我们简单说一下,并进行比较。
1.  自动屏幕点击:如果将其看作游戏辅助的话,那么这种方法实际上就是按键精灵那样的模拟辅助类型,为自动点击屏幕,代替手动操作。本例就是典型的这种方法,核心的实现方法就是窗口事件回调方法。从整体的smali来看,本例在主入口点的oncreate()方法中调用updateServiceStatus()函数,该函数用于开启和关闭抢红包服务,该服务就是HongbaoService。这种方法简单易行,且早已出现,但和所有的模拟辅助缺点一样,适配性和成功率不高,功能过弱,且容易被检测和处罚;
2.  注入微信:这种案例就类似于我的上一篇文章中的样本,具体不再分析,缺点显而易见,微信版本一旦更新,就要重写,重用性太低;
3.  微信服务器协议:首先要提醒,如果你通过抓取微信的服务器协议来制作辅助,是处于法律底线的,微信的服务器协议分析也常常只能想想,其分析难度可想而知。很多人想实现后台控制辅助,也就是每次都能抢到金额最大的一个红包,这可能是不现实的。因为能否抢到大包,这取决于微信红包的随机算法,应该是在服务器。就好像很多游戏抽奖道具一样,修改服务器的随机算法近乎不可能。
本例的抢红包实现算法逻辑:
逻辑非常重要,因为红包存在很多种情况,如有没有被戳开,有没有被抢完,会不会出现重复,会不会出现误判等等问题。所以,一个好的抢红包辅助最主要是好的算法,来处理这些问题。其实我们可以看出,红包类型在算法里尤为重要。本例的核心在我看来就两点:
1、  利用Accessibility服务实现屏幕的自动点击;
2、  利用对于红包节点信息的检测,即红包匹配文字,来判断红包类型,进而得出是否可以戳开或抢。
本例的主要逻辑流程:
1.判断屏幕上是否有微信红包;
2.获取屏幕的红包根节点;
3.检测红包的节点(根节点的子节点)信息,主要针对戳开后,得到待抢队列;
4.自动点击,戳没有戳开的红包;
5.自动点击,抢戳开后但未领取的红包。
当然,上述已经说过,要处理的问题还有很多,特别是到底怎么才能得到可以抢的红包,以及那么多的情况,要怎么样去安排,先做什么后做什么,最主要的,是如何来抢这些红包,是先全部都去抢,然后再去判断结果,还是先获得正确的红包,接着再去抢。
具体的实现分析都在资料中,非常详细,但这里我说两点可能会出现疑问的地方,原因一个是Accessibility服务需要配置,再者就是dex2jar获得的java代码是伪代码,跟真实代码差距比较大:
1.  我们看如下代码,可以知道,Accessibility服务需要配置:
private final Intent mAccessibleIntent = new Intent("android.settings.ACCESSIBILITY_SETTINGS");
本例的配置是在逆向后的目录:/res/xml/accessible_service_config文件之中。我们只说一个配置,本例是微信红包辅助,所以Accessibility服务在配置时需要指定包名:
<accessibility-service android:description="@string/app_name" android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowContentChanged|typeWindowStateChanged" android:packageNames="com.tencent.mm"
2.  很多人对于java伪代码中performAction(16)的16不知道什么意思,先分析这个函数可以知道,这是一个进行屏幕操作的函数,先看出现位置:
((AccessibilityNodeInfo)this.mReceiveNode.get(i - 1)).getParent().performAction(16);
如果想理解这个16的意思并不困难,我们需要知道它肯定是使用了Accessibility的函数库,16的十六进制为0x10,我们到函数库的地方,一目了然,16就是ACTION_CLICK.
.field public static final ACTION_CLEAR_FOCUS:I = 0x2

.field public static final ACTION_CLEAR_SELECTION:I = 0x8

.field public static final ACTION_CLICK:I = 0x10

.field public static final ACTION_COPY:I = 0x4000

.field public static final ACTION_CUT:I = 0x10000

.field public static final ACTION_FOCUS:I = 0x1
ACTION_CLICK也就是自动点击,这就告诉我们,当分析java伪代码时,不能囫囵吞枣,对相应的支持性函数库也要分析,这就像分析soARM,不能只看寄存器和代码,要结合这个so本身的一些信息,和它要达到的功能。想起小雨Eriky的那个cm试题,很多人F5之后,静态分析得到的c伪代码非常少,没有关键的加密算法,原因是因为IDA被小雨写的代码误导,误以为malloc是一个函数块trunk,而不是函数。回到本例,从功能来看,这一个功能也一定是自动点击屏幕。
最后,就是检测节点信息的重点分析截图,可见非常详细:
private void checkNodeInfo()
  {
    if (this.rootNodeInfo == null) {} //如果红包根节点信息不为空
    do
    {
      do
      {
        do
        {
          return;
                  
                  //该函数主要是利用findAccessibilityNodeInfosByTexts()函数匹配红包文字内容,来检测节点,
                  //进而判断出是否接收、是否打开,是否需要抢等结论,以及得到接收队列和待抢队列
                  
                  //遍历节点匹配“领取红包”和"查看红包"
          localList = findAccessibilityNodeInfosByTexts(this.rootNodeInfo, new String[] { "领取红包", "查看红包" });
          if (localList.isEmpty()) { //如果队列为空,则退出
            break;
          }
                  //利用红包文字内容+节点ID的HASH值,进行判断红包是否重复,避免红包重复
        } while (Integer.toHexString(System.identityHashCode(this.rootNodeInfo)).equals(this.lastFetchedHongbaoId));
        this.mLuckyMoneyReceived = true; //已经接收
        this.mReceiveNode = localList; //得到接收队列
        return;
               
                //戳开红包,红包还没抢完,遍历节点匹配“拆红包”
        List localList = findAccessibilityNodeInfosByTexts(this.rootNodeInfo, new String[] { "拆红包", "Open" });
        if (!localList.isEmpty()) //如果队列不为空
        {
          this.mUnpackNode = localList; //得到待抢队列
          this.mNeedUnpack = true; //需要抢
          return;
        }
      } while (!this.mLuckyMoneyPicked); //没有被打开过
          
          //戳开红包,红包已被抢完,遍历节点匹配“红包详情”和“手慢了”
    } while (findAccessibilityNodeInfosByTexts(this.rootNodeInfo, new String[] { "手慢了", "红包详情", "Better luck next time!", "Details" }).isEmpty());
    this.mNeedBack = true;//需要返回
    this.mLuckyMoneyPicked = false; //没有被打开过
  }
资料下载链接:http://pan.baidu.com/s/1eRyK9LS

已有1人评分 NB 荣获致谢 理由
freeparty + 1 + 1 很给力!

查看全部评分 总评分: NB +1  荣获致谢 +1 

举报 使用道具

回复

精彩评论4

何须执手问年华    发表于 2016-1-29 11:20:17 | 显示全部楼层
请问github上的代码不都是开源的吗?为什么还需要逆向啊?

举报 使用道具

回复 支持 反对
我放不下你    发表于 2016-1-30 17:58:40 | 显示全部楼层
少月大牛就是刁,虽然没看懂,希望能给详细点思路

举报 使用道具

回复 支持 反对
maikesoft    发表于 2016-1-30 20:25:07 | 显示全部楼层
厉害支持

举报 使用道具

回复
Foooooooood    发表于 2016-1-30 22:14:45 | 显示全部楼层
厉害支持

举报 使用道具

回复
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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