代码加壳保护软件VMProtect:Tls回调函数分析(下)

转帖|使用教程|编辑:杨鹏连|2021-07-28 11:09:55.987|阅读 42 次

概述:由于工作需要,经常会接触一些加过壳的软件,VMProtect是其中自己比较'欣赏'的一款加壳软件,Tls回调函数分析。

# 31款JAVA开发必备控件和工具 # 企业数字化建设合规无风险[专题]

VMProtect是一种很可靠的工具,可以保护应用程序代码免受分析和破解,但只有在应用程序内保护机制正确构建且没有可能破坏整个保护的严重错误的情况下,才能实现最好的效果。

VMProtect通过在具有非标准体系结构的虚拟机上执行代码来保护代码,这将使分析和破解软件变得十分困难。除此之外,VMProtect还可以生成和验证序列号,限制免费升级等等。

下载VMProtect最新试用版

VMProtect正版授权在线订购享受最低价,仅售801元起!还不赶紧加入你的订购清单?>>更多详情可点击咨询购买

Tls回调函数(上)

参考上节的跟踪记录vm_tls.txt,可以看到第117行和第290行的VmCALL将代码分成3块,标记为Chunk1 - Chunk3,我们先看下VmCALL的实现,再分别分析这3块代码。

VmCALL

可以看到,VmCALL取栈中DWORD作为基数计算RBX和RSI,我们第一篇分析过,RSI指向字节码缓冲区,RBX为解密Seed,也就是说每个Chunk都有自己的RSI和RBX。

Chunk1

在继续分析Chunk之前,可先参考下节Nor Gate说明,其对用到的运算的Nor变换做了详细说明,下面的分析不在赘述。

