Skip to content

Commit

Permalink
add support for Intel CET_IBT (endbr/notrack)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdcht committed Mar 4, 2024
1 parent 89349a6 commit fa1eb9d
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 6 deletions.
4 changes: 4 additions & 0 deletions amoco/arch/x64/asm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1819,3 +1819,7 @@ def i_XLATB(i, fmap):
fmap[rip] = fmap[rip] + i.length
_b = fmap(mem(rbx + al.zeroextend(64), 8))
fmap[al] = _b

i_ENDBR32 = i_NOP
i_ENDBR64 = i_NOP

9 changes: 9 additions & 0 deletions amoco/arch/x64/spec_ia32e.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,8 @@ def ia32_rm64(obj, Mod, RM, data):
op1, data = getModRM(obj, Mod, RM, data, REX)
obj.operands = [op1]
obj.misc["absolute"] = True
if obj.misc['segreg'] is env.ds:
setpfx(obj, ('notrack',True), 0)
obj.type = type_control_flow


Expand Down Expand Up @@ -1089,6 +1091,13 @@ def ia32_movbe_crc32(obj, s, Mod, RM, REG, data):
obj.operands = [op1, op2]
obj.type = type_data_processing

# ENDBR (added by Intel in 2017 to protect against ROP)
@ispec_ia32("32>[ {f3}{0f}{1e}{fb} ]", mnemonic="ENDBR32")
@ispec_ia32("32>[ {f3}{0f}{1e}{fa} ]", mnemonic="ENDBR64")
def ia32_endbr(obj):
obj.operands = []
obj.type = type_cpu_state


# FPU instructions:
# -----------------
Expand Down
4 changes: 4 additions & 0 deletions amoco/arch/x86/asm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1800,3 +1800,7 @@ def i_PEXTRW(i, fmap):
else:
v = top(16)
fmap[op1] = v.zeroextend(op1.size)

i_ENDBR32 = i_NOP
i_ENDBR64 = i_NOP

5 changes: 4 additions & 1 deletion amoco/arch/x86/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def att_syntax_gen(env, CONDITION_CODES, cpu_addrsize, instruction):
"repe",
"repne",
"repnz",
"notrack",
]
)

Expand Down Expand Up @@ -318,13 +319,15 @@ def action_instr(toks):
i = instruction(b"")
i.mnemonic = toks[0].upper()
# Remove prefixes
if i.mnemonic in ("REP", "REPZ", "REPNZ", "REPE", "REPNE", "LOCK"):
if i.mnemonic in ("REP", "REPZ", "REPNZ", "REPE", "REPNE", "LOCK", "NOTRACK"):
if i.mnemonic in ("REP", "REPZ", "REPE"):
i.misc.update({"pfx": ["rep", None, None, None], "rep": True})
if i.mnemonic in ("REPNZ", "REPNE"):
i.misc.update({"pfx": ["repne", None, None, None], "repne": True})
if i.mnemonic in ("LOCK",):
i.misc.update({"pfx": ["lock", None, None, None], "lock": True})
if i.mnemonic in ("NOTRACK",):
i.misc.update({"pfx": ["notrack", None, None, None], "notrack": True})
del toks[0] # toks.pop(0) is broken for pyparsing 2.0.2
# https://bugs.launchpad.net/ubuntu/+source/pyparsing/+bug/1381564
i.mnemonic = toks[0].upper()
Expand Down
29 changes: 25 additions & 4 deletions amoco/arch/x86/spec_ia32.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,6 @@ def ia32_rm8(obj, Mod, RM, data):
# r/m16/32
@ispec_ia32("*>[ {ff} /0 ]", mnemonic="INC", type=type_data_processing)
@ispec_ia32("*>[ {ff} /1 ]", mnemonic="DEC", type=type_data_processing)
@ispec_ia32("*>[ {ff} /2 ]", mnemonic="CALL", type=type_control_flow)
@ispec_ia32("*>[ {ff} /4 ]", mnemonic="JMP", type=type_control_flow)
@ispec_ia32("*>[ {ff} /6 ]", mnemonic="PUSH", type=type_data_processing)
@ispec_ia32("*>[ {8f} /0 ]", mnemonic="POP", type=type_data_processing)
@ispec_ia32("*>[ {f7} /2 ]", mnemonic="NOT", type=type_data_processing)
Expand All @@ -328,8 +326,16 @@ def ia32_rm8(obj, Mod, RM, data):
def ia32_rm32(obj, Mod, RM, data):
op1, data = getModRM(obj, Mod, RM, data)
obj.operands = [op1]
if obj.mnemonic in ("JMP", "CALL"):
obj.misc["absolute"] = True

@ispec_ia32("*>[ {ff} /2 ]", mnemonic="CALL")
@ispec_ia32("*>[ {ff} /4 ]", mnemonic="JMP")
def ia32_rm32(obj, Mod, RM, data):
op1, data = getModRM(obj, Mod, RM, data)
obj.operands = [op1]
obj.misc["absolute"] = True
if obj.misc['segreg'] is env.ds:
setpfx(obj, ('notrack',True), 0)
obj.type = type_control_flow


# r/m32/48
Expand All @@ -339,6 +345,14 @@ def ia32_rm32(obj, Mod, RM, data):
@ispec_ia32("*>[ {0f}{01} /1 ]", mnemonic="SIDT", type=type_system)
@ispec_ia32("*>[ {0f}{01} /2 ]", mnemonic="LGDT", type=type_system)
@ispec_ia32("*>[ {0f}{01} /3 ]", mnemonic="LIDT", type=type_system)
def ia32_far(obj, Mod, RM, data):
op1, data = getModRM(obj, Mod, RM, data)
if op1._is_reg:
raise InstructionError(obj)
size = obj.misc["opdsz"] or env.internals["mode"]
op1.size = size+16
obj.operands = [op1]

@ispec_ia32("*>[ {0f}{01} /4 ]", mnemonic="SMSW", type=type_system)
@ispec_ia32("*>[ {0f}{01} /7 ]", mnemonic="INVLPG", type=type_system)
def ia32_op48(obj, Mod, RM, data):
Expand Down Expand Up @@ -1012,6 +1026,13 @@ def ia32_movbe_crc32(obj, s, Mod, RM, REG, data):
obj.operands = [op1, op2]
obj.type = type_data_processing

# ENDBR (added by Intel in 2017 to protect against ROP)
@ispec_ia32("32>[ {f3}{0f}{1e}{fb} ]", mnemonic="ENDBR32")
@ispec_ia32("32>[ {f3}{0f}{1e}{fa} ]", mnemonic="ENDBR64")
def ia32_endbr(obj):
obj.operands = []
obj.type = type_cpu_state

# FPU instructions:
# -----------------

Expand Down
13 changes: 12 additions & 1 deletion tests/test_arch_x64.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,18 @@ def test_decoder_028():
assert i.operands[0].ref == 'xmm2'
assert i.operands[1].size == 64

def test_decoder_29():
def test_decoder_029():
i = cpu.disassemble(b'\xf3\x0f\x1e\xfa')
assert i.mnemonic=='ENDBR64'
assert str(i).strip()=='endbr64'

def test_decoder_030():
i = cpu.disassemble(b'\x3e\xff\xe0')
assert i.mnemonic=='JMP'
assert i.misc['notrack']==True
assert str(i).startswith('notrack')

def test_decoder_30():
i = cpu.disassemble(b'\x66\x48\x0f\x6e\xce')
assert i.mnemonic == "MOVQ"
assert i.operands[0].ref == "xmm1"
Expand Down

0 comments on commit fa1eb9d

Please sign in to comment.