improve const generator; emit unicorn.h consts

This commit is contained in:
Ryan Hileman 2015-08-28 07:31:38 -07:00
parent 4a1c5ff071
commit 40ba1ea1b0
19 changed files with 2808 additions and 2825 deletions

View file

@ -15,6 +15,7 @@ SAMPLE_X86 = $(TMPDIR)/sample_x86
all: all:
cd python && $(MAKE) gen_const cd python && $(MAKE) gen_const
cd go && $(MAKE) gen_const
samples: expected python samples: expected python

View file

@ -5,7 +5,7 @@ import sys, re
INCL_DIR = '../include/unicorn/' INCL_DIR = '../include/unicorn/'
include = [ 'arm.h', 'arm64.h', 'mips.h', 'x86.h', 'sparc.h', 'm68k.h' ] include = [ 'arm.h', 'arm64.h', 'mips.h', 'x86.h', 'sparc.h', 'm68k.h', 'unicorn.h' ]
template = { template = {
'python': { 'python': {
@ -20,13 +20,14 @@ template = {
'x86.h': 'x86', 'x86.h': 'x86',
'sparc.h': 'sparc', 'sparc.h': 'sparc',
'm68k.h': 'm68k', 'm68k.h': 'm68k',
'unicorn.h': 'unicorn',
'comment_open': '#', 'comment_open': '#',
'comment_close': '', 'comment_close': '',
}, },
'go': { 'go': {
'header': "package unicorn\n// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [%s_const.go]\nconst (", 'header': "package unicorn\n// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [%s_const.go]\nconst (\n",
'footer': ")", 'footer': ")",
'line_format': '%s = %s\n', 'line_format': '\t%s = %s\n',
'out_file': './go/unicorn/%s_const.go', 'out_file': './go/unicorn/%s_const.go',
# prefixes for constant filenames of all archs - case sensitive # prefixes for constant filenames of all archs - case sensitive
'arm.h': 'arm', 'arm.h': 'arm',
@ -35,6 +36,7 @@ template = {
'x86.h': 'x86', 'x86.h': 'x86',
'sparc.h': 'sparc', 'sparc.h': 'sparc',
'm68k.h': 'm68k', 'm68k.h': 'm68k',
'unicorn.h': 'unicorn',
'comment_open': '//', 'comment_open': '//',
'comment_close': '', 'comment_close': '',
}, },
@ -50,9 +52,11 @@ def gen(lang):
prefix = templ[target] prefix = templ[target]
outfile = open(templ['out_file'] %(prefix), 'w') outfile = open(templ['out_file'] %(prefix), 'w')
outfile.write(templ['header'] % (prefix)) outfile.write(templ['header'] % (prefix))
if target == 'unicorn.h':
prefix = ''
lines = open(INCL_DIR + target).readlines() lines = open(INCL_DIR + target).readlines()
previous = {}
count = 0 count = 0
for line in lines: for line in lines:
line = line.strip() line = line.strip()
@ -65,17 +69,21 @@ def gen(lang):
if line == '' or line.startswith('//'): if line == '' or line.startswith('//'):
continue continue
if not line.startswith("UC_" + prefix.upper()):
continue
tmp = line.strip().split(',') tmp = line.strip().split(',')
for t in tmp: for t in tmp:
t = t.strip() t = t.strip()
if not t or t.startswith('//'): continue if not t or t.startswith('//'): continue
f = re.split('\s+', t) f = re.split('\s+', t)
# parse #define UC_TARGET (num)
define = False
if f[0] == '#define' and len(f) >= 3 and f[2].isdigit():
define = True
f.pop(0)
f.insert(1, '=')
if f[0].startswith("UC_" + prefix.upper()): if f[0].startswith("UC_" + prefix.upper()):
if len(f) > 1 and f[1] not in '//=': if len(f) > 1 and f[1] not in ('//', '='):
print("Error: Unable to convert %s" % f) print("Error: Unable to convert %s" % f)
continue continue
elif len(f) > 1 and f[1] == '=': elif len(f) > 1 and f[1] == '=':
@ -84,29 +92,31 @@ def gen(lang):
rhs = str(count) rhs = str(count)
count += 1 count += 1
try: lhs = f[0].strip()
# evaluate bitshifts in constants e.g. "UC_X86 = 1 << 1"
match = re.match(r'(?P<rhs>\s*\d+\s*<<\s*\d+\s*)', rhs)
if match:
rhs = eval(match.group(1))
else:
# evaluate references to other constants e.g. "UC_ARM_REG_X = UC_ARM_REG_SP"
match = re.match(r'^([^\d]\w+)$', rhs)
if match:
rhs = previous[match.group(1)]
count = int(rhs) + 1 count = int(rhs) + 1
if (count == 1): if (count == 1):
outfile.write("\n") outfile.write("\n")
except ValueError: outfile.write(templ['line_format'] % (lhs, rhs))
if lang == 'ocaml': previous[lhs] = rhs
# ocaml uses lsl for '<<', lor for '|'
rhs = rhs.replace('<<', ' lsl ')
rhs = rhs.replace('|', ' lor ')
# ocaml variable has _ as prefix
if rhs[0].isalpha():
rhs = '_' + rhs
outfile.write(templ['line_format'] %(f[0].strip(), rhs))
outfile.write(templ['footer']) outfile.write(templ['footer'])
outfile.close() outfile.close()
def main(): def main():
try: lang = sys.argv[1]
if not lang in template:
raise RuntimeError("Unsupported binding %s" % lang)
gen(sys.argv[1]) gen(sys.argv[1])
except:
raise RuntimeError("Unsupported binding %s" % sys.argv[1])
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) < 2: if len(sys.argv) < 2:

View file

@ -2,9 +2,13 @@
.PHONY: gen_const test .PHONY: gen_const test
all:
$(MAKE) gen_const
cd unicorn && go build
$(MAKE) test
gen_const: gen_const:
cd .. && python const_generator.py go cd .. && python const_generator.py go
cd unicorn && go build
test: test:
cd unicorn && go test cd unicorn && go test

View file

@ -1,6 +1,7 @@
package unicorn package unicorn
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [arm64_const.go] // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [arm64_const.go]
const ( const (
// ARM64 registers // ARM64 registers
UC_ARM64_REG_INVALID = 0 UC_ARM64_REG_INVALID = 0
@ -269,8 +270,8 @@ UC_ARM64_REG_PC = 260
UC_ARM64_REG_ENDING = 261 UC_ARM64_REG_ENDING = 261
// alias registers // alias registers
UC_ARM64_REG_IP1 = UC_ARM64_REG_X16 UC_ARM64_REG_IP1 = 215
UC_ARM64_REG_IP0 = UC_ARM64_REG_X17 UC_ARM64_REG_IP0 = 216
UC_ARM64_REG_FP = UC_ARM64_REG_X29 UC_ARM64_REG_FP = 1
UC_ARM64_REG_LR = UC_ARM64_REG_X30 UC_ARM64_REG_LR = 2
) )

View file

@ -1,6 +1,7 @@
package unicorn package unicorn
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [arm_const.go] // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [arm_const.go]
const ( const (
// ARM registers // ARM registers
UC_ARM_REG_INVALID = 0 UC_ARM_REG_INVALID = 0
@ -117,11 +118,11 @@ UC_ARM_REG_S31 = 110
UC_ARM_REG_ENDING = 111 UC_ARM_REG_ENDING = 111
// alias registers // alias registers
UC_ARM_REG_R13 = UC_ARM_REG_SP UC_ARM_REG_R13 = 12
UC_ARM_REG_R14 = UC_ARM_REG_LR UC_ARM_REG_R14 = 10
UC_ARM_REG_R15 = UC_ARM_REG_PC UC_ARM_REG_R15 = 11
UC_ARM_REG_SB = UC_ARM_REG_R9 UC_ARM_REG_SB = 75
UC_ARM_REG_SL = UC_ARM_REG_R10 UC_ARM_REG_SL = 76
UC_ARM_REG_FP = UC_ARM_REG_R11 UC_ARM_REG_FP = 77
UC_ARM_REG_IP = UC_ARM_REG_R12 UC_ARM_REG_IP = 78
) )

View file

@ -1,22 +0,0 @@
package unicorn
// #include <unicorn/unicorn.h>
import "C"
// TODO: update const script to generate these?
const (
UC_HOOK_BLOCK = C.UC_HOOK_BLOCK
UC_HOOK_CODE = C.UC_HOOK_CODE
UC_HOOK_MEM_INVALID = C.UC_HOOK_MEM_INVALID
UC_HOOK_MEM_READ = C.UC_HOOK_MEM_READ
UC_HOOK_MEM_WRITE = C.UC_HOOK_MEM_WRITE
UC_HOOK_MEM_READ_WRITE = C.UC_HOOK_MEM_READ_WRITE
UC_HOOK_INSN = C.UC_HOOK_INSN
UC_ARCH_X86 = C.UC_ARCH_X86
UC_MODE_32 = C.UC_MODE_32
UC_MODE_64 = C.UC_MODE_64
UC_ERR_MEM_READ = C.UC_ERR_MEM_READ
UC_ERR_MEM_WRITE = C.UC_ERR_MEM_WRITE
)

View file

@ -1,6 +1,7 @@
package unicorn package unicorn
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [m68k_const.go] // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [m68k_const.go]
const ( const (
// M68K registers // M68K registers
UC_M68K_REG_INVALID = 0 UC_M68K_REG_INVALID = 0

View file

@ -1,6 +1,7 @@
package unicorn package unicorn
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [mips_const.go] // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [mips_const.go]
const ( const (
// MIPS registers // MIPS registers
UC_MIPS_REG_INVALID = 0 UC_MIPS_REG_INVALID = 0
@ -153,45 +154,45 @@ UC_MIPS_REG_MPL0 = 134
UC_MIPS_REG_MPL1 = 135 UC_MIPS_REG_MPL1 = 135
UC_MIPS_REG_MPL2 = 136 UC_MIPS_REG_MPL2 = 136
UC_MIPS_REG_ENDING = 137 UC_MIPS_REG_ENDING = 137
UC_MIPS_REG_ZERO = UC_MIPS_REG_0 UC_MIPS_REG_ZERO = 2
UC_MIPS_REG_AT = UC_MIPS_REG_1 UC_MIPS_REG_AT = 3
UC_MIPS_REG_V0 = UC_MIPS_REG_2 UC_MIPS_REG_V0 = 4
UC_MIPS_REG_V1 = UC_MIPS_REG_3 UC_MIPS_REG_V1 = 5
UC_MIPS_REG_A0 = UC_MIPS_REG_4 UC_MIPS_REG_A0 = 6
UC_MIPS_REG_A1 = UC_MIPS_REG_5 UC_MIPS_REG_A1 = 7
UC_MIPS_REG_A2 = UC_MIPS_REG_6 UC_MIPS_REG_A2 = 8
UC_MIPS_REG_A3 = UC_MIPS_REG_7 UC_MIPS_REG_A3 = 9
UC_MIPS_REG_T0 = UC_MIPS_REG_8 UC_MIPS_REG_T0 = 10
UC_MIPS_REG_T1 = UC_MIPS_REG_9 UC_MIPS_REG_T1 = 11
UC_MIPS_REG_T2 = UC_MIPS_REG_10 UC_MIPS_REG_T2 = 12
UC_MIPS_REG_T3 = UC_MIPS_REG_11 UC_MIPS_REG_T3 = 13
UC_MIPS_REG_T4 = UC_MIPS_REG_12 UC_MIPS_REG_T4 = 14
UC_MIPS_REG_T5 = UC_MIPS_REG_13 UC_MIPS_REG_T5 = 15
UC_MIPS_REG_T6 = UC_MIPS_REG_14 UC_MIPS_REG_T6 = 16
UC_MIPS_REG_T7 = UC_MIPS_REG_15 UC_MIPS_REG_T7 = 17
UC_MIPS_REG_S0 = UC_MIPS_REG_16 UC_MIPS_REG_S0 = 18
UC_MIPS_REG_S1 = UC_MIPS_REG_17 UC_MIPS_REG_S1 = 19
UC_MIPS_REG_S2 = UC_MIPS_REG_18 UC_MIPS_REG_S2 = 20
UC_MIPS_REG_S3 = UC_MIPS_REG_19 UC_MIPS_REG_S3 = 21
UC_MIPS_REG_S4 = UC_MIPS_REG_20 UC_MIPS_REG_S4 = 22
UC_MIPS_REG_S5 = UC_MIPS_REG_21 UC_MIPS_REG_S5 = 23
UC_MIPS_REG_S6 = UC_MIPS_REG_22 UC_MIPS_REG_S6 = 24
UC_MIPS_REG_S7 = UC_MIPS_REG_23 UC_MIPS_REG_S7 = 25
UC_MIPS_REG_T8 = UC_MIPS_REG_24 UC_MIPS_REG_T8 = 26
UC_MIPS_REG_T9 = UC_MIPS_REG_25 UC_MIPS_REG_T9 = 27
UC_MIPS_REG_K0 = UC_MIPS_REG_26 UC_MIPS_REG_K0 = 28
UC_MIPS_REG_K1 = UC_MIPS_REG_27 UC_MIPS_REG_K1 = 29
UC_MIPS_REG_GP = UC_MIPS_REG_28 UC_MIPS_REG_GP = 30
UC_MIPS_REG_SP = UC_MIPS_REG_29 UC_MIPS_REG_SP = 31
UC_MIPS_REG_FP = UC_MIPS_REG_30 UC_MIPS_REG_FP = 32
UC_MIPS_REG_S8 = UC_MIPS_REG_30 UC_MIPS_REG_S8 = 32
UC_MIPS_REG_RA = UC_MIPS_REG_31 UC_MIPS_REG_RA = 33
UC_MIPS_REG_HI0 = UC_MIPS_REG_AC0 UC_MIPS_REG_HI0 = 45
UC_MIPS_REG_HI1 = UC_MIPS_REG_AC1 UC_MIPS_REG_HI1 = 46
UC_MIPS_REG_HI2 = UC_MIPS_REG_AC2 UC_MIPS_REG_HI2 = 47
UC_MIPS_REG_HI3 = UC_MIPS_REG_AC3 UC_MIPS_REG_HI3 = 48
UC_MIPS_REG_LO0 = UC_MIPS_REG_HI0 UC_MIPS_REG_LO0 = 45
UC_MIPS_REG_LO1 = UC_MIPS_REG_HI1 UC_MIPS_REG_LO1 = 46
UC_MIPS_REG_LO2 = UC_MIPS_REG_HI2 UC_MIPS_REG_LO2 = 47
UC_MIPS_REG_LO3 = UC_MIPS_REG_HI3 UC_MIPS_REG_LO3 = 48
) )

View file

@ -1,6 +1,7 @@
package unicorn package unicorn
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [sparc_const.go] // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [sparc_const.go]
const ( const (
// SPARC registers // SPARC registers
UC_SPARC_REG_INVALID = 0 UC_SPARC_REG_INVALID = 0
@ -93,6 +94,6 @@ UC_SPARC_REG_Y = 86
UC_SPARC_REG_XCC = 87 UC_SPARC_REG_XCC = 87
UC_SPARC_REG_PC = 88 UC_SPARC_REG_PC = 88
UC_SPARC_REG_ENDING = 89 UC_SPARC_REG_ENDING = 89
UC_SPARC_REG_O6 = UC_SPARC_REG_SP UC_SPARC_REG_O6 = 85
UC_SPARC_REG_I6 = UC_SPARC_REG_FP UC_SPARC_REG_I6 = 53
) )

View file

@ -17,7 +17,7 @@ func (u UcError) Error() string {
} }
func errReturn(err C.uc_err) error { func errReturn(err C.uc_err) error {
if err != C.UC_ERR_OK { if err != UC_ERR_OK {
return UcError(err) return UcError(err)
} }
return nil return nil
@ -36,10 +36,10 @@ func NewUc(arch, mode int) (*Uc, error) {
var major, minor C.uint var major, minor C.uint
C.uc_version(&major, &minor) C.uc_version(&major, &minor)
if major != C.UC_API_MAJOR || minor != C.UC_API_MINOR { if major != C.UC_API_MAJOR || minor != C.UC_API_MINOR {
return nil, UcError(C.UC_ERR_VERSION) return nil, UcError(UC_ERR_VERSION)
} }
var handle C.uch var handle C.uch
if ucerr := C.uc_open(C.uc_arch(arch), C.uc_mode(mode), &handle); ucerr != C.UC_ERR_OK { if ucerr := C.uc_open(C.uc_arch(arch), C.uc_mode(mode), &handle); ucerr != UC_ERR_OK {
return nil, UcError(ucerr) return nil, UcError(ucerr)
} }
uc := &Uc{handle, arch, mode} uc := &Uc{handle, arch, mode}

View file

@ -0,0 +1,63 @@
package unicorn
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [unicorn_const.go]
const (
UC_API_MAJOR = 0
UC_API_MINOR = 9
UC_SECOND_SCALE = 1000000
UC_MILISECOND_SCALE = 1000
UC_ARCH_ARM = 1
UC_ARCH_ARM64 = 2
UC_ARCH_MIPS = 3
UC_ARCH_X86 = 4
UC_ARCH_PPC = 5
UC_ARCH_SPARC = 6
UC_ARCH_M68K = 7
UC_ARCH_MAX = 8
UC_MODE_LITTLE_ENDIAN = 0
UC_MODE_ARM = 0
UC_MODE_16 = 2
UC_MODE_32 = 4
UC_MODE_64 = 8
UC_MODE_THUMB = 16
UC_MODE_MCLASS = 32
UC_MODE_V8 = 64
UC_MODE_MICRO = 16
UC_MODE_MIPS3 = 32
UC_MODE_MIPS32R6 = 64
UC_MODE_V9 = 16
UC_MODE_QPX = 16
UC_MODE_BIG_ENDIAN = 2147483648
UC_MODE_MIPS32 = 4
UC_MODE_MIPS64 = 8
UC_ERR_OK = 0
UC_ERR_OOM = 1
UC_ERR_ARCH = 2
UC_ERR_HANDLE = 3
UC_ERR_UCH = 4
UC_ERR_MODE = 5
UC_ERR_VERSION = 6
UC_ERR_MEM_READ = 7
UC_ERR_MEM_WRITE = 8
UC_ERR_CODE_INVALID = 9
UC_ERR_HOOK = 10
UC_ERR_INSN_INVALID = 11
UC_ERR_MAP = 12
UC_MEM_READ = 16
UC_MEM_WRITE = 17
UC_MEM_READ_WRITE = 18
UC_HOOK_INTR = 32
UC_HOOK_INSN = 33
UC_HOOK_CODE = 34
UC_HOOK_BLOCK = 35
UC_HOOK_MEM_INVALID = 36
UC_HOOK_MEM_READ = 37
UC_HOOK_MEM_WRITE = 38
UC_HOOK_MEM_READ_WRITE = 39
UC_PROT_READ = 1
UC_PROT_WRITE = 2
UC_PROT_EXEC = 4
)

View file

@ -1,6 +1,7 @@
package unicorn package unicorn
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [x86_const.go] // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [x86_const.go]
const ( const (
// X86 registers // X86 registers
UC_X86_REG_INVALID = 0 UC_X86_REG_INVALID = 0

View file

@ -1,464 +1,4 @@
# Unicorn Python bindings, by Nguyen Anh Quynnh <aquynh@gmail.com> # Unicorn Python bindings, by Nguyen Anh Quynnh <aquynh@gmail.com>
import sys
_python2 = sys.version_info[0] < 3
if _python2:
range = xrange
from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const
from unicorn_const import *
__all__ = [ from unicorn import Uc, uc_version, uc_arch_supported, version_bind, debug, UcError
'Uc',
'uc_version',
'uc_arch_supported',
'version_bind',
'debug',
'UC_API_MAJOR',
'UC_API_MINOR',
'UC_ARCH_ARM',
'UC_ARCH_ARM64',
'UC_ARCH_MIPS',
'UC_ARCH_X86',
'UC_ARCH_SPARC',
'UC_ARCH_M68K',
'UC_ARCH_ALL',
'UC_MODE_LITTLE_ENDIAN',
'UC_MODE_BIG_ENDIAN',
'UC_MODE_16',
'UC_MODE_32',
'UC_MODE_64',
'UC_MODE_ARM',
'UC_MODE_THUMB',
'UC_MODE_MCLASS',
'UC_MODE_MICRO',
'UC_MODE_MIPS3',
'UC_MODE_MIPS32R6',
'UC_MODE_MIPSGP64',
'UC_MODE_V8',
'UC_MODE_V9',
'UC_MODE_MIPS32',
'UC_MODE_MIPS64',
'UC_ERR_OK',
'UC_ERR_OOM',
'UC_ERR_ARCH',
'UC_ERR_HANDLE',
'UC_ERR_UCH',
'UC_ERR_MODE',
'UC_ERR_VERSION',
'UC_ERR_MEM_READ',
'UC_ERR_MEM_WRITE',
'UC_ERR_CODE_INVALID',
'UC_ERR_HOOK',
'UC_ERR_INSN_INVALID',
'UC_ERR_MAP',
'UC_HOOK_INTR',
'UC_HOOK_INSN',
'UC_HOOK_CODE',
'UC_HOOK_BLOCK',
'UC_HOOK_MEM_INVALID',
'UC_HOOK_MEM_READ',
'UC_HOOK_MEM_WRITE',
'UC_HOOK_MEM_READ_WRITE',
'UC_MEM_READ',
'UC_MEM_WRITE',
'UC_MEM_READ_WRITE',
'UC_SECOND_SCALE',
'UC_MILISECOND_SCALE',
'UcError',
]
# Unicorn C interface
# API version
UC_API_MAJOR = 0
UC_API_MINOR = 9
# Architectures
UC_ARCH_ARM = 1
UC_ARCH_ARM64 = 2
UC_ARCH_MIPS = 3
UC_ARCH_X86 = 4
UC_ARCH_PPC = 5
UC_ARCH_SPARC = 6
UC_ARCH_M68K = 7
UC_ARCH_MAX = 8
UC_ARCH_ALL = 0xFFFF
# Hardware modes
UC_MODE_LITTLE_ENDIAN = 0 # little-endian mode (default mode)
UC_MODE_ARM = 0 # ARM mode
UC_MODE_16 = (1 << 1) # 16-bit mode (for X86)
UC_MODE_32 = (1 << 2) # 32-bit mode (for X86)
UC_MODE_64 = (1 << 3) # 64-bit mode (for X86, PPC)
UC_MODE_THUMB = (1 << 4) # ARM's Thumb mode, including Thumb-2
UC_MODE_MCLASS = (1 << 5) # ARM's Cortex-M series
UC_MODE_V8 = (1 << 6) # ARMv8 A32 encodings for ARM
UC_MODE_MICRO = (1 << 4) # MicroMips mode (MIPS architecture)
UC_MODE_MIPS3 = (1 << 5) # Mips III ISA
UC_MODE_MIPS32R6 = (1 << 6) # Mips32r6 ISA
UC_MODE_MIPSGP64 = (1 << 7) # General Purpose Registers are 64-bit wide (MIPS arch)
UC_MODE_V9 = (1 << 4) # Sparc V9 mode (for Sparc)
UC_MODE_BIG_ENDIAN = (1 << 31) # big-endian mode
UC_MODE_MIPS32 = UC_MODE_32 # Mips32 ISA
UC_MODE_MIPS64 = UC_MODE_64 # Mips64 ISA
# Unicorn error type
UC_ERR_OK = 0 # No error: everything was fine
UC_ERR_OOM = 1 # Out-Of-Memory error: uc_open(), uc_emulate()
UC_ERR_ARCH = 2 # Unsupported architecture: uc_open()
UC_ERR_HANDLE = 3 # Invalid handle
UC_ERR_UCH = 4 # Invalid handle (uch)
UC_ERR_MODE = 5 # Invalid/unsupported mode: uc_open()
UC_ERR_VERSION = 6 # Unsupported version (bindings)
UC_ERR_MEM_READ = 7 # Quit emulation due to invalid memory READ: uc_emu_start()
UC_ERR_MEM_WRITE = 8 # Quit emulation due to invalid memory WRITE: uc_emu_start()
UC_ERR_CODE_INVALID = 9 # Quit emulation due to invalid code address: uc_emu_start()
UC_ERR_HOOK = 10 # Invalid hook type: uc_hook_add()
UC_ERR_INSN_INVALID = 11 # Invalid instruction
UC_ERR_MAP = 12 # Invalid memory mapping
# All type of hooks for uc_hook_add() API.
UC_HOOK_INTR = 32 # Hook all interrupt events
UC_HOOK_INSN = 33 # Hook a particular instruction
UC_HOOK_CODE = 34 # Hook a range of code
UC_HOOK_BLOCK = 35 # Hook basic blocks
UC_HOOK_MEM_INVALID = 36 # Hook for all invalid memory access events
UC_HOOK_MEM_READ = 37 # Hook all memory read events.
UC_HOOK_MEM_WRITE = 38 # Hook all memory write events.
UC_HOOK_MEM_READ_WRITE = 39 # Hook all memory accesses (either READ or WRITE).
# All type of memory accesses for UC_HOOK_MEM_*
UC_MEM_READ = 16 # Memory is read from
UC_MEM_WRITE = 17 # Memory is written to
UC_MEM_READ_WRITE = 18 # Memory is accessed (either READ or WRITE)
# Time scales to calculate timeout on microsecond unit
# This is for Uc.emu_start()
UC_SECOND_SCALE = 1000000 # 1 second = 1000,000 microseconds
UC_MILISECOND_SCALE = 1000 # 1 milisecond = 1000 nanoseconds
import ctypes, ctypes.util, sys
from os.path import split, join, dirname
import distutils.sysconfig
import inspect
if not hasattr(sys.modules[__name__], '__file__'):
__file__ = inspect.getfile(inspect.currentframe())
_lib_path = split(__file__)[0]
_all_libs = ['unicorn.dll', 'libunicorn.so', 'libunicorn.dylib']
_found = False
for _lib in _all_libs:
try:
_lib_file = join(_lib_path, _lib)
# print "Trying to load:", _lib_file
_uc = ctypes.cdll.LoadLibrary(_lib_file)
_found = True
break
except OSError:
pass
if _found == False:
# try loading from default paths
for _lib in _all_libs:
try:
_uc = ctypes.cdll.LoadLibrary(_lib)
_found = True
break
except OSError:
pass
if _found == False:
# last try: loading from python lib directory
_lib_path = distutils.sysconfig.get_python_lib()
for _lib in _all_libs:
try:
_lib_file = join(_lib_path, 'unicorn', _lib)
# print "Trying to load:", _lib_file
_uc = ctypes.cdll.LoadLibrary(_lib_file)
_found = True
break
except OSError:
pass
if _found == False:
raise ImportError("ERROR: fail to load the dynamic library.")
# setup all the function prototype
def _setup_prototype(lib, fname, restype, *argtypes):
getattr(lib, fname).restype = restype
getattr(lib, fname).argtypes = argtypes
_setup_prototype(_uc, "uc_version", ctypes.c_int, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
_setup_prototype(_uc, "uc_arch_supported", ctypes.c_bool, ctypes.c_int)
_setup_prototype(_uc, "uc_open", ctypes.c_int, ctypes.c_uint, ctypes.c_uint, ctypes.POINTER(ctypes.c_size_t))
_setup_prototype(_uc, "uc_close", ctypes.c_int, ctypes.POINTER(ctypes.c_size_t))
_setup_prototype(_uc, "uc_strerror", ctypes.c_char_p, ctypes.c_int)
_setup_prototype(_uc, "uc_errno", ctypes.c_int, ctypes.c_size_t)
_setup_prototype(_uc, "uc_reg_read", ctypes.c_int, ctypes.c_size_t, ctypes.c_int, ctypes.c_void_p)
_setup_prototype(_uc, "uc_reg_write", ctypes.c_int, ctypes.c_size_t, ctypes.c_int, ctypes.c_void_p)
_setup_prototype(_uc, "uc_mem_read", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t)
_setup_prototype(_uc, "uc_mem_write", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t)
_setup_prototype(_uc, "uc_emu_start", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_size_t)
_setup_prototype(_uc, "uc_emu_stop", ctypes.c_int, ctypes.c_size_t)
_setup_prototype(_uc, "uc_hook_del", ctypes.c_int, ctypes.c_size_t, ctypes.POINTER(ctypes.c_size_t))
_setup_prototype(_uc, "uc_mem_map", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_size_t)
# uc_hook_add is special due to variable number of arguments
_uc.uc_hook_add = getattr(_uc, "uc_hook_add")
_uc.uc_hook_add.restype = ctypes.c_int
UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p)
UC_HOOK_MEM_INVALID_CB = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_size_t, ctypes.c_int, \
ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p)
UC_HOOK_MEM_ACCESS_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_int, \
ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p)
UC_HOOK_INTR_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint32, \
ctypes.c_void_p)
UC_HOOK_INSN_IN_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_size_t, ctypes.c_uint32, \
ctypes.c_int, ctypes.c_void_p)
UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint32, \
ctypes.c_int, ctypes.c_uint32, ctypes.c_void_p)
UC_HOOK_INSN_SYSCALL_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_void_p)
# access to error code via @errno of UcError
class UcError(Exception):
def __init__(self, errno):
self.errno = errno
def __str__(self):
return _uc.uc_strerror(self.errno)
# return the core's version
def uc_version():
major = ctypes.c_int()
minor = ctypes.c_int()
combined = _uc.uc_version(ctypes.byref(major), ctypes.byref(minor))
return (major.value, minor.value, combined)
# return the binding's version
def version_bind():
return (UC_API_MAJOR, UC_API_MINOR, (UC_API_MAJOR << 8) + UC_API_MINOR)
# check to see if this engine supports a particular arch
def uc_arch_supported(query):
return _uc.uc_arch_supported(query)
class Uc(object):
def __init__(self, arch, mode):
# verify version compatibility with the core before doing anything
(major, minor, _combined) = uc_version()
if major != UC_API_MAJOR or minor != UC_API_MINOR:
self._uch = None
# our binding version is different from the core's API version
raise UcError(UC_ERR_VERSION)
self._arch, self._mode = arch, mode
self._uch = ctypes.c_size_t()
status = _uc.uc_open(arch, mode, ctypes.byref(self._uch))
if status != UC_ERR_OK:
self._uch = None
raise UcError(status)
# internal mapping table to save callback & userdata
self._callbacks = {}
self._callback_count = 0
# destructor to be called automatically when object is destroyed.
def __del__(self):
if self._uch:
try:
status = _uc.uc_close(ctypes.byref(self._uch))
if status != UC_ERR_OK:
raise UcError(status)
except: # _uc might be pulled from under our feet
pass
# emulate from @begin, and stop when reaching address @until
def emu_start(self, begin, until, timeout=0, count=0):
status = _uc.uc_emu_start(self._uch, begin, until, timeout, count)
if status != UC_ERR_OK:
raise UcError(status)
# stop emulation
def emu_stop(self):
status = _uc.uc_emu_stop(self._uch)
if status != UC_ERR_OK:
raise UcError(status)
# return the value of a register
def reg_read(self, reg_id):
# read to 64bit number to be safe
reg = ctypes.c_int64(0)
status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg))
if status != UC_ERR_OK:
raise UcError(status)
return reg.value
# write to a register
def reg_write(self, reg_id, value):
# convert to 64bit number to be safe
reg = ctypes.c_int64(value)
status = _uc.uc_reg_write(self._uch, reg_id, ctypes.byref(reg))
if status != UC_ERR_OK:
raise UcError(status)
# read data from memory
def mem_read(self, address, size):
data = ctypes.create_string_buffer(size)
status = _uc.uc_mem_read(self._uch, address, data, size)
if status != UC_ERR_OK:
raise UcError(status)
return bytearray(data)
# write to memory
def mem_write(self, address, data):
status = _uc.uc_mem_write(self._uch, address, data, len(data))
if status != UC_ERR_OK:
raise UcError(status)
# map a range of memory
def mem_map(self, address, size):
status = _uc.uc_mem_map(self._uch, address, size)
if status != UC_ERR_OK:
raise UcError(status)
def _hookcode_cb(self, handle, address, size, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
cb(self, address, size, data)
def _hook_mem_invalid_cb(self, handle, access, address, size, value, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
return cb(self, access, address, size, value, data)
def _hook_mem_access_cb(self, handle, access, address, size, value, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
cb(self, access, address, size, value, data)
def _hook_intr_cb(self, handle, intno, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
cb(self, intno, data)
def _hook_insn_in_cb(self, handle, port, size, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
return cb(self, port, size, data)
def _hook_insn_out_cb(self, handle, port, size, value, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
cb(self, port, size, value, data)
def _hook_insn_syscall_cb(self, handle, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
cb(self, data)
# add a hook
def hook_add(self, htype, callback, user_data=None, arg1=1, arg2=0):
_h2 = ctypes.c_size_t()
# save callback & user_data
self._callback_count += 1
self._callbacks[self._callback_count] = (callback, user_data)
if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE):
begin = ctypes.c_uint64(arg1)
end = ctypes.c_uint64(arg2)
# set callback with wrapper, so it can be called
# with this object as param
cb = ctypes.cast(UC_HOOK_CODE_CB(self._hookcode_cb), UC_HOOK_CODE_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \
ctypes.cast(self._callback_count, ctypes.c_void_p), begin, end)
elif htype == UC_HOOK_MEM_INVALID:
cb = ctypes.cast(UC_HOOK_MEM_INVALID_CB(self._hook_mem_invalid_cb), UC_HOOK_MEM_INVALID_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
elif htype in (UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ_WRITE):
cb = ctypes.cast(UC_HOOK_MEM_ACCESS_CB(self._hook_mem_access_cb), UC_HOOK_MEM_ACCESS_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
elif htype == UC_HOOK_INSN:
insn = ctypes.c_int(arg1)
if arg1 == x86_const.UC_X86_INS_IN: # IN instruction
cb = ctypes.cast(UC_HOOK_INSN_IN_CB(self._hook_insn_in_cb), UC_HOOK_INSN_IN_CB)
if arg1 == x86_const.UC_X86_INS_OUT: # OUT instruction
cb = ctypes.cast(UC_HOOK_INSN_OUT_CB(self._hook_insn_out_cb), UC_HOOK_INSN_OUT_CB)
if arg1 in (x86_const.UC_X86_INS_SYSCALL, x86_const.UC_X86_INS_SYSENTER): # SYSCALL/SYSENTER instruction
cb = ctypes.cast(UC_HOOK_INSN_SYSCALL_CB(self._hook_insn_syscall_cb), UC_HOOK_INSN_SYSCALL_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p), insn)
elif htype == UC_HOOK_INTR:
cb = ctypes.cast(UC_HOOK_INTR_CB(self._hook_intr_cb), UC_HOOK_INTR_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
if status != UC_ERR_OK:
raise UcError(status)
return _h2.value
# delete a hook
def hook_del(self, h):
_h = ctypes.c_size_t(h)
status = _uc.uc_hook_del(self._uch, ctypes.byref(_h))
if status != UC_ERR_OK:
raise UcError(status)
h = 0
# print out debugging info
def debug():
archs = { "arm": UC_ARCH_ARM, "arm64": UC_ARCH_ARM64, \
"mips": UC_ARCH_MIPS, "sparc": UC_ARCH_SPARC, \
"m68k": UC_ARCH_M68K, "x86": UC_ARCH_X86 }
all_archs = ""
keys = archs.keys()
keys.sort()
for k in keys:
if uc_arch_supported(archs[k]):
all_archs += "-%s" % k
(major, minor, _combined) = uc_version()
return "python-%s-c%u.%u-b%u.%u" % (all_archs, major, minor, UC_API_MAJOR, UC_API_MINOR)

View file

@ -268,7 +268,7 @@ UC_ARM64_REG_PC = 260
UC_ARM64_REG_ENDING = 261 UC_ARM64_REG_ENDING = 261
# alias registers # alias registers
UC_ARM64_REG_IP1 = UC_ARM64_REG_X16 UC_ARM64_REG_IP1 = 215
UC_ARM64_REG_IP0 = UC_ARM64_REG_X17 UC_ARM64_REG_IP0 = 216
UC_ARM64_REG_FP = UC_ARM64_REG_X29 UC_ARM64_REG_FP = 1
UC_ARM64_REG_LR = UC_ARM64_REG_X30 UC_ARM64_REG_LR = 2

View file

@ -116,10 +116,10 @@ UC_ARM_REG_S31 = 110
UC_ARM_REG_ENDING = 111 UC_ARM_REG_ENDING = 111
# alias registers # alias registers
UC_ARM_REG_R13 = UC_ARM_REG_SP UC_ARM_REG_R13 = 12
UC_ARM_REG_R14 = UC_ARM_REG_LR UC_ARM_REG_R14 = 10
UC_ARM_REG_R15 = UC_ARM_REG_PC UC_ARM_REG_R15 = 11
UC_ARM_REG_SB = UC_ARM_REG_R9 UC_ARM_REG_SB = 75
UC_ARM_REG_SL = UC_ARM_REG_R10 UC_ARM_REG_SL = 76
UC_ARM_REG_FP = UC_ARM_REG_R11 UC_ARM_REG_FP = 77
UC_ARM_REG_IP = UC_ARM_REG_R12 UC_ARM_REG_IP = 78

View file

@ -152,44 +152,44 @@ UC_MIPS_REG_MPL0 = 134
UC_MIPS_REG_MPL1 = 135 UC_MIPS_REG_MPL1 = 135
UC_MIPS_REG_MPL2 = 136 UC_MIPS_REG_MPL2 = 136
UC_MIPS_REG_ENDING = 137 UC_MIPS_REG_ENDING = 137
UC_MIPS_REG_ZERO = UC_MIPS_REG_0 UC_MIPS_REG_ZERO = 2
UC_MIPS_REG_AT = UC_MIPS_REG_1 UC_MIPS_REG_AT = 3
UC_MIPS_REG_V0 = UC_MIPS_REG_2 UC_MIPS_REG_V0 = 4
UC_MIPS_REG_V1 = UC_MIPS_REG_3 UC_MIPS_REG_V1 = 5
UC_MIPS_REG_A0 = UC_MIPS_REG_4 UC_MIPS_REG_A0 = 6
UC_MIPS_REG_A1 = UC_MIPS_REG_5 UC_MIPS_REG_A1 = 7
UC_MIPS_REG_A2 = UC_MIPS_REG_6 UC_MIPS_REG_A2 = 8
UC_MIPS_REG_A3 = UC_MIPS_REG_7 UC_MIPS_REG_A3 = 9
UC_MIPS_REG_T0 = UC_MIPS_REG_8 UC_MIPS_REG_T0 = 10
UC_MIPS_REG_T1 = UC_MIPS_REG_9 UC_MIPS_REG_T1 = 11
UC_MIPS_REG_T2 = UC_MIPS_REG_10 UC_MIPS_REG_T2 = 12
UC_MIPS_REG_T3 = UC_MIPS_REG_11 UC_MIPS_REG_T3 = 13
UC_MIPS_REG_T4 = UC_MIPS_REG_12 UC_MIPS_REG_T4 = 14
UC_MIPS_REG_T5 = UC_MIPS_REG_13 UC_MIPS_REG_T5 = 15
UC_MIPS_REG_T6 = UC_MIPS_REG_14 UC_MIPS_REG_T6 = 16
UC_MIPS_REG_T7 = UC_MIPS_REG_15 UC_MIPS_REG_T7 = 17
UC_MIPS_REG_S0 = UC_MIPS_REG_16 UC_MIPS_REG_S0 = 18
UC_MIPS_REG_S1 = UC_MIPS_REG_17 UC_MIPS_REG_S1 = 19
UC_MIPS_REG_S2 = UC_MIPS_REG_18 UC_MIPS_REG_S2 = 20
UC_MIPS_REG_S3 = UC_MIPS_REG_19 UC_MIPS_REG_S3 = 21
UC_MIPS_REG_S4 = UC_MIPS_REG_20 UC_MIPS_REG_S4 = 22
UC_MIPS_REG_S5 = UC_MIPS_REG_21 UC_MIPS_REG_S5 = 23
UC_MIPS_REG_S6 = UC_MIPS_REG_22 UC_MIPS_REG_S6 = 24
UC_MIPS_REG_S7 = UC_MIPS_REG_23 UC_MIPS_REG_S7 = 25
UC_MIPS_REG_T8 = UC_MIPS_REG_24 UC_MIPS_REG_T8 = 26
UC_MIPS_REG_T9 = UC_MIPS_REG_25 UC_MIPS_REG_T9 = 27
UC_MIPS_REG_K0 = UC_MIPS_REG_26 UC_MIPS_REG_K0 = 28
UC_MIPS_REG_K1 = UC_MIPS_REG_27 UC_MIPS_REG_K1 = 29
UC_MIPS_REG_GP = UC_MIPS_REG_28 UC_MIPS_REG_GP = 30
UC_MIPS_REG_SP = UC_MIPS_REG_29 UC_MIPS_REG_SP = 31
UC_MIPS_REG_FP = UC_MIPS_REG_30 UC_MIPS_REG_FP = 32
UC_MIPS_REG_S8 = UC_MIPS_REG_30 UC_MIPS_REG_S8 = 32
UC_MIPS_REG_RA = UC_MIPS_REG_31 UC_MIPS_REG_RA = 33
UC_MIPS_REG_HI0 = UC_MIPS_REG_AC0 UC_MIPS_REG_HI0 = 45
UC_MIPS_REG_HI1 = UC_MIPS_REG_AC1 UC_MIPS_REG_HI1 = 46
UC_MIPS_REG_HI2 = UC_MIPS_REG_AC2 UC_MIPS_REG_HI2 = 47
UC_MIPS_REG_HI3 = UC_MIPS_REG_AC3 UC_MIPS_REG_HI3 = 48
UC_MIPS_REG_LO0 = UC_MIPS_REG_HI0 UC_MIPS_REG_LO0 = 45
UC_MIPS_REG_LO1 = UC_MIPS_REG_HI1 UC_MIPS_REG_LO1 = 46
UC_MIPS_REG_LO2 = UC_MIPS_REG_HI2 UC_MIPS_REG_LO2 = 47
UC_MIPS_REG_LO3 = UC_MIPS_REG_HI3 UC_MIPS_REG_LO3 = 48

View file

@ -92,5 +92,5 @@ UC_SPARC_REG_Y = 86
UC_SPARC_REG_XCC = 87 UC_SPARC_REG_XCC = 87
UC_SPARC_REG_PC = 88 UC_SPARC_REG_PC = 88
UC_SPARC_REG_ENDING = 89 UC_SPARC_REG_ENDING = 89
UC_SPARC_REG_O6 = UC_SPARC_REG_SP UC_SPARC_REG_O6 = 85
UC_SPARC_REG_I6 = UC_SPARC_REG_FP UC_SPARC_REG_I6 = 53

View file

@ -0,0 +1,321 @@
# Unicorn Python bindings, by Nguyen Anh Quynnh <aquynh@gmail.com>
import sys
_python2 = sys.version_info[0] < 3
if _python2:
range = xrange
from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const
from unicorn_const import *
import ctypes, ctypes.util, sys
from os.path import split, join, dirname
import distutils.sysconfig
import inspect
if not hasattr(sys.modules[__name__], '__file__'):
__file__ = inspect.getfile(inspect.currentframe())
_lib_path = split(__file__)[0]
_all_libs = ['unicorn.dll', 'libunicorn.so', 'libunicorn.dylib']
_found = False
for _lib in _all_libs:
try:
_lib_file = join(_lib_path, _lib)
# print "Trying to load:", _lib_file
_uc = ctypes.cdll.LoadLibrary(_lib_file)
_found = True
break
except OSError:
pass
if _found == False:
# try loading from default paths
for _lib in _all_libs:
try:
_uc = ctypes.cdll.LoadLibrary(_lib)
_found = True
break
except OSError:
pass
if _found == False:
# last try: loading from python lib directory
_lib_path = distutils.sysconfig.get_python_lib()
for _lib in _all_libs:
try:
_lib_file = join(_lib_path, 'unicorn', _lib)
# print "Trying to load:", _lib_file
_uc = ctypes.cdll.LoadLibrary(_lib_file)
_found = True
break
except OSError:
pass
if _found == False:
raise ImportError("ERROR: fail to load the dynamic library.")
# setup all the function prototype
def _setup_prototype(lib, fname, restype, *argtypes):
getattr(lib, fname).restype = restype
getattr(lib, fname).argtypes = argtypes
_setup_prototype(_uc, "uc_version", ctypes.c_int, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
_setup_prototype(_uc, "uc_arch_supported", ctypes.c_bool, ctypes.c_int)
_setup_prototype(_uc, "uc_open", ctypes.c_int, ctypes.c_uint, ctypes.c_uint, ctypes.POINTER(ctypes.c_size_t))
_setup_prototype(_uc, "uc_close", ctypes.c_int, ctypes.POINTER(ctypes.c_size_t))
_setup_prototype(_uc, "uc_strerror", ctypes.c_char_p, ctypes.c_int)
_setup_prototype(_uc, "uc_errno", ctypes.c_int, ctypes.c_size_t)
_setup_prototype(_uc, "uc_reg_read", ctypes.c_int, ctypes.c_size_t, ctypes.c_int, ctypes.c_void_p)
_setup_prototype(_uc, "uc_reg_write", ctypes.c_int, ctypes.c_size_t, ctypes.c_int, ctypes.c_void_p)
_setup_prototype(_uc, "uc_mem_read", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t)
_setup_prototype(_uc, "uc_mem_write", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t)
_setup_prototype(_uc, "uc_emu_start", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_size_t)
_setup_prototype(_uc, "uc_emu_stop", ctypes.c_int, ctypes.c_size_t)
_setup_prototype(_uc, "uc_hook_del", ctypes.c_int, ctypes.c_size_t, ctypes.POINTER(ctypes.c_size_t))
_setup_prototype(_uc, "uc_mem_map", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_size_t)
# uc_hook_add is special due to variable number of arguments
_uc.uc_hook_add = getattr(_uc, "uc_hook_add")
_uc.uc_hook_add.restype = ctypes.c_int
UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p)
UC_HOOK_MEM_INVALID_CB = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_size_t, ctypes.c_int, \
ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p)
UC_HOOK_MEM_ACCESS_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_int, \
ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p)
UC_HOOK_INTR_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint32, \
ctypes.c_void_p)
UC_HOOK_INSN_IN_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_size_t, ctypes.c_uint32, \
ctypes.c_int, ctypes.c_void_p)
UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint32, \
ctypes.c_int, ctypes.c_uint32, ctypes.c_void_p)
UC_HOOK_INSN_SYSCALL_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_void_p)
# access to error code via @errno of UcError
class UcError(Exception):
def __init__(self, errno):
self.errno = errno
def __str__(self):
return _uc.uc_strerror(self.errno)
# return the core's version
def uc_version():
major = ctypes.c_int()
minor = ctypes.c_int()
combined = _uc.uc_version(ctypes.byref(major), ctypes.byref(minor))
return (major.value, minor.value, combined)
# return the binding's version
def version_bind():
return (UC_API_MAJOR, UC_API_MINOR, (UC_API_MAJOR << 8) + UC_API_MINOR)
# check to see if this engine supports a particular arch
def uc_arch_supported(query):
return _uc.uc_arch_supported(query)
class Uc(object):
def __init__(self, arch, mode):
# verify version compatibility with the core before doing anything
(major, minor, _combined) = uc_version()
if major != UC_API_MAJOR or minor != UC_API_MINOR:
self._uch = None
# our binding version is different from the core's API version
raise UcError(UC_ERR_VERSION)
self._arch, self._mode = arch, mode
self._uch = ctypes.c_size_t()
status = _uc.uc_open(arch, mode, ctypes.byref(self._uch))
if status != UC_ERR_OK:
self._uch = None
raise UcError(status)
# internal mapping table to save callback & userdata
self._callbacks = {}
self._callback_count = 0
# destructor to be called automatically when object is destroyed.
def __del__(self):
if self._uch:
try:
status = _uc.uc_close(ctypes.byref(self._uch))
if status != UC_ERR_OK:
raise UcError(status)
except: # _uc might be pulled from under our feet
pass
# emulate from @begin, and stop when reaching address @until
def emu_start(self, begin, until, timeout=0, count=0):
status = _uc.uc_emu_start(self._uch, begin, until, timeout, count)
if status != UC_ERR_OK:
raise UcError(status)
# stop emulation
def emu_stop(self):
status = _uc.uc_emu_stop(self._uch)
if status != UC_ERR_OK:
raise UcError(status)
# return the value of a register
def reg_read(self, reg_id):
# read to 64bit number to be safe
reg = ctypes.c_int64(0)
status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg))
if status != UC_ERR_OK:
raise UcError(status)
return reg.value
# write to a register
def reg_write(self, reg_id, value):
# convert to 64bit number to be safe
reg = ctypes.c_int64(value)
status = _uc.uc_reg_write(self._uch, reg_id, ctypes.byref(reg))
if status != UC_ERR_OK:
raise UcError(status)
# read data from memory
def mem_read(self, address, size):
data = ctypes.create_string_buffer(size)
status = _uc.uc_mem_read(self._uch, address, data, size)
if status != UC_ERR_OK:
raise UcError(status)
return bytearray(data)
# write to memory
def mem_write(self, address, data):
status = _uc.uc_mem_write(self._uch, address, data, len(data))
if status != UC_ERR_OK:
raise UcError(status)
# map a range of memory
def mem_map(self, address, size):
status = _uc.uc_mem_map(self._uch, address, size)
if status != UC_ERR_OK:
raise UcError(status)
def _hookcode_cb(self, handle, address, size, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
cb(self, address, size, data)
def _hook_mem_invalid_cb(self, handle, access, address, size, value, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
return cb(self, access, address, size, value, data)
def _hook_mem_access_cb(self, handle, access, address, size, value, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
cb(self, access, address, size, value, data)
def _hook_intr_cb(self, handle, intno, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
cb(self, intno, data)
def _hook_insn_in_cb(self, handle, port, size, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
return cb(self, port, size, data)
def _hook_insn_out_cb(self, handle, port, size, value, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
cb(self, port, size, value, data)
def _hook_insn_syscall_cb(self, handle, user_data):
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
cb(self, data)
# add a hook
def hook_add(self, htype, callback, user_data=None, arg1=1, arg2=0):
_h2 = ctypes.c_size_t()
# save callback & user_data
self._callback_count += 1
self._callbacks[self._callback_count] = (callback, user_data)
if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE):
begin = ctypes.c_uint64(arg1)
end = ctypes.c_uint64(arg2)
# set callback with wrapper, so it can be called
# with this object as param
cb = ctypes.cast(UC_HOOK_CODE_CB(self._hookcode_cb), UC_HOOK_CODE_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \
ctypes.cast(self._callback_count, ctypes.c_void_p), begin, end)
elif htype == UC_HOOK_MEM_INVALID:
cb = ctypes.cast(UC_HOOK_MEM_INVALID_CB(self._hook_mem_invalid_cb), UC_HOOK_MEM_INVALID_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
elif htype in (UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ_WRITE):
cb = ctypes.cast(UC_HOOK_MEM_ACCESS_CB(self._hook_mem_access_cb), UC_HOOK_MEM_ACCESS_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
elif htype == UC_HOOK_INSN:
insn = ctypes.c_int(arg1)
if arg1 == x86_const.UC_X86_INS_IN: # IN instruction
cb = ctypes.cast(UC_HOOK_INSN_IN_CB(self._hook_insn_in_cb), UC_HOOK_INSN_IN_CB)
if arg1 == x86_const.UC_X86_INS_OUT: # OUT instruction
cb = ctypes.cast(UC_HOOK_INSN_OUT_CB(self._hook_insn_out_cb), UC_HOOK_INSN_OUT_CB)
if arg1 in (x86_const.UC_X86_INS_SYSCALL, x86_const.UC_X86_INS_SYSENTER): # SYSCALL/SYSENTER instruction
cb = ctypes.cast(UC_HOOK_INSN_SYSCALL_CB(self._hook_insn_syscall_cb), UC_HOOK_INSN_SYSCALL_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p), insn)
elif htype == UC_HOOK_INTR:
cb = ctypes.cast(UC_HOOK_INTR_CB(self._hook_intr_cb), UC_HOOK_INTR_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
if status != UC_ERR_OK:
raise UcError(status)
return _h2.value
# delete a hook
def hook_del(self, h):
_h = ctypes.c_size_t(h)
status = _uc.uc_hook_del(self._uch, ctypes.byref(_h))
if status != UC_ERR_OK:
raise UcError(status)
h = 0
# print out debugging info
def debug():
archs = { "arm": UC_ARCH_ARM, "arm64": UC_ARCH_ARM64, \
"mips": UC_ARCH_MIPS, "sparc": UC_ARCH_SPARC, \
"m68k": UC_ARCH_M68K, "x86": UC_ARCH_X86 }
all_archs = ""
keys = archs.keys()
keys.sort()
for k in keys:
if uc_arch_supported(archs[k]):
all_archs += "-%s" % k
(major, minor, _combined) = uc_version()
return "python-%s-c%u.%u-b%u.%u" % (all_archs, major, minor, UC_API_MAJOR, UC_API_MINOR)

View file

@ -0,0 +1,60 @@
# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [unicorn_const.py]
UC_API_MAJOR = 0
UC_API_MINOR = 9
UC_SECOND_SCALE = 1000000
UC_MILISECOND_SCALE = 1000
UC_ARCH_ARM = 1
UC_ARCH_ARM64 = 2
UC_ARCH_MIPS = 3
UC_ARCH_X86 = 4
UC_ARCH_PPC = 5
UC_ARCH_SPARC = 6
UC_ARCH_M68K = 7
UC_ARCH_MAX = 8
UC_MODE_LITTLE_ENDIAN = 0
UC_MODE_ARM = 0
UC_MODE_16 = 2
UC_MODE_32 = 4
UC_MODE_64 = 8
UC_MODE_THUMB = 16
UC_MODE_MCLASS = 32
UC_MODE_V8 = 64
UC_MODE_MICRO = 16
UC_MODE_MIPS3 = 32
UC_MODE_MIPS32R6 = 64
UC_MODE_V9 = 16
UC_MODE_QPX = 16
UC_MODE_BIG_ENDIAN = 2147483648
UC_MODE_MIPS32 = 4
UC_MODE_MIPS64 = 8
UC_ERR_OK = 0
UC_ERR_OOM = 1
UC_ERR_ARCH = 2
UC_ERR_HANDLE = 3
UC_ERR_UCH = 4
UC_ERR_MODE = 5
UC_ERR_VERSION = 6
UC_ERR_MEM_READ = 7
UC_ERR_MEM_WRITE = 8
UC_ERR_CODE_INVALID = 9
UC_ERR_HOOK = 10
UC_ERR_INSN_INVALID = 11
UC_ERR_MAP = 12
UC_MEM_READ = 16
UC_MEM_WRITE = 17
UC_MEM_READ_WRITE = 18
UC_HOOK_INTR = 32
UC_HOOK_INSN = 33
UC_HOOK_CODE = 34
UC_HOOK_BLOCK = 35
UC_HOOK_MEM_INVALID = 36
UC_HOOK_MEM_READ = 37
UC_HOOK_MEM_WRITE = 38
UC_HOOK_MEM_READ_WRITE = 39
UC_PROT_READ = 1
UC_PROT_WRITE = 2
UC_PROT_EXEC = 4