首页
社区
课程
招聘
2
[原创]看雪CTF2019Q3 第二题WP
发表于: 2019-9-25 17:00 7033

[原创]看雪CTF2019Q3 第二题WP

2019-9-25 17:00
7033

一、概述

1  依然是dephi+脚本形式;
2  与前版相比加入了反调试;
3 与前版相比解密部分全部用虚拟机实现,不会用代码执行非虚拟机指令;
4 使用异常处理进入真正的解密函数。
二、脚本获取
1、通过跟踪函数Tfrmcrackme_FormShow,可以获取脚本,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
Function tion sptWBCallback(spt_wb_id,spt_wb_name,optionstr)
{
    url='#sptWBCallback:id=';
    url=url+spt_wb_id+';
    eventName='+spt_wb_name;
    if(optionstr) 
        url=url+';
    params=optionstr';
    location=url;
}
 
<script language="vbscript">
function alert(msg_str)
    MsgBox msg_str,vbOKOnly + vbExclamation + vbApplicationModal,""
     
End Function
     
</script>
 
 
<body bgcolor=f0f0f0 topmargn=0 leftmargn=0 >、
    <center>
    <br><br><br>
    <input value="" id="pswd" size=39>
    </input>
    <br><br><br>
    <input type=button value="checkMyFlag" onclick="ckpswd();">
    </center>
 
</body>
 
function ckpswd() {
    key = "Simpower91";
    a = document.all.pswd.value;
    if (a.indexOf(key) == 0) {
        l = a.length;
        i = key.length;
        sptWBCallback(a.substring(i, l));
    else {
        alert("wrong!<" + a + "> is not my GUID ;-)");
        return "1234";
    }
}
 
function ok() {
    alert("congratulations!");
}
 
CMShowingChanged
Tfrmcrackme_ApplicationEvents1Message
_Tfrmcrackme_FormCreate
 
 
about:blank#sptWBCallback:id=111;eventName=undefined
2 在脚本部分要求输入sn前部分字符必须是“Simpower91”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
Function tion sptWBCallback(spt_wb_id,spt_wb_name,optionstr)
{
    url='#sptWBCallback:id=';
    url=url+spt_wb_id+';
    eventName='+spt_wb_name;
    if(optionstr) 
        url=url+';
    params=optionstr';
    location=url;
}
 
<script language="vbscript">
function alert(msg_str)
    MsgBox msg_str,vbOKOnly + vbExclamation + vbApplicationModal,""
     
End Function
     
</script>
 
 
<body bgcolor=f0f0f0 topmargn=0 leftmargn=0 >、
    <center>
    <br><br><br>
    <input value="" id="pswd" size=39>
    </input>
    <br><br><br>
    <input type=button value="checkMyFlag" onclick="ckpswd();">
    </center>
 
</body>
 
function ckpswd() {
    key = "Simpower91";
    a = document.all.pswd.value;
    if (a.indexOf(key) == 0) {
        l = a.length;
        i = key.length;
        sptWBCallback(a.substring(i, l));
    else {
        alert("wrong!<" + a + "> is not my GUID ;-)");
        return "1234";
    }
}
 
function ok() {
    alert("congratulations!");
}
 
CMShowingChanged
Tfrmcrackme_ApplicationEvents1Message
_Tfrmcrackme_FormCreate
 
 
about:blank#sptWBCallback:id=111;eventName=undefined
2 在脚本部分要求输入sn前部分字符必须是“Simpower91”
3、然后通过sptWBCallback进入dephi回调函数执行校验。
三、回调函数定位-sncheck
在函数Tfrmcrackme_FormCreate中注册:0049945C
1
2
3
4
HIDWORD(v5) = v1;
  LODWORD(v5) = &sncheck;
  Teengine::TTeeFunction::InternalSetPeriod(*(Teengine::TTeeFunction **)(v1 + 824), v5);
  Idsyslogmessage::TIdSysLogMessage::SetTimeStamp(*(Idsyslogmessage::TIdSysLogMessage **)(v1 + 824), v6);

1
2
3
4
HIDWORD(v5) = v1;
  LODWORD(v5) = &sncheck;
  Teengine::TTeeFunction::InternalSetPeriod(*(Teengine::TTeeFunction **)(v1 + 824), v5);
  Idsyslogmessage::TIdSysLogMessage::SetTimeStamp(*(Idsyslogmessage::TIdSysLogMessage **)(v1 + 824), v6);

四、反调试
1、 在Tfrmcrackme_FormCreate中调用反调试相关函数477DDC
1
2
v10 = sub_477DDC((int)&cls_antiDebug_TAntiDebug, 1, 0);
  *(_DWORD *)(v1 + 828) = v10;

1
2
v10 = sub_477DDC((int)&cls_antiDebug_TAntiDebug, 1, 0);
  *(_DWORD *)(v1 + 828) = v10;

2、在Tfrmcrackme_FormCreate中貌似设置反调试函数:49978C
1
2
3
4
HIDWORD(v11) = v1;
  LODWORD(v11) = sub_49978C;
  Teengine::TTeeFunction::InternalSetPeriod(v10, v12, v13, v11);
  Idsyslogmessage::TIdSysLogMessage::SetTimeStamp(*(Idsyslogmessage::TIdSysLogMessage **)(v1 + 828), v14);
3、反调试函数477F64
1
2
3
4
HIDWORD(v11) = v1;
  LODWORD(v11) = sub_49978C;
  Teengine::TTeeFunction::InternalSetPeriod(v10, v12, v13, v11);
  Idsyslogmessage::TIdSysLogMessage::SetTimeStamp(*(Idsyslogmessage::TIdSysLogMessage **)(v1 + 828), v14);
3、反调试函数477F64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __usercall antiDebug5@<eax>(int a1@<eax>, int a2@<ebx>)
{
  int v2; // esi
  int v4; // [esp+0h] [ebp-408h]
 
  v2 = a1;
  Windows::FillMemory(&v4, 0x400u, 0);
  DeleteFiber(&v4);
  if ( GetLastError_0() == 0x57 )
  {
    a2 = 0;
    unknown_libname_1058(v2);
  }
  else
  {
    LOBYTE(a2) = 1;
    unknown_libname_1059(v2);
  }
  return a2;
}
4、反调试函数478110
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __usercall antiDebug5@<eax>(int a1@<eax>, int a2@<ebx>)
{
  int v2; // esi
  int v4; // [esp+0h] [ebp-408h]
 
  v2 = a1;
  Windows::FillMemory(&v4, 0x400u, 0);
  DeleteFiber(&v4);
  if ( GetLastError_0() == 0x57 )
  {
    a2 = 0;
    unknown_libname_1058(v2);
  }
  else
  {
    LOBYTE(a2) = 1;
    unknown_libname_1059(v2);
  }
  return a2;
}
4、反调试函数478110
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int __usercall antiDebug3@<eax>(int a1@<eax>, int a2@<ebx>)
{
  if ( *(_BYTE *)(__readfsdword(0x30u) + 2) )
  {
    LOBYTE(a2) = 1;
    unknown_libname_1059(a1);
  }
  else
  {
    a2 = 0;
    unknown_libname_1058(a1);
  }
  return a2;
}
5、反调试47814C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int __usercall antiDebug3@<eax>(int a1@<eax>, int a2@<ebx>)
{
  if ( *(_BYTE *)(__readfsdword(0x30u) + 2) )
  {
    LOBYTE(a2) = 1;
    unknown_libname_1059(a1);
  }
  else
  {
    a2 = 0;
    unknown_libname_1058(a1);
  }
  return a2;
}
5、反调试47814C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int __usercall antiDebug4@<eax>(int a1@<eax>, int a2@<ebx>)
{
  if ( *(_DWORD *)(__readfsdword(0x30u) + 104) & 0x70 )
  {
    LOBYTE(a2) = 1;
    unknown_libname_1059(a1);
  }
  else
  {
    a2 = 0;
    unknown_libname_1058(a1);
  }
  return a2;
}
6、反调试函数:477F64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int __usercall antiDebug4@<eax>(int a1@<eax>, int a2@<ebx>)
{
  if ( *(_DWORD *)(__readfsdword(0x30u) + 104) & 0x70 )
  {
    LOBYTE(a2) = 1;
    unknown_libname_1059(a1);
  }
  else
  {
    a2 = 0;
    unknown_libname_1058(a1);
  }
  return a2;
}
6、反调试函数:477F64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __usercall antiDebug5@<eax>(int a1@<eax>, int a2@<ebx>)
{
  int v2; // esi
  int v4; // [esp+0h] [ebp-408h]
 
  v2 = a1;
  Windows::FillMemory(&v4, 0x400u, 0);
  DeleteFiber(&v4);
  if ( GetLastError_0() == 0x57 )
  {
    a2 = 0;
    unknown_libname_1058(v2);
  }
  else
  {
    LOBYTE(a2) = 1;
    unknown_libname_1059(v2);
  }
  return a2;
}
7、反调试函数4780B8
1
2
3
4
5
6
7
8
9
10
int antiDebug7()
{
  HMODULE v0; // eax
  HANDLE v1; // eax
 
  v0 = LoadLibraryA("ntdll.dll");
  dword_49DCC0 = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD))GetProcAddress_0(v0, "NtSetInformationThread");
  v1 = GetCurrentThread();
  return dword_49DCC0(v1, 17, 0, 0);
}
8 、过掉反调试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#coding=utf-8
import struct
from idaapi import *
from idc import *
from idautils import *
 
