bdcht / amoco

yet another tool for analysing binaries
GNU General Public License v2.0
453 stars 65 forks source link

x86&x64: add notrack (Intel CET_IBT) #94

Open LRGH opened 4 months ago

LRGH commented 4 months ago

Here is the patch I use

diff --git a/amoco/arch/x64/spec_ia32e.py b/amoco/arch/x64/spec_ia32e.py
index ce976ea..c84285c 100644
--- a/amoco/arch/x64/spec_ia32e.py
+++ b/amoco/arch/x64/spec_ia32e.py
@@ -36,6 +36,10 @@ def prefix_grp1(obj, _pfx):
     setpfx(obj, _pfx, 0)

+# Because of the addition of CET_IBT, the 3e prefix has now two
+# possible meanings: DS: segment override, or notrack
+# We keep the traditional "DS: segment override" but will need to
+# hack the instructions where it means notrack: call & jmp
 @ispec_ia32("8>[ {26} ]+", _pfx=("segreg", env.es))
 @ispec_ia32("8>[ {2e} ]+", _pfx=("segreg", env.cs))
 @ispec_ia32("8>[ {36} ]+", _pfx=("segreg", env.ss))
@@ -371,6 +375,14 @@ def ia32_rm64(obj, Mod, RM, data):
     obj.operands = [op1]
     obj.misc["absolute"] = True
     obj.type = type_control_flow
+    # Because of the addition of CET_IBT, the 3e prefix has now two
+    # possible meanings: DS: segment override, or notrack
+    # We keep the traditional "DS: segment override" but will need to
+    # hack the instructions where it means notrack: this one
+    if obj.misc["segreg"] is env.ds:
+        del obj.misc["segreg"]
+        obj.misc["notrack"] = True
+        obj.misc["pfx"] = ["notrack", None, None, None]

 # r/m32/48
diff --git a/amoco/arch/x86/parsers.py b/amoco/arch/x86/parsers.py
index 9bbccbe..8024347 100644
--- a/amoco/arch/x86/parsers.py
+++ b/amoco/arch/x86/parsers.py
@@ -81,6 +81,7 @@ def att_syntax_gen(env, CONDITION_CODES, cpu_addrsize, instruction):
             "repe",
             "repne",
             "repnz",
+            "notrack",
         ]
     )

@@ -321,13 +322,15 @@ def att_syntax_gen(env, CONDITION_CODES, cpu_addrsize, instruction):
         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()
diff --git a/amoco/arch/x86/spec_ia32.py b/amoco/arch/x86/spec_ia32.py
index f343675..9b20c97 100644
--- a/amoco/arch/x86/spec_ia32.py
+++ b/amoco/arch/x86/spec_ia32.py
@@ -34,6 +34,10 @@ def prefix_grp1(obj, _pfx):
     setpfx(obj, _pfx, 0)

+# Because of the addition of CET_IBT, the 3e prefix has now two
+# possible meanings: DS: segment override, or notrack
+# We keep the traditional "DS: segment override" but will need to
+# hack the instructions where it means notrack: call & jmp
 @ispec_ia32("8>[ {26} ]+", _pfx=("segreg", env.es))
 @ispec_ia32("8>[ {2e} ]+", _pfx=("segreg", env.cs))
 @ispec_ia32("8>[ {36} ]+", _pfx=("segreg", env.ss))
@@ -330,6 +334,14 @@ def ia32_rm32(obj, Mod, RM, data):
     obj.operands = [op1]
     if obj.mnemonic in ("JMP", "CALL"):
         obj.misc["absolute"] = True
+        # Because of the addition of CET_IBT, the 3e prefix has now two
+        # possible meanings: DS: segment override, or notrack
+        # We keep the traditional "DS: segment override" but will need to
+        # hack the instructions where it means notrack: this one
+        if obj.misc["segreg"] is env.ds:
+            del obj.misc["segreg"]
+            obj.misc["notrack"] = True
+            obj.misc["pfx"] = ["notrack", None, None, None]

 # r/m32/48
diff --git a/tests/test_arch_x64.py b/tests/test_arch_x64.py
index 8758829..2a2c673 100644
--- a/tests/test_arch_x64.py
+++ b/tests/test_arch_x64.py
@@ -207,3 +207,8 @@ def test_decoder_029():
   i = cpu.disassemble(b'\xf3\x0f\x1e\xfa')
   assert i.mnemonic=='ENDBR64'
   assert str(i) == 'endbr64     '
+
+def test_decoder_030():
+  i = cpu.disassemble(b'\x3e\xff\xe0')
+  assert i.mnemonic=='JMP'
+  assert str(i) == 'notrack jmp         rax'
bdcht commented 4 months ago

Thanks, added in fa1eb9d.