【文章标题】: Themida VM 代码还原
【文章作者】: hawk
【作者邮箱】: hkp2000hk@sina.com
【作者主页】: http://localhost
【作者QQ号】: 99224775
【软件名称】: Themida.不知道
【下载地址】: 自己搜索下载
【保护方式】: 虚拟机
【使用工具】: 老三样
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
IDA分析目标发现虚拟机,应该是Themida CISC 版本及加密参数不详。
虚拟机入口0x1EAE4,ContextBase 0x1E800 MethodTableSize 0xA8
首先IDA手工修复代码,虚拟机主体为一函数,160+Method分别建立函数。
把0x1EB4E主循环扒下来
//----------------------------------------------------//
lodsb
xor al, bl
push 7BB9h
mov [esp], edx
mov dh, 28h
jmp loc_22604
shl dh, 6
push ebx
mov bl, 4Eh
sub bl, 11h
sub bl, 0EAh
xor dh, bl
pop ebx
jmp loc_1F55B
xor al, dh
jmp loc_23352
mov edx, [esp]
add esp, 4
push ecx
jmp loc_1FF5D
push ebx
jmp loc_1F06D
mov bh, 6Eh
add bh, 0DDh
jmp loc_20342
neg bh
shl bh, 2
sub bh, 1
not bh
xor bh, 0B3h
mov ch, bh
pop ebx
jmp loc_20878
sub al, ch
mov ecx, [esp]
jmp loc_20CB2
add esp, 4
sub bl, 7Eh
sub bl, 2Ah
sub bl, al
jmp loc_21116
push ecx
mov cl, 2Ah
add bl, cl
jmp loc_22287
pop ecx
push edx
mov dl, 0C3h
xor dl, 84h
jmp loc_22B10
sub dl, 0DBh
jmp loc_2273F
sub dl, 0F7h
xor dl, 0Bh
jmp loc_1F6D9
add bl, dl
pop edx
movzx eax, al
jmp dword ptr [edi+eax*4]
//-------------------修复后的代码--------------------//
LODSB
XOR AL, BL
XOR AL, 53H
SUB AL, 9FH
SUB BL, AL
MOVZX EAX, AL
JMP DWORD PTR [EDI+EAX*4]
//---------------------------------------------------//
VS2008 新建工程
ref class _VM_Analyze
{
public:
static String^ GetHexString(UInt32 HexValue,Int32 Size);
UInt32 ImageBase;
array<Byte> ^ImageData;
UInt32 ContextBase;
UInt32 ContextKey;
UInt32 CodePointer;
StringWriter ^AnalyzeResult;
Byte ReadByte();
UInt16 ReadWord();
UInt32 ReadDword();
Boolean Decode();
Void LoadImage(String^ ImagePath);
_VM_Analyze(UInt32 Key);
};
Boolean _VM_Analyze::Decode()
{
/*
LODSB
XOR AL, BL
XOR AL, 53H
SUB AL, 9FH
SUB BL, AL
MOVZX EAX, AL
JMP DWORD PTR [EDI+EAX*4]
*/
Byte Opcode=ReadByte();
Byte Key=ContextKey;
Opcode=Opcode^Key;
Opcode=Opcode^0x53;
Opcode=Opcode-0x9F;
Key=Key-Opcode;
ContextKey=ContextKey&0xFFFFFF00|Key;
switch (Opcode)
{
default:
{
UInt32 K=ContextKey;
UInt32 P=CodePointer;
String ^s=AnalyzeResult->ToString();
throw s;
}
}
}
OllyICE 加载目标 下断MainLoop JumpMethodTable
VS2008 F5 抛出异常 Opcode=0x?? ContextKey=0x????????
OllyICE JumpMethodTable 条件断 AL==0x??
对比ContextKey==EBX 恭喜清洗代码应该没有什么BUG
按照Opcode==0x??拔下对应的Method代码
清洗之
一般都是
LODS?
(ADD|SUB|???) EAX, EBX
(ADD|???????) EAX, 0x???????
(ADD|???????) EAX, 0x???????
(ADD|???????) EBX, EAX
????????
????????
JMP MainLoop
清洗后的代码贴到switch(Opcode)里面
case 0x2E:
/*
LODSB
XOR AL, BL
ADD AL, 0CAH
ADD AL, 1BH
ADD BL, AL
MOVZX EAX, AL
LEA EAX, [EDI+EAX*4]
PUSH EAX
*/
{
Byte arg1=ReadByte();
Byte Key=ContextKey;
arg1=arg1^Key;
arg1=arg1+0xCA;
arg1=arg1+0x1B;
Key=Key+arg1;
ContextKey=ContextKey&0xFFFFFF00|Key;
AnalyzeResult->WriteLine(String::Format("PUSH\t{0}",GetHexString(ContextBase+arg1*4,4)));
}
return true;
扒掉取arg1和解码更新Key的代码
剩下的代码原样输出
本来160+的Method现在大概只要处理20-40个吧
原先的VMCode经过处理之后就成功从CISC映射到了X86
//-----------------------------映射过的代码---------------------------//
PUSH 1E81CH
POP EDX
POP DWORD PTR [EDX]
PUSH 1E814H
POP EDX
POP DWORD PTR [EDX]
PUSH 1E800H
POP EDX
POP DWORD PTR [EDX]
PUSH 1E810H
POP EDX
POP DWORD PTR [EDX]
PUSH 1E80CH
POP EDX
POP DWORD PTR [EDX]
MOV BYTE PTR [1E828H], 1
PUSH 1E80CH
POP EDX
POP DWORD PTR [EDX]
PUSH 1E808H
POP EDX
POP DWORD PTR [EDX]
PUSH 1E804H
POP EDX
POP DWORD PTR [EDX]
PUSH 1E818H
POP EDX
POP DWORD PTR [EDX]
MOV EDX, ESP
PUSH EDX
PUSH 4
POP EAX
ADD [ESP], EAX
POP ESP
PUSH 1E810H
POP EDX
PUSH DWORD PTR [EDX]
PUSH ESP
PUSH 1E810H
POP EDX
PUSH EDX
PUSH 1E804H
PUSH 1E810H
POP EDX
POP EDX
POP EDX
POP DWORD PTR [EDX]
PUSH ESP
PUSH 14H
POP EAX
SUB [ESP], EAX
PUSHF
POP DWORD PTR [1E81CH]
POP ESP
PUSH 1E80CH
POP EDX
PUSH DWORD PTR [EDX]
PUSH 1E800H
POP EDX
PUSH DWORD PTR [EDX]
PUSH EDX
PUSH 1E800H
POP EDX
PUSH DWORD PTR [EDX]
POP EDX
PUSH 1E80CH
POP EDX
PUSH DWORD PTR [EDX]
POP EDX
POP EDX
PUSH 1E814H
PUSH 1E818H
POP EDX
PUSH DWORD PTR [EDX]
POP EDX
POP EDX
PUSH DWORD PTR [EDX]
PUSH 1E80CH
POP EDX
PUSH DWORD PTR [EDX]
PUSH 1E80CH
POP EDX
PUSH DWORD PTR [EDX]
PUSH 1E810H
POP EDX
PUSH DWORD PTR [EDX]
PUSH 1E80CH
POP EDX
PUSH DWORD PTR [EDX]
POP EAX
ADD [ESP], EAX
PUSHF
POP DWORD PTR [1E81CH]
POP EDX
POP EAX
XOR [ESP], EAX
PUSHF
POP DWORD PTR [1E81CH]
PUSH 1E80CH
POP EDX
PUSH EDX
PUSH EDX
PUSH 4
POP EAX
ADD [ESP], EAX
POP EDX
POP EDX
POP DWORD PTR [EDX]
PUSH 1E818H
POP EDX
PUSH DWORD PTR [EDX]
PUSH 1E818H
PUSH 1E800H
PUSH 1E814H
POP EDX
POP EDX
PUSH DWORD PTR [EDX]
POP EDX
POP EDX
PUSH DWORD PTR [EDX]
POP EAX
XOR [ESP], EAX
PUSHF
POP DWORD PTR [1E81CH]
PUSH 1E818H
POP EDX
PUSH EDX
PUSH SMALL 6B21H
PUSH 1E808H
POP EDX
PUSH DWORD PTR [EDX]
POP EDX
PUSH SMALL 9594H
POP EDX
POP EDX
POP DWORD PTR [EDX]
PUSH 1E80CH
POP EDX
PUSH SMALL WORD PTR [EDX]
PUSH DWORD PTR [1E810H]
POP EDX
PUSH EDX
PUSH 0FFFFFFF4H
POP EAX
ADD [ESP], EAX
POP EDX
PUSH EDX
PUSH 1E804H
POP EDX
PUSH DWORD PTR [EDX]
PUSH SMALL 6C0EH
PUSH SMALL 0D566H
POP EDX
POP EDX
POP EDX
POP SMALL WORD PTR [EDX]
PUSH DWORD PTR [1E810H]
POP EDX
PUSH EDX
PUSH 0FFFFFFF6H
POP EAX
ADD [ESP], EAX
PUSH SMALL 8E94H
PUSH SMALL 5A8FH
POP EDX
POP EDX
PUSH EDX
PUSH EDX
PUSH 1E810H
PUSH SMALL 0CE98H
PUSH SMALL 152DH
POP EDX
POP EDX
POP EDX
PUSH 1E814H
POP EDX
POP DWORD PTR [EDX]
MOV EBX, 0
PUSH 1E818H
POP EDX
PUSH EDX
PUSH 1E818H
POP EDX
PUSH DWORD PTR [EDX]
POP EDX
POP EDX
MOV EBX, 0
PUSH DWORD PTR [EDX]
MOV EBX, 0
PUSH EDX
PUSH SMALL 0BD8FH
PUSH SMALL 0C90CH
POP EDX
POP EDX
PUSH DWORD PTR [1E814H]
POP EDX
MOV EBX, 0
POP DWORD PTR [EDX]
PUSH EDX
PUSH 1E808H
POP EDX
POP EDX
MOV EBX, 0
JXXX 3000011H
JNX 23B6CH
//-----------------------------------------------------------//
Themida 的VMCode也是经过混淆的(该死的多态变形)
一开始的代码大概意思就是
POPF
POP EDI
POP ESI
POP EBP
POP ESP//VM 是堆栈机 不用ESP 再说了 POPA 也不改ESP
POP EBX
POP EDX
POP ECX
POP EAX
搞定VM 寄存器 地址啦
#define R_EFLAG "1E81CH"
#define R_EDI "1E814H"
#define R_ESI "1E800H"
#define R_EBP "1E810H"
#define R_ESP "1E80CH"
#define R_EBX "1E80CH"
#define R_EDX "1E808H"
#define R_ECX "1E804H"
#define R_EAX "1E818H"
//------------------------------经过清洗的X86版虚拟代码--------------------//
MOV EDX, 1E81CH
POP DWORD PTR [EDX]
MOV EDX, 1E814H
POP DWORD PTR [EDX]
MOV EDX, 1E800H
POP DWORD PTR [EDX]
MOV EDX, 1E810H
POP DWORD PTR [EDX]
MOV EDX, 1E80CH
POP DWORD PTR [EDX]
MOV BYTE PTR [1E828H], 1
MOV EDX, 1E80CH
POP DWORD PTR [EDX]
MOV EDX, 1E808H
POP DWORD PTR [EDX]
MOV EDX, 1E804H
POP DWORD PTR [EDX]
MOV EDX, 1E818H
POP DWORD PTR [EDX]
MOV EDX, ESP
PUSH EDX
MOV EAX, 4
ADD [ESP], EAX
POP ESP
MOV EDX, 1E810H
PUSH DWORD PTR [EDX]
PUSH ESP
MOV EDX, 1E810H
POP DWORD PTR [EDX]
PUSH ESP
MOV EAX, 14H
SUB [ESP], EAX
PUSHF
POP DWORD PTR [1E81CH]
POP ESP
MOV EDX, 1E80CH
PUSH DWORD PTR [EDX]
MOV EDX, 1E800H
PUSH DWORD PTR [EDX]
MOV EDX, 1E814H
PUSH DWORD PTR [EDX]
MOV EDX, 1E80CH
PUSH DWORD PTR [EDX]
MOV EDX, 1E80CH
PUSH DWORD PTR [EDX]
MOV EDX, 1E810H
PUSH DWORD PTR [EDX]
MOV EDX, 1E80CH
MOV EAX, [EDX]
ADD [ESP], EAX
PUSHF
POP DWORD PTR [1E81CH]
POP EDX
POP EAX
XOR [ESP], EAX
PUSHF
POP DWORD PTR [1E81CH]
PUSH 1E80CH
PUSH EDX
MOV EAX, 4
ADD [ESP], EAX
POP EDX
POP EDX
POP DWORD PTR [EDX]
MOV EDX, 1E818H
PUSH DWORD PTR [EDX]
MOV EDX, 1E818H
MOV EAX, [EDX]
XOR [ESP], EAX
PUSHF
POP DWORD PTR [1E81CH]
PUSH 1E818H
PUSH SMALL 6B21H
MOV EDX, [1E808H]
PUSH SMALL 9594H
POP EDX
POP EDX
POP DWORD PTR [EDX]
MOV EDX, 1E80CH
PUSH SMALL WORD PTR [EDX]
PUSH DWORD PTR [1E810H]
MOV EAX, 0FFFFFFF4H
ADD [ESP], EAX
POP EDX
POP SMALL WORD PTR [EDX]
PUSH DWORD PTR [1E810H]
MOV EAX, 0FFFFFFF6H
ADD [ESP], EAX
MOV EDX, 8E945A8FH
MOV EDX, 1E814H
POP DWORD PTR [EDX]
MOV EDX, 1E818H
PUSH DWORD PTR [EDX]
MOV EDX, [1E814H]
POP DWORD PTR [EDX]
JXXX 3000011H
JNX 23B6CH
//---------------------------------------------------------------------------------//
现在吧X86代码空间的虚拟代码在映射一把
吧Register也映射回来
//----------------------------------真正的X86版代码--------------------------------//
POPF
POP EDI
POP ESI
POP EBP
POP EBX
MOV BYTE PTR [1E828H], 1
POP EBX
POP EDX
POP ECX
POP EAX
PUSH ESP
ADD DWORD PTR [ESP], 4
POP ESP
PUSH EBP
PUSH ESP
POP EBP
PUSH ESP
SUB DWORD PTR [ESP], 14H
PUSHF
POPF
POP ESP
PUSH EBX
PUSH ESI
PUSH EDI
PUSH EBX
XOR [ESP], EBX
PUSHF
POPF
POP EBX
PUSH EAX
XOR [ESP], EAX
PUSHF
POPF
POP EAX
PUSH BX
POP SMALL WORD PTR [EBP+0FFFFFFF4H]
PUSH EBP
ADD DWORD PTR [ESP], 0FFFFFFF6H
POP EDI
PUSH EAX
POP DWORD PTR [EDI]
JXXX 3000011H
JNX 23B6CH
//-------------------------------------------------------------------------------------//
再次清洗一边
//-------------------------------------最终的成品面世啦--------------------------------//
POPF
POP EDI
POP ESI
POP EBP
POP EBX
MOV BYTE PTR [1E828H], 1
POP EBX
POP EDX
POP ECX
POP EAX
ADD ESP, 4
PUSH EBP
MOV EBP, ESP
SUB ESP, 14H
PUSH EBX
PUSH ESI
PUSH EDI
XOR EBX, EBX
XOR EAX, EAX
MOV [EBP-0CH], BX
LEA EDI, [EBP-0AH]
MOV [EDI], EAX
JXXX 3000011H
JNX 23B6CH
//-----------------------------------------------------------------------------------------------//
至此全部工序就此结束
//-----------------------------------------------------------------------------------------------//
--------------------------------------------------------------------------------
【经验总结】
虚拟机的本质其实就是代码的多态变形,难点也就是对多态代码的归一化处理,从明文到密文是单向和确定的,
但是从密文到明文却是多项和不确定的。规则复杂的吓人,盼望会玩太极的牛人快快写一工具出来救广大人民于水火。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2009年02月17日 22:18:27
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。