首页
社区
课程
招聘
[原创]指令壳开源
发表于: 2021-5-6 21:45 19737

[原创]指令壳开源

2021-5-6 21:45
19737

  在把壳子开源之前,我会先对VMProtect1.70.4这个版本做一个简单的分析。在这几天分析过程中,我感受到了VMProtect的威力,并得出一个结论:分析VMProtect非常耗时间,如果没有做好与之长期斗争的准备,很难有实用的成果。另外,由于我第一次分析VMProtect,有分析不对的地方或者术语用得不恰当的地方,希望老萌萌们能指出来,我立即修改,不能误人子弟。分析的样本有三份,我放到了附件里面。
  壳子我是去年写的,当时刚刚看了<<加密与解密>>第四版的第21章,我估摸了一下,自己可以写出来,然后就写出来了。在写之前,我记得当时还在bilibili观看了哈工大姜守旭教授教授的编译原理这门课程的视频,了解了大概就开干,看视频这个操作,对我写指令壳起了一种壮胆的效果。现在要开源,我又熟悉了下整个项目的流程。代码写得有点乱,我会画一张加壳时的流程图做一个直观的说明,和其他一些要点说明,以减少读代码时遇到的困惑。如果遇到调试或者编译问题,可以留言,我看到会及时回复。指令壳源码我会上传到附件。

写一个简单程序来测试:(ps:这个程序在vmp样本一文件夹)

在OD中打开,函数在0x401080这个位置。
clipboard_31_
打开vmp,开始加壳:
clipboard_41_
下拉列表选择最快速度,其他不选择。
clipboard_7_
程序加好壳子后,用OD打开,开始分析:
clipboard_28_
0x401080这儿已经变为jmp了,跳到.vmp0这节里面:
clipboard_2_

以上操作是把寄存器压到栈里,执行完后如下图:

clipboard_38_

寄存器压栈完成后,会先计算出调度表的地址。
[esp+48]这个值就是入口push 4A781400 这个值,经过计算后得到调度表的地址。调度表地址存放在esi寄存器里。

如下,内存5里显示的就是经过加密的调度表:
clipboard

然后按F7,到下面那个位置,箭头指向的三步,ebp指向的是真实堆栈,edi就是虚拟机的上下文环境(VMContext)。edi指向的堆栈空间,最大的作用就是存放寄存器。
clipboard_5_

clipboard_25_

在接下来的步骤中,通过在esi指向的调度表中取值,然后把ebp所指向的寄存器的值,挨个放到edi的虚拟环境中。
clipboard_39_
至此,虚拟机的环境构建完成,准备工作已经做好。

接下来进入正题,程序会通过edi寄存器取ebx的值,取两次,第一次的值压入[ebp],第二次压入[ebp+4],然后进入一个handler块进行运算。
这就是那个handler块:

可以把上面的handler块命名为Handler_NOT_AND

那么,可以把以上的运算过程可以表示成这样:not(ebx) and not(ebx)

执行xor eax,ebx这条指令的时候,虚拟机会多次调用Handler_NOT_AND 块,整个流程可以记录为如下形式:

T = not(not(ebx) and not(ebx)) and not(not(eax) and not(eax));即为:T = ebx and eax;
S= not(eax) and not(ebx);
最终结果:ret= not(T) and not(S)。
通过写程序来验证,与虚拟机算出来的0x690035一致,说明流程记录没有问题。那么,xor eax,ebx可以用这个表达式来表示:eax = not(ebx and eax) and not(not(eax) and not(ebx))。
clipboard_43_
执行完xor eax,ebx之后,eax寄存器的位置在edi中的会变:
clipboard_35_

下一个xor eax,ebx 和上面的操作是一样的,这个操作完了,eax=0x004A3035。
eax寄存器的位置在edi中又变了:
clipboard_42_

按F7单步跟,(...省略不重要的部分),接着,程序把edi中所保存的寄存器,再吐出来给ebp所指向的堆栈空间,然后ebp赋值给esp,最后再pop到真实寄存器,退出虚拟机。
clipboard_24_
退出虚拟机:

clipboard_33_

测试程序和上面一样。(ps:这个程序在vmp样本二文件夹)
clipboard_3_
下拉列表选择最快速度,再把调试器勾选上,其他不选择。
clipboard_19_

加壳完成后,打开CFF来查看,程序会新增一节.vmp1,程序入口也在这节里面。
clipboard_11_

clipboard_30_

此外,还构建了一个TLS表:(但在这儿作用似乎不大)
clipboard_27_

程序执行到入口后,按F7单步跟,步骤和上面“01速度最快"分析时相差无几,会先构建虚拟机环境。
虚拟环境构建完成后,接着按F7单步跟,我的想法是,很快就能找到一些反调试的线索,但是跟了几个小时,发现不对劲了,和上面“01
速度最快"分析时用手工跟踪,完全不在一个数量级的。天气又大,整个人木在那里。后来,想到在退出虚拟机那个地方下断,方法就是搜索vmp1这节的ret或者ret xx,最终找到两个地方,一个是调度器ret xx,这个不管,另一个就是下图所给出的,在ret 0x40处下断。按F9程序跑起来后,会断在这里,能看到右边寄存器窗口的字符串。这个位置,可以作为过掉检测调试器的突破口。
clipboard_14_
当然,最好的办法应该是在一些能检测出调试器的API函数下断。
vmp1.70.4这个版本,开启调试器检测后,程序会依次调用以下的API来检测是否有调试器存在:

注意:API下断时,不要在头部下断,虚拟机会对有些API函数的头部进行0xCC检测,比如在这个程序中,虚拟机执行到GetThreadContext函数之前,会对GetThreadContext函数的头部进行0xCC检测。建议:没有特殊状况,对API下断时要避开在头部下断。

此外,在调用CloseHandle之前,虚拟机会手工构造一个SEH异常处理例程,如果调用成功,没出现异常,那么虚拟机会移除这个SEH。假如调用CloseHandle触发异常,那么将万劫不复,程序进入0x4A99AE后,你会寸步难行,我这儿遇到的是非法写入的异常,程序一直卡在那里。

clipboard_10_

想过掉CloseHandle检测,可以在CloseHandle头部直接返回(eax=0),然后恢复选区即可。

测试程序:(ps:这个程序在vmp样本三文件夹)

用OD打开,找到test_vmp函数的位置:0x4010E0。
clipboard_36_

打开vmp,开始加壳:
clipboard_22_

选择最大保护。
clipboard_26_

把加壳后的程序,拖入OD,程序断在了入口处:
clipboard_29_

找到0x4010E0,下一个硬件断点,然后按F9让程序跑起来:
clipboard_16_

