Handler的基本执行流程 下面介绍handler的执行过程。不同类型的handler对VM_Context.flag的位有不同的解释,对于从PCODE.OpcodeDetail解码数据的使用也不同。这里只涉及handler共同的部分,与handler类型相关的细节在分析handler类别的时候再讲。 以Vm_Load指令为例,这个指令将1个imm32装入VM_Context.register(即VM的寄存器),后续代码并未使用,实际上等同于垃圾指令。该指令不使用VM_Context.flag,可以避免过多的细节。 进入handler后,将esi置为pcode数据地址,取Init_Keys字节,若b7为1则将Key1清0。取InitKey1_and_NumOfRotate(名取得很拙劣,但总得有个名字J)字节的低2位,进一步变换Key1。 cl=1。这些imm8是加壳时生成的随机数。 cl
= 2。 cl
= 3。 取InitKey1_and_NumOfRotate的b2-b4 3位,这个值若为0,jz跳走。否则将VM_Context内的通用寄存器环滚动指定的字节数。这段代码看起来比较啰嗦,对于写解码器也没有影响,可以直接到jz的dst继续。 如果你想看看数据是怎么滚动的,可以用OllyDbg,在进入VM前将各寄存器设为特定值。 进入VM后,在dump窗口显示VM_Context。 设置停止条件,然后Ctrl-F11跟踪。 很直观J。注意不是每次都会滚动,寄存器的值也会因执行的操作而变化。 继续。下面解码PCODE.Argument。 解码handler操作需要的细节数据,即上文中的OpcodeDetail。Vm_Load需要2个byte。 这里将flag的值预置为4。解码2个字节,根据解码结果设置VM_Context.flag。具体的细节在分析特定类型的handler时再讲。 测试OpcodeDetail第1个字节的低7位,继续设置VM_Context.flag。这是个switch-case,无论走哪个分枝,都会在VM栈内压入1个dword。细节后面再讲。 下面有很多caller的代码就是switch-case的出口。到这里,VM栈内(与进入该handler时相比)压入了2个dword,[esp+4]为解码的Argument,[esp]是switch-case压入的dword。 解码下1条指令的opcode2。 接下来这不起眼的2行,就是在执行Vm_Load了。将switch-case压入栈的dword送到VM_Context.register。 解码下1条指令的opcode1。 解码下1条指令的pcode数据地址。 到这里结束当前handler,执行下1条指令。 对于当前handler的执行,有几项数据是在执行实质的操作前必须解码的,即寄存器滚动字节数,Argument,OpcodeDetail。跳到下条指令需要的数据(Next_pcode,Next_opcode1,Next_opcode2)只要在jmp esi前解码即可,实际上Themida正是这样做的,这3项数据的解码操作位置是可变的。 在下面的部分,我们将详细分析4类handler的细节。
- 标 题: Themida v1.8.0.0 Demo虚拟机分析 – Part3
- 作 者:softworm
- 时 间:2006-12-17 12:33
- 链 接:http://bbs.pediy.com/showthread.php?threadid=36453