"""Test the production #DE decoder in a freestanding Windows DLL, not a guest."""
import argparse
import ctypes
import hashlib
import json
from pathlib import Path
import struct
FIELDS = 'r15 r14 r13 r12 r11 r10 r9 r8 rsi rdi rbp rdx rcx rbx rax vector error rip cs rflags rsp ss'.split()
class Frame(ctypes.Structure):
_fields_ = [(field, ctypes.c_uint64) for field in FIELDS]
def main(dll_path):
library = ctypes.CDLL(str(dll_path.resolve()))
decode = library.XfeRuntimeClassifyDivideFault
decode.argtypes = [ctypes.POINTER(Frame), ctypes.POINTER(ctypes.c_uint32)]
decode.restype = ctypes.c_int
checks = 0
def test(opcode, registers=None, overflow=False, valid=True, tail=b''):
nonlocal checks
instructions = ctypes.create_string_buffer(opcode + tail)
frame = Frame()
frame.rip = ctypes.addressof(instructions)
for name, value in (registers or {}).items():
setattr(frame, name, value)
code = ctypes.c_uint32(0)
result = decode(ctypes.byref(frame), ctypes.byref(code))
assert result == int(valid), (opcode.hex(), result)
if valid:
assert code.value == (0xC0000095 if overflow else 0xC0000094), (opcode.hex(), hex(code.value))
checks += 1
test(bytes.fromhex('f7f9'), {'rcx': 0})
test(bytes.fromhex('f7f9'), {'rcx': 0xFFFFFFFF}, overflow=True)
test(bytes.fromhex('48f7fe'), {'rsi': 0xFFFFFFFFFFFFFFFF}, overflow=True)
test(bytes.fromhex('49f7fc'), {'r12': 0})
test(bytes.fromhex('49f7fc'), {'r12': 0xFFFFFFFFFFFFFFFF}, overflow=True)
test(bytes.fromhex('66f7fb'), {'rbx': 0x10000}) # Width truncates to BX.
test(bytes.fromhex('66f7fb'), {'rbx': 0xFFFF}, overflow=True)
test(bytes.fromhex('f6fc'), {'rax': 0x0100}, overflow=True) # AH without REX.
test(bytes.fromhex('f6fc'), {'rax': 0x0001})
test(bytes.fromhex('40f6fc'), {'rsp': 0x0100}) # REX selects SPL, not AH.
test(bytes.fromhex('40f6fc'), {'rsp': 1}, overflow=True)
test(bytes.fromhex('41f6f9'), {'r9': 1}, overflow=True)
test(bytes.fromhex('48f7f3'), {'rbx': 1}, overflow=True) # Unsigned DIV too.
test(bytes.fromhex('48f7f3'), {'rbx': 0})
test(bytes.fromhex('f73d00000000'), tail=struct.pack('<I', 0))
test(bytes.fromhex('f73d00000000'), tail=struct.pack('<I', 0xFFFFFFFF), overflow=True)
test(bytes.fromhex('48f73d00000000'), tail=struct.pack('<Q', 0xFFFFFFFFFFFFFFFF), overflow=True)
operand = ctypes.c_uint64(1)
address = ctypes.addressof(operand)
test(bytes.fromhex('48f73b'), {'rbx': address}, overflow=True)
test(bytes.fromhex('48f77b80'), {'rbx': address + 128}, overflow=True) # Signed disp8.
test(bytes.fromhex('48f7bb00020000'), {'rbx': address - 512}, overflow=True)
test(bytes.fromhex('48f73cf3'), {'rbx': address - 40, 'rsi': 5}, overflow=True) # SIB *8.
test(bytes.fromhex('4af73c23'), {'rbx': address - 64, 'r12': 64}, overflow=True) # REX.X R12.
test(bytes.fromhex('49f77d00'), {'r13': address}, overflow=True)
kernel = ctypes.WinDLL('kernel32', use_last_error=True)
kernel.VirtualAlloc.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_ulong, ctypes.c_ulong]
kernel.VirtualAlloc.restype = ctypes.c_void_p
kernel.VirtualFree.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_ulong]
kernel.VirtualFree.restype = ctypes.c_int
low = kernel.VirtualAlloc(0x50000000, 4096, 0x3000, 4)
assert low == 0x50000000, ctypes.get_last_error()
try:
ctypes.c_uint32.from_address(low).value = 1
test(bytes.fromhex('f73c25') + struct.pack('<I', low), overflow=True) # No SIB base.
test(bytes.fromhex('6741f738'), {'r8': 0xFFFF000000000000 | low}, overflow=True) # 32-bit address.
finally:
assert kernel.VirtualFree(low, 0, 0x8000), ctypes.get_last_error()
test(bytes.fromhex('90'), valid=False)
test(bytes.fromhex('f7c0'), valid=False)
test(bytes.fromhex('66') * 15, valid=False)
assert decode(None, ctypes.byref(ctypes.c_uint32())) == 0
checks += 1
result = {'Kind': 'XfeHardwareDivideDecoderHostProof', 'Passed': True, 'Checks': checks,
'GuestExecutionVerified': False, 'DllSha256': hashlib.sha256(dll_path.read_bytes()).hexdigest()}
(dll_path.parent / 'Result.json').write_text(json.dumps(result, indent=2), encoding='utf-8')
print(json.dumps(result))
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('dll', type=Path)
args = parser.parse_args()
main(args.dll)
"""Test the production #DE decoder in a freestanding Windows DLL, not a guest."""
import argparse
import ctypes
import hashlib
import json
from pathlib import Path
import struct
FIELDS = 'r15 r14 r13 r12 r11 r10 r9 r8 rsi rdi rbp rdx rcx rbx rax vector error rip cs rflags rsp ss'.split()
class Frame(ctypes.Structure):
_fields_ = [(field, ctypes.c_uint64) for field in FIELDS]
def main(dll_path):
library = ctypes.CDLL(str(dll_path.resolve()))
decode = library.XfeRuntimeClassifyDivideFault
decode.argtypes = [ctypes.POINTER(Frame), ctypes.POINTER(ctypes.c_uint32)]
decode.restype = ctypes.c_int
checks = 0
def test(opcode, registers=None, overflow=False, valid=True, tail=b''):
nonlocal checks
instructions = ctypes.create_string_buffer(opcode + tail)
frame = Frame()
frame.rip = ctypes.addressof(instructions)
for name, value in (registers or {}).items():
setattr(frame, name, value)
code = ctypes.c_uint32(0)
result = decode(ctypes.byref(frame), ctypes.byref(code))
assert result == int(valid), (opcode.hex(), result)
if valid:
assert code.value == (0xC0000095 if overflow else 0xC0000094), (opcode.hex(), hex(code.value))
checks += 1
test(bytes.fromhex('f7f9'), {'rcx': 0})
test(bytes.fromhex('f7f9'), {'rcx': 0xFFFFFFFF}, overflow=True)
test(bytes.fromhex('48f7fe'), {'rsi': 0xFFFFFFFFFFFFFFFF}, overflow=True)
test(bytes.fromhex('49f7fc'), {'r12': 0})
test(bytes.fromhex('49f7fc'), {'r12': 0xFFFFFFFFFFFFFFFF}, overflow=True)
test(bytes.fromhex('66f7fb'), {'rbx': 0x10000}) # Width truncates to BX.
test(bytes.fromhex('66f7fb'), {'rbx': 0xFFFF}, overflow=True)
test(bytes.fromhex('f6fc'), {'rax': 0x0100}, overflow=True) # AH without REX.
test(bytes.fromhex('f6fc'), {'rax': 0x0001})
test(bytes.fromhex('40f6fc'), {'rsp': 0x0100}) # REX selects SPL, not AH.
test(bytes.fromhex('40f6fc'), {'rsp': 1}, overflow=True)
test(bytes.fromhex('41f6f9'), {'r9': 1}, overflow=True)
test(bytes.fromhex('48f7f3'), {'rbx': 1}, overflow=True) # Unsigned DIV too.
test(bytes.fromhex('48f7f3'), {'rbx': 0})
test(bytes.fromhex('f73d00000000'), tail=struct.pack('<I', 0))
test(bytes.fromhex('f73d00000000'), tail=struct.pack('<I', 0xFFFFFFFF), overflow=True)
test(bytes.fromhex('48f73d00000000'), tail=struct.pack('<Q', 0xFFFFFFFFFFFFFFFF), overflow=True)
operand = ctypes.c_uint64(1)
address = ctypes.addressof(operand)
test(bytes.fromhex('48f73b'), {'rbx': address}, overflow=True)
test(bytes.fromhex('48f77b80'), {'rbx': address + 128}, overflow=True) # Signed disp8.
test(bytes.fromhex('48f7bb00020000'), {'rbx': address - 512}, overflow=True)
test(bytes.fromhex('48f73cf3'), {'rbx': address - 40, 'rsi': 5}, overflow=True) # SIB *8.
test(bytes.fromhex('4af73c23'), {'rbx': address - 64, 'r12': 64}, overflow=True) # REX.X R12.
test(bytes.fromhex('49f77d00'), {'r13': address}, overflow=True)
kernel = ctypes.WinDLL('kernel32', use_last_error=True)
kernel.VirtualAlloc.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_ulong, ctypes.c_ulong]
kernel.VirtualAlloc.restype = ctypes.c_void_p
kernel.VirtualFree.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_ulong]
kernel.VirtualFree.restype = ctypes.c_int
low = kernel.VirtualAlloc(0x50000000, 4096, 0x3000, 4)
assert low == 0x50000000, ctypes.get_last_error()
try:
ctypes.c_uint32.from_address(low).value = 1
test(bytes.fromhex('f73c25') + struct.pack('<I', low), overflow=True) # No SIB base.
test(bytes.fromhex('6741f738'), {'r8': 0xFFFF000000000000 | low}, overflow=True) # 32-bit address.
finally:
assert kernel.VirtualFree(low, 0, 0x8000), ctypes.get_last_error()
test(bytes.fromhex('90'), valid=False)
test(bytes.fromhex('f7c0'), valid=False)
test(bytes.fromhex('66') * 15, valid=False)
assert decode(None, ctypes.byref(ctypes.c_uint32())) == 0
checks += 1
result = {'Kind': 'XfeHardwareDivideDecoderHostProof', 'Passed': True, 'Checks': checks,
'GuestExecutionVerified': False, 'DllSha256': hashlib.sha256(dll_path.read_bytes()).hexdigest()}
(dll_path.parent / 'Result.json').write_text(json.dumps(result, indent=2), encoding='utf-8')
print(json.dumps(result))
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('dll', type=Path)
args = parser.parse_args()
main(args.dll)