圣天诺的虚拟机保护方式:关于那个巨大的二叉树。。。。。
先说明一个结构:
CallStruct
{ WORD
key1;
WORD key2;
DWORD code;
};
这个结构共 8 个字节长,程序开始部分即取自该结构中的数据进行分析,从而进入不同的模块部分。
代码如下:
:004119A6 A194754000
mov eax, dword ptr [00407594] <---注:地址
00407594 中保存的就是 CallStruct 结构的指针
:004119AB 8B0D94754000
mov ecx, dword ptr [00407594]
:004119B1 668B00
mov ax, word ptr [eax]
<---取 key1
:004119B4
66A3A0754000 mov word ptr [004075A0],
ax
:004119BA 668B5102
mov dx, word ptr [ecx+02] <---取
key2
:004119BE 668915A4754000 mov word
ptr [004075A4], dx
:004119C5 8B4104
mov eax, dword ptr [ecx+04] <---取
code
:004119C8 A398754000
mov dword ptr [00407598], eax
:004119CD 011D94754000
add dword ptr [00407594], ebx
:004119D3 33C0
xor eax, eax
:004119D5
66A1A0754000 mov ax, word ptr [004075A0]
:004119DB 3D42030000 cmp
eax, 00000342
<---判断 key1 从而进入不同的模块部分
:004119E0 7F13
jg 004119F5
:004119E2 0F84C6010000
je 00411BAE
:004119E8 3DE4000000
cmp eax, 000000E4
:004119ED 0F8481010000
je 00411B74
:004119F3 EBB1
jmp 004119A6
从以上可以看到 key1 用作代表不同的模块。进一步分析程序,可以分析得出其使用 00407590 、00407594 、00407598 这三个地址来用作数据传递的地址。以后我将其简称为
A 、B 、C 。
key1 的作用知道了,那么来了解一下 key2 的作用。分析可以发现 key2 是在某些模块内部(也就是说并非所有模块)用作取值方式的。
下面以分析 004116D0 处的模块为例:
其调用形式为: CALL_004116D0(var1,var2)
当 key2 = 68 时,程序实现功能为: 返回 [var1] 的 Byte 字节。(注: [var1] 表示取 var1 地址中的值,以下类同)
当 key2 = D4 时,程序实现功能为: 返回 [[407590] + 4*var1] 的 DWORD 字节。
(注:即 取407590地址中的值,然后加上4乘以var1的和,再取以"和"为地址的值,返回)
下面列举几个模块和 key2 的组合及相应实现的功能:
key2 模块名1
模块名2
模块名3
4116D0
411670
411E1D
功能:返回 eax
功能:赋值
功能:判断某些位是否不为0
68
byte [var1]
[var1] <= byte var3
if( [[407590]] & 0x000000FF
<> 0 ) ok!
D4 dword [var1 * 4 + [407590]]
[var1 * 4 + [407590]] <= var3
if( [[407590]] <>
0 ) ok!
234 dword [var1]
[var1] <=
dword var3 if(
[[407590]] <> 0 ) ok!
28E word [var1]
[var1] <=
word var3 if(
[[407590]] & 0x0000FFFF <> 0 ) ok!
3D5
var1
直接返回
if( [[407590]] <>
0 ) ok!
下面再来具体分析一下各个模块的功能及作用,列举如下:
为简化表达,把 4116D0 、411670
、411E1D 分别命名为 f1( ) 、f2( ) 、f3( )
key1 模块起始地址
模块功能
0611 411BCA
类似 411E1D 模块,也会根据key2的值实现判断功能。只是 <> 变为 == 判断即可。
0704
411C1B f2([407598],key2,f1([407598],key2))
1092 411C4F
[[407590]] += f1([407598],key2)
1109 411C72
[[407590]+4] = call_407598([[407590]+4],[[407590]])
, [407590] += 4
1992 411C9B
f2([407598],key2,[[407590]]) , [407590] += 4
1A44 411CC4
[407590] -= 4, [[407590]] =
call_407598()
22B7 411D00
[[407590]] -= f1([407598],key2)
3345 411D23
[[407590]] &= f1([407598],key2)
5910 411FBA
[407594] <= [407598]
654D 411D9D
[[407590]] |= f1([407598],key2)
698A
411E00 f2([407598],key2,0)
7123 411E1D
判断
74BB 411E6E
[[407590]] ^= f1([407598],key2)
9104
411ED1 [[407590]]
*= f1([407598],key2)
AA61 411F2D
[[407590]+C] = call_407598([[407590]+C],[[407590]+8],[[407590]+4],[[407590]]),
[407590] += 0xC
B323 411F5F
[[407590]+8] = call_407598([[407590]+8],[[407590]+4],[[407590]]),
[407590] += 8 还原算法
BA51 411F8C
[[407590]] = call_407598([407590])
CDD3 411FC9
[[407590]+edi] = [407598] = f1([407598],key2)
归纳可以发现如下:
1、判断模块,分别实现不等跳转和相等跳转。
0611 411BCA
类似 411E1D 模块,也会根据key2的值实现判断功能。只是 <> 变为 == 判断即可。
7123 411E1D
判断
2、四则运算模块,分别实现加、减、乘、等运算。
74BB 411E6E
[[407590]] ^= f1([407598],key2)
9104 411ED1
[[407590]] *= f1([407598],key2)
1092 411C4F
[[407590]] += f1([407598],key2)
22B7 411D00
[[407590]] -= f1([407598],key2)
3345 411D23
[[407590]] &= f1([407598],key2)
654D 411D9D
[[407590]] |= f1([407598],key2)
3、赋值模块,分别实现不同方式的赋值。
698A 411E00 f2([407598],key2,0)
0704 411C1B
f2([407598],key2,f1([407598],key2))
1992 411C9B
f2([407598],key2,[[407590]])
, [407590] += esi
4、调用函数模块,分别实现不同参数方式函数调用。
1A44 411CC4
[407590] += edi, [[407590]]
= call_407598()
BA51 411F8C
[[407590]] = call_407598([407590])
1109 411C72
[[407590]+4] = call_407598([[407590]+4],[[407590]])
, [407590] += esi
AA61 411F2D
[[407590]+C] = call_407598([[407590]+C],[[407590]+8],[[407590]+4],[[407590]]),
[407590] += 0xC
B323 411F5F
[[407590]+8] = call_407598([[407590]+8],[[407590]+4],[[407590]]),
[407590] += ebx 还原算法
5、其他,实现数据的传递和控制程序流程。
CDD3
411FC9 [[407590]+edi]
= [407598] = f1([407598],key2)
5910 411FBA
[407594] <= [407598]
最后说明一下:
这是以前自己分析圣天诺外壳时整理的一些记录。那个二叉树的各个分支就是用于识别各个伪机器码的。上面分析的就是各个伪机器码的作用,以及伪机器码的格式的。这个伪处理机只使用在圣天诺的最外层结构上,而进入核心部分还是和我们常见的程序没有什么区别。
如果你不了解圣天诺的这个伪处理机,那么从某些方面来说防止了暴破,因为我们常常会从弹出的对话框入手来找到程序的关键暴破点,但是这个壳中使用的伪处理机的判断部分是在伪处理机的一个用于进行"判断"的模块(实际上就是一条伪机器码)中,如果你不明白这其中的道理,把这个"判断"模块中的"JZ"语句修改了,就相当于把整个伪处理机中的"判断"模块修改了一样,想象一下如果我们把程序中所有的"JZ"指令改成"JNZ"的后果,这有些类似这个道理。
当然,也有有趣的地方,在其中一个早期版本的圣天诺外壳中,倒是程序中只使用了"JZ"判断模块,如果你把这个"判断"模块修改一下,会出现什么后果?这样伪处理机反而使暴破省事了。
- 标 题:圣天诺的虚拟机保护方式:关于那个巨大的二叉树。。。。。 (5千字)
- 作 者:ljtt
- 时 间:2002-7-7
16:14:19
- 链 接:http://bbs.pediy.com