吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 26715|回复: 109
收起左侧

[原创] 分析一个新型VM的CrackMe

  [复制链接]
Sound 发表于 2018-2-5 14:12
本帖最后由 Sound 于 2018-2-5 14:22 编辑

0x00 前段时间实在是太忙了,没时间看这个cm,最近闲下来了, 准备开搞。
sd大佬来玩 cm 了 爆破就成 算法太简单 https://www.52pojie.cn/thread-682451-1-1.html

0x01 初步了解这个cm

要求玩家输入一串字符串, 如果错误则显示fail, 如果正确...应该就会显示其他信息, 作者没有给出成功后的截图, PE中也没有发现这类字符串...
拖进调试器, 发现这个cm的算法是通过虚拟机加密了的, 难怪作者说只要爆破就可以了, 废话不多,直接进入下一个步奏吧.

0x02 一个带虚拟机加密的cm

首先查虚拟机壳的相关信息, 发现毛都没看到, 但使用PE工具查看节表信息发现有个sp0101节, 直接反汇编这个节, 发现这里
就是那一处虚拟机..

        因为这个虚拟机应该是作者自写的, 所以我也决定手动来会会这个虚拟机..

        加密段进入虚拟机的代码:
图1.png

虚拟机入口代码:

图2.png

虚拟机的过程大概是 -> 保存现场 -> 设置esi edi vmesp -> 设置重定位字段 -> 进入第一个handler
        
        有兴趣的朋友可以自行跟踪了解, 这里就不详细述说了.

0x03 虚拟机自效验

        我想手写hook记录hanlder的日志信息, 发现只要hook就会出问题, 仔细操作发现只要在虚拟机任意位置下一个断点(int3)然后直接运行就会发生同样的错误,
        猜测虚拟机有自效验, 这就尴尬了, 想直接hook是不可能的了, 得先过这个自效验才行..
错误:
图3.png
经过多次尝试发现, 仅仅只是修改虚拟机以及虚拟机的跳转表以及虚拟机内 jmp dword [eax * 4 + X] 的最后4字节会发生这个错误, 作者显然是不想别人动他的虚拟机了..
        
        不过作者没有效验整个PE文件, 这就给我们留了很大的空间发挥了, 如果作者这样做了, 那这个搞起来就很伤身体了..

0x04 六耳猕猴

现在先搞定它的自效验.
        
        步奏如下:
        1. 使用loadpe工具复制sp0101节.
        2. 使用loadpe工具添加复制的节到末尾.
        3. 删除重定位节. (因为虚拟机里面有很多地方都有重定位, 把这些重定位一并修复显然蛋疼, 还是直接删掉重定位爽~)
        4. 使用任意十六进制工具打开cm0.exe 查找加密段的最后的那个jmp, 请看图1, 将其跳转修改为跳转到我们复制的虚拟机入口处.
        
        *** 到这里之后, 我们先保存这个exe, 取个名字为: 修改至第一阶段.exe, 之后每次修改都从这个exe复制一份出来改名为:cm0.exe ***
        
        现在只是将虚拟机入口修改好了, 现在要修正跳转表, 否则跳转表依然指向的是之前的虚拟机位置, 跳转表有多大不清楚.. 只能去查特征,
发现几乎所有的handler最后一行代码都是 jmp dword ptr[eax * 4 + X], 且X是虚拟机内唯一的特征, 那么就好办了, 写一段代码现查然后在
重新指向我们拷贝的虚拟机节中的跳转表(不能修改原始的, 因为原始的依然会被检测.). 前面说了X是虚拟机内唯一, 但是我们拷贝了一份, 因此
在2处位置会撞脸, 我们首先手动将我们拷贝那一处手动替换成新的跳转表地址吧, 然后在写代码查询这个就一定是唯一的了.

        手动替换跳转表地址, 新的跳转表VA为: 0x0047534a, 我使用的工具是HxD, 使用替换功能就可以了, 记得是从新虚拟机的位置开始哦, 如图:

图4.png

