逆向分析某office插件

注:本文仅用于技术研究与探讨,不提供任何成品和补丁程序

收集信息

今天要逆向的是XX格子这款部分功能付费的Office插件。先安装好后打开看看,看它都有啥可以调教的功能,发现了一个VIP窗口,那这就有意思了,狠狠的开破。

![](https://img-
blog.csdnimg.cn/img_convert/458ebcb01c59dd000d6d275c2abeec6d.png)

随后我们点击加入会员,点击离线登录,弹出如下窗口:

![](https://img-
blog.csdnimg.cn/img_convert/509c9588f1d3f438b9a4a25bb7e6d5ba.png)

关键信息都已经取得了,那就开始进入分析环节。

因为现在微软加载项都是以vsto进行部署的,所以我们先打开目录下的vsto文件,看看它调用了哪些DLL库,vsto文件关键节选如下:

  <dependency>
    <dependentAssembly dependencyType="install" codebase="FFCell.dll.manifest" size="25452">
      <assemblyIdentity name="FFCell.dll" version="2.0.0.0" publicKeyToken="b0c5e50cded54578" language="neutral" processorArchitecture="msil" type="win32" />
      <hash>
        <dsig:Transforms>
          <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
        </dsig:Transforms>
        <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
        <dsig:DigestValue>HswFQTT/AEBRt6Esc2Qlgpkx1Nc=</dsig:DigestValue>
      </hash>
    </dependentAssembly>
  </dependency>

不难发现其首先带调用的是FFCell.dll这个库,那我们直接开干,拖入exeinfope查壳,发现其为.NET程序并且加了混淆,如下图所示:

![](https://img-
blog.csdnimg.cn/img_convert/ff61507d7bf2f3b97f33ee4795fe9381.png)

可以发现其为IntelliLock加密,无所谓,我会出手,but技术水平有限,就不手工脱壳了,直接拖入NET Reactor
Slayer脱壳机,可以直接一键脱掉。

![](https://img-
blog.csdnimg.cn/img_convert/34dce76a7925e4d0a0b7b3f361dc11f5.png)

脱壳机

开始分析

基本代码分析

脱壳完毕后直接拖入dnSpy开始分析,我们直接搜索“绑定”,发现找不到,于是把函数名看看,发现关于软件注册的函数并没有在这个模块里面,那我们重新猜想,把目录里面的DLL都拿来分析了下,发现除了本体FFCell.dll外,还有若干个DLL也同样加了壳,猜测这几个DLL可能也是作者原创的DLL,再次执行上述的脱壳大法后拖入dnspy分析,可以在Newmem.dll这个文件中找到关于软件注册的函数,函数名也是如此,那我们就不难推断其实这个DLL专门就是管软件注册的事情的

![](https://img-
blog.csdnimg.cn/img_convert/3135cace9cf75f1674011e308e0a3bf6.png)

关于软件注册的函数

随后我们再次搜索关键字符串“绑定”,可以发现出现了结果

![](https://img-
blog.csdnimg.cn/img_convert/bc97e050f59d1f66bb61e35e5aa657a3.png)

在多个函数中均出现了关键字符串,那无所谓我们一个个看,经过分析,发现这几个函数分别对应不同的注册方式,分别有离线和在线两种。

![](https://img-
blog.csdnimg.cn/img_convert/bd86f28a7db28a289a2c222aabd39a0a.png)

首先先进行离线注册的分析,可在代码中发现确定绑定的按钮如下:

this.Button1.TabIndex = 0;
this.Button1.Text = "确定绑定";
this.Button1.UseVisualStyleBackColor = true;
this.LinkLabel1.AutoSize = true;

那我们就Button1对应的事件,长这样子:

internal virtual Button Button1
{
    get
    {
        return this.button_0;
    }
    set
    {
        EventHandler value2 = new EventHandler(this.method_2);
        if (this.button_0 != null)
        {
            this.button_0.Click -= value2;
        }
        this.button_0 = value;
        if (this.button_0 != null)
        {
            this.button_0.Click += value2;
        }
    }
}

可以看出好像method_2方法是点击这个按钮后的,无所谓是不是总之我们先跟进去看看就是,节选如下:

private void method_2(object sender, EventArgs e)
    {
        int num;
        int num4;
        object obj;
        try
        {
            IL_01:
            ProjectData.ClearProjectError();
            num = -2;
            IL_0A:
            int num2 = 2;
            string machineName = Environment.MachineName;
            IL_13:
            num2 = 3;
            string computerNo = VipRegV2Helper.GetComputerNo(machineName);
            IL_1E:
            num2 = 4;
            string text = this.TextBox1.Text;
            IL_2D:
            num2 = 5;
            if (Operators.CompareString(text, "授权码", false) != 0)
            {
                goto IL_4B;
            }
            IL_42:
            num2 = 6;
            text = "";
            IL_4B:
            num2 = 8;
            if (Operators.CompareString(text, "", false) != 0)
            {
                goto IL_7B;
            }
            IL_5F:
            num2 = 9;
            Interaction.MsgBox("授权码不能为空", MsgBoxStyle.OkOnly, "提示");
            IL_76:
            goto IL_2E3;
            IL_7B:
            num2 = 12;
            string left = this.TextBox3.Text.Trim();
            IL_91:
            num2 = 13;
            if (Operators.CompareString(left, this.VerfyImage1.code, false) == 0)
            {
                goto IL_CC;
            }
            IL_B0:
            num2 = 14;
            Interaction.MsgBox("验证码错误", MsgBoxStyle.OkOnly, "提示");
            IL_C7:
            goto IL_2E3;
            IL_CC:
            num2 = 17;
            string str = "";
            IL_D6:
            num2 = 18;
            if (VipRegV2Helper.CheckAccessCode(text, computerNo, ref str))
            {
                goto IL_11A;
            }
            IL_E9:
            num2 = 19;
            Interaction.MsgBox("授权码错误,原因:" + str, MsgBoxStyle.OkOnly, "提示");
            IL_106:
            num2 = 20;
            this.VerfyImage1.Gen();
            IL_115:
            goto IL_2E3;
            IL_11A:
            num2 = 23;
            DateTime expireDateFromAccessCode = VipRegV2Helper.GetExpireDateFromAccessCode(text);
            IL_125:
            num2 = 24;
            if (DateTime.Compare(expireDateFromAccessCode, DateTime.Now) < 0)
            {
                goto IL_1BF;
            }
            IL_13F:
            num2 = 31;
            string userNameFromAccessCode = VipRegV2Helper.GetUserNameFromAccessCode(text);
            IL_14B:
            num2 = 32;
            LoginHelper.SetLocalLogin(userNameFromAccessCode, "----");
            IL_15C:
            num2 = 33;
            VipOfflineHelper.SetLocalExpireDate(expireDateFromAccessCode);
            IL_166:
            num2 = 34;
            VipRegHelper.g_isReg = true;
            IL_170:
            num2 = 35;
            VipRegHelper.GetVipUility().SetVipValid(true);
            IL_180:
            num2 = 36;
            Interaction.MsgBox("离线绑定成功!绑定至" + expireDateFromAccessCode.ToString("yyyy年MM月dd日") + "\r\n\r\n到期后可继续申请绑定。", MsgBoxStyle.OkOnly, "离线绑定成功");
            IL_1AF:
            num2 = 37;
            this.DialogResult = DialogResult.OK;
            IL_1BA:
            goto IL_2E3;
            IL_1BF:
            num2 = 26;
            IL_1C3:
            num2 = 27;
            Interaction.MsgBox("授权码中绑定的日期已经过期", MsgBoxStyle.OkOnly, "提示");
            IL_1DA:
            num2 = 28;
            this.VerfyImage1.Gen();
            IL_1E9:
            goto IL_2E3;
            IL_1EE:
            int num3 = num4 + 1;
            num4 = 0;
            @switch(ICSharpCode.Decompiler.ILAst.ILLabel[], num3);
            IL_296:
            goto IL_2D8;
            IL_298:
            num4 = num2;
            if (num <= -2)
            {
                goto IL_1EE;
            }
            @switch(ICSharpCode.Decompiler.ILAst.ILLabel[], num);
            IL_2B4:;
        }

不难看出这个函数其实就是判断看用户输入的注册码是否正确,但是还存在部分没有脱壳脱干净的代码,不过无伤大雅,已经不影响我们对代码的判读了。其实就是先根据电脑名称算一个机器码出来,然后与用户输入的注册码进行对比,对比上了就说明输入正确,予以注册,否则就弹错误窗口,期间还有注册码格式的检查过程等。其中,关键的函数是

if (VipRegV2Helper.CheckAccessCode(text, computerNo, ref str))
{
    goto IL_11A;
}

这个CheckAccessCode函数就是我们要找的关键了,跟进看看:

![](https://img-
blog.csdnimg.cn/img_convert/f1112d0bb71fcc83afec39ec2bf586bf.png)

不难发现就是判断注册码输对了没,然后返回一个bool类型,如果是true就说明对了,可以注册,是false就说明不对,不让注册,那我们思路就非常清楚了,可以在函数的返回处下断进行调试。

![](https://img-
blog.csdnimg.cn/img_convert/6a2c4934a030a7bc0f7926715f42c491.png)

此处下断直接强行改变量为true,这下不得不给我狠狠注册了

![](https://img-
blog.csdnimg.cn/img_convert/462d43b69dc8290fda7b32a9d4f24dd2.png)

随后程序带着true跳出CheckAccessCode函数,返回到method_2函数,因为改成true了所以现在要判断注册多长时间,因为我刚才的注册码是胡乱敲的,怎么可能包含注册有效时间在里面,所以我们还要在我们再改一处,当程序来到这里的时候我们可以修改expireDateFromAccessCode变量的值,如下图所示:

![](https://img-
blog.csdnimg.cn/img_convert/f9097dce7ae3b1942489f62930ddfea7.png)

直接把到期日期设置为2099年1月1日,随后我们继续运行程序,可以看到我们梦寐以求的窗口弹出来了:

![](https://img-
blog.csdnimg.cn/img_convert/18e02570534836aaefeab9ca7e7d86d2.png)

至此,我们就成功拿到了会员身份,但是还是有局限。

  1. 全程需要断网运行,否则软件一旦联网就发现你这个会员身份是假的,就给你覆盖掉了,又成为了非会员身份。

  2. 每次用这个插件都要先用dnspy调试下断改变量,老麻烦了

那首先我们先解决第二个问题,那既然每次都要用,那我们为什么不直接输入正确的注册码呢,那我们就对注册码的算法来一波狠狠的扒皮。

授权码算法分析

通过对多个函数的分析,为了方便读者阅读,特画出超强理解的流程图,保证你一看就懂。

![](https://img-
blog.csdnimg.cn/img_convert/6e507bee22ea21b2aba083f6e88d382b.png)

注册表分析

如果觉得上面注册码算法过于困难,还是有点看不懂,没有关系,其实我们还可以利用注册表法来直接把到期时间改了,不难发现SetLocalExpireDate函数就是拿来把到期日期写进电脑系统的注册表的,其代码如下:

public static void SetLocalExpireDate(DateTime dt)
{
    Simple3Des simple3Des = new Simple3Des("为防止泄露密钥已隐藏");
    string v = simple3Des.EncryptData(dt.ToString());
    RegistryHelper.SetValue("FFCELL_VIPOFFLINE_SETTING", "OfflineExpireFlag", v);
}

可以很清楚的发现这是三轮的DES加密,密钥也直接写死在代码中了,为防止泄露,在本文中就隐藏掉了,我们拿到密钥后自己把授权到期日期一加密手动写进注册表就直接达到了授权到2099年的目的了。

![](https://img-
blog.csdnimg.cn/img_convert/192076bff8c1fb3b58473f48748c7cf6.png)

再提一嘴,除了加密授权到期的日期外,如果用的是联网登录账号,那么你的账号和密码也是用这个算法来加密存储在注册表里面的。

通信协议分析

联网验证也没关系,我们只需要分析一下通信内容即可,先找到判断是否为VIP的联网通信函数

public static bool GetVipInfo(ref string info, ref VipUser vip1)
    {
        string localUserName = LoginHelper.GetLocalUserName();
        string localEnpwd = LoginHelper.GetLocalEnpwd();
        bool result;
        if (Operators.CompareString(localUserName, "", false) == 0 | Operators.CompareString(localEnpwd, "", false) == 0)
        {
            result = false;
        }
        else
        {
            try
            {
                Login login = new Login();
                string vipInfo = login.GetVipInfo(localUserName);
                if (vipInfo == null)
                {
                    info = "无法连接服务器,请检查网络或联系我们!\r\n" + Information.Err().Description;
                    result = false;
                }
                else if (vipInfo.IndexOf("RegOK") > 0)
                {
                    string text = "#@x#";
                    info = "";
                    int num = vipInfo.LastIndexOf(")");
                    string text2 = vipInfo.Substring(checked(num + 1));
                    string[] array = Regex.Split(text2, text);
                    if (array.Length != 5)
                    {
                        result = false;
                    }
                    else
                    {
                        if (Operators.CompareString(array[0].ToLower(), "t", false) == 0)
                        {
                            vip1.isValid = true;
                        }
                        else
                        {
                            vip1.isValid = false;
                        }
                        vip1.userName = array[1];
                        vip1.expireDate = array[2];
                        vip1.lastPc = array[3];
                        vip1.vipscore = array[4];
                        if (Operators.CompareString(vip1.vipscore, "", false) == 0)
                        {
                            vip1.vipscore = "0";
                        }
                        result = true;
                    }
                }
                else
                {
                    info = vipInfo;
                    result = false;
                }
            }
            catch (Exception ex)
            {
                info = "执行过程出现异常:" + ex.Message;
                result = false;
            }
        }
        return result;
    }

注意上述代码的第34行,如果从服务器接收的值是t就是会员,是其他值就不是会员,那我们使用Fiddler抓包看看

请求:

POST /vip/VipRegV2/VipRegVer2.aspx HTTP/1.0

接收:

(RegOK:1)f#@x#UserName#@x#2023/2/18 23:51:32#@x##@x#0

可以看到接收的内容中有f,我们猜测这可能就是和是否为会员相关的值,我们使用fiddler的拦截功能将数据包拦下,修改成t后再放行此数据包
,可以看见已经成为会员了。

![](https://img-
blog.csdnimg.cn/img_convert/dd1682cfbec59427dc956d228f75fc79.png)

接收内容的最后那个0猜测就是会员等级,也可以随意修改的。

总结

至此,这个软件就分析的差不多了,还有其他的一些小功能在此就不再赘述了,本文起到一个抛砖引玉的作用,读者可以参考本文自行分析其余的功能模块,若想获得VIP权限,有如下几种方法。

  1. 每次使用软件时用dnSpy调试,修改局部变量, 在内存中改成VIP;

  2. 分析授权码算法,自行编写注册机进行授权;

  3. 直接拿密钥写注册表;

  4. 拦截通讯数据包,抓包改包,欺骗软件自己已经是VIP了。

上述1~3条方法建议配合断网使用,否则可能会失效,不过也可以通过hook方法屏蔽掉它的联网功能,此处不再赘述。

接下来我将给各位同学划分一张学习计划表!

学习计划

那么问题又来了,作为萌新小白,我应该先学什么,再学什么?
既然你都问的这么直白了,我就告诉你,零基础应该从什么开始学起:

阶段一:初级网络安全工程师

接下来我将给大家安排一个为期1个月的网络安全初级计划,当你学完后,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web渗透、安全服务、安全分析等岗位;其中,如果你等保模块学的好,还可以从事等保工程师。

综合薪资区间6k~15k

1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)

