VMP3 的 jcc 简单分析及可能应用
2019-11-03 19:37:06 Author: bbs.pediy.com(查看原文) 阅读量:120 收藏

[原创] VMP3 的 jcc 简单分析及可能应用

6小时前 243

[原创] VMP3 的 jcc 简单分析及可能应用

直接引码:

	for (int i = 0; i < 4; i++) {
01222056  mov         dword ptr [ebp-4],0  // # var i
0122205D  jmp         fun_pickup_from_map+28h (01222068h)  
0122205F  mov         eax,dword ptr [ebp-4]  // refer i
01222062  add         eax,1  // i++
01222065  mov         dword ptr [ebp-4],eax  
01222068  cmp         dword ptr [ebp-4],4  // # cmp i, 4
0122206C  jge         fun_pickup_from_map+57h (01222097h)  
    // ...
	}

以下对应VMP3的虚拟指令:

# i = 0
0087 006A6ED1 vAdd4 0018FEDC <- FFFFFFFC, <ebp>0018FEE0
0088 00688494 vPopReg4 [004] <- 00000203
0089 007416A8 vReadMemSs4 [0018FEDC] -> 00000000

# cmp i, 4

# ~i
0090 0052FDC6 vPushEsp4 0018FE82
0091 0073A93F vReadMemSs4 [0018FE82] -> 00000000
0092 005EEFA2 vNand4 FFFFFFFF <- 00000000, 00000000
0093 006B7196 vPopReg4 [010] <- 00000286
# ~i + 4
0094 0072EEBE vAdd4 00000003 <- FFFFFFFF, 00000004
0095 006C187D vPopReg4 [010] <- 00000217
# ~(~i + 4) => i - 4
0096 00560EEB vPushEsp4 0018FE86
0097 005AC9B3 vReadMemSs4 [0018FE86] -> 00000003
0098 0067C7EB vNor4 FFFFFFFC <- 00000003, 00000003
0099 004FF4B9 vPopReg4 [018] <- 00000286
0100 0071E4FC vPopReg4 [024] <- FFFFFFFC

# f1 = eflags of ~i + 4
0101 00519664 vPushReg4 [010] 00000217
0102 006A846B vPushImm4 2E7D332F
0103 0067C969 vPushImm4 004AB24C
0104 0064EFA4 vReadMemSs4 [004AB24C] -> D182D4E6
# NOTE: 0x815 
0105 005C6201 vAdd4 00000815 <- D182D4E6, 2E7D332F
0106 00639539 vPopReg4 [01C] <- 00000213
0107 006D4743 vNand4 FFFFFFEA <- 00000815, 00000217
0108 00531E52 vPopReg4 [024] <- 00000282
0109 00645F27 vPushEsp4 0018FE86
0110 005ED537 vReadMemSs4 [0018FE86] -> FFFFFFEA
0111 00510455 vNor4 00000015 <- FFFFFFEA, FFFFFFEA
0112 005919C4 vPopReg4 [008] <- 00000202

# f2 = eflags of ~(~i + 4)
0113 005188E3 vPushReg4 [018] 00000286

0114 00700BC1 vPushImm4 BEC22E73
0115 0073CFF4 vPushImm4 004AB250
0116 004E3333 vReadMemSs4 [004AB250] -> 413DC977
0117 0057E963 vAdd4 FFFFF7EA <- 413DC977, BEC22E73
0118 00551056 vPopReg4 [004] <- 00000282
# NOTE: FFFFF7EA == ~0x815
0119 0052C370 vNand4 FFFFFD7D <- FFFFF7EA, 00000286
0120 006519B6 vPopReg4 [020] <- 00000286
0121 004AE960 vPushEsp4 0018FE82
0122 00675D8B vReadMemSs4 [0018FE82] -> FFFFFD7D
0123 004F6BCA vNor4 00000282 <- FFFFFD7D, FFFFFD7D
0124 00523E4C vPopReg4 [020] <- 00000206

# => eflags =  (f1 & 0x815) + (f2 & ~0x815)
0125 0055A32C vAdd4 00000297 <- 00000282, 00000015
0126 00688494 vPopReg4 [030] <- 00000202
0127 006B7196 vPopReg4 [030] <- 00000297
0128 006C187D vPopReg4 [024] <- 00000207

0129 004FBD09 vPushReg4 [030] 00000297
0130 006B2A12 vPushReg4 [030] 00000297
0131 00525C60 vNand4 FFFFFD68 <- 00000297, 00000297
0132 004FF4B9 vPopReg4 [004] <- 00000282
0133 005A067A vPushImm4 57A4C945
0134 005A793D vPushImm4 004AB256
0135 00617E7D vReadMemSs4 [004AB256] -> A85B363A
0136 006FBCFE vAdd4 FFFFFF7F <- A85B363A, 57A4C945
0137 0071E4FC vPopReg4 [010] <- 00000282