查询修正跳转表代码如下
[Asm] 纯文本查看 复制代码
 start.        
        //
        // 打开cm0.exe
        
        CFMBuffer fp("cm0.exe");

        //
        // 移动至虚拟机机器码开始位置

        fp.FM_MOV_SET(0x6cc00);

        //
        // 获取虚拟机机器码 0x134a 为虚拟机机器码的总长度, 使用7534a(跳转表RVA) - 74000(新虚拟机节RVA) == 134a 但我不确定是不是, 不过使用134a貌似没有问题

        string vm_bc;
        char *vm_bytecode = new char[0x134a];
        fp.FM_R_DATA(vm_bytecode, 0x134a);
        vm_bc.append(vm_bytecode, 0x134a);

        //
        // 确定 跳转表的个数

        DWORD Addr = 0;
        DWORD table_cnt = 0;
        for (;;)
        {
                char Number[5] = { 0x4a, 0x53, 0x47, 0x00, 0x00 };
                Addr = vm_bc.find(Number, Addr);

                if (Addr == -1)
                {
                        break;
                }

                table_cnt++;
                Addr += 4;
        }

        printf("一共查询到跳转表数据:%d个.\n", table_cnt);
        
        //
        // 获取跳转表中的VA

        vector<DWORD> table_data;

        for (DWORD i = 0; i < table_cnt; ++i)
        {
                DWORD data = 0;
                data = fp.FM_R_UINT32();
                table_data.push_back(data);
        }

        fp.FM_OFF();
        fp.FM_ON_AB();
        fp.FM_MOV_SET(0x6cc00 + 0x134a);

        //
        // 根据table_cnt 替换跳转表

        for (DWORD i = 0; i < table_cnt; ++i)
        {
                DWORD data = table_data[i] - 0x28000 + 0x74000;
                fp.FM_W_UINT32(data);
        }

        printf("一共重写跳转表数据:%d个.\n", table_cnt);

        fp.FM_OFF();
        
        查询修正跳转表代码如下 end.

        
        运行结果:
图5.png

现在运行处理后的cm0.exe, 发现会GG, 查看问题发现代码异常还是跟之前图3一样.. 这是为啥, 仔细检查确定该修改的都修改了,
为什么还是出问题呢? 百思不得其解, 吃饭去了, 这里就告一段落.. - _ -

0x05 花世界

上面遇到挫折后猜测了很多可能, 但是由于虚拟机有大量花指令插在里面影响阅读, 所以决定去花然后看看有没有什么异常的地方..

前面说了手动干, 因此去花也决定手动写代码解决, 其实这个虚拟机使用的花并不多, 也就5 6 7朵吧, 还都是一些古老的花指令, 去起来也好办.
        
由于代码太长我就不发了, 截图发个效果吧.
        
        去花结果:


图6.png

虚拟机去花后的效果:

图7.png

现在虚拟机干净了, 就是很多nop好长, 不过至少可以正常阅读了, 花了一些时间快速扫了很久, 发现一处handler:
[Asm] 纯文本查看 复制代码
VA: 00474D40
        
        00474D40   push        eax
        00474D41   push        edx
        00474D42   push        ecx
        ... nop 无关紧要省略
        00474D51   push        eax
        00474D52   fldz                                                                // ------> 注意这个
        ... nop 无关紧要省略
        00474D62   mov         ecx,0xFF08AD38
        00474D67   not         ecx
        ... nop 无关紧要省略
        00474D79   wait
        00474D7A   fstenv      [esp-0xC]                        // ------> 注意这个
        00474D7E   pop         ecx
        00474D7F   lea         esp,[esp+0xC]
        00474D83   push        ecx
        00474D84   lodsb
        00474D85   xor         al,0xD8
        00474D87   not         al
        00474D89   sub         al,0x76
        00474D8B   add         bl,al
        00474D8D   not         bl
        00474D8F   movzx       eax,al
        00474D92   jmp         dword ptr [eax*4+0x47534A]