dbg_write_memory(0x478070, '\xEB')#antiDebug2
refresh_debugger_memory()
 
dbg_write_memory(0x47812E, '\x90\x90')#antiDebug3
refresh_debugger_memory()
 
dbg_write_memory(0x47816C, '\x90\x90')#antiDebug4
refresh_debugger_memory()
 
dbg_write_memory(0x4781F4, '\x90\x90')#antiDebug6
refresh_debugger_memory()
 
dbg_write_memory(0x477F64, '\x33\xC0\xC3\x90')#antiDebug5
refresh_debugger_memory()
 
dbg_write_memory(0x4780B8, '\x33\xC0\xC3\x90')#antiDebug7
refresh_debugger_memory()
五、sncheck分析
1、异常处理函数注册
1
2
3
4
5
6
7
CODE:004994A7                 push    dword ptr fs:[eax]
CODE:004994AA                 mov     fs:[eax], esp
CODE:004994AD                 mov     eax, offset sub_475ED8
CODE:004994B2                 mov     edx, ds:off_49C3D8
CODE:004994B8                 mov     [edx+4], eax
CODE:004994BB                 mov     eax, ds:off_49C3D8
CODE:004994C0                 call    sub_46590C
其中sub_475ED8为异常处理函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
signed int __cdecl sub_475ED8(_DWORD *a1, int a2, int a3)
{
  signed int result; // eax
 
  result = 1;
  if ( !a1[1] )
  {
    if ( *a1 == 0xC0000096 )
    {
      *(_DWORD *)(a3 + 184) = realSnCheck;
      result = 0;
    }
    else if ( *a1 == 0xC00000FD )
    {
      *(_DWORD *)(a3 + 196) -= 256;
    }
  }
  return result;
}
其中 475EBC(realSnCheck)为异常0C0000096h处理函数
2、获取vmp指令
1
2
CODE:00499530                 call    GetVmpCode
CODE:00499535                 mov     [ebp+var_10], eax
其中 eax+4 为VMP指令地址,  eax+8为指令大小
3、产生异常,进入 475EBC(realSnCheck)
六、 realSnCheck( 475EBC )
1、realSnCheck  调用477778 与之前类似
     1)解密代码和指令
     2)判断加密的指令是否是真实代码,如果是,这将相应代码进行重定位动态执行
     3)如果是VMP指令,则进入虚拟机执行。
      本题没有真实代码,所有指令都为虚拟机代码
