本帖最后由 currwin 于 2014-10-6 11:43 编辑
恩恩,啰嗦了这么久,其实也就是把很少的东西讲来讲去而已: Esi 保存数据流。 Ebp变成堆栈指针。 Edi 有0x60的空间保存数据。 程序使用数据流来驱动。
好像懂了,又好像不懂对吧。前面我说了啥Handle的,高深得很,装逼装得太厉害了。其实并没有这么高大上。比如说,我前面讲到的3号Handle,就完成了一个pop的操作,所以,我把它命名为 VM_POP_[Num],需要一个字节的数据标志出pop到的地方。 好,其他的handle也同样的来处理。
0号: 004015D2 /> \8B75 00 mov esi,dword ptr [ebp] ; 移动数据流的指针 004015D5 |. 83C5 04 add ebp,4 ; 移动堆指针 004015D8 \.^ E9 FBFEFFFF jmp VM_Distribution ;返回到VM分配 根据对指针修改数据流指针。表达为: pop esi 命名: VM_JMP_[ebp] 所需数据:0个
1号: 004015A2 /> \8B5D 00 mov ebx,dword ptr [ebp] ; 取栈数据① 004015A5 |. 8B55 04 mov edx,dword ptr [ebp+4] ; 取栈数据② 004015A8 |. F7D3 not ebx ; ①取反 004015AA |. F7D2 not edx ; ②取反 004015AC |. 23DA and ebx,edx ; 取反结果求与 004015AE |. 895D 04 mov dword ptr [ebp+4],ebx ; 最终结果写入栈数据② 004015B1 |. 9C pushfd 004015B2 |. 8F45 00 pop dword ptr [ebp] ; 取反导致的flag寄存器值写入栈数据① 004015B5 \.^ E9 1EFFFFFF jmp VM_Distribution 取了栈中数据①,②,取反求与,然后写入flag寄存器值以及求与后的值。这其实是或非门,自身就是一个全集了。什么,不懂?不要紧,下面会解析的 命名: VM_Or_Non 所需数据:0个
2号: 00401529 |> \33C0 xor eax,eax 0040152B |. AC lods byte ptr [esi] ; 取序号 0040152C |. C1E0 02 shl eax,2 ; 取地址 0040152F |. 83ED 04 sub ebp,4 ; 移动堆栈指针 00401532 |. 8B1C38 mov ebx,dword ptr [edi+eax] ; 从数据空间中取出数据 00401535 |. 895D 00 mov dword ptr [ebp],ebx ; 进入堆栈中 00401538 \.^ EB 9E jmp short VM_Distribution 与最初介绍的pop恰好是相反的操作,从数据空间(edi)中取出数据,进入到堆栈(ebp)中。 命名: VM_PUSH_[Num] 所需数据:1个。 (push 的数据的序号)
3号: 00401500 |> \33C0 xor eax,eax 00401502 |. AC lods byte ptr [esi] ; 取序号 00401503 |. C1E0 02 shl eax,2 ; * 4 = 地址 00401506 |. 8B5D 00 mov ebx,dword ptr [ebp] ; 取堆顶内容 00401509 |. 891C38 mov dword ptr [edi+eax],ebx ; 移动到栈空间去 0040150C |. 83C5 04 add ebp,4 ; 移动VM堆指针 0040150F \.^ EB C7 mp short VM_Distribution ; 跳回去VM函数分派地方,进行下一个分派 作用已经说明,是一个pop的操作 命名: VM_POP_[Num] 所需数据:1个。 (pop 的数据的序号)
4号: 0040154E /> \33C0 xor eax,eax 00401550 |. AD lods dword ptr [esi] ; 取 DWORD 数据 00401551 |. 83ED 04 sub ebp,4 ; 入栈 00401554 |. 8945 00 mov dword ptr [ebp],eax 00401557 \.^ E9 7CFFFFFF jmp VM_Distribution 依旧是对堆栈进行操作,直接push 一个4直接的数据。 命名: VM_PUSH_DWORD 所需数据: 4个。 (push 所需的一个 DWORD 大小的立即数)
5号: 00401574 |> \8B5D 00 mov ebx,dword ptr [ebp] ; 取数据① 00401577 |. 8B55 04 mov edx,dword ptr [ebp+4] ; 取数据② 0040157A |. 03DA add ebx,edx ; ①+② 0040157C |. 895D 04 mov dword ptr [ebp+4],ebx ; 保存相加结果到②中 0040157F |. 9C pushfd 00401580 |. 8F45 00 pop dword ptr [ebp] ; ①中存放相加得到的flag寄存器 00401583 \.^ E9 50FFFFFF jmp VM_Distribution 把堆栈中的数据相加。。。 命名: VM_ADD 所需数据:0个
6号: 004015F5 /> \33C0 xor eax,eax 004015F7 |. 66:AD lods word ptr [esi] ; 取WORD大小的数据 004015F9 |. 83ED 02 sub ebp,2 ; 入堆栈 004015FC |. 66:8945 00 mov word ptr [ebp],ax 00401600 \.^ E9 D3FEFFFF jmp VM_Distribution Push 一个WORD大小的数据进入堆栈。。。呵呵,这个堆栈还不是严格4字节对齐的。 命名: VM_PUSH_WORD 所需数据:2个 (push 所需的一个WORD大小的立即数)
7号: 00401623 /> \60 pushad 00401624 |. 896C24 1C mov dword ptr [esp+1C],ebp ; 修改eax 00401628 |. 61 popad ; --> eax = ebp(堆指针) 00401629 |. 8A08 mov cl,byte ptr [eax] ; 取除数①(BYTE -> WORD) 0040162B |. 8B40 02 mov eax,dword ptr [eax+2] ; 取被除数②(DWORD) 0040162E |. 83ED 02 sub ebp,2 ; 移动堆栈 00401631 |. D3E8 shr eax,cl ; ②/2^① 00401633 |. 8945 04 mov dword ptr [ebp+4],eax ; 除法结果写入② 00401636 |. 9C pushfd 00401637 |. 8F45 00 pop dword ptr [ebp] ; 标志位写入① 0040163A \.^ E9 99FEFFFF jmp VM_Distribution 取堆栈中的两个数据,进行移位,移位结果写回堆栈。前后堆栈变化如下: 除数①(WORD) --> flag①(DWORD) 被除数②(DWORD) --> 结果②(DWORD) 就结果来说堆栈大小变大了2个字节。那么我想大家可能已经明白了为啥前面会有push WORD 的操作了吧。 这个是移位操作,但是理解为除法也是可以的。比如:② = ② / 2^① 命名: VM_DIV 所需数据:0个
8号: 00401657 |> \8BC5 mov eax,ebp 00401659 |. 83ED 04 sub ebp,4 0040165C |. 8945 00 mov dword ptr [ebp],eax ; push 堆栈顶指针 0040165F \.^ E9 74FEFFFF jmp VM_Distribution Push 当前堆栈顶的指针。。。有啥用啊? 命名: VM_PUSH_EBP 所需数据:0个
9号: 004016A7 |> \83C4 60 add esp,60 ; 清除新建的空间 004016AA |. 9D popfd ; 还原标志flag 004016AB |. 61 popad ; 还原寄存器 004016AC \. C3 retn 与前面初始化VM的时候的操作是恰好相反的,结尾也是retn而不是跳回VM分派的地方。实际上,这里就是退出VM的地方了。 命名: VM_RETN 所需数据:0个
10号: 00401682 /> \8B45 00 mov eax,dword ptr [ebp] ; 取栈顶指针数据 00401685 |. 8B00 mov eax,dword ptr [eax] ; 取指针指向的数据 00401687 |. 8945 00 mov dword ptr [ebp],eax ; 写入栈顶 0040168A \.^ E9 49FEFFFF jmp VM_Distribution 很简单的几行代码,只是把栈顶的数据当做一个指针,把它指向的DWORD的数据给还原出来而已。 如果配合上面讲到的VM_PUSH_EBP 来使用的话,就相当于把栈顶的内容复制了一遍。 命名: VM_DECODEPOINT_DWORD 所需数据:0个
11号: 004016AD /. 33C0 xor eax,eax ; VM_DECODEPOINT_BYTE 004016AF |. 8B45 00 mov eax,dword ptr [ebp] 004016B2 |. 8A00 mov al,byte ptr [eax] 004016B4 |. 0FB6C0 movzx eax,al 004016B7 |. 8945 00 mov dword ptr [ebp],eax 004016BA \.^ E9 19FEFFFF jmp VM_Distribution 与10号作用非常相似,只是他还原的目标对象为一个BYTE的数据而已。 命名: VM_DECODEPOINT_BYTE 所需数据: 0个
|