VM Reverse Engineering Part 2 - Disassembly
Wring a simple disassembler for our VM instruction set
Overview
This is a continuation of our previous work on Zeus VM. After reverse engineering the VM instruction handlers are now going to create an instruction set representation in python which will be our first step in creating a disassembler.
CODE_HEX = '1a09029c96ff81020089249a881f8cc1ecfff903bc02414b249015aa648ad582c81d3615e6a6ee5c6bf9ab6fec5d09e3da29c71a0178ea5d76bc302819ba41474563b987c556f06aad9809c9b86c44bc4fafc9fede01008a518fe191d47d3881bf24a74bf05b6bd82e95bec48930e73714e72b8cf81be623ffaecdf2d694b9dd1d7ad773fd1cde891dd1bf31f3d676ab0528a0d45a05dd4cd75d6ece255154538218a7b761beebb01ac9e5b3569105a50655c156f2058ec4035752e405e27ca367cf0567b7e224f6050aa605ec38d97bffeeb0fe8104a70ea6d8702fa604debb0e8a31c0799904d170b0047ebf047d9d04b256413ece04f996a3eea9048d759f04bb0e268a0bd2234b09cf0bf1b20b801dc30e962cf50b43a4bc0eb5d00e7e9a0e3b1de3bee70e91fabc0ead0d200ca20f19378db5820de053be729e0f8bed0f28e2ff820d7c79d07d88ffb6dd8fffa50fd60715786465a703b3ae07c939fd7de60735139b07cb02ecc2bb3b970b4a189cbef40969ee07d4c64107a909fa907bc19bd60bd2158b37ff03b4fb1423ae07c109d2ff0167c5e502c36c8dbdcf19b4099fd719c309e09e99d4026bf73db58f09d00557e14e04c905c0fe8875ce05d61a8a05728555fe056215c7dbad0b78ccde05e00b00880af7c4ccaaf4aaee0a7be29a38ccaae0a4c60aa21ea20ba90ce4c7d2bcf80b73d3e105f1075a4ae477cd77bb0b28d30bb9f4ccfe0732d3eacc8cb7e57cd70bb704dda5dd06eaee04af7c0c6702d699d4b7c32a55ebfefe2651e18e51474e2e3c4fdacedbcc829663994d359c2f18bfe9b6a678e6db034557067661dbd17f6490436e7bc06e2e8389a47ced889fbe4bebc88d1d66c6f317952edf8268164c1179aa3df2afa40a4278903cd5d631dccc9022a4ceb5471c156a0010cd9cc18be07d01b85fb38bade4900eaf0371e433ec33e2e3a30f3ca9ef850738c2c354bcefaeffb2e7de074d910e94d2f39f0e53055733de0f7cb6a477c637f00e95d8f7c33fe703aeef0eceb973ad0eb20ce23de20bbfa30b7a9e0b8148f6bcd90b15f10c16ced20b880dae03e3369766eb33880d07c0f333960d2318a6e18d0d75b2d38cd3cf0db1077bd7f8015168ff07c020f40714f5d3fcad71be01bbc20749d09077a2014bb307166a06a6810148a11cc5ac07c8cabd06a707899967d60672d0dd15c667fb06b08c8801b901a18d09b9959472bc19d209d18f0920dbc609d90b0a01046d00c6ba5a8c5d937cc46fdd07a60254ce22fd22d30209ee07027d429dae073f71dc0790dee0229e72ac07bfc1fef00baa0233b00b843ef80283ffb2c622940bb60c0fda039683cccd085ecdf0082e9880086687b53296c5ea0c6fa9ccbf080e59491ea00562a7c89105dceee8058718abccbc8cbb08e600d6088d95d400275ef800e2b40d9e5d71a591dbba0b780ed56c8600e49d00b74be0bbc60d32e751daca00d1bbeddbf300a50000820c07879419b60b1030a7bcda0eb6691ddaa80bb0c9156ca30b9de6fb0bc1d4c50d6dc3005bdb005dd4e00dbf00d1b3c8d296dbbd4a8fb28c2763d854e7e9b119b2eaafe99d4d370cbc815a35ddd902d9ca8c4115173bb64258ab8e246782e4383dc6883045a27e9ae6035930c0d528bc112115863db19d903f000e325ac03f8fea1eaafc9040f538722d236e12d40adb4b42d81b56a06d291b430475edb9c58d4801f17e3093c070ee2ccb108a287986321680b230f3375c9804172a78f97e87736441f0669c698c54efccab07426d5083d9072b85174fc707c302a30f03992ff02fdc0217b4cc5ba32fd62fc0ffcb02bf08bcc168e48e00948800c4a8008cf3a3e9b7ef027688cd22f62884029aec90228e02ae96f7d3fde20aa80d9bf49b0cc5d5dced0aaf1756f89c0a7d8ead8eacd6ddf2add70aed15c60d68768ebbf90c66adcdec0aa47cff2d8a04a60b91bbaeba8c0425f90423e30b660e4488dcbbed4be004f4b4258d91048c3b7af7ec0490a15f619c04eb90040ec5090ced27ede104e40200800572ac712ac20873f19154c101dfc585c605e36de0569d01f79305c728b80801eb85850ccd0046cbce0190f601b2c318d3589bcc9281d80cbbdaa76b8b08679f01c86b2709d601f73fad0179ebfa068e58a306613c9616c20a8e8f06c081061ef906d3aae406a614e406c6081c72cb060168df1bac0a513e8534daa1cf065b9ced01b1cc0ab177e876d506800a88039288a3f7a3ff0a9c068401899961de19eb69d20648bcb506bcb4df368c062cc069af19cf19ac19c799bb11c399da99b206da9401f1b806f54fac06c61ba62da3dd3b3ba7139e66c7e6142096fc1589faae43e6371fa572a82fffeb8c01e66a88c4d70e83b3aa01ec6aa8d28701d14535c6323b7610aafc976af3b7da0f1da68b257048d6e1bcdcd970f0a5e87b7ace6892e8c415a02c1b1c49a777de00c28b0554e22c2434961a30d08e0f7cb4cb9839ce73a72ddd952ffeb6fb5a32a5fe0f419672e210ef5bee15d56995e3a30eb8c0e6582814c15126c7a974469fd70f82f8f685b4959dcc3cd5a73db435f4a609b2f0800db1a85583427a0250c285a8298bcb96d5210d3f30faef32b2641ec00c71ce3b2b4241afd6e23e33dab2c87fe40f43550bcea83b15b768537699a439cbe476d8ddab4fdf0780218cfa9919bbf085be70e89e14f716fcbc4e06098e263596d1650dd9f78c7a4d97e6256ffbf77e2ab617e5f1741db48e2464ad6df1c52f5b783d2eef52283514f08339faaab8230920b5918d939d010923647c0bb44b37e10e4cae80c0b3555966f1134e85791ec3e22b5736e1f11a2f52a56d038b0f00ea65f59ff657e0e40f97a6b312a70a6041801ed108fef6c98ad78ff40f798903ecaddf084f841043e308d042abf39c08ffa50f9be5ace1f90861cccb0f874be208beb8e5b40fac09ee64cdbaed0f33d399c499caf9a899f50fb2755151b299adf9baf9bc0fc18009f684f9a20fd0db2832ff0f05b1af0f491edb0fb0091eb00dd1d20933f9d00d155eeb0d3e31e10d1fe20df440c4e1980de1e07c7b463a18ca0ca13b1144a5c54784538679876d87398ad38be0eef2e748dc1546905c8c920e81a796bb02817efcc9eb62c89b25399bbe0c401f8e59cef9e2e246028a2324a6c9b2d9876d6f0f7fe9cfe0c889c1cc0cf36e893b478ad4a67452b1c328c6366d82cf23893a2d60014ac8aacfd3907877f82584ce3ff97930d075778f484c954b0053ba63126865acde0206e13993b9e5074847edf9c329fe7e540b01f1473b06ab05df350f20256417f190009bdf2e5fc456fa0c59b8ac888338c525469c1c75f296fd61c3400882e0cd776c0e39cff65951c98559b46f92267fe9a7c9f509aa0b762a91a8f39bfd0a02af24c58b9ac10b6a3e6139d29be30956420e8fd809d416e609b40a9908b14ea905353cd5f7b8a9fb0682a9ba96da0ab4d109a8ce0523dd96cb668a65b70adf8105cef2b8569a0968920aece5c70a21b57228af06039ecc06f18fbc54d5d87cfecc0ba8079407aa77cc77fc0bcc06a60fc5c406f5bcffd664ea06c100a00d39a00de901f4d908ef6dd411c0d8b608b70041db2230a100d1ec4d12d418cb8dd70db6c708da00bbfa0114ea18cd01bddc118e00e70eede1e994e8ee8a06e2f36498061383ec0631c90682125d12920edf8bf60e04d7ac0e61b50ed009008a01787dfa07efcaa6edec01b1e7045338705cd104571db90ee7e40772358a74af048c0916009e04b20e927bbae7a30ef7697160c507b790481f840e0be604d78a8a7317b608aa0dbed9bc07e8807ae5f30d63f9bca9948dddd79d77bd0df682f309b5c77f32b4086a0148a7d1d7f1086bf6ab07c10af4087a9a094fbb844cbbdd968dc277d608bc8a2b0610b9fd4e21a3e6a1f8bc76f8bee8820feaf1b90a2e763ecc39308dbdbeba137da1da45cc7b475152a8011f3a0b9262ee506084c7933225ee0e3a74cf9bcbfa6ceff1f127c0bb42c861dd068cf720fecf22c7508165e9a20f93e70f1bedd7e45040c79a606b7c62a96318637f0d28be26de6999ff54fd0e740b0f6e56fdb8837176ad63367b4a302cc0d101f14ec911d911e911ee071a0628ff9117f3018069c201a88469efb001c300a00a75ee0ae500addd07e3d5d100d9a200f4837aa700fd4ab76dd08906a50593dcab559a0629d75588658665de06e26501df2c274a8fccc2cdc9ad7c9852e6da0d3b80263c1fcba0fe6ce667d728a5d75ad1fe0e2e74790451fcf73e02476fb89979fdc809ab0fb5eb9b09beeabb040e6ca08c8d0f9ae3091844fa04cc0bb333caffb894b84fee448d04a89ed0448b94b509b30300800bb9f7900b684ec3ba840be7a89b6b4c569816733225425ff5c8a17a3d0acb499171560e261dc0395be11d1ef0c3a56bc9eea6902aef22be68c818d41ab8c691311c8f9489ee17e88b5d54dac4ccf42b498de4b031123e8248a8da2cdef9d5230232eb6057820a8b14174bf23275a2c4ed2dc5c3c6fac15010135d6528ebca8df1d46cf610cc495f88332d1c3f9a70e114646a3f9accdcfb8bfc543315249f29e10eaa68dfd5b5150ac72c25335f6f56f0529b0ff748b9b9810f8d0c12be003845e590b00ca0f0e403822d032c990f9193fe0ae8c0b203e88c0fd05db003324d9c0333dace99cd0fe98d0fec4f9900c50fb3a4d40fa78c0f8dde3cd30f42883cd90fede70fc395fdda07850420a207829334338e041ce507a8819807c9090082783a6aed9aa1f8ccae3405401e6535007d10d490c185cd1d7b22fda4477944d39b2f03cad9ba1f8d768a2dce5f682dbc09a3e08055cba491ecc6ab6e19aab9ddabf2052d55c1c2da86687821586c8ed241cda64016f0d7fc73163f57d593342ade542961464d9e7c3aa128ff1c041e40557f273679ea425bbc48b87d9fc4fcd302009d64555bd3fe602859a6e784df7fcd93b3b8820eb9a118cb49e3f2931562943b801975f2997450822cc595db2312b746b3084543a56142a791a5e47812564ce8ae9b4ee9f7afdb268aa187184e8de45971313d49f4bc11f64663abd317172c544c63d21d5afd3c959c099b00c146f200df5991a1e308c209f81cffe9fa092411f80806cf0bdec000c75c9a001e36e25caa98f609d151ed8bd008a74b1969960b7301ad083b44ec99fb0bda08e30fcd5f418731950173ef12e77508c99ff08dc0b0b2c08a8bf00c8d01f64dc011b80ccc1b27100a4fac18772770ed0591879605948fc8f1ef8099912500f93c19e60fac0bf169d80f6855c2858a0f2e779a0f256eca2b9ffb930733a7fbdd0fe813a80f3cde8e7b8b07e7d8a60f12d7b7ee0f0124d90fe17902d780c998cd76bc7d1d6dc7a2897a24ed4bb67a83e8a61950bafffae8bc0878f3d4967adb4d6421bad86104bfa731b1316b382650a7ddb2f17185ad6459ab524e1ba8a9ddd5c8adeb84ea5a586b82be5e39444a53acdb446aa642182f86b57e581981454f858589f7f1ab58f66a73e8f29c94f636db2c8bda99a003a20077ea03e99373b4df00d200f7091e9f03fcb430e030cd01ddc909c303a8d1d8078701db8817f5de11c50740f39e07c2d5ae04ad17c4f3a8418a0709c344a0019f27c4718541870767e0532af5078a6f7f368311ab07daaedec0d8c1027a57c322f60868e102d90d2f820e11bc91045dc54d890e29d93357904e9a0ef3d94ff08f0dd271950dc4f64db2b0e4add484d4eb0458a04d20a50e41a70e95ee04bfd304c40000000000'
CODE = bytes.fromhex(CODE_HEX)
Manual Instruction Decoding (test)
1a 09 02 9c 96 ff 81 02 00
- current_key: 0
- opcode: 1a
- opcode decrypted: 1a
- instruction: h_shift_data_imm_w
- op_key: 09
- key: 8f ^ 09 = 0x86
- size: 3
- instruction: 1a 09 02
9c 96 ff 81 02 00
- current_key: 86
- opcode: 9c
- opcode decrypted: 1a
- instruction: h_shift_data_imm_w
- op_key: 96
- key: 8f ^ 96 = 0x19
- size: 3
- instruction: 9c 96 ff
81 02 00
- current_key: 19
- opcode: 81
- opcode decrypted: 98 XXXXX (should be 18)
- instruction: h_rol_b_data_b
- op_key: 0
- key: 0xC ^ 96 = 0x9a
- size: 2
- instruction: 9c 96
from enum import Enum
import struct
class LoopCounter:
text = "LoopCounter"
class Data:
text = "Data"
class DP:
text = "DP"
class PC:
text = "PC"
class OPKey:
text = "OPKey"
def create_register_class(register_name):
class Register:
text = register_name
return Register
registers = [ create_register_class("Reg" + str(i))() for i in range(0,16)]
class DataSize:
def __init__(self, value):
self.value = value
@classmethod
def BYTE(cls):
return cls(1)
@classmethod
def WORD(cls):
return cls(2)
@classmethod
def DWORD(cls):
return cls(4)
def __str__(self):
if self.value == 1:
return 'BYTE'
elif self.value == 2:
return 'WORD'
elif self.value == 4:
return 'DWORD'
else:
return f'VALUE({self.value})'
class Operand:
def __init__(self):
self.text = ""
self.op_size = 0
class OperandData(Operand):
def __init__(self, data_size: DataSize):
super().__init__()
self.op_size = 0
self.data_size = data_size
self.text = f"{self.data_size}(Data[DP])"
def parse(self, code):
pass
class OperandDP(Operand):
def __init__(self, data_size: DataSize):
super().__init__()
self.op_size = 0
self.data_size = data_size
self.text = f"{self.data_size}(DP)"
def parse(self, code):
pass
class OperandPC(Operand):
def __init__(self, data_size: DataSize):
super().__init__()
self.op_size = 0
self.data_size = data_size
self.text = f"{self.data_size}(PC)"
def parse(self, code):
pass
class OperandRegisterLow(Operand):
def __init__(self, data_size: DataSize):
super().__init__()
self.op_size = 1
self.reg_index = None
self.reg = None
self.data_size = data_size
self.text = ""
def parse(self, code):
self.reg_index = code[0] & 0x0F
self.reg = registers[self.reg_index]
self.data_size = self.data_size
self.text = f"{self.data_size}({self.reg.text})"
class OperandRegisterHigh(Operand):
def __init__(self, data_size: DataSize):
super().__init__()
self.op_size = 0
self.reg_index = None
self.reg = None
self.data_size = data_size
self.text = ""
def parse(self, code):
self.reg_index = (code[0] >> 4) & 0x0F
self.reg = registers[self.reg_index]
self.data_size = self.data_size
self.text = f"{self.data_size}({self.reg.text})"
class OperandImmediate(Operand):
def __init__(self, data_size: DataSize):
super().__init__()
self.op_size = data_size.value
self.data_size = data_size
self.value = None
self.text = ""
def parse(self, code):
int_size = self.data_size.value
if int_size == 1:
self.value = ord(code[0:int_size])
self.text = f"{self.data_size}({hex(self.value)})"
elif int_size == 2:
self.value = struct.unpack('<H', code[0:int_size])[0]
self.text = f"{self.data_size}({hex(self.value)})"
elif int_size == 4:
self.value = struct.unpack('<I', code[0:int_size])[0]
self.text = f"{self.data_size}({hex(self.value)})"
else:
self.value = code[0:int_size]
self.text = f"{self.data_size}({self.value.hex()})"
class OperandLoopCounter(Operand):
def __init__(self, data_size: DataSize):
super().__init__()
self.op_size = 0
self.text = f"LoopCounter"
def parse(self, code):
pass
class OperandBuffer(Operand):
def __init__(self, size: DataSize):
super().__init__()
self.op_size = size.value
self.value = None
self.text = ""
def parse(self, code):
self.value = code[0:self.op_size]
self.text = f"Buffer[{self.value.hex()}]"
class Instruction:
def __init__(self, code):
self.size = 0
self.text = ""
self.key = 0
self.operands = []
def parse(self, code):
for operand in self.operands:
operand.parse(code[self.size:])
self.size += operand.op_size
self.text += " " + operand.text
print("size: " + str(self.size))
print("operand count: " + str(len(self.operands)))
# Handle special case for nop of larger than one byte
if self.size > 1 and len(self.operands) == 0:
# We have real operands (bytes to skip) but no instruction operands
# Use the first byte of the first operand as key
print(f"self.key ^= code[1]({hex(code[1])})")
self.key ^= code[1]
else:
# Assumption, the first operand is never larger than 1 byte
if len(self.operands) == 0:
# Key is the opcode
print(f"self.key ^= code[0]({hex(code[0])})")
self.key ^= code[0]
elif len(self.operands) == 1:
# Check if the operand is a real operand or a fake operand
if self.operands[0].op_size != 0:
# Key is the first byte in the operand
print(f"self.key ^= code[1]({hex(code[1])})")
self.key ^= code[1]
else:
# Key is the opcode
print(f"self.key ^= code[0]({hex(code[0])})")
self.key ^= code[0]
elif len(self.operands) == 2:
# If the both operands are real operands, the key is the first byte of the second operand
if self.operands[0].op_size != 0 and self.operands[1].op_size != 0:
print(f"self.key ^= code[2]({hex(code[2])})")
self.key ^= code[2]
# If either of the operands is fake, the key is the first byte of the second operand (real operand 1)
elif self.operands[0].op_size == 0 or self.operands[1].op_size == 0:
print(f"self.key ^= code[1]({hex(code[1])})")
self.key ^= code[1]
else:
raise Exception("Invalid operands")
elif len(self.operands) == 4:
# There is only one case with more than 2 operands, rc4
# key_len, data_len, key_buff[key_len], (fake)data_buff[data_len]
# The key is the first byte in the third operand
print(f"self.key ^= code[3]({hex(code[2])})")
self.key ^= code[3]
else:
raise Exception("Invalid operands")
class nop_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "nop"
self.key = 0xC7
self.operands = []
class nop_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 2
self.text = "nop"
self.key = 0x45
self.operands = []
class nop_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 4
self.text = "nop"
self.key = 0x25
self.operands = []
class xor_data_imm_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "xor"
self.key = 0x51
self.operands = [OperandData(DataSize.BYTE()), OperandImmediate(DataSize.BYTE())]
class h_xor_data_imm_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "xor"
self.key = 0x32
self.operands = [OperandData(DataSize.WORD()), OperandImmediate(DataSize.WORD())]
class h_xor_data_imm_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "xor"
self.key = 0x7C
self.operands = [OperandData(DataSize.DWORD()), OperandImmediate(DataSize.DWORD())]
class h_add_data_imm_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "add"
self.key = 0xB4
self.operands = [OperandData(DataSize.BYTE()), OperandImmediate(DataSize.BYTE())]
class h_add_data_imm_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "add"
self.key = 0x16
self.operands = [OperandData(DataSize.WORD()), OperandImmediate(DataSize.WORD())]
class h_add_data_imm_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "add"
self.key = 2
self.operands = [OperandData(DataSize.DWORD()), OperandImmediate(DataSize.DWORD())]
class h_sub_data_imm_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "sub"
self.key = 0xC9
self.operands = [OperandData(DataSize.BYTE()), OperandImmediate(DataSize.BYTE())]
class h_sub_data_imm_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "sub"
self.key = 0xF7
self.operands = [OperandData(DataSize.WORD()), OperandImmediate(DataSize.WORD())]
class h_sub_data_imm_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "sub"
self.key = 0x71
self.operands = [OperandData(DataSize.DWORD()), OperandImmediate(DataSize.DWORD())]
class h_rol_b_data_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "rol"
self.key = 0xC
self.operands = [OperandData(DataSize.BYTE()), OperandImmediate(DataSize.BYTE())]
class h_rol_w_data_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "rol"
self.key = 0xFA
self.operands = [OperandData(DataSize.WORD()), OperandImmediate(DataSize.BYTE())]
class h_rol_dw_data_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "rol"
self.key = 0x57
self.operands = [OperandData(DataSize.DWORD()), OperandImmediate(DataSize.BYTE())]
class h_ror_b_data_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "ror"
self.key = 0x98
self.operands = [OperandData(DataSize.BYTE()), OperandImmediate(DataSize.BYTE())]
class h_ror_w_data_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "ror"
self.key = 0xD3
self.operands = [OperandData(DataSize.WORD()), OperandImmediate(DataSize.BYTE())]
class h_ror_dw_data_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "ror"
self.key = 0xFB
self.operands = [OperandData(DataSize.DWORD()), OperandImmediate(DataSize.BYTE())]
class h_not_b_data(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "not"
self.key = 0xFA
self.operands = [OperandData(DataSize.BYTE())]
class h_not_w_data(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "not"
self.key = 0x28
self.operands = [OperandData(DataSize.WORD())]
class h_not_dw_data(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "not"
self.key = 4
self.operands = [OperandData(DataSize.DWORD())]
class h_dw_data_shuffle(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "shuffle"
self.key = 0x82
self.operands = [OperandData(DataSize.DWORD()), OperandImmediate(DataSize.BYTE())]
class h_rc4(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "rc4"
self.key = 0xC9
self.operands = [OperandImmediate(DataSize.BYTE()), # key_len
OperandImmediate(DataSize.BYTE()), # data_len
OperandBuffer(DataSize(code[1])), # key_buff[key_len]
OperandData(DataSize(code[2]))] # data_buff[data_len]
class h_set_loop_imm_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "set loop"
self.key = 0x4e
self.operands = [OperandLoopCounter(DataSize.DWORD()), OperandImmediate(DataSize.BYTE())]
class h_set_loop_imm_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "set loop"
self.key = 0x9D
self.operands = [OperandLoopCounter(DataSize.DWORD()), OperandImmediate(DataSize.WORD())]
class h_set_value_imm_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "set loop"
self.key = 0x61
self.operands = [OperandLoopCounter(DataSize.DWORD()), OperandImmediate(DataSize.DWORD())]
class h_shift_data_imm_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "add"
self.key = 0x8F
self.operands = [OperandDP(DataSize.DWORD()), OperandImmediate(DataSize.WORD())]
class h_loop_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "loop"
self.key = 0xF8
# Immediate is subtracted from PC (displacement)
self.operands = [OperandPC(DataSize.DWORD()), OperandImmediate(DataSize.BYTE())]
class h_loop_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "loop"
self.key = 0x2C
# Immediate is subtracted from PC (displacement)
self.operands = [OperandPC(DataSize.DWORD()), OperandImmediate(DataSize.WORD())]
class h_mov_reg_imm_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "mov"
self.key = 0xB3
self.operands = [OperandRegisterLow(DataSize.BYTE()), OperandImmediate(DataSize.BYTE())]
class h_mov_reg_imm_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "mov"
self.key = 0x9D
self.operands = [OperandRegisterLow(DataSize.WORD()), OperandImmediate(DataSize.WORD())]
class h_mov_reg_imm_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "mov"
self.key = 0xAF
self.operands = [OperandRegisterLow(DataSize.DWORD()), OperandImmediate(DataSize.DWORD())]
class h_mov_reg_reg_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "mov"
self.key = 0xD5
self.operands = [OperandRegisterLow(DataSize.BYTE()), OperandRegisterHigh(DataSize.BYTE())]
class h_mov_reg_reg_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "mov"
self.key = 0x9D
self.operands = [OperandRegisterLow(DataSize.WORD()), OperandRegisterHigh(DataSize.WORD())]
class h_mov_reg_reg_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "mov"
self.key = 0x4C
self.operands = [OperandRegisterLow(DataSize.DWORD()), OperandRegisterHigh(DataSize.DWORD())]
class h_add_reg_reg_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "add"
self.key = 0x1F
self.operands = [OperandRegisterLow(DataSize.BYTE()), OperandRegisterHigh(DataSize.BYTE())]
class h_add_reg_reg_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "add"
self.key = 0xC9
self.operands = [OperandRegisterLow(DataSize.WORD()), OperandRegisterHigh(DataSize.WORD())]
class h_add_reg_reg_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "add"
self.key = 0xE0
self.operands = [OperandRegisterLow(DataSize.DWORD()), OperandRegisterHigh(DataSize.DWORD())]
class h_sub_reg_reg_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "sub"
self.key = 0x75
self.operands = [OperandRegisterLow(DataSize.BYTE()), OperandRegisterHigh(DataSize.BYTE())]
class h_sub_reg_reg_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "sub"
self.key = 0x8B
self.operands = [OperandRegisterLow(DataSize.WORD()), OperandRegisterHigh(DataSize.WORD())]
class h_sub_reg_reg_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "sub"
self.key = 0xDD
self.operands = [OperandRegisterLow(DataSize.DWORD()), OperandRegisterHigh(DataSize.DWORD())]
class h_xor_reg2_to_reg1_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "xor"
self.key = 0x77
self.operands = [OperandRegisterLow(DataSize.BYTE()), OperandRegisterHigh(DataSize.BYTE())]
class h_xor_reg2_to_reg1_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "xor"
self.key = 0x79
self.operands = [OperandRegisterLow(DataSize.WORD()), OperandRegisterHigh(DataSize.WORD())]
class h_xor_reg2_to_reg1_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "xor"
self.key = 0x6A
self.operands = [OperandRegisterLow(DataSize.DWORD()), OperandRegisterHigh(DataSize.DWORD())]
class h_reg_add_imm_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "add"
self.key = 0x49
self.operands = [OperandRegisterLow(DataSize.BYTE()), OperandImmediate(DataSize.BYTE())]
class h_reg_add_imm_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "add"
self.key = 0xF3
self.operands = [OperandRegisterLow(DataSize.WORD()), OperandImmediate(DataSize.WORD())]
class h_reg_add_imm_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "add"
self.key = 0x1C
self.operands = [OperandRegisterLow(DataSize.DWORD()), OperandImmediate(DataSize.DWORD())]
class h_reg_sub_imm_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "sub"
self.key = 0x54
self.operands = [OperandRegisterLow(DataSize.BYTE()), OperandImmediate(DataSize.BYTE())]
class h_reg_sub_imm_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "sub"
self.key = 0x53
self.operands = [OperandRegisterLow(DataSize.WORD()), OperandImmediate(DataSize.WORD())]
class h_reg_sub_imm_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "sub"
self.key = 0x23
self.operands = [OperandRegisterLow(DataSize.DWORD()), OperandImmediate(DataSize.DWORD())]
class h_reg_xor_imm_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "xor"
self.key = 0x6E
self.operands = [OperandRegisterLow(DataSize.BYTE()), OperandImmediate(DataSize.BYTE())]
class h_reg_xor_imm_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "xor"
self.key = 0x9A
self.operands = [OperandRegisterLow(DataSize.WORD()), OperandImmediate(DataSize.WORD())]
class h_reg_xor_imm_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "xor"
self.key = 0xD1
self.operands = [OperandRegisterLow(DataSize.DWORD()), OperandImmediate(DataSize.DWORD())]
class mw_add_reg_to_data_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "add"
self.key = 0x46
self.operands = [OperandData(DataSize.BYTE()), OperandRegisterLow(DataSize.BYTE())]
class mw_add_reg_to_data_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "add"
self.key = 0x32
self.operands = [OperandData(DataSize.WORD()), OperandRegisterLow(DataSize.WORD())]
class mw_add_reg_to_data_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "add"
self.key = 0x3D
self.operands = [OperandData(DataSize.DWORD()), OperandRegisterLow(DataSize.DWORD())]
class mw_subs_reg_from_data_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "sub"
self.key = 4
self.operands = [OperandData(DataSize.BYTE()), OperandRegisterLow(DataSize.BYTE())]
class mw_subs_reg_from_data_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "sub"
self.key = 0xDB
self.operands = [OperandData(DataSize.WORD()), OperandRegisterLow(DataSize.WORD())]
class mw_subs_reg_from_data_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "sub"
self.key = 0xC6
self.operands = [OperandData(DataSize.DWORD()), OperandRegisterLow(DataSize.DWORD())]
class mw_xor_data_with_reg_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "xor"
self.key = 0x7D
self.operands = [OperandData(DataSize.BYTE()), OperandRegisterLow(DataSize.BYTE())]
class mw_xor_data_with_reg_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "xor"
self.key = 0x71
self.operands = [OperandData(DataSize.WORD()), OperandRegisterLow(DataSize.WORD())]
class mw_xor_data_with_reg_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "xor"
self.key = 0x7A
self.operands = [OperandData(DataSize.DWORD()), OperandRegisterLow(DataSize.DWORD())]
class h_mov_data_to_reg_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "mov"
self.key = 0xBC
self.operands = [OperandRegisterLow(DataSize.BYTE()), OperandData(DataSize.BYTE())]
class h_mov_data_to_reg_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "mov"
self.key = 0x3D
self.operands = [OperandRegisterLow(DataSize.WORD()), OperandData(DataSize.WORD())]
class h_mov_data_to_reg_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "mov"
self.key = 0x9F
self.operands = [OperandRegisterLow(DataSize.DWORD()), OperandData(DataSize.DWORD())]
class mw_push_reg_to_data_b(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "mov"
self.key = 0x22
self.operands = [OperandData(DataSize.BYTE()), OperandRegisterLow(DataSize.BYTE())]
class mw_push_reg_to_data_w(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "mov"
self.key = 0xF8
self.operands = [OperandData(DataSize.WORD()), OperandRegisterLow(DataSize.WORD())]
class mw_push_reg_to_data_dw(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "mov"
self.key = 0x56
self.operands = [OperandData(DataSize.DWORD()), OperandRegisterLow(DataSize.DWORD())]
class h_vm_exit(Instruction):
def __init__(self, code):
super().__init__(code)
self.size = 1
self.text = "exit"
self.key = 0x00
self.operands = []
# Create an array of the instruction functions
instructions = [nop_b, nop_w, nop_dw, xor_data_imm_b, h_xor_data_imm_w, h_xor_data_imm_dw, h_add_data_imm_b, h_add_data_imm_w, h_add_data_imm_dw, h_sub_data_imm_b, h_sub_data_imm_w, h_sub_data_imm_dw, h_rol_b_data_b, h_rol_w_data_b, h_rol_dw_data_b, h_ror_b_data_b, h_ror_w_data_b, h_ror_dw_data_b, h_not_b_data, h_not_w_data, h_not_dw_data, h_dw_data_shuffle, h_rc4, h_set_loop_imm_b, h_set_loop_imm_w, h_set_value_imm_dw, h_shift_data_imm_w, h_loop_b, h_loop_w, h_mov_reg_imm_b, h_mov_reg_imm_w, h_mov_reg_imm_dw, h_mov_reg_reg_b, h_mov_reg_reg_w, h_mov_reg_reg_dw, h_add_reg_reg_b, h_add_reg_reg_w, h_add_reg_reg_dw, h_sub_reg_reg_b, h_sub_reg_reg_w, h_sub_reg_reg_dw, h_xor_reg2_to_reg1_b, h_xor_reg2_to_reg1_w, h_xor_reg2_to_reg1_dw, h_reg_add_imm_b, h_reg_add_imm_w, h_reg_add_imm_dw, h_reg_sub_imm_b, h_reg_sub_imm_w, h_reg_sub_imm_dw, h_reg_xor_imm_b, h_reg_xor_imm_w, h_reg_xor_imm_dw, mw_add_reg_to_data_b, mw_add_reg_to_data_w, mw_add_reg_to_data_dw, mw_subs_reg_from_data_b, mw_subs_reg_from_data_w, mw_subs_reg_from_data_dw, mw_xor_data_with_reg_b, mw_xor_data_with_reg_w, mw_xor_data_with_reg_dw, h_mov_data_to_reg_b, h_mov_data_to_reg_w, h_mov_data_to_reg_dw, mw_push_reg_to_data_b, mw_push_reg_to_data_w, mw_push_reg_to_data_dw, h_vm_exit]
def disassemble(code):
key = 0x00
ptr = 0
disassembly = []
while ptr < len(code):
op = code[ptr]
print(f"OP: {hex(op)}")
op = (op ^ key) & 0x7F
# Replace the ecrypted opcode with the decrypted one
code = code[0:ptr] + bytes([op]) + code[ptr+1:]
print(f"OP (decrypted): {hex(op)}")
if op >= len(instructions):
raise Exception(f"Invalid opcode {hex(op)}")
inst = instructions[op](code[ptr:])
print(f"INST: {type(inst).__name__}")
inst.parse(code[ptr:])
print(f"{hex(ptr)}: {op} -> {inst.text}")
disassembly.append(inst)
ptr += inst.size
key = inst.key
if inst.text == "exit":
break
return disassembly
disassembly = disassemble(CODE)
for i in disassembly:
print(i.text)