(2023.7.24)软件加密与解密-2-1-程序分析方法[XDbg].md
阅读原文时间:2023年08月31日阅读:5

body { font-size: 15px; color: rgba(51, 51, 51, 1); background: rgba(255, 255, 255, 1); font-family: Helvetica, Arial, "PingFang SC", "Microsoft YaHei", "WenQuanYi Micro Hei", "tohoma,sans-serif"; margin: 0; padding: 10% }
h1 { font-size: 2.2em; font-weight: 700; line-height: 1.1; padding-top: 16px; margin-bottom: 4px }
h2, h3, h4, h5, h6 { line-height: 1.5em; margin-top: 2.2em; margin-bottom: 4px }
h2 { color: rgba(255, 255, 255, 1) !important; background-color: rgba(255, 155, 152, 1); border-left: 12px solid rgba(255, 126, 121, 1); padding: 1px 1px 1px 20px }
h3 { font-weight: 700; font-size: 1.2em; line-height: 1.4; margin: 10px 0 5px; padding-top: 10px }
h4 { font-weight: 700; text-transform: uppercase; font-size: 1.1em; line-height: 1.4; margin: 10px 0 5px; padding-top: 10px }
h5, h6 { font-size: 0.9em }
h5 { font-weight: bold; text-transform: uppercase }
h6 { font-weight: normal; color: rgba(170, 170, 170, 1) }
img { width: 100%; border-radius: 5px; display: block; margin-bottom: 15px; height: auto }
dl, ol, ul { margin-top: 12px; margin-bottom: 20px; padding-left: 5%; line-height: 1.8 }
p { margin: 0 0 20px; padding: 0; line-height: 1.8 }
a { color: rgba(242, 47, 39, 1); text-decoration: none }
a:hover { color: rgba(245, 88, 82, 1); text-decoration: underline }
a:focus { outline-offset: -2px }
blockquote { font-size: 1em; font-style: normal; padding: 30px 38px; margin: 0 0 15px; position: relative; line-height: 1.8; text-indent: 0; border: none; color: rgba(136, 136, 136, 1) }
blockquote:before { content: "“"; left: 12px; top: 0; color: rgba(224, 224, 224, 1); font-size: 4em; font-family: Arial, serif; line-height: 1em; font-weight: 700; position: absolute }
blockquote:after { content: "”"; right: 12px; bottom: -31px; color: rgba(224, 224, 224, 1); font-size: 4em; font-family: Arial, serif; line-height: 1em; font-weight: 700; position: absolute }
strong, dfn { font-weight: 700 }
em, dfn { font-style: italic; font-weight: 400 }
del { text-decoration: line-through }
pre { margin: 0 0 25px; font-size: 13px; line-height: 1.42857; word-break: break-all; word-wrap: break-word; border-radius: 4px; white-space: pre-wrap; display: block; background: rgba(248, 248, 248, 1); padding: 10px 20px; border: none; color: rgba(102, 102, 102, 1); font-family: Courier, sans-serif }
code { color: rgba(199, 37, 78, 1); background-color: rgba(249, 242, 244, 1); border-radius: 4px; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; padding: 2px 4px; font-size: 90% }
p>code { color: rgba(199, 38, 78, 1); background-color: rgba(249, 242, 244, 1); font-size: 0.95em; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px }
figure { margin: 1em 0 }
figcaption { font-size: 0.75em; padding: 0.5em 2em; margin-bottom: 2em }
figure img { margin-bottom: 0 }
hr { border: 0; height: 1px; background: linear-gradient(90deg, rgba(204, 204, 204, 1), rgba(51, 51, 51, 1), rgba(204, 204, 204, 1)) rgba(51, 51, 51, 1) }
ol p, ul p { margin-bottom: 0 }
li { margin-bottom: 0.75em; margin-top: 0.75em }
ol#footnotes { font-size: 0.95em; padding-top: 1em; margin: 20px 0; border-top: 1px solid rgba(234, 234, 234, 1); counter-reset: footer-counter 0; list-style: none; color: rgba(85, 85, 85, 1); padding-left: 5% }
ol#footnotes li { margin-bottom: 10px; margin-left: 16px; font-weight: 400; line-height: 2; list-style-type: none }
ol#footnotes li:before { content: counter(footer-counter) ". "; counter-increment: footer-counter 1; font-weight: 800; font-size: 0.95em }
@keyframes highfade { 0% { } 20% { background-color: rgba(255, 255, 0, 1) } 100% { } }
@-webkit-keyframes highfade{0%{background-color:none}20%{background-color:yellow}100%{background-color:none}}
a:target, ol#footnotes li:target, sup a:target { animation-name: highfade; animation-duration: 2s; animation-iteration-count: 1; animation-timing-function: ease-in-out; -webkit-animation-name: highfade; -webkit-animation-duration: 2s; -webkit-animation-iteration-count: 1; -webkit-animation-timing-function: ease-in-out }
a:target { border: 0; outline: 0 }
a:target { border: 0; outline: 0 }
a:target { border: 0; outline: 0 }