2、渗透测试基础(1周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等

3、操作系统基础(1周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)

4、计算机网络基础(1周)
①计算机网络基础、协议和架构
②网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
④网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现

5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固

6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)

那么,到此为止,已经耗时1个月左右。你已经成功成为了一名“脚本小子”。那么你还想接着往下探索吗?

阶段二:中级or高级网络安全工程师(看自己能力)

综合薪资区间15k~30k

7、脚本编程学习(4周)
在网络安全领域。是否具备编程能力是“脚本小子”和真正网络安全工程师的本质区别。在实际的渗透测试过程中,面对复杂多变的网络环境,当常用工具不能满足实际需求的时候,往往需要对现有工具进行扩展,或者编写符合我们要求的工具、自动化脚本,这个时候就需要具备一定的编程能力。在分秒必争的CTF竞赛中,想要高效地使用自制的脚本工具来实现各种目的,更是需要拥有编程能力。

零基础入门的同学,我建议选择脚本语言Python/PHP/Go/Java中的一种,对常用库进行编程学习
搭建开发环境和选择IDE,PHP环境推荐Wamp和XAMPP,IDE强烈推荐Sublime;

Python编程学习,学习内容包含:语法、正则、文件、 网络、多线程等常用库,推荐《Python核心编程》,没必要看完

用Python编写漏洞的exp,然后写一个简单的网络爬虫

PHP基本语法学习并书写一个简单的博客系统

熟悉MVC架构,并试着学习一个PHP框架或者Python框架 (可选)

了解Bootstrap的布局或者CSS。

阶段三:顶级网络安全工程师

如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

学习资料分享

当然,只给予计划不给予学习资料的行为无异于耍流氓,这里给大家整理了一份【282G】的网络安全工程师从入门到精通的学习资料包,可点击下方二维码链接领取哦。

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值