├── PyFlags.py ├── bb.py ├── clean_handlers ├── 000.txt ├── 001.txt ├── 002.txt ├── 003.txt ├── 004.txt ├── 006.txt ├── 007.txt ├── 009.txt ├── 00a.txt ├── 00b.txt ├── 00c.txt ├── 00e.txt ├── 00f.txt ├── 011.txt ├── 012.txt ├── 013.txt ├── 015.txt ├── 016.txt ├── 017.txt ├── 018.txt ├── 019.txt ├── 01a.txt ├── 01b.txt ├── 01c.txt ├── 01e.txt ├── 01f.txt ├── 020.txt ├── 022.txt ├── 023.txt ├── 024.txt ├── 026.txt ├── 027.txt ├── 028.txt ├── 029.txt ├── 02c.txt ├── 02d.txt ├── 02f.txt ├── 030.txt ├── 031.txt ├── 033.txt ├── 034.txt ├── 035.txt ├── 037.txt ├── 038.txt ├── 039.txt ├── 03b.txt ├── 03c.txt ├── 03d.txt ├── 03f.txt ├── 040.txt ├── 041.txt ├── 043.txt ├── 044.txt ├── 045.txt ├── 048.txt ├── 049.txt ├── 04d.txt ├── 053.txt ├── 054.txt ├── 055.txt ├── 057.txt ├── 058.txt ├── 059.txt ├── 05b.txt ├── 05c.txt ├── 05d.txt ├── 05f.txt ├── 060.txt ├── 061.txt ├── 063.txt ├── 064.txt ├── 065.txt ├── 067.txt ├── 068.txt ├── 069.txt ├── 06b.txt ├── 06c.txt ├── 06d.txt ├── 06f.txt ├── 070.txt ├── 071.txt ├── 073.txt ├── 074.txt ├── 075.txt ├── 077.txt ├── 078.txt ├── 079.txt ├── 07b.txt ├── 080.txt ├── 081.txt ├── 085.txt ├── 087.txt ├── 08b.txt ├── 08f.txt ├── 093.txt ├── 097.txt ├── 09b.txt ├── 09f.txt ├── 0a3.txt ├── 0a8.txt ├── 0a9.txt ├── 0ab.txt ├── 0ac.txt ├── 0af.txt ├── 0b0.txt ├── 0b3.txt ├── 0b4.txt ├── 0b7.txt ├── 0b8.txt ├── 0b9.txt ├── 0bb.txt ├── 0bc.txt ├── 0bd.txt ├── 0bf.txt ├── 0c0.txt ├── 0c1.txt ├── 0c3.txt ├── 0c4.txt ├── 0c5.txt ├── 0c7.txt ├── 0c8.txt ├── 0c9.txt ├── 0cd.txt ├── 0cf.txt ├── 0d0.txt ├── 0d1.txt ├── 0d3.txt ├── 0d4.txt ├── 0d5.txt ├── 14a.txt ├── 14b.txt ├── 14c.txt ├── 14d.txt ├── 14e.txt ├── 14f.txt ├── 150.txt ├── 151.txt ├── 152.txt ├── 153.txt ├── 154.txt ├── 155.txt ├── 156.txt ├── 157.txt ├── 158.txt ├── 15a.txt ├── 15d.txt ├── 15e.txt ├── 15f.txt ├── 160.txt ├── 161.txt ├── 200.txt ├── 201.txt ├── 202.txt ├── 203.txt ├── 204.txt ├── 205.txt ├── 206.txt ├── 207.txt ├── 208.txt ├── 209.txt ├── 20a.txt ├── 20b.txt ├── 20c.txt ├── 20d.txt ├── 20e.txt ├── 20f.txt ├── 210.txt ├── 211.txt ├── 212.txt ├── 213.txt └── 214.txt ├── common.py ├── config.py ├── decompiler.py ├── decv.py ├── dump_clean.py ├── emu.py ├── example_recover.txt ├── gen_vmi.py ├── matcher.py ├── op.py ├── op_classes.py ├── opt.py ├── pickler.py ├── readme.txt ├── recover_x86.py ├── vm_classes.py ├── vm_instructions.py ├── vmi_auto_gen.py ├── vmi_top_common.py └── vmis.txt /PyFlags.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ######################################################################## 4 | # 5 | # PyEmu: scriptable x86 emulator 6 | # 7 | # Cody Pierce - cpierce@tippingpoint.com - 2007 8 | # 9 | # License: None 10 | # 11 | ######################################################################## 12 | 13 | ''' 14 | This is a new class for setting flags. It is used by PyCPU to set 15 | flags per instruction. This was shamelessly ripped from Bochs 16 | 17 | http://bochs.sourceforge.net/ 18 | ''' 19 | 20 | class PyFlags: 21 | parity_lookup_table = [1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 22 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 23 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 24 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 25 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 26 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 27 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 28 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 29 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 30 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 31 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 32 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 33 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 34 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 35 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 36 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1] 37 | 38 | def __init__(self, mnemonic, op1, op2, result, size): 39 | assert isinstance(mnemonic, str) 40 | assert isinstance(op1, long) or isinstance(op1, int) 41 | assert isinstance(op2, long) or isinstance(op2, int) 42 | assert isinstance(result, long) or isinstance(result, int) 43 | assert isinstance(size, long) or isinstance(size, int) 44 | 45 | self.mnemonic = mnemonic 46 | self.op1 = op1 47 | self.op2 = op2 48 | self.result = result 49 | self.size = size 50 | self.bit_count = self.size * 8 51 | self.mask = (2 ** (self.bit_count) - 1) 52 | self.sign_mask = (self.mask + 1) / 2 53 | 54 | def get_CF(self): 55 | if self.mnemonic == "ADD": 56 | cf = int(self.result < self.op1) 57 | elif self.mnemonic == "ADC": 58 | # used only if CF = 1 59 | cf = int(self.result <= self.op1) 60 | elif self.mnemonic in ["SUB", "CMP"]: 61 | cf = int(self.op1 < self.op2) 62 | elif self.mnemonic == "SBB": 63 | # used only if CF = 1 64 | cf = int((self.op1 < self.result) or (self.op2 == self.mask)) 65 | elif self.mnemonic == "NEG": 66 | cf = int(self.result != 0) 67 | elif self.mnemonic == "LOGIC": 68 | cf = 0 69 | elif self.mnemonic == "SAR": 70 | if self.op2 < self.bit_count: 71 | cf = int((self.op1 >> (self.op2 - 1)) & 0x01) 72 | else: 73 | cf = int((self.op1 & self.sign_mask) > 0) 74 | elif self.mnemonic in ["SHR", "SHRD"]: 75 | cf = int((self.op1 >> (self.op2 - 1)) & 0x01) 76 | elif self.mnemonic in ["SHL", "SAL"]: 77 | if self.op2 <= self.bit_count: 78 | cf = int((self.op1 >> (self.bit_count - self.op2)) & 0x01) 79 | else: 80 | cf = 0 81 | elif self.mnemonic == "IMUL": 82 | cf = int(not ((self.op1 < self.sign_mask and self.op2 == 0) or ((self.op1 & self.sign_mask) and self.op2 == self.mask))) 83 | 84 | elif self.mnemonic == "MUL": 85 | cf = int(self.op2 != 0) 86 | else: 87 | cf = None 88 | 89 | return cf 90 | 91 | def get_AF(self): 92 | if self.mnemonic in ["ADD", "ADC", "SUB", "CMP", "SBB"]: 93 | af = int(((self.op1 ^ self.op2) ^ self.result) & 0x10) 94 | af = int(af != 0) 95 | elif self.mnemonic == "NEG": 96 | af = int((self.result & 0x0f) != 0) 97 | elif self.mnemonic == "INC": 98 | af = int((self.result & 0x0f) == 0) 99 | elif self.mnemonic == "DEC": 100 | af = int((self.result & 0x0f) == 0x0f) 101 | else: 102 | af = None 103 | 104 | return af 105 | 106 | def get_ZF(self): 107 | if self.mnemonic in ["LOGIC", "ADD", "ADC", "SUB", "CMP", "SBB", "NEG", "SAR", "SHR", "SHL", "SAR", "INC", "DEC"]: 108 | zf = int(self.result == 0) 109 | elif self.mnemonic in ["IMUL", "MUL"]: 110 | zf = int(self.op1 == 0) 111 | else: 112 | zf = None 113 | 114 | return zf 115 | 116 | def get_SF(self): 117 | if self.mnemonic in ["LOGIC", "ADD", "ADC", "SUB", "CMP", "SBB", "NEG", "SAR", "SHR", "SHL", "SAL", "INC", "DEC"]: 118 | sf = int(self.result >= self.sign_mask) 119 | elif self.mnemonic in ["IMUL", "MUL"]: 120 | sf = int(self.op1 >= self.sign_mask) 121 | else: 122 | sf = None 123 | 124 | return sf 125 | 126 | def get_OF_ADD(self): 127 | return int(((~((self.op1) ^ (self.op2)) & ((self.op2) ^ (self.result))) & (self.sign_mask)) != 0) 128 | 129 | def get_OF_SUB(self): 130 | return int(((((self.op1) ^ (self.op2)) & ((self.op1) ^ (self.result))) & (self.sign_mask)) != 0) 131 | 132 | def get_OF(self): 133 | if self.mnemonic in ["ADD", "ADC"]: 134 | of = self.get_OF_ADD() 135 | elif self.mnemonic in ["SUB", "CMP", "SBB"]: 136 | of = self.get_OF_SUB() 137 | elif self.mnemonic == "NEG": 138 | of = int(self.result == self.sign_mask) 139 | elif self.mnemonic in ["LOGIC", "SAR"]: 140 | of = 0 141 | elif self.mnemonic == "SHR": 142 | if self.op2 == 1: 143 | of = int(self.op1 >= self.sign_mask) 144 | else: 145 | of = 0 146 | elif self.mnemonic == "SHRD": 147 | of = int((((self.result << 1) ^ self.result) & self.sign_mask) > 0) 148 | elif self.mnemonic in ["SHL", "SAL"]: 149 | if self.op2 == 1: 150 | of = int(((self.op1 ^ self.result) & self.sign_mask) > 0) 151 | else: 152 | of = int((((self.op1 << (self.op2 - 1)) ^ self.result) & self.sign_mask) > 0) 153 | elif self.mnemonic == "IMUL": 154 | of = int(not ((self.op1 < self.sign_mask and self.op2 == 0) or ((self.op1 & self.sign_mask) and self.op2 == self.mask))) 155 | elif self.mnemonic == "MUL": 156 | of = int(self.op2 != 0) 157 | elif self.mnemonic == "INC": 158 | of = int(self.result == self.sign_mask) 159 | elif self.mnemonic == "DEC": 160 | of = int(self.result == self.sign_mask - 1) 161 | else: 162 | of = None 163 | 164 | return of 165 | 166 | def get_PF(self): 167 | if self.mnemonic in ["LOGIC", "ADD", "ADC", "SUB", "CMP", "SBB", "NEG", "SAR", "SHR", "SHL", "SAR", "INC", "DEC"]: 168 | pf = self.parity_lookup_table[self.result & 0xff] 169 | elif self.mnemonic in ["IMUL", "MUL"]: 170 | pf = self.parity_lookup_table[self.op1 & 0xff] 171 | else: 172 | pf = None 173 | 174 | return pf 175 | 176 | 177 | # End PyFlags 178 | -------------------------------------------------------------------------------- /bb.py: -------------------------------------------------------------------------------- 1 | import idc 2 | import idaapi 3 | import idautils 4 | from common import * 5 | 6 | class BB(BB_): 7 | def __init__(self): 8 | BB_.__init__(self) 9 | 10 | def verify(self): 11 | for i,n in enumerate(self.body[:-1]): 12 | if is_jxx(n) and not is_jmp(n): 13 | return False 14 | if is_jmp(n): 15 | nxt = self.body[i+1] 16 | if nxt != jxx_target(n): 17 | return False 18 | last = self.body[-1] 19 | 20 | if self.child1 == self.child2 and self.child1 == None: 21 | return True 22 | 23 | if is_jxx(last): 24 | if is_jmp(last): 25 | return self.child1.get_addr() == jxx_target(last) 26 | else: 27 | b1 = self.child1.get_addr() == next_head(last) 28 | b2 = self.child2.get_addr() == jxx_target(last) 29 | return b1 and b2 30 | 31 | else: 32 | return self.child1.get_addr() == next_head(last) 33 | 34 | return True 35 | 36 | def mnem_stats(self): 37 | stats = {} 38 | for n in self.body: 39 | mnem = idc.GetMnem(n) 40 | try: 41 | stats[mnem] += 1 42 | except: 43 | stats[mnem] = 1 44 | return stats 45 | 46 | 47 | def disasm(self): 48 | l = [] 49 | for n in self.body: 50 | di = "0x%08x %s %s %s"%(n, idc.GetMnem(n), idc.GetOpnd(n, 0), idc.GetOpnd(n, 1)) 51 | l.append(di) 52 | return "\n".join(l) 53 | 54 | def disasm(root): 55 | di = dfs(root, f_disasm) 56 | return di 57 | 58 | def f_disasm(acc, node, children): 59 | if acc == None: 60 | acc = "" 61 | acc += node.disasm() 62 | return acc 63 | 64 | def mnem_stats(root): 65 | stats = dfs(root, f_mnem_stats) 66 | return stats 67 | 68 | def f_mnem_stats(acc, node, children): 69 | if acc == None: 70 | acc = dict() 71 | 72 | stats = node.mnem_stats() 73 | for k,v in stats.iteritems(): 74 | try: 75 | acc[k] += v 76 | except: 77 | acc[k] = v 78 | return acc 79 | 80 | # heads - handler body 81 | # outputs a graph of basic blocks 82 | # no cleaning 83 | def consume_raw_code(heads, c_jmps, u_jmps): 84 | 85 | jmp_targets = set(c_jmps.values()).union(set(u_jmps.values())) 86 | ea_to_bb = dict() 87 | visited = set() 88 | heads_set = set(heads) 89 | assert(len(heads) == len(heads_set)) 90 | 91 | root = BB() 92 | root = make_bbs(heads[0], root, heads_set, jmp_targets, ea_to_bb, visited) 93 | 94 | return root 95 | 96 | 97 | def merge(cur_bb, new_bb): 98 | 99 | if cur_bb.empty(): 100 | return new_bb 101 | 102 | assert(cur_bb.child1 == None) 103 | cur_bb.child1 = new_bb 104 | return cur_bb 105 | 106 | def handle_jxx(head, make_bbs_fun): 107 | 108 | target = jxx_target(head) 109 | 110 | c1 = make_bbs_fun(target, BB()) 111 | c2 = None 112 | 113 | nxt = next_head(head) 114 | if not is_jmp(head): 115 | c2 = make_bbs_fun(nxt, BB()) 116 | 117 | # false path comes first 118 | c1, c2 = c2, c1 119 | 120 | return c1,c2 121 | 122 | def make_bbs(head, cur_bb, heads_set, jmp_targets, ea_to_bb, visited): 123 | 124 | make_bbs_fun = lambda h, cur: make_bbs(h, cur, heads_set, jmp_targets, ea_to_bb, visited) 125 | 126 | while True: 127 | if head not in heads_set: 128 | if cur_bb.empty(): 129 | #we went outside of handler? 130 | print "outside handler:", hex(head) 131 | assert(False) 132 | break 133 | 134 | if head in visited: 135 | bb = ea_to_bb[head] 136 | return merge(cur_bb, bb) 137 | 138 | if head in jmp_targets: 139 | 140 | new_bb = BB() 141 | new_bb.add(head) 142 | ea_to_bb[head] = new_bb 143 | visited.add(head) 144 | 145 | if is_jxx(head): 146 | c1, c2 = handle_jxx(head, make_bbs_fun) 147 | new_bb.child1 = c1 148 | new_bb.child2 = c2 149 | 150 | return merge(cur_bb, new_bb) 151 | 152 | nxt = next_head(head) 153 | new_bb = make_bbs_fun(nxt, new_bb) 154 | return merge(cur_bb, new_bb) 155 | 156 | cur_bb.add(head) 157 | ea_to_bb[head] = cur_bb 158 | visited.add(head) 159 | 160 | if is_jxx(head): 161 | c1, c2 = handle_jxx(head, make_bbs_fun) 162 | cur_bb.child1 = c1 163 | cur_bb.child2 = c2 164 | break 165 | 166 | head = next_head(head) 167 | 168 | cur_bb.verify() 169 | return cur_bb 170 | 171 | 172 | def hexx(n): 173 | return hex(n).replace("0x", "x") 174 | 175 | # export to dot (graphviz) format 176 | def export_graph(root, fn): 177 | 178 | visited = set() 179 | o = "digraph g {\n" 180 | Q = [root] 181 | edges = [] 182 | nodes = [] 183 | # dfs 184 | while Q: 185 | node = Q.pop(0) 186 | addr = node.get_addr() 187 | if addr in visited: 188 | continue 189 | visited.add(addr) 190 | nodes.append(hexx(addr)) 191 | c1, c2 = node.child1, node.child2 192 | 193 | for c in [c1,c2]: 194 | if c: 195 | c_addr = c.get_addr() 196 | Q.append(c) 197 | edges.append((hexx(addr), hexx(c_addr))) 198 | 199 | s = "\n".join(nodes) 200 | o += s 201 | o += "\n" 202 | 203 | for n1,n2 in edges: 204 | o += "%s -> %s\n"%(n1,n2) 205 | 206 | o += "}" 207 | 208 | f = open(fn, "w") 209 | f.write(o) 210 | f.close() 211 | 212 | -------------------------------------------------------------------------------- /clean_handlers/000.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | movzx eax, al 3 | lea eax, [edi+eax*4] 4 | push eax -------------------------------------------------------------------------------- /clean_handlers/001.txt: -------------------------------------------------------------------------------- 1 | pop edx -------------------------------------------------------------------------------- /clean_handlers/002.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | movzx eax, al 3 | push ax -------------------------------------------------------------------------------- /clean_handlers/003.txt: -------------------------------------------------------------------------------- 1 | lodsw 2 | movzx eax, ax 3 | push ax -------------------------------------------------------------------------------- /clean_handlers/004.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | push eax -------------------------------------------------------------------------------- /clean_handlers/006.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | add [esp], eax -------------------------------------------------------------------------------- /clean_handlers/007.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | movzx eax, al 3 | push dword ptr [edi+eax*4] -------------------------------------------------------------------------------- /clean_handlers/009.txt: -------------------------------------------------------------------------------- 1 | push edx -------------------------------------------------------------------------------- /clean_handlers/00a.txt: -------------------------------------------------------------------------------- 1 | movzx ax, byte ptr [edx] 2 | push ax -------------------------------------------------------------------------------- /clean_handlers/00b.txt: -------------------------------------------------------------------------------- 1 | push word ptr [edx] -------------------------------------------------------------------------------- /clean_handlers/00c.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edx] -------------------------------------------------------------------------------- /clean_handlers/00e.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | movzx eax, al 3 | mov eax, [edi+eax*4] 4 | movzx ax, byte ptr [eax] 5 | push ax -------------------------------------------------------------------------------- /clean_handlers/00f.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | movzx eax, al 3 | mov eax, [edi+eax*4] 4 | push word ptr [eax] -------------------------------------------------------------------------------- /clean_handlers/011.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | movzx ax, byte ptr [eax] 3 | push ax -------------------------------------------------------------------------------- /clean_handlers/012.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | push word ptr [eax] -------------------------------------------------------------------------------- /clean_handlers/013.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | push dword ptr [eax] -------------------------------------------------------------------------------- /clean_handlers/015.txt: -------------------------------------------------------------------------------- 1 | pop edx -------------------------------------------------------------------------------- /clean_handlers/016.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | mov [edx], al -------------------------------------------------------------------------------- /clean_handlers/017.txt: -------------------------------------------------------------------------------- 1 | pop word ptr [edx] -------------------------------------------------------------------------------- /clean_handlers/018.txt: -------------------------------------------------------------------------------- 1 | pop dword ptr [edx] -------------------------------------------------------------------------------- /clean_handlers/019.txt: -------------------------------------------------------------------------------- 1 | pop dword ptr [edx] -------------------------------------------------------------------------------- /clean_handlers/01a.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | movzx eax, al 3 | pop dx 4 | mov [edi+eax*4], dl -------------------------------------------------------------------------------- /clean_handlers/01b.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | movzx eax, al 3 | pop word ptr [edi+eax*4] -------------------------------------------------------------------------------- /clean_handlers/01c.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | movzx eax, al 3 | pop dword ptr [edi+eax*4] -------------------------------------------------------------------------------- /clean_handlers/01e.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | pop dx 3 | mov [eax], dl -------------------------------------------------------------------------------- /clean_handlers/01f.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | pop word ptr [eax] -------------------------------------------------------------------------------- /clean_handlers/020.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | pop dword ptr [eax] -------------------------------------------------------------------------------- /clean_handlers/022.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | add [esp], al 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/023.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | add [esp], ax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/024.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | add [esp], eax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/026.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | sub [esp], eax -------------------------------------------------------------------------------- /clean_handlers/027.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | sub [esp], al 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/028.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | sub [esp], ax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/029.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | sub [esp], eax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/02c.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | pop cx 3 | imul cx, ax 4 | push cx 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/02d.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | pop ecx 3 | imul ecx, eax 4 | push ecx 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/02f.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edi+1ch] 2 | popf 3 | pop ax 4 | adc [esp], al 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/030.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edi+1ch] 2 | popf 3 | pop ax 4 | adc [esp], ax 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/031.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edi+1ch] 2 | popf 3 | pop eax 4 | adc [esp], eax 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/033.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | and [esp], al 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/034.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | and [esp], ax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/035.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | and [esp], eax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/037.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | pop cx 3 | cmp cl, al 4 | pushf -------------------------------------------------------------------------------- /clean_handlers/038.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | pop cx 3 | cmp cx, ax 4 | pushf -------------------------------------------------------------------------------- /clean_handlers/039.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | pop ecx 3 | cmp ecx, eax 4 | pushf -------------------------------------------------------------------------------- /clean_handlers/03b.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | xor [esp], al 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/03c.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | xor [esp], ax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/03d.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | xor [esp], eax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/03f.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | or [esp], al 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/040.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | or [esp], ax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/041.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | or [esp], eax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/043.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | pop cx 3 | test al, cl 4 | pushf -------------------------------------------------------------------------------- /clean_handlers/044.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | pop cx 3 | test ax, cx 4 | pushf -------------------------------------------------------------------------------- /clean_handlers/045.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | pop ecx 3 | test eax, ecx 4 | pushf -------------------------------------------------------------------------------- /clean_handlers/048.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | pop ax 3 | movzx cx, al 4 | push cx -------------------------------------------------------------------------------- /clean_handlers/049.txt: -------------------------------------------------------------------------------- 1 | pop ecx 2 | pop eax 3 | movzx ecx, al 4 | push ecx -------------------------------------------------------------------------------- /clean_handlers/04d.txt: -------------------------------------------------------------------------------- 1 | pop ecx 2 | pop eax 3 | movzx ecx, ax 4 | push ecx -------------------------------------------------------------------------------- /clean_handlers/053.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | inc byte ptr [esp] 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/054.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | inc word ptr [esp] 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/055.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | inc dword ptr [esp] 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/057.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edi+1ch] 2 | popf 3 | pop cx 4 | rcl byte ptr [esp], cl 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/058.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edi+1ch] 2 | popf 3 | pop cx 4 | rcl word ptr [esp], cl 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/059.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edi+1ch] 2 | popf 3 | pop cx 4 | rcl dword ptr [esp], cl 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/05b.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edi+1Ch] 2 | popf 3 | pop cx 4 | rcr byte ptr [esp], cl 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/05c.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edi+1Ch] 2 | popf 3 | pop cx 4 | rcr word ptr [esp], cl 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/05d.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edi+1Ch] 2 | popf 3 | pop cx 4 | rcr dword ptr [esp], cl 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/05f.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | rol byte ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/060.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | rol word ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/061.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | rol dword ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/063.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | ror byte ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/064.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | ror word ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/065.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | ror dword ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/067.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | shl byte ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/068.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | shl word ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/069.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | shl dword ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/06b.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | sar byte ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/06c.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | sar word ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/06d.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | sar dword ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/06f.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | shl byte ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/070.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | shl dword ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/071.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | shl dword ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/073.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | shr byte ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/074.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | shr word ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/075.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | shr dword ptr [esp], cl 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/077.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | dec byte ptr [esp] 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/078.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | dec word ptr [esp] 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/079.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | dec dword ptr [esp] 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/07b.txt: -------------------------------------------------------------------------------- 1 | mov eax, eax -------------------------------------------------------------------------------- /clean_handlers/080.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | pop ax 3 | movsx cx, al 4 | push cx -------------------------------------------------------------------------------- /clean_handlers/081.txt: -------------------------------------------------------------------------------- 1 | pop ecx 2 | pop eax 3 | movsx ecx, al 4 | push ecx -------------------------------------------------------------------------------- /clean_handlers/085.txt: -------------------------------------------------------------------------------- 1 | pop ecx 2 | pop eax 3 | movsx ecx, ax 4 | push ecx -------------------------------------------------------------------------------- /clean_handlers/087.txt: -------------------------------------------------------------------------------- 1 | and dword ptr [edi+1Ch], 0FEh -------------------------------------------------------------------------------- /clean_handlers/08b.txt: -------------------------------------------------------------------------------- 1 | and dword ptr [edi+1Ch], 0FFFFFBFFh -------------------------------------------------------------------------------- /clean_handlers/08f.txt: -------------------------------------------------------------------------------- 1 | and dword ptr [edi+1Ch], 0FFFFFDFFh -------------------------------------------------------------------------------- /clean_handlers/093.txt: -------------------------------------------------------------------------------- 1 | mov eax, [edi+1Ch] 2 | and eax, 1 3 | or eax, eax 4 | jz short loc_603838 5 | and dword ptr [edi+1Ch], 0FFFFFFFEh 6 | jmp short loc_60383C 7 | or dword ptr [edi+1Ch], 1 8 | mov ebx, ebx -------------------------------------------------------------------------------- /clean_handlers/097.txt: -------------------------------------------------------------------------------- 1 | or dword ptr [edi+1Ch], 1 -------------------------------------------------------------------------------- /clean_handlers/09b.txt: -------------------------------------------------------------------------------- 1 | or dword ptr [edi+1Ch], 400h -------------------------------------------------------------------------------- /clean_handlers/09f.txt: -------------------------------------------------------------------------------- 1 | or dword ptr [edi+1Ch], 200h -------------------------------------------------------------------------------- /clean_handlers/0a3.txt: -------------------------------------------------------------------------------- 1 | mov eax, eax -------------------------------------------------------------------------------- /clean_handlers/0a8.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | bt [esp], ax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/0a9.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | bt [esp], eax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/0ab.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | btc [esp], ax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/0ac.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | btc [esp], ax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/0af.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | btr [esp], ax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/0b0.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | btr [esp], ax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/0b3.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | bts [esp], ax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/0b4.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | bts [esp], ax 3 | pushf -------------------------------------------------------------------------------- /clean_handlers/0b7.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edi+1Ch] 2 | popf 3 | pop ax 4 | sbb [esp], al 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/0b8.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edi+1ch] 2 | popf 3 | pop ax 4 | sbb [esp], ax 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/0b9.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edi+1ch] 2 | popf 3 | pop eax 4 | sbb [esp], eax 5 | pushf -------------------------------------------------------------------------------- /clean_handlers/0bb.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | pop ax 3 | mul cl 4 | movzx cx, ah 5 | push cx 6 | movzx cx, al 7 | push cx 8 | pushf -------------------------------------------------------------------------------- /clean_handlers/0bc.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | pop ax 3 | mul cx 4 | push dx 5 | push ax 6 | pushf -------------------------------------------------------------------------------- /clean_handlers/0bd.txt: -------------------------------------------------------------------------------- 1 | pop ecx 2 | pop eax 3 | mul ecx 4 | push edx 5 | push eax 6 | pushf -------------------------------------------------------------------------------- /clean_handlers/0bf.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | pop ax 3 | imul cl 4 | movzx cx, ah 5 | push cx 6 | movzx cx, al 7 | push cx 8 | pushf -------------------------------------------------------------------------------- /clean_handlers/0c0.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | pop ax 3 | imul cx 4 | push dx 5 | push ax 6 | pushf -------------------------------------------------------------------------------- /clean_handlers/0c1.txt: -------------------------------------------------------------------------------- 1 | pop ecx 2 | pop eax 3 | imul ecx 4 | push edx 5 | push eax 6 | pushf -------------------------------------------------------------------------------- /clean_handlers/0c3.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | pop ax 3 | div cl 4 | movzx cx, ah 5 | push cx 6 | movzx cx, al 7 | push cx 8 | pushf -------------------------------------------------------------------------------- /clean_handlers/0c4.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | pop ax 3 | pop ax 4 | div cx 5 | push dx 6 | push ax 7 | pushf -------------------------------------------------------------------------------- /clean_handlers/0c5.txt: -------------------------------------------------------------------------------- 1 | pop ecx 2 | pop eax 3 | pop edx 4 | div ecx 5 | push edx 6 | push eax 7 | pushf -------------------------------------------------------------------------------- /clean_handlers/0c7.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | pop ax 3 | idiv cl 4 | movzx cx, ah 5 | push cx 6 | movzx cx, al 7 | push cx 8 | pushf -------------------------------------------------------------------------------- /clean_handlers/0c8.txt: -------------------------------------------------------------------------------- 1 | pop cx 2 | pop ax 3 | pop dx 4 | idiv cx 5 | push dx 6 | push ax 7 | pushf -------------------------------------------------------------------------------- /clean_handlers/0c9.txt: -------------------------------------------------------------------------------- 1 | pop ecx 2 | pop eax 3 | pop edx 4 | idiv ecx 5 | push edx 6 | push eax 7 | pushf -------------------------------------------------------------------------------- /clean_handlers/0cd.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | bswap eax 3 | push eax -------------------------------------------------------------------------------- /clean_handlers/0cf.txt: -------------------------------------------------------------------------------- 1 | neg byte ptr [esp] 2 | pushf -------------------------------------------------------------------------------- /clean_handlers/0d0.txt: -------------------------------------------------------------------------------- 1 | neg word ptr [esp] 2 | pushf -------------------------------------------------------------------------------- /clean_handlers/0d1.txt: -------------------------------------------------------------------------------- 1 | neg dword ptr [esp] 2 | pushf -------------------------------------------------------------------------------- /clean_handlers/0d3.txt: -------------------------------------------------------------------------------- 1 | not byte ptr [esp] -------------------------------------------------------------------------------- /clean_handlers/0d4.txt: -------------------------------------------------------------------------------- 1 | not word ptr [esp] -------------------------------------------------------------------------------- /clean_handlers/0d5.txt: -------------------------------------------------------------------------------- 1 | not dword ptr [esp] -------------------------------------------------------------------------------- /clean_handlers/14a.txt: -------------------------------------------------------------------------------- 1 | mov dword ptr [edi+30h], 0 2 | popa 3 | popf 4 | retn -------------------------------------------------------------------------------- /clean_handlers/14b.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | add edi, 3FCh 3 | movzx eax, al 4 | push dword ptr [edi+eax*4] 5 | sub edi, 3FCh 6 | retn -------------------------------------------------------------------------------- /clean_handlers/14c.txt: -------------------------------------------------------------------------------- 1 | push esp -------------------------------------------------------------------------------- /clean_handlers/14d.txt: -------------------------------------------------------------------------------- 1 | pop esp -------------------------------------------------------------------------------- /clean_handlers/14e.txt: -------------------------------------------------------------------------------- 1 | mov edx, esp -------------------------------------------------------------------------------- /clean_handlers/14f.txt: -------------------------------------------------------------------------------- 1 | push sp 2 | add word [esp], 2 -------------------------------------------------------------------------------- /clean_handlers/150.txt: -------------------------------------------------------------------------------- 1 | push esp 2 | add dword ptr [esp], 4 -------------------------------------------------------------------------------- /clean_handlers/151.txt: -------------------------------------------------------------------------------- 1 | pop sp -------------------------------------------------------------------------------- /clean_handlers/152.txt: -------------------------------------------------------------------------------- 1 | pop esp -------------------------------------------------------------------------------- /clean_handlers/153.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | movzx eax, al 3 | mov eax, [edi+eax*4] 4 | add edx, eax -------------------------------------------------------------------------------- /clean_handlers/154.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | add esi, eax 3 | mov ebx, 0 -------------------------------------------------------------------------------- /clean_handlers/155.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | and al, 7Fh 3 | push ebx 4 | mov ebx, eax 5 | mov dword ptr [edi+20h], 1 6 | mov dword ptr [edi+24h], 0 7 | xor edx, edx 8 | and eax, 200h 9 | mov ecx, [edi+1Ch] 10 | and ecx, 1 11 | shr ecx, 0 12 | or eax, eax 13 | jz short loc_6039C9 14 | mov eax, ebx 15 | and eax, 100h 16 | shr eax, 8 17 | xor eax, ecx 18 | not eax 19 | and eax, 1 20 | or edx, eax 21 | shl edx, 1 22 | inc dword ptr [edi+24h] 23 | mov eax, ebx 24 | and eax, 800h 25 | or eax, eax 26 | jz short loc_6039F5 27 | mov ecx, [edi+1Ch] 28 | and ecx, 40h 29 | shr ecx, 6 30 | mov eax, ebx 31 | and eax, 400h 32 | shr eax, 0Ah 33 | xor eax, ecx 34 | not eax 35 | and eax, 1 36 | or edx, eax 37 | shl edx, 1 38 | inc dword ptr [edi+24h] 39 | mov eax, ebx 40 | and eax, 2000000h 41 | or eax, eax 42 | jz short loc_603A21 43 | mov ecx, [edi+1Ch] 44 | and ecx, 4 45 | shr ecx, 0Ah 46 | mov eax, ebx 47 | and eax, 1000000h 48 | shr eax, 18h 49 | xor eax, ecx 50 | not eax 51 | and eax, 1 52 | or edx, eax 53 | shl edx, 1 54 | inc dword ptr [edi+24h] 55 | mov eax, ebx 56 | and eax, 2000h 57 | or eax, eax 58 | jz short loc_603A50 59 | mov ecx, [edi+1Ch] 60 | and ecx, 80h 61 | shr ecx, 7 62 | mov eax, ebx 63 | and eax, 1000h 64 | shr eax, 0Ch 65 | xor eax, ecx 66 | not eax 67 | and eax, 1 68 | or edx, eax 69 | shl edx, 1 70 | inc dword ptr [edi+24h] 71 | mov eax, ebx 72 | and eax, 8000h 73 | or eax, eax 74 | jz short loc_603A7F 75 | mov ecx, [edi+1Ch] 76 | and ecx, 800h 77 | shr ecx, 0Bh 78 | mov eax, ebx 79 | and eax, 4000h 80 | shr eax, 0Eh 81 | xor eax, ecx 82 | not eax 83 | and eax, 1 84 | or edx, eax 85 | shl edx, 1 86 | inc dword ptr [edi+24h] 87 | mov eax, ebx 88 | and eax, 20000h 89 | or eax, eax 90 | jz short loc_603AAB 91 | mov ecx, [edi+1Ch] 92 | and ecx, 4 93 | shr ecx, 2 94 | mov eax, ebx 95 | and eax, 10000h 96 | shr eax, 10h 97 | xor eax, ecx 98 | not eax 99 | and eax, 1 100 | or edx, eax 101 | shl edx, 1 102 | inc dword ptr [edi+24h] 103 | mov eax, ebx 104 | and eax, 80000h 105 | or eax, eax 106 | jz short loc_603AE7 107 | mov ecx, [edi+1Ch] 108 | and ecx, 80h 109 | shr ecx, 7 110 | mov eax, [edi+1Ch] 111 | and eax, 800h 112 | shr eax, 0Bh 113 | xor ecx, eax 114 | mov eax, ebx 115 | and eax, 40000h 116 | shr eax, 12h 117 | xor eax, ecx 118 | not eax 119 | and eax, 1 120 | or edx, eax 121 | shl edx, 1 122 | inc dword ptr [edi+24h] 123 | mov eax, ebx 124 | and eax, 200000h 125 | or eax, eax 126 | jz short loc_603B06 127 | mov eax, [edi+28h] 128 | mov eax, [edi+eax*4] 129 | and eax, 0FFFFh 130 | or eax, eax 131 | jnz short loc_603B06 132 | mov edx, 1 133 | mov eax, ebx 134 | and eax, 800000h 135 | or eax, eax 136 | jz short loc_603B20 137 | mov eax, [edi+28h] 138 | mov eax, [edi+eax*4] 139 | or eax, eax 140 | jnz short loc_603B20 141 | mov edx, 1 142 | mov ecx, [edi+24h] 143 | mov eax, 1 144 | shl eax, cl 145 | dec eax 146 | and ebx, 10h 147 | or ebx, ebx 148 | jnz short loc_603B37 149 | mov [edi+20h], edx 150 | jmp short loc_603B44 151 | shr edx, 1 152 | cmp eax, edx 153 | jz short loc_603B44 154 | mov dword ptr [edi+20h], 0 155 | pop ebx -------------------------------------------------------------------------------- /clean_handlers/156.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | cmp dword ptr [edi+20h], 0 3 | jz short loc_603B53 4 | add esi, eax 5 | mov ebx, 0 6 | mov eax, eax -------------------------------------------------------------------------------- /clean_handlers/157.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | mov [edi+28h], al -------------------------------------------------------------------------------- /clean_handlers/158.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | movzx eax, al 3 | pop dx 4 | mov [edi+eax*4+1], dl -------------------------------------------------------------------------------- /clean_handlers/15a.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | add eax, [edi+2Ch] 3 | push eax -------------------------------------------------------------------------------- /clean_handlers/15d.txt: -------------------------------------------------------------------------------- 1 | mov eax, [edi+2Ch] 2 | add [esp], eax -------------------------------------------------------------------------------- /clean_handlers/15e.txt: -------------------------------------------------------------------------------- 1 | mov eax, [edi+2Ch] 2 | add edx, eax -------------------------------------------------------------------------------- /clean_handlers/15f.txt: -------------------------------------------------------------------------------- 1 | pop ecx 2 | shl dword ptr [esp], cl -------------------------------------------------------------------------------- /clean_handlers/160.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | xor [esp], eax -------------------------------------------------------------------------------- /clean_handlers/161.txt: -------------------------------------------------------------------------------- 1 | mov ebx, 0 -------------------------------------------------------------------------------- /clean_handlers/200.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | pop ecx 3 | mov [eax], ecx -------------------------------------------------------------------------------- /clean_handlers/201.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | xor edx, eax 3 | -------------------------------------------------------------------------------- /clean_handlers/202.txt: -------------------------------------------------------------------------------- 1 | mov ax, [edx] 2 | push ax 3 | -------------------------------------------------------------------------------- /clean_handlers/203.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | movzx eax, al 3 | -------------------------------------------------------------------------------- /clean_handlers/204.txt: -------------------------------------------------------------------------------- 1 | push dword ptr [edi+40h] 2 | -------------------------------------------------------------------------------- /clean_handlers/205.txt: -------------------------------------------------------------------------------- 1 | pop dword ptr [edi+40h] 2 | -------------------------------------------------------------------------------- /clean_handlers/206.txt: -------------------------------------------------------------------------------- 1 | mov sp, [esp] 2 | -------------------------------------------------------------------------------- /clean_handlers/207.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | sub edx, eax 3 | -------------------------------------------------------------------------------- /clean_handlers/208.txt: -------------------------------------------------------------------------------- 1 | mov esp, [esp] 2 | -------------------------------------------------------------------------------- /clean_handlers/209.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | mov edx, eax 3 | -------------------------------------------------------------------------------- /clean_handlers/20a.txt: -------------------------------------------------------------------------------- 1 | push sp 2 | add word ptr [esp], 2 3 | -------------------------------------------------------------------------------- /clean_handlers/20b.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | add edx, eax 3 | -------------------------------------------------------------------------------- /clean_handlers/20c.txt: -------------------------------------------------------------------------------- 1 | lodsd 2 | push dword ptr [eax] 3 | -------------------------------------------------------------------------------- /clean_handlers/20d.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | mov [edi+38h], al -------------------------------------------------------------------------------- /clean_handlers/20e.txt: -------------------------------------------------------------------------------- 1 | pop ax 2 | mov [edx], ax 3 | -------------------------------------------------------------------------------- /clean_handlers/20f.txt: -------------------------------------------------------------------------------- 1 | pop dword ptr [edi+1ch] 2 | -------------------------------------------------------------------------------- /clean_handlers/210.txt: -------------------------------------------------------------------------------- 1 | pop eax 2 | push edx 3 | mov edx, eax 4 | -------------------------------------------------------------------------------- /clean_handlers/211.txt: -------------------------------------------------------------------------------- 1 | lodsb 2 | movzx eax, al 3 | cmp eax, 7 4 | jz stack 5 | mov eax, [edi+eax*4] 6 | jmp fix_edx 7 | stack: 8 | mov eax, esp 9 | fix_edx: 10 | add edx, eax 11 | -------------------------------------------------------------------------------- /clean_handlers/212.txt: -------------------------------------------------------------------------------- 1 | mov ecx, [edi+38h] 2 | mov edx, edi 3 | or ecx, ecx 4 | jz fin 5 | mov esi, esp 6 | add esi, 24h 7 | mov edi, esi 8 | add edi, ecx 9 | std 10 | mov ecx, 0ah 11 | rep movsd 12 | add esp, [edx+38h] 13 | mov [edx+38h], 0 14 | fin: 15 | mov [edx+30h], 0 16 | popa 17 | popf 18 | retn 19 | -------------------------------------------------------------------------------- /clean_handlers/213.txt: -------------------------------------------------------------------------------- 1 | mov eax, [esp+4] 2 | mov [edi+40h], eax 3 | pop eax 4 | add esp, 4 5 | push eax 6 | -------------------------------------------------------------------------------- /clean_handlers/214.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pakt/decv/7c678726b11aec80a79e50ae8c7fc1096922fca0/clean_handlers/214.txt -------------------------------------------------------------------------------- /common.py: -------------------------------------------------------------------------------- 1 | import idc 2 | import idautils 3 | import idaapi 4 | 5 | 6 | MAX_USER_ADDR = 0x7fffffff 7 | FAKE_INSTR_ADDR = 0x0BADC0DE 8 | 9 | # "abstract" basic block class 10 | # we use different subclasses for different tasks 11 | class BB_: 12 | 13 | def __init__(self): 14 | self.child1 = self.child2 = None 15 | self.body = [] 16 | self.body_set = set() 17 | self.org_addr = None 18 | 19 | def get_addr(self): 20 | return self.org_addr 21 | 22 | def set_addr(self, addr): 23 | self.org_addr = addr 24 | 25 | def try_to_set_addr(self, addr): 26 | if self.org_addr == None: 27 | if type(addr) != int: 28 | addr = addr.get_addr() 29 | self.org_addr = addr 30 | 31 | def add(self, instr): 32 | self.try_to_set_addr(instr) 33 | if instr in self.body_set: 34 | assert(False) 35 | 36 | self.body.append(instr) 37 | self.body_set.add(instr) 38 | 39 | def merge(self, bb): 40 | self.try_to_set_addr(bb.get_addr()) 41 | 42 | if self.body_set.intersection(bb.body_set): 43 | assert(False) 44 | 45 | self.body += bb.body 46 | self.body_set.union(bb.body_set) 47 | 48 | def empty(self): 49 | return len(self.body)==0 50 | 51 | #"or" instead of "and" because root's only child can be a target for multiple jumps 52 | def is_multibranch(self): 53 | return self.child1 or self.child2 54 | 55 | def is_jxx(head): 56 | mnem = idc.GetMnem(head) 57 | if not mnem: 58 | print "Problem with getting mnemonic @ %08x"%head 59 | assert(False) 60 | return mnem[0]=="j" 61 | 62 | def is_jmp(head): 63 | mnem = idc.GetMnem(head) 64 | return mnem=="jmp" 65 | 66 | def is_short_jmp(ea): 67 | b = idc.Byte(ea) 68 | if b in [0xEB, 0x74, 0x75]: #short jmp 69 | return (True, 1) 70 | elif b == 0xE9: #long jmp 71 | return (False, 1) 72 | elif b == 0x0F: 73 | b2 = idc.Byte(ea+1) 74 | if b in [0x84, 0x85]: 75 | return (False, 2) 76 | else: 77 | pass #unexpected, throw assert 78 | 79 | print "unexpected byte @ 0x%x"%ea 80 | assert(False) 81 | 82 | # jump to next line? 83 | def is_jmp_next(ea): 84 | (short, off) = is_short_jmp(ea) 85 | if short: 86 | b = idc.Byte(ea+off) 87 | return b == 0x00 88 | else: 89 | s = idc.GetManyBytes(ea+off, 4) #Byte() returns int, but GetManyBytes a string. consistency FTW ;p 90 | return s == "\0\0\0\0" 91 | assert(False) 92 | 93 | def raw2int(x, bits): 94 | assert(bits in [8,16,32]) 95 | sign_mask = 1<<(bits-1) 96 | N = sign_mask << 1 97 | mul = 1 98 | if x & sign_mask: 99 | x = ~x+1 100 | x %= N 101 | mul = -1 102 | return x*mul 103 | 104 | def decode_jump(ea): 105 | (short, off) = is_short_jmp(ea) 106 | if short: 107 | b = idc.Byte(ea+off) 108 | t = raw2int(b, 8) + 2 109 | return ea+t 110 | else: 111 | s = idc.GetManyBytes(ea+off, 4) #Byte() returns int, but GetManyBytes a string. consistency FTW ;p 112 | s = s[::-1] 113 | x = 0 114 | for b in s: 115 | x <<= 8 116 | x += ord(b) 117 | t = raw2int(x, 32) + 5 118 | t = int(t) #cast from long 119 | return ea+t 120 | 121 | assert(False) 122 | 123 | def jxx_target(head): 124 | refs = idautils.CodeRefsFrom(head, 0) 125 | refs = list([x for x in refs]) 126 | n = len(refs) 127 | #jmp $+5 128 | if n>0: 129 | target = refs[0] 130 | elif n==0: 131 | if is_jmp_next(head): 132 | target = idc.NextNotTail(head) 133 | else: 134 | print "decoding @ 0x%x"%head 135 | #this is a bug in IDA. if MakeCode results in a new jmp, pointing to undefined byte: 136 | #jmp lol 137 | #... 138 | #lol: 139 | # db 0 140 | # 141 | #then CodeRefsFrom() will return nothing, so we need to decode the address ourselves :p 142 | #FIXME: remove everything except decode_jump? 143 | target = decode_jump(head) 144 | print "result: 0x%x"%target 145 | else: 146 | print "unknown jxx_target @ 0x%x"%head 147 | assert(False) 148 | 149 | return target 150 | 151 | def next_head(head): 152 | nxt = idc.NextHead(head, MAX_USER_ADDR) 153 | assert(nxt != idc.BADADDR) 154 | return nxt 155 | 156 | def prev_head(head): 157 | 158 | prv = idc.PrevHead(head, 0) 159 | assert(prv != idc.BADADDR) 160 | 161 | return prv 162 | 163 | def dfs(root, func): 164 | jmps = dict() 165 | Q = [root] 166 | visited = set() 167 | acc = None 168 | while Q: 169 | n = Q.pop() 170 | if n in visited: 171 | continue 172 | visited.add(n) 173 | c1, c2 = n.child1, n.child2 174 | children = filter(lambda c: c != None, [c1,c2]) 175 | for child in children: 176 | Q.append(child) 177 | #func. programming style :P 178 | acc = func(acc, n, children) 179 | 180 | return acc 181 | 182 | def str2int(s): 183 | s = s.replace("h", "") 184 | x = int(s, 16) 185 | return x 186 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | FN_EXAMPLE = "example.recover.txt" 2 | CLEAN_HANDLERS_DIR = "d:/_src/cv.1.3.8/decv/branches/tiny-emu/clean_handlers" 3 | -------------------------------------------------------------------------------- /decompiler.py: -------------------------------------------------------------------------------- 1 | import emu 2 | import copy 3 | from op_classes import * 4 | from vm_classes import * 5 | 6 | VMI_PREFIX = "VM_" 7 | HANDLER_ID_SIZE = 1 8 | handlers_dict = {} 9 | 10 | def emu_decrypt(handler, ctx, vm_code, size): 11 | 12 | raw = vm_code.consume(size) 13 | ctx.set_reg(EAX, raw) 14 | proc = handler.decrypt_proc 15 | 16 | emu.emulate_list(ctx, proc) 17 | eax = ctx.get_reg(EAX) 18 | return eax 19 | 20 | def decompile(main, handlers, vm_code): 21 | 22 | for i,h in enumerate(handlers): 23 | handlers_dict[i] = h 24 | 25 | ebx = vm_code.vaddr 26 | ctx = Ctx() 27 | ctx.set_reg(EBX, ebx) #ebx is our decryption key 28 | 29 | vmis = decompile_(main, ctx, handlers, vm_code) 30 | return vmis 31 | 32 | def decompile_(main, ctx, handlers, vm_code): 33 | 34 | c = 0 35 | vmis = [] 36 | while True: 37 | ebx = ctx.get_reg(EBX) 38 | #print "ebx:", hex(ebx) 39 | id = vm_code.peek(HANDLER_ID_SIZE) 40 | #print "enc id:", hex(id) 41 | 42 | vm_code_off = vm_code.offset 43 | next_id = emu_decrypt(main, ctx, vm_code, HANDLER_ID_SIZE) 44 | 45 | #0x13 dwords before handlers_tab 46 | next_id = next_id - 0x13 47 | #print "next_id:", hex(next_id) 48 | 49 | handler = handlers_dict[next_id] 50 | vmi = handler.vmi 51 | 52 | param, param_size = None, None 53 | if handler.takes_esi_params: 54 | param_size = handler.param_size 55 | param = emu_decrypt(handler, ctx, vm_code, param_size) 56 | #print "size:", size, "decrypted param:", hex(param) 57 | 58 | if vmi.affects_ctx(): 59 | vmi.update_ctx(ctx, vm_code, param) 60 | 61 | c += 1 62 | 63 | vmi = copy.deepcopy(vmi) 64 | vmi.param = param #we don't know these until decryption 65 | vmi.param_size = param_size 66 | vmi.code_off = vm_code_off 67 | 68 | dis = vmi.all_disasm() 69 | print dis 70 | 71 | vmis.append(vmi) 72 | 73 | if vmi.is_halt(): 74 | break 75 | return vmis 76 | -------------------------------------------------------------------------------- /decv.py: -------------------------------------------------------------------------------- 1 | #DeCV 2 | #decompiler for code virtualizer by oreans 3 | #tested on cv 1.3.8 4 | # 5 | #greets to softworm for his unpacked CV version :) 6 | # 7 | #p_k 8 | #02.10.2012 9 | #gdtr.wordpress.com 10 | 11 | import idc 12 | import idautils 13 | import idaapi 14 | import op 15 | import bb 16 | import opt 17 | import matcher 18 | import pickler 19 | from common import * 20 | from vm_classes import * 21 | from vm_instructions import * 22 | import decompiler 23 | import emu 24 | import sys 25 | import time 26 | import copy 27 | import cProfile, pstats 28 | import recover_x86 as x86 29 | import pickle 30 | 31 | #magic constants 32 | #this can be greater, up to 168 33 | #earlier versions of CV have 150 handlers, newer 168 34 | MIN_HANDLERS_COUNT = 100 35 | MAX_HANDLERS_PREFIX_LEN = 0x13*4 36 | MIN_REFS_TO_MAGIC_LODSB = MIN_HANDLERS_COUNT+1 37 | 38 | CALL_DELTA = "e8 00 00 00 00" 39 | LODSB = "ac" 40 | 41 | # if this is the handlers table 42 | # all entries should have two highest bytes equal 43 | def get_handlers(ea): 44 | handlers = [] 45 | dw = idc.Dword(ea) 46 | hi_word = dw & 0xffff0000 47 | while True: 48 | handlers.append(dw) 49 | ea += 4 50 | dw = idc.Dword(ea) 51 | if dw & 0xffff0000 != hi_word: 52 | break 53 | return handlers 54 | 55 | def skip_zero_dwords(ea): 56 | while True: 57 | dw = idc.Dword(ea) 58 | if dw != 0: 59 | break 60 | ea += 4 61 | return ea 62 | 63 | def is_handlers_tab(ea): 64 | 65 | handlers = get_handlers(ea) 66 | 67 | return (len(handlers) >= MIN_HANDLERS_COUNT) 68 | 69 | # collect 2nd op, if it's immediate 70 | def collect_imm_opnd2(ea, count): 71 | 72 | ops = [] 73 | ea = prev_head(ea) 74 | for i in range(count): 75 | ea = next_head(ea) 76 | 77 | otype = idc.GetOpType(ea, 1) 78 | if otype != idc.o_imm: 79 | continue 80 | 81 | op2 = idc.GetOperandValue(ea, 1) 82 | ops.append(op2) 83 | 84 | return ops 85 | 86 | def find_bytes(start, end, seq, seq_len): 87 | hits = [] 88 | 89 | while start < end-seq_len: 90 | 91 | hit_ea = idaapi.find_binary(start, end, seq, 16, idaapi.BIN_SEARCH_FORWARD) 92 | 93 | if hit_ea == idaapi.BADADDR: 94 | break 95 | 96 | start = hit_ea+seq_len 97 | 98 | #if idaapi.isCode(idc.GetFlags(hit_ea)): 99 | # hits.append(hit_ea) 100 | 101 | hits.append(hit_ea) 102 | 103 | return hits 104 | 105 | # search for call $+5 (delta call) 106 | # CV main handler starts this way 107 | def search_for_delta(start, end): 108 | 109 | call_len = CALL_DELTA.count(" ")+1 110 | 111 | calls = find_bytes(start, end, CALL_DELTA, call_len) 112 | 113 | # (delta_call, handler table) pairs 114 | found = [] 115 | for call_ea in calls: 116 | ops = collect_imm_opnd2(call_ea, 5) 117 | for op in ops: 118 | new_op = skip_zero_dwords(op) 119 | if new_op > op + MAX_HANDLERS_PREFIX_LEN or new_op == op: 120 | continue 121 | op = new_op 122 | if is_handlers_tab(op): 123 | found.append((call_ea, op)) 124 | 125 | return found 126 | 127 | # all handlers end with a jump to magic lodsb 128 | def search_for_magic_lodsb(start): 129 | SCAN_SIZE = 0x10000 130 | 131 | loads = find_bytes(start, start+SCAN_SIZE, LODSB, 1) 132 | candidates = [] 133 | for load_ea in loads: 134 | refs = idautils.CodeRefsTo(load_ea, 1) 135 | 136 | #unpack generator 137 | refs = list(x for x in refs) 138 | 139 | #the one we are looking for has >150 refs pointing to it 140 | if len(refs) 0: 237 | target = refs[0] 238 | 239 | if is_jmp(ea): 240 | uncond_jmps[ea] = target 241 | 242 | if target in visited_heads: 243 | break 244 | 245 | ea = prev_head(target) 246 | 247 | # multibranching 248 | elif is_jxx(ea): 249 | cond_jmps[ea] = target 250 | 251 | if target not in visited_heads: 252 | collected_branch = contract_handler_rec(target, f_terminate, visited_heads, cond_jmps, uncond_jmps) 253 | 254 | # append it later, for natural code layout 255 | branches.append(collected_branch) 256 | else: 257 | assert(False) 258 | 259 | combined_branches = reduce(lambda x,y: x+y, branches, []) 260 | 261 | return collected+combined_branches 262 | 263 | def visit(ea, visited): visited[ea]=True 264 | 265 | def was_visited(ea, visited): 266 | try: 267 | visited[ea] 268 | return True 269 | except: 270 | return False 271 | 272 | def make_code_rec(ea, visited, magic_lodsb): 273 | 274 | #print "rec" 275 | while True: 276 | 277 | if was_visited(ea, visited): 278 | break 279 | 280 | if ea == magic_lodsb: 281 | break 282 | 283 | visit(ea, visited) 284 | 285 | old_op = idc.GetOpnd(ea, 0) 286 | if not isCode(GetFlags(ea)): 287 | n = 6 288 | undefBytes(ea, n) 289 | i = 0 290 | while i>16 29 | 30 | def dump_all(tab): 31 | while True: 32 | id = idc.Dword(tab) 33 | start = idc.Dword(tab+4) 34 | end = idc.Dword(tab+8) 35 | tab += 16 36 | id = decode_id(id) 37 | print hex(id), hex(start), hex(end) 38 | if id == 0xFFFF: 39 | break 40 | dump_one(id, start, end) 41 | 42 | handlers = 0x603b70 43 | dump_all(handlers) 44 | -------------------------------------------------------------------------------- /emu.py: -------------------------------------------------------------------------------- 1 | from op_classes import * 2 | 3 | STACK_MEM_TOP = 0x11220000 4 | 5 | def emu_init_ctx(): 6 | ctx = Ctx() 7 | ctx.set_reg(ESP, STACK_MEM_TOP) 8 | return ctx 9 | 10 | def emu_decide_jump(dbb, ctx): 11 | #don't ask about the last BB 12 | #assert(dbb.child1 != None or dbb.child2 != None) 13 | 14 | taken = None 15 | seen_jxx = True 16 | for instr in dbb.body: 17 | instr.eval(ctx) 18 | if instr.is_jxx(): 19 | seen_jxx = True 20 | if instr.can_eval(ctx): 21 | taken = instr.eval_jxx(ctx) 22 | 23 | #jumps are last instructions in BBs 24 | break 25 | 26 | #if there is no jump at the end, then execution transfers to the only child 27 | if not seen_jxx: 28 | assert(dbb.child1 != None and dbb.child2 == None) 29 | taken = True 30 | 31 | return taken 32 | 33 | def emulate_list(ctx, instrs): 34 | for instr in instrs: 35 | instr.eval(ctx) 36 | 37 | def emulate(dbb): 38 | 39 | visited = set() 40 | ctx = emu_init_ctx() 41 | emulate_rec(dbb, ctx, visited) 42 | 43 | def emulate_rec(dbb, ctx, visited): 44 | 45 | assert(dbb not in visited) 46 | 47 | visited.add(dbb) 48 | 49 | for instr in dbb.body: 50 | 51 | instr.eval(ctx) 52 | print instr.dump() 53 | o = ctx.dump() 54 | print o 55 | 56 | if instr.is_jxx(): 57 | taken = None 58 | if instr.can_eval(ctx): 59 | taken = instr.eval_jxx(ctx) 60 | 61 | #jumps are last instructions 62 | if taken == None: 63 | break 64 | 65 | if taken: 66 | child = dbb.true_branch() 67 | else: 68 | child = dbb.false_branch() 69 | 70 | emulate_rec(child, ctx, visited) 71 | 72 | print "#"*10 73 | -------------------------------------------------------------------------------- /example_recover.txt: -------------------------------------------------------------------------------- 1 | original code: 2 | 3 | VIRTUALIZER_START 4 | 5 | bar: 6 | xor eax, 1111h 7 | xor ebx, 2222h 8 | xor ecx, 3333h 9 | xor edx, 4444h 10 | xor ebp, 5555h 11 | xor esi, 6666h 12 | xor edi, 7777h 13 | mov edx, offset x 14 | mov dword ptr [edx+eax], 1 15 | 16 | VIRTUALIZER_END 17 | 18 | recovery from CVL: 19 | 20 | 0x00000000 000[07] load ptr eflags 21 | 0x00000002 001 store addr 22 | 0x00000003 018 store dword [addr] 23 | vm_eflags <- eflags 24 | 0x00000004 000[03] load ptr edi 25 | 0x00000006 001 store addr 26 | 0x00000007 018 store dword [addr] 27 | vm_edi <- edi 28 | 0x00000008 000[04] load ptr esi 29 | 0x0000000a 001 store addr 30 | 0x0000000b 018 store dword [addr] 31 | vm_esi <- esi 32 | 0x0000000c 000[00] load ptr ebp 33 | 0x0000000e 001 store addr 34 | 0x0000000f 018 store dword [addr] 35 | vm_ebp <- ebp 36 | 0x00000010 000[01] load ptr ebx 37 | 0x00000012 001 store addr 38 | 0x00000013 018 store dword [addr] 39 | vm_ebx <- ebx 40 | 0x00000014 157[02] 157 param: 0x02 41 | unk_157: mov byte [edi+28h], 2 42 | 0x00000016 000[01] load ptr ebx 43 | 0x00000018 001 store addr 44 | 0x00000019 018 store dword [addr] 45 | vm_ebx <- ebx 46 | 0x0000001a 000[05] load ptr edx 47 | 0x0000001c 001 store addr 48 | 0x0000001d 018 store dword [addr] 49 | vm_edx <- edx 50 | 0x0000001e 000[02] load ptr ecx 51 | 0x00000020 001 store addr 52 | 0x00000021 018 store dword [addr] 53 | vm_ecx <- ecx 54 | 0x00000022 000[06] load ptr eax 55 | 0x00000024 001 store addr 56 | 0x00000025 018 store dword [addr] 57 | vm_eax <- eax 58 | 0x00000026 14e move addr, STACK 59 | 0x00000027 009 load addr 60 | 0x00000028 004[00000004] load dword 0x4L 61 | 0x0000002d 006 add. dword 62 | 0x0000002e 208 move STACK, [STACK] 63 | 0x0000002f 009 load addr 64 | 0x00000030 000[03] load ptr edi 65 | 0x00000032 001 store addr 66 | 0x00000033 00c load dword [addr] 67 | 0x00000034 001 store addr 68 | 0x00000035 001 store addr 69 | 0x00000036 000[06] load ptr eax 70 | 0x00000038 001 store addr 71 | 0x00000039 00c load dword [addr] 72 | 0x0000003a 004[00001111] load dword 0x1111L 73 | 0x0000003f 03d xor dword 74 | 0x00000040 01c[07] store dword eflags 75 | 0x00000042 000[06] load ptr eax 76 | 0x00000044 001 store addr 77 | 0x00000045 018 store dword [addr] 78 | eax <- 0x1111L ^ eax 79 | 0x00000046 000[01] load ptr ebx 80 | 0x00000048 001 store addr 81 | 0x00000049 00c load dword [addr] 82 | 0x0000004a 004[00002222] load dword 0x2222L 83 | 0x0000004f 03d xor dword 84 | 0x00000050 009 load addr 85 | 0x00000051 009 load addr 86 | 0x00000052 004[00000004] load dword 0x4L 87 | 0x00000057 006 add. dword 88 | 0x00000058 001 store addr 89 | 0x00000059 001 store addr 90 | 0x0000005a 01c[07] store dword eflags 91 | 0x0000005c 009 load addr 92 | 0x0000005d 000[01] load ptr ebx 93 | 0x0000005f 001 store addr 94 | 0x00000060 001 store addr 95 | 0x00000061 000[01] load ptr ebx 96 | 0x00000063 001 store addr 97 | 0x00000064 018 store dword [addr] 98 | ebx <- 0x2222L ^ ebx 99 | 0x00000065 000[02] load ptr ecx 100 | 0x00000067 001 store addr 101 | 0x00000068 00c load dword [addr] 102 | 0x00000069 004[00003333] load dword 0x3333L 103 | 0x0000006e 03d xor dword 104 | 0x0000006f 01c[07] store dword eflags 105 | 0x00000071 000[02] load ptr ecx 106 | 0x00000073 001 store addr 107 | 0x00000074 018 store dword [addr] 108 | ecx <- 0x3333L ^ ecx 109 | 0x00000075 009 load addr 110 | 0x00000076 000[06] load ptr eax 111 | 0x00000078 001 store addr 112 | 0x00000079 001 store addr 113 | 0x0000007a 000[05] load ptr edx 114 | 0x0000007c 001 store addr 115 | 0x0000007d 00c load dword [addr] 116 | 0x0000007e 004[00004444] load dword 0x4444L 117 | 0x00000083 03d xor dword 118 | 0x00000084 01c[07] store dword eflags 119 | 0x00000086 000[05] load ptr edx 120 | 0x00000088 001 store addr 121 | 0x00000089 009 load addr 122 | 0x0000008a 009 load addr 123 | 0x0000008b 004[00000004] load dword 0x4L 124 | 0x00000090 006 add. dword 125 | 0x00000091 001 store addr 126 | 0x00000092 001 store addr 127 | 0x00000093 018 store dword [addr] 128 | edx <- 0x4444L ^ edx 129 | 0x00000094 000[00] load ptr ebp 130 | 0x00000096 001 store addr 131 | 0x00000097 00c load dword [addr] 132 | 0x00000098 004[00005555] load dword 0x5555L 133 | 0x0000009d 000[02] load ptr ecx 134 | 0x0000009f 001 store addr 135 | 0x000000a0 00c load dword [addr] 136 | 0x000000a1 000[02] load ptr ecx 137 | 0x000000a3 001 store addr 138 | 0x000000a4 00c load dword [addr] 139 | 0x000000a5 024 add dword 140 | 0x000000a6 01c[07] store dword eflags 141 | 0x000000a8 001 store addr 142 | 0x000000a9 03d xor dword 143 | 0x000000aa 01c[07] store dword eflags 144 | 0x000000ac 000[00] load ptr ebp 145 | 0x000000ae 001 store addr 146 | 0x000000af 018 store dword [addr] 147 | ebp <- 0x5555L ^ ebp 148 | 0x000000b0 000[04] load ptr esi 149 | 0x000000b2 001 store addr 150 | 0x000000b3 00c load dword [addr] 151 | 0x000000b4 004[00006666] load dword 0x6666L 152 | 0x000000b9 03d xor dword 153 | 0x000000ba 01c[07] store dword eflags 154 | 0x000000bc 000[04] load ptr esi 155 | 0x000000be 001 store addr 156 | 0x000000bf 018 store dword [addr] 157 | esi <- 0x6666L ^ esi 158 | 0x000000c0 000[03] load ptr edi 159 | 0x000000c2 001 store addr 160 | 0x000000c3 00c load dword [addr] 161 | 0x000000c4 004[00007777] load dword 0x7777L 162 | 0x000000c9 03d xor dword 163 | 0x000000ca 01c[07] store dword eflags 164 | 0x000000cc 000[03] load ptr edi 165 | 0x000000ce 001 store addr 166 | 0x000000cf 009 load addr 167 | 0x000000d0 000[04] load ptr esi 168 | 0x000000d2 001 store addr 169 | 0x000000d3 001 store addr 170 | 0x000000d4 018 store dword [addr] 171 | edi <- 0x7777L ^ edi 172 | 0x000000d5 004[00403000] load dword 0x403000L 173 | 0x000000da 009 load addr 174 | 0x000000db 003[53a5] load word 0x53a5L 175 | 0x000000de 003[1b62] load word 0x1b62L 176 | 0x000000e1 001 store addr 177 | 0x000000e2 001 store addr 178 | 0x000000e3 000[05] load ptr edx 179 | 0x000000e5 001 store addr 180 | 0x000000e6 018 store dword [addr] 181 | edx <- 4206592 182 | 0x000000e7 009 load addr 183 | 0x000000e8 003[e92b] load word 0xe92bL 184 | 0x000000eb 003[7882] load word 0x7882L 185 | 0x000000ee 001 store addr 186 | 0x000000ef 001 store addr 187 | 0x000000f0 004[00000001] load dword 0x1L 188 | 0x000000f5 007[06] load dword eax 189 | 0x000000f7 001 store addr 190 | 0x000000f8 211[05] add_reg_to_addr edx 191 | 0x000000fa 018 store dword [addr] 192 | [eax + edx] <- 1 193 | 0x000000fb 004[0040105b] load dword 0x40105bL 194 | 0x00000100 15d 15d 195 | push_return_address: 0x0040105b 196 | 0x00000101 154[00000001] jmp $+0x1 197 | jmp $+1 198 | 0x00000107 000[07] load ptr eflags 199 | 0x00000109 001 store addr 200 | 0x0000010a 00c load dword [addr] 201 | 0x0000010b 000[06] load ptr eax 202 | 0x0000010d 001 store addr 203 | 0x0000010e 00c load dword [addr] 204 | 0x0000010f 000[02] load ptr ecx 205 | 0x00000111 001 store addr 206 | 0x00000112 00c load dword [addr] 207 | 0x00000113 000[05] load ptr edx 208 | 0x00000115 001 store addr 209 | 0x00000116 00c load dword [addr] 210 | 0x00000117 000[01] load ptr ebx 211 | 0x00000119 001 store addr 212 | 0x0000011a 00c load dword [addr] 213 | 0x0000011b 000[01] load ptr ebx 214 | 0x0000011d 001 store addr 215 | 0x0000011e 00c load dword [addr] 216 | 0x0000011f 000[00] load ptr ebp 217 | 0x00000121 001 store addr 218 | 0x00000122 00c load dword [addr] 219 | 0x00000123 000[04] load ptr esi 220 | 0x00000125 001 store addr 221 | 0x00000126 00c load dword [addr] 222 | 0x00000127 000[03] load ptr edi 223 | 0x00000129 001 store addr 224 | 0x0000012a 00c load dword [addr] 225 | 0x0000012b 212 gtfo 226 | gtfo 227 | 228 | -------------------------------------------------------------------------------- /gen_vmi.py: -------------------------------------------------------------------------------- 1 | import re, os 2 | import sys 3 | from config import * 4 | 5 | # super(self).init__() ? 6 | 7 | top_class_body = """ 8 | class %s(VM_Inst_With_Suff): 9 | def __init__(self): 10 | self.mnem = "%s" 11 | VM_Inst_With_Suff.__init__(self) 12 | """ 13 | 14 | small_class_body = """ 15 | class VM_%s(%s): 16 | def __init__(self): 17 | self.fn = "%s.txt" 18 | self.size = %d 19 | %s.__init__(self) 20 | """ 21 | 22 | disasm = """ 23 | def disasm(self, param): 24 | d = VM_Inst_With_Suff.disasm(self, param) 25 | %s 26 | return d 27 | """ 28 | 29 | def gen_bwd(mnem, top_class_name, fn_list, custom_disasm): 30 | top_class = top_class_body%(top_class_name, mnem) 31 | if custom_disasm: 32 | dis_proc = disasm%custom_disasm 33 | top_class += "\n" + dis_proc 34 | 35 | if len(fn_list)==3: 36 | sizes = [8,16,32] 37 | elif len(fn_list)==2: 38 | sizes = [16,32] 39 | else: 40 | assert(False) 41 | 42 | fn_list = zip(fn_list, sizes) 43 | out = top_class 44 | for fn,size in fn_list: 45 | small_class = small_class_body%(fn, top_class_name, fn, size, top_class_name) 46 | out += small_class 47 | 48 | return out 49 | 50 | def add_generated(new, d): 51 | for h in new: 52 | d[h] = 1 53 | return d 54 | 55 | def extract_small_names(s): 56 | l = re.findall(r"class (VM_.*?)\(", s) 57 | return l 58 | 59 | if __name__=="__main__": 60 | 61 | # not;VM_Not;001,002,003;d+=foo; 62 | 63 | if len(sys.argv)<2: 64 | print sys.argv[0], " [vm_instructions.py]" 65 | sys.exit(1) 66 | 67 | src_fn = None 68 | if len(sys.argv)==3: 69 | src_fn = sys.argv[2] 70 | 71 | f = open(sys.argv[1]) 72 | l = f.readlines() 73 | f.close() 74 | 75 | l = map(lambda x: x.strip(), l) 76 | 77 | all_handlers = os.listdir("clean_handlers") 78 | generated_handlers = dict() 79 | 80 | pre = "# AUTOGENERATED BY gen_vmi.py\n# DO NOT EDIT!\n" 81 | pre += "from vmi_top_common import *" 82 | 83 | print pre 84 | 85 | prefix = "VM_" 86 | 87 | classes = [] 88 | for line in l: 89 | line = re.sub(r"#.*", "", line) 90 | if not line: 91 | continue 92 | mnem, class_name, fn_list, custom_disasm = line.split(";") 93 | clean = re.sub(r"\s+", "", custom_disasm) 94 | if clean == "": 95 | custom_disasm = None 96 | 97 | fn_list = fn_list.split(",") 98 | fn_count = len(fn_list) 99 | 100 | if fn_count==1: 101 | n = int(fn_list[0], 16) 102 | fn_list = [n, n+1, n+2] 103 | fn_list = map(lambda n: hex(n).replace("0x",""), fn_list) 104 | fn_list = map(lambda s: "0"*(3-len(s))+s, fn_list) 105 | 106 | generated_handlers = add_generated(fn_list, generated_handlers) 107 | 108 | if not class_name: 109 | class_name = prefix + mnem.title() 110 | else: 111 | class_name = prefix + class_name.title().replace(" ", "_") 112 | 113 | o = gen_bwd(mnem, class_name, fn_list, custom_disasm) 114 | 115 | print o 116 | 117 | small = extract_small_names(o) 118 | classes += small 119 | 120 | #print "# not handled:" 121 | 122 | not_handled = [] 123 | for h_fn in all_handlers: 124 | h_id = h_fn.replace(".txt", "") 125 | try: 126 | generated_handlers[h_id] 127 | continue 128 | except: 129 | pass 130 | 131 | #print "# ", h_fn 132 | not_handled.append(h_id) 133 | 134 | if src_fn != None: 135 | classes.sort() 136 | f = open(src_fn, "r") 137 | src = f.read() 138 | f.close() 139 | 140 | #ocaml.. 141 | def seek(cn, callback): 142 | cn = "class "+cn 143 | res = src.find(cn)>=0 144 | callback(res, cn, src_fn) 145 | 146 | def remove_f(found, cn, src_fn): 147 | if found: 148 | print "# remove %s from %s!"%(cn, src_fn) 149 | 150 | def add_f(found, cn, src_fn): 151 | if not found: 152 | print "# add %s to %s!"%(cn, src_fn) 153 | 154 | for cn in classes: 155 | seek(cn, remove_f) 156 | 157 | not_handled = map(lambda x: prefix+x, not_handled) 158 | 159 | for cn in not_handled: 160 | seek(cn, add_f) 161 | 162 | -------------------------------------------------------------------------------- /matcher.py: -------------------------------------------------------------------------------- 1 | # matches deobfuscated handlers the original ones 2 | from config import * 3 | import re 4 | import os 5 | from vm_instructions import * 6 | 7 | HANDLERS_DICT = dict() 8 | 9 | def get_disasm(handler_id): 10 | return HANDLERS_DICT[handler_id] 11 | 12 | def get_id_from_fn(fn): 13 | dot = fn.find(".") 14 | assert(dot>0) 15 | return int(fn[:dot], 16) 16 | 17 | def load_clean_handlers(clean_dir): 18 | clean_handlers = [] 19 | files = os.listdir(clean_dir) 20 | for fn in files: 21 | dir_fn = os.path.join(clean_dir, fn) 22 | f = open(dir_fn, "r") 23 | disasm = f.read() 24 | f.close() 25 | id = get_id_from_fn(fn) 26 | HANDLERS_DICT[id] = disasm 27 | clean_handlers.append(id) 28 | return clean_handlers 29 | 30 | def dump_identified(identified): 31 | for disasm, clean_sorted in identified: 32 | print disasm 33 | print "matched with:", "#"*10 34 | id = clean_sorted[0] 35 | clean_disasm = get_disasm(handler_id) 36 | print clean_disasm 37 | 38 | #make lowercase 39 | #contract whitespace 40 | def normalize(txt): 41 | txt = txt.lower() 42 | txt = re.sub("\s+", " ", txt) 43 | txt = txt.strip() 44 | return txt 45 | 46 | def count_matching_lines(s1, s2): 47 | s = s1 & s2 48 | return len(s) 49 | 50 | #n^2, but no need to be faster 51 | #returns list of (i,j) pairs: l1[i] == l2[j] 52 | def exact_matcher(l1, l2): 53 | c = 0 54 | matched = [] 55 | for i,x1 in enumerate(l1): 56 | ok = False 57 | for j,x2 in enumerate(l2): 58 | if x1 == x2 and ok: 59 | """ 60 | print "dupe:" 61 | print x1 62 | print "---" 63 | """ 64 | elif x1 == x2: 65 | #print "EXACT MATCH!" 66 | #print x1 67 | c += 1 68 | matched.append((i,j)) 69 | ok = True 70 | if not ok: 71 | #print "unmatched: '%s'"%x1 72 | pass 73 | 74 | print "matched: %d/%d"%(c, len(l1)) 75 | 76 | return matched 77 | 78 | #cut everything after "j" (cut after first jump) 79 | def trim_jxx(txt): 80 | txt = re.sub(r"j.*", "j", txt) 81 | return txt 82 | 83 | #FIXME: empty handlers 84 | def x_identify_handlers(deobfu_handlers): 85 | 86 | clean_handlers = load_clean_handlers(CLEAN_HANDLERS_DIR) 87 | 88 | print "clean_handlers:", len(clean_handlers) 89 | 90 | identified = [] 91 | 92 | deobfu_disasms = map(lambda h: h.get_org_disasm(), deobfu_handlers) 93 | clean_disasms = map(lambda h_id: HANDLERS_DICT[h_id], clean_handlers) 94 | 95 | norm_deobfu_disasms = map(lambda h: normalize(h), deobfu_disasms) 96 | norm_clean_disasms = map(lambda h: normalize(h), clean_disasms) 97 | 98 | matched = exact_matcher(norm_deobfu_disasms, norm_clean_disasms) 99 | unmatched = list(set(norm_deobfu_disasms) - set(matched)) 100 | unmatched_clean = list(set(norm_clean_disasms) - set(matched)) 101 | 102 | trim_unmatched = map(lambda h: trim_jxx(h), unmatched) 103 | trim_clean = map(lambda h: trim_jxx(h), unmatched_clean) 104 | 105 | matched = exact_matcher(trim_unmatched, trim_clean) 106 | 107 | unmatched = list(set(trim_unmatched) - set(matched)) 108 | 109 | #print "UNMATCHED" 110 | assert(unmatched == []) 111 | 112 | vm_instrs = map(lambda h: VM_Instruction(), deobfu_handlers) 113 | return vm_instrs 114 | 115 | def load_all_vm_instrs(): 116 | 117 | vmis = map(lambda vmi_class: vmi_class(), VM_INSTRUCTIONS_SET) 118 | return vmis 119 | 120 | def identify_handlers(deobfu_handlers): 121 | 122 | vmis = load_all_vm_instrs() 123 | for vmi in vmis: 124 | vmi.trimmed_src = trim_jxx(normalize(vmi.src)) 125 | 126 | """ 127 | vmis_with_jxx = filter(lambda vmi: vmi.src_has_branches(), vmis) 128 | vmis_with_jxx = set(vmis_with_jxx) 129 | vmis = set(vmis) - vmis_with_jxx 130 | """ 131 | 132 | print "deobfu handlers count:", len(deobfu_handlers) 133 | print "vmi count:", len(vmis) 134 | 135 | identified = [] 136 | 137 | for h in deobfu_handlers: 138 | disasm = h.get_org_disasm() 139 | trimmed_disasm = trim_jxx(normalize(disasm)) 140 | found = False 141 | for vmi in vmis: 142 | if trimmed_disasm == vmi.trimmed_src: 143 | if not found: 144 | identified.append(vmi) 145 | found = True 146 | else: 147 | """ 148 | print "dupe:", disasm 149 | print "-"*5 150 | """ 151 | pass 152 | 153 | if found: 154 | continue 155 | 156 | print "not found:" 157 | print hex(h.get_addr()) 158 | print disasm 159 | print "-"*5 160 | assert(False) 161 | 162 | assert(len(identified) == len(deobfu_handlers)) 163 | 164 | return identified 165 | 166 | -------------------------------------------------------------------------------- /op.py: -------------------------------------------------------------------------------- 1 | import idc 2 | import re 3 | from common import * 4 | from op_classes import * 5 | 6 | def convert_graph(root): 7 | _, root = dfs(root, f_convert) 8 | return root 9 | 10 | def f_convert(acc, bb, children): 11 | if acc == None: 12 | acc = dict(), None 13 | 14 | bb_to_dbb, root = acc 15 | 16 | try: 17 | dbb = bb_to_dbb[bb] 18 | except: 19 | dbb = convert_bb(bb) 20 | bb_to_dbb[bb] = dbb 21 | 22 | #print "bb:", bb.disasm() 23 | 24 | for i,child in enumerate(children): 25 | try: 26 | child_dbb = bb_to_dbb[child] 27 | except: 28 | child_dbb = convert_bb(child) 29 | bb_to_dbb[child] = child_dbb 30 | 31 | #print "child:", i, child.disasm() 32 | 33 | if i==0: 34 | dbb.child1 = child_dbb 35 | elif i==1: 36 | dbb.child2 = child_dbb 37 | 38 | if root==None: 39 | root = dbb 40 | 41 | return bb_to_dbb, root 42 | 43 | def convert_bb(bb): 44 | dbb = DBB() 45 | last = bb.body[-1] 46 | for n in bb.body: 47 | # don't collect uncond. jmps from inside 48 | if is_jmp(n) and n!=last: 49 | continue 50 | m = convert_inst(n) 51 | dbb.add(m) 52 | return dbb 53 | 54 | def convert_inst(addr): 55 | mnem = idc.GetMnem(addr) 56 | 57 | op1 = idc.GetOpnd(addr, 0) 58 | op2 = idc.GetOpnd(addr, 1) 59 | 60 | if not op1: op1 = None 61 | if not op2: op2 = None 62 | 63 | if is_jxx(addr): 64 | op1 = jxx_target(addr) 65 | op1 = str(op1) 66 | 67 | if op1: 68 | op1 = Opnd(op1) 69 | if op2: 70 | op2 = Opnd(op2) 71 | 72 | if is_jmp(addr): 73 | ni = Jmp(addr, mnem, op1) 74 | elif is_jxx(addr): 75 | ni = Jxx(addr, mnem, op1) 76 | 77 | elif mnem == "add": 78 | ni = Add(addr, mnem, op1, op2) 79 | elif mnem == "sub": 80 | ni = Sub(addr, mnem, op1, op2) 81 | elif mnem == "and": 82 | ni = And(addr, mnem, op1, op2) 83 | elif mnem == "or": 84 | ni = Or(addr, mnem, op1, op2) 85 | elif mnem == "xor": 86 | ni = Xor(addr, mnem, op1, op2) 87 | elif mnem == "dec": 88 | ni = Dec(addr, mnem, op1, op2) 89 | elif mnem == "inc": 90 | ni = Inc(addr, mnem, op1, op2) 91 | elif mnem == "not": 92 | ni = Not(addr, mnem, op1, op2) 93 | elif mnem == "neg": 94 | ni = Neg(addr, mnem, op1, op2) 95 | elif mnem == "shl": 96 | ni = Shl(addr, mnem, op1, op2) 97 | elif mnem == "shr": 98 | ni = Shr(addr, mnem, op1, op2) 99 | elif mnem == "test": 100 | ni = Test(addr, mnem, op1, op2) 101 | elif mnem == "xchg": 102 | ni = Xchg(addr, mnem, op1, op2) 103 | elif mnem == "mov": 104 | ni = Mov(addr, mnem, op1, op2) 105 | 106 | elif mnem == "push": 107 | ni = Push(addr, mnem, op1, op2) 108 | elif mnem == "pop": 109 | ni = Pop(addr, mnem, op1, op2) 110 | 111 | elif mnem == "pushf": 112 | ni = Pushf(addr, mnem, op1, op2) 113 | elif mnem == "popf": 114 | ni = Popf(addr, mnem, op1, op2) 115 | 116 | elif mnem in NOT_IMPLEMENTED: 117 | ni = Inst(addr, mnem, op1, op2) 118 | 119 | else: 120 | print "Unsupported addrruction @%s: %s"%(hex(addr), mnem) 121 | assert(False) 122 | 123 | return ni 124 | 125 | 126 | -------------------------------------------------------------------------------- /op_classes.py: -------------------------------------------------------------------------------- 1 | import re 2 | from common import * 3 | from PyFlags import PyFlags 4 | 5 | NOT_IMPLEMENTED = set(['lea', 'adc', 'bswap', 'bt', 'btc', 'btr', 'bts', 'cmp', 'div', 'idiv', 'imul', 'lods', 'movs', 'movsx', 'movzx', 'mul', 'popa', 'rcl', 'rcr', 'retn', 'rol', 'ror', 'sar', 'sbb', 'std']) 6 | 7 | ESP = "esp" 8 | EAX = "eax" 9 | EBX = "ebx" 10 | ESI = "esi" 11 | 12 | EAX_REGS = set(["al", "ah", "ax", "eax"]) 13 | EBX_REGS = set(["bl", "bh", "bx", "ebx"]) 14 | ECX_REGS = set(["cl", "ch", "cx", "ecx"]) 15 | EDX_REGS = set(["dl", "dh", "dx", "edx"]) 16 | ESI_REGS = set(["si", "esi"]) 17 | EDI_REGS = set(["di", "edi"]) 18 | EBP_REGS = set(["bp", "ebp"]) 19 | ESP_REGS = set(["sp", "esp"]) 20 | 21 | UNSET_EAX_AFFECTED = { "al": EAX_REGS-set(["ah"]), 22 | "ah": EAX_REGS-set(["al"]), 23 | "ax": EAX_REGS, 24 | "eax": EAX_REGS 25 | } 26 | def unset_affected_aux(unset, patt, rep): 27 | new_unset = dict() 28 | for reg, affected in unset.iteritems(): 29 | new_reg = reg.replace(patt, rep) 30 | new_unset[new_reg] = set(map(lambda r: r.replace(patt, rep), affected)) 31 | return new_unset 32 | 33 | def combine_unset_affected(reg_sets, aff_sets): 34 | combined = dict() 35 | for reg_set, aff_set in zip(reg_sets, aff_sets): 36 | for reg in reg_set: 37 | combined[reg] = aff_set 38 | return combined 39 | 40 | UNSET_EBX_AFFECTED = unset_affected_aux(UNSET_EAX_AFFECTED, "a", "b") 41 | UNSET_ECX_AFFECTED = unset_affected_aux(UNSET_EAX_AFFECTED, "a", "c") 42 | UNSET_EDX_AFFECTED = unset_affected_aux(UNSET_EAX_AFFECTED, "a", "d") 43 | UNSET_ESI_AFFECTED = {"si": ESI_REGS, "esi": ESI_REGS} 44 | UNSET_EDI_AFFECTED = {"di": EDI_REGS, "edi": EDI_REGS} 45 | UNSET_EBP_AFFECTED = {"bp": EBP_REGS, "ebp": EBP_REGS} 46 | UNSET_ESP_AFFECTED = {"sp": ESP_REGS, "esp": ESP_REGS} 47 | 48 | RESET_EAX_AFFECTED = { "eax": EAX_REGS, 49 | "ax": EAX_REGS-set(["eax"]), 50 | "ah": set(["ah"]), 51 | "al": set(["al"]) 52 | } 53 | RESET_EBX_AFFECTED = unset_affected_aux(RESET_EAX_AFFECTED, "a", "b") 54 | RESET_ECX_AFFECTED = unset_affected_aux(RESET_EAX_AFFECTED, "a", "c") 55 | RESET_EDX_AFFECTED = unset_affected_aux(RESET_EAX_AFFECTED, "a", "d") 56 | RESET_ESI_AFFECTED = {"si": ESI_REGS, "esi": ESI_REGS} 57 | RESET_EDI_AFFECTED = {"di": EDI_REGS, "edi": EDI_REGS} 58 | RESET_EBP_AFFECTED = {"bp": EBP_REGS, "ebp": EBP_REGS} 59 | RESET_ESP_AFFECTED = {"sp": ESP_REGS, "esp": ESP_REGS} 60 | 61 | REG_UNSET_AFFECTED_LIST = [ UNSET_EAX_AFFECTED, UNSET_EBX_AFFECTED, UNSET_ECX_AFFECTED, UNSET_EDX_AFFECTED, 62 | UNSET_ESI_AFFECTED, UNSET_EDI_AFFECTED, UNSET_EBP_AFFECTED, UNSET_ESP_AFFECTED 63 | ] 64 | REG_RESET_AFFECTED_LIST = [ RESET_EAX_AFFECTED, RESET_EBX_AFFECTED, RESET_ECX_AFFECTED, RESET_EDX_AFFECTED, 65 | RESET_ESI_AFFECTED, RESET_EDI_AFFECTED, RESET_EBP_AFFECTED, RESET_ESP_AFFECTED 66 | ] 67 | 68 | REG_LIST = [EAX_REGS, EBX_REGS, ECX_REGS, EDX_REGS, ESI_REGS, EDI_REGS, EBP_REGS, ESP_REGS] 69 | REG_UNSET_AFFECTED = combine_unset_affected(REG_LIST, REG_UNSET_AFFECTED_LIST) 70 | REG_RESET_AFFECTED = combine_unset_affected(REG_LIST, REG_RESET_AFFECTED_LIST) 71 | 72 | REG_TO_REG_SET = combine_unset_affected(REG_LIST, REG_LIST) 73 | 74 | REG_SET = reduce(lambda x,y: x|y, REG_LIST, set()) 75 | 76 | REG_8BIT = set(filter(lambda r: r[1] in ["l","h"], REG_SET)) 77 | REG_16BIT = set(filter(lambda r: len(r)==2 and r not in REG_8BIT, REG_SET)) 78 | REG_32BIT = REG_SET - REG_8BIT - REG_16BIT 79 | 80 | F_SET_EAX = lambda reg_dict,reg,val: f_reg_set32(reg_dict, reg, val, "eax", "ax", "ah", "al") 81 | F_SET_EBX = lambda reg_dict,reg,val: f_reg_set32(reg_dict, reg, val, "ebx", "bx", "bh", "bl") 82 | F_SET_ECX = lambda reg_dict,reg,val: f_reg_set32(reg_dict, reg, val, "ecx", "cx", "ch", "cl") 83 | F_SET_EDX = lambda reg_dict,reg,val: f_reg_set32(reg_dict, reg, val, "edx", "dx", "dh", "dl") 84 | F_SET_ESI = lambda reg_dict,reg,val: f_reg_set32(reg_dict, reg, val, "esi", "si", None, None) 85 | F_SET_EDI = lambda reg_dict,reg,val: f_reg_set32(reg_dict, reg, val, "edi", "di", None, None) 86 | F_SET_EBP = lambda reg_dict,reg,val: f_reg_set32(reg_dict, reg, val, "ebp", "bp", None, None) 87 | F_SET_ESP = lambda reg_dict,reg,val: f_reg_set32(reg_dict, reg, val, "esp", "sp", None, None) 88 | 89 | FUN_SET_LIST = [(EAX_REGS, F_SET_EAX), (EBX_REGS, F_SET_EBX), (ECX_REGS, F_SET_ECX), (EDX_REGS, F_SET_EDX), 90 | (ESI_REGS, F_SET_ESI), (EDI_REGS, F_SET_EDI), (EBP_REGS, F_SET_EBP), (ESP_REGS, F_SET_ESP)] 91 | 92 | CF = "CF" #carry 93 | PF = "PF" #parity 94 | AF = "AF" #auxiliary 95 | ZF = "ZF" #zero 96 | SF = "SF" #sign 97 | OF = "OF" #overflow 98 | FLAGS = [CF, PF, AF, ZF, SF, OF] 99 | 100 | def set_reg_aux(values, reg, value): 101 | assert(reg in REG_SET) 102 | 103 | for reg_set, func_set in FUN_SET_LIST: 104 | if reg in reg_set: 105 | return func_set(values, reg, value) 106 | assert(False) 107 | 108 | O_MEM = 0 109 | O_REG = 1 110 | O_IMM = 2 111 | O_MEM_REG_PLUS_INDEX = 0x10 112 | O_MEM_COMPLEX = 0x11 113 | 114 | imm_re = re.compile("([0-9a-fA-F]+)h?") 115 | 116 | def try_get_from_dict(dic, k): 117 | try: 118 | v = dic[k] 119 | except: 120 | v = None 121 | return v 122 | 123 | def f_reg_upd32(mod_values, reg32, value): 124 | 125 | bit32v = try_get_from_dict(mod_values, reg32) 126 | if bit32v != None: 127 | bit32v = (bit32v & 0xFFFF0000) | value 128 | mod_values[reg32] = bit32v 129 | 130 | return mod_values 131 | 132 | def f_reg_set8(values, reg, value): 133 | assert(reg in REG_8BIT) 134 | values[reg] = value 135 | return values 136 | 137 | def f_reg_set16(values, reg, value, hi_bit8, lo_bit8): 138 | assert(reg in REG_16BIT) 139 | mod_values = values 140 | mod_values[reg] = value 141 | if hi_bit8: 142 | assert(lo_bit8 != None) 143 | mod_values = f_reg_set8(values, hi_bit8, value>>8) 144 | mod_values = f_reg_set8(mod_values, lo_bit8, value&0xFF) 145 | return mod_values 146 | 147 | def f_reg_set32(values, reg, value, bit32, lo_bit16, hi_bit8, lo_bit8): 148 | if reg == bit32: 149 | value16 = value & 0xFFFF 150 | mod_values = f_reg_set16(values, lo_bit16, value16, hi_bit8, lo_bit8) 151 | mod_values[bit32] = value 152 | 153 | elif reg == lo_bit16: 154 | mod_values = f_reg_set16(values, reg, value, hi_bit8, lo_bit8) 155 | mod_values = f_reg_upd32(mod_values, bit32, value) 156 | 157 | elif reg in [lo_bit8, hi_bit8]: 158 | mod_values = f_reg_set8(values, reg, value) 159 | hi8v = try_get_from_dict(mod_values, hi_bit8) 160 | lo8v = try_get_from_dict(mod_values, lo_bit8) 161 | if hi8v != None and lo8v != None: 162 | lo16v = (hi8v<<8)|lo8v 163 | mod_values[lo_bit16] = lo16v 164 | mod_values = f_reg_upd32(mod_values, bit32, lo16v) 165 | else: 166 | print "bad reg to set:", reg 167 | assert(False) 168 | 169 | return mod_values 170 | 171 | 172 | def is_special_case(dis): 173 | special_hints = ["pushf", "popf", "lods", "movs", "stos", "ret", "mul", "div"] 174 | for hint in special_hints: 175 | if dis.find(hint)>=0: 176 | return True 177 | return False 178 | 179 | def special_read_mod_regs(dis): 180 | esi = set(ESI_REGS) 181 | edi = set(EDI_REGS) 182 | esi_edi = esi|edi 183 | eax = set(EAX_REGS) 184 | edx = set(EDX_REGS) 185 | esp = set(ESP_REGS) 186 | rep_reg = set() 187 | if dis.find("rep")>=0: 188 | rep_reg = set(ECX_REGS) 189 | 190 | if dis.find("movs")>=0: 191 | (read, mod) = (esi_edi, esi_edi) 192 | elif dis.find("stos")>=0: 193 | (read, mod) = (eax|edi, edi) 194 | elif dis.find("lods")>=0: 195 | (read, mod) = (esi, eax|esi) 196 | elif dis == "popa": 197 | (read, mod) = (esp,REG_SET) 198 | elif dis == "pusha": 199 | (read, mod) = (REG_SET,esp) 200 | elif dis.find("pushf")>=0 or dis.find("popf")>=0: 201 | (read, mod) = (esp, esp) 202 | elif dis.find("ret")>=0: 203 | (read, mod) = (esp, esp) 204 | elif dis.find("mul")>=0 or dis.find("div")>=0: 205 | (read, mod) = (eax|edx, eax|edx) 206 | else: 207 | print dis 208 | assert(False) 209 | 210 | return (rep_reg|read, rep_reg|mod) 211 | 212 | def bwd_variants(mnem): 213 | variants = [] 214 | for bits, postfix in zip([8,16,32],["b","w","d"]): 215 | variants.append((mnem+postfix, bits)) 216 | return variants 217 | 218 | #FIXME(?): movzx, etc 219 | def guess_bits(dis, addr, op1, op2): 220 | o = dis 221 | hints = [("small", 16), ("dword", 32), ("word", 16), ("byte", 8)] 222 | for hint,bits in hints: 223 | if o.find(hint)>=0: 224 | return bits 225 | 226 | reg_classes = [(REG_8BIT, 8), (REG_16BIT, 16), (REG_32BIT, 32)] 227 | ops = filter(lambda o: o != None, [op1, op2]) 228 | for op in ops: 229 | if op.type == O_REG: 230 | reg = op.reg 231 | for reg_class, bits in reg_classes: 232 | if reg in reg_class: 233 | return bits 234 | 235 | mnem = idc.GetMnem(addr) 236 | if mnem in ["pushf", "popf"]: 237 | return 8 238 | if mnem in ["push", "pop", "popa", "pusha", "std", "retn"]: 239 | return 32 #not important anyway 240 | 241 | 242 | dis = idc.GetDisasm(addr) 243 | hints = reduce(lambda l,mnem: l+bwd_variants(mnem), ["lods", "stos", "movs"], []) 244 | 245 | if is_jxx(addr): 246 | return 32 247 | 248 | for hint, bits in hints: 249 | if dis.find(hint)>=0: 250 | return bits 251 | 252 | print "can't guess bits of instruction @ %08x: %s"%(addr, mnem) 253 | assert(False) 254 | 255 | ################################################## 256 | # basic block for wrapped code 257 | ################################################## 258 | class DBB(BB_): 259 | def __init__(self): 260 | BB_.__init__(self) 261 | 262 | def dump(self): 263 | l = [] 264 | for inst in self.body: 265 | l.append(inst.dump()) 266 | 267 | o = "DBB(%08x)\n"%self.get_addr() 268 | o += "\n".join(l) 269 | o += "\n" 270 | o += "#"*10 271 | o += "\n" 272 | return o 273 | 274 | def get_org_disasm(self): 275 | disasm = [] 276 | for bb in self.body: 277 | disasm.append(bb.get_org_disasm()) 278 | disasm = "\n".join(disasm) 279 | return disasm 280 | 281 | def set_body(self, new_body): 282 | if not self.get_addr(): 283 | self.org_addr = new_body[0].get_addr() 284 | self.body = new_body 285 | 286 | def disasm(self): 287 | di = dfs(self, dbb_f_disasm) 288 | return di 289 | 290 | #remove conditional jump at the end and one instruction before it 291 | #return the result as new DBB 292 | def trim_jxx(self): 293 | assert(len(self.body) >= 2) 294 | 295 | i = self.body[-1] 296 | assert(i.is_jxx()) 297 | 298 | dbb = DBB() 299 | new_body = self.body[:-2] 300 | dbb.set_body(new_body) 301 | 302 | return dbb 303 | 304 | def untrim_jxx(self, tdbb): 305 | new_body = tdbb.body + self.body[-2:] 306 | tdbb.set_body(new_body) 307 | return tdbb 308 | 309 | def true_branch(self): 310 | if self.child1 and self.child2: 311 | return self.child2 312 | elif self.child1 and not self.child2: 313 | return self.child1 314 | else: 315 | assert(False) 316 | 317 | def false_branch(self): 318 | if self.child1 and self.child2: 319 | return self.child1 320 | else: 321 | assert(False) 322 | 323 | def dbb_f_disasm(acc, node, children): 324 | if acc == None: 325 | acc = "" 326 | acc += node.dump() 327 | return acc 328 | 329 | ################################################## 330 | # main instruction wrapper 331 | ################################################## 332 | class Inst(): 333 | 334 | def make_disasm(self, mnem, op1, op2, bits=0): 335 | t1 = t2 = comma = "" 336 | if op1: t1 = op1.text_org 337 | if op2: 338 | t2 = op2.text_org 339 | comma = "," 340 | #we don't want to have: mov eax, dword ptr [xyz] (dword ptr is redundant) 341 | if mnem == "mov" and (op2.type == O_MEM or (op1.type == O_MEM and op2.type == O_REG)): 342 | t1 = self.clean_disasm(t1) 343 | t2 = self.clean_disasm(t2) 344 | elif bits != 0: 345 | if mnem == "lods": 346 | assert(bits in [8,16,32]) 347 | l = ["b","w","LOL","d"] 348 | mnem = "lods" + l[(bits/8)-1] 349 | elif ((op1 and op2 and op1.type == O_MEM and op2.type == O_IMM) or 350 | (op1 and not op2 and op1.type == O_MEM)): 351 | ptr = self.bits_text(bits) 352 | t1 = self.clean_disasm(t1) 353 | t1 = "%s %s"%(ptr, t1) 354 | 355 | dis = "%s %s%s %s"%(mnem, t1, comma, t2) 356 | dis = dis.strip() 357 | return dis 358 | 359 | def get_org_disasm(self): 360 | disasm = self.make_disasm(self.mnem, self.op1, self.op2, bits=self.bits) 361 | return disasm 362 | 363 | def update_disasm(self): 364 | self.dis = self.make_disasm(self.mnem, self.op1, self.op2, bits=self.bits) 365 | self.clean_dis = self.clean_disasm(self.dis) 366 | 367 | def clean_disasm(self, dis): 368 | dis = re.sub("(dword ptr |word ptr |byte ptr |small )", "", dis) 369 | dis = re.sub("\s+", " ", dis) 370 | return dis 371 | 372 | def get_clean_dis(self): 373 | #return self.clean_disasm(self.dis) 374 | return self.clean_dis 375 | 376 | # True in Branch instrunctions (JMP/Jcc) 377 | def is_jxx(self): 378 | return False 379 | 380 | # True only in Jxx() 381 | def is_cond_jmp(self): 382 | return False 383 | 384 | def __init__(self, addr, mnem, op1, op2, bits=0): 385 | self.read_regs = set() 386 | self.modified_regs = set() 387 | self.modified_flags = set() 388 | self.op1 = None 389 | self.op2 = None 390 | 391 | self.mnem = mnem 392 | self.op1 = op1 393 | self.op2 = op2 394 | self.addr = addr 395 | 396 | dis = idc.GetDisasm(addr) 397 | if dis == "": 398 | dis = self.make_disasm(mnem, op1, op2) 399 | self.dis = dis 400 | 401 | if bits == 0: 402 | self.bits = guess_bits(dis, addr, op1, op2) 403 | else: 404 | self.bits = bits 405 | 406 | #guessbits uses hints for determining size, so clean here 407 | self.dis = self.clean_disasm(dis) 408 | self.clean_dis = self.dis 409 | 410 | #override this behavior in subclasses!!! 411 | 412 | if op1 and op1.type != O_MEM: 413 | self.modified_regs = op1.regs 414 | 415 | if op1 and op2: 416 | self.read_regs = op2.regs.union(op1.regs) 417 | 418 | elif op1 and not op2: 419 | self.read_regs = op1.regs 420 | 421 | elif not op1 and op2: 422 | # GetOpnd("imul cx", 0) -> None 423 | # GetOpnd("imul cx", 1) -> "cx" 424 | # just switch args.. 425 | if mnem in ["imul", "mul", "idiv", "div"]: 426 | self.op1 = op2 427 | self.op2 = None 428 | self.read_regs = op2.regs 429 | else: 430 | print "op2 but no op1:", mnem, op2.text 431 | assert(False) 432 | 433 | else: 434 | #print "no arg. instr:", mnem 435 | pass 436 | 437 | dis = self.dis 438 | if is_special_case(dis): 439 | (read, mod) = special_read_mod_regs(dis) 440 | self.read_regs |= read 441 | self.modified_regs |= mod 442 | 443 | def update_ops(self, new_op1, new_op2, bits=None): 444 | if bits == None: 445 | bits = self.bits 446 | self.__init__(FAKE_INSTR_ADDR, self.mnem, new_op1, new_op2, bits) 447 | 448 | def update_op2(self, new_op2): 449 | assert(new_op2.type == O_IMM) 450 | assert(self.op2.type == O_REG) 451 | 452 | dis = self.make_disasm(self.mnem, self.op1, new_op2) 453 | self.dis = dis 454 | self.clean_dis = self.clean_disasm(self.dis) 455 | self.read_regs = self.read_regs - self.op2.regs 456 | self.modified_regs = self.modified_regs - self.op2.regs 457 | self.op2 = new_op2 458 | self.read_regs |= new_op2.regs 459 | 460 | def get_addr(self): return self.addr 461 | 462 | def bits_text(self, bits): 463 | if bits == 8: 464 | o = "byte ptr" 465 | elif bits == 16: 466 | o = "word ptr" 467 | elif bits == 32: 468 | o = "dword ptr" 469 | else: 470 | print "bits:", bits 471 | assert(False) 472 | return o 473 | 474 | def dump(self): 475 | if False: 476 | t1 = t2 = "" 477 | if self.op1: t1 = self.op1.text 478 | if self.op2: t2 = self.op2.text 479 | 480 | if ((self.op1 and not self.op2 and self.op1.type == O_MEM) or 481 | (self.op1 and self.op2 and self.op1.type == O_MEM and self.op2.type == O_IMM)): 482 | ptr = self.bits_text() 483 | t1 = "%s %s"%(ptr, t1) 484 | 485 | o = "%s %s %s"%(self.mnem, t1, t2) 486 | 487 | else: 488 | o = self.get_clean_dis() 489 | 490 | return o 491 | 492 | def dump_verbose(self): 493 | o = self.dump() 494 | o += " \t# bits: %d "%self.bits 495 | if self.op1: 496 | o += "OP1(%s)"%self.op1.dump() 497 | if self.op2: 498 | o += "OP2(%s)"%self.op2.dump() 499 | 500 | read = self.read_regs 501 | mod = self.modified_regs 502 | o += " read_regs: %s, mod_regs: %s"%(str(read), str(mod)) 503 | return o 504 | 505 | #needs to be overridden in subclasses 506 | #always fail to evaluate and set modified regs to unk. state 507 | #set modified flags to unknown state 508 | def eval(self, ctx): 509 | ctx.unset_regs(self.modified_regs) 510 | ctx.unset_flags(self.modified_flags) 511 | return False 512 | 513 | def can_substitue(self, ctx): 514 | return False 515 | 516 | ################################################## 517 | # operand 518 | ################################################## 519 | class Opnd: 520 | #"parse" a text representation 521 | #easier than reading IDA's dox :p 522 | def __init__(self, op): 523 | 524 | if type(op) in [int, long]: 525 | #op = str(hex(op)) 526 | op = self.nice_hex(op) 527 | op = op.replace("0x", "") 528 | op = op.replace("L", "") 529 | 530 | self.type = None 531 | self.regs = set() 532 | self.imm = None 533 | self.text_org = op 534 | 535 | op = re.sub("(dword ptr |word ptr |byte ptr |small )", "", op) 536 | self.text = op 537 | 538 | #push small 0000h 539 | op = op.replace("small ", "") 540 | 541 | match = imm_re.match(op) 542 | 543 | if op.find("]")>=0: 544 | self.type = O_MEM 545 | self.regs = self.extract_regs(op) 546 | mem_type, match_obj = self.get_mem_type(op) 547 | if mem_type == O_MEM_REG_PLUS_INDEX: 548 | reg = match_obj.group(1) 549 | assert(reg in REG_SET) 550 | #sign = match_obj.group(2) 551 | index = match_obj.group(3) 552 | index = int(index, 16) 553 | self.mem_reg = reg 554 | self.mem_idx = index 555 | self.mem_type = O_MEM_REG_PLUS_INDEX 556 | self.set_mem_idx(index) 557 | else: 558 | self.mem_type = O_MEM_COMPLEX 559 | 560 | elif op in REG_SET: 561 | self.type = O_REG 562 | self.regs = set([op]) 563 | self.reg = op 564 | elif match != None: 565 | self.type = O_IMM 566 | num = match.group(1) 567 | imm = int(num, 16) 568 | self.imm = imm 569 | self.text = self.nice_hex(imm) 570 | else: 571 | print "strange op:", op 572 | #assert(False) 573 | 574 | def nice_hex(self, v): 575 | o = "%x"%v 576 | if o[0] in "abcdef": 577 | o = "0%sh"%o 578 | elif v>9: 579 | o = "%sh"%o 580 | return o 581 | 582 | def update_mem_idx(self, value): 583 | assert(self.mem_type == O_MEM_REG_PLUS_INDEX) 584 | value = value + self.mem_idx 585 | self.set_mem_idx(value) 586 | 587 | def set_mem_idx(self, value): 588 | assert(self.mem_type == O_MEM_REG_PLUS_INDEX) 589 | self.mem_idx = value 590 | v_abs = abs(value) 591 | v = self.nice_hex(v_abs) 592 | if value>0: 593 | sign = "+" 594 | elif value == 0: 595 | sign = "" 596 | v = "" 597 | else: 598 | sign = "-" 599 | old_text = self.text 600 | self.text = "[%s%s%s]"%(self.mem_reg, sign, v) 601 | self.text_org = self.text_org.replace(old_text, self.text) 602 | 603 | def get_mem_type(self, op): 604 | hits = re.findall(r".*?\[[a-z]+\]", op) 605 | if len(hits)>0: 606 | op = op.replace("]", "+0]") 607 | base_idx_re = ".*?\[([a-z]+)(\+|\-)([0-9a-fA-F]+)h?\]" 608 | base_idx_re = re.compile(base_idx_re) 609 | m = re.match(base_idx_re, op) 610 | if m != None: 611 | return (O_MEM_REG_PLUS_INDEX, m) 612 | 613 | return (None, None) 614 | 615 | def extract_regs(self, op): 616 | parts = re.split("\W+", op) 617 | regs = filter(lambda part: part in REG_SET, parts) 618 | return set(regs) 619 | 620 | def dump(self): 621 | o = "type: %d, regs: %s"%(self.type, str(self.regs)) 622 | if self.imm: 623 | o += " imm: %08x"%self.imm 624 | return o 625 | 626 | def get_mem_addr(self, ctx): 627 | assert(self.type == O_MEM) 628 | 629 | if self.mem_type != O_MEM_REG_PLUS_INDEX: 630 | return None 631 | 632 | reg = self.mem_reg 633 | idx = self.mem_idx 634 | 635 | if not ctx.is_known(reg): 636 | return None 637 | 638 | reg_val = ctx.get_reg(reg) 639 | return reg_val+idx 640 | 641 | def unpack_type(self, ctx): 642 | my_type = self.type 643 | if my_type == O_MEM: 644 | unp = self.get_mem_addr(ctx) 645 | elif my_type == O_REG: 646 | unp = self.reg 647 | elif my_type == O_IMM: 648 | unp = self.imm 649 | else: 650 | assert(False) 651 | 652 | return unp 653 | 654 | ################################################## 655 | # context (registers/flags state and values) 656 | ################################################## 657 | class Ctx(): 658 | def __init__(self): 659 | self.known_regs = set() 660 | self.unknown_regs = REG_SET 661 | self.values = dict() 662 | self.mem = dict() 663 | self.flags = dict() 664 | 665 | self.unset_flags(FLAGS) 666 | 667 | def is_known_flag(self, flag): 668 | assert(flag in FLAGS) 669 | return self.flags[flag] != None 670 | 671 | def get_flag(self, flag): 672 | assert(self.is_known_flag(flag)) 673 | return self.flags[flag] 674 | 675 | def set_flag(self, flag, value): 676 | assert(value in [True, False]) 677 | self.flags[flag] = value 678 | 679 | def mod_flag(self, flag, value): 680 | #PyFlags returns None in 2 cases: 681 | # - when flag in unaffected 682 | # - when instruction is not supported 683 | # we chose to always interpret it as option 1 684 | if value == None: 685 | pass 686 | elif value == 1: 687 | self.set_flag(flag, True) 688 | elif value == 0: 689 | self.set_flag(flag, False) 690 | else: 691 | print "flag: %s, value: %s"%(flag, str(value)) 692 | assert(False) 693 | 694 | def unset_flag(self, flag): 695 | self.flags[flag] = None 696 | 697 | def unset_flags(self, flags): 698 | for flag in flags: 699 | self.unset_flag(flag) 700 | 701 | def is_known_mem(self, addr): 702 | try: 703 | self.mem[addr] 704 | return True 705 | except: 706 | return False 707 | 708 | def set_mem(self, addr, value): 709 | assert(value != None) 710 | self.mem[addr] = value 711 | 712 | def get_mem(self, addr): 713 | assert(self.is_known_mem(addr)) 714 | return self.mem[addr] 715 | 716 | def unset_mem(self, addr): 717 | try: 718 | del self.mem[addr] 719 | except: 720 | pass 721 | 722 | def unset_by_type(self, op_type, op): 723 | if op_type == O_REG: 724 | self.unset_reg(op) 725 | elif op_type == O_MEM: 726 | self.unset_mem(op) 727 | elif op_type == O_IMM: 728 | pass 729 | else: 730 | assert(False) 731 | 732 | def is_known_by_type(self, op_type, op): 733 | if op_type == O_REG: 734 | return self.is_known(op) 735 | elif op_type == O_MEM: 736 | return self.is_known_mem(op) 737 | elif op_type == O_IMM: 738 | return True 739 | else: 740 | assert(False) 741 | 742 | def set_by_type(self, op_type, op, value): 743 | if op_type == O_REG: 744 | self.set_reg(op, value) 745 | elif op_type == O_MEM: 746 | self.set_mem(op, value) 747 | elif op_type == O_IMM: 748 | pass 749 | else: 750 | assert(False) 751 | 752 | def get_by_type(self, op_type, op): 753 | if op_type == O_REG: 754 | return self.get_reg(op) 755 | elif op_type == O_MEM: 756 | return self.get_mem(op) 757 | elif op_type == O_IMM: 758 | return op 759 | else: 760 | assert(False) 761 | 762 | def is_known(self, reg): 763 | return reg in self.known_regs 764 | 765 | def get_reg(self, reg): 766 | assert(self.is_known(reg)) 767 | return self.values[reg] 768 | 769 | def set_reg(self, reg, val): 770 | assert(type(val) in [int, long]) 771 | 772 | self.values = set_reg_aux(self.values, reg, val) 773 | self.known_regs |= set(self.values.keys()) 774 | self.unknown_regs = REG_SET - self.known_regs 775 | 776 | #invariants 777 | assert(self.known_regs | self.unknown_regs == REG_SET) 778 | assert(self.known_regs & self.unknown_regs == set()) 779 | 780 | def unset_regs(self, regs): 781 | for reg in regs: 782 | self.unset_reg(reg) 783 | 784 | def unset_reg(self, reg): 785 | assert(reg in REG_SET) 786 | unset_affected = REG_UNSET_AFFECTED[reg] 787 | affected_regs = unset_affected[reg] 788 | new_known = self.known_regs - affected_regs 789 | if new_known == self.known_regs: 790 | return 791 | self.known_regs = new_known 792 | self.unknown_regs = self.unknown_regs | affected_regs 793 | for reg in affected_regs: 794 | try: 795 | del(self.values[reg]) 796 | except: 797 | pass 798 | #invariants 799 | #assert(self.known_regs | self.unknown_regs == REG_SET) 800 | #assert(self.known_regs & self.unknown_regs == set()) 801 | #assert(self.known_regs == set(self.values.keys())) 802 | 803 | def update_flags(self, mnem, val1, val2, res, bits): 804 | size = bits/8 805 | if mnem in ["and", "or", "xor", "not", "test"]: 806 | mnem = "logic" 807 | mnem = mnem.upper() 808 | flags = PyFlags(mnem, val1, val2, res, size) 809 | self.mod_flag(AF, flags.get_AF()) 810 | self.mod_flag(CF, flags.get_CF()) 811 | self.mod_flag(OF, flags.get_OF()) 812 | self.mod_flag(PF, flags.get_PF()) 813 | self.mod_flag(SF, flags.get_SF()) 814 | self.mod_flag(ZF, flags.get_ZF()) 815 | 816 | def dump(self): 817 | o = "regs: %s\n" % str(self.known_regs) 818 | o += "reg values: %s\n" % str(self.values) 819 | o += "mem: %s\n" % str(self.mem) 820 | o += "flags: %s\n" % str(self.flags) 821 | return o 822 | 823 | ################################################## 824 | # common things for instructions used in handlers 825 | ################################################## 826 | class Comp(Inst): 827 | def __init__(self, addr, mnem, op1, op2, bits=0): 828 | Inst.__init__(self, addr, mnem, op1, op2, bits=bits) 829 | self.modified_flags = FLAGS 830 | 831 | def eval(self, ctx): 832 | type1 = self.op1.type 833 | N = 1<>v2 974 | 975 | # test is used only before pushf, so we can ignore how it affects flags 976 | class Test(Inst): 977 | 978 | def __init__(self, addr, mnem, op1, op2): 979 | Inst.__init__(self, addr, mnem, op1, op2) 980 | self.modified_regs = set() 981 | 982 | #no flags modified 983 | class Xchg(Inst): 984 | def __init__(self, addr, mnem, op1, op2): 985 | Inst.__init__(self, addr, mnem, op1, op2) 986 | if op2.type == O_REG: 987 | self.modified_regs = self.modified_regs.union(op2.regs) 988 | 989 | def equivalent_mov(self, ctx): 990 | type1 = self.op1.type 991 | type2 = self.op2.type 992 | 993 | if type1 != O_REG or type2 != O_REG: 994 | assert(False) 995 | 996 | reg1 = self.op1.reg 997 | reg2 = self.op2.reg 998 | assert(ctx.is_known(reg1) and ctx.is_known(reg2)) 999 | v1 = ctx.get_reg(reg1) 1000 | v2 = ctx.get_reg(reg2) 1001 | 1002 | op_reg1 = Opnd(reg1) 1003 | op_reg2 = Opnd(reg2) 1004 | op_v1 = Opnd(v1) 1005 | op_v2 = Opnd(v2) 1006 | 1007 | mov1 = Mov(FAKE_INSTR_ADDR, "mov", op_reg1, op_v1, self.bits) 1008 | mov2 = Mov(FAKE_INSTR_ADDR, "mov", op_reg2, op_v2, self.bits) 1009 | 1010 | return [mov1, mov2] 1011 | 1012 | def eval(self, ctx): 1013 | type1 = self.op1.type 1014 | type2 = self.op2.type 1015 | 1016 | rm = (type1 == O_REG and type2 == O_MEM) 1017 | mr = (type1 == O_MEM and type2 == O_REG) 1018 | mm = (type1 == O_MEM and type2 == O_MEM) 1019 | 1020 | if type1 == O_REG and type2 == O_REG: 1021 | reg1 = self.op1.reg 1022 | reg2 = self.op2.reg 1023 | v1, v2 = None, None 1024 | if ctx.is_known(reg1): 1025 | v1 = ctx.get_reg(reg1) 1026 | if ctx.is_known(reg2): 1027 | v2 = ctx.get_reg(reg2) 1028 | 1029 | v1, v2 = v2, v1 1030 | 1031 | for reg,val in [(reg1,v1),(reg2,v2)]: 1032 | if val != None: 1033 | ctx.set_reg(reg, val) 1034 | else: 1035 | ctx.unset_reg(reg) 1036 | 1037 | if None not in [v1, v2]: 1038 | # can return TWO equivalent movs 1039 | return True 1040 | 1041 | elif rm or mr or mm: 1042 | op1 = self.op1.unpack_type(ctx) 1043 | op2 = self.op2.unpack_type(ctx) 1044 | 1045 | if None in [op1, op2]: 1046 | #print "None" 1047 | #print op1, op2 1048 | return Inst.eval(self, ctx) 1049 | 1050 | t1 = self.op1.type 1051 | t2 = self.op2.type 1052 | 1053 | known1 = ctx.is_known_by_type(t1, op1) 1054 | known2 = ctx.is_known_by_type(t2, op2) 1055 | 1056 | v1, v2 = None, None 1057 | if known1: 1058 | v1 = ctx.get_by_type(t1, op1) 1059 | if known2: 1060 | v2 = ctx.get_by_type(t2, op2) 1061 | 1062 | if known1: 1063 | ctx.set_by_type(t2, op2, v1) 1064 | else: 1065 | ctx.unset_by_type(t2, op2) 1066 | 1067 | if known2: 1068 | ctx.set_by_type(t1, op1, v2) 1069 | else: 1070 | ctx.unset_by_type(t1, op1) 1071 | 1072 | print "xchg info:" 1073 | print t1, t2 1074 | print known1, known2 1075 | print v1, v2 1076 | 1077 | #we don't want to be asked about "equivalent mov" 1078 | return False 1079 | 1080 | #no flags modified 1081 | class Mov(Inst): 1082 | def __init__(self, addr, mnem, op1, op2, bits = 0): 1083 | Inst.__init__(self, addr, mnem, op1, op2, bits) 1084 | if op1.type != O_MEM: 1085 | self.read_regs = self.read_regs - op1.regs 1086 | 1087 | def eval(self, ctx): 1088 | type1 = self.op1.type 1089 | type2 = self.op2.type 1090 | 1091 | if type1 == O_REG and type2 == O_IMM: 1092 | reg = self.op1.reg 1093 | imm = self.op2.imm 1094 | ctx.set_reg(reg, imm) 1095 | return True 1096 | 1097 | elif type1 == type2 == O_REG: 1098 | reg1 = self.op1.reg 1099 | reg2 = self.op2.reg 1100 | if ctx.is_known(reg2): 1101 | val2 = ctx.get_reg(reg2) 1102 | ctx.set_reg(reg1, val2) 1103 | return True 1104 | 1105 | elif O_MEM in [type1, type2]: 1106 | src_type = self.op2.type 1107 | dst_type = self.op1.type 1108 | 1109 | src_val = None 1110 | if src_type == O_IMM: 1111 | src_val = self.op2.imm 1112 | else: 1113 | op = self.op2.unpack_type(ctx) 1114 | if ctx.is_known_by_type(src_type, op): 1115 | src_val = ctx.get_by_type(src_type, op) 1116 | 1117 | #addr or reg 1118 | dst = self.op1.unpack_type(ctx) 1119 | 1120 | if src_val == None: 1121 | ctx.unset_by_type(dst_type, dst) 1122 | else: 1123 | if dst != None: 1124 | ctx.set_by_type(dst_type, dst, src_val) 1125 | 1126 | if src_type in [O_IMM, O_REG] and src_val != None: 1127 | return True 1128 | 1129 | return Inst.eval(self, ctx) 1130 | 1131 | def equivalent_mov(self, ctx): 1132 | type2 = self.op2.type 1133 | if type2 == O_REG: 1134 | src_reg = self.op2.reg 1135 | imm = ctx.get_reg(src_reg) 1136 | new_op2 = Opnd(imm) 1137 | new_mov = Mov(FAKE_INSTR_ADDR, "mov", self.op1, new_op2, self.bits) 1138 | elif type2 == O_IMM: 1139 | new_mov = self 1140 | else: 1141 | assert(False) 1142 | 1143 | return new_mov 1144 | 1145 | #no flags modified 1146 | class Push(Inst): 1147 | def __init__(self, addr, mnem, op1, op2, bits=0): 1148 | Inst.__init__(self, addr, mnem, op1, op2, bits) 1149 | self.modified_regs = ESP_REGS 1150 | self.read_regs = ESP_REGS|op1.regs 1151 | 1152 | def eval(self, ctx): 1153 | 1154 | type1 = self.op1.type 1155 | op1 = self.op1.unpack_type(ctx) 1156 | 1157 | if not ctx.is_known(ESP): 1158 | ctx.unset_by_type(type1, op1) 1159 | else: 1160 | esp = ctx.get_reg(ESP) 1161 | #FIXME: 16bit push 1162 | 1163 | val = None 1164 | if ctx.is_known_by_type(type1, op1): 1165 | val = ctx.get_by_type(type1, op1) 1166 | 1167 | esp = esp-4 1168 | ctx.set_reg(ESP, esp) 1169 | 1170 | if val: 1171 | ctx.set_mem(esp, val) 1172 | 1173 | #we never want this instruction to be replaced by a mov 1174 | return False 1175 | 1176 | #no flags modified 1177 | class Pop(Inst): 1178 | def __init__(self, addr, mnem, op1, op2): 1179 | Inst.__init__(self, addr, mnem, op1, op2) 1180 | self.modified_regs = ESP_REGS|op1.regs 1181 | self.read_regs = ESP_REGS 1182 | 1183 | def eval(self, ctx): 1184 | 1185 | type1 = self.op1.type 1186 | if type1 == O_REG: 1187 | o1_reg = self.op1.reg 1188 | op1 = o1_reg 1189 | 1190 | elif type1 == O_MEM: 1191 | o1_addr = self.op1.get_mem_addr(ctx) 1192 | op1 = o1_addr 1193 | else: 1194 | assert(False) 1195 | 1196 | if not ctx.is_known(ESP): 1197 | ctx.unset_by_type(type1, op1) 1198 | else: 1199 | esp = ctx.get_reg(ESP) 1200 | if not ctx.is_known_mem(esp): 1201 | ctx.unset_by_type(type1, op1) 1202 | elif type1 == O_REG or (type1 == O_MEM and op1 != None): 1203 | stack_val = ctx.get_mem(esp) 1204 | ctx.set_by_type(type1, op1, stack_val) 1205 | #FIXME: pop 16bit 1206 | if not (type1 == O_REG and op1 == ESP): 1207 | ctx.set_reg(ESP, esp+4) 1208 | 1209 | #we never want this instruction to be replaced by a mov 1210 | return False 1211 | 1212 | class Pushf(Inst): 1213 | def __init__(self, addr, mnem, op1, op2): 1214 | Inst.__init__(self, addr, mnem, op1, op2) 1215 | 1216 | def eval(self, ctx): 1217 | if ctx.is_known(ESP): 1218 | esp = ctx.get_reg(ESP) 1219 | esp = esp-4 1220 | ctx.set_reg(ESP, esp) 1221 | #we never want this instruction to be replaced by a mov 1222 | return False 1223 | 1224 | class Popf(Inst): 1225 | def __init__(self, addr, mnem, op1, op2): 1226 | Inst.__init__(self, addr, mnem, op1, op2) 1227 | 1228 | def eval(self, ctx): 1229 | if ctx.is_known(ESP): 1230 | esp = ctx.get_reg(ESP) 1231 | esp = esp+4 1232 | ctx.set_reg(ESP, esp) 1233 | #we never want this instruction to be replaced by a mov 1234 | return False 1235 | 1236 | ################################################## 1237 | # jump classes 1238 | ################################################## 1239 | class Branch(Inst): 1240 | def __init__(self, addr, mnem, op1): 1241 | assert(op1.type == O_IMM) 1242 | Inst.__init__(self, addr, mnem, op1, None) 1243 | self.target = op1.imm 1244 | 1245 | def is_jxx(self): 1246 | return True 1247 | 1248 | class Jmp(Branch): 1249 | def __init__(self, addr, mnem, op1): 1250 | Branch.__init__(self, addr, mnem, op1) 1251 | 1252 | def can_eval(self, ctx): 1253 | return True 1254 | 1255 | def eval_jxx(self, ctx): 1256 | return True 1257 | 1258 | #these should be lambdas, but lambdas can't be pickled :( 1259 | def jo_func ((of,)): of==True 1260 | def jno_func ((of,)): return of==False 1261 | def js_func ((sf,)): return sf==True 1262 | def jns_func ((sf,)): return sf==False 1263 | def je_func ((zf,)): return zf==True 1264 | def jne_func ((zf,)): return zf==False 1265 | def jb_func ((cf,)): return cf==True 1266 | def jnb_func ((cf,)): return cf==False 1267 | def jbe_func ((cf,zf)): return cf==True or zf==True 1268 | def jnbe_func ((cf,zf)): return cf==False and zf==False 1269 | def jl_func ((sf,of)): return sf != of 1270 | def jnl_func ((sf,of)): return sf == of 1271 | def jle_func ((zf,sf,of)): return zf == True or (sf != of) 1272 | def jnle_func ((zf,sf,of)): return zf == False and (sf == of) 1273 | def jp_func ((pf,)): return pf==True 1274 | def jnp_func ((pf,)): return pf==False 1275 | 1276 | class Jxx(Branch): 1277 | def __init__(self, addr, mnem, op1): 1278 | Branch.__init__(self, addr, mnem, op1) 1279 | 1280 | self.conds = [] 1281 | self.conds += [(["jo"], [OF], jo_func)] 1282 | self.conds += [(["jno"], [OF], jno_func)] 1283 | self.conds += [(["js"], [SF], js_func)] 1284 | self.conds += [(["jns"], [SF], jns_func)] 1285 | self.conds += [(["je", "jz"], [ZF], je_func)] 1286 | self.conds += [(["jne", "jnz"], [ZF], jne_func)] 1287 | self.conds += [(["jb", "jnae", "jc"], [CF], jb_func)] 1288 | self.conds += [(["jnb", "jae", "jnc"], [CF], jnb_func)] 1289 | self.conds += [(["jbe", "jna"], [CF, ZF], jbe_func)] 1290 | self.conds += [(["jnbe", "ja"], [CF, ZF], jnbe_func)] 1291 | self.conds += [(["jl", "jnge"], [SF, OF], jl_func)] 1292 | self.conds += [(["jnl", "jge"], [SF, OF], jnl_func)] 1293 | self.conds += [(["jle", "jng"], [ZF, SF, OF], jle_func)] 1294 | self.conds += [(["jnle", "jg"], [ZF, SF, OF], jnle_func)] 1295 | self.conds += [(["jp", "jpe"], [PF], jp_func)] 1296 | self.conds += [(["jnp", "jpo"], [PF], jnp_func)] 1297 | 1298 | self.flag_list = None 1299 | self.lambda_cond = None 1300 | 1301 | mnem = self.mnem.lower() 1302 | for cond in self.conds: 1303 | mnem_list, flag_list, lambda_cond = cond 1304 | if mnem in mnem_list: 1305 | self.flag_list = flag_list 1306 | self.lambda_cond = lambda_cond 1307 | break 1308 | 1309 | assert(self.lambda_cond != None) 1310 | assert(self.flag_list != None) 1311 | 1312 | def get_flags(self, flag_list, ctx): 1313 | o = [] 1314 | for flag in flag_list: 1315 | if ctx.is_known_flag(flag): 1316 | flag = ctx.get_flag(flag) 1317 | else: 1318 | flag = None 1319 | o.append(flag) 1320 | return o 1321 | 1322 | def can_eval(self, ctx): 1323 | flags = self.get_flags(self.flag_list, ctx) 1324 | if None in flags: 1325 | return False 1326 | return True 1327 | 1328 | def eval_jxx(self, ctx): 1329 | # callers need to check if they can eval 1330 | if not self.can_eval(ctx): 1331 | assert(False) 1332 | 1333 | flags = self.get_flags(self.flag_list, ctx) 1334 | flags = tuple(flags) 1335 | taken = self.lambda_cond(flags) 1336 | return taken 1337 | 1338 | def is_cond_jmp(self): 1339 | return True 1340 | -------------------------------------------------------------------------------- /pickler.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os 3 | import idc 4 | import sys 5 | 6 | class Pickler: 7 | def __init__(self): 8 | self.pickle_fn = self.get_pickle_fn() 9 | 10 | def get_pickle_fn(self): 11 | exe_fn = idc.GetInputFile() 12 | md5 = idc.GetInputMD5() 13 | fn = "%s.%s.pickle"%(exe_fn, md5) 14 | return fn 15 | 16 | def can_load_state(self): 17 | return os.path.exists(self.pickle_fn) 18 | 19 | def save_state(self, state): 20 | f = open(self.pickle_fn, "w") 21 | try: 22 | pickle.dump(state, f) 23 | except: 24 | f.close() 25 | os.remove(self.pickle_fn) 26 | raise 27 | 28 | f.close() 29 | 30 | def load_state(self): 31 | f = open(self.pickle_fn, "r") 32 | state = pickle.load(f) 33 | f.close() 34 | return state 35 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | DeCV 1.0b 2 | --------- 3 | 4 | - What is it 5 | - Usage 6 | - Possible problems 7 | 8 | About 9 | ----- 10 | DeCV is a decompiler for files protected with Code Virtualizer v1.3.8.0 by 11 | Oreans Technologies (www.oreans.com). 12 | 13 | It's able to devirtualize macro-protected code back to a stack language used 14 | by CV. If anyone is interested enough to write a CVL -> x86 converter, take 15 | a look at recover_x86.py -- it it's not hard to extend this code to handle 16 | more opcodes, but it's quite a bit of work. 17 | 18 | Usage 19 | ----- 20 | DeCV was tested on IDA 6.2.x with IDAPython. 21 | 22 | To use, open the file you want to deprotect and load decv.py script and wait. 23 | DeCV will automatically perform all tasks. 24 | 25 | Possible problems 26 | ----------------- 27 | DeCV relies on IDA to correctly disassemble code. If you encounter problems 28 | during the handler parsing (basic block creation), manifested in errors like: 29 | - outside handler: *address* 30 | - Problem with getting mnemonic @ *address* 31 | they are most likely caused by incorrect disasm generated by IDA. 32 | 33 | To fix, go to the address you see in the error message. If you see garbage 34 | instructions or data mixed with code (DB xxh), undefine whole block by 35 | pressing 'u', and then directly convert to code, by pressing 'c'. Resulting 36 | code should be cleaner and should not have garbage instructions, or DB xxh 37 | stuff in it. 38 | 39 | p_k 40 | gdtr.wordpress.com 41 | twitter.com/pa_kt 42 | 43 | -------------------------------------------------------------------------------- /recover_x86.py: -------------------------------------------------------------------------------- 1 | from config import * 2 | import pickle 3 | from vmi_top_common import * 4 | 5 | ID_EFLAGS = 7 6 | REG_EFLAGS = REG_DICT[ID_EFLAGS] 7 | ID_ESP = 7 8 | 9 | #FIXME: autogen these 10 | LOAD_PTR_REG = 0x000 11 | STORE_ADDR = 0x001 12 | STORE_DWORD_ADDR = 0x018 13 | MOVE_ADDR_STACK = 0x14e 14 | LOAD_ADDR = 0x009 15 | LOAD_DWORD = 0x004 16 | LOAD_REG = 0x007 17 | ADD_NO_FLAGS = 0x006 18 | MOVE_STACK_STACK = 0x208 19 | LOAD_DWORD_ADDR = 0x00c 20 | LOAD_WORD = 0x003 21 | STORE_DWORD_REG = 0x01c 22 | INC_DWORD = 0x055 23 | ADD_DWORD = 0x024 24 | XOR_DWORD = 0x03d 25 | ADD_REG_TO_ADDR = 0x211 26 | PUSH_RET_ADDR = 0x15d 27 | UNCOND_JMP = 0x154 28 | GTFO = 0x212 29 | 30 | STACK = "stack" 31 | ADDR = "addr" 32 | 33 | T_INVALID = "t_invalid" 34 | T_REG_PTR = "t_reg_ptr" 35 | T_CONST = "t_const" 36 | T_REG = "t_reg" 37 | 38 | T_BINOP = "t_binop" 39 | 40 | N = 2**32 41 | 42 | XOR = "OP_XOR" 43 | ADD = "OP_ADD" 44 | 45 | class Thing: 46 | def __init__(self, typ, thing): 47 | self.typ = typ 48 | self.thing = thing 49 | 50 | def __repr__(self): 51 | typ = self.typ 52 | thing = self.thing 53 | if typ == T_REG: 54 | return thing 55 | elif typ == T_CONST: 56 | return hex(thing) 57 | elif typ == T_REG_PTR: 58 | return "ptr "+thing 59 | else: 60 | assert False, "bad type: "+typ 61 | 62 | def __str__(self): return self.__repr__() 63 | 64 | class BinOp: 65 | def __init__(self, op, left, right): 66 | self.op = op 67 | self.l = left 68 | self.r = right 69 | 70 | def __repr__(self): 71 | if self.op == XOR: 72 | st = "^" 73 | elif self.op == ADD: 74 | st = "+" 75 | else: 76 | assert False 77 | sl = str(self.l) 78 | sr = str(self.r) 79 | s = "%s %s %s"%(sl, st, sr) 80 | return s 81 | 82 | def t_type(tu): return tu[0] 83 | def t_thing(tu): return tu[1] 84 | def t_size(tu): return tu[2] 85 | 86 | def t_reg_ptr(reg_id): 87 | reg = REG_DICT[reg_id] 88 | return (T_REG_PTR, reg, 4) 89 | 90 | def symb_eval(state, vmi): 91 | def stack_size(stack): 92 | l = map(lambda t: t_size(t), stack) 93 | return sum(l) 94 | 95 | def pop4(stack): 96 | (typ, thing, size) = stack.pop() 97 | if size == 4: 98 | return (typ, thing, size) 99 | elif size == 2: 100 | assert typ == T_CONST 101 | (typ2, thing2, size2) = stack.pop() 102 | if typ2 != typ or size != size2: 103 | s= "mismatch: (%s, %s), (%d, %d)"%(typ, typ2, size, size2) 104 | assert False, s 105 | x = (thing<<16)+thing2 106 | return (typ, x, 4) 107 | else: 108 | assert False, "bad size: "+size 109 | 110 | stack = state[STACK] 111 | addr = state[ADDR] 112 | vid = int(vmi.vid, 16) 113 | 114 | native = None 115 | 116 | if vid == LOAD_PTR_REG: 117 | reg_id = vmi.param 118 | t = t_reg_ptr(reg_id) 119 | stack.append(t) 120 | 121 | elif vid == STORE_ADDR: 122 | addr = pop4(stack) 123 | 124 | elif vid == STORE_DWORD_ADDR: 125 | (addr_typ, addr_thing, _) = addr 126 | if addr_typ == T_REG_PTR and stack == []: 127 | native = "vm_%s <- %s"%(addr_thing, addr_thing) 128 | else: 129 | if addr_typ in [T_REG_PTR]: 130 | dst = "%s" 131 | elif addr_typ in [T_REG, T_BINOP]: 132 | dst = "[%s]" 133 | elif addr_typ == T_CONST: 134 | dst = "[%x]" 135 | else: 136 | assert False 137 | (typ, thing, sz) = stack.pop() 138 | fmt = dst + " <- %s" 139 | native = fmt%(addr_thing, thing) 140 | 141 | elif vid == MOVE_ADDR_STACK: 142 | size = stack_size(stack) 143 | addr = (T_CONST, size, 4) 144 | 145 | elif vid == LOAD_ADDR: 146 | stack.append(addr) 147 | 148 | elif vid == LOAD_DWORD: 149 | assert vmi.param_size == 4 150 | t = (T_CONST, vmi.param, 4) 151 | stack.append(t) 152 | 153 | elif vid == LOAD_WORD: 154 | assert vmi.param_size == 2 155 | t = (T_CONST, vmi.param, 2) 156 | stack.append(t) 157 | 158 | elif vid == LOAD_REG: 159 | assert vmi.param_size == 1 160 | reg = REG_DICT[vmi.param] 161 | t = (T_REG, reg, 4) 162 | stack.append(t) 163 | 164 | elif vid == ADD_NO_FLAGS: 165 | (typ1, x1, s1) = stack.pop() 166 | (typ2, x2, s2) = stack.pop() 167 | assert s1 == s2 168 | if typ1 == typ2 == T_CONST: 169 | t = (T_CONST, (x1+x2)%N, s1) 170 | stack.append(t) 171 | else: 172 | th1 = Thing(typ1, x1) 173 | th2 = Thing(typ2, x2) 174 | th = BinOp(ADD, th1, th2) 175 | t = (T_BINOP, th, s1) 176 | stack.append(t) 177 | 178 | elif vid == ADD_DWORD: 179 | (typ1, x1, s1) = stack.pop() 180 | (typ2, x2, s2) = stack.pop() 181 | assert s1 == s2 182 | if typ1 == typ2 == T_CONST: 183 | assert False 184 | th1 = Thing(typ1, x1) 185 | th2 = Thing(typ2, x2) 186 | th = BinOp(ADD, th1, th2) 187 | t = (T_BINOP, th, s1) 188 | stack.append(t) 189 | t = (T_REG, REG_EFLAGS, 4) 190 | stack.append(t) 191 | 192 | elif vid == ADD_REG_TO_ADDR: 193 | (typ, thing, sz) = addr 194 | 195 | assert vmi.param_size == 1 196 | assert sz == 4 197 | 198 | reg_id = vmi.param 199 | if reg_id == ID_ESP: 200 | reg = REG_ESP 201 | else: 202 | reg = REG_DICT[reg_id] 203 | 204 | th1 = Thing(typ, thing) 205 | th2 = Thing(T_REG, reg) 206 | th = BinOp(ADD, th1, th2) 207 | t = (T_BINOP, th, 4) 208 | addr = t 209 | 210 | #nop 211 | elif vid == MOVE_STACK_STACK: 212 | (typ, x, sz) = stack.pop() 213 | cur_size = stack_size(stack) 214 | assert x == cur_size+4 215 | 216 | elif vid == LOAD_DWORD_ADDR: 217 | (typ, thing, sz) = addr 218 | if typ == T_REG_PTR: 219 | t = (T_REG, thing, sz) 220 | stack.append(t) 221 | else: 222 | assert False 223 | 224 | elif vid == XOR_DWORD: 225 | (typ1, thing1, sz1) = stack.pop() 226 | (typ2, thing2, sz2) = stack.pop() 227 | 228 | assert sz1 == sz2 229 | assert typ1 in [T_REG, T_CONST] 230 | assert typ2 in [T_REG, T_CONST] 231 | 232 | th1 = Thing(typ1, thing1) 233 | th2 = Thing(typ2, thing2) 234 | tt = BinOp(XOR, th1, th2) 235 | t = (T_BINOP, tt, sz1) 236 | stack.append(t) 237 | #push flags after arith ops 238 | t = (T_REG, REG_EFLAGS, 4) 239 | stack.append(t) 240 | 241 | elif vid == STORE_DWORD_REG: 242 | (typ, thing, sz) = stack.pop() 243 | 244 | if typ == T_REG: 245 | if vmi.param == ID_EFLAGS: 246 | if thing == REG_EFLAGS: 247 | pass #nothing to do 248 | else: 249 | assert False 250 | else: 251 | assert False 252 | else: 253 | assert False 254 | 255 | elif vid == UNCOND_JMP: 256 | assert vmi.param == 1 257 | native = "jmp $+1" 258 | 259 | elif vid == PUSH_RET_ADDR: 260 | (typ, ret_addr, sz) = stack.pop() 261 | assert typ == T_CONST 262 | native = "push_return_address: 0x%08x"%ret_addr 263 | 264 | elif vid == GTFO: 265 | native = "gtfo" 266 | 267 | elif vid == 0x157: 268 | native = "unk_157: mov byte [edi+28h], %d"%vmi.param 269 | 270 | else: 271 | assert False, "unkown instr: "+hex(vid) 272 | 273 | state[STACK] = stack 274 | state[ADDR] = addr 275 | 276 | return state, native 277 | 278 | def recover(vmis): 279 | 280 | state = {STACK: [], ADDR: (T_INVALID, 0, 0)} 281 | 282 | for vmi in vmis: 283 | print vmi.all_disasm() 284 | 285 | state, native = symb_eval(state, vmi) 286 | #print state 287 | 288 | if native != None: 289 | print native 290 | 291 | -------------------------------------------------------------------------------- /vm_classes.py: -------------------------------------------------------------------------------- 1 | import idc 2 | 3 | class Handler: 4 | def __init__(self, addr, dbb, decrypt, vmi): 5 | #original address (as in handlers tab) 6 | self.addr = addr 7 | #is this the dispatcher? 8 | self.is_main = False 9 | #deobfuscated dbb 10 | self.dbb = None 11 | #parameter decryption procedure (few instructions: add/sub/xor) 12 | self.decrypt_proc = decrypt 13 | #corresponding vm_instruction class 14 | self.vmi = vmi 15 | 16 | #we need to care about handlers taking params from esi 17 | #stack params are irrelevant 18 | self.takes_esi_params = False 19 | #what is it: lodsb/w/d? 20 | self.param_size = None 21 | 22 | self.set_dbb(dbb) 23 | 24 | def bits_to_bytes(self, fst): 25 | bits = fst.bits 26 | if bits == 8: 27 | size = 1 28 | elif bits == 16: 29 | size = 2 30 | elif bits == 32: 31 | size = 4 32 | else: 33 | print "bits:", bits 34 | assert(False) 35 | 36 | return size 37 | 38 | def set_dbb(self, dbb): 39 | self.dbb = dbb 40 | if len(dbb.body)==0: #true for empty handler 41 | return 42 | fst = dbb.body[0] 43 | if fst.mnem == "lods": 44 | size = self.bits_to_bytes(fst) 45 | self.takes_esi_params = True 46 | self.param_size = size 47 | 48 | def set_main(self): 49 | self.is_main = True 50 | 51 | #unfortunately, we don't know size of the code before we decrypt it, 52 | #so we need to talk to IDA here :( 53 | class VM_Code: 54 | def __init__(self, push_addr, vaddr): 55 | self.push_addr = push_addr 56 | self.vaddr = vaddr 57 | self.offset = 0 58 | 59 | def peek(self, size): 60 | ea = self.vaddr + self.offset 61 | if size==1: 62 | raw = idc.Byte(ea) 63 | elif size==2: 64 | raw = idc.Word(ea) 65 | elif size==4: 66 | raw = idc.Dword(ea) 67 | else: 68 | print "bad size:", size 69 | assert(False) 70 | return raw 71 | 72 | def advance(self, size): 73 | self.offset += size 74 | 75 | def consume(self, size): 76 | raw = self.peek(size) 77 | self.advance(size) 78 | return raw 79 | -------------------------------------------------------------------------------- /vm_instructions.py: -------------------------------------------------------------------------------- 1 | from op_classes import * 2 | from vmi_top_common import * 3 | from vmi_auto_gen import * 4 | 5 | class VM_000(VM_Instruction): 6 | def __init__(self): 7 | self.fn = "000.txt" 8 | VM_Instruction.__init__(self) 9 | 10 | def disasm(self, param): 11 | o = "load ptr %s"%REG_DICT[param] 12 | return o 13 | 14 | class VM_001(VM_Instruction): 15 | def __init__(self): 16 | self.fn = "001.txt" 17 | VM_Instruction.__init__(self) 18 | 19 | def disasm(self, param): 20 | o = "store addr" 21 | return o 22 | 23 | #top: load ptr reg (pointer to value holding reg's value) 24 | class VM_Load(VM_Inst_With_Suff): 25 | def __init__(self): 26 | self.mnem = "load" 27 | VM_Inst_With_Suff.__init__(self) 28 | 29 | def disasm(self, param): 30 | d = VM_Inst_With_Suff.disasm(self, param) 31 | d += " %s"%hex(param) 32 | return d 33 | 34 | class VM_006(VM_Instruction): 35 | def __init__(self): 36 | self.fn = "006.txt" 37 | VM_Instruction.__init__(self) 38 | 39 | def disasm(self, param): 40 | o = "add. dword" 41 | return o 42 | 43 | class VM_009(VM_Instruction): 44 | def __init__(self): 45 | self.fn = "009.txt" 46 | VM_Instruction.__init__(self) 47 | 48 | def disasm(self, param): 49 | o = "load addr" 50 | return o 51 | 52 | class VM_013(VM_Instruction): 53 | def __init__(self): 54 | self.fn = "013.txt" 55 | VM_Instruction.__init__(self) 56 | 57 | def disasm(self, param): 58 | o = "load ptr; store dword [ptr]" 59 | 60 | class VM_015(VM_Instruction): 61 | def __init__(self): 62 | self.fn = "015.txt" 63 | VM_Instruction.__init__(self) 64 | 65 | def disasm(self, param): 66 | o = "store addr" 67 | 68 | #top: store [addr] 69 | class VM_Store(VM_Inst_With_Suff): 70 | def __init__(self): 71 | self.mnem = "store" 72 | VM_Inst_With_Suff.__init__(self) 73 | 74 | def disasm(self, param): 75 | d = VM_Inst_With_Suff.disasm(self, param) 76 | d += " [addr]" 77 | return d 78 | 79 | class VM_019(VM_Store): 80 | def __init__(self): 81 | self.fn = "019.txt" 82 | self.size = 32 83 | VM_Store.__init__(self) 84 | 85 | class VM_026(VM_Instruction): 86 | def __init__(self): 87 | self.fn = "026.txt" 88 | VM_Instruction.__init__(self) 89 | 90 | def disasm(self, param): 91 | o = "sub. dword" 92 | return o 93 | 94 | class VM_048(VM_Instruction): 95 | def __init__(self): 96 | self.fn = "048.txt" 97 | VM_Instruction.__init__(self) 98 | 99 | class VM_049(VM_Instruction): 100 | def __init__(self): 101 | self.fn = "049.txt" 102 | VM_Instruction.__init__(self) 103 | 104 | class VM_04d(VM_Instruction): 105 | def __init__(self): 106 | self.fn = "04d.txt" 107 | VM_Instruction.__init__(self) 108 | 109 | class VM_06f(VM_Instruction): 110 | def __init__(self): 111 | self.fn = "06f.txt" 112 | VM_Instruction.__init__(self) 113 | 114 | class VM_070(VM_Instruction): 115 | def __init__(self): 116 | self.fn = "070.txt" 117 | VM_Instruction.__init__(self) 118 | 119 | class VM_071(VM_Instruction): 120 | def __init__(self): 121 | self.fn = "071.txt" 122 | VM_Instruction.__init__(self) 123 | 124 | class VM_07b(VM_Instruction): 125 | def __init__(self): 126 | self.fn = "07b.txt" 127 | VM_Instruction.__init__(self) 128 | 129 | class VM_080(VM_Instruction): 130 | def __init__(self): 131 | self.fn = "080.txt" 132 | VM_Instruction.__init__(self) 133 | 134 | class VM_081(VM_Instruction): 135 | def __init__(self): 136 | self.fn = "081.txt" 137 | VM_Instruction.__init__(self) 138 | 139 | class VM_085(VM_Instruction): 140 | def __init__(self): 141 | self.fn = "085.txt" 142 | VM_Instruction.__init__(self) 143 | 144 | class VM_087(VM_Instruction): 145 | def __init__(self): 146 | self.fn = "087.txt" 147 | VM_Instruction.__init__(self) 148 | 149 | class VM_08b(VM_Instruction): 150 | def __init__(self): 151 | self.fn = "08b.txt" 152 | VM_Instruction.__init__(self) 153 | 154 | class VM_08f(VM_Instruction): 155 | def __init__(self): 156 | self.fn = "08f.txt" 157 | VM_Instruction.__init__(self) 158 | 159 | class VM_093(VM_Instruction): 160 | def __init__(self): 161 | self.fn = "093.txt" 162 | VM_Instruction.__init__(self) 163 | 164 | class VM_097(VM_Instruction): 165 | def __init__(self): 166 | self.fn = "097.txt" 167 | VM_Instruction.__init__(self) 168 | 169 | class VM_09b(VM_Instruction): 170 | def __init__(self): 171 | self.fn = "09b.txt" 172 | VM_Instruction.__init__(self) 173 | 174 | class VM_09f(VM_Instruction): 175 | def __init__(self): 176 | self.fn = "09f.txt" 177 | VM_Instruction.__init__(self) 178 | 179 | class VM_0a3(VM_Instruction): 180 | def __init__(self): 181 | self.fn = "0a3.txt" 182 | VM_Instruction.__init__(self) 183 | 184 | class VM_0cd(VM_Instruction): 185 | def __init__(self): 186 | self.fn = "0cd.txt" 187 | VM_Instruction.__init__(self) 188 | 189 | def disasm(self, param): 190 | return "bswap" 191 | 192 | class VM_14a(VM_Instruction): 193 | def __init__(self): 194 | self.fn = "14a.txt" 195 | VM_Instruction.__init__(self) 196 | 197 | class VM_14b(VM_Instruction): 198 | def __init__(self): 199 | self.fn = "14b.txt" 200 | VM_Instruction.__init__(self) 201 | 202 | class VM_14c(VM_Instruction): 203 | def __init__(self): 204 | self.fn = "14c.txt" 205 | VM_Instruction.__init__(self) 206 | 207 | class VM_14d(VM_Instruction): 208 | def __init__(self): 209 | self.fn = "14d.txt" 210 | VM_Instruction.__init__(self) 211 | 212 | class VM_14e(VM_Instruction): 213 | def __init__(self): 214 | self.fn = "14e.txt" 215 | VM_Instruction.__init__(self) 216 | 217 | def disasm(self, param): 218 | o = "move addr, STACK" #stack = current esp 219 | return o 220 | 221 | class VM_14f(VM_Instruction): 222 | def __init__(self): 223 | self.fn = "14f.txt" 224 | VM_Instruction.__init__(self) 225 | 226 | class VM_150(VM_Instruction): 227 | def __init__(self): 228 | self.fn = "150.txt" 229 | VM_Instruction.__init__(self) 230 | 231 | class VM_151(VM_Instruction): 232 | def __init__(self): 233 | self.fn = "151.txt" 234 | VM_Instruction.__init__(self) 235 | 236 | class VM_152(VM_Instruction): 237 | def __init__(self): 238 | self.fn = "152.txt" 239 | VM_Instruction.__init__(self) 240 | 241 | class VM_153(VM_Instruction): 242 | def __init__(self): 243 | self.fn = "153.txt" 244 | VM_Instruction.__init__(self) 245 | 246 | # lodsd 247 | # add esi, eax 248 | # mov ebx, 0 249 | class VM_154(VM_Instruction): 250 | def __init__(self): 251 | self.fn = "154.txt" 252 | VM_Instruction.__init__(self) 253 | 254 | def disasm(self, param): 255 | o = "jmp $+%s"%hex(param) 256 | return o 257 | 258 | def affects_ctx(self): 259 | return True 260 | 261 | def update_ctx(self, ctx, vm_code, param): 262 | assert(param != None) 263 | vm_code.advance(param) 264 | ctx.set_reg(EBX, 0) 265 | 266 | class VM_155(VM_Instruction): 267 | def __init__(self): 268 | self.fn = "155.txt" 269 | VM_Instruction.__init__(self) 270 | 271 | def disasm(self, param): 272 | cond = param & 0x7f 273 | o = "check_cond 0x%02x"%cond 274 | return o 275 | 276 | #jmp iff [edi+20h] == 1 277 | class VM_156(VM_Instruction): 278 | def __init__(self): 279 | self.fn = "156.txt" 280 | VM_Instruction.__init__(self) 281 | 282 | def disasm(self, param): 283 | o = "cond_jmp $+%s"%hex(param) 284 | return o 285 | 286 | class VM_157(VM_Instruction): 287 | def __init__(self): 288 | self.fn = "157.txt" 289 | VM_Instruction.__init__(self) 290 | 291 | def disasm(self, param): 292 | o = "157 param: 0x%02x"%param 293 | return o 294 | 295 | class VM_158(VM_Instruction): 296 | def __init__(self): 297 | self.fn = "158.txt" 298 | VM_Instruction.__init__(self) 299 | 300 | class VM_15a(VM_Instruction): 301 | def __init__(self): 302 | self.fn = "15a.txt" 303 | VM_Instruction.__init__(self) 304 | 305 | class VM_15d(VM_Instruction): 306 | def __init__(self): 307 | self.fn = "15d.txt" 308 | VM_Instruction.__init__(self) 309 | 310 | class VM_15e(VM_Instruction): 311 | def __init__(self): 312 | self.fn = "15e.txt" 313 | VM_Instruction.__init__(self) 314 | 315 | class VM_15f(VM_Instruction): 316 | def __init__(self): 317 | self.fn = "15f.txt" 318 | VM_Instruction.__init__(self) 319 | 320 | class VM_160(VM_Instruction): 321 | def __init__(self): 322 | self.fn = "160.txt" 323 | VM_Instruction.__init__(self) 324 | 325 | def disasm(self, param): 326 | o = "xor. dword" 327 | return o 328 | 329 | #set ebx=0 330 | class VM_161(VM_Instruction): 331 | def __init__(self): 332 | self.fn = "161.txt" 333 | VM_Instruction.__init__(self) 334 | 335 | def disasm(self, param): 336 | return "reset_key" 337 | 338 | def affects_ctx(self): 339 | return True 340 | 341 | def update_ctx(self, ctx, vm_code, param): 342 | ctx.set_reg(EBX, 0) 343 | 344 | class VM_200(VM_Instruction): 345 | def __init__(self): 346 | self.fn = "200.txt" 347 | VM_Instruction.__init__(self) 348 | 349 | def disasm(self, param): 350 | o = "load ptr; load dword; [ptr] = dword" 351 | return o 352 | 353 | class VM_201(VM_Instruction): 354 | def __init__(self): 355 | self.fn = "201.txt" 356 | VM_Instruction.__init__(self) 357 | 358 | def disasm(self, param): 359 | o = "xor addr, 0x%08x"%param 360 | return o 361 | 362 | class VM_202(VM_Instruction): 363 | def __init__(self): 364 | self.fn = "202.txt" 365 | VM_Instruction.__init__(self) 366 | 367 | class VM_203(VM_Instruction): 368 | def __init__(self): 369 | self.fn = "203.txt" 370 | VM_Instruction.__init__(self) 371 | 372 | class VM_204(VM_Instruction): 373 | def __init__(self): 374 | self.fn = "204.txt" 375 | VM_Instruction.__init__(self) 376 | 377 | def disasm(self, param): 378 | o = "load TMP" 379 | return o 380 | 381 | class VM_205(VM_Instruction): 382 | def __init__(self): 383 | self.fn = "205.txt" 384 | VM_Instruction.__init__(self) 385 | 386 | def disasm(self, param): 387 | o = "store TMP" 388 | return o 389 | 390 | class VM_206(VM_Instruction): 391 | def __init__(self): 392 | self.fn = "206.txt" 393 | VM_Instruction.__init__(self) 394 | 395 | class VM_207(VM_Instruction): 396 | def __init__(self): 397 | self.fn = "207.txt" 398 | VM_Instruction.__init__(self) 399 | 400 | def disasm(self, param): 401 | o = "sub. addr, %s"%hex(param) 402 | return o 403 | 404 | class VM_208(VM_Instruction): 405 | def __init__(self): 406 | self.fn = "208.txt" 407 | VM_Instruction.__init__(self) 408 | 409 | def disasm(self, param): 410 | o = "move STACK, [STACK]" 411 | return o 412 | 413 | class VM_209(VM_Instruction): 414 | def __init__(self): 415 | self.fn = "209.txt" 416 | VM_Instruction.__init__(self) 417 | 418 | def disasm(self, param): 419 | o = "move addr, %s"%hex(param) 420 | return o 421 | 422 | class VM_20a(VM_Instruction): 423 | def __init__(self): 424 | self.fn = "20a.txt" 425 | VM_Instruction.__init__(self) 426 | 427 | class VM_20b(VM_Instruction): 428 | def __init__(self): 429 | self.fn = "20b.txt" 430 | VM_Instruction.__init__(self) 431 | 432 | def disasm(self, param): 433 | o = "add. addr, %s"%hex(param) 434 | return o 435 | 436 | class VM_20d(VM_Instruction): 437 | def __init__(self): 438 | self.fn = "20d.txt" 439 | VM_Instruction.__init__(self) 440 | 441 | class VM_20e(VM_Instruction): 442 | def __init__(self): 443 | self.fn = "20e.txt" 444 | VM_Instruction.__init__(self) 445 | 446 | class VM_20f(VM_Instruction): 447 | def __init__(self): 448 | self.fn = "20f.txt" 449 | VM_Instruction.__init__(self) 450 | 451 | # xchg edx, [esp[ 452 | class VM_210(VM_Instruction): 453 | def __init__(self): 454 | self.fn = "210.txt" 455 | VM_Instruction.__init__(self) 456 | 457 | def disasm(self, param): 458 | o = "xchg [STACK], addr" 459 | return o 460 | 461 | #add reg to edx 462 | class VM_211(VM_Instruction): 463 | def __init__(self): 464 | self.fn = "211.txt" 465 | VM_Instruction.__init__(self) 466 | 467 | def disasm(self, param): 468 | o = "add_reg_to_addr" 469 | if param == 7: 470 | reg = "esp" 471 | else: 472 | reg = REG_DICT[param] 473 | o += " %s"%reg 474 | return o 475 | 476 | # vm_exit ? 477 | class VM_212(VM_Instruction): 478 | def __init__(self): 479 | self.fn = "212.txt" 480 | VM_Instruction.__init__(self) 481 | 482 | def is_halt(self): 483 | return True 484 | 485 | def disasm(self, param): 486 | o = "gtfo" 487 | return o 488 | 489 | class VM_213(VM_Instruction): 490 | def __init__(self): 491 | self.fn = "213.txt" 492 | VM_Instruction.__init__(self) 493 | 494 | def disasm(self, param): 495 | o = "swap; store TMP" 496 | return o 497 | 498 | # empty handler 499 | class VM_214(VM_Instruction): 500 | def __init__(self): 501 | self.fn = "214.txt" 502 | VM_Instruction.__init__(self) 503 | 504 | def disasm(self, param=None): 505 | return "nop" 506 | 507 | VM_INSTRUCTIONS_SET = [ 508 | VM_000, VM_001, VM_002, VM_003, VM_004, VM_006, VM_007, VM_009, 509 | VM_00a, VM_00b, VM_00c, VM_00e, VM_00f, VM_011, VM_012, VM_013, 510 | VM_015, VM_016, VM_017, VM_018, VM_019, VM_01a, VM_01b, VM_01c, 511 | VM_01e, VM_01f, VM_020, VM_022, VM_023, VM_024, VM_026, VM_027, 512 | VM_028, VM_029, VM_02c, VM_02d, VM_02f, VM_030, VM_031, VM_033, 513 | VM_034, VM_035, VM_037, VM_038, VM_039, VM_03b, VM_03c, VM_03d, 514 | VM_03f, VM_040, VM_041, VM_043, VM_044, VM_045, VM_048, VM_049, 515 | VM_04d, VM_053, VM_054, VM_055, VM_057, VM_058, VM_059, VM_05b, 516 | VM_05c, VM_05d, VM_05f, VM_060, VM_061, VM_063, VM_064, VM_065, 517 | VM_067, VM_068, VM_069, VM_06b, VM_06c, VM_06d, VM_06f, VM_070, 518 | VM_071, VM_073, VM_074, VM_075, VM_077, VM_078, VM_079, VM_07b, 519 | VM_080, VM_081, VM_085, VM_087, VM_08b, VM_08f, VM_093, VM_097, 520 | VM_09b, VM_09f, VM_0a3, VM_0a8, VM_0a9, VM_0ab, VM_0ac, VM_0af, 521 | VM_0b0, VM_0b3, VM_0b4, VM_0b7, VM_0b8, VM_0b9, VM_0bb, VM_0bc, 522 | VM_0bd, VM_0bf, VM_0c0, VM_0c1, VM_0c3, VM_0c4, VM_0c5, VM_0c7, 523 | VM_0c8, VM_0c9, VM_0cd, VM_0cf, VM_0d0, VM_0d1, VM_0d3, VM_0d4, 524 | VM_0d5, VM_14a, VM_14b, VM_14c, VM_14d, VM_14e, VM_14f, VM_150, 525 | VM_151, VM_152, VM_153, VM_154, VM_155, VM_156, VM_157, VM_158, 526 | VM_15a, VM_15d, VM_15e, VM_15f, VM_160, VM_161, VM_200, VM_201, 527 | VM_202, VM_203, VM_204, VM_205, VM_206, VM_207, VM_208, VM_209, 528 | VM_20a, VM_20b, VM_20c, VM_20d, VM_20e, VM_20f, VM_210, VM_211, 529 | VM_212, VM_213, VM_214 530 | ] 531 | -------------------------------------------------------------------------------- /vmi_auto_gen.py: -------------------------------------------------------------------------------- 1 | # AUTOGENERATED BY gen_vmi.py 2 | # DO NOT EDIT! 3 | from vmi_top_common import * 4 | 5 | class VM_Load_Const(VM_Inst_With_Suff): 6 | def __init__(self): 7 | self.mnem = "load" 8 | VM_Inst_With_Suff.__init__(self) 9 | 10 | 11 | def disasm(self, param): 12 | d = VM_Inst_With_Suff.disasm(self, param) 13 | d += " %s"%hex(param) 14 | return d 15 | 16 | class VM_002(VM_Load_Const): 17 | def __init__(self): 18 | self.fn = "002.txt" 19 | self.size = 8 20 | VM_Load_Const.__init__(self) 21 | 22 | class VM_003(VM_Load_Const): 23 | def __init__(self): 24 | self.fn = "003.txt" 25 | self.size = 16 26 | VM_Load_Const.__init__(self) 27 | 28 | class VM_004(VM_Load_Const): 29 | def __init__(self): 30 | self.fn = "004.txt" 31 | self.size = 32 32 | VM_Load_Const.__init__(self) 33 | 34 | 35 | class VM_Load_Addr(VM_Inst_With_Suff): 36 | def __init__(self): 37 | self.mnem = "load" 38 | VM_Inst_With_Suff.__init__(self) 39 | 40 | 41 | def disasm(self, param): 42 | d = VM_Inst_With_Suff.disasm(self, param) 43 | d += " [addr]" 44 | return d 45 | 46 | class VM_00a(VM_Load_Addr): 47 | def __init__(self): 48 | self.fn = "00a.txt" 49 | self.size = 8 50 | VM_Load_Addr.__init__(self) 51 | 52 | class VM_00b(VM_Load_Addr): 53 | def __init__(self): 54 | self.fn = "00b.txt" 55 | self.size = 16 56 | VM_Load_Addr.__init__(self) 57 | 58 | class VM_00c(VM_Load_Addr): 59 | def __init__(self): 60 | self.fn = "00c.txt" 61 | self.size = 32 62 | VM_Load_Addr.__init__(self) 63 | 64 | 65 | class VM_Load_Reg(VM_Inst_With_Suff): 66 | def __init__(self): 67 | self.mnem = "load" 68 | VM_Inst_With_Suff.__init__(self) 69 | 70 | 71 | def disasm(self, param): 72 | d = VM_Inst_With_Suff.disasm(self, param) 73 | d += " %s"%REG_DICT[param] 74 | return d 75 | 76 | class VM_00e(VM_Load_Reg): 77 | def __init__(self): 78 | self.fn = "00e.txt" 79 | self.size = 8 80 | VM_Load_Reg.__init__(self) 81 | 82 | class VM_00f(VM_Load_Reg): 83 | def __init__(self): 84 | self.fn = "00f.txt" 85 | self.size = 16 86 | VM_Load_Reg.__init__(self) 87 | 88 | class VM_007(VM_Load_Reg): 89 | def __init__(self): 90 | self.fn = "007.txt" 91 | self.size = 32 92 | VM_Load_Reg.__init__(self) 93 | 94 | 95 | class VM_Load_Ptr(VM_Inst_With_Suff): 96 | def __init__(self): 97 | self.mnem = "load" 98 | VM_Inst_With_Suff.__init__(self) 99 | 100 | 101 | def disasm(self, param): 102 | d = VM_Inst_With_Suff.disasm(self, param) 103 | d += " [%s]"%hex(param) 104 | return d 105 | 106 | class VM_011(VM_Load_Ptr): 107 | def __init__(self): 108 | self.fn = "011.txt" 109 | self.size = 8 110 | VM_Load_Ptr.__init__(self) 111 | 112 | class VM_012(VM_Load_Ptr): 113 | def __init__(self): 114 | self.fn = "012.txt" 115 | self.size = 16 116 | VM_Load_Ptr.__init__(self) 117 | 118 | class VM_20c(VM_Load_Ptr): 119 | def __init__(self): 120 | self.fn = "20c.txt" 121 | self.size = 32 122 | VM_Load_Ptr.__init__(self) 123 | 124 | 125 | class VM_Store_Addr(VM_Inst_With_Suff): 126 | def __init__(self): 127 | self.mnem = "store" 128 | VM_Inst_With_Suff.__init__(self) 129 | 130 | 131 | def disasm(self, param): 132 | d = VM_Inst_With_Suff.disasm(self, param) 133 | d += " [addr]" 134 | return d 135 | 136 | class VM_016(VM_Store_Addr): 137 | def __init__(self): 138 | self.fn = "016.txt" 139 | self.size = 8 140 | VM_Store_Addr.__init__(self) 141 | 142 | class VM_017(VM_Store_Addr): 143 | def __init__(self): 144 | self.fn = "017.txt" 145 | self.size = 16 146 | VM_Store_Addr.__init__(self) 147 | 148 | class VM_018(VM_Store_Addr): 149 | def __init__(self): 150 | self.fn = "018.txt" 151 | self.size = 32 152 | VM_Store_Addr.__init__(self) 153 | 154 | 155 | class VM_Store_Reg(VM_Inst_With_Suff): 156 | def __init__(self): 157 | self.mnem = "store" 158 | VM_Inst_With_Suff.__init__(self) 159 | 160 | 161 | def disasm(self, param): 162 | d = VM_Inst_With_Suff.disasm(self, param) 163 | d += " %s"%REG_DICT[param] 164 | return d 165 | 166 | class VM_01a(VM_Store_Reg): 167 | def __init__(self): 168 | self.fn = "01a.txt" 169 | self.size = 8 170 | VM_Store_Reg.__init__(self) 171 | 172 | class VM_01b(VM_Store_Reg): 173 | def __init__(self): 174 | self.fn = "01b.txt" 175 | self.size = 16 176 | VM_Store_Reg.__init__(self) 177 | 178 | class VM_01c(VM_Store_Reg): 179 | def __init__(self): 180 | self.fn = "01c.txt" 181 | self.size = 32 182 | VM_Store_Reg.__init__(self) 183 | 184 | 185 | class VM_Store_Ptr(VM_Inst_With_Suff): 186 | def __init__(self): 187 | self.mnem = "store" 188 | VM_Inst_With_Suff.__init__(self) 189 | 190 | 191 | def disasm(self, param): 192 | d = VM_Inst_With_Suff.disasm(self, param) 193 | d += " [%s]"%hex(param) 194 | return d 195 | 196 | class VM_01e(VM_Store_Ptr): 197 | def __init__(self): 198 | self.fn = "01e.txt" 199 | self.size = 8 200 | VM_Store_Ptr.__init__(self) 201 | 202 | class VM_01f(VM_Store_Ptr): 203 | def __init__(self): 204 | self.fn = "01f.txt" 205 | self.size = 16 206 | VM_Store_Ptr.__init__(self) 207 | 208 | class VM_020(VM_Store_Ptr): 209 | def __init__(self): 210 | self.fn = "020.txt" 211 | self.size = 32 212 | VM_Store_Ptr.__init__(self) 213 | 214 | 215 | class VM_Add(VM_Inst_With_Suff): 216 | def __init__(self): 217 | self.mnem = "add" 218 | VM_Inst_With_Suff.__init__(self) 219 | 220 | class VM_022(VM_Add): 221 | def __init__(self): 222 | self.fn = "022.txt" 223 | self.size = 8 224 | VM_Add.__init__(self) 225 | 226 | class VM_023(VM_Add): 227 | def __init__(self): 228 | self.fn = "023.txt" 229 | self.size = 16 230 | VM_Add.__init__(self) 231 | 232 | class VM_024(VM_Add): 233 | def __init__(self): 234 | self.fn = "024.txt" 235 | self.size = 32 236 | VM_Add.__init__(self) 237 | 238 | 239 | class VM_Sub(VM_Inst_With_Suff): 240 | def __init__(self): 241 | self.mnem = "sub" 242 | VM_Inst_With_Suff.__init__(self) 243 | 244 | class VM_027(VM_Sub): 245 | def __init__(self): 246 | self.fn = "027.txt" 247 | self.size = 8 248 | VM_Sub.__init__(self) 249 | 250 | class VM_028(VM_Sub): 251 | def __init__(self): 252 | self.fn = "028.txt" 253 | self.size = 16 254 | VM_Sub.__init__(self) 255 | 256 | class VM_029(VM_Sub): 257 | def __init__(self): 258 | self.fn = "029.txt" 259 | self.size = 32 260 | VM_Sub.__init__(self) 261 | 262 | 263 | class VM_Imul2(VM_Inst_With_Suff): 264 | def __init__(self): 265 | self.mnem = "imul2" 266 | VM_Inst_With_Suff.__init__(self) 267 | 268 | class VM_02c(VM_Imul2): 269 | def __init__(self): 270 | self.fn = "02c.txt" 271 | self.size = 16 272 | VM_Imul2.__init__(self) 273 | 274 | class VM_02d(VM_Imul2): 275 | def __init__(self): 276 | self.fn = "02d.txt" 277 | self.size = 32 278 | VM_Imul2.__init__(self) 279 | 280 | 281 | class VM_Adc(VM_Inst_With_Suff): 282 | def __init__(self): 283 | self.mnem = "adc" 284 | VM_Inst_With_Suff.__init__(self) 285 | 286 | class VM_02f(VM_Adc): 287 | def __init__(self): 288 | self.fn = "02f.txt" 289 | self.size = 8 290 | VM_Adc.__init__(self) 291 | 292 | class VM_030(VM_Adc): 293 | def __init__(self): 294 | self.fn = "030.txt" 295 | self.size = 16 296 | VM_Adc.__init__(self) 297 | 298 | class VM_031(VM_Adc): 299 | def __init__(self): 300 | self.fn = "031.txt" 301 | self.size = 32 302 | VM_Adc.__init__(self) 303 | 304 | 305 | class VM_And(VM_Inst_With_Suff): 306 | def __init__(self): 307 | self.mnem = "and" 308 | VM_Inst_With_Suff.__init__(self) 309 | 310 | class VM_033(VM_And): 311 | def __init__(self): 312 | self.fn = "033.txt" 313 | self.size = 8 314 | VM_And.__init__(self) 315 | 316 | class VM_034(VM_And): 317 | def __init__(self): 318 | self.fn = "034.txt" 319 | self.size = 16 320 | VM_And.__init__(self) 321 | 322 | class VM_035(VM_And): 323 | def __init__(self): 324 | self.fn = "035.txt" 325 | self.size = 32 326 | VM_And.__init__(self) 327 | 328 | 329 | class VM_Cmp(VM_Inst_With_Suff): 330 | def __init__(self): 331 | self.mnem = "cmp" 332 | VM_Inst_With_Suff.__init__(self) 333 | 334 | class VM_037(VM_Cmp): 335 | def __init__(self): 336 | self.fn = "037.txt" 337 | self.size = 8 338 | VM_Cmp.__init__(self) 339 | 340 | class VM_038(VM_Cmp): 341 | def __init__(self): 342 | self.fn = "038.txt" 343 | self.size = 16 344 | VM_Cmp.__init__(self) 345 | 346 | class VM_039(VM_Cmp): 347 | def __init__(self): 348 | self.fn = "039.txt" 349 | self.size = 32 350 | VM_Cmp.__init__(self) 351 | 352 | 353 | class VM_Xor(VM_Inst_With_Suff): 354 | def __init__(self): 355 | self.mnem = "xor" 356 | VM_Inst_With_Suff.__init__(self) 357 | 358 | class VM_03b(VM_Xor): 359 | def __init__(self): 360 | self.fn = "03b.txt" 361 | self.size = 8 362 | VM_Xor.__init__(self) 363 | 364 | class VM_03c(VM_Xor): 365 | def __init__(self): 366 | self.fn = "03c.txt" 367 | self.size = 16 368 | VM_Xor.__init__(self) 369 | 370 | class VM_03d(VM_Xor): 371 | def __init__(self): 372 | self.fn = "03d.txt" 373 | self.size = 32 374 | VM_Xor.__init__(self) 375 | 376 | 377 | class VM_Or(VM_Inst_With_Suff): 378 | def __init__(self): 379 | self.mnem = "or" 380 | VM_Inst_With_Suff.__init__(self) 381 | 382 | class VM_03f(VM_Or): 383 | def __init__(self): 384 | self.fn = "03f.txt" 385 | self.size = 8 386 | VM_Or.__init__(self) 387 | 388 | class VM_040(VM_Or): 389 | def __init__(self): 390 | self.fn = "040.txt" 391 | self.size = 16 392 | VM_Or.__init__(self) 393 | 394 | class VM_041(VM_Or): 395 | def __init__(self): 396 | self.fn = "041.txt" 397 | self.size = 32 398 | VM_Or.__init__(self) 399 | 400 | 401 | class VM_Test(VM_Inst_With_Suff): 402 | def __init__(self): 403 | self.mnem = "test" 404 | VM_Inst_With_Suff.__init__(self) 405 | 406 | class VM_043(VM_Test): 407 | def __init__(self): 408 | self.fn = "043.txt" 409 | self.size = 8 410 | VM_Test.__init__(self) 411 | 412 | class VM_044(VM_Test): 413 | def __init__(self): 414 | self.fn = "044.txt" 415 | self.size = 16 416 | VM_Test.__init__(self) 417 | 418 | class VM_045(VM_Test): 419 | def __init__(self): 420 | self.fn = "045.txt" 421 | self.size = 32 422 | VM_Test.__init__(self) 423 | 424 | 425 | class VM_Inc(VM_Inst_With_Suff): 426 | def __init__(self): 427 | self.mnem = "inc" 428 | VM_Inst_With_Suff.__init__(self) 429 | 430 | class VM_053(VM_Inc): 431 | def __init__(self): 432 | self.fn = "053.txt" 433 | self.size = 8 434 | VM_Inc.__init__(self) 435 | 436 | class VM_054(VM_Inc): 437 | def __init__(self): 438 | self.fn = "054.txt" 439 | self.size = 16 440 | VM_Inc.__init__(self) 441 | 442 | class VM_055(VM_Inc): 443 | def __init__(self): 444 | self.fn = "055.txt" 445 | self.size = 32 446 | VM_Inc.__init__(self) 447 | 448 | 449 | class VM_Rcl(VM_Inst_With_Suff): 450 | def __init__(self): 451 | self.mnem = "rcl" 452 | VM_Inst_With_Suff.__init__(self) 453 | 454 | class VM_057(VM_Rcl): 455 | def __init__(self): 456 | self.fn = "057.txt" 457 | self.size = 8 458 | VM_Rcl.__init__(self) 459 | 460 | class VM_058(VM_Rcl): 461 | def __init__(self): 462 | self.fn = "058.txt" 463 | self.size = 16 464 | VM_Rcl.__init__(self) 465 | 466 | class VM_059(VM_Rcl): 467 | def __init__(self): 468 | self.fn = "059.txt" 469 | self.size = 32 470 | VM_Rcl.__init__(self) 471 | 472 | 473 | class VM_Rcr(VM_Inst_With_Suff): 474 | def __init__(self): 475 | self.mnem = "rcr" 476 | VM_Inst_With_Suff.__init__(self) 477 | 478 | class VM_05b(VM_Rcr): 479 | def __init__(self): 480 | self.fn = "05b.txt" 481 | self.size = 8 482 | VM_Rcr.__init__(self) 483 | 484 | class VM_05c(VM_Rcr): 485 | def __init__(self): 486 | self.fn = "05c.txt" 487 | self.size = 16 488 | VM_Rcr.__init__(self) 489 | 490 | class VM_05d(VM_Rcr): 491 | def __init__(self): 492 | self.fn = "05d.txt" 493 | self.size = 32 494 | VM_Rcr.__init__(self) 495 | 496 | 497 | class VM_Rol(VM_Inst_With_Suff): 498 | def __init__(self): 499 | self.mnem = "rol" 500 | VM_Inst_With_Suff.__init__(self) 501 | 502 | class VM_05f(VM_Rol): 503 | def __init__(self): 504 | self.fn = "05f.txt" 505 | self.size = 8 506 | VM_Rol.__init__(self) 507 | 508 | class VM_060(VM_Rol): 509 | def __init__(self): 510 | self.fn = "060.txt" 511 | self.size = 16 512 | VM_Rol.__init__(self) 513 | 514 | class VM_061(VM_Rol): 515 | def __init__(self): 516 | self.fn = "061.txt" 517 | self.size = 32 518 | VM_Rol.__init__(self) 519 | 520 | 521 | class VM_Ror(VM_Inst_With_Suff): 522 | def __init__(self): 523 | self.mnem = "ror" 524 | VM_Inst_With_Suff.__init__(self) 525 | 526 | class VM_063(VM_Ror): 527 | def __init__(self): 528 | self.fn = "063.txt" 529 | self.size = 8 530 | VM_Ror.__init__(self) 531 | 532 | class VM_064(VM_Ror): 533 | def __init__(self): 534 | self.fn = "064.txt" 535 | self.size = 16 536 | VM_Ror.__init__(self) 537 | 538 | class VM_065(VM_Ror): 539 | def __init__(self): 540 | self.fn = "065.txt" 541 | self.size = 32 542 | VM_Ror.__init__(self) 543 | 544 | 545 | class VM_Sar(VM_Inst_With_Suff): 546 | def __init__(self): 547 | self.mnem = "sar" 548 | VM_Inst_With_Suff.__init__(self) 549 | 550 | class VM_06b(VM_Sar): 551 | def __init__(self): 552 | self.fn = "06b.txt" 553 | self.size = 8 554 | VM_Sar.__init__(self) 555 | 556 | class VM_06c(VM_Sar): 557 | def __init__(self): 558 | self.fn = "06c.txt" 559 | self.size = 16 560 | VM_Sar.__init__(self) 561 | 562 | class VM_06d(VM_Sar): 563 | def __init__(self): 564 | self.fn = "06d.txt" 565 | self.size = 32 566 | VM_Sar.__init__(self) 567 | 568 | 569 | class VM_Shl(VM_Inst_With_Suff): 570 | def __init__(self): 571 | self.mnem = "shl" 572 | VM_Inst_With_Suff.__init__(self) 573 | 574 | class VM_067(VM_Shl): 575 | def __init__(self): 576 | self.fn = "067.txt" 577 | self.size = 8 578 | VM_Shl.__init__(self) 579 | 580 | class VM_068(VM_Shl): 581 | def __init__(self): 582 | self.fn = "068.txt" 583 | self.size = 16 584 | VM_Shl.__init__(self) 585 | 586 | class VM_069(VM_Shl): 587 | def __init__(self): 588 | self.fn = "069.txt" 589 | self.size = 32 590 | VM_Shl.__init__(self) 591 | 592 | 593 | class VM_Shr(VM_Inst_With_Suff): 594 | def __init__(self): 595 | self.mnem = "shr" 596 | VM_Inst_With_Suff.__init__(self) 597 | 598 | class VM_073(VM_Shr): 599 | def __init__(self): 600 | self.fn = "073.txt" 601 | self.size = 8 602 | VM_Shr.__init__(self) 603 | 604 | class VM_074(VM_Shr): 605 | def __init__(self): 606 | self.fn = "074.txt" 607 | self.size = 16 608 | VM_Shr.__init__(self) 609 | 610 | class VM_075(VM_Shr): 611 | def __init__(self): 612 | self.fn = "075.txt" 613 | self.size = 32 614 | VM_Shr.__init__(self) 615 | 616 | 617 | class VM_Dec(VM_Inst_With_Suff): 618 | def __init__(self): 619 | self.mnem = "dec" 620 | VM_Inst_With_Suff.__init__(self) 621 | 622 | class VM_077(VM_Dec): 623 | def __init__(self): 624 | self.fn = "077.txt" 625 | self.size = 8 626 | VM_Dec.__init__(self) 627 | 628 | class VM_078(VM_Dec): 629 | def __init__(self): 630 | self.fn = "078.txt" 631 | self.size = 16 632 | VM_Dec.__init__(self) 633 | 634 | class VM_079(VM_Dec): 635 | def __init__(self): 636 | self.fn = "079.txt" 637 | self.size = 32 638 | VM_Dec.__init__(self) 639 | 640 | 641 | class VM_Bt(VM_Inst_With_Suff): 642 | def __init__(self): 643 | self.mnem = "bt" 644 | VM_Inst_With_Suff.__init__(self) 645 | 646 | class VM_0a8(VM_Bt): 647 | def __init__(self): 648 | self.fn = "0a8.txt" 649 | self.size = 16 650 | VM_Bt.__init__(self) 651 | 652 | class VM_0a9(VM_Bt): 653 | def __init__(self): 654 | self.fn = "0a9.txt" 655 | self.size = 32 656 | VM_Bt.__init__(self) 657 | 658 | 659 | class VM_Btc(VM_Inst_With_Suff): 660 | def __init__(self): 661 | self.mnem = "btc" 662 | VM_Inst_With_Suff.__init__(self) 663 | 664 | class VM_0ab(VM_Btc): 665 | def __init__(self): 666 | self.fn = "0ab.txt" 667 | self.size = 16 668 | VM_Btc.__init__(self) 669 | 670 | class VM_0ac(VM_Btc): 671 | def __init__(self): 672 | self.fn = "0ac.txt" 673 | self.size = 32 674 | VM_Btc.__init__(self) 675 | 676 | 677 | class VM_Btr(VM_Inst_With_Suff): 678 | def __init__(self): 679 | self.mnem = "btr" 680 | VM_Inst_With_Suff.__init__(self) 681 | 682 | class VM_0af(VM_Btr): 683 | def __init__(self): 684 | self.fn = "0af.txt" 685 | self.size = 16 686 | VM_Btr.__init__(self) 687 | 688 | class VM_0b0(VM_Btr): 689 | def __init__(self): 690 | self.fn = "0b0.txt" 691 | self.size = 32 692 | VM_Btr.__init__(self) 693 | 694 | 695 | class VM_Bts(VM_Inst_With_Suff): 696 | def __init__(self): 697 | self.mnem = "bts" 698 | VM_Inst_With_Suff.__init__(self) 699 | 700 | class VM_0b3(VM_Bts): 701 | def __init__(self): 702 | self.fn = "0b3.txt" 703 | self.size = 16 704 | VM_Bts.__init__(self) 705 | 706 | class VM_0b4(VM_Bts): 707 | def __init__(self): 708 | self.fn = "0b4.txt" 709 | self.size = 32 710 | VM_Bts.__init__(self) 711 | 712 | 713 | class VM_Sbb(VM_Inst_With_Suff): 714 | def __init__(self): 715 | self.mnem = "sbb" 716 | VM_Inst_With_Suff.__init__(self) 717 | 718 | class VM_0b7(VM_Sbb): 719 | def __init__(self): 720 | self.fn = "0b7.txt" 721 | self.size = 8 722 | VM_Sbb.__init__(self) 723 | 724 | class VM_0b8(VM_Sbb): 725 | def __init__(self): 726 | self.fn = "0b8.txt" 727 | self.size = 16 728 | VM_Sbb.__init__(self) 729 | 730 | class VM_0b9(VM_Sbb): 731 | def __init__(self): 732 | self.fn = "0b9.txt" 733 | self.size = 32 734 | VM_Sbb.__init__(self) 735 | 736 | 737 | class VM_Mul(VM_Inst_With_Suff): 738 | def __init__(self): 739 | self.mnem = "mul" 740 | VM_Inst_With_Suff.__init__(self) 741 | 742 | class VM_0bb(VM_Mul): 743 | def __init__(self): 744 | self.fn = "0bb.txt" 745 | self.size = 8 746 | VM_Mul.__init__(self) 747 | 748 | class VM_0bc(VM_Mul): 749 | def __init__(self): 750 | self.fn = "0bc.txt" 751 | self.size = 16 752 | VM_Mul.__init__(self) 753 | 754 | class VM_0bd(VM_Mul): 755 | def __init__(self): 756 | self.fn = "0bd.txt" 757 | self.size = 32 758 | VM_Mul.__init__(self) 759 | 760 | 761 | class VM_Imul1(VM_Inst_With_Suff): 762 | def __init__(self): 763 | self.mnem = "imul1" 764 | VM_Inst_With_Suff.__init__(self) 765 | 766 | class VM_0bf(VM_Imul1): 767 | def __init__(self): 768 | self.fn = "0bf.txt" 769 | self.size = 8 770 | VM_Imul1.__init__(self) 771 | 772 | class VM_0c0(VM_Imul1): 773 | def __init__(self): 774 | self.fn = "0c0.txt" 775 | self.size = 16 776 | VM_Imul1.__init__(self) 777 | 778 | class VM_0c1(VM_Imul1): 779 | def __init__(self): 780 | self.fn = "0c1.txt" 781 | self.size = 32 782 | VM_Imul1.__init__(self) 783 | 784 | 785 | class VM_Div(VM_Inst_With_Suff): 786 | def __init__(self): 787 | self.mnem = "div" 788 | VM_Inst_With_Suff.__init__(self) 789 | 790 | class VM_0c3(VM_Div): 791 | def __init__(self): 792 | self.fn = "0c3.txt" 793 | self.size = 8 794 | VM_Div.__init__(self) 795 | 796 | class VM_0c4(VM_Div): 797 | def __init__(self): 798 | self.fn = "0c4.txt" 799 | self.size = 16 800 | VM_Div.__init__(self) 801 | 802 | class VM_0c5(VM_Div): 803 | def __init__(self): 804 | self.fn = "0c5.txt" 805 | self.size = 32 806 | VM_Div.__init__(self) 807 | 808 | 809 | class VM_Idiv(VM_Inst_With_Suff): 810 | def __init__(self): 811 | self.mnem = "idiv" 812 | VM_Inst_With_Suff.__init__(self) 813 | 814 | class VM_0c7(VM_Idiv): 815 | def __init__(self): 816 | self.fn = "0c7.txt" 817 | self.size = 8 818 | VM_Idiv.__init__(self) 819 | 820 | class VM_0c8(VM_Idiv): 821 | def __init__(self): 822 | self.fn = "0c8.txt" 823 | self.size = 16 824 | VM_Idiv.__init__(self) 825 | 826 | class VM_0c9(VM_Idiv): 827 | def __init__(self): 828 | self.fn = "0c9.txt" 829 | self.size = 32 830 | VM_Idiv.__init__(self) 831 | 832 | 833 | class VM_Neg(VM_Inst_With_Suff): 834 | def __init__(self): 835 | self.mnem = "neg" 836 | VM_Inst_With_Suff.__init__(self) 837 | 838 | class VM_0cf(VM_Neg): 839 | def __init__(self): 840 | self.fn = "0cf.txt" 841 | self.size = 8 842 | VM_Neg.__init__(self) 843 | 844 | class VM_0d0(VM_Neg): 845 | def __init__(self): 846 | self.fn = "0d0.txt" 847 | self.size = 16 848 | VM_Neg.__init__(self) 849 | 850 | class VM_0d1(VM_Neg): 851 | def __init__(self): 852 | self.fn = "0d1.txt" 853 | self.size = 32 854 | VM_Neg.__init__(self) 855 | 856 | 857 | class VM_Not(VM_Inst_With_Suff): 858 | def __init__(self): 859 | self.mnem = "not" 860 | VM_Inst_With_Suff.__init__(self) 861 | 862 | class VM_0d3(VM_Not): 863 | def __init__(self): 864 | self.fn = "0d3.txt" 865 | self.size = 8 866 | VM_Not.__init__(self) 867 | 868 | class VM_0d4(VM_Not): 869 | def __init__(self): 870 | self.fn = "0d4.txt" 871 | self.size = 16 872 | VM_Not.__init__(self) 873 | 874 | class VM_0d5(VM_Not): 875 | def __init__(self): 876 | self.fn = "0d5.txt" 877 | self.size = 32 878 | VM_Not.__init__(self) 879 | 880 | -------------------------------------------------------------------------------- /vmi_top_common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from config import * 3 | 4 | #for arithmetic ops: 5 | #e1 = s.pop() 6 | #e2 = s.pop() 7 | #e = e1 op e2 8 | #s.push(e) 9 | #s.push(new eflags) 10 | REG_DICT = {0: "ebp", 1: "ebx", 2: "ecx", 3: "edi", 4: "esi", 5: "edx", 6: "eax", 7: "eflags"} 11 | 12 | class VM_Instruction: 13 | def __init__(self): 14 | if hasattr(self, "fn"): #fn is defined only in subclasses 15 | self.src = self.load_src(self.fn) 16 | name = self.__class__.__name__ 17 | vid = name.replace("VM_", "") 18 | self.vid = vid 19 | self.param = None 20 | 21 | def load_src(self, fn): 22 | fn = os.path.join(CLEAN_HANDLERS_DIR, fn) 23 | f = open(fn) 24 | src = f.read() 25 | f.close() 26 | return src 27 | 28 | def disasm(self, param=None): 29 | o = "%s"%(self.vid) 30 | if param != None: 31 | o += " param: %s"%hex(param) 32 | return o 33 | 34 | def pre_disasm(self): 35 | vid = self.vid 36 | param = self.param 37 | param_size = self.param_size 38 | off = self.code_off 39 | 40 | param_s = "" 41 | if param != None: 42 | if param_size == 1: param_s = "%02x"%param 43 | elif param_size == 2: param_s = "%04x"%param 44 | elif param_size == 4: param_s = "%08x"%param 45 | else: assert(False) 46 | 47 | if param != None: 48 | s = "%s[%s]"%(vid, param_s) 49 | else: 50 | s = vid 51 | 52 | sep = "\t\t" 53 | if param_size == 4: 54 | sep = "\t" 55 | 56 | o = "0x%08x %s%s"%(off, s, sep) 57 | return o 58 | 59 | def all_disasm(self): 60 | pre = self.pre_disasm() 61 | dis = self.disasm(self.param) 62 | s = "%s %s"%(pre, dis) 63 | return s 64 | 65 | def is_halt(self): 66 | return False 67 | 68 | def affects_ctx(self): 69 | return False 70 | 71 | def is_branch(self): 72 | assert(False) 73 | 74 | #only IFJMP will have these 2 methods below 75 | def true_branch(self): 76 | assert(False) 77 | 78 | def false_branch(self): 79 | assert(False) 80 | 81 | class VM_Inst_With_Suff(VM_Instruction): 82 | def __init__(self): 83 | assert(hasattr(self, "mnem")) 84 | assert(self.size in [8, 16, 32]) 85 | self.size_dict = {8: "byte", 16: "word", 32: "dword"} 86 | VM_Instruction.__init__(self) 87 | 88 | def disasm(self, param): 89 | size = self.size_dict[self.size] 90 | o = "%s %s"%(self.mnem, size) 91 | return o 92 | 93 | -------------------------------------------------------------------------------- /vmis.txt: -------------------------------------------------------------------------------- 1 | # handler classification w.r.t. operand size (byte, word, dword) 2 | # format: 3 | # mnemonic;top class name;n1,n2,n3;custom disasm line 4 | # if only n1 is present, n2=n1+1, n3=n2+1 5 | # if only two values are present (like ;n1,n2;) they are interpreted as word,dword variants (there will be no byte variant) 6 | # if top class name is not present, it is set to "VM_Mnemonic" 7 | # 8 | # everything after # is ignored 9 | # 10 | #movsx;;080,081,085; strange size combinations 11 | 12 | load;load const;002;d += " %s"%hex(param) 13 | load;load addr;00a;d += " [addr]" 14 | load;load reg;00e,00f,007;d += " %s"%REG_DICT[param] 15 | load;load ptr;011,012,20c;d += " [%s]"%hex(param) 16 | store;store addr;016;d += " [addr]" 17 | store;store reg;01a;d += " %s"%REG_DICT[param] #storeZX 18 | store;store ptr;01e;d += " [%s]"%hex(param) 19 | add;;022; 20 | sub;;027; 21 | imul2;;02c,02d; 22 | adc;;02f; 23 | and;;033; 24 | cmp;;037; 25 | xor;;03b; 26 | or;;03f; 27 | test;;043; 28 | inc;;053; 29 | rcl;;057; 30 | rcr;;05b; 31 | rol;;05f; 32 | ror;;063; 33 | sar;;06b; 34 | shl;;067; 35 | shr;;073; 36 | dec;;077; 37 | bt;;0a8,0a9; #word, dword? FIXME? 38 | btc;;0ab,0ac; #word, dword? FIXME? 39 | btr;;0af,0b0; #word, dword? FIXME? 40 | bts;;0b3,0b4; #word, dword? FIXME? 41 | sbb;;0b7; 42 | mul;;0bb; 43 | imul1;;0bf; 44 | div;;0c3; 45 | idiv;;0c7; 46 | neg;;0cf; 47 | not;;0d3; 48 | --------------------------------------------------------------------------------