[Anakin] VmPOP V_98                 ;V_98 = $HandlerBase
[Anakin] VmPUSH FFFFFFFF9F5A5C32
[Anakin] VmADD
[Anakin] VmPOP V_40
[Anakin] VmPOP V_B8
[Anakin] VmPOP V_28
[Anakin] VmPOP V_18
[Anakin] VmPOP V_00
[Anakin] VmPOP V_78
[Anakin] VmPOP V_A0
[Anakin] VmPOP V_90
[Anakin] VmPOP V_40
[Anakin] VmPOP V_20
[Anakin] VmPOP V_68
[Anakin] VmPOP V_50
[Anakin] VmPOP V_58
[Anakin] VmPOP V_30
[Anakin] VmPOP V_B0
[Anakin] VmPOP V_38
[Anakin] VmPOP V_48
[Anakin] VmPOP V_70
[Anakin] VmPOP V_88
[Anakin] VmPOP V_10
[Anakin] VmPOP V_A8
[Anakin] VmPUSH 0000000064765E24    ;压栈分支1标识
[Anakin] VmPUSHB8 00
[Anakin] VmPUSH 000000014018B3E7
[Anakin] VmPUSH V_98
[Anakin] VmADD
[Anakin] VmPOP V_08
[Anakin] VmREADB                    ;b = BYTE:[000000014018B3E7 + $HandlerBase]
[Anakin] VmSBP
[Anakin] VmREADB
[Anakin] VmNOTANDB                  ;b = ~b
[Anakin] VmPOP V_60         
[Anakin] VmADDB                     ;b = 00 + b
[Anakin] VmPOP V_10                 ;V_10 = eflags
[Anakin] VmSBP
[Anakin] VmREADB
[Anakin] VmNOTANDB                  ;b = ~b
[Anakin] VmPOP V_80                 ;V_80 = eflags
[Anakin] VmPOPW8 V_60               ;V_60 = b  
[Anakin] VmPUSH V_10
[Anakin] VmPUSH V_10
[Anakin] VmNOTAND                   ;d1 = NOTAND(V_10, V_10)            => d1 = ~V_10
[Anakin] VmPOP V_60
[Anakin] VmPUSH FFFFFFFFFFFFF7EA
[Anakin] VmNOTAND                   ;d1 = NOTAND(d1, FFFFF7EA)          => d1 = Nor(~V_10, ~00000815) = V_10 & 00000815
[Anakin] VmPOP V_08
[Anakin] VmPUSH V_80                
[Anakin] VmPUSH V_80
[Anakin] VmNOTAND                   ;d2 = NOTAND(V_80, V_80)            => d2 = ~V_80
[Anakin] VmPOP V_60
[Anakin] VmPUSH 0000000000000815
[Anakin] VmNOTAND                   ;d2 = NOTAND(d2, 00000815)          => d2 = Nor(~V_80, ~FFFFF7EA) = V_80 & FFFFF7EA
[Anakin] VmPOP V_08
[Anakin] VmADD
[Anakin] VmPOP V_08
[Anakin] VmPOP V_70                 ;V_70 = d1 + d2                     => V_70 = EFLAGS(BYTE:[000000014018B3E7 + $HandlerBase] - 0)
[Anakin] VmPUSH 0000000064766651    ;压栈分支2标识
[Anakin] VmSBP                      ;压栈栈顶指针,用于后文选择分支
[Anakin] VmPUSHB8 03
[Anakin] VmPUSHD 000000BF
[Anakin] VmPUSH V_70
[Anakin] VmNOTAND                   ;q = CDQ(NOTAND(V_70, 000000BF))    => ZF == 0 ? 0b1000000 : 0 
[Anakin] VmPOP V_68
[Anakin] VmSHR                      ;q = SHR(q, 3)                      => ZF == 0 ? 8 : 0 
[Anakin] VmPOP V_08
[Anakin] VmADD                      ;q += SavedRBP (上文压栈的栈顶指针,选择分支)
[Anakin] VmPOP V_08
[Anakin] VmREADQ
[Anakin] VmPOP V_A8                 ;V_A8 = QWORD:[q](取分支标识)
[Anakin] VmPOP V_68
[Anakin] VmPOP V_08
[Anakin] VmPUSH V_A8
[Anakin] VmPOPD V_A8                ;V_A8 = CQD(V_A8)
[Anakin] VmPUSHD V_A8               
[Anakin] VmSBP
[Anakin] VmREADD
[Anakin] VmNOTANDD                  ;d1 = NOTAND(V_A8, V_A8)
[Anakin] VmPOP V_08
[Anakin] VmPUSHD DB91AA8C
[Anakin] VmNOTANDD                  ;d1 = NOTAND(d1, DB91AA8C)          => d1 = Nor(~V_A8, ~246E5573)
[Anakin] VmPOP V_68
[Anakin] VmPUSHD 246E5573
[Anakin] VmPUSHD V_A8
[Anakin] VmNOTANDD                  ;d2 = NOTAND(V_A8, 246E5573)        => d2 = Nor(V_A8, 246E5573)
[Anakin] VmPOP V_60
[Anakin] VmNOTANDD
[Anakin] VmPOP V_60
[Anakin] VmPOP V_08                 ;V_08 = NOTAND(d2, d1)              => V_08 = Nor(d1, d2) = V_A8 ^ 246E5573 (分支标识解密)
[Anakin] VmPUSH V_18
[Anakin] VmPUSH V_98
[Anakin] VmPUSH V_60
[Anakin] VmPUSH V_00
[Anakin] VmPUSH V_88
[Anakin] VmPUSH V_50
[Anakin] VmPUSH V_30
[Anakin] VmPUSH V_B0
[Anakin] VmPUSH V_20
[Anakin] VmPUSH V_28
[Anakin] VmPUSH V_38
[Anakin] VmPUSH V_78
[Anakin] VmPUSH V_A0
[Anakin] VmPUSH V_90
[Anakin] VmPUSH V_58
[Anakin] VmPUSH V_48
[Anakin] VmPUSH V_40
[Anakin] VmPUSH V_18
[Anakin] VmPUSH V_70
[Anakin] VmPUSH V_B8
[Anakin] VmPUSH 0000000060A5A3CE
[Anakin] VmADD
[Anakin] VmPOP V_60
[Anakin] VmPUSH V_98
[Anakin] VmPUSH V_08                ;压栈解码后的分支标识                           
[Anakin] VmCALL                      ;调用选择分支

