## 前言 以该分支为例,做分析学习记录 ## 样本伪代码 ``` switch ( vmcode >> 26 ) // opcode { case 1u: case 6u: v49 = *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2); v50 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v51 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *(_WORD *)((char *)Reg_Context + v50 + v51) = v49; goto LABEL_103; case 4u: v43 = *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2); v44 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v45 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *(_DWORD *)((char *)Reg_Context + v44 + v45) = v43; goto LABEL_103; case 5u: v37 = Reg_Context + 1; v2 = (vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1)); v3 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v4 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *((_DWORD *)v37 + v2) = *(_DWORD *)((char *)Reg_Context + v3 + v4); goto LABEL_103; case 7u: v6 = *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2); v7 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v8 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *((_BYTE *)Reg_Context + v7 + v8) = v6; goto LABEL_103; case 8u: if ( *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) != *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) ) goto LABEL_103; goto LABEL_70; case 9u: v20 = Reg_Context + 1; v21 = HIWORD(vmcode) & 0x1F; v22 = *((_DWORD *)Reg_Context + ((vmcode >> 21) & 0x1F) + 2) + (__int16)vmcode; goto LABEL_2; case 10u: v18 = Reg_Context + 1; v28 = (vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1)); v29 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v30 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *((_DWORD *)v18 + v28) = *(unsigned __int16 *)((char *)Reg_Context + v29 + v30); goto LABEL_103; case 11u: case 14u: v5 = Reg_Context + 1; v31 = (vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1)); v32 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v33 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *((_DWORD *)v5 + v31) = *((unsigned __int8 *)Reg_Context + v32 + v33); goto LABEL_103; case 12u: v23 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v24 = *((_WORD *)Reg_Context + 2 * ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 5); v25 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *(_WORD *)((char *)Reg_Context + v23 + v25 - 1) = v24; goto LABEL_103; case 13u: v53 = Reg_Context + 1; v54 = 4LL * ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))); *(_DWORD *)((char *)v53 + v54) = *(unsigned __int16 *)((char *)Reg_Context + v54 + 8); v38 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v39 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *(_DWORD *)((char *)v53 + v54) |= *(unsigned __int16 *)((char *)Reg_Context + v38 + v39 - 1) << 16; goto LABEL_103; case 15u: v17 = HIWORD(vmcode) & 0x1F; v19 = vmcode << 16; goto LABEL_58; case 28u: if ( (vmcode & 0x7FF) == 2 ) *((_DWORD *)Reg_Context + ((unsigned __int16)vmcode >> 11) + 2) = *((_DWORD *)Reg_Context + ((vmcode >> 21) & 0x1F) + 2) * *((_DWORD *)Reg_Context + (HIWORD(vmcode) & 0x1F) + 2); goto LABEL_103; case 32u: *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) = *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) ^ ((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0xFFFF07FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); goto LABEL_103; case 34u: *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) = (vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0xFFFF07FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11) | *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); goto LABEL_103; case 35u: *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) = *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) & ((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0xFFFF07FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); goto LABEL_103; case 36u: *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) = *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) < (unsigned int)(__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); goto LABEL_103; case 37u: *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) = *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) < (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); goto LABEL_103; case 38u: *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) = *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) + (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); goto LABEL_103; case 40u: if ( *((int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) < 1 ) goto LABEL_103; goto LABEL_70; case 41u: if ( *((int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) > 0 ) goto LABEL_103; goto LABEL_70; case 42u: if ( *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) == *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) ) goto LABEL_103; goto LABEL_70; case 43u: v46 = Reg_Context + 1; v47 = 4LL * ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))); *(_DWORD *)((char *)v46 + v47) = *(_DWORD *)((_BYTE *)Reg_Context + v47 + 8) & 0xFFFF0000; v26 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v27 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *(_DWORD *)((char *)v46 + v47) |= *(unsigned __int16 *)((char *)Reg_Context + v26 + v27); goto LABEL_103; case 46u: if ( (*((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) & 0x80000000) == 0 ) goto LABEL_103;LABEL_70: v40 = Reg_Context[18]; v52 = (int)(((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0xFFFF07FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)) << 16) >> 14; Reg_Context = sub_1A7B40(Reg_Context, *(_DWORD *)(v40 + 4)); v56[18] = v40 + v52; goto LABEL_103; case 58u: v35 = Reg_Context[18]; v36 = (int)(vmcode << 6) >> 4; *(_DWORD *)Reg_Context[36] = v35 + 8; Reg_Context = sub_1A7B40(Reg_Context, *(_DWORD *)(v35 + 4)); v42 = v35 + 4 + v36; goto LABEL_43; ``` ## vmcode结构分析 首先将vmcode右移26位,获取高位6比特作为opcode进入switch,从右到左进行索引,记录vmcode结构: instruction_fields = [ {"name": "OPCODE", "bits": 6, "position": 26, "is_opcode": True}, ]  case1和case6会进入同一个分支,单独做代码分析: ``` v49 = *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2); v50 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v51 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *(_WORD *)((char *)Reg_Context + v50 + v51) = v49; ``` 逐行分析,v49由三部分组成,(_DWORD *)Reg_Context,((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))),+2 ``` v49 = *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2); ``` 可以理解成从Reg_Context越过两个字段后,取索引((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1)))位置的寄存器的值,这里我们把它标记为Rn。 Rn由vmcode上三部分操作码组成,记录一下怎么取的,首先是(vmcode >> 19) & 0xC: ¥¥¥¥ ¥¥¥¥ ¥AA¥ ¥¥¥¥ ¥¥¥¥ ¥¥¥¥ ¥¥¥¥ ¥¥¥¥ 然后是 (vmcode >> 9) & 3 ¥¥¥¥ ¥¥¥¥ ¥AA¥ ¥¥¥¥ ¥¥¥¥ ¥BB¥ ¥¥¥¥ ¥¥¥¥ 然后是 (vmcode >> 2) & 1 ¥¥¥¥ ¥¥¥¥ ¥AA¥ ¥¥¥¥ ¥¥¥¥ ¥BB¥ ¥¥¥¥ ¥C¥¥ 然后分析v50,同样从Reg_Context取某个寄存器的值,标记为Rm。 ``` v50 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); ``` 同样记录下怎么取,首先是(vmcode >> 14) & 0xC: ¥¥¥¥ ¥¥¥¥ ¥AA¥ ¥¥DD ¥¥¥¥ ¥BB¥ ¥¥¥¥ ¥C¥¥ 然后是 vmcode & 3 ¥¥¥¥ ¥¥¥¥ ¥AA¥ ¥¥DD ¥¥¥¥ ¥BB¥ ¥¥¥¥ ¥CEE 最后是 (vmcode >> 4) & 0x10 ¥¥¥¥ ¥¥¥¥ ¥AA¥ ¥¥DD ¥¥¥¥ ¥BBF ¥¥¥¥ ¥CEE 最后看v51 ``` v51 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); ``` v51不是一个从context中取寄存器的操作了,是直接取了值。我们设置为imme,立即数。也是分为几个部分,逐个来看: (vmcode >> 18) & 0xE0 ¥¥¥¥ ¥¥GG GAA¥ ¥¥DD ¥¥¥¥ ¥BBF ¥¥¥¥ ¥CEE ((unsigned __int16)vmcode >> 11) & 0x7FF ,这里对vmcode强转int16,也就是舍掉高位16比特,然后再右移11位,取最低5位 ¥¥¥¥ ¥¥GG GAA¥ ¥¥DD HHHH HBBF ¥¥¥¥ ¥CEE (vmcode >> 10) & 0x700 ¥¥¥¥ ¥¥GG GAAJ JJDD HHHH HBBF ¥¥¥¥ ¥CEE (unsigned __int8)vmcode >> 3 << 11) 一样是获取最低8位然后右移,取值为: ¥¥¥¥ ¥¥GG GAAJ JJDD HHHH HBBF KKKK KCEE 我们发现vmcode取完了,前六位是opcode。 abc ->Rn def ->Rm ghjk->imme 写一下字段分布 instruction_fields = [ {"name": "Rm1", "bits": 2, "position": 0, "is_opcode": False}, {"name": "Rn1", "bits": 1, "position": 2, "is_opcode": False}, {"name": "imme1", "bits": 5, "position": 3, "is_opcode": False}, {"name": "Rm2", "bits": 1, "position": 8, "is_opcode": False}, {"name": "Rn2", "bits": 2, "position": 9, "is_opcode": False}, {"name": "imme2", "bits": 5, "position": 11, "is_opcode": False}, {"name": "Rm3", "bits": 2, "position": 16, "is_opcode": False}, {"name": "imme3", "bits": 3, "position": 18, "is_opcode": False}, {"name": "Rn3", "bits": 2, "position": 21, "is_opcode": False}, {"name": "imme4", "bits": 3, "position": 23, "is_opcode": False}, {"name": "OPCODE", "bits": 6, "position": 26, "is_opcode": True}, ] 由此可生成vmcode的结构图,如下(忽略命名不一致,自行对照映射):  ## 逻辑分析 ### case1、6 回到case1、6的分支代码,取完Rn Rm后,做了如下操作: Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); 将Reg_Context值转为一个64位的Quad WORD(四字),通常用于表示64位的整数,然后进入函数做了: *a1 & 0xFFFFFFFF00000000LL; 最终Reg_Context的值就是0。然后做了 *(_WORD *)((char *)Reg_Context + v50 + v51) = v49; v49是Rn,v50是Rm,v51是imme,效果等同于 STR Rn,[Rm,#imme],查看汇编  所以case1、6等价于 STRH Value [Base, #offset] ### case4 查看case4  查看汇编  所以case4等价于 STRW Value [Base, #offset] ### case5 查看case5  首先给Reg_context加了8字节,等价于之前的+2。 此时做的操作*((_DWORD *)v37 + v2) = *(_DWORD *)((char *)Reg_Context + v3 + v4);,等价于 LDR Value [Base, #offset] 查看汇编,注意v2等价之前的索引值。  所以case5等价于 LDRW Value [Base, #offset] ### case7 同理 等价于 STRB Value [Base, #offset] ### case8  将Rn与Rm进行比较 等价于CMP ### case9 这里就比较特殊了,首先从vmcode.0x10位置取了宽度为5个位,然后取五位。 也就是Rd ¥¥¥¥ ¥¥¥¥ ¥¥¥A AAAA ¥¥¥¥ ¥¥¥¥ ¥¥¥¥ ¥¥¥¥ v22 = *((_DWORD *)Reg_Context + ((vmcode >> 21) & 0x1F) + 2) + (__int16)vmcode 这行代码也是拿到一个寄存器的值Rn,然后加上一个立即数imme。 ¥¥¥¥ ¥¥¥¥ ¥¥¥A AAAA BBBB BBBB BBBB BBBB ¥¥¥¥ ¥¥CC CCCA AAAA BBBB BBBB BBBB BBBB instruction_fields = [ {"name": "imme", "bits": 16, "position": 0, "is_opcode": False}, {"name": "Rd", "bits": 5, "position": 16, "is_opcode": False}, {"name": "Rn", "bits": 5, "position": 21, "is_opcode": False}, {"name": "OPCODE", "bits": 6, "position": 26, "is_opcode": True}, ]
## 前言 以该分支为例,做分析学习记录 ## 样本伪代码 ``` switch ( vmcode >> 26 ) // opcode { case 1u: case 6u: v49 = *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2); v50 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v51 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *(_WORD *)((char *)Reg_Context + v50 + v51) = v49; goto LABEL_103; case 4u: v43 = *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2); v44 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v45 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *(_DWORD *)((char *)Reg_Context + v44 + v45) = v43; goto LABEL_103; case 5u: v37 = Reg_Context + 1; v2 = (vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1)); v3 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v4 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *((_DWORD *)v37 + v2) = *(_DWORD *)((char *)Reg_Context + v3 + v4); goto LABEL_103; case 7u: v6 = *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2); v7 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v8 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *((_BYTE *)Reg_Context + v7 + v8) = v6; goto LABEL_103; case 8u: if ( *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) != *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) ) goto LABEL_103; goto LABEL_70; case 9u: v20 = Reg_Context + 1; v21 = HIWORD(vmcode) & 0x1F; v22 = *((_DWORD *)Reg_Context + ((vmcode >> 21) & 0x1F) + 2) + (__int16)vmcode; goto LABEL_2; case 10u: v18 = Reg_Context + 1; v28 = (vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1)); v29 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v30 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *((_DWORD *)v18 + v28) = *(unsigned __int16 *)((char *)Reg_Context + v29 + v30); goto LABEL_103; case 11u: case 14u: v5 = Reg_Context + 1; v31 = (vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1)); v32 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v33 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *((_DWORD *)v5 + v31) = *((unsigned __int8 *)Reg_Context + v32 + v33); goto LABEL_103; case 12u: v23 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v24 = *((_WORD *)Reg_Context + 2 * ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 5); v25 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *(_WORD *)((char *)Reg_Context + v23 + v25 - 1) = v24; goto LABEL_103; case 13u: v53 = Reg_Context + 1; v54 = 4LL * ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))); *(_DWORD *)((char *)v53 + v54) = *(unsigned __int16 *)((char *)Reg_Context + v54 + 8); v38 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v39 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *(_DWORD *)((char *)v53 + v54) |= *(unsigned __int16 *)((char *)Reg_Context + v38 + v39 - 1) << 16; goto LABEL_103; case 15u: v17 = HIWORD(vmcode) & 0x1F; v19 = vmcode << 16; goto LABEL_58; case 28u: if ( (vmcode & 0x7FF) == 2 ) *((_DWORD *)Reg_Context + ((unsigned __int16)vmcode >> 11) + 2) = *((_DWORD *)Reg_Context + ((vmcode >> 21) & 0x1F) + 2) * *((_DWORD *)Reg_Context + (HIWORD(vmcode) & 0x1F) + 2); goto LABEL_103; case 32u: *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) = *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) ^ ((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0xFFFF07FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); goto LABEL_103; case 34u: *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) = (vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0xFFFF07FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11) | *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); goto LABEL_103; case 35u: *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) = *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) & ((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0xFFFF07FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); goto LABEL_103; case 36u: *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) = *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) < (unsigned int)(__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); goto LABEL_103; case 37u: *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) = *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) < (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); goto LABEL_103; case 38u: *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) = *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) + (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); goto LABEL_103; case 40u: if ( *((int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) < 1 ) goto LABEL_103; goto LABEL_70; case 41u: if ( *((int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) > 0 ) goto LABEL_103; goto LABEL_70; case 42u: if ( *((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) == *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2) ) goto LABEL_103; goto LABEL_70; case 43u: v46 = Reg_Context + 1; v47 = 4LL * ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))); *(_DWORD *)((char *)v46 + v47) = *(_DWORD *)((_BYTE *)Reg_Context + v47 + 8) & 0xFFFF0000; v26 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v27 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *(_DWORD *)((char *)v46 + v47) |= *(unsigned __int16 *)((char *)Reg_Context + v26 + v27); goto LABEL_103; case 46u: if ( (*((_DWORD *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2) & 0x80000000) == 0 ) goto LABEL_103;LABEL_70: v40 = Reg_Context[18]; v52 = (int)(((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0xFFFF07FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)) << 16) >> 14; Reg_Context = sub_1A7B40(Reg_Context, *(_DWORD *)(v40 + 4)); v56[18] = v40 + v52; goto LABEL_103; case 58u: v35 = Reg_Context[18]; v36 = (int)(vmcode << 6) >> 4; *(_DWORD *)Reg_Context[36] = v35 + 8; Reg_Context = sub_1A7B40(Reg_Context, *(_DWORD *)(v35 + 4)); v42 = v35 + 4 + v36; goto LABEL_43; ``` ## vmcode结构分析 首先将vmcode右移26位,获取高位6比特作为opcode进入switch,从右到左进行索引,记录vmcode结构: instruction_fields = [ {"name": "OPCODE", "bits": 6, "position": 26, "is_opcode": True}, ]  case1和case6会进入同一个分支,单独做代码分析: ``` v49 = *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2); v50 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); v51 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); *(_WORD *)((char *)Reg_Context + v50 + v51) = v49; ``` 逐行分析,v49由三部分组成,(_DWORD *)Reg_Context,((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))),+2 ``` v49 = *((_DWORD *)Reg_Context + ((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1))) + 2); ``` 可以理解成从Reg_Context越过两个字段后,取索引((vmcode >> 19) & 0xC | (vmcode >> 9) & 3 | (16 * ((vmcode >> 2) & 1)))位置的寄存器的值,这里我们把它标记为Rn。 Rn由vmcode上三部分操作码组成,记录一下怎么取的,首先是(vmcode >> 19) & 0xC: ¥¥¥¥ ¥¥¥¥ ¥AA¥ ¥¥¥¥ ¥¥¥¥ ¥¥¥¥ ¥¥¥¥ ¥¥¥¥ 然后是 (vmcode >> 9) & 3 ¥¥¥¥ ¥¥¥¥ ¥AA¥ ¥¥¥¥ ¥¥¥¥ ¥BB¥ ¥¥¥¥ ¥¥¥¥ 然后是 (vmcode >> 2) & 1 ¥¥¥¥ ¥¥¥¥ ¥AA¥ ¥¥¥¥ ¥¥¥¥ ¥BB¥ ¥¥¥¥ ¥C¥¥ 然后分析v50,同样从Reg_Context取某个寄存器的值,标记为Rm。 ``` v50 = *((unsigned int *)Reg_Context + ((vmcode >> 14) & 0xC | vmcode & 3 | (vmcode >> 4) & 0x10) + 2); ``` 同样记录下怎么取,首先是(vmcode >> 14) & 0xC: ¥¥¥¥ ¥¥¥¥ ¥AA¥ ¥¥DD ¥¥¥¥ ¥BB¥ ¥¥¥¥ ¥C¥¥ 然后是 vmcode & 3 ¥¥¥¥ ¥¥¥¥ ¥AA¥ ¥¥DD ¥¥¥¥ ¥BB¥ ¥¥¥¥ ¥CEE 最后是 (vmcode >> 4) & 0x10 ¥¥¥¥ ¥¥¥¥ ¥AA¥ ¥¥DD ¥¥¥¥ ¥BBF ¥¥¥¥ ¥CEE 最后看v51 ``` v51 = (__int16)((vmcode >> 18) & 0xE0 | ((unsigned __int16)vmcode >> 11) & 0x7FF | (vmcode >> 10) & 0x700 | ((unsigned __int8)vmcode >> 3 << 11)); ``` v51不是一个从context中取寄存器的操作了,是直接取了值。我们设置为imme,立即数。也是分为几个部分,逐个来看: (vmcode >> 18) & 0xE0 ¥¥¥¥ ¥¥GG GAA¥ ¥¥DD ¥¥¥¥ ¥BBF ¥¥¥¥ ¥CEE ((unsigned __int16)vmcode >> 11) & 0x7FF ,这里对vmcode强转int16,也就是舍掉高位16比特,然后再右移11位,取最低5位 ¥¥¥¥ ¥¥GG GAA¥ ¥¥DD HHHH HBBF ¥¥¥¥ ¥CEE (vmcode >> 10) & 0x700 ¥¥¥¥ ¥¥GG GAAJ JJDD HHHH HBBF ¥¥¥¥ ¥CEE (unsigned __int8)vmcode >> 3 << 11) 一样是获取最低8位然后右移,取值为: ¥¥¥¥ ¥¥GG GAAJ JJDD HHHH HBBF KKKK KCEE 我们发现vmcode取完了,前六位是opcode。 abc ->Rn def ->Rm ghjk->imme 写一下字段分布 instruction_fields = [ {"name": "Rm1", "bits": 2, "position": 0, "is_opcode": False}, {"name": "Rn1", "bits": 1, "position": 2, "is_opcode": False}, {"name": "imme1", "bits": 5, "position": 3, "is_opcode": False}, {"name": "Rm2", "bits": 1, "position": 8, "is_opcode": False}, {"name": "Rn2", "bits": 2, "position": 9, "is_opcode": False}, {"name": "imme2", "bits": 5, "position": 11, "is_opcode": False}, {"name": "Rm3", "bits": 2, "position": 16, "is_opcode": False}, {"name": "imme3", "bits": 3, "position": 18, "is_opcode": False}, {"name": "Rn3", "bits": 2, "position": 21, "is_opcode": False}, {"name": "imme4", "bits": 3, "position": 23, "is_opcode": False}, {"name": "OPCODE", "bits": 6, "position": 26, "is_opcode": True}, ] 由此可生成vmcode的结构图,如下(忽略命名不一致,自行对照映射):  ## 逻辑分析 ### case1、6 回到case1、6的分支代码,取完Rn Rm后,做了如下操作: Reg_Context = (_QWORD *)sub_1A7708((_QWORD *)*Reg_Context); 将Reg_Context值转为一个64位的Quad WORD(四字),通常用于表示64位的整数,然后进入函数做了: *a1 & 0xFFFFFFFF00000000LL; 最终Reg_Context的值就是0。然后做了 *(_WORD *)((char *)Reg_Context + v50 + v51) = v49; v49是Rn,v50是Rm,v51是imme,效果等同于 STR Rn,[Rm,#imme],查看汇编  所以case1、6等价于 STRH Value [Base, #offset] ### case4 查看case4  查看汇编  所以case4等价于 STRW Value [Base, #offset] ### case5 查看case5  首先给Reg_context加了8字节,等价于之前的+2。 此时做的操作*((_DWORD *)v37 + v2) = *(_DWORD *)((char *)Reg_Context + v3 + v4);,等价于 LDR Value [Base, #offset] 查看汇编,注意v2等价之前的索引值。  所以case5等价于 LDRW Value [Base, #offset] ### case7 同理 等价于 STRB Value [Base, #offset] ### case8  将Rn与Rm进行比较 等价于CMP ### case9 这里就比较特殊了,首先从vmcode.0x10位置取了宽度为5个位,然后取五位。 也就是Rd的索引 ¥¥¥¥ ¥¥¥¥ ¥¥¥A AAAA ¥¥¥¥ ¥¥¥¥ ¥¥¥¥ ¥¥¥¥ v22 = *((_DWORD *)Reg_Context + ((vmcode >> 21) & 0x1F) + 2) + (__int16)vmcode 这行代码也是拿到一个寄存器的值Rn,然后加上一个立即数imme。 ¥¥¥¥ ¥¥¥¥ ¥¥¥A AAAA BBBB BBBB BBBB BBBB ¥¥¥¥ ¥¥CC CCCA AAAA BBBB BBBB BBBB BBBB instruction_fields = [ {"name": "imme", "bits": 16, "position": 0, "is_opcode": False}, {"name": "Rd", "bits": 5, "position": 16, "is_opcode": False}, {"name": "Rn", "bits": 5, "position": 21, "is_opcode": False}, {"name": "OPCODE", "bits": 6, "position": 26, "is_opcode": True}, ] 之后跳转到LABEL_2: ``` LABEL_2: *((_DWORD *)v20 + v21) = v22; goto LABEL_103; } ``` 最后取到Rd寄存器,将Rm+imme的值赋给Rd,所以这是一条add指令  看汇编 是一个addw指令
Difference
Hamlet: Do you see yonder cloud that's almost in shape of a camel?
Polonius: By the mass, and 'tis like a camel, indeed.
Hamlet: Methinks it is like a weasel. Polonius: It is backed like a weasel. Hamlet: Or like a whale? Polonius: Very like a whale. -- Shakespeare
Hamlet: Do you see the cloud over there that's almost the shape of a camel?
Polonius: By golly, it is like a camel, indeed.
Hamlet: I think it looks like a weasel.
Polonius: It is shaped like a weasel.
Hamlet: Or like a whale? Polonius: It's totally like a whale. -- Shakespeare