【文章标题】: MoleBox中的SMC分析
【文章作者】: 一朵雪花
【软件名称】: MoleBox2.x
【下载地址】: 自己搜索下载
【加壳方式】: Molebox2.x
【软件介绍】: OllyDBG
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
在解包MoleBox文件的时候,发现MoleBox中有用到SMC的技术,顺便分析一下。
因为只是分析SMC部分,所以就略过跟踪过程,直接分析他的机制。
下面是SMC函数的汇编代码
00560A4D 55 push ebp
00560A4E 8BEC mov ebp, esp
00560A50 53 push ebx
00560A51 56 push esi
00560A52 57 push edi
00560A53 60 pushad
00560A54 33D2 xor edx, edx ;edx清0
00560A56 8D4D 08 lea ecx, dword ptr [ebp+8] ;参数一的地址,后面通过该地址加4找到要修改的代码地址
00560A59 E8 11FFFFFF call 0056096F
00560A5E 61 popad
00560A5F 5F pop edi
00560A60 5E pop esi
00560A61 5B pop ebx
00560A62 5D pop ebp
00560A63 C2 0400 retn 4
下面我们进入0056096F处看看
0056096F 55 push ebp
00560970 8BEC mov ebp, esp
00560972 6A FF push -1
00560974 68 58A45600 push 0056A458
00560979 68 4C855500 push 0055854C
0056097E 64:A1 00000000 mov eax, dword ptr fs:[0]
00560984 50 push eax
00560985 64:8925 0000000>mov dword ptr fs:[0], esp
0056098C 51 push ecx
0056098D 51 push ecx
0056098E 83EC 1C sub esp, 1C
00560991 53 push ebx
00560992 56 push esi
00560993 57 push edi
上面是设置SEH栈
00560994 8955 CC mov dword ptr [ebp-34], edx
00560997 894D D0 mov dword ptr [ebp-30], ecx ; 参数地址
temp_34 = edx; //前面知道edx=0
temp_30 = ecx; //ecx为参数的地址
0056099A B8 C0975500 mov eax, 005597C0
0056099F FF70 04 push dword ptr [eax+4]
005609A2 FF15 58D75600 call dword ptr [56D758] ; ntdll.RtlEnterCriticalSection
005609A8 8365 FC 00 and dword ptr [ebp-4], 0
//进入CriticalSection
005609AC 8B45 D0 mov eax, dword ptr [ebp-30]
005609AF 8B00 mov eax, dword ptr [eax]
005609B1 8945 DC mov dword ptr [ebp-24], eax
temp_24 = 参数1的值
005609B4 8B45 D0 mov eax, dword ptr [ebp-30]
005609B7 8B40 FC mov eax, dword ptr [eax-4]
005609BA 8945 D4 mov dword ptr [ebp-2C], eax
temp_2c = 函数的返回地址的值
005609BD 8B45 DC mov eax, dword ptr [ebp-24]
005609C0 25 FFFF0000 and eax, 0FFFF
005609C5 8B4D D4 mov ecx, dword ptr [ebp-2C]
005609C8 2BC8 sub ecx, eax
005609CA 894D E4 mov dword ptr [ebp-1C], ecx
temp_1c = temp_2c + LOWWORD(temp_24) = 函数的返回地址-LOWWORD(arg1);
005609CD 8B45 DC mov eax, dword ptr [ebp-24]
005609D0 C1E8 10 shr eax, 10
005609D3 8B4D D4 mov ecx, dword ptr [ebp-2C]
005609D6 03C8 add ecx, eax
005609D8 894D D8 mov dword ptr [ebp-28], ecx
temp_28 = 函数的返回地址-HIGHWORD(arg1);
005609DB 8B45 E4 mov eax, dword ptr [ebp-1C]
005609DE 8945 E0 mov dword ptr [ebp-20], eax
005609E1 EB 07 jmp short 005609EA
005609E3 8B45 E4 mov eax, dword ptr [ebp-1C]
005609E6 40 inc eax
005609E7 8945 E4 mov dword ptr [ebp-1C], eax
005609EA 8B45 E4 mov eax, dword ptr [ebp-1C]
005609ED 3B45 D8 cmp eax, dword ptr [ebp-28]
005609F0 74 1C je short 00560A0E
005609F2 8B45 E4 mov eax, dword ptr [ebp-1C]
005609F5 69C0 0D661900 imul eax, eax, 19660D
005609FB 05 5FF36E3C add eax, 3C6EF35F
00560A00 8B4D E4 mov ecx, dword ptr [ebp-1C]
00560A03 8A09 mov cl, byte ptr [ecx]
00560A05 32C8 xor cl, al
00560A07 8B45 E4 mov eax, dword ptr [ebp-1C]
00560A0A 8808 mov byte ptr [eax], cl
00560A0C ^ EB D5 jmp short 005609E3
for(int i=temp_1c; i<temp_28; i++){
*((char*)i) ^= (char)(i * 0x19660D + 0x3C6EF35F);
}
00560A0E 8B45 D8 mov eax, dword ptr [ebp-28]
00560A11 2B45 E0 sub eax, dword ptr [ebp-20]
00560A14 50 push eax
00560A15 FF75 E0 push dword ptr [ebp-20]
00560A18 FF35 20D75600 push dword ptr [56D720]
00560A1E FF15 04D75600 call dword ptr [56D704] ; kernel32.FlushInstructionCache
//把指令写入缓存
00560A24 834D FC FF or dword ptr [ebp-4], FFFFFFFF
00560A28 E8 02000000 call 00560A2F ;退出CriticalSection
00560A2D EB 0F jmp short 00560A3E
00560A2F B8 C0975500 mov eax, 005597C0
00560A34 FF70 04 push dword ptr [eax+4]
00560A37 FF15 E8D75600 call dword ptr [56D7E8] ; ntdll.RtlLeaveCriticalSection
00560A3D C3 retn
00560A3E 8B4D F0 mov ecx, dword ptr [ebp-10]
00560A41 64:890D 0000000>mov dword ptr fs:[0], ecx
00560A48 5F pop edi
00560A49 5E pop esi
00560A4A 5B pop ebx
00560A4B C9 leave
00560A4C C3 retn
上面就是SMC的原理:函数有一个整型参数,参数的低16位保存这要往前修改的指令字节码数,高16位保存向后修改的指令字节码数。
下面我们看一个该函数的完整过程。
005600AC > \68 00001200 push 120000
005600B1 . E8 689BFFFF call <fn_smc> ; 要改变005600B6开始的0x12个字节
005600B6 . 0D 3A840D54 or eax, 540D843A
005600BB . 17 pop ss
005600BC . 9E sahf
005600BD . 16 push ss
005600BE . 6D ins dword ptr es:[edi], dx
005600BF . 001F add byte ptr [edi], bl
005600C1 . 05 39AE05FB add eax, FB05AE39
005600C6 . 92 xchg eax, edx
005600C7 . 8517 test dword ptr [edi], edx
005600C9 . 04 92 add al, 92
函数执行后指令变为
005600B6 . 90 nop
005600B7 ? 90 nop
005600B8 ? 33C9 xor ecx, ecx
005600BA ? 85C9 test ecx, ecx
005600BC .^ 75 EE jnz short 005600AC
005600BE . 68 12002900 push 290012 ; UNICODE "yy-MM-dd"
005600C3 ? E8 569BFFFF call <fn_smc>
005600C8 ? 17 pop ss
005600C9 . 04 92 add al, 92
005600CB . 7C 3E jl short 0056010B
005600CD . 1AA0 0C4EE4DE sbb ah, byte ptr [eax+DEE44E0C]
005600D3 . 40 inc eax
005600D4 . 23BB 7566D4A5 and edi, dword ptr [ebx+A5D46675]
005600DA . 51 push ecx
005600DB . 2F das
005600DC . 06 push es ; 保存和密钥相关的东西
005600DD . 15 754F4033 adc eax, 33404F75
005600E2 . 319411 FFF272>xor dword ptr [ecx+edx+E72F2FF], edx
005600E9 . 34 69 xor al, 69
005600EB . 4E dec esi
005600EC . B3 45 mov bl, 45
005600EE . EE out dx, al
005600EF . 7D 70 jge short 00560161
005600F1 . 0C 39 or al, 39
005600F3 . 8511 test dword ptr [ecx], edx
可见这里要修改005600C8前0x12个字节开始修改(0x12 + 0x29)个字节,首先恢复(因为实际是指令的改变是异或运算)上次调用修改的0x12个字节。
执行后指令变为
005600C8 ? 90 nop
005600C9 ? 90 nop
005600CA ? 33D2 xor edx, edx
005600CC ? 85D2 test edx, edx
005600CE ?^ 75 EE jnz short 005600BE
005600D0 . A1 18D75600 mov eax, dword ptr [56D718]
005600D5 . 8B48 2C mov ecx, dword ptr [eax+2C]
005600D8 . 83C1 20 add ecx, 20
005600DB . 51 push ecx
005600DC . 8D8D D0FDFFFF lea ecx, dword ptr [ebp-230] ;
005600E2 . E8 72E2FFFF call 0055E359 ;这里调用了一个函数
005600E7 . 68 29002800 push 280029 ;这里恢复前面修改的0x29个字节,修改下面的0x28个字节
005600EC . E8 2D9BFFFF call <fn_smc> ;执行SMC函数
005600F1 . 0C 39 or al, 39
005600F3 . 8511 test dword ptr [ecx], edx
005600F5 . 55 push ebp
005600F6 . 0F9F19 setg byte ptr [ecx]
005600F9 8F db 8F
005600FA . 54 push esp
005600FB . BE EAD04602 mov esi, 246D0EA
00560100 . D4 21 aam 21
00560102 . A5 movs dword ptr es:[edi], dword ptr [e>
00560103 . D7 xlat byte ptr [ebx+al]
00560104 . 1E push ds
00560105 . 2D 7D47382B sub eax, 2B38477D
0056010A . 096A 16 or dword ptr [edx+16], ebp
0056010D . F7EA imul edx
0056010F > 4A dec edx
00560110 . 07 pop es
00560111 . 3C 49 cmp al, 49
00560113 . 56 push esi
00560114 . 8B75 E6 mov esi, dword ptr [ebp-1A]
00560117 . 75 68 jnz short 00560181
00560119 . 90 nop
执行后指令变为
005600F1 . 90 nop
005600F2 ? 90 nop
005600F3 . 33D2 xor edx, edx
005600F5 . 85D2 test edx, edx
005600F7 ?^ 75 EE jnz short 005600E7
005600F9 8B db 8B
005600FA . 45 inc ebp
005600FB . A0 C1E80350 mov al, byte ptr [5003E8C1]
00560100 . 8B4D DC mov ecx, dword ptr [ebp-24]
00560103 . 51 push ecx
00560104 . 8D8D D0FDFFFF lea ecx, dword ptr [ebp-230]
0056010A . E8 84EDFFFF call 0055EE93 ;这里执行了一个函数
0056010F > 68 28000000 push 28
00560114 . E8 059BFFFF call <fn_smc> ;向前恢复0x28个字节指令。
00560119 . 90 nop
至此指令数据完全恢复原状。
SMC函数的参数依次为0x120000,0x290012, 0x280029, 0x28,恰好是一个闭合环。
下面使我对Molebox如何实现这一点做的一些猜测:
1.首先是利用下面的字节序列做特征串。
005600F1 . 90 nop
005600F2 ? 90 nop
005600F3 . 33D2 xor edx, edx
005600F5 . 85D2 test edx, edx
005600F7 ?^ 75 EE jnz short 005600E7
2.函数修改时按修改后的代码进行编写。
3.在生成的目标文件中搜索特征串,并计算该处指令映射到内存中后的地址,然后对地址做加密操作。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2010年01月21日 15:21:14
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!