等价逻辑:

If (*(BYTE*)(000000014018B3E7 + $HandlerBase) != 0)
{
//未执行
VmCALL 40180B57
}
Else
{
//即Chunk2
VmCALL 40183322
}

Chunk2

[Anakin] VmPOP V_90                     ;V_90 = $HandlerBase
[Anakin] VmPUSH FFFFFFFF9F5A5C32
[Anakin] VmADD
[Anakin] VmPOP V_20
[Anakin] VmPOP V_00
[Anakin] VmPOP V_70
[Anakin] VmPOP V_80
[Anakin] VmPOP V_60
[Anakin] VmPOP V_98
[Anakin] VmPOP V_38
[Anakin] VmPOP V_48
[Anakin] VmPOP V_28
[Anakin] VmPOP V_18
[Anakin] VmPOP V_30
[Anakin] VmPOP V_10
[Anakin] VmPOP V_88
[Anakin] VmPOP V_08
[Anakin] VmPOP V_A8
[Anakin] VmPOP V_40
[Anakin] VmPOP V_20
[Anakin] VmPOP V_68
[Anakin] VmPOPD V_78                    ;V_78 = eflags
[Anakin] VmPUSHD V_78
[Anakin] VmPUSHD V_78
[Anakin] VmNOTANDD
[Anakin] VmPOP V_B0
[Anakin] VmPUSHD DB91AA8C
[Anakin] VmNOTANDD
[Anakin] VmPOP V_B8
[Anakin] VmPUSHD 246E5573
[Anakin] VmPUSHD V_78
[Anakin] VmNOTANDD
[Anakin] VmPOP V_50
[Anakin] VmNOTANDD
[Anakin] VmPOP V_B0
[Anakin] VmPOP V_A0                     ;V_A0 = V_78 ^ 246E5573
[Anakin] VmPOP V_58
[Anakin] VmPOP V_B8
[Anakin] VmPUSH V_70
[Anakin] VmPUSH V_88
[Anakin] VmPUSH V_08
[Anakin] VmPUSH V_48
[Anakin] VmPUSH V_98
[Anakin] VmPUSH V_80
[Anakin] VmPUSH V_A8
[Anakin] VmPUSH 000000000CABFA9E        ;PUSH Branch1
[Anakin] VmPUSH 000000014018B3E7
[Anakin] VmPUSH V_90
[Anakin] VmADD
[Anakin] VmPOP V_50                     ;PUSH (V_90 + 000000014018B3E7)
[Anakin] VmPUSH 0000000140000000
[Anakin] VmPUSH V_90
[Anakin] VmADD
[Anakin] VmPOP V_58
[Anakin] VmPOP V_50                     ;V_50 = V_90 + 0000000140000000         => V_50 = PIMAGE_DOS_HEADR
[Anakin] VmPUSH V_50
[Anakin] VmPUSHD 0000003C
[Anakin] VmADD
[Anakin] VmPOP V_58                     ;PUSH (V_50 + 0000003C)
[Anakin] VmREADD
[Anakin] VmPOPD V_88                    ;V_88 = DWORD:[BP]                      => V_88 = PIMAGE_DOS_HEADER->e_lfanew
[Anakin] VmPUSH 0000000000000000
[Anakin] VmPOPD V_8C
[Anakin] VmPUSH V_88
[Anakin] VmPUSH V_50
[Anakin] VmADD
[Anakin] VmPOP V_A8                     ;PUSH (V_50 + V_88)                     => PUSH PIMAGE_NT_HEADERS64
[Anakin] VmSBP
[Anakin] VmREADQ        
[Anakin] VmPOP V_B0   
[Anakin] VmPUSHD 00000028               
[Anakin] VmADD
[Anakin] VmPOP V_A8                     ;PUSH (PIMAGE_NT_HEADERS64 + 00000028)  => PUSH PIMAGE_NT_HEADERS64->AddressOfEntryPoint
[Anakin] VmREADD
[Anakin] VmPOPD V_B0                    ;V_B0 = AddressOfEntryPoint
[Anakin] VmPUSH 0000000000000000
[Anakin] VmPOPD V_B4                    ;V_B4 = 0
[Anakin] VmPUSH V_50
[Anakin] VmPUSH V_B0
[Anakin] VmADD
[Anakin] VmPOP V_A8
[Anakin] VmPOP V_A8                     ;V_A8 = V_B0 + V_50
[Anakin] VmPUSHB8 cc
[Anakin] VmPUSH V_A8
[Anakin] VmREADB                        ;b = BYTE:[V_A8], 判断程序入口点地址第一个字节是不是‘0xCC’
[Anakin] VmSBP                          ;判断逻辑参考Chunk1及Nor Gate
[Anakin] VmREADB
[Anakin] VmNOTANDB
[Anakin] VmPOP V_58                     
[Anakin] VmADDB
[Anakin] VmPOP V_58
[Anakin] VmSBP
[Anakin] VmREADB
[Anakin] VmNOTANDB
[Anakin] VmPOP V_B8
[Anakin] VmPOPW8 V_70
[Anakin] VmPUSH V_58
[Anakin] VmSBP
[Anakin] VmREADQ
[Anakin] VmNOTAND
[Anakin] VmPOP V_88
[Anakin] VmPUSH FFFFFFFFFFFFF7EA
[Anakin] VmNOTAND
[Anakin] VmPOP V_B0
[Anakin] VmPUSH V_B8
[Anakin] VmPUSH V_B8
[Anakin] VmNOTAND
[Anakin] VmPOP V_70
[Anakin] VmPUSH 0000000000000815
[Anakin] VmNOTAND
[Anakin] VmPOP V_88
[Anakin] VmADD
[Anakin] VmPOP V_88
[Anakin] VmPOP V_70
[Anakin] VmPOP V_88
[Anakin] VmPUSH 000000000CABFDC1        ;PUSH Branch2
[Anakin] VmSBP
[Anakin] VmPUSHB8 03
[Anakin] VmPUSHD 000000BF
[Anakin] VmPUSH V_70
[Anakin] VmNOTAND
[Anakin] VmPOP V_A0
[Anakin] VmSHR
[Anakin] VmPOP V_B0
[Anakin] VmADD
[Anakin] VmPOP V_B0
[Anakin] VmREADQ
[Anakin] VmPOP V_58
[Anakin] VmPOP V_B0
[Anakin] VmPOP V_08
[Anakin] VmPUSH V_58
[Anakin] VmPOPD V_58
[Anakin] VmPUSHD V_58
[Anakin] VmSBP
[Anakin] VmREADD
[Anakin] VmNOTANDD
[Anakin] VmPOP V_A0
[Anakin] VmPUSHD B34CBE36
[Anakin] VmNOTANDD
[Anakin] VmPOP V_78
[Anakin] VmPUSHD 4CB341C9       
[Anakin] VmPUSHD V_58
[Anakin] VmNOTANDD
[Anakin] VmPOP V_B0
[Anakin] VmNOTANDD
[Anakin] VmPOP V_B0
[Anakin] VmPOP V_08                     ;V_08 = $Branch ^ 4CB341C9
[Anakin] VmPUSH V_50
[Anakin] VmPUSH V_08
[Anakin] VmPUSH V_80
[Anakin] VmPUSH V_B0
[Anakin] VmPUSH V_40
[Anakin] VmPUSH V_88
[Anakin] VmPUSH V_38
[Anakin] VmPUSH V_98
[Anakin] VmPUSH V_18
[Anakin] VmPUSH V_68
[Anakin] VmPUSH V_28
[Anakin] VmPUSH V_30
[Anakin] VmPUSH V_48
[Anakin] VmPUSH V_60
[Anakin] VmPUSH V_10
[Anakin] VmPUSH V_A8
[Anakin] VmPUSH V_20
[Anakin] VmPUSH V_50
[Anakin] VmPUSH V_70
[Anakin] VmPUSH V_00
[Anakin] VmPUSH 0000000060A5A3CE
[Anakin] VmADD
[Anakin] VmPOP V_B0
[Anakin] VmPUSH V_90
[Anakin] VmPUSH V_08                     ;压栈选择的分支
[Anakin] VmCALL