程序断在了这里,按F7单步跟踪:
clipboard_17_

程序会先构建虚拟机环境,上面已经分析了,这里省略。
clipboard_18_

开始进入正题,因为程序在加壳的时候勾选了隐藏常量和内存保护,对我这种初等选手,所以刚开始的时候就遇到了困难。
在第一条指令(mov eax,[esp+4])中,虚拟机会先对[esp+4]解码,又因为4是常量,所以虚拟机刚开始的时候,会对这个常量解密操作。
大概步骤:程序会在esi指向的调度表读取四个字节,并且在解密过程,还会读取多次,来对常量解密。esp寄存器也是加密了的,解码操作和解码常量差不多。

mov eax,[esp+4] 模型是:mov 寄存器,内存
这种模式的指令会走如下的handler块:

关于xor eax, ebx 指令,上面有分析过,除了垃圾指令,其他没变:

在mov g_num,eax这条指令中,虚拟机对g_num内存地址也是加密了的,解密时候,程序会对esi指向的调度表读取四个字节,并且会读取多次,经过计算最终得到g_num的内存地址。
mov g_num,eax 模型是:mov 内存地址,寄存器
这种模式的指令会走如下handler块:

  关于隐藏常量和内存保护的解密过程,只是跟了几遍,了解了大概流程,没有具体分析,退出虚拟机时,加密寄存器,这个解密模式和隐藏常量和内存保护的解密过程似乎差不多。总的来说,这次分析过程是失败的,因为隐藏常量、内存保护以及离开虚拟机时加密寄存器的解密过程没有分析出来,只是把汇编指令在虚拟机中的handler块找出来了。我觉得,这些解密操作,正是vmprotect虚拟机最精华的部分之一,在跟踪这些解密操作的时候,我脑袋都大了,暂时先搁在这儿,做一些更有意义的事情(^_^)。这节可以省略不看。如果有像我一样的初等选手,跟起来又有点费劲,又想了解这个解密过程的,可以在看雪搜搜,有很多大神都应该分析过。

项目名称:指令壳框架
功能:可以对32位可执行程序加壳(*.exe)
编译器:vs2019(编译模式采用的是Debug模式,也就是调试模式)
开发语言:C、C++、内联汇编
解决方案:一个解决方案,两个项目(VMProtect、Stub,VMProtect是现实核心功能,Stub是外壳部分)

Common文件夹里封装了一些类:
CString类即是字符串操作的类,支持字符串和整型混合相加(字符串+(DWORD)16进制/10进),生成一个字符串。(注意:加16进制时,前面要加DWORD表示这是16进制。)
PE类封装了处理PE文件格式一些函数,比如文件拉伸、修复重定位表、添加新节等等。
FileOpenration类是文件操作类,封装了打开文件、删除文件、保存文件、创建子进程等等一些函数。

clipboard_8_
clipboard_40_

在加壳过程中,要频繁用到内存申请、内存释放的操作,为了防止内存泄漏,我封装了一个类(AllocMemory)用来申请内存,
这个类的作用就是只管申请内存,不用管释放,这个类会自动释放内存:

vmp编写流程图

程序外观:
clipboard_1_
clipboard_12_

实验:对test_vmp函数加壳

拖入OD,在0x401010这个位置:
clipboard_23_

打开vmp_1.0,开始加壳:
clipboard_44_
clipboard_21_

回到项目,点击编译:
clipboard_34_

用OD打开,经过加了花指令的从IAT表拷贝过来的API的跳转地址,每次执行时,样式都不一样。
第一次打开:
clipboard_20_

用OD第二次打开:
clipboard_4_

此外,对加了该指令壳的函数,每次进入该函数后,指令也会变,这些操作都是在外壳中完成的,具体请参考Stub项目。

  指令分析器的作用:把要保护的指令,翻译为中间表示。我用的是BeaEngine引擎,所以在解析指令的时候,需要遵循BeaEngine反汇编引擎的规则。
指令分析器的主框架如下:

上面这个解析器,对一条指令是从右往左解析的,比如这条指令:mov eax,eax
翻译为中间表示就是:

handler操作和数据是分别保存的,仍然以上面那条指令为例:

内存操作处理起来比较麻烦,至少对我来说是如此,MemoryMiddle()函数用来专门处理内存操作。
例如这条指令 mov dword ptr[eax+ecx*4+0x401000],eax,可以译成如下的中间表示:

此外,局部变量的操作,比如这条指令:mov dword ptr[ebp-0x8],eax,仍然可以用MemoryMiddle函数来翻译:

下面举个完整的例子:

上面这个函数,翻译为中间表示如下:

垃圾指令构造器的设计很简单,对我来说,难点在于垃圾指令的选择,有些指令是不能作为垃圾指令,改变普通寄存器的指令我没有用,比如AAA指令,会改变eax寄存器的值。
下面是垃圾指令的构造器核心函数:

ProduceRubbishOpecode函数,每被调用一次就可以构造一条垃圾指令。

把要用到的handler全部放到一个表格中归类整理,如下图:
191710p9gyvz88fxe8i1qd
先来举一个例子,比如指令:xor eax,eax

上面每一个中间表示的handler都有对应一个函数:

vmtest.h和vmtest.cpp分别存放了所有handler块的声明和具体实现。请参考VMProtect项目。

IAT解密模块、反调试模块以及花指令构造器,都在Stub项目中,Stub.dll动态库是整个程序的外壳部分。
IAT加密过程:
第一步把IAT表转存到一个临时数据结构中,然后清除IAT和INT表,最后把临时数据结构中的函数名称加密。这步是在VMProtect项目中完成的。
第二步在Stub中解密这个临时数据结构,解密之后,再加密,并且加上花指令。
花指令构造器具体实现在JunkCode.cpp文件中。以下列出花指令构造器的核心函数:

测试的时候,我只是对常用的指令添加了handler块,还有很多指令是没有处理的,那么,程序在加壳过程中,如果有jmp或者jxx跳转到未知指令(未知指令是指没有添加handler的指令,找不到匹配),就会出错,此时,则应该先检查是否有未知指令,并添加相应的handler块。
添加方式:以inc指令为例子
第一步:
在vmtest.h中添加声明CString vINC(char VR0, char VR1);
clipboard_15_

第二步:在vmtest.cpp中实现其函数功能。
clipboard_6_