每天一个技术点

(2023.7.24)软件加密与解密-2-1-程序分析方法[XDbg]

本文作者:XDbgPYG(小吧唧)

发布时间:2023年7月24日

内容概要:练一道题

img { box-shadow: 0 0 2px rgba(6, 24, 44, 0.4), 0 4px 6px -1px rgba(6, 24, 44, 0.65), inset 0 1px rgba(255, 255, 255, 0.08) }

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-1-%E8%BD%AF%E4%BB%B6%E4%BF%9D%E6%8A%A4%E6%8A%80%E6%9C%AF%5BXDbg%5D-1.png)

程序名:CrackMeDemo.tvmp.1.exe

程序界面长相如下:

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-1.png)

程序内存长相如下:

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-2.png)

程序内存字符串长相如下:

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-3.png)

看样子是个 MFC 程序(“应用程序向导生成的本地应用程序”、“CWINAPP”)

除此之外有用的信息似乎就是 “恭喜你,注册成功!” 了。

1.1 学习反调试

扔进 OllyDbg 里,F9跑起来。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-4.png)

查看 OllyDbg 日志,并无太多有用信息,只是知道它跑了俩个异常。

  1. 浮点数除以零
  2. 内存访问违规

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-5.png)

嗯。。想想有没有办法定位反调试代码范围。

通过例子来学习反调试,点击图片开始学习。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-6.png)

这是我刚才 CV 过来的反调试例子。看样子我们可以试试通过 API 断点,来定位反调试。

if (IsDebuggerPresent())
    ExitProcess(-1);

BOOL bDebuggerPresent;
if (TRUE == CheckRemoteDebuggerPresent(GetCurrentProcess(), &bDebuggerPresent) &&
    TRUE == bDebuggerPresent)
    ExitProcess(-1);

1.2 跟踪反调试

在 CheckRemoteDebuggerPresent 函数下断点,程序断下后,Ctrl + F9 出 CALL。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-7.png)

似乎走到了 ".tvm" 这个代码段来了,简单的使用下我们在日后编写的分析工具 - “基于 CPU 模拟的 xxx ” 。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-8.png)

好的,成功模拟到了 0x040157A 这个地址。通过反汇编代码可以看出,这个代码块似乎含有多个反调试函数,有俩个 jcc 指令跳转到了含有 CALL ExitThread 指令的基本块。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-9.png)

F9 运行到 0x040157A 里,由于我们的反反调试插件强大,所以CheckRemoteDebuggerPresent 返回了 0 ,即程序未被调试的意思。

继续模拟程序,运行到 IsDebuggerPresent 函数中。嗯,是刚才我们学过的反调试内容。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-10.png)

1.3 总结 Call 运行流程

1.3.0 随便看看

将程序扔入 IDA 中 F5 继续分析。根据 IDA 提供的符号,我们大致可以看出这个反调试是在执行 MFC m = new M(b,c) 后才开始检测的。这个信息对于我们完整还原这个程序至关重要,没错,我想把这个程序还原掉~

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-12.png)

1.3.1 检测到调试后会执行什么?

让我们看看程序检测调试到后会做些什么?

发现有个 sub_4031f0 call,学过设计模式的朋友应该知道单例模式:即一个类负责一个功能。所以 sub_403530 我是优先不管的。

  if ( cObf_CheckRemoteDebug() == 1 || cObf_IsDebug() == 1 )
  {
    v4 = sub_403530(1);                         // thiscall 不用理他,估计就是销毁 Dialog 用的。
    sub_4031F0(v4);                             // cdeclCall 有点意思~
    ExitThread(8u);
  }

对 sub_4031f0 扫引用,发现有个未被 Ida 识别成函数的地址(0x4021B6)。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-13.png)

转到 0x4021B6 看看,发现有个 call MessageBoxA ,字符串参数为 byte_428D64 。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-14.png)

用 OD 转到 byte_428D64 看看是什么内容。运气不错,直逼关键内容。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-15.png)

让我们对 0x4021B6 附近的代码进行简单的分析。发现一个循环代码,跳转到 loc_401F9A 看看。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-16.png)

发现了一个立即数:8。(如果你足够细心就可以发现,这是我们可输入的用户名的最大长度)

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-17.png)

看样子关键算法代码,我们已经定位到了,即在 0x00401FA9 附近。