2、最终会进入476B8C(codeExe)函数中
七、codeExe函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
int __stdcall codeExe(int a1, int codeData, int retAddr, int dataOfFile, _DWORD *a5, int *a6, _DWORD *a7)
{
  struct globalInfo *global; // ebx
  struct vmpInfo *vmpInfo; // esi
  int v9; // edi
  int v10; // ecx
  int v11; // esi
  int v12; // edx
  int *v14; // [esp+1Ch] [ebp-380h]
  void *v15; // [esp+20h] [ebp-37Ch]
  int *v16; // [esp+24h] [ebp-378h]
  void *v17; // [esp+28h] [ebp-374h]
  int v18; // [esp+34h] [ebp-368h]
  int *v19; // [esp+38h] [ebp-364h]
  int v20; // [esp+3Ch] [ebp-360h]
  char v21; // [esp+40h] [ebp-35Ch]
  char v22; // [esp+140h] [ebp-25Ch]
  _BYTE *v23; // [esp+374h] [ebp-28h]
  char a4[6]; // [esp+37Ah] [ebp-22h]
  int v25; // [esp+380h] [ebp-1Ch]
  char *a2; // [esp+384h] [ebp-18h]
  int v27; // [esp+388h] [ebp-14h]
  int vmpDataSize; // [esp+38Ch] [ebp-10h]
  char *v29; // [esp+390h] [ebp-Ch]
  char *insSize; // [esp+394h] [ebp-8h]
  int v31; // [esp+398h] [ebp-4h]
  int vars0; // [esp+39Ch] [ebp+0h]
 
  v19 = 0;
  v18 = 0;
  v27 = 0;
  v16 = &vars0;
  v15 = &loc_477095;
  v14 = (int *)__readfsdword(0);
  __writefsdword(0, (unsigned int)&v14);
  global = sub_4760D0();
  v31 = vars0 + 8;
  global->retAddr = retAddr;
  *(_DWORD *)&a4[2] = global->curVmpCode1;
  a2 = *(char **)&a4[2];
  vmpInfo = global->vmpInfo;
  if ( !vmpInfo )
  {
    sub_4778E8(global);
    vmpInfo = global->vmpInfo;
  }
  a4[1] = 0;
  if ( vmpInfo->isVmpFlag == 1 )
  {
    a4[1] = 1;
    simvm_Init(global, v31, 16);
  }
  while ( 1 )
  {
    callCodeDecrypt((int)global, dataOfFile, *(int *)&a4[2], &vmpDataSize);
    while ( 1 )
    {
      while ( vmpInfo->isVmpFlag == 1 )
      {
        a4[0] = 0;
        v25 = (int)callVmpHandle(vmpInfo, codeData, *(_BYTE **)&a4[2], (int)a4);
        insSize = (char *)(v25 - *(_DWORD *)&a4[2]);
        if ( dataOfFile == global->curVmpCodeAddr )
        {
          GetNextValueByLen(&codeData, (unsigned __int8)a4[0]);
          global->curCodeAddr = codeData;
          GetNextValueByLen(&dataOfFile, insSize);
          global->curVmpCodeAddr = dataOfFile;
        }
        else
        {
          dataOfFile = global->curVmpCodeAddr;
          codeData = global->curCodeAddr;
        }
        callCodeDecrypt((int)global, dataOfFile, *(int *)&a4[2], &vmpDataSize);
      }
      if ( ifCode_simvm_orign(vmpInfo, &a2) != 1 )
        break;
      a2 = *(char **)&a4[2];
      a4[1] = 1;
      simvm_Init(global, v31, 16);
    }
    insSize = &a2[-*(_DWORD *)&a4[2]];
    a2 = *(char **)&a4[2];
    if ( !a4[1] )
      break;
    a4[1] = 0;
    vmpInfo->field_914 = 1;
  }
  if ( (signed int)insSize > 0 )
  {
    GetNextValueByLen(&dataOfFile, insSize);
    callCodeDecrypt((int)global, dataOfFile, *(int *)&a4[2], &vmpDataSize);
  }
  vmpDataSize = off_49DCA8(*(_DWORD *)&a4[2], vmpDataSize, 0, &v20, 4, v14);
  *a5 = vmpDataSize;
  v9 = unknown_libname_29(32 - vmpDataSize - 6);
  a2 = (char *)&global->field_1038 + v9;
  qmemcpy(a2, *(const void **)&a4[2], vmpDataSize);
  v14 = 0;
  *((_BYTE *)&global->field_1038 + v9 + vmpDataSize) = 104;
  unknown_libname_56(&v27, &v22);
  if ( (unsigned __int8)sub_476200(v27, global->cmpReg1) )
  {
    unknown_libname_56(&v27, &v21);
    if ( sub_466514(&str_FF_0[1], v27) != 1 )
    {
      insSize = (char *)sub_466514(&str___29[1], v27);
      v14 = &v27;
      sn11111(v27);
      System::__linkproc__ LStrCopy(v14);
      insSize = (char *)sub_466578(v27);
      if ( vmpDataSize - 1 >= 0 )
      {
        v10 = vmpDataSize;
        v29 = 0;
        do
        {
          v14 = 0;
          (v29++)[v9 + 4152 + (_DWORD)global] = -112;
          --v10;
        }
        while ( v10 );
      }
      insSize += vmpDataSize;
      vmpInfo->isVmpFlag1 = vmpInfo->isVmpFlag;
      if ( (signed int)insSize <= 0 )
      {
        insSize += dataOfFile - global->field_1070;
        v14 = (int *)&v29;
        callCodeDecrypt((int)global, global->field_1070, *(int *)&a4[2], &v29);
      }
      v23 = sub_475A90(vmpInfo, *(int *)&a4[2], (unsigned int)insSize);
      vmpInfo->isVmpFlag = vmpInfo->isVmpFlag1;
      if ( !v23 )
        global->curCodeAddr1 = global->curCodeAddr;
    }
  }
  else if ( sub_466514(&str_CALL_0[1], v27) == 1 )
  {
    unknown_libname_56(&v27, &v21);
    if ( sub_466514(&str_FF_0[1], v27) != 1 )
    {
      insSize = (char *)sub_466514(&str___29[1], v27);
      v29 = insSize - 1;
      v11 = (signed int)(insSize - 1) / 2;
      a2 = (char *)&global->field_1038 + v9 + v11;
      v14 = &v27;
      sn11111(v27);
      System::__linkproc__ LStrCopy(v14);
      insSize = (char *)sub_466578(v27);
      v29 = (char *)(&insSize[codeData] - ((char *)&global->field_1038 + v9));
      qmemcpy(a2, &v29, vmpDataSize - v11);
    }
    insSize = (char *)vmpDataSize;
    v23 = (_BYTE *)vmpDataSize;
  }
  else
  {
    insSize = (char *)vmpDataSize;
    v23 = (_BYTE *)vmpDataSize;
  }
  *a7 = insSize;
  insSize = (char *)retAddr;
  a2 = (char *)&global->field_1038 + v9 + vmpDataSize + 1;
  qmemcpy(a2, &insSize, 4u);
  v14 = 0;
  *((_BYTE *)&global->field_103C + v9 + vmpDataSize + 1) = -61;
  *a6 = (int)&global->field_1038 + v9;
  global->curCodeAddr = codeData + *a7;
  global->curVmpCodeAddr = (int)&v23[dataOfFile];
  unknown_libname_56(&v19, &v22);
  v14 = v19;
  unknown_libname_56(&v18, &v21);
  v12 = *a6;
  sub_47745C(vmpDataSize, v18, v14);
  __writefsdword(0, (unsigned int)v15);
  v17 = &loc_47709C;
  System::__linkproc__ LStrArrayClr(&v18, 2);
  return System::__linkproc__ LStrClr(&v27);
}
1、调用callCodeDecrypt(4774D8)对指令进行解密
2、调用callVmpHandle(475C08)对指令进行分析和执行,一直到所有指令执行完毕。
八、 callVmpHandle函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
char *__fastcall callVmpHandle(struct vmpInfo *vmpInfo, int codeAddr, _BYTE *vmpCode_1, int pinsLen)
{
  struct vmpInfo *vmpInfo1; // esi
  struct tempStruct tempStruct; // [esp+8h] [ebp-10h]
  char *vmpCodeEnd; // [esp+10h] [ebp-8h]
  int vmpCode; // [esp+14h] [ebp-4h]
 
  vmpCode = (int)vmpCode_1;
  vmpInfo1 = vmpInfo;
  vmpCodeEnd = vmpCode_1;
  if ( vmpInfo->isVmpFlag == 1 )
  {
    if ( ifCode_simvm_orign(vmpInfo, (char **)&vmpCode) == 2 )
    {
      vmpCodeEnd = (char *)vmpCode;
    }
    else
    {
      vmpCodeEnd = (char *)vmpCode;
      if ( GetTempStructByVmpCmd(vmpInfo1, *(_BYTE *)vmpCode, &tempStruct) )
        vmpCodeEnd = vmpHandle(vmpInfo1, vmpCode, (_BYTE *)pinsLen, (int)tempStruct.vmpInfo, tempStruct.copyFun);
      else
        vmpInfo1->isVmpFlag = 2;
    }
  }
  return vmpCodeEnd;
}
1、调用ifCode_simvm_orign判断指令类型
2、如果是VMP指令则
1)调用GetTempStructByVmpCmd函数初始化相关结构,并获取对应真实代码的处理函数(474F08)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
char *__fastcall callVmpHandle(struct vmpInfo *vmpInfo, int codeAddr, _BYTE *vmpCode_1, int pinsLen)
{
  struct vmpInfo *vmpInfo1; // esi
  struct tempStruct tempStruct; // [esp+8h] [ebp-10h]
  char *vmpCodeEnd; // [esp+10h] [ebp-8h]
  int vmpCode; // [esp+14h] [ebp-4h]
 
  vmpCode = (int)vmpCode_1;
  vmpInfo1 = vmpInfo;
  vmpCodeEnd = vmpCode_1;
  if ( vmpInfo->isVmpFlag == 1 )
  {
    if ( ifCode_simvm_orign(vmpInfo, (char **)&vmpCode) == 2 )
    {
      vmpCodeEnd = (char *)vmpCode;
    }
    else
    {
      vmpCodeEnd = (char *)vmpCode;
      if ( GetTempStructByVmpCmd(vmpInfo1, *(_BYTE *)vmpCode, &tempStruct) )
        vmpCodeEnd = vmpHandle(vmpInfo1, vmpCode, (_BYTE *)pinsLen, (int)tempStruct.vmpInfo, tempStruct.copyFun);
      else
        vmpInfo1->isVmpFlag = 2;
    }
  }
  return vmpCodeEnd;
}
2)调用vmpHandle(474EAC)
九、 vmpHandle (474EAC)函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
char *__fastcall vmpHandle(struct vmpInfo *vmpInfo, int vmpCode, _BYTE *pinsLen1, int vmpInfo1, int vmpExeFun)
{
  _BYTE *pinsLen; // esi
  struct vmpInfo *vmpInfo_1; // ebx
  char *vmpInsEnd; // edi
  int out_size; // [esp+Ch] [ebp-14h]
  char out21; // [esp+10h] [ebp-10h]
  char out11; // [esp+14h] [ebp-Ch]
  int out_orgReg; // [esp+18h] [ebp-8h]
  int out_aimReg; // [esp+1Ch] [ebp-4h]
 
  pinsLen = pinsLen1;
  vmpInfo_1 = vmpInfo;
  vmpInsEnd = copyVMPcode(vmpInfo, (char *)vmpCode);
  *pinsLen = vmpInfo_1->vmpCode.codeInsLen;
  getVmpReg(vmpInfo_1, &out_aimReg, &out_orgReg, &out11, &out21, &out_size);
  vmpRealFunHandle((int)vmpInfo_1, out_aimReg, out_orgReg, vmpInfo1, (int (__fastcall *)(intint))vmpExeFun, out_size);
  return vmpInsEnd;
}
1、调用copyVMPcode拷贝当前条VMP指令,一条指令长度为0x64
2、调用getVmpReg,应该是获取相关寄存器或者执行简单指令执行
3、执行该指令的真实指令处理函数
4、稍微分析了下虚拟指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
firt ins
+0      01 00 00 00 
+4         00 00 00 00             setout1Flag
+8         17 11 01 F0                  vmpcmd 1 reg1
+c         00 00 00 00 
+10     00 00 00 00 
+14     00 00 00 00                      offset
+18     00 00 00 00 
+1c     00 00 00 00 
+20     00 00 00 00 
+24     00 00 00 00 
+28     00 
+29     04                              unknowcmd1
+2A     01 
+2B     00 
+2C     0C 00 00 F0                     vmdcmp2  
+30     00 00 00 00 
+34   00 00 00 00 
+38     30 00 00 00                      offset 
+3C     01 00 00 00 
+40     00 00 00 00 
+44     00 00 00 00 
+48     00 00 00 00 
+4C     00 
+4D     04 
+4E     00 
+4F     02 
+50     07                 insSize
+51     00 
+52     00 
+53     00 
+54     00 00 00 00 
+58     00 00 00 00 
+5C     00 00 00 00 
+60     00 00 00 00
 
if ( vmpInfo->vmpCode.vmpCmd1 )              F0011117
{
    out1 = result0Reg
    out3 = [result0Reg]+offset
    if(unknowcmd1 !=3)
        out5 = unknowcmd1
    if(setout1Flag || offset)
        out1 = out3
     
}
 
//0x01
varc = fs:[offset2]
var7 = fs:[offset2] + offset1
================================================
 