第三步:
在VMLoader2.cpp,把55改成56,在g_FunName数组里添加{vINC,"inc ","vINC "},注意"inc "和"vINC ",后面有一个空格,
不然程序在匹配inc指令的时候匹配不上,就会把inc当成不可模拟指令来处理。
clipboard_13_

  这个加壳程序,设计上有先天缺陷,这可以归咎于我正向开发的基础不扎实,还有就是只掌握了编译原理的一些皮毛知识,好些地方都有点乱,像是硬怼的,很多地方现在还能看到打斗的痕迹。整个程序,由于在设计上的缺陷,使得虚拟机不能对寄存器进行轮转操作。另外,汇编指令是直接换成handler块的,中间没有先对汇编指令进行任何变形。所以,这只是一个模拟vmprotect的最最简单的指令壳子。

编译时,请采用Debug和x86模式:
clipboard_9_

编译时,可能会遇到的编码错误:
clipboard_37_

Stub项目运行库选择多线程(/MT)
clipboard88

#include <Windows.h>
#include <iostream>
 
void __declspec(naked) test_vmp(int a, int b)
{
    /*__asm {
        mov eax,dword ptr[esp+4]
        mov ecx,dword ptr[esp+8]
        add eax,ecx
        ret
    }*/
    __asm {
        xor eax,ebx
        xor eax, ebx
        ret
    }
}
 
int main()
{
    test_vmp(1, 2);
    printf("%d\n", x);
    system("pause");
    return 0;
}
#include <Windows.h>
#include <iostream>
 
void __declspec(naked) test_vmp(int a, int b)
{
    /*__asm {
        mov eax,dword ptr[esp+4]
        mov ecx,dword ptr[esp+8]
        add eax,ecx
        ret
    }*/
    __asm {
        xor eax,ebx
        xor eax, ebx
        ret
    }
}
 
int main()
{
    test_vmp(1, 2);
    printf("%d\n", x);
    system("pause");
    return 0;
}
//入口
00401080| jmp debug_test2.vmp.4A77D2                                       | Debug_test2.cpp:5
 
004A77D2| push 4A781400                                                    |
004A77D7| call debug_test2.vmp.4A6B9F                                      |
 
004A6B9F| jmp debug_test2.vmp.4A703A                                       |
 
004A703A| push esi                                                         | esi:_mainCRTStartup
004A703B| jmp debug_test2.vmp.4A52E8                                       |
 
004A52E8| pushfd                                                           |
004A52E9| push D3AC6D6A                                                    |
004A52EE| mov byte ptr ss:[esp+4],8F                                       |
004A52F3| pushfd                                                           |
004A52F4| pop dword ptr ss:[esp+4]                                         | [esp+4]:___use_sse2_mathfcns+4A78
004A52F8| jmp debug_test2.vmp.4A64C1                                       |
 
004A64C1| call debug_test2.vmp.4A5FE9                                      |
 
004A5FE9| pushad                                                           |
004A5FEA| mov dword ptr ss:[esp+24],ebp                                    | [esp+24]:_mainCRTStartup
004A5FEE| push esp                                                         |
004A5FEF| pushfd                                                           |
004A5FF0| push 72B57CE7                                                    |
004A5FF5| pushfd                                                           |
004A5FF6| mov dword ptr ss:[esp+30],eax                                    | eax:___use_sse2_mathfcns+2D1
004A5FFA| mov byte ptr ss:[esp],cl                                         |
004A5FFD| call debug_test2.vmp.4A701F                                      |
 
004A701F| call debug_test2.vmp.4A5A25                                      |
 
004A5A25| jmp debug_test2.vmp.4A6BC5                                       |
 
 
004A6BC5| mov dword ptr ss:[esp+34],edx                                    | [esp+34]:___use_sse2_mathfcns+2D1
004A6BC9| call debug_test2.vmp.4A5C3D                                      |
 
 
004A5C3D| call debug_test2.vmp.4A6681                                      |
 
004A6681| mov dword ptr ss:[esp+38],edx                                    | [esp+38]:___use_sse2_mathfcns+2D1
004A6685| push dword ptr ss:[esp+8]                                        | [esp+8]:___use_sse2_mathfcns+42C0
004A6689| mov dword ptr ss:[esp+38],ecx                                    | [esp+38]:___use_sse2_mathfcns+2D1, ecx:___use_sse2_mathfcns+2D1
004A668D| push E7FE4EC3                                                    |
004A6692| mov byte ptr ss:[esp],dh                                         |
004A6695| lea esp,dword ptr ss:[esp+3C]                                    |
004A6699| jmp debug_test2.vmp.4A632E                                       |
 
004A632E| btr si,6                                                         |
004A6333| push edi                                                         |
004A6334| push 20AD5139                                                    |
004A6339| xchg esi,ecx                                                     | esi:_mainCRTStartup, ecx:___use_sse2_mathfcns+2D1
004A633B| call debug_test2.vmp.4A6129                                      |
 
004A6129| mov dword ptr ss:[esp+4],ebx                                     |
004A612D| movsx esi,cl                                                     | esi:___use_sse2_mathfcns+2D1
004A6130| pop ecx                                                          | ecx:"U嬱Q梓\x0E"
004A6131| btc di,cx                                                        |
004A6135| pushad                                                           |
004A6136| mov dword ptr ss:[esp+1C],0                                      |
004A613E| stc                                                              |
004A613F| jmp debug_test2.vmp.4A70CF
//入口
00401080| jmp debug_test2.vmp.4A77D2                                       | Debug_test2.cpp:5
 
004A77D2| push 4A781400                                                    |
004A77D7| call debug_test2.vmp.4A6B9F                                      |
 
004A6B9F| jmp debug_test2.vmp.4A703A                                       |
 
004A703A| push esi                                                         | esi:_mainCRTStartup
004A703B| jmp debug_test2.vmp.4A52E8                                       |
 
004A52E8| pushfd                                                           |
004A52E9| push D3AC6D6A                                                    |
004A52EE| mov byte ptr ss:[esp+4],8F                                       |
004A52F3| pushfd                                                           |
004A52F4| pop dword ptr ss:[esp+4]                                         | [esp+4]:___use_sse2_mathfcns+4A78
004A52F8| jmp debug_test2.vmp.4A64C1                                       |
 
004A64C1| call debug_test2.vmp.4A5FE9                                      |
 
004A5FE9| pushad                                                           |
004A5FEA| mov dword ptr ss:[esp+24],ebp                                    | [esp+24]:_mainCRTStartup
004A5FEE| push esp                                                         |
004A5FEF| pushfd                                                           |
004A5FF0| push 72B57CE7                                                    |
004A5FF5| pushfd                                                           |
004A5FF6| mov dword ptr ss:[esp+30],eax                                    | eax:___use_sse2_mathfcns+2D1
004A5FFA| mov byte ptr ss:[esp],cl                                         |
004A5FFD| call debug_test2.vmp.4A701F                                      |
 
004A701F| call debug_test2.vmp.4A5A25                                      |
 