1.4 拿下第一个符号:MFC_INIT

经过刚才的分析,我们基本可以判断这个 Call 是在做 MFC 初始化 + AntiDebuger 操作了。将其记录下来~ 这是我们逆向出来的第一个符号。这是一个重要的阶段性胜利。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-11.png)

1.5 Patch 掉反调试

这里用最容易被 Anti 掉的过检测方式来过掉反调试。将其 leave ret 即可过掉反调试。(还有内存校验没有解决)

可以看到,这里程序已经正常运行了。hiahia。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-18.png)

OD 转到 0x00401FA9 下查看情况,似乎 IDA 有好多代码没有识别出来,有点小尴尬哈。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-19.png)

找了下函数头部 0x00401B35 ,回到 IDA ,一路选中未识别的代码,按下 C 键完成格式转换。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-20.png)

先静态分析看看函数的控制流程好了,在这里我给出我认为简洁有用的信息。

.text:00401DA6                 call    ?UpdateData@CWnd@@QAEHH@Z ; CWnd::UpdateData(int)
.text:00401DFC                 call    ?GetDlgItem@CWnd@@QBEPAV1@H@Z ; CWnd::GetDlgItem(int)
.text:00401E1F                 call    ?GetDlgItem@CWnd@@QBEPAV1@H@Z ; CWnd::GetDlgItem(int)

.text:00401E9A                 cmp     dword ptr [ebp-8C4h], 8
.text:00401EA1                 jge     short loc_401F21

.text:00402204                 repe cmpsd
.text:00402206                 jnz     short loc_40221C
.text:00402208                 push    0               ; unsigned int
.text:0040220A                 push    0               ; lpCaption
.text:0040220C                 push    offset Text     ; lpText
.text:00402211                 mov     ecx, [ebp-8D0h] ; this
.text:00402217                 call    ?MessageBoxA@CWnd@@QAEHPBD0I@Z ; CWnd::MessageBoxA(char const *,char const *,uint)

用 OD 看看和 MsgBoxA 有关的信息 text:00402204 repe cmpsd。经过测试,发现算法不允许输入中文字符串,尴尬了。

uN: XXXXXDbg
pW: EasyXEasyXEasyXEasyXEasyXEasyXEasyXEasyXEasyX

程序是明码比较,这似乎意味着我们在算法部分可以轻松一下了 O(∩_∩)O。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-21.png)

用 IDA 进行 F5 操作。嗯,好模糊的代码,看样子需要清理花指令才能看清楚。(可是现在已经是 22:11:38 了,一天要结束了,就不写脚本清理了)

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-22.png)

数了下大致的代码行数,只有 213 行汇编,直接用 OD 调试还原掉好了。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-23.png)

好了,回到让我们到 0x0401E9A 下断点.

.text:00401E9A                 cmp     dword ptr [ebp-8C4h], 8
.text:00401EA1                 jge     short loc_401F21

经过我努力的跟踪,还原出了如下代码,发现程序获取了代码段的内容并参与到了算法的计算当中,真是个不错的设计。

这样做的话,程序如果直接爆破,生成出来的 serial 必然是错的,难怪程序会直接明码比较,原来暗藏着一股气。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-24.png)

打开 VS ,编写我们的第一段 KeyGen。

// KeyGen.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>

unsigned char t[0x0010] =
{
0xf7, 0xff, 0xff, 0x89, 0x8d, 0x4c, 0xf7, 0xff, 0xff, 0xc7, 0x85, 0x48, 0xf7, 0xff, 0xff, 0x14
};

unsigned char t2[0x0010] =
{
0x07, 0x82, 0x19, 0xe8, 0x1f, 0xfe, 0xff, 0xff, 0x0f, 0xb6, 0xd0, 0x85, 0xd2, 0x74, 0x05, 0xe9
};

void getUn2(unsigned char* _un, unsigned char* _un2)
{
    unsigned char* un = _un;
    unsigned char* un2 = _un2;

    for (size_t i = 0; i < 8; i++)
    {
        int a = (int)*(char*)(t+i);
        int a2 = (int)*(char*)(un + i) ^ i;
        un2[i] = a2 ^ a;
        int b = (int)*(char*)(t2 + i);
        int b2 = (int)*(char*)(un2 + i) ;
        un2[i] =  b2 ^ b;
    }

}

int main()
{
    std::cout << "Hello KeyGen!\n";
    unsigned char uN[] = "XXXXXDbg";
    unsigned char* uN2 = new unsigned char[sizeof(uN)];
    getUn2(uN,uN2);

    return 0;
}

a8 24 bc 3a ce f3 4c 40 // cd fd fd fd
A8 24 BC 3A CE F3 4C 40 // 00 00 00 00