+0      01 00 00 00 
+4      00                     aimreg_SetFlag
+5      00 
+6      00 
+7      00                
+8      17 01 00 F0                 aimreg_cmd
+C      00 00 00 00 
+10     00 00 00 00 
+14     00 00 00 00                 aimreg_offset
+18     00 00 00 00 
+1C     00 00 00 00 
+20     00 00 00 00 
+24     00 00 00 00 
+28     00 
+29     01                     aimreg_size
+2A     01                            
+2B     00 
+2C     17 11 01 F0                     orgreg_cmd
+30     00 00 00 00 
+34     00 00 00 00 
+38     02 00 00 00                     orgreg_offset
+3C     01 00 00 00 
+40     00 00 00 00 
+44     00 00 00 00 
+48     00 00 00 00 
+4C     00 
+4D     04                     orgreg_size
+4E     01 
+4F     02 
+50     03                                  
+51     00 
+52     00
+53     00 
+54     00 00 00 00 
+58     00 00 00 00 
+5C     00 00 00 00 
+60     00 00 00 00
//==============================================================
+0      01 00 00 00 
+4      01 00 00 00                          aimreg_SetFlag
+8      02 00 00 F0              aimreg_cmd
+c      00 00 00 00 
+10     00 00 00 00 
+14     EF FF FF FF                     aimreg_offset
+18     02 00 00 00
+1c     00 00 00 00 
+20     00 00 00 00 
+24     00 00 00 00 
+28     00 
+29     04                  aimreg_size 
+2A     00 
+2B     00
+2c     17 01 00 F0                     orgreg_cmd
+30     00 00 00 00 
+34     00 00 00 00 
+38     00 00 00 00              orgreg_offset
+3C     00 00 00 00 
+40     00 00 00 00 
+44     00 00 00 00 
+48     00 00 00 00
+4C     00 
+4D     01                      orgreg_size
+4E     00 
+4F     02 
+50     03 
+51     00 
+52     00 
+53     00 
+54     00 00 00 00 
+58     00 00 00 00
+5C     00 00 00 00 
+60     00 00 00 00 
 
//=====================================================
cmp [aimreg+offset], orgreg_value set global.cmpReg    0x80位
+0      08 00 00 00  
+4      01 00 00 00                          aimreg_SetFlag
+8      02 00 00 F0                          aimreg_cmd
+c      00 00 00 00 
+10     00 00 00 00  
+14     EF FF FF FF                          aimreg_offset
+18     02 00 00 00 
+1c     00 00 00 00 
+20     00 00 00 00  
+24     00 00 00 00 
+28     00 
+29     04                      aimreg_size
+2A     00 
+2B     00 
+2c     00 00 00 00                          orgreg_cmd
+30     00 00 00 00  
+34     01 00 00 00                             orgreg_value
+38     00 00 00 00                         orgreg_offset
+3C     00 00 00 00 
+40     00 00 00 00  
+44     00 00 00 00 
+48     00 00 00 00 
+4C     00 
+4D     04                             orgreg_size
+4E     01 
+4F     02 
+50     04 
+51     00 
+52     00 
+53     00  
+54     00 00 00 00 
+58     00 00 00 00 
+5C     00 00 00 00 
+60     00 00 00 00  
 
//==========================================================================
+0      1F 00 00 00  
+4      00 00 00 00                      aimreg_SetFlag
+8      00 00 00 00 
+c      00 00 00 00 
+10     6A 01 00 00                              branch_offset
+14     00 00 00 00                      aimreg_offset
+18     00 00 00 00 
+1c     00 00 00 00 
+20     00 00 00 00  
+24     00 00 00 00 
+28     00 
+29     04                      aimreg_size
+2A     00 
+2B     00 
+2c     00 00 00 00                      orgreg_cmd
+30     00 00 00 00  
+34     00 00 00 00                      orgreg_value
+38     00 00 00 00                      orgreg_offset
+3C     00 00 00 00 
+40     00 00 00 00  
+44     00 00 00 00 
+48     00 00 00 00 
+4C     00 
+4D     00                      orgreg_size
+4E     00 
+4F     01 
+50     06 
+51     00 
+52     00 
+53     00  
+54     00 00 00 00 
+58     00 00 00 00 
+5C     00 00 00 00 
+60     00 00 00 00
//===================================================
cmp [aimreg+offset], orgreg_value set global.cmpReg    0x80位
+0      08 00 00 00  
+4      01 00 00 00                     aimreg_SetFlag
+8      14 11 01 F0                     aimreg_cmd
+c      00 00 00 00            
+10     00 00 00 00  
+14     44 03 00 00                     aimreg_offset
+18     01 00 00 00 
+1c     00 00 00 00 
+20     00 00 00 00  
+24     00 00 00 00 
+28     00 
+29     04                     aimreg_size
+2A     00 
+2B     00 
+2c     00 00 00 00                     orgreg_cmd
+30     00 00 00 00  
+34     01 00 00 00                     orgreg_value
+38     00 00 00 00 
+3C     00 00 00 00 
+40     00 00 00 00  
+44     00 00 00 00 
+48     00 00 00 00 
+4C     00 
+4D     04                         orgreg_size
+4E     01 
+4F     02 
+50     07 
+51     00 
+52     00 
+53     00  
+54     00 00 00 00 
+58     00 00 00 00 
+5C     00 00 00 00 
+60     00 00 00 00
============================================================================
+0      1F 00 00 00       
+4      00 00 00 00                       aimreg_SetFlag
+8      00 00 00 00                aimreg_cmd
+c      00 00 00 00 
+10     5D 01 00 00                      branch_offset
+14     00 00 00 00                       aimreg_offset
+18     00 00 00 00
+1c     00 00 00 00 
+20     00 00 00 00  
+24     00 00 00 00 
+28     00 
+29     04                           aimreg_size
+2A     00 
+2B     00
+2c     00 00 00 00                       orgreg_cmd
+30     00 00 00 00  
+34     00 00 00 00                      orgreg_value
+38     00 00 00 00
+3C     00 00 00 00 
+40     00 00 00 00  
+44     00 00 00 00 
+48     00 00 00 00
+4C     00 
+4D     00                      orgreg_size
+4E     00 
+4F     01 
+50     06
+51     00 
+52     00 
+53     00  
+54     00 00 00 00 
+58     00 00 00 00
+5C     00 00 00 00 
+60     00 00 00 00
 
//====================================================
//获取输入sn的地址
mov aimreg+aimReg, [org+orgOfset]
+0      01 00 00 00  
+4      00 00 00 00                          aimreg_SetFlag
+8      17 11 01 F0                   aimreg_cmd
+c      00 00 00 00 
+10     00 00 00 00  
+14     00 00 00 00                          aimreg_offset
+18     00 00 00 00
+1c     00 00 00 00 
+20     00 00 00 00  
+24     00 00 00 00 
+28     00 
+29     04                      aimreg_size
+2A     01 
+2B     00
+2c     02 00 00 F0                          orgreg_cmd
+30     00 00 00 00  
+34     00 00 00 00                          orgreg_value
+38     E4 FF FF FF                   orgreg_offset
+3C     02 00 00 00 
+40     00 00 00 00  
+44     00 00 00 00 
+48     00 00 00 00
+48     00 04 00 02 
+4C     03 
+4D     00                      orgreg_size
+4E     00 
+4F     00  
+50     00 
+51     00 
+52     00 
+53     00 
+54     00 00 00 00
+58     00 00 00 00 
+5C     00 00 00 00  
//===================================================
+0      0B 00 00 00  
+4      00 00 00 00                aimreg_SetFlag 
+8      00 00 00 00              aimreg_cmd
+c      00 00 00 00 
+10     6D B1 F6 FF                branch_offset
+14     00 00 00 00                 aimreg_offset
+18     00 00 00 00
+1c     00 00 00 00 
+20     00 00 00 00  
+24     00 00 00 00 
+28     00    
+29     04                     aimreg_size
+2A     00 
+2B     00
+2c     00 00 00 00                 orgreg_cmd
+30     00 00 00 00  
+34     00 00 00 00 
+38     00 00 00 00
+3C     00 00 00 00 
+40     00 00 00 00  
+44     00 00 00 00 
+48     00 00 00 00
+48     00 00 00 01 
+4C     05                     code_offset
+4D     00                     orgreg_size
+4E     00 
+4F     00  
+50     00 
+51     00 
+52     00 
+53     00 
+54     00 00 00 00
+58     00 00 00 00 
+5C     00 00 00 00  
+60     08 00 00 00 
其中如下函数vmp_opcode_0x08为处理比较指令的,跟踪到这里后即基本可以还原了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
truct vmpInfo *__userpurge vmp_opcode_0x08@<eax>(struct vmpInfo *vmpInfo@<eax>, _DWORD *out1@<edx>, _DWORD *vmpcodeLocation@<ecx>, unsigned int vmpcodeEnd@<edi>, int out5)
{
  unsigned int v5; // et0
  unsigned int v6; // et0
  unsigned int v7; // et0
  unsigned int v8; // et0
  struct vmpInfo *result; // eax
 
  switch ( out5 )
  {
    case 1:
      v5 = __readeflags();
      __writeeflags(v5);
      result = vmp_opcode_0x08_setCmpFlag(
                 vmpInfo,
                 *(unsigned __int8 *)out1 - *(unsigned __int8 *)vmpcodeLocation,
                 1,
                 v5);
      break;
    case 2:
      v6 = __readeflags();
      __writeeflags(v6);
      result = vmp_opcode_0x08_setCmpFlag(vmpInfo, vmpcodeEnd, 2, v6);
      break;
    case 4:
      v7 = __readeflags();
      __writeeflags(v7);
      result = vmp_opcode_0x08_setCmpFlag(vmpInfo, *out1 - *vmpcodeLocation, out5, v7);
      break;
    default:
      v8 = __readeflags();
      __writeeflags(v8);
      result = vmp_opcode_0x08_setCmpFlag(vmpInfo, *out1 - *vmpcodeLocation, 4, v8);
      break;
  }
  return result;
}
使用输入的字符-0x7F,然后与如下地址中的E0  B2 B1比较相等即为正确。
1
2
3
4
5
6
CODE:00499570                 clts
CODE:00499572                 mov     al, 0B1h
CODE:00499574                 mov     dl, 0B8h
CODE:00499576                 mov     bh, 0E0h
CODE:00499578                 mov     dl, 0B1h
CODE:0049957A                 mov     al, 0E2h
其中 499572地址敲好在产生异常clts指令的下方。