004A5A25| jmp debug_test2.vmp.4A6BC5                                       |
 
 
004A6BC5| mov dword ptr ss:[esp+34],edx                                    | [esp+34]:___use_sse2_mathfcns+2D1
004A6BC9| call debug_test2.vmp.4A5C3D                                      |
 
 
004A5C3D| call debug_test2.vmp.4A6681                                      |
 
004A6681| mov dword ptr ss:[esp+38],edx                                    | [esp+38]:___use_sse2_mathfcns+2D1
004A6685| push dword ptr ss:[esp+8]                                        | [esp+8]:___use_sse2_mathfcns+42C0
004A6689| mov dword ptr ss:[esp+38],ecx                                    | [esp+38]:___use_sse2_mathfcns+2D1, ecx:___use_sse2_mathfcns+2D1
004A668D| push E7FE4EC3                                                    |
004A6692| mov byte ptr ss:[esp],dh                                         |
004A6695| lea esp,dword ptr ss:[esp+3C]                                    |
004A6699| jmp debug_test2.vmp.4A632E                                       |
 
004A632E| btr si,6                                                         |
004A6333| push edi                                                         |
004A6334| push 20AD5139                                                    |
004A6339| xchg esi,ecx                                                     | esi:_mainCRTStartup, ecx:___use_sse2_mathfcns+2D1
004A633B| call debug_test2.vmp.4A6129                                      |
 
004A6129| mov dword ptr ss:[esp+4],ebx                                     |
004A612D| movsx esi,cl                                                     | esi:___use_sse2_mathfcns+2D1
004A6130| pop ecx                                                          | ecx:"U嬱Q梓\x0E"
004A6131| btc di,cx                                                        |
004A6135| pushad                                                           |
004A6136| mov dword ptr ss:[esp+1C],0                                      |
004A613E| stc                                                              |
004A613F| jmp debug_test2.vmp.4A70CF
 
 
004A70CF| mov esi,dword ptr ss:[esp+48]                                    |
004A70D3| btr bp,sp                                                        |
004A70D7| jmp debug_test2.vmp.4A53AF                                       |
 
004A53AF| movzx bp,bl                                                      |
004A53B3| btc bp,si                                                        |
004A53B7| rol esi,18                                                       |
004A53BA| push 124E6496                                                    |
004A53BF| inc esi                                                          |
004A53C0| jmp debug_test2.vmp.4A6C85                                       |
004A70CF| mov esi,dword ptr ss:[esp+48]                                    |
004A70D3| btr bp,sp                                                        |
004A70D7| jmp debug_test2.vmp.4A53AF                                       |
 
004A53AF| movzx bp,bl                                                      |
004A53B3| btc bp,si                                                        |
004A53B7| rol esi,18                                                       |
004A53BA| push 124E6496                                                    |
004A53BF| inc esi                                                          |
004A53C0| jmp debug_test2.vmp.4A6C85                                       |
 
 
 
 
004A53F7 | rol ah,6                                                         |
004A53FA | sbb edx,esp                                                      |
004A53FC | mov eax,dword ptr ss:[ebp]                                       |
004A53FF | jmp debug_test2.vmp.4A5BC4   
 
004A5BC4 | cmc                                                              |
004A5BC5 | mov edx,dword ptr ss:[ebp+4]                                     |
004A5BC8 | push 25584F9E                                                    |
004A5BCD | pushad                                                           |
004A5BCE | clc                                                              |
004A5BCF | bt cx,C                                                          |
004A5BD4 | not eax                                                          |
004A5BD6 | pushad                                                           |
004A5BD7 | bt cx,bx                                                         |
004A5BDB | call debug_test2.vmp.4A5D63                                      |
 
004A5D63 | cmc                                                              |
004A5D64 | not edx                                                          |
004A5D66 | cmp edi,F7A6A772                                                 |
004A5D6C | stc                                                              |
004A5D6D | stc                                                              |
004A5D6E | stc                                                              |
004A5D6F | and eax,edx                                                      |
004A5D71 | jmp debug_test2.vmp.4A5A3F                                       |
 
004A5A3F | jmp debug_test2.vmp.4A6E72                                       |
 
004A6E73 | pushfd                                                           |
004A6E74 | mov dword ptr ss:[ebp+4],eax                                     |
004A6E77 | jmp debug_test2.vmp.4A564D                                       |
 
----------------------------------------------------------------------------------------------------------
 
//化简之后
004A53FC | mov eax,dword ptr ss:[ebp]                                       |                                                                            
004A5BC5 | mov edx,dword ptr ss:[ebp+4]                                     |                                                       
004A5BD4 | not eax                                                          |                                                     
004A5D64 | not edx                                                          |                                                          
004A5D6F | and eax,edx                                                      |
004A6E74 | mov dword ptr ss:[ebp+4],eax                                     |
004A6E77 | jmp debug_test2.vmp.4A564D                                       |
004A53F7 | rol ah,6                                                         |
004A53FA | sbb edx,esp                                                      |
004A53FC | mov eax,dword ptr ss:[ebp]                                       |
004A53FF | jmp debug_test2.vmp.4A5BC4   
 
004A5BC4 | cmc                                                              |
004A5BC5 | mov edx,dword ptr ss:[ebp+4]                                     |
004A5BC8 | push 25584F9E                                                    |
004A5BCD | pushad                                                           |
004A5BCE | clc                                                              |
004A5BCF | bt cx,C                                                          |
004A5BD4 | not eax                                                          |
004A5BD6 | pushad                                                           |
004A5BD7 | bt cx,bx                                                         |
004A5BDB | call debug_test2.vmp.4A5D63                                      |
 
004A5D63 | cmc                                                              |
004A5D64 | not edx                                                          |
004A5D66 | cmp edi,F7A6A772                                                 |
004A5D6C | stc                                                              |
004A5D6D | stc                                                              |
004A5D6E | stc                                                              |
004A5D6F | and eax,edx                                                      |
004A5D71 | jmp debug_test2.vmp.4A5A3F                                       |
 
004A5A3F | jmp debug_test2.vmp.4A6E72                                       |
 
004A6E73 | pushfd                                                           |
004A6E74 | mov dword ptr ss:[ebp+4],eax                                     |
004A6E77 | jmp debug_test2.vmp.4A564D                                       |
 
----------------------------------------------------------------------------------------------------------
 