等价逻辑:

If (*(BYTE*)($ImageBase + AddressOfEntryPoint) != 0xCC)
{
//即Chunk3
VmCALL 4018BB57
}
Else
{
//虽然调试器设置默认在入口地址处下int3断点,但是我们的脚本启动时,会把所有断点禁用,因此并没有走Else分支。
VmCALL 4018BC08
}

Chunk3

[Anakin] VmPOP V_A8
[Anakin] VmPUSH FFFFFFFF9F5A5C32
[Anakin] VmADD
[Anakin] VmPOP V_10
[Anakin] VmPOP V_10
[Anakin] VmPOP V_30
[Anakin] VmPOP V_28
[Anakin] VmPOP V_08
[Anakin] VmPOP V_B8
[Anakin] VmPOP V_60
[Anakin] VmPOP V_88
[Anakin] VmPOP V_40
[Anakin] VmPOP V_70
[Anakin] VmPOP V_A0
[Anakin] VmPOP V_B0
[Anakin] VmPOP V_18
[Anakin] VmPOP V_48
[Anakin] VmPOP V_00
[Anakin] VmPOP V_80
[Anakin] VmPOP V_90
[Anakin] VmSBP
[Anakin] VmREADD
[Anakin] VmPOPD V_38
[Anakin] VmSBP
[Anakin] VmREADD
[Anakin] VmNOTANDD
[Anakin] VmPOP V_68
[Anakin] VmPUSHD B34CBE36
[Anakin] VmNOTANDD
[Anakin] VmPOP V_50
[Anakin] VmPUSHD V_38
[Anakin] VmPUSHD 4CB341C9
[Anakin] VmNOTANDD
[Anakin] VmPOP V_98
[Anakin] VmNOTANDD
[Anakin] VmPOP V_20
[Anakin] VmPOP V_20
[Anakin] VmPOP V_68
[Anakin] VmPOP V_98
[Anakin] VmPOP V_78
[Anakin] VmPOP V_50
[Anakin] VmPOP V_58
[Anakin] VmPOP V_78
[Anakin] VmPOP V_28
[Anakin] VmPOP V_40
[Anakin] VmPOP V_80
[Anakin] VmPOP V_68
[Anakin] VmPUSH V_68
[Anakin] VmSBP
[Anakin] VmREADQ
[Anakin] VmNOTAND
[Anakin] VmPOP V_48
[Anakin] VmPUSH 00000000000008FF
[Anakin] VmNOTAND
[Anakin] VmPOP V_B8
[Anakin] VmPOPFQ
[Anakin] VmPUSH V_08
[Anakin] VmPUSH V_20
[Anakin] VmPUSH V_78
[Anakin] VmPUSH V_70
[Anakin] VmPUSH V_40
[Anakin] VmPUSH V_50
[Anakin] VmPUSH V_00
[Anakin] VmPUSH V_90
[Anakin] VmPUSH V_68
[Anakin] VmPUSH V_80
[Anakin] VmPUSH V_88
[Anakin] VmPUSH V_28
[Anakin] VmPUSH V_A0
[Anakin] VmPUSH V_18
[Anakin] VmPUSH V_B0
[Anakin] VmPUSH V_58
[Anakin] VmPUSH V_60
[Anakin] VmPUSH V_18
[Anakin] VmPUSH V_A8