# a = eflags & SF
0138 004AEAD6 vNor4 00000080 <- FFFFFF7F, FFFFFD68
0139 00639539 vPopReg4 [024] <- 00000202
0140 00531E52 vPopReg4 [004] <- 00000080

0141 004E4FCE vPushReg4 [030] 00000297
0142 005147F9 vPushImm4 673258CD
0143 0072A795 vPushImm4 004AB25A
0144 006E9C8F vReadMemSs4 [004AB25A] -> 98CDAF33
0145 0076946A vAdd4 00000800 <- 98CDAF33, 673258CD
0146 005919C4 vPopReg4 [01C] <- 00000217

# b = eflags & OF
0147 0052FBE7 vNand4 FFFFFFFF <- 00000800, 00000297
0148 00551056 vPopReg4 [010] <- 00000286
0149 0066B4C7 vPushEsp4 0018FE8A
0150 0053AA78 vReadMemSs4 [0018FE8A] -> FFFFFFFF
0151 004EECA7 vNand4 00000000 <- FFFFFFFF, FFFFFFFF
0152 006519B6 vPopReg4 [01C] <- 00000246
0153 00523E4C vPopReg4 [010] <- 00000000


0154 006FA614 vPushReg4 [024] 00000202
0155 005626A0 vPushReg4 [024] 00000202
0156 0072F738 vNand4 FFFFFDFD <- 00000202, 00000202
0157 00688494 vPopReg4 [008] <- 00000282

0158 005CC9A6 vPushReg4 [01C] 00000246
0159 00595AA8 vPushReg4 [01C] 00000246
0160 0065994B vNor4 FFFFFDB9 <- 00000246, 00000246
0161 006B7196 vPopReg4 [010] <- 00000282

# c = a_eflags & b_eflags 
0162 005582AF vNor4 00000202 <- FFFFFDB9, FFFFFDFD
0163 006C187D vPopReg4 [010] <- 00000202

# d = ~a_eflags & ~b_eflags 
0164 006FD628 vPushReg4 [024] 00000202
0165 005B5F3B vPushReg4 [01C] 00000246
0166 0050A804 vNor4 FFFFFDB9 <- 00000246, 00000202
0167 004FF4B9 vPopReg4 [004] <- 00000282

# e = nor(c, d)
0168 006B1989 vNor4 00000044 <- FFFFFDB9, 00000202
0169 0071E4FC vPopReg4 [004] <- 00000206
0170 00639539 vPopReg4 [010] <- 00000044

# e = c | d => nxor(c, d) => if(c == d)
0171 00519664 vPushReg4 [010] 00000044
0172 005188E3 vPushReg4 [010] 00000044
0173 00574BF9 vNor4 FFFFFFBB <- 00000044, 00000044
0174 00531E52 vPopReg4 [018] <- 00000286
0175 005919C4 vPopReg4 [004] <- FFFFFFBB


# g = e & ZF 
0176 004FBD09 vPushReg4 [004] FFFFFFBB
0177 006B2A12 vPushReg4 [004] FFFFFFBB
0178 0063803A vNand4 00000044 <- FFFFFFBB, FFFFFFBB
0179 00551056 vPopReg4 [008] <- 00000206

0180 00700D65 vPushImm4 F291278B
0181 005C99F9 vPushImm4 004AB25E
0182 005267FF vReadMemSs4 [004AB25E] -> 0D6ED834
0183 0071F837 vAdd4 FFFFFFBF <- 0D6ED834, F291278B
0184 006519B6 vPopReg4 [010] <- 00000282

0185 00621576 vNor4 00000000 <- FFFFFFBF, 00000044
0186 00523E4C vPopReg4 [018] <- 00000246

# h = g >> 0x6  // 0 or 1
0187 005E5B67 vShr4 00000000 <- 00000000, 00000006
0188 00688494 vPopReg4 [020] <- 00000246

0189 006A846B vPushImm4 C207B9AF
0190 0067C969 vPushImm4 004AB262
0191 00715986 vReadMemSs4 [004AB262] -> 3DF84650
0192 00698BD3 vAdd4 FFFFFFFF <- 3DF84650, C207B9AF
0193 006B7196 vPopReg4 [020] <- 00000286

# h1 = h - 1
0194 006A8ACA vAdd4 FFFFFFFF <- FFFFFFFF, 00000000
0195 006C187D vPopReg4 [018] <- 00000286
0196 004FF4B9 vPopReg4 [020] <- FFFFFFFF

0197 005C99F9 vPushImm4 94315D17
0198 0073CFF4 vPushImm4 004AB266
0199 005B610F vReadMemSs4 [004AB266] -> 6C423157
0200 006010F8 vAdd4 00738E6E <- 6C423157, 94315D17
0201 0071E4FC vPopReg4 [008] <- 00000203

0202 004E4FCE vPushReg4 [020] FFFFFFFF
0203 006FA614 vPushReg4 [020] FFFFFFFF
0204 0071DD9C vNand4 00000000 <- FFFFFFFF, FFFFFFFF
0205 00639539 vPopReg4 [018] <- 00000246