最后得到flag为: Simpower91a321

ps :
作者的dephi相关题目已经出到了3.0阶段
1.0 ---------------------dephi+jscrypt 内存中暴露了key
2.0---------------------- dephi+代码重定位 +VMP;虽然有vmp但是主要算法在代码重定位部分
3.0---------------------- dephi+代码重定位 +VMP:所有代码都在vmp
4.0---------------------- dephi+代码重定位 +VMP:算法复杂化????????????

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __usercall antiDebug5@<eax>(int a1@<eax>, int a2@<ebx>)
{
  int v2; // esi
  int v4; // [esp+0h] [ebp-408h]
 
  v2 = a1;
  Windows::FillMemory(&v4, 0x400u, 0);
  DeleteFiber(&v4);
  if ( GetLastError_0() == 0x57 )
  {
    a2 = 0;
    unknown_libname_1058(v2);
  }
  else
  {
    LOBYTE(a2) = 1;
    unknown_libname_1059(v2);
  }
  return a2;
}
7、反调试函数4780B8
1
2
3
4
5
6
7
8
9
10
int antiDebug7()
{
  HMODULE v0; // eax
  HANDLE v1; // eax
 
  v0 = LoadLibraryA("ntdll.dll");
  dword_49DCC0 = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD))GetProcAddress_0(v0, "NtSetInformationThread");
  v1 = GetCurrentThread();
  return dword_49DCC0(v1, 17, 0, 0);
}
8 、过掉反调试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#coding=utf-8
import struct
from idaapi import *
from idc import *
from idautils import *
 
dbg_write_memory(0x478070, '\xEB')#antiDebug2
refresh_debugger_memory()
 
dbg_write_memory(0x47812E, '\x90\x90')#antiDebug3
refresh_debugger_memory()
 
dbg_write_memory(0x47816C, '\x90\x90')#antiDebug4
refresh_debugger_memory()
 
dbg_write_memory(0x4781F4, '\x90\x90')#antiDebug6
refresh_debugger_memory()
 
dbg_write_memory(0x477F64, '\x33\xC0\xC3\x90')#antiDebug5
refresh_debugger_memory()
 
dbg_write_memory(0x4780B8, '\x33\xC0\xC3\x90')#antiDebug7
refresh_debugger_memory()
五、sncheck分析
1、异常处理函数注册
1
2
3
4
5
6
7
CODE:004994A7                 push    dword ptr fs:[eax]
CODE:004994AA                 mov     fs:[eax], esp
CODE:004994AD                 mov     eax, offset sub_475ED8
CODE:004994B2                 mov     edx, ds:off_49C3D8
CODE:004994B8                 mov     [edx+4], eax
CODE:004994BB                 mov     eax, ds:off_49C3D8
CODE:004994C0                 call    sub_46590C
其中sub_475ED8为异常处理函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
signed int __cdecl sub_475ED8(_DWORD *a1, int a2, int a3)
{
  signed int result; // eax
 
  result = 1;
  if ( !a1[1] )
  {
    if ( *a1 == 0xC0000096 )
    {
      *(_DWORD *)(a3 + 184) = realSnCheck;
      result = 0;
    }
    else if ( *a1 == 0xC00000FD )
    {
      *(_DWORD *)(a3 + 196) -= 256;
    }
  }
  return result;
}
其中 475EBC(realSnCheck)为异常0C0000096h处理函数
2、获取vmp指令
1
2
CODE:00499530                 call    GetVmpCode
CODE:00499535                 mov     [ebp+var_10], eax
其中 eax+4 为VMP指令地址,  eax+8为指令大小
3、产生异常,进入 475EBC(realSnCheck)
六、 realSnCheck( 475EBC )
1、realSnCheck  调用477778 与之前类似
     1)解密代码和指令
     2)判断加密的指令是否是真实代码,如果是,这将相应代码进行重定位动态执行
     3)如果是VMP指令,则进入虚拟机执行。
      本题没有真实代码,所有指令都为虚拟机代码