这个handler是获取当前运行时的eip的, 我在原始的cm0.exe这个handler上下断点将栈顶数据改为一个很大的值, 然后去掉断点, 发现GG了, 又是那个错误..
经过很多次的实验, 我发现这个虚拟机居然还检测当前位置是否在合法的范围内, 应该就是用来防止拷贝虚拟机过自效验的, 现在知道了这个handler我们只需要
强行修改它, 在栈顶设置一个跟原始cm0.exe一模一样的值就可以了.

方法: 从新虚拟机的位置开始搜索特征码, 找到这个handler, 然后自行发挥修改即可, 我的修改如下:

代码:

[Asm] 纯文本查看 复制代码
UCHAR bc[] = {
                0x50, 0x52, 0x51, 0x90, 0x90, 0x90, 0x68, 0x58, 0x8C, 0x42, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90,
                0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
                0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
                0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x59, 0x8D,
                0x64, 0x24, 0x0C, 0x51, 0xAC, 0x34, 0xD8, 0xF6, 0xD0, 0x2C, 0x76, 0x02, 0xD8, 0xF6, 0xD3, 0x0F,
                0xB6, 0xC0, 0xFF, 0x24, 0x85, 0x4A, 0x53, 0x47, 0x00
        };

        CFMBuffer fp("cm0.exe");
        fp.FM_OFF();
        fp.FM_ON_AB();

        //
        // 移动至虚拟机机器码开始位置 与 handler 的开始位置

        fp.FM_MOV_SET(0x6cc00 + 0xD40);
        fp.FM_W_DATA(bc, sizeof(bc));
        fp.FM_OFF();

        printf("修改handler_geteip代码已经完成.\n");


效果图:

图8.png

然后在运行一次cm0.exe, 哈哈哈哈哈哈啊, 完美运行, OK鸟, 虚拟机自效验算是完整突破(因为我们修改了一个handler, 还是可以正常运行), 接下来就可以回到最前面, hook~~

0x06 糟糕的体力活 hook

这里hook我使用了最简单的方法, inline hook, 一步一步的hook这个虚拟机使用的handler, 然后打印出日志信息, 有了详细的日志信息, 基本上在notepad++上通过查询一些关键数据

就可以突破了。

下面是我hook的一些handler:

图9.png

由于hook的细节有一些繁琐, 这里就不说了, 总而言之就是记录每个handler的作用, 以及当时的参数 数据等信息, 我录下来的日志是这样的:

图10.png

现在有了这些日志, 但是完整的日志显然太大了, 这非常不利于我们分析, 于是我又想了一个办法, 过滤掉cm0.exe输入之前的所有记录, 于是我加了个
Sleep(6000), 运行后6秒重新创建一个日志文件, 将输入以及之后的handler保存到另外一个单独的文件中, 这样我们就可以直接分析我们关心的handler逻辑了。

        虽然几句话就说完了hook, 但实际动手去搞真的很蛋疼, 需要一点点耐心.

0x07 大海捞针之抽象定位

很久以前, 我这样分析一个VM, 都会将表达式整出来, 这样做其实是相当消耗时间跟耐心的, 但这次我没有这样做, 而是从爆破出发, 所以我只关心了一个指令: VMSetPC.
        
        从所有handler找到操作esi寄存器的handler, 这个十有八九就是VMSetPC指令, 然后hook, 打印出所有我们关心的信息, 然后看日志:

图11.png

我们看到有一行日志是: VMSetPC key:[0x95], h:[0x74], pc:[0x0004684a], 当前pc:[0x0046cb45], 跳转pc:[0x0046fe55].


        key是跳转过去后修正的key
        h是跳转过去后下一个指令的handler
        pc是字节码内的RVA
        当前pc是指执行这个VMSetPC时esi的值
        跳转的pc是指esi被修改后的值

有了这些数据, 一切都好办了, 现在唯一要解决的问题就是怎么爆破, 因为我们输入的数据是胡乱输入的, 因此那个跳转pc, 一定是跳到提示错误的地方去了,
所以我们要找到如果它不是要跳到那, 那究竟是要跳到哪...

        这个需要分析这个jcc的vm指令, 向上找日志, 搜索关键字0x0004684a, 向上找看看这个0x0004684a是怎么被计算出来的.

        向上找到第一个0x004684a, 如图:

图12.png

其中日志: VMNulNor32 [0x03e08020], [0xfc1b1795], 结果:[0x0004684a].

        是一个nor操作, 那我们向上跟踪这3个值, 可以发现是5个nor得出的, 很显然, 这是一个xor, 也就是说, 0x0004684a是一个数被解密出来的, 这个数是第一个nor里面的:
        
        VMNulNor32 [0xfc1b5f95], [0xfc1f37df], 结果:[0x03e08020]. 加上后面的4个nor, 其实就是 xor 0xfc1b5f95, 0xfc1f37df, 知道了加密方法, 那我们看看哪个是被加密的数值,
继续向上查询这两个数, 直到找不到为止, 就一定是第一次出现的地方.

        找到如下日志:

图13.png

日志内容:
        
        VMPushImm32 [0x0000005d].
        VMPushImm32 [0x00000074].
        VMPushImm32 [0x00000046].
        VMPushImm32 [0x00000095].
        VMPushImm32 [0xfc1f6aae].
        VMPushImm32 [0xfc1f37df].
        
        里面包含了数据 0xfc1f37df, 那么就好办了, 它上面的那个一定会是跳到正确路径的RVA了, 我们拿出它跟 0xfc1b5f95 xor 得到RVA 0x0004353B,
那么不用犹豫了, 上面的其他数据也是跟着配套的, 请回顾:

        VMSetPC key:[0x95], h:[0x74], pc:[0x0004684a], 当前pc:[0x0046cb45], 跳转pc:[0x0046fe55].
        那我们这个VMSetPC要强制修正为:
        VMSetPC key:[0x46], h:[0x5d], pc:[0x0004353B] (为什么只要改这3个? 因为只有这3个是参数, 后面2个是影响后的数据, 不能修改.)
        
        那么我们回到hook的地方, 自己写段代码强行将数据修改为我上面的指出的数据即可.
        
        然后在尝试录制一次日志, 你会发现, 嘿嘿, 现在有2个VMSetPC了, 这表示我们之前的修改是完全正确的, 因此, 我们只要使用这个方法, 一直修改下去,
就可以爆破这个cm0.exe了, 为了节省篇幅, 我直接截图我这边的修改吧.

图14.png

好了, 当这些补丁全部分析完打上去之后, 爆破就成功了, 效果:

图15.png

0x08 总结
        
        1 制造六耳猕猴 过掉自效验
        2 多想想有可能导致自效验依然生效的原因
        3 利用日志的关键字搜索 快速定位核心信息
        4 要有耐心
        
题外话:  
这个cm0.exe里面使用的虚拟机, 只是作者拿出来娱乐的虚拟机,
真正有强度的虚拟机跟这个虚拟机的架构完全是不一样的, 无法使用相同的方法过自效验, 也没有跳转表, 想找handler非常不容易, 总之架构已经完全不同,
以后你们遇见sp0101的虚拟机壳, 很可能就是作者的SProtect壳了.    这些是之后我向作者请教才了解的,


52cm.rar (1.48 MB, 下载次数: 119)

免费评分