[Anakin] VmRet

没有特别需要关注的信息,处理寄存器,函数执行完毕,返回调用处。

综上,Tls的执行逻辑为:
If (*(BYTE*)(000000014018B3E7 + $HandlerBase) != 0)
{
//未执行
VmCALL 40180B57
}
Else
{
If (*(BYTE*)($ImageBase + AddressOfEntryPoint) != 0xCC)
{
Return
}
Else
{
//虽然调试器设置默认在入口地址处下int3断点,但是我们的脚本运行时,会把所有断点禁用(line 15),因此并没有走Else分支。
//PS:  这个分支会在 $HandlerBase + 000000014018B3E8 地址处写一个字节‘0x01’,然后返回。
//            此处暂略,后文分析反调试时再谈。
VmCALL 4018BC08
}
}

Nor Gate

基本单元:或非门(Nor)

两个输入位皆为0时输出1,其它情况输出0.
PS: VMP实现的NOTAND操作使用了Not和And操作,有些文档称之为'与非门',但是从逻辑语义上来说,其实现的是'或非'操作(见上表),此处遵从语义将其称之为或非门(Nor)。

取反(~)

[Anakin] VmREADB                    ;b = BYTE:[000000014018B3E7 + $HandlerBase]
[Anakin] VmSBP
[Anakin] VmREADB