2、最终会进入476B8C(codeExe)函数中
七、codeExe函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
int __stdcall codeExe(int a1, int codeData, int retAddr, int dataOfFile, _DWORD *a5, int *a6, _DWORD *a7)
{
  struct globalInfo *global; // ebx
  struct vmpInfo *vmpInfo; // esi
  int v9; // edi
  int v10; // ecx
  int v11; // esi
  int v12; // edx
  int *v14; // [esp+1Ch] [ebp-380h]
  void *v15; // [esp+20h] [ebp-37Ch]
  int *v16; // [esp+24h] [ebp-378h]
  void *v17; // [esp+28h] [ebp-374h]
  int v18; // [esp+34h] [ebp-368h]
  int *v19; // [esp+38h] [ebp-364h]
  int v20; // [esp+3Ch] [ebp-360h]
  char v21; // [esp+40h] [ebp-35Ch]
  char v22; // [esp+140h] [ebp-25Ch]
  _BYTE *v23; // [esp+374h] [ebp-28h]
  char a4[6]; // [esp+37Ah] [ebp-22h]
  int v25; // [esp+380h] [ebp-1Ch]
  char *a2; // [esp+384h] [ebp-18h]
  int v27; // [esp+388h] [ebp-14h]
  int vmpDataSize; // [esp+38Ch] [ebp-10h]
  char *v29; // [esp+390h] [ebp-Ch]
  char *insSize; // [esp+394h] [ebp-8h]
  int v31; // [esp+398h] [ebp-4h]
  int vars0; // [esp+39Ch] [ebp+0h]
 
  v19 = 0;
  v18 = 0;
  v27 = 0;
  v16 = &vars0;
  v15 = &loc_477095;
  v14 = (int *)__readfsdword(0);
  __writefsdword(0, (unsigned int)&v14);
  global = sub_4760D0();
  v31 = vars0 + 8;
  global->retAddr = retAddr;
  *(_DWORD *)&a4[2] = global->curVmpCode1;
  a2 = *(char **)&a4[2];
  vmpInfo = global->vmpInfo;
  if ( !vmpInfo )
  {
    sub_4778E8(global);
    vmpInfo = global->vmpInfo;
  }
  a4[1] = 0;
  if ( vmpInfo->isVmpFlag == 1 )
  {
    a4[1] = 1;
    simvm_Init(global, v31, 16);
  }
  while ( 1 )
  {
    callCodeDecrypt((int)global, dataOfFile, *(int *)&a4[2], &vmpDataSize);
    while ( 1 )
    {
      while ( vmpInfo->isVmpFlag == 1 )
      {
        a4[0] = 0;
        v25 = (int)callVmpHandle(vmpInfo, codeData, *(_BYTE **)&a4[2], (int)a4);
        insSize = (char *)(v25 - *(_DWORD *)&a4[2]);
        if ( dataOfFile == global->curVmpCodeAddr )
        {
          GetNextValueByLen(&codeData, (unsigned __int8)a4[0]);
          global->curCodeAddr = codeData;
          GetNextValueByLen(&dataOfFile, insSize);
          global->curVmpCodeAddr = dataOfFile;
        }
        else
        {
          dataOfFile = global->curVmpCodeAddr;
          codeData = global->curCodeAddr;
        }
        callCodeDecrypt((int)global, dataOfFile, *(int *)&a4[2], &vmpDataSize);
      }
      if ( ifCode_simvm_orign(vmpInfo, &a2) != 1 )
        break;
      a2 = *(char **)&a4[2];
      a4[1] = 1;
      simvm_Init(global, v31, 16);
    }
    insSize = &a2[-*(_DWORD *)&a4[2]];
    a2 = *(char **)&a4[2];
    if ( !a4[1] )
      break;
    a4[1] = 0;
    vmpInfo->field_914 = 1;
  }
  if ( (signed int)insSize > 0 )
  {
    GetNextValueByLen(&dataOfFile, insSize);
    callCodeDecrypt((int)global, dataOfFile, *(int *)&a4[2], &vmpDataSize);
  }
  vmpDataSize = off_49DCA8(*(_DWORD *)&a4[2], vmpDataSize, 0, &v20, 4, v14);
  *a5 = vmpDataSize;
  v9 = unknown_libname_29(32 - vmpDataSize - 6);
  a2 = (char *)&global->field_1038 + v9;
  qmemcpy(a2, *(const void **)&a4[2], vmpDataSize);
  v14 = 0;
  *((_BYTE *)&global->field_1038 + v9 + vmpDataSize) = 104;
  unknown_libname_56(&v27, &v22);
  if ( (unsigned __int8)sub_476200(v27, global->cmpReg1) )
  {
    unknown_libname_56(&v27, &v21);
    if ( sub_466514(&str_FF_0[1], v27) != 1 )
    {
      insSize = (char *)sub_466514(&str___29[1], v27);
      v14 = &v27;
      sn11111(v27);
      System::__linkproc__ LStrCopy(v14);
      insSize = (char *)sub_466578(v27);
      if ( vmpDataSize - 1 >= 0 )
      {
        v10 = vmpDataSize;
        v29 = 0;
        do
        {
          v14 = 0;
          (v29++)[v9 + 4152 + (_DWORD)global] = -112;
          --v10;
        }
        while ( v10 );
      }
      insSize += vmpDataSize;
      vmpInfo->isVmpFlag1 = vmpInfo->isVmpFlag;
      if ( (signed int)insSize <= 0 )
      {
        insSize += dataOfFile - global->field_1070;
        v14 = (int *)&v29;
        callCodeDecrypt((int)global, global->field_1070, *(int *)&a4[2], &v29);
      }
      v23 = sub_475A90(vmpInfo, *(int *)&a4[2], (unsigned int)insSize);
      vmpInfo->isVmpFlag = vmpInfo->isVmpFlag1;
      if ( !v23 )
        global->curCodeAddr1 = global->curCodeAddr;
    }
  }
  else if ( sub_466514(&str_CALL_0[1], v27) == 1 )
  {
    unknown_libname_56(&v27, &v21);
    if ( sub_466514(&str_FF_0[1], v27) != 1 )
    {
      insSize = (char *)sub_466514(&str___29[1], v27);
      v29 = insSize - 1;
      v11 = (signed int)(insSize - 1) / 2;
      a2 = (char *)&global->field_1038 + v9 + v11;
      v14 = &v27;
      sn11111(v27);
      System::__linkproc__ LStrCopy(v14);
      insSize = (char *)sub_466578(v27);
      v29 = (char *)(&insSize[codeData] - ((char *)&global->field_1038 + v9));
      qmemcpy(a2, &v29, vmpDataSize - v11);
    }
    insSize = (char *)vmpDataSize;
    v23 = (_BYTE *)vmpDataSize;
  }
  else
  {
    insSize = (char *)vmpDataSize;
    v23 = (_BYTE *)vmpDataSize;
  }
  *a7 = insSize;
  insSize = (char *)retAddr;
  a2 = (char *)&global->field_1038 + v9 + vmpDataSize + 1;
  qmemcpy(a2, &insSize, 4u);
  v14 = 0;
  *((_BYTE *)&global->field_103C + v9 + vmpDataSize + 1) = -61;
  *a6 = (int)&global->field_1038 + v9;
  global->curCodeAddr = codeData + *a7;
  global->curVmpCodeAddr = (int)&v23[dataOfFile];
  unknown_libname_56(&v19, &v22);
  v14 = v19;
  unknown_libname_56(&v18, &v21);
  v12 = *a6;
  sub_47745C(vmpDataSize, v18, v14);
  __writefsdword(0, (unsigned int)v15);
  v17 = &loc_47709C;
  System::__linkproc__ LStrArrayClr(&v18, 2);
  return System::__linkproc__ LStrClr(&v27);
}
1、调用callCodeDecrypt(4774D8)对指令进行解密
2、调用callVmpHandle(475C08)对指令进行分析和执行,一直到所有指令执行完毕。
八、 callVmpHandle函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
char *__fastcall callVmpHandle(struct vmpInfo *vmpInfo, int codeAddr, _BYTE *vmpCode_1, int pinsLen)
{
  struct vmpInfo *vmpInfo1; // esi
  struct tempStruct tempStruct; // [esp+8h] [ebp-10h]
  char *vmpCodeEnd; // [esp+10h] [ebp-8h]
  int vmpCode; // [esp+14h] [ebp-4h]
 
  vmpCode = (int)vmpCode_1;
  vmpInfo1 = vmpInfo;
  vmpCodeEnd = vmpCode_1;
  if ( vmpInfo->isVmpFlag == 1 )
  {
    if ( ifCode_simvm_orign(vmpInfo, (char **)&vmpCode) == 2 )
    {
      vmpCodeEnd = (char *)vmpCode;
    }
    else
    {
      vmpCodeEnd = (char *)vmpCode;
      if ( GetTempStructByVmpCmd(vmpInfo1, *(_BYTE *)vmpCode, &tempStruct) )
        vmpCodeEnd = vmpHandle(vmpInfo1, vmpCode, (_BYTE *)pinsLen, (int)tempStruct.vmpInfo, tempStruct.copyFun);
      else
        vmpInfo1->isVmpFlag = 2;
    }
  }
  return vmpCodeEnd;
}
1、调用ifCode_simvm_orign判断指令类型
2、如果是VMP指令则
1)调用GetTempStructByVmpCmd函数初始化相关结构,并获取对应真实代码的处理函数(474F08)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
char *__fastcall callVmpHandle(struct vmpInfo *vmpInfo, int codeAddr, _BYTE *vmpCode_1, int pinsLen)
{
  struct vmpInfo *vmpInfo1; // esi
  struct tempStruct tempStruct; // [esp+8h] [ebp-10h]
  char *vmpCodeEnd; // [esp+10h] [ebp-8h]
  int vmpCode; // [esp+14h] [ebp-4h]
 
  vmpCode = (int)vmpCode_1;
  vmpInfo1 = vmpInfo;
  vmpCodeEnd = vmpCode_1;
  if ( vmpInfo->isVmpFlag == 1 )
  {
    if ( ifCode_simvm_orign(vmpInfo, (char **)&vmpCode) == 2 )
    {
      vmpCodeEnd = (char *)vmpCode;
    }
    else
    {
      vmpCodeEnd = (char *)vmpCode;
      if ( GetTempStructByVmpCmd(vmpInfo1, *(_BYTE *)vmpCode, &tempStruct) )
        vmpCodeEnd = vmpHandle(vmpInfo1, vmpCode, (_BYTE *)pinsLen, (int)tempStruct.vmpInfo, tempStruct.copyFun);
      else
        vmpInfo1->isVmpFlag = 2;
    }
  }
  return vmpCodeEnd;
}
2)调用vmpHandle(474EAC)
九、 vmpHandle (474EAC)函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
char *__fastcall vmpHandle(struct vmpInfo *vmpInfo, int vmpCode, _BYTE *pinsLen1, int vmpInfo1, int vmpExeFun)
{
  _BYTE *pinsLen; // esi
  struct vmpInfo *vmpInfo_1; // ebx
  char *vmpInsEnd; // edi
  int out_size; // [esp+Ch] [ebp-14h]
  char out21; // [esp+10h] [ebp-10h]
  char out11; // [esp+14h] [ebp-Ch]
  int out_orgReg; // [esp+18h] [ebp-8h]
  int out_aimReg; // [esp+1Ch] [ebp-4h]
 
  pinsLen = pinsLen1;
  vmpInfo_1 = vmpInfo;
  vmpInsEnd = copyVMPcode(vmpInfo, (char *)vmpCode);
  *pinsLen = vmpInfo_1->vmpCode.codeInsLen;
  getVmpReg(vmpInfo_1, &out_aimReg, &out_orgReg, &out11, &out21, &out_size);
  vmpRealFunHandle((int)vmpInfo_1, out_aimReg, out_orgReg, vmpInfo1, (int (__fastcall *)(intint))vmpExeFun, out_size);
  return vmpInsEnd;
}
1、调用copyVMPcode拷贝当前条VMP指令,一条指令长度为0x64
2、调用getVmpReg,应该是获取相关寄存器或者执行简单指令执行
3、执行该指令的真实指令处理函数
4、稍微分析了下虚拟指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
firt ins
+0      01 00 00 00 
+4         00 00 00 00             setout1Flag
+8         17 11 01 F0                  vmpcmd 1 reg1
+c         00 00 00 00 
+10     00 00 00 00 
+14     00 00 00 00                      offset
+18     00 00 00 00 
+1c     00 00 00 00 
+20     00 00 00 00 
+24     00 00 00 00 
+28     00 
+29     04                              unknowcmd1
+2A     01 
+2B     00 
+2C     0C 00 00 F0                     vmdcmp2  
+30     00 00 00 00 
+34   00 00 00 00 
+38     30 00 00 00                      offset 
+3C     01 00 00 00 
+40     00 00 00 00 
+44     00 00 00 00 
+48     00 00 00 00 
+4C     00 
+4D     04 
+4E     00 
+4F     02 
+50     07                 insSize
+51     00 
+52     00 
+53     00 
+54     00 00 00 00 
+58     00 00 00 00 
+5C     00 00 00 00 
+60     00 00 00 00
 