//化简之后
004A53FC | mov eax,dword ptr ss:[ebp]                                       |                                                                            
004A5BC5 | mov edx,dword ptr ss:[ebp+4]                                     |                                                       
004A5BD4 | not eax                                                          |                                                     
004A5D64 | not edx                                                          |                                                          
004A5D6F | and eax,edx                                                      |
004A6E74 | mov dword ptr ss:[ebp+4],eax                                     |
004A6E77 | jmp debug_test2.vmp.4A564D                                       |
 
 
 
 
 
 
 
 
 
 
IsDebuggerPresent
CheckRemoteDebuggerPresent
GetThreadContext
CloseHandle
NtQueryInformationProcess
NtSetInformationThread
//关于这些函数介绍,看雪里有很多大神发了反调试相关的帖子,搜一下就能找到。
IsDebuggerPresent
CheckRemoteDebuggerPresent
GetThreadContext
CloseHandle
NtQueryInformationProcess
NtSetInformationThread
//关于这些函数介绍,看雪里有很多大神发了反调试相关的帖子,搜一下就能找到。
 
 
 
#include <Windows.h>
#include <iostream>
int g_num = 0;
 
void __declspec(naked) test_vmp(int a, int b)
{
    __asm {
        mov eax,[esp+4] // [esp+4] == a
        mov ebx,[esp+8] // [esp+8] == b
        xor eax, ebx
        mov g_num,eax
        ret
    }
}
 
void test2()
{
    test_vmp(0x10, 0x21);
    printf("%X\n", g_num);
}
 
int main()
{   
    test2();   
    system("pause");
    return 0;
}
#include <Windows.h>
#include <iostream>
int g_num = 0;
 
void __declspec(naked) test_vmp(int a, int b)
{
    __asm {
        mov eax,[esp+4] // [esp+4] == a
        mov ebx,[esp+8] // [esp+8] == b
        xor eax, ebx
        mov g_num,eax
        ret
    }
}
 
void test2()
{
    test_vmp(0x10, 0x21);
    printf("%X\n", g_num);
}
 
int main()
{   
    test2();   
    system("pause");
    return 0;
}
 
 
 
 
 
 
 
 
004A6AFF | 66:0FB6C3                | movzx ax,bl                         |
004A6B03 | F6D0                     | not al                              |
004A6B05 | 66:0FB6C3                | movzx ax,bl                         |
004A6B09 | 66:0FBEC2                | movsx ax,dl                         |
004A6B0D | 8B45 00                  | mov eax,dword ptr ss:[ebp]          |
004A6B10 | 60                       | pushad                              |
004A6B11 | E9 41140000              | jmp debug_test2.vmp.4A7F57          |
 
004A6A55 | 36:8B00                  | mov eax,dword ptr ss:[eax]          |
004A6A58 | 55                       | push ebp                            |
004A6A59 | E9 8A000000              | jmp debug_test2.vmp.4A6AE8          |
 
004A6AE8 | 882C24                   | mov byte ptr ss:[esp],ch            |
004A6AEB | FF3424                   | push dword ptr ss:[esp]             |
004A6AEE | 8945 00                  | mov dword ptr ss:[ebp],eax          |
004A6AF1 | FF3424                   | push dword ptr ss:[esp]             |
004A6AF4 | 9C                       | pushfd                              |
004A6AF5 | 9C                       | pushfd                              |
004A6AF6 | 8D6424 38                | lea esp,dword ptr ss:[esp+38]       |
004A6AFA | E9 83150000              | jmp debug_test2.vmp.4A8082          |
 
------------------------------------------------------
可以化简为:
004A6B0D | 8B45 00                  | mov eax,dword ptr ss:[ebp]          |
004A6A55 | 36:8B00                  | mov eax,dword ptr ss:[eax]          |
004A6AEE | 8945 00                  | mov dword ptr ss:[ebp],eax          |
 
可以把上面的handler块命名为Handler_Reg_Mem
004A6AFF | 66:0FB6C3                | movzx ax,bl                         |
004A6B03 | F6D0                     | not al                              |
004A6B05 | 66:0FB6C3                | movzx ax,bl                         |
004A6B09 | 66:0FBEC2                | movsx ax,dl                         |
004A6B0D | 8B45 00                  | mov eax,dword ptr ss:[ebp]          |
004A6B10 | 60                       | pushad                              |
004A6B11 | E9 41140000              | jmp debug_test2.vmp.4A7F57          |
 
004A6A55 | 36:8B00                  | mov eax,dword ptr ss:[eax]          |
004A6A58 | 55                       | push ebp                            |
004A6A59 | E9 8A000000              | jmp debug_test2.vmp.4A6AE8          |
 
004A6AE8 | 882C24                   | mov byte ptr ss:[esp],ch            |
004A6AEB | FF3424                   | push dword ptr ss:[esp]             |
004A6AEE | 8945 00                  | mov dword ptr ss:[ebp],eax          |
004A6AF1 | FF3424                   | push dword ptr ss:[esp]             |
004A6AF4 | 9C                       | pushfd                              |
004A6AF5 | 9C                       | pushfd                              |
004A6AF6 | 8D6424 38                | lea esp,dword ptr ss:[esp+38]       |
004A6AFA | E9 83150000              | jmp debug_test2.vmp.4A8082          |
 
------------------------------------------------------
可以化简为:
004A6B0D | 8B45 00                  | mov eax,dword ptr ss:[ebp]          |
004A6A55 | 36:8B00                  | mov eax,dword ptr ss:[eax]          |
004A6AEE | 8945 00                  | mov dword ptr ss:[ebp],eax          |
 
可以把上面的handler块命名为Handler_Reg_Mem
004A6113 | push ebp                                   |
004A6114 | lahf                                       |
004A6115 | pushad                                     |
004A6116 | mov eax,dword ptr ss:[ebp]                 |
004A6119 | rcr dh,6                                   |
004A611C | bts dx,7                                   |
004A6121 | bts dx,1                                   |
004A6126 | mov edx,dword ptr ss:[ebp+4]               |
004A6129 | stc                                        |
004A612A | not eax                                    |
004A612C | pushfd                                     |
004A612D | push dword ptr ss:[esp]                    |
004A6130 | not edx                                    |
004A6132 | jmp debug_test2.vmp.4A66E3                 |
004A6137 | not esi                                    |
004A6139 | mov byte ptr ss:[esp],dh                   |
004A613C | pushfd                                     |
004A613D | push C19B900A                              |
004A6142 | pushfd                                     |
004A6143 | lea esp,dword ptr ss:[esp+4C]              |
004A6147 | jmp debug_test2.vmp.4A60CA                 |
 
004A66E3 | clc                                        |
004A66E4 | and eax,edx                                |
004A66E6 | push edi                                   |
004A66E7 | push esi                                   |
004A66E8 | jmp debug_test2.vmp.4A61EF                 |
 
