Fix simple_x64 REX for python3

This commit is contained in:
hakril
2020-02-05 23:57:34 +01:00
parent 2f778b69f9
commit bac3dcb55b
5 changed files with 73 additions and 14 deletions
+16 -5
View File
@@ -8,6 +8,8 @@ import windows.native_exec.simple_x64 as x64
from windows.native_exec.simple_x64 import *
del Test # Prevent pytest warning
from windows.pycompat import int_types
if capstone:
disassembleur = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64)
disassembleur.detail = True
@@ -27,8 +29,6 @@ def disas(x):
mnemonic_name_exception = {'movabs': 'mov'}
class CheckInstr(object):
def __init__(self, instr_to_test, expected_result=None, immediat_accepted=None, must_fail=None, debug=False):
self.instr_to_test = instr_to_test
@@ -87,7 +87,7 @@ class CheckInstr(object):
raise AssertionError("Expected args {0} operands got {1}".format(op_args, capres_op))
if op_args.lower() != capres.reg_name(cap_op.reg).lower():
raise AssertionError("Expected register <{0}> got {1}".format(op_args.lower(), capres.reg_name(cap_op.reg).lower()))
elif isinstance(op_args, (int, long)):
elif isinstance(op_args, int_types):
if (op_args != cap_op.imm) and not (self.immediat_accepted and self.immediat_accepted == cap_op.imm):
raise AssertionError("Expected Immediat <{0}> got {1}".format(op_args, cap_op.imm))
elif isinstance(op_args, mem_access):
@@ -272,13 +272,18 @@ def test_assembler():
CheckInstr(Add, must_fail=True)('RAX', 0xffffffff)
# Test some prefix / REP
assert (x64.Rep + x64.Nop()).get_code() == b"\xf3\x90"
assert (x64.GSPrefix + x64.Nop()).get_code() == b"\x65\x90"
assert (x64.OperandSizeOverride + x64.Nop()).get_code() == b"\x66\x90"
assert (x64.Repne + x64.Nop()).get_code() == b"\xf2\x90"
code = MultipleInstr()
code += Nop()
code += Rep + Nop()
code += Ret()
print(repr(code.get_code()))
assert code.get_code() == "\x90\xf3\x90\xc3"
assert code.get_code() == b"\x90\xf3\x90\xc3"
def test_simple_x64_raw_instruction():
# Test the fake instruction "raw"
@@ -296,8 +301,14 @@ def test_x64_multiple_instr_add_instr_and_str():
res += "ret; ret; label :offset_3; ret"
res += x64.Nop()
res += x64.Label(":offset_5")
assert res.get_code() == "\x90\xc3\xc3\xc3\x90"
assert res.get_code() == b"\x90\xc3\xc3\xc3\x90"
assert res.labels == {":offset_3": 3, ":offset_5": 5}
def test_x64_instr_multiply():
res = x64.MultipleInstr()
res += (x64.Nop() * 5)
res += x64.Ret()
assert res.get_code() == b"\x90\x90\x90\x90\x90\xc3"
if __name__ == "__main__":
test_assembler()
+11 -3
View File
@@ -9,6 +9,8 @@ import windows.native_exec.simple_x86 as x86
from windows.native_exec.simple_x86 import *
del Test # Prevent pytest warning
from windows.pycompat import int_types
VERBOSE = False
if capstone:
@@ -77,7 +79,7 @@ class CheckInstr(object):
raise AssertionError("Expected args {0} operands got {1}".format(op_args, capres_op))
if op_args.lower() != capres.reg_name(cap_op.reg).lower():
raise AssertionError("Expected register <{0}> got {1}".format(op_args.lower(), capres.reg_name(cap_op.reg).lower()))
elif isinstance(op_args, (int, long)):
elif isinstance(op_args, int_types):
if (op_args != cap_op.imm) and not (self.immediat_accepted and self.immediat_accepted == cap_op.imm):
raise AssertionError("Expected Immediat <{0}> got {1}".format(op_args, cap_op.imm))
elif isinstance(op_args, mem_access):
@@ -226,7 +228,7 @@ def test_assembler():
code += Rep + Nop()
code += Ret()
print(repr(code.get_code()))
assert code.get_code() == "\x90\xf3\x90\xc3"
assert code.get_code() == b"\x90\xf3\x90\xc3"
def test_simple_x64_raw_instruction():
# Test the fake instruction "raw"
@@ -239,9 +241,15 @@ def test_x86_multiple_instr_add_instr_and_str():
res += "ret; ret; label :offset_3; ret"
res += x86.Nop()
res += x86.Label(":offset_5")
assert res.get_code() == "\x90\xc3\xc3\xc3\x90"
assert res.get_code() == b"\x90\xc3\xc3\xc3\x90"
assert res.labels == {":offset_3": 3, ":offset_5": 5}
def test_x86_instr_multiply():
res = x86.MultipleInstr()
res += (x86.Nop() * 5)
res += x86.Ret()
assert res.get_code() == b"\x90\x90\x90\x90\x90\xc3"
if capstone is None:
test_assembler = pytest.mark.skip("Capstone not installed")(test_assembler)
+40 -3
View File
@@ -1,8 +1,19 @@
import sys
import collections
import struct
import binascii
DEBUG = False
# py3
is_py3 = (sys.version_info.major >= 3)
if is_py3:
basestring = str
int_types = int
else:
int_types = (int, long)
class BitArray(object):
def __init__(self, size, bits):
self.size = size
@@ -73,6 +84,16 @@ class BitArray(object):
def copy(self):
return type(self)(self.size, self.array)
def __eq__(self, other):
if not isinstance(other, BitArray):
return NotImplemented
return self.array == other.array
def __ne__(self, other):
if not isinstance(other, BitArray):
return NotImplemented
return self.array != other.array
# Prefix
class Prefix(object):
@@ -84,9 +105,15 @@ class Prefix(object):
def __add__(self, other):
return type(self)(other)
def get_code_py3(self):
return bytes([self.PREFIX_VALUE]) + self.next.get_code()
def get_code(self):
return chr(self.PREFIX_VALUE) + self.next.get_code()
if is_py3:
get_code = get_code_py3
def create_prefix(name, value):
prefix_type = type(name + "Type", (Prefix,), {'PREFIX_VALUE': value})
@@ -763,6 +790,9 @@ class Instruction(object):
default_rex = BitArray.from_int(8, 0x40)
def __init__(self, *initial_args):
# if (type(self) is Push):
# import pdb;pdb.set_trace()
for type_encoding in self.encoding:
args = list(initial_args)
res = []
@@ -783,7 +813,7 @@ class Instruction(object):
continue
self.prefix = prefix
self.value = sum(res, BitArray(0, ""))
if str(full_rex.dump()) != "\x40":
if full_rex != self.default_rex:
self.value = full_rex + self.value
return
raise ValueError("Cannot encode <{0} {1}>:(".format(type(self).__name__, initial_args))
@@ -792,8 +822,15 @@ class Instruction(object):
prefix_opcode = b"".join(chr(p.PREFIX_VALUE) for p in self.prefix)
return prefix_opcode + bytes(self.value.dump())
def get_code_py3(self):
prefix_opcode = b"".join(bytes([p.PREFIX_VALUE]) for p in self.prefix)
return prefix_opcode + bytes(self.value.dump())
if is_py3:
get_code = get_code_py3
def __mul__(self, value):
if not isinstance(value, (int, long)):
if not isinstance(value, int_types):
return NotImplemented
res = MultipleInstr()
for i in range(value):
@@ -1071,7 +1108,7 @@ class Raw(Instruction):
if len(initial_args) != 1:
raise ValueError("raw 'opcode' only accept one argument")
# Accept space
self.data = initial_args[0].replace(" ", "").decode("hex")
self.data = binascii.unhexlify(initial_args[0].replace(" ", ""))
def get_code(self):
return self.data
+6 -2
View File
@@ -1,11 +1,15 @@
import sys
import collections
import struct
import binascii
# py3
is_py3 = (sys.version_info.major >= 3)
if is_py3:
basestring = str
int_types = int
else:
int_types = (int, long)
class BitArray(object):
def __init__(self, size, bits):
@@ -633,7 +637,7 @@ class Instruction(object):
# return res
def __mul__(self, value):
if not isinstance(value, (int, long)):
if not isinstance(value, int_types):
return NotImplemented
res = MultipleInstr()
for i in range(value):
@@ -910,7 +914,7 @@ class Raw(Instruction):
if len(initial_args) != 1:
raise ValueError("raw 'opcode' only accept one argument")
# Accept space
self.data = initial_args[0].replace(" ", "").decode("hex")
self.data = binascii.unhexlify(initial_args[0].replace(" ", ""))
def get_code(self):
return self.data
-1
View File
@@ -54,7 +54,6 @@ class PipeConnection(object): # Cannot inherit: crash the interpreter
gdef.PIPE_UNLIMITED_INSTANCES, cls.BUFFER_SIZE, cls.BUFFER_SIZE,
gdef.NMPWAIT_WAIT_FOREVER, security_attributes
)
import pdb;pdb.set_trace()
return cls.from_handle(pipehandle, name=addr, server=True)
@classmethod