参与人数 58吾爱币 +70 热心值 +57 收起 理由
小生我怕怕 + 10 + 1 超赞的文章
fa1123 + 1 膜拜
duyuesheng + 1 热心回复!
少爷灬小贝 + 1 我很赞同!
抱书人人 + 1 + 1 谢谢大佬@Thanks!
wjshan0808 + 1 + 1 谢谢@Thanks!
muzb + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
躲在角落看繁华 + 1 + 1 用心讨论,共获提升!
aristotlez + 1 + 1 热心回复!
cwl + 1 + 1 我很赞同!
o不懂爱的魂o + 1 + 1 我很赞同!
josong + 2 + 1 不明觉厉,厉害厉害
kilkilo502 + 1 + 1 根本没有达到这个级别无法理解 一些手段。。
antclt + 1 + 1 我很赞同!
liphily + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
a1305315624 + 1 + 1 我很赞同!
老道 + 1 + 1 &amp;quot;字&amp;quot;看上去那么像&amp;quot;宇&amp;quot;
ScareCrowL + 1 + 1 真的是非常6~
精华帖 + 1 + 1 谢谢@Thanks!
siuhoapdou + 1 + 1 谢谢@Thanks!
?﹏從此沉默 + 1 + 1 我很赞同!
cyj1236786 + 1 + 1 用心讨论,共获提升!
Wester + 1 + 1 谢谢@Thanks!
太冲 + 1 + 1 谢谢@Thanks!
sunnylds7 + 1 + 1 谢谢@Thanks!
yAYa + 3 + 1 膜拜师傅~ 学习了~
ljs01 + 1 + 1 用心讨论,共获提升!
丶Kevin + 1 谢谢@Thanks!
zy1234 + 1 + 1 热心回复!
chkds + 1 + 1 膜大佬~~~
cnmmb + 1 + 1 写的很好,就是我看不懂
工口大佐 + 1 + 1 我很赞同!
qwerttqqaz + 1 + 1 热心回复!
Ganlv + 1 + 1 中间的hook脚本是什么语言?不亲自试试,还真看不太懂啊
tomtory + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
泽雨天下 + 1 + 1 6666666666666666666666
z1220197 + 1 + 1 用心讨论,共获提升!
天蝎浪花 + 1 + 1 突然很佩服自己竟然能把它看完。。
Ravey + 1 + 1 谢谢@Thanks!
wgz001 + 3 + 1 都是寂寞惹的货
mycc + 1 + 1 厉害
小怪兽出现 + 1 + 1 热心回复!
很快再相见123 + 1 + 1 爆破辛苦了
朱朱你堕落了 + 1 + 1 一脸懵逼。只是纯粹来给你加分的。
lies2014 + 1 + 1 谢谢@Thanks!
iteamo + 1 + 1 热心回复!
whdfog + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
286733081 + 2 + 1 无形装逼,最为致命
黑的思想 + 1 + 1 用心讨论,共获提升!
小道观 + 1 + 1 全部看完,一脸懵逼。
方妍心 + 2 + 1 Sound大威武霸气
苏紫方璇 + 1 + 1 一脸懵逼
Eaysuild.xean + 2 + 1 .收下的。
aqtata + 1 + 1 用心讨论,共获提升!
初亦泽 + 2 + 1 大S
smallpox + 1 + 1 大佬就是大佬
610100 + 1 膜拜大佬!
lakshmi + 1 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

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

Aug.LuKai 发表于 2018-2-5 23:15
栋呀 发表于 2018-2-5 21:32
最近在破解一个vmp壳的软件    搞得好头疼 或许我不该碰vmp这个东西

我遇到的vmp壳,反虚拟机,反调试
wo4mt 发表于 2018-2-7 16:46
cunzhe0410 发表于 2018-2-7 16:02
斑竹。吃J开挂被封后,该怎么处理电脑才能玩下一个号,而导致不会再被封啊。

重装系统 233
张桓 发表于 2018-2-5 14:31
大佬刚才下载了你发的主播吃鸡专用 小白不会用,卡密怎么输入啊。谢谢大佬了
材鸟 发表于 2018-2-5 14:39
看了一半,然后就没有看下去的欲望了
索马里的海贼 发表于 2018-2-5 14:56
大佬终究是大佬,全程看不懂。
Webrobot 发表于 2018-2-5 15:31
大佬还是大佬。
东吴周郎 发表于 2018-2-5 16:13
学习了,牛逼
小道观 发表于 2018-2-5 17:33
非常有看下去的兴趣,但是看完了依然懵逼。
quenna 发表于 2018-2-5 17:46
看到sound这个名字 想起来以前某游戏的恶心的随机crc和内存检查代码就藏在sound.dll 里

点评

网易的xx,然后还是WL壳是不是?  发表于 2019-1-14 17:31
lies2014 发表于 2018-2-5 19:55
大佬的文章必须顶贴加分
苏子陌 发表于 2018-2-5 20:06
版主用的什么破解工具
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-21 19:31

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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