[Anakin] VmNOTANDB                  ;b = NOTAND(b, b)

取反计算~v实现如下:

Result = Nor(v, v)

输入1   输入2   Result
  0          0          1
   1            1            0

与(&)

[Anakin] VmPUSH V_10
[Anakin] VmPUSH V_10
[Anakin] VmNOTAND                   ;d1 = NOTAND(V_10, V_10)            => d1 = ~V_10
[Anakin] VmPOP V_60
[Anakin] VmPUSH FFFFFFFFFFFFF7EA

[Anakin] VmNOTAND                   ;d1 = NOTAND(d1, FFFFF7EA)          => d1 = Nor(~V_10, ~00000815) = V_10 & 00000815

与计算v1&v2实现如下:
D1 = ~v1
D2 = ~v2
Result = Nor(D1, D2)

异或(^)

[Anakin] VmPUSHD V_A8               ;V_A8 = CQD(V_A8)
[Anakin] VmSBP
[Anakin] VmREADD
[Anakin] VmNOTANDD                  ;d1 = NOTAND(V_A8, V_A8)            => d1 = ~V_A8
[Anakin] VmPOP V_08
[Anakin] VmPUSHD DB91AA8C
[Anakin] VmNOTANDD                  ;d1 = NOTAND(d1, DB91AA8C)          => d1 = Nor(~V_A8, ~246E5573)
[Anakin] VmPOP V_68
[Anakin] VmPUSHD 246E5573
[Anakin] VmPUSHD V_A8
[Anakin] VmNOTANDD                  ;d2 = NOTAND(V_A8, 246E5573)        => d2 = Nor(V_A8, 246E5573)
[Anakin] VmPOP V_60
[Anakin] VmNOTANDD
[Anakin] VmPOP V_60

[Anakin] VmPOP V_08                 ;V_08 = NOTAND(d2, d1)              => V_08 = Nor(d1, d2) = V_A8 ^ 246E5573

异或计算v1^v2实现如下:
D1 = Nor(~v1, ~v2) = v1 & v2
D2 = Nor(v1, v2)
Result = Nor(D1, D2)

减法(-)

[Anakin] VmREADB                    ;b = BYTE:[000000014018B3E7 + $HandlerBase]
[Anakin] VmSBP
[Anakin] VmREADB
[Anakin] VmNOTANDB                  ;b = NOTAND(b, b) = ~b
[Anakin] VmPOP V_60         
[Anakin] VmADDB                     ;b = 00 + b
[Anakin] VmPOP V_10                 ;V_10 = eflags
[Anakin] VmSBP
[Anakin] VmREADB
[Anakin] VmNOTANDB                  ;b = NOTAND(b, b) = ~b
[Anakin] VmPOP V_80                 ;V_80 = eflags

[Anakin] VmPOPW8 V_60               ;V_60 = b = BYTE:[000000014018B3E7 + $HandlerBase] - 0 

反码实现减法运算v1-v2如下:
D1 = ~v1
D2 = D1 + v2
Result  = ~D2, 即 Result  = ~(~v1 + v2)

此处不做推导,看几个实例:

 再看下对eflags的处理:
[Anakin] VmPUSH V_10
[Anakin] VmPUSH V_10
[Anakin] VmNOTAND                   ;d1 = NOTAND(V_10, V_10)            => d1 = ~V_10
[Anakin] VmPOP V_60
[Anakin] VmPUSH FFFFFFFFFFFFF7EA
[Anakin] VmNOTAND                   ;d1 = NOTAND(d1, FFFFF7EA)          => d1 = Nor(~V_10, ~00000815) = V_10 & 00000815
[Anakin] VmPOP V_08
[Anakin] VmPUSH V_80                
[Anakin] VmPUSH V_80
[Anakin] VmNOTAND                   ;d2 = NOTAND(V_80, V_80)            => d2 = ~V_80
[Anakin] VmPOP V_60
[Anakin] VmPUSH 0000000000000815
[Anakin] VmNOTAND                   ;d2 = NOTAND(d2, 00000815)          => d2 = Nor(~V_80, ~FFFFF7EA) = V_80 & FFFFF7EA
[Anakin] VmPOP V_08
[Anakin] VmADD
[Anakin] VmPOP V_08
[Anakin] VmPOP V_70                 ;V_70 = d1 + d2
其中FFFFF7EA = ~00000815, 00000815 = 0b100000010101。
eflags定义如下:
V_10和V_80皆为eflags, 可以看到v_70 由 V_10的CF, PF, AF及OF位 +(or) V_80的其它位(ZF, SF等)得到。
V_10由VmADDB置位,最后指令为Add, 受影响标志位为 OF, SF, ZF, AF, CF, PF;
V_80由VmNOTANDB置位,最后指令为And, 受影响标志位为OF(0), CF(0), SF, ZF, PF。
简单考虑最常用到的SF和ZF,可以看到这两个标志位是可以正确反映运算结果的。

不等(!=)

[Anakin] VmPUSHB8 03
[Anakin] VmPUSHD 000000BF
[Anakin] VmPUSH V_70
[Anakin] VmNOTAND                   ;q = CDQ(NOTAND(V_70, 000000BF))
[Anakin] VmPOP V_68
[Anakin] VmSHR                      ;q = SHR(q, 3) = ZF == 0 ? 8 : 0
[Anakin] VmPOP V_08
[Anakin] VmADD                      ;q += SavedRBP
[Anakin] VmPOP V_08
[Anakin] VmREADQ
[Anakin] VmPOP V_A8                 ;V_A8 = QWORD:[q]

不等判断需结合上文的'减法'分析,代码中V_70为eflag(v1 - v2);

像And操作取'1'位一样,Nor操作可以取'0'位,上述代码Nor(V_70, 000000BF),其中000000BF = 0b10111111。可以看到当ZF标志位为0时(!=, 即两数相减结果不为0时),返回0b1000000,否则返回0。
结合之后的SHR及取栈数据代码, 可以进一步猜想SHR 3 是经过优化的代码,如下:
优化前:Bool b = Nor(Eflags(v1 - v2), 000000BF) >> 6;Qword offset = b << 3;
优化后:Qword offset = Nor(Eflags(v1 - v2), 000000BF) >> 3;
计算v1 != v2得实现如下:

(Nor(Eflags(v1 - v2), 000000BF) >> 6)  == 1。


如果您对该加密/解密软件感兴趣,欢迎加入vmpQQ交流群:740060302


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至hey@evget.com

文章转载自:看雪

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
在线咨询
联系我们
TOP
在线客服系统
live chat