if ( vmpInfo->vmpCode.vmpCmd1 )              F0011117
{
    out1 = result0Reg
    out3 = [result0Reg]+offset
    if(unknowcmd1 !=3)
        out5 = unknowcmd1
    if(setout1Flag || offset)
        out1 = out3
     
}
 
//0x01
varc = fs:[offset2]
var7 = fs:[offset2] + offset1
================================================
 
+0      01 00 00 00 
+4      00                     aimreg_SetFlag
+5      00 
+6      00 
+7      00                
+8      17 01 00 F0                 aimreg_cmd
+C      00 00 00 00 
+10     00 00 00 00 
+14     00 00 00 00                 aimreg_offset
+18     00 00 00 00 
+1C     00 00 00 00 
+20     00 00 00 00 
+24     00 00 00 00 
+28     00 
+29     01                     aimreg_size
+2A     01                            
+2B     00 
+2C     17 11 01 F0                     orgreg_cmd
+30     00 00 00 00 
+34     00 00 00 00 
+38     02 00 00 00                     orgreg_offset
+3C     01 00 00 00 
+40     00 00 00 00 
+44     00 00 00 00 
+48     00 00 00 00 
+4C     00 
+4D     04                     orgreg_size
+4E     01 
+4F     02 
+50     03                                  
+51     00 
+52     00
+53     00 
+54     00 00 00 00 
+58     00 00 00 00 
+5C     00 00 00 00 
+60     00 00 00 00
//==============================================================
+0      01 00 00 00 
+4      01 00 00 00                          aimreg_SetFlag
+8      02 00 00 F0              aimreg_cmd
+c      00 00 00 00 
+10     00 00 00 00 
+14     EF FF FF FF                     aimreg_offset
+18     02 00 00 00
+1c     00 00 00 00 
+20     00 00 00 00 
+24     00 00 00 00 
+28     00 
+29     04                  aimreg_size 
+2A     00 
+2B     00
+2c     17 01 00 F0                     orgreg_cmd
+30     00 00 00 00 
+34     00 00 00 00 
+38     00 00 00 00              orgreg_offset
+3C     00 00 00 00 
+40     00 00 00 00 
+44     00 00 00 00 
+48     00 00 00 00
+4C     00 
+4D     01                      orgreg_size
+4E     00 
+4F     02 
+50     03 
+51     00 
+52     00 
+53     00 
+54     00 00 00 00 
+58     00 00 00 00
+5C     00 00 00 00 
+60     00 00 00 00 
 
//=====================================================
cmp [aimreg+offset], orgreg_value set global.cmpReg    0x80位
+0      08 00 00 00  
+4      01 00 00 00                          aimreg_SetFlag
+8      02 00 00 F0                          aimreg_cmd
+c      00 00 00 00 
+10     00 00 00 00  
+14     EF FF FF FF                          aimreg_offset
+18     02 00 00 00 
+1c     00 00 00 00 
+20     00 00 00 00  
+24     00 00 00 00 
+28     00 
+29     04                      aimreg_size
+2A     00 
+2B     00 
+2c     00 00 00 00                          orgreg_cmd
+30     00 00 00 00  
+34     01 00 00 00                             orgreg_value
+38     00 00 00 00                         orgreg_offset
+3C     00 00 00 00 
+40     00 00 00 00  
+44     00 00 00 00 
+48     00 00 00 00 
+4C     00 
+4D     04                             orgreg_size
+4E     01 
+4F     02 
+50     04 
+51     00 
+52     00 
+53     00  
+54     00 00 00 00 
+58     00 00 00 00 
+5C     00 00 00 00 
+60     00 00 00 00  
 
//==========================================================================
+0      1F 00 00 00  
+4      00 00 00 00                      aimreg_SetFlag
+8      00 00 00 00 
+c      00 00 00 00 
+10     6A 01 00 00                              branch_offset
+14     00 00 00 00                      aimreg_offset
+18     00 00 00 00 
+1c     00 00 00 00 
+20     00 00 00 00  
+24     00 00 00 00 
+28     00 
+29     04                      aimreg_size
+2A     00 
+2B     00 
+2c     00 00 00 00                      orgreg_cmd
+30     00 00 00 00  
+34     00 00 00 00                      orgreg_value
+38     00 00 00 00                      orgreg_offset
+3C     00 00 00 00 
+40     00 00 00 00  
+44     00 00 00 00 
+48     00 00 00 00 
+4C     00 
+4D     00                      orgreg_size
+4E     00 
+4F     01 
+50     06 
+51     00 
+52     00 
+53     00  
+54     00 00 00 00 
+58     00 00 00 00 
+5C     00 00 00 00 
+60     00 00 00 00
//===================================================
cmp [aimreg+offset], orgreg_value set global.cmpReg    0x80位
+0      08 00 00 00  
+4      01 00 00 00                     aimreg_SetFlag
+8      14 11 01 F0                     aimreg_cmd
+c      00 00 00 00            
+10     00 00 00 00  
+14     44 03 00 00                     aimreg_offset
+18     01 00 00 00 
+1c     00 00 00 00 
+20     00 00 00 00  
+24     00 00 00 00 
+28     00 
+29     04                     aimreg_size
+2A     00 
+2B     00 
+2c     00 00 00 00                     orgreg_cmd
+30     00 00 00 00  
+34     01 00 00 00                     orgreg_value
+38     00 00 00 00 
+3C     00 00 00 00 
+40     00 00 00 00  
+44     00 00 00 00 
+48     00 00 00 00 
+4C     00 
+4D     04                         orgreg_size
+4E     01 
+4F     02 
+50     07 
+51     00 
+52     00 
+53     00  
+54     00 00 00 00 
+58     00 00 00 00 
+5C     00 00 00 00 
+60     00 00 00 00
============================================================================
+0      1F 00 00 00       
+4      00 00 00 00                       aimreg_SetFlag
+8      00 00 00 00                aimreg_cmd
+c      00 00 00 00 
+10     5D 01 00 00                      branch_offset
+14     00 00 00 00                       aimreg_offset
+18     00 00 00 00
+1c     00 00 00 00 
+20     00 00 00 00  
+24     00 00 00 00 
+28     00 
+29     04                           aimreg_size
+2A     00 
+2B     00
+2c     00 00 00 00                       orgreg_cmd
+30     00 00 00 00  
+34     00 00 00 00                      orgreg_value
+38     00 00 00 00
+3C     00 00 00 00 
+40     00 00 00 00  
+44     00 00 00 00 
+48     00 00 00 00
+4C     00 
+4D     00                      orgreg_size
+4E     00 
+4F     01 
+50     06
+51     00 
+52     00 
+53     00  
+54     00 00 00 00 
+58     00 00 00 00
+5C     00 00 00 00 
+60     00 00 00 00
 