可以看到结果完全正确,让我们继续还原。发现了一个未知的值,[EBP - 0x828],OD 往上翻翻,看看它的算法。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-25.png)

可以看到一个循环很多次的代码,结合刚才的经验,可以看出这个 constV 也是通过代码段的内容算出来的。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-26.png)

这个函数就不用还原了,取消所有软件断点,然后在 0x0401C53 下硬件执行断点,拿到 constV 即可。

constV = 0xCF238EE8;
int constV = 0xCF238EE8;
*(int*)((int*)uN2) ^= constV;
*(int*)((int*)uN2+1) ^= constV;

接下来又是一个循环,估计又有好多表要 CV 下来,哈哈,可以看到依旧循环 8 次。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-27.png)

继续单步~发现了三个 flag 将这段汇编还原成 C 代码~。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-28.png)

还原代码如下。

for (size_t i = 0; i < 8; i++)
    {
        flag1 = ((uN2[i] & 0xE0) +  (((uN2[i] & 0xE0 )>> 24) & 0x1F)) >> 5;
        flag2 = (uN2[i] & 0x1C) + (((uN2[i] & 0x1C) >> 24) & 3) >> 2;
        flag3 = uN2[i] & 0x3;

        int flag4 = i / 3;
        int id = i >> 24;
        if (id == 2)
        {
          // .......
        }

        if (id == 1)
        {
          // .......
        }

        if (id == 0)
        {
          // .......
        }
    }

继续单步跟踪,在这块代码中,我们发现几张 table 和新的 flag ,翻翻汇编代码看看 flag 有什么意义。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-29.png)

联系上文可以发现,它存储的就是正确的注册码 Serial。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-30.png)

将 table dump 出来将这个基本块还原成 C 代码。

unsigned char t3_834[0x0040] =
{
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x40, 0xed, 0x9f, 0xf5,
0x26, 0x3a, 0x6f, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

unsigned char t4_87c[0x00B0] =
{
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7a, 0x6e, 0x69, 0xc9, 0x1b, 0x40, 0x00, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x18, 0x00, 0xa0, 0xf0, 0x18, 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x00, 0x00, 0x40, 0xed, 0x9f, 0xf5, 0x26, 0x3a, 0x6f, 0x8f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

unsigned char t5_864[0x0090] =
{
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x18, 0x00, 0xa0, 0xf0, 0x18, 0x00,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x40, 0xed, 0x9f, 0xf5,
0x26, 0x3a, 0x6f, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

        if (id == 0)
        {
            serial[i] = t3_834[flag2];
            serial[i+1] = t4_87c[flag3];
            serial[i+2] = t5_864[flag1];
        }

好了,接下来我们继续还原其他分支,这是 id == 1 的情况。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-31.png)

还原代码如下。

        if (id == 1)
        {
            serial[i] = t3_834[flag1];
            serial[i + 1] = t4_87c[flag2];
            serial[i + 2] = t5_864[flag3];
        }

这是 id == 2 的情况,发现了俩张新的 table:t6、t7 。

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-32.png)

将新的 table dump 下来,还原 C 代码如下。

unsigned char t6_83c[0x001E] =
{
0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5A, 0x7F, 0x00, 0xF6, 0x9A, 0xE2, 0xF7, 0x9B, 0x50, 0x09, 0x80, 0x00, 0x00
};

unsigned char t7_874[0x003C] =
{
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x19, 0x00, 0xC9, 0x1B, 0x40, 0x00,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C
};

        if (id == 2)
        {
            serial[i] = t5_864[flag3];
            serial[i+ 1] = t6_83c[flag1];
            serial[i + 2] = t7_874[flag2];
        }

在测试的时候,发现 serial 对不上,原因是因为我忘记还原这条汇编指令了、flag4 和 id 的关系搞错了 、constV 提取错了。

IMUL    EAX, EAX, 0x3

//int constV = 0xCF238EE8;
int constV = 0xE0698E5C;

int flag4 = i % 3;
int id = flag4;

最终输出结果如下。

XXXXXDbg
Vi7Vk21OvWk6Um21LxRj0Ui0

show time

%E8%BD%AF%E4%BB%B6%E5%8A%A0%E5%AF%86%E4%B8%8E%E8%A7%A3%E5%AF%86-2-1-%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95%5BXDbg%5D-33.png)

看样子这个程序被巧妙的绕过了未知的 vm 保护,实际上经过我的测试,这个程序并无 vm 保护,有基于堆栈的花指令混淆。

这在学习第三章也就是下一章代码混淆时,会将其清除~

日后再补。

CrackMeDemo.tvmp.1.exe

KeyGen

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章