Skip to content

Commit 53554f4

Browse files
committed
Improve handling of Jmp/Call/Push/Pop
1 parent 006dce7 commit 53554f4

3 files changed

Lines changed: 62 additions & 7 deletions

File tree

tests/test_simple_x64.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,10 @@ def test_assembler():
232232

233233

234234
CheckInstr(Pop)('RAX')
235+
CheckInstr(Push, must_fail=True)('EAX')
236+
CheckInstr(Pop)('R15')
237+
CheckInstr(Pop)(mem("[ECX]"))
238+
CheckInstr(Pop)(mem("[RCX]"))
235239
assert len(Pop("RAX").get_code()) == 1
236240

237241

windows/native_exec/simple_x64.py

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ class X64(object):
153153
@staticmethod
154154
def is_reg(name):
155155
try:
156-
return (name.upper() in reg_order) or X64.is_new_reg(name) or X64.is_32b_reg(name)
156+
return X64.is_64b_reg(name) or X64.is_32b_reg(name)
157157
except AttributeError: # Not a string
158158
return False
159159

@@ -164,6 +164,13 @@ def is_new_reg(name):
164164
except AttributeError: # Not a string
165165
return False
166166

167+
@staticmethod
168+
def is_64b_reg(name):
169+
try:
170+
return (name.upper() in x64_regs)
171+
except AttributeError: # Not a string
172+
return False
173+
167174
@staticmethod
168175
def is_32b_reg(name):
169176
try:
@@ -656,6 +663,38 @@ def __init__(self, arg1, arg2, reversed, instr_state):
656663
self.setup_rm_as_register(arg1)
657664
self.direction = 0
658665

666+
class ModRM_REG64__REG64(SubModRM):
667+
"""handle Reg64 Only, used by slash(x) that do not allow 32bits/rex (push / call / jmp)"""
668+
@classmethod
669+
def match(cls, arg1, arg2):
670+
return X64.is_64b_reg(arg1) and X64.is_64b_reg(arg2)
671+
672+
def setup_reg_as_register(self, name):
673+
name = name.upper()
674+
# register IS a 64b register
675+
self.setup_as_64bit_operation()
676+
self.reg = X64RegisterSelector.get_reg_bits(name)
677+
if X64.is_new_reg(name):
678+
self.is_rex_needed = True
679+
self.rex[5] = 1
680+
681+
def setup_rm_as_register(self, name):
682+
name = name.upper()
683+
# register IS a 64b register
684+
self.setup_as_64bit_operation()
685+
686+
self.rm = X64RegisterSelector.get_reg_bits(name)
687+
if X64.is_new_reg(name):
688+
self.is_rex_needed = True
689+
self.rex[7] = 1
690+
691+
def __init__(self, arg1, arg2, reversed, instr_state):
692+
super(ModRM_REG64__REG64, self).__init__()
693+
694+
self.mod = BitArray(2, "11")
695+
self.setup_reg_as_register(arg2)
696+
self.setup_rm_as_register(arg1)
697+
self.direction = 0
659698

660699
class ModRM_REG64__MEM(SubModRM):
661700
@classmethod
@@ -772,10 +811,13 @@ def setup_reg_as_register(self, name):
772811
class Slash(object):
773812
"No idea for the name: represent the modRM for single args + encoding in reg (/7 in cmp in man intel)"
774813

775-
def __init__(self, reg_num):
814+
# only64b seems to be the contrary ok Instr.default_32_bits use this as a base ?
815+
# Make a Slash64 () ?
816+
def __init__(self, reg_num, only64b=False):
776817
"reg = 7 for /7"
777818
self.reg = reg_order[reg_num]
778819
self.reg_num = reg_num
820+
self.only64b = only64b
779821

780822
def accept_arg(self, args, instr_state):
781823
if len(args) < 1:
@@ -785,8 +827,13 @@ def accept_arg(self, args, instr_state):
785827
injected_reg = self.reg
786828
if X64.is_32b_reg(args[0]):
787829
injected_reg = registers_64_to_32_bits[injected_reg]
830+
if self.only64b:
831+
modrm_reg_reg_type = ModRM_REG64__REG64
832+
else:
833+
modrm_reg_reg_type = ModRM_REG__REG
834+
788835
try:
789-
arg_consum, value, rex = ModRM([ModRM_REG__REG, REG64__MEM_Slash], has_direction_bit=False).accept_arg(args[:1] + [injected_reg] + args[1:], instr_state)
836+
arg_consum, value, rex = ModRM([modrm_reg_reg_type, REG64__MEM_Slash], has_direction_bit=False).accept_arg(args[:1] + [injected_reg] + args[1:], instr_state)
790837
except ValueError as e:
791838
# Size mismatch
792839
return None, None, None
@@ -868,11 +915,14 @@ def __new__(cls, *initial_args):
868915
class Push(Instruction):
869916
encoding = [(RawBits.from_int(5, 0x50 >> 3), X64RegisterSelector()),
870917
(RawBits.from_int(8, 0x68), AnyImm32()),
871-
(RawBits.from_int(8, 0xff), Slash(6))]
918+
(RawBits.from_int(8, 0xff), Slash(6, only64b=True))]
872919

873920

874921
class Pop(Instruction):
875-
encoding = [(RawBits.from_int(5, 0x58 >> 3), X64RegisterSelector())]
922+
encoding = [(RawBits.from_int(5, 0x58 >> 3), X64RegisterSelector()),
923+
(RawBits.from_int(8, 0x8f), Slash(0, only64b=True))
924+
925+
]
876926

877927

878928

@@ -976,12 +1026,13 @@ class JmpImm32(JmpImm):
9761026

9771027
class Call(JmpType):
9781028
encoding = [(RawBits.from_int(8, 0xe8), JmpImm32(5)),
979-
(RawBits.from_int(8, 0xff), Slash(2))]
1029+
(RawBits.from_int(8, 0xff), Slash(2, only64b=True))]
9801030

9811031

9821032
class Jmp(JmpType):
9831033
encoding = [(RawBits.from_int(8, 0xeb), JmpImm8(2)),
9841034
(RawBits.from_int(8, 0xe9), JmpImm32(5)),
1035+
(RawBits.from_int(8, 0xff), Slash(4, only64b=True)),
9851036
(RawBits.from_int(13, 0xffe0 >> 3), X64RegisterSelector())]
9861037

9871038

windows/native_exec/simple_x86.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,6 @@ class JmpImm8(JmpImm):
698698
class JmpImm32(JmpImm):
699699
accept_as_Ximmediat = staticmethod(accept_as_32immediat)
700700

701-
702701
# Instructions
703702

704703
class Call(JmpType):
@@ -709,6 +708,7 @@ class Call(JmpType):
709708
class Jmp(JmpType):
710709
encoding = [(RawBits.from_int(8, 0xeb), JmpImm8(2)),
711710
(RawBits.from_int(8, 0xe9), JmpImm32(5)),
711+
(RawBits.from_int(8, 0xff), Slash(4)),
712712
(RawBits.from_int(8, 0xea), SegmentSelectorAbsoluteAddr())]
713713

714714

0 commit comments

Comments
 (0)