004A61EF | mov dword ptr ss:[ebp+4],eax               |
004A61F2 | mov byte ptr ss:[esp+C],31                 | 31:'1'
004A61F7 | mov byte ptr ss:[esp+C],65                 | 65:'e'
004A61FC | push A8B985C4                              |
004A6201 | mov word ptr ss:[esp+C],sp                 |
004A6206 | pushfd                                     |
004A6207 | pop dword ptr ss:[esp+34]                  |
004A620B | mov byte ptr ss:[esp+8],ah                 |
004A620F | call debug_test2.vmp.4A78E2                |
 
----------------------------------------------------------------------
//可以化简为:
004A6116 | mov eax,dword ptr ss:[ebp]                 |
004A6126 | mov edx,dword ptr ss:[ebp+4]               |
004A612A | not eax                                    |
004A6130 | not edx                                    |
004A66E4 | and eax,edx                                |
004A61EF | mov dword ptr ss:[ebp+4],eax               |
004A6113 | push ebp                                   |
004A6114 | lahf                                       |
004A6115 | pushad                                     |
004A6116 | mov eax,dword ptr ss:[ebp]                 |
004A6119 | rcr dh,6                                   |
004A611C | bts dx,7                                   |
004A6121 | bts dx,1                                   |
004A6126 | mov edx,dword ptr ss:[ebp+4]               |
004A6129 | stc                                        |
004A612A | not eax                                    |
004A612C | pushfd                                     |
004A612D | push dword ptr ss:[esp]                    |
004A6130 | not edx                                    |
004A6132 | jmp debug_test2.vmp.4A66E3                 |
004A6137 | not esi                                    |
004A6139 | mov byte ptr ss:[esp],dh                   |
004A613C | pushfd                                     |
004A613D | push C19B900A                              |
004A6142 | pushfd                                     |
004A6143 | lea esp,dword ptr ss:[esp+4C]              |
004A6147 | jmp debug_test2.vmp.4A60CA                 |
 
004A66E3 | clc                                        |
004A66E4 | and eax,edx                                |
004A66E6 | push edi                                   |
004A66E7 | push esi                                   |
004A66E8 | jmp debug_test2.vmp.4A61EF                 |
 
004A61EF | mov dword ptr ss:[ebp+4],eax               |
004A61F2 | mov byte ptr ss:[esp+C],31                 | 31:'1'
004A61F7 | mov byte ptr ss:[esp+C],65                 | 65:'e'
004A61FC | push A8B985C4                              |
004A6201 | mov word ptr ss:[esp+C],sp                 |
004A6206 | pushfd                                     |
004A6207 | pop dword ptr ss:[esp+34]                  |
004A620B | mov byte ptr ss:[esp+8],ah                 |
004A620F | call debug_test2.vmp.4A78E2                |
 
----------------------------------------------------------------------
//可以化简为:
004A6116 | mov eax,dword ptr ss:[ebp]                 |
004A6126 | mov edx,dword ptr ss:[ebp+4]               |
004A612A | not eax                                    |
004A6130 | not edx                                    |
004A66E4 | and eax,edx                                |
004A61EF | mov dword ptr ss:[ebp+4],eax               |
004A69C7 | 04 08                    | add al,8                            |
004A69C9 | 60                       | pushad                              |
004A69CA | 66:05 7B36               | add ax,367B                         |
004A69CE | 8B45 00                  | mov eax,dword ptr ss:[ebp]          |
004A69D1 | 20D6                     | and dh,dl                           |
004A69D3 | 66:F7D2                  | not dx                              |
004A69D6 | 08C2                     | or dl,al                            |
004A69D8 | 8B55 04                  | mov edx,dword ptr ss:[ebp+4]        |
004A69DB | 68 37EDD2A5              | push A5D2ED37                       |
004A69E0 | 66:81FF 7052             | cmp di,5270                         |
004A69E5 | 84CB                     | test bl,cl                          |
004A69E7 | F8                       | clc                                 |
004A69E8 | 83C5 08                  | add ebp,8                           |
004A69EB | FF7424 04                | push dword ptr ss:[esp+4]           |
004A69EF | 66:896424 14             | mov word ptr ss:[esp+14],sp         |
004A69F4 | E9 94F4FFFF              | jmp debug_test2.vmp.4A5E8D          |
 
 
004A5E8D | 8910                     | mov dword ptr ds:[eax],edx          |
004A5E8F | 9C                       | pushfd                              |
004A5E90 | 66:895424 04             | mov word ptr ss:[esp+4],dx          |
004A5E95 | 8D6424 2C                | lea esp,dword ptr ss:[esp+2C]       |
004A5E99 | E9 E4210000              | jmp debug_test2.vmp.4A8082          |
 
-------------------------------------------------------------------------------
可以化简为:
004A69CE | 8B45 00                  | mov eax,dword ptr ss:[ebp]          |
004A69D8 | 8B55 04                  | mov edx,dword ptr ss:[ebp+4]        |
004A69E8 | 83C5 08                  | add ebp,8                           |
004A5E8D | 8910                     | mov dword ptr ds:[eax],edx          |
 
可以把上面的handler块命名为Handler_Mem_Reg
004A69C7 | 04 08                    | add al,8                            |
004A69C9 | 60                       | pushad                              |
004A69CA | 66:05 7B36               | add ax,367B                         |
004A69CE | 8B45 00                  | mov eax,dword ptr ss:[ebp]          |
004A69D1 | 20D6                     | and dh,dl                           |
004A69D3 | 66:F7D2                  | not dx                              |
004A69D6 | 08C2                     | or dl,al                            |
004A69D8 | 8B55 04                  | mov edx,dword ptr ss:[ebp+4]        |
004A69DB | 68 37EDD2A5              | push A5D2ED37                       |
004A69E0 | 66:81FF 7052             | cmp di,5270                         |
004A69E5 | 84CB                     | test bl,cl                          |
004A69E7 | F8                       | clc                                 |
004A69E8 | 83C5 08                  | add ebp,8                           |
004A69EB | FF7424 04                | push dword ptr ss:[esp+4]           |
004A69EF | 66:896424 14             | mov word ptr ss:[esp+14],sp         |
004A69F4 | E9 94F4FFFF              | jmp debug_test2.vmp.4A5E8D          |
 
 
004A5E8D | 8910                     | mov dword ptr ds:[eax],edx          |
004A5E8F | 9C                       | pushfd                              |
004A5E90 | 66:895424 04             | mov word ptr ss:[esp+4],dx          |
004A5E95 | 8D6424 2C                | lea esp,dword ptr ss:[esp+2C]       |
004A5E99 | E9 E4210000              | jmp debug_test2.vmp.4A8082          |
 