//====================================================
//获取输入sn的地址
mov aimreg+aimReg, [org+orgOfset]
+0      01 00 00 00  
+4      00 00 00 00                          aimreg_SetFlag
+8      17 11 01 F0                   aimreg_cmd
+c      00 00 00 00 
+10     00 00 00 00  
+14     00 00 00 00                          aimreg_offset
+18     00 00 00 00
+1c     00 00 00 00 
+20     00 00 00 00  
+24     00 00 00 00 
+28     00 
+29     04                      aimreg_size
+2A     01 
+2B     00
+2c     02 00 00 F0                          orgreg_cmd
+30     00 00 00 00  
+34     00 00 00 00                          orgreg_value
+38     E4 FF FF FF                   orgreg_offset
+3C     02 00 00 00 
+40     00 00 00 00  
+44     00 00 00 00 
+48     00 00 00 00
+48     00 04 00 02 
+4C     03 
+4D     00                      orgreg_size
+4E     00 
+4F     00  
+50     00 
+51     00 
+52     00 
+53     00 
+54     00 00 00 00
+58     00 00 00 00 
+5C     00 00 00 00  
//===================================================
+0      0B 00 00 00  
+4      00 00 00 00                aimreg_SetFlag 
+8      00 00 00 00              aimreg_cmd
+c      00 00 00 00 
+10     6D B1 F6 FF                branch_offset
+14     00 00 00 00                 aimreg_offset
+18     00 00 00 00
+1c     00 00 00 00 
+20     00 00 00 00  
+24     00 00 00 00 
+28     00    
+29     04                     aimreg_size
+2A     00 
+2B     00
+2c     00 00 00 00                 orgreg_cmd
+30     00 00 00 00  
+34     00 00 00 00 
+38     00 00 00 00
+3C     00 00 00 00 
+40     00 00 00 00  
+44     00 00 00 00 
+48     00 00 00 00
+48     00 00 00 01 
+4C     05                     code_offset
+4D     00                     orgreg_size
+4E     00 
+4F     00  
+50     00 
+51     00 
+52     00 
+53     00 
+54     00 00 00 00
+58     00 00 00 00 
+5C     00 00 00 00  
+60     08 00 00 00 
其中如下函数vmp_opcode_0x08为处理比较指令的,跟踪到这里后即基本可以还原了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
truct vmpInfo *__userpurge vmp_opcode_0x08@<eax>(struct vmpInfo *vmpInfo@<eax>, _DWORD *out1@<edx>, _DWORD *vmpcodeLocation@<ecx>, unsigned int vmpcodeEnd@<edi>, int out5)
{
  unsigned int v5; // et0
  unsigned int v6; // et0
  unsigned int v7; // et0
  unsigned int v8; // et0
  struct vmpInfo *result; // eax
 
  switch ( out5 )
  {
    case 1:
      v5 = __readeflags();
      __writeeflags(v5);
      result = vmp_opcode_0x08_setCmpFlag(
                 vmpInfo,
                 *(unsigned __int8 *)out1 - *(unsigned __int8 *)vmpcodeLocation,
                 1,
                 v5);
      break;
    case 2:
      v6 = __readeflags();
      __writeeflags(v6);
      result = vmp_opcode_0x08_setCmpFlag(vmpInfo, vmpcodeEnd, 2, v6);
      break;
    case 4:
      v7 = __readeflags();
      __writeeflags(v7);
      result = vmp_opcode_0x08_setCmpFlag(vmpInfo, *out1 - *vmpcodeLocation, out5, v7);
      break;
    default:
      v8 = __readeflags();
      __writeeflags(v8);
      result = vmp_opcode_0x08_setCmpFlag(vmpInfo, *out1 - *vmpcodeLocation, 4, v8);
      break;
  }
  return result;
}
使用输入的字符-0x7F,然后与如下地址中的E0  B2 B1比较相等即为正确。
1
2
3
4
5
6
CODE:00499570                 clts
CODE:00499572                 mov     al, 0B1h
CODE:00499574                 mov     dl, 0B8h
CODE:00499576                 mov     bh, 0E0h
CODE:00499578                 mov     dl, 0B1h
CODE:0049957A                 mov     al, 0E2h
其中 499572地址敲好在产生异常clts指令的下方。

最后得到flag为: Simpower91a321

ps :
作者的dephi相关题目已经出到了3.0阶段
1.0 ---------------------dephi+jscrypt 内存中暴露了key
2.0---------------------- dephi+代码重定位 +VMP;虽然有vmp但是主要算法在代码重定位部分
3.0---------------------- dephi+代码重定位 +VMP:所有代码都在vmp
4.0---------------------- dephi+代码重定位 +VMP:算法复杂化????????????

1
2
3
4
5
6
7
8
9
10
int antiDebug7()
{
  HMODULE v0; // eax
  HANDLE v1; // eax
 
  v0 = LoadLibraryA("ntdll.dll");
  dword_49DCC0 = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD))GetProcAddress_0(v0, "NtSetInformationThread");
  v1 = GetCurrentThread();
  return dword_49DCC0(v1, 17, 0, 0);
}
8 、过掉反调试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#coding=utf-8
import struct
from idaapi import *
from idc import *
from idautils import *
 
dbg_write_memory(0x478070, '\xEB')#antiDebug2
refresh_debugger_memory()
 
dbg_write_memory(0x47812E, '\x90\x90')#antiDebug3
refresh_debugger_memory()
 
dbg_write_memory(0x47816C, '\x90\x90')#antiDebug4
refresh_debugger_memory()
 
dbg_write_memory(0x4781F4, '\x90\x90')#antiDebug6
refresh_debugger_memory()
 
dbg_write_memory(0x477F64, '\x33\xC0\xC3\x90')#antiDebug5
refresh_debugger_memory()
 
dbg_write_memory(0x4780B8, '\x33\xC0\xC3\x90')#antiDebug7
refresh_debugger_memory()
五、sncheck分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#coding=utf-8
import struct
from idaapi import *
from idc import *
from idautils import *
 
dbg_write_memory(0x478070, '\xEB')#antiDebug2
refresh_debugger_memory()
 
dbg_write_memory(0x47812E, '\x90\x90')#antiDebug3
refresh_debugger_memory()
 
dbg_write_memory(0x47816C, '\x90\x90')#antiDebug4
refresh_debugger_memory()
 
dbg_write_memory(0x4781F4, '\x90\x90')#antiDebug6
refresh_debugger_memory()
 
dbg_write_memory(0x477F64, '\x33\xC0\xC3\x90')#antiDebug5
refresh_debugger_memory()
 
dbg_write_memory(0x4780B8, '\x33\xC0\xC3\x90')#antiDebug7
refresh_debugger_memory()
五、sncheck分析
1、异常处理函数注册
1
2
3
4
5
6
7
CODE:004994A7                 push    dword ptr fs:[eax]
CODE:004994AA                 mov     fs:[eax], esp
CODE:004994AD                 mov     eax, offset sub_475ED8
CODE:004994B2                 mov     edx, ds:off_49C3D8
CODE:004994B8                 mov     [edx+4], eax
CODE:004994BB                 mov     eax, ds:off_49C3D8
CODE:004994C0                 call    sub_46590C
其中sub_475ED8为异常处理函数
1
2
3
4
5
6
7
CODE:004994A7                 push    dword ptr fs:[eax]
CODE:004994AA                 mov     fs:[eax], esp
CODE:004994AD                 mov     eax, offset sub_475ED8
CODE:004994B2                 mov     edx, ds:off_49C3D8
CODE:004994B8                 mov     [edx+4], eax
CODE:004994BB                 mov     eax, ds:off_49C3D8
CODE:004994C0                 call    sub_46590C
其中sub_475ED8为异常处理函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
signed int __cdecl sub_475ED8(_DWORD *a1, int a2, int a3)
{
  signed int result; // eax
 
  result = 1;
  if ( !a1[1] )
  {
    if ( *a1 == 0xC0000096 )
    {
      *(_DWORD *)(a3 + 184) = realSnCheck;
      result = 0;
    }
    else if ( *a1 == 0xC00000FD )
    {
      *(_DWORD *)(a3 + 196) -= 256;
    }
  }
  return result;
}
其中 475EBC(realSnCheck)为异常0C0000096h处理函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
signed int __cdecl sub_475ED8(_DWORD *a1, int a2, int a3)
{
  signed int result; // eax
 
  result = 1;
  if ( !a1[1] )
  {
    if ( *a1 == 0xC0000096 )
    {
      *(_DWORD *)(a3 + 184) = realSnCheck;
      result = 0;
    }
    else if ( *a1 == 0xC00000FD )
    {
      *(_DWORD *)(a3 + 196) -= 256;
    }
  }
  return result;
}
其中 475EBC(realSnCheck)为异常0C0000096h处理函数
2、获取vmp指令
1
2
CODE:00499530                 call    GetVmpCode
CODE:00499535                 mov     [ebp+var_10], eax
其中 eax+4 为VMP指令地址,  eax+8为指令大小
1
2
CODE:00499530                 call    GetVmpCode
CODE:00499535                 mov     [ebp+var_10], eax
其中 eax+4 为VMP指令地址,  eax+8为指令大小
3、产生异常,进入 475EBC(realSnCheck)
六、 realSnCheck( 475EBC )
1、realSnCheck  调用477778 与之前类似
     1)解密代码和指令
     2)判断加密的指令是否是真实代码,如果是,这将相应代码进行重定位动态执行
     3)如果是VMP指令,则进入虚拟机执行。
      本题没有真实代码,所有指令都为虚拟机代码
2、最终会进入476B8C(codeExe)函数中
七、codeExe函数

[注意]看雪招聘,专注安全领域的专业人才平台!

最后于 2019-9-25 17:53 被oooAooo编辑 ,原因:
收藏
免费 2
支持
分享
赞赏记录
参与人
雪币
留言
时间
PLEBFE
为你点赞~
2023-1-22 03:07
wsc
为你点赞~
2019-9-25 18:18
最新回复 (3)
雪    币: 19
活跃值: (128)
能力值: ( LV9,RANK:146 )
在线值:
发帖
回帖
粉丝
2
哦哦,原来是这样子,'嗯'我已经完全搞懂了
2019-9-25 19:14
0
雪    币: 5801
活跃值: (10625)
能力值: ( LV9,RANK:181 )
在线值:
发帖
回帖
粉丝
3
这题最牛的是,如果调试的时候输入了正确的结果,也提示错误!!!让我完美的错过了侥幸获取flag的机会。
2019-9-27 12:06
0
雪    币: 441
活跃值: (419)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
师傅,你这个脚本编写的时候那几个地址的来历可以普及下吗
2019-10-4 22:35
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册