107 lines
3.1 KiB
Python
107 lines
3.1 KiB
Python
|
#!/usr/bin/env python3
|
||
|
#
|
||
|
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||
|
|
||
|
from unicorn.x86_const import (
|
||
|
UC_X86_REG_EAX, UC_X86_REG_RAX, UC_X86_REG_RCX, UC_X86_REG_RDI,
|
||
|
UC_X86_REG_RDX, UC_X86_REG_RSI, UC_X86_REG_R8, UC_X86_REG_R9,
|
||
|
UC_X86_REG_R10
|
||
|
)
|
||
|
|
||
|
from qiling.cc import QlCommonBaseCC
|
||
|
|
||
|
class QlIntelBaseCC(QlCommonBaseCC):
|
||
|
"""Calling convention base class for Intel-based systems.
|
||
|
Supports arguments passing over registers and stack.
|
||
|
"""
|
||
|
|
||
|
def setReturnAddress(self, addr: int) -> None:
|
||
|
self.arch.stack_push(addr)
|
||
|
|
||
|
def unwind(self, nslots: int) -> int:
|
||
|
# no cleanup; just pop out the return address
|
||
|
return self.arch.stack_pop()
|
||
|
|
||
|
class QlIntel64(QlIntelBaseCC):
|
||
|
"""Calling convention base class for Intel-based 64-bit systems.
|
||
|
"""
|
||
|
|
||
|
_retreg = UC_X86_REG_RAX
|
||
|
|
||
|
@staticmethod
|
||
|
def getNumSlots(argbits: int) -> int:
|
||
|
return max(argbits, 64) // 64
|
||
|
|
||
|
class QlIntel32(QlIntelBaseCC):
|
||
|
"""Calling convention base class for Intel-based 32-bit systems.
|
||
|
"""
|
||
|
|
||
|
_retreg = UC_X86_REG_EAX
|
||
|
|
||
|
@staticmethod
|
||
|
def getNumSlots(argbits: int) -> int:
|
||
|
return max(argbits, 32) // 32
|
||
|
|
||
|
def getRawParam(self, slot: int, nbits: int = 0) -> int:
|
||
|
__super_getparam = super().getRawParam
|
||
|
|
||
|
if nbits == 64:
|
||
|
lo = __super_getparam(slot)
|
||
|
hi = __super_getparam(slot + 1)
|
||
|
|
||
|
val = (hi << 32) | lo
|
||
|
else:
|
||
|
val = __super_getparam(slot, nbits)
|
||
|
|
||
|
return val
|
||
|
|
||
|
class amd64(QlIntel64):
|
||
|
"""Default calling convention for POSIX (x86-64).
|
||
|
First 6 arguments are passed in regs, the rest are passed on the stack.
|
||
|
"""
|
||
|
|
||
|
_argregs = (UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 10
|
||
|
|
||
|
class ms64(QlIntel64):
|
||
|
"""Default calling convention for Windows and UEFI (x86-64).
|
||
|
First 4 arguments are passed in regs, the rest are passed on the stack.
|
||
|
|
||
|
Each stack frame starts with a shadow space in size of 4 items, corresponding
|
||
|
to the first arguments passed in regs.
|
||
|
"""
|
||
|
|
||
|
_argregs = (UC_X86_REG_RCX, UC_X86_REG_RDX, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 12
|
||
|
_shadow = 4
|
||
|
|
||
|
class macosx64(QlIntel64):
|
||
|
"""Default calling convention for Mac OS (x86-64).
|
||
|
First 6 arguments are passed in regs, the rest are passed on the stack.
|
||
|
"""
|
||
|
|
||
|
_argregs = (UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, UC_X86_REG_RCX, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 10
|
||
|
|
||
|
class cdecl(QlIntel32):
|
||
|
"""Calling convention used by all operating systems (x86).
|
||
|
All arguments are passed on the stack.
|
||
|
|
||
|
The caller is resopnsible to unwind the stack.
|
||
|
"""
|
||
|
|
||
|
_argregs = (None, ) * 16
|
||
|
|
||
|
class stdcall(QlIntel32):
|
||
|
"""Calling convention used by all operating systems (x86).
|
||
|
All arguments are passed on the stack.
|
||
|
|
||
|
The callee is resopnsible to unwind the stack.
|
||
|
"""
|
||
|
|
||
|
_argregs = (None, ) * 16
|
||
|
|
||
|
def unwind(self, nslots: int) -> int:
|
||
|
retaddr = super().unwind(nslots)
|
||
|
|
||
|
self.arch.regs.arch_sp += (nslots * self._asize)
|
||
|
|
||
|
return retaddr
|