-------------------------------------------------------------------------------
可以化简为:
004A69CE | 8B45 00                  | mov eax,dword ptr ss:[ebp]          |
004A69D8 | 8B55 04                  | mov edx,dword ptr ss:[ebp+4]        |
004A69E8 | 83C5 08                  | add ebp,8                           |
004A5E8D | 8910                     | mov dword ptr ds:[eax],edx          |
 
可以把上面的handler块命名为Handler_Mem_Reg
 
 
#pragma once
#include <vector>
#include <basetsd.h>
using namespace std;
 
class AllocMemory
{
    vector<char*>p;   
public:
    virtual ~AllocMemory()
    {
        for (int i = 0; i < p.size(); i++)
        {
            if (p[i]==0)
            {
                continue;
            }
            free(p[i]);
            p[i] = 0;
        }
        p.clear();
    }
 
public:
    template<typename T>
    T auto_malloc( ULONG_PTR MAXSIZE)
    {
        T tmp = (T)malloc(MAXSIZE);
        memset((char*)tmp, 0, MAXSIZE);
        p.push_back((char*)tmp);
        return tmp;
    }
};
#pragma once
#include <vector>
#include <basetsd.h>
using namespace std;
 
class AllocMemory
{
    vector<char*>p;   
public:
    virtual ~AllocMemory()
    {
        for (int i = 0; i < p.size(); i++)
        {
            if (p[i]==0)
            {
                continue;
            }
            free(p[i]);
            p[i] = 0;
        }
        p.clear();
    }
 
public:
    template<typename T>
    T auto_malloc( ULONG_PTR MAXSIZE)
    {
        T tmp = (T)malloc(MAXSIZE);
        memset((char*)tmp, 0, MAXSIZE);
        p.push_back((char*)tmp);
        return tmp;
    }
};
 
 
void __declspec(naked) test_vmp(int a, int b)
{
    __asm {
        mov eax, [esp + 4]
        mov eax, [esp + 4]
        mov eax, [esp + 4]
        mov eax,[esp+4] // [esp+4] == a
        mov ebx,[esp+8] // [esp+8] == b
        xor eax, ebx
        mov g_num,eax
        ret
    }
}
int main()
{
    test_vmp(1,2);
    system("pause");
    return;
}
void __declspec(naked) test_vmp(int a, int b)
{
    __asm {
        mov eax, [esp + 4]
        mov eax, [esp + 4]
        mov eax, [esp + 4]
        mov eax,[esp+4] // [esp+4] == a
        mov ebx,[esp+8] // [esp+8] == b
        xor eax, ebx
        mov g_num,eax
        ret
    }
}
int main()
{
    test_vmp(1,2);
    system("pause");
    return;
}
 
 
 
 
 
//解析要保护的指令,翻译为中间表示
void MiddleRepresent(DISASM disAsm)
{
/*----------------------------------------------------------------------------------*/
/*    1、是否有操作3                                   */
/*----------------------------------------------------------------------------------*/
    if (NO_ARGUMENT != disAsm.Argument3.ArgType)
    {
        switch (disAsm.Argument3.ArgType & 0xF0000000)
        {
        case REGISTER_TYPE: //寄存器
            break;
        case MEMORY_TYPE: //内存
            break;
        case CONSTANT_TYPE://常数
            break;
        default:
            break;
        }
    }
 
 /*----------------------------------------------------------------------------------*/
/*    2、是否有操作2                                   */
/*----------------------------------------------------------------------------------*/
    if (NO_ARGUMENT != disAsm.Argument2.ArgType)
    {
        switch (disAsm.Argument2.ArgType & 0xF0000000)
        {
        case REGISTER_TYPE: //寄存器
            break;
        case MEMORY_TYPE: //内存
            break;
        case CONSTANT_TYPE://常数
            break;
        default:
            break;
        }
    }
 
 /*----------------------------------------------------------------------------------*/
/*    3、是否有操作1                                   */
/*----------------------------------------------------------------------------------*/
    if (NO_ARGUMENT != disAsm.Argument1.ArgType)
    {
        switch (disAsm.Argument1.ArgType & 0xF0000000)
        {
        case REGISTER_TYPE: //寄存器
            break;
        case MEMORY_TYPE: //内存
            break;
        case CONSTANT_TYPE://常数
            break;
        default:
            break;
        }
    }
 
 /*----------------------------------------------------------------------------------*/
/*    4、处理普通handler                                   */
/*----------------------------------------------------------------------------------*/
 
//省略...
 
/*----------------------------------------------------------------------------------*/
/*    5、判断是否有辅助handler                                   */
/*----------------------------------------------------------------------------------*/
    if (
        0x10000000 != disAsm.Argument1.ArgType ||
        0x10000000 != disAsm.Argument2.ArgType ||
        0x10000000 != disAsm.Argument3.ArgType
        )
    {
            if (NO_ARGUMENT != disAsm.Argument1.ArgType)
            {
            switch (disAsm.Argument1.ArgType & 0xF0000000)
            {
            case REGISTER_TYPE: //寄存器
                break;
            case MEMORY_TYPE: //内存
                break;
            case CONSTANT_TYPE://常数
                break;
            default:
                break;
            }
        }
     }
}
//解析要保护的指令,翻译为中间表示
void MiddleRepresent(DISASM disAsm)
{
/*----------------------------------------------------------------------------------*/
/*    1、是否有操作3                                   */
/*----------------------------------------------------------------------------------*/
    if (NO_ARGUMENT != disAsm.Argument3.ArgType)
    {
        switch (disAsm.Argument3.ArgType & 0xF0000000)
        {
        case REGISTER_TYPE: //寄存器
            break;
        case MEMORY_TYPE: //内存
            break;
        case CONSTANT_TYPE://常数
            break;
        default:
            break;
        }
    }
 
 /*----------------------------------------------------------------------------------*/
/*    2、是否有操作2                                   */
/*----------------------------------------------------------------------------------*/
    if (NO_ARGUMENT != disAsm.Argument2.ArgType)
    {
        switch (disAsm.Argument2.ArgType & 0xF0000000)
        {
        case REGISTER_TYPE: //寄存器
            break;
        case MEMORY_TYPE: //内存
            break;
        case CONSTANT_TYPE://常数
            break;
        default:
            break;
        }
    }
 
 /*----------------------------------------------------------------------------------*/
/*    3、是否有操作1                                   */
/*----------------------------------------------------------------------------------*/
    if (NO_ARGUMENT != disAsm.Argument1.ArgType)
    {
        switch (disAsm.Argument1.ArgType & 0xF0000000)
        {
        case REGISTER_TYPE: //寄存器
            break;
        case MEMORY_TYPE: //内存
            break;
        case CONSTANT_TYPE://常数
            break;
        default:
            break;
        }
    }
 
 /*----------------------------------------------------------------------------------*/
/*    4、处理普通handler                                   */
/*----------------------------------------------------------------------------------*/
 
//省略...
 
/*----------------------------------------------------------------------------------*/
/*    5、判断是否有辅助handler                                   */
/*----------------------------------------------------------------------------------*/
    if (
        0x10000000 != disAsm.Argument1.ArgType ||
        0x10000000 != disAsm.Argument2.ArgType ||
        0x10000000 != disAsm.Argument3.ArgType
        )
    {
            if (NO_ARGUMENT != disAsm.Argument1.ArgType)
            {
            switch (disAsm.Argument1.ArgType & 0xF0000000)
            {
            case REGISTER_TYPE: //寄存器
                break;
            case MEMORY_TYPE: //内存
                break;
            case CONSTANT_TYPE://常数
                break;
            default:
                break;
            }
        }
     }
}
vPushReg  VR_ecx  //操作2
vPushReg  VR_eax //操作1
vMOV            //普通handler
vPopReg   VR_eax //辅助handler
vPushReg  VR_ecx  //操作2
vPushReg  VR_eax //操作1
vMOV            //普通handler
vPopReg   VR_eax //辅助handler
vPushReg  VR_ecx  //操作2
vPushReg  VR_eax //操作1
vMOV            //普通handler
vPopReg   VR_eax //辅助handler
 