# h2 = nand(~h1, 00738E6E)
0206 006027AC vNand4 FFFFFFFF <- 00000000, 00738E6E
0207 00531E52 vPopReg4 [024] <- 00000286

# h3 = ~h2 => ~h1 & 00738E6E
0208 006EB142 vPushEsp4 0018FE8C
0209 00573C6C vReadMemSs4 [0018FE8C] -> FFFFFFFF
0210 006CC28D vNand4 00000000 <- FFFFFFFF, FFFFFFFF
0211 005919C4 vPopReg4 [018] <- 00000246

0212 006A846B vPushImm4 A39EE577
0213 005A067A vPushImm4 004AB26A
0214 00612BD5 vReadMemSs4 [004AB26A] -> 5CD4A85E
0215 006A6ED1 vAdd4 00738DD5 <- 5CD4A85E, A39EE577
0216 00551056 vPopReg4 [01C] <- 00000213

# h4 = nand(h1, 00738DD5)
0217 005626A0 vPushReg4 [020] FFFFFFFF
0218 005EEFA2 vNand4 FF8C722A <- FFFFFFFF, 00738DD5
0219 006519B6 vPopReg4 [018] <- 00000282

# h5 = ~h4 => h1 & 00738DD5
0220 004AE312 vPushEsp4 0018FE88
0221 00580DA6 vReadMemSs4 [0018FE88] -> FF8C722A
0222 006D4743 vNand4 00738DD5 <- FF8C722A, FF8C722A
0223 00523E4C vPopReg4 [018] <- 00000202

# h6 = h5 + h3 
0224 0072EEBE vAdd4 00738DD5 <- 00738DD5, 00000000
0225 00688494 vPopReg4 [01C] <- 00000202

# h7 = vbase + h6
0226 005CC9A6 vPushReg4 [00C] 00000000
0227 005C6201 vAdd4 00738DD5 <- 00000000, 00738DD5

以上代码过多,请按需要决定阅读,阅读的时候,请参照汇编代码。以下做分析说明

for 循环中的 i<4; 对应 jnl/jge 跳转指令,指令测试条件为 SF==OF,在循环中如果测试条件成立则跳出循环。在虚拟机中执行逻辑过程:

  1. cmp 指令进行减法操作,随后收集减法操作的eflags
    1. VMP中进行减法:a-b = ~(~a + b)
    2. eflags 收集:
      1. f1 = eflags of (~a + b)
      2. f2 = eflags of ~(~a + b)
      3. eflags = (f1 & 0x815) + (f2 & ~0x815)
  2. 测试 SF==OF 条件,对eflags分别测试SF位与OF位并分别记录
    1. VMP3中使用同或计算,也就是SF与OF同时为0或者同时为1则条件成立
  3. 转换条件测试结果为0或1
    1. 对SF位和OF位测试结果进行同或运算,运算结果只有0或1
    2. 测试同或运算产生的eflags中ZF位,同或结果为真则ZF置1
  4. 依据条件测试结果选择地址
    1. 把同或运算eflags & ZF 减1,则只有0或-1(FFFFFFFF),即互斥掩码对
    2. 真假条件目标地址与互斥掩码分别与运算然后相加(要么取真地址要么取假地址)
  5. 计算真实地址并跳转
    1. 对选择后的相对虚地址与虚基地址相加。此处的“虚”指的是vmp的v
    2. 把vmcontext 压入虚栈,然后调用vJmp指令,再出栈vmcontext。此时进入了新的条件地址执行

通过以上执行逻辑,我们可以找到一些可以应用:

  • 用于比较的常数如0x815、SF/ZF/OF等可以被修改进而影响执行跳转逻辑。但这些常数被加密写死在vm bytecode中
  • eflags 是同态计算的,可以被相对容易地修改而改变执行跳转逻辑
  • 可以修改4.1中的减数1,也较为容易地进行跳转逻辑修改
  • 等等
  • 但是,vmp3中严密的内存校验保护,让这些修改都有一定难度。而进入逻辑或者算术运算中修改真实eflags寄存器上的数值则可以更容易一些。
  • 等等。总之,本文志在说明vmp3中新的jcc技巧,也许与其他前辈所发布的相对旧版本vmp中分析出来的有所不同。

另:最近在逆向mt4的通讯协议进行学习金融交易系统,新版mt4采用新版vmp进行订制性保护。工作量非常巨大,所以开发了几个工具。而在开发工具的过程中,得到了一些关于vmp方面的思路。其中一个想法是:把vmp中的虚拟指令转编为其他语言表示,如汇编或C/CPP。但由于当前手上工作量庞大,想招募一两个擅长或特别有兴趣于vmp的伙伴组个队完成这个小工具。由汇编到虚拟指令的工具已经完成。

[公告][征集寄语] 看雪20周年年会 | 感恩有你,一路同行

最后于 6小时前 被yiivon编辑 ,原因:


文章来源: https://bbs.pediy.com/thread-255389.htm
如有侵权请联系:admin#unsafe.sh