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
標簽:
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:看雪