把VR_ecx、VR_eax、VR_eax分离出来保存在一个数据表的结构体中。
翻译就可以这样表示了:
vPushReg
vPushReg
vMOV          
vPopReg
vPushReg  VR_ecx  //操作2
vPushReg  VR_eax //操作1
vMOV            //普通handler
vPopReg   VR_eax //辅助handler
 
把VR_ecx、VR_eax、VR_eax分离出来保存在一个数据表的结构体中。
翻译就可以这样表示了:
vPushReg
vPushReg
vMOV          
vPopReg
vPushReg   //eax
vPushImm4  //4
vPushReg4  //ecx
vMUL_MEM  //*
vPushReg4 //eax
vAdd4    //+
vPushImm4 //0x401000
vAdd     //+
vWriteMemDs4
vPushReg   //eax
vPushImm4  //4
vPushReg4  //ecx
vMUL_MEM  //*
vPushReg4 //eax
vAdd4    //+
vPushImm4 //0x401000
vAdd     //+
vWriteMemDs4
vPushImm4  //0xFFFFFFF8
vPushReg4 //ebp
vAdd4
8会被BeaEngine引擎解析为0xFFFFFFF8,ebp-0x80xFFFFFFF8+ebp是等价的
vPushImm4  //0xFFFFFFF8
vPushReg4 //ebp
vAdd4
8会被BeaEngine引擎解析为0xFFFFFFF8,ebp-0x80xFFFFFFF8+ebp是等价的

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2021-5-7 18:28 被舒默哦编辑 ,原因: 更正错误
上传的附件:
收藏
免费 42
支持
分享
打赏 + 1.00雪花
打赏次数 1 雪花 + 1.00
 
赞赏  demoscene   +1.00 2021/05/24 精品文章~
最新回复 (43)
雪    币: 10874
活跃值: (14669)
能力值: ( LV13,RANK:400 )
在线值:
发帖
回帖
粉丝
2

2021-5-6 23:20
1
雪    币: 1319
活跃值: (1960)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
现在逆向VMP全都研究编译器了...
2021-5-7 01:45
1
雪    币: 5194
活跃值: (9722)
能力值: ( LV9,RANK:181 )
在线值:
发帖
回帖
粉丝
4
感谢分享!!!
2021-5-7 08:43
1
雪    币: 791
活跃值: (404)
能力值: ( LV4,RANK:51 )
在线值:
发帖
回帖
粉丝
5
牛啊
2021-5-7 09:18
1
雪    币: 23080
活跃值: (3432)
能力值: (RANK:648 )
在线值:
发帖
回帖
粉丝
6
感谢分享!致敬!
2021-5-7 10:22
1
雪    币: 3359
活跃值: (10992)
能力值: ( LV9,RANK:240 )
在线值:
发帖
回帖
粉丝
7
真大神!
2021-5-7 11:38
1
雪    币: 1378
活跃值: (3067)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
感谢分享!
2021-5-7 12:06
1
雪    币: 2325
活跃值: (4908)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
厉害啊·!~
2021-5-7 12:12
1
雪    币: 210
活跃值: (646)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
10
牛贝塔
2021-5-7 12:41
1
雪    币: 1475
活跃值: (14652)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
11

2021-5-7 13:12
1
雪    币: 2989
活跃值: (4911)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
12
统一回复,谢谢老萌萌们捧场。以后有问题,还得向你们请教。
2021-5-7 13:21
1
雪    币: 1042
活跃值: (500)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13

以后还更新吗,建议放gitee github

最后于 2021-5-7 14:23 被Rookietp编辑 ,原因:
2021-5-7 14:21
1
雪    币: 2325
活跃值: (2304)
能力值: ( LV6,RANK:89 )
在线值:
发帖
回帖
粉丝
14
好家伙
2021-5-7 14:28
1
雪    币: 1385
活跃值: (5609)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
15
666666666666
2021-5-7 15:08
1
雪    币: 29357
活跃值: (3910)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
16
感谢分享!致敬!
2021-5-7 15:15
1
雪    币: 2415
活跃值: (2160)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
666666送你,别客气哈。。
2021-5-7 15:28
1
雪    币: 3796
活跃值: (1882)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
2021-5-7 16:01
1
雪    币: 78
活跃值: (1875)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
双手大拇指
2021-5-7 16:08
1
雪    币: 14530
活跃值: (17548)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
20
感谢分享
2021-5-7 17:11
1
雪    币: 2745
活跃值: (1846)
能力值: ( LV12,RANK:298 )
在线值:
发帖
回帖
粉丝
21
感谢分享

"此外,还构建了一个STL表:(但在这儿作用似乎不大)"
这里有个小错误, STL->TLS
2021-5-7 17:25
1
雪    币: 2989
活跃值: (4911)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
22
KuCha128 感谢分享[em_63] "此外,还构建了一个STL表:(但在这儿作用似乎不大)" 这里有个小错误, STL->TLS
已改
2021-5-7 18:29
0
雪    币: 3738
活跃值: (3872)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
23
感谢分享!
2021-5-7 19:13
1
雪    币: 1129
活跃值: (2761)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
24
感谢分享
2021-5-7 23:30
1
雪    币: 8209
活跃值: (6434)
能力值: ( LV12,RANK:207 )
在线值:
发帖
回帖
粉丝
25
大佬终于来看雪发文了
2021-5-8 07:40
1
游客
登录 | 注册 方可回帖
返回
//