1# Capstone Python bindings, by Nguyen Anh Quynnh <aquynh@gmail.com> 2import sys 3from platform import system 4_python2 = sys.version_info[0] < 3 5if _python2: 6 range = xrange 7 8__all__ = [ 9 'Cs', 10 'CsInsn', 11 12 'cs_disasm_quick', 13 'cs_disasm_lite', 14 'cs_version', 15 'cs_support', 16 'version_bind', 17 'debug', 18 19 'CS_API_MAJOR', 20 'CS_API_MINOR', 21 22 'CS_VERSION_MAJOR', 23 'CS_VERSION_MINOR', 24 'CS_VERSION_EXTRA', 25 26 'CS_ARCH_ARM', 27 'CS_ARCH_ARM64', 28 'CS_ARCH_MIPS', 29 'CS_ARCH_X86', 30 'CS_ARCH_PPC', 31 'CS_ARCH_SPARC', 32 'CS_ARCH_SYSZ', 33 'CS_ARCH_XCORE', 34 'CS_ARCH_ALL', 35 36 'CS_MODE_LITTLE_ENDIAN', 37 'CS_MODE_BIG_ENDIAN', 38 'CS_MODE_16', 39 'CS_MODE_32', 40 'CS_MODE_64', 41 'CS_MODE_ARM', 42 'CS_MODE_THUMB', 43 'CS_MODE_MCLASS', 44 'CS_MODE_MICRO', 45 'CS_MODE_MIPS3', 46 'CS_MODE_MIPS32R6', 47 'CS_MODE_MIPSGP64', 48 'CS_MODE_V8', 49 'CS_MODE_V9', 50 'CS_MODE_MIPS32', 51 'CS_MODE_MIPS64', 52 53 'CS_OPT_SYNTAX', 54 'CS_OPT_SYNTAX_DEFAULT', 55 'CS_OPT_SYNTAX_INTEL', 56 'CS_OPT_SYNTAX_ATT', 57 'CS_OPT_SYNTAX_NOREGNAME', 58 59 'CS_OPT_DETAIL', 60 'CS_OPT_MODE', 61 'CS_OPT_ON', 62 'CS_OPT_OFF', 63 64 'CS_ERR_OK', 65 'CS_ERR_MEM', 66 'CS_ERR_ARCH', 67 'CS_ERR_HANDLE', 68 'CS_ERR_CSH', 69 'CS_ERR_MODE', 70 'CS_ERR_OPTION', 71 'CS_ERR_DETAIL', 72 'CS_ERR_VERSION', 73 'CS_ERR_MEMSETUP', 74 'CS_ERR_DIET', 75 'CS_ERR_SKIPDATA', 76 'CS_ERR_X86_ATT', 77 'CS_ERR_X86_INTEL', 78 79 'CS_SUPPORT_DIET', 80 'CS_SUPPORT_X86_REDUCE', 81 'CS_SKIPDATA_CALLBACK', 82 83 'CS_OP_INVALID', 84 'CS_OP_REG', 85 'CS_OP_IMM', 86 'CS_OP_MEM', 87 'CS_OP_FP', 88 89 'CS_GRP_INVALID', 90 'CS_GRP_JUMP', 91 'CS_GRP_CALL', 92 'CS_GRP_RET', 93 'CS_GRP_INT', 94 'CS_GRP_IRET', 95 96 'CsError', 97 98 '__version__', 99] 100 101# Capstone C interface 102 103# API version 104CS_API_MAJOR = 3 105CS_API_MINOR = 0 106 107# Package version 108CS_VERSION_MAJOR = CS_API_MAJOR 109CS_VERSION_MINOR = CS_API_MINOR 110CS_VERSION_EXTRA = 5 111 112__version__ = "%u.%u.%u" %(CS_VERSION_MAJOR, CS_VERSION_MINOR, CS_VERSION_EXTRA) 113 114# architectures 115CS_ARCH_ARM = 0 116CS_ARCH_ARM64 = 1 117CS_ARCH_MIPS = 2 118CS_ARCH_X86 = 3 119CS_ARCH_PPC = 4 120CS_ARCH_SPARC = 5 121CS_ARCH_SYSZ = 6 122CS_ARCH_XCORE = 7 123CS_ARCH_MAX = 8 124CS_ARCH_ALL = 0xFFFF 125 126# disasm mode 127CS_MODE_LITTLE_ENDIAN = 0 # little-endian mode (default mode) 128CS_MODE_ARM = 0 # ARM mode 129CS_MODE_16 = (1 << 1) # 16-bit mode (for X86) 130CS_MODE_32 = (1 << 2) # 32-bit mode (for X86) 131CS_MODE_64 = (1 << 3) # 64-bit mode (for X86, PPC) 132CS_MODE_THUMB = (1 << 4) # ARM's Thumb mode, including Thumb-2 133CS_MODE_MCLASS = (1 << 5) # ARM's Cortex-M series 134CS_MODE_V8 = (1 << 6) # ARMv8 A32 encodings for ARM 135CS_MODE_MICRO = (1 << 4) # MicroMips mode (MIPS architecture) 136CS_MODE_MIPS3 = (1 << 5) # Mips III ISA 137CS_MODE_MIPS32R6 = (1 << 6) # Mips32r6 ISA 138CS_MODE_MIPSGP64 = (1 << 7) # General Purpose Registers are 64-bit wide (MIPS arch) 139CS_MODE_V9 = (1 << 4) # Sparc V9 mode (for Sparc) 140CS_MODE_BIG_ENDIAN = (1 << 31) # big-endian mode 141CS_MODE_MIPS32 = CS_MODE_32 # Mips32 ISA 142CS_MODE_MIPS64 = CS_MODE_64 # Mips64 ISA 143 144# Capstone option type 145CS_OPT_SYNTAX = 1 # Intel X86 asm syntax (CS_ARCH_X86 arch) 146CS_OPT_DETAIL = 2 # Break down instruction structure into details 147CS_OPT_MODE = 3 # Change engine's mode at run-time 148CS_OPT_MEM = 4 # Change engine's mode at run-time 149CS_OPT_SKIPDATA = 5 # Skip data when disassembling 150CS_OPT_SKIPDATA_SETUP = 6 # Setup user-defined function for SKIPDATA option 151 152# Capstone option value 153CS_OPT_OFF = 0 # Turn OFF an option - default option of CS_OPT_DETAIL 154CS_OPT_ON = 3 # Turn ON an option (CS_OPT_DETAIL) 155 156# Common instruction operand types - to be consistent across all architectures. 157CS_OP_INVALID = 0 158CS_OP_REG = 1 159CS_OP_IMM = 2 160CS_OP_MEM = 3 161CS_OP_FP = 4 162 163# Common instruction groups - to be consistent across all architectures. 164CS_GRP_INVALID = 0 # uninitialized/invalid group. 165CS_GRP_JUMP = 1 # all jump instructions (conditional+direct+indirect jumps) 166CS_GRP_CALL = 2 # all call instructions 167CS_GRP_RET = 3 # all return instructions 168CS_GRP_INT = 4 # all interrupt instructions (int+syscall) 169CS_GRP_IRET = 5 # all interrupt return instructions 170 171# Capstone syntax value 172CS_OPT_SYNTAX_DEFAULT = 0 # Default assembly syntax of all platforms (CS_OPT_SYNTAX) 173CS_OPT_SYNTAX_INTEL = 1 # Intel X86 asm syntax - default syntax on X86 (CS_OPT_SYNTAX, CS_ARCH_X86) 174CS_OPT_SYNTAX_ATT = 2 # ATT asm syntax (CS_OPT_SYNTAX, CS_ARCH_X86) 175CS_OPT_SYNTAX_NOREGNAME = 3 # Asm syntax prints register name with only number - (CS_OPT_SYNTAX, CS_ARCH_PPC, CS_ARCH_ARM) 176 177# Capstone error type 178CS_ERR_OK = 0 # No error: everything was fine 179CS_ERR_MEM = 1 # Out-Of-Memory error: cs_open(), cs_disasm() 180CS_ERR_ARCH = 2 # Unsupported architecture: cs_open() 181CS_ERR_HANDLE = 3 # Invalid handle: cs_op_count(), cs_op_index() 182CS_ERR_CSH = 4 # Invalid csh argument: cs_close(), cs_errno(), cs_option() 183CS_ERR_MODE = 5 # Invalid/unsupported mode: cs_open() 184CS_ERR_OPTION = 6 # Invalid/unsupported option: cs_option() 185CS_ERR_DETAIL = 7 # Invalid/unsupported option: cs_option() 186CS_ERR_MEMSETUP = 8 187CS_ERR_VERSION = 9 # Unsupported version (bindings) 188CS_ERR_DIET = 10 # Information irrelevant in diet engine 189CS_ERR_SKIPDATA = 11 # Access irrelevant data for "data" instruction in SKIPDATA mode 190CS_ERR_X86_ATT = 12 # X86 AT&T syntax is unsupported (opt-out at compile time) 191CS_ERR_X86_INTEL = 13 # X86 Intel syntax is unsupported (opt-out at compile time) 192 193# query id for cs_support() 194CS_SUPPORT_DIET = CS_ARCH_ALL + 1 195CS_SUPPORT_X86_REDUCE = CS_ARCH_ALL+2 196 197 198import ctypes, ctypes.util 199from os.path import split, join, dirname 200import distutils.sysconfig 201import pkg_resources 202 203import inspect 204if not hasattr(sys.modules[__name__], '__file__'): 205 __file__ = inspect.getfile(inspect.currentframe()) 206 207if sys.platform == 'darwin': 208 _lib = "libcapstone.dylib" 209elif sys.platform in ('win32', 'cygwin'): 210 _lib = "capstone.dll" 211else: 212 _lib = "libcapstone.so" 213 214_found = False 215 216def _load_lib(path): 217 lib_file = join(path, _lib) 218 #print("Trying to load %s" %lib_file) 219 try: 220 return ctypes.cdll.LoadLibrary(lib_file) 221 except OSError: 222 # if we're on linux, try again with .so.3 extension 223 if lib_file.endswith('.so'): 224 try: 225 return ctypes.cdll.LoadLibrary(lib_file + '.3') 226 except OSError: 227 return None 228 return None 229 230_cs = None 231 232# Loading attempts, in order 233# - pkg_resources can get us the path to the local libraries 234# - we can get the path to the local libraries by parsing our filename 235# - global load 236# - python's lib directory 237# - last-gasp attempt at some hardcoded paths on darwin and linux 238 239_path_list = [pkg_resources.resource_filename(__name__, 'lib'), 240 join(split(__file__)[0], 'lib'), 241 '', 242 distutils.sysconfig.get_python_lib(), 243 "/usr/local/lib/" if sys.platform == 'darwin' else '/usr/lib64'] 244 245for _path in _path_list: 246 _cs = _load_lib(_path) 247 if _cs is not None: break 248else: 249 raise ImportError("ERROR: fail to load the dynamic library.") 250 251 252# low-level structure for C code 253 254def copy_ctypes(src): 255 """Returns a new ctypes object which is a bitwise copy of an existing one""" 256 dst = type(src)() 257 ctypes.memmove(ctypes.byref(dst), ctypes.byref(src), ctypes.sizeof(type(src))) 258 return dst 259 260def copy_ctypes_list(src): 261 return [copy_ctypes(n) for n in src] 262 263# Weird import placement because these modules are needed by the below code but need the above functions 264from . import arm, arm64, mips, ppc, sparc, systemz, x86, xcore 265 266class _cs_arch(ctypes.Union): 267 _fields_ = ( 268 ('arm64', arm64.CsArm64), 269 ('arm', arm.CsArm), 270 ('mips', mips.CsMips), 271 ('x86', x86.CsX86), 272 ('ppc', ppc.CsPpc), 273 ('sparc', sparc.CsSparc), 274 ('sysz', systemz.CsSysz), 275 ('xcore', xcore.CsXcore), 276 ) 277 278class _cs_detail(ctypes.Structure): 279 _fields_ = ( 280 ('regs_read', ctypes.c_ubyte * 12), 281 ('regs_read_count', ctypes.c_ubyte), 282 ('regs_write', ctypes.c_ubyte * 20), 283 ('regs_write_count', ctypes.c_ubyte), 284 ('groups', ctypes.c_ubyte * 8), 285 ('groups_count', ctypes.c_ubyte), 286 ('arch', _cs_arch), 287 ) 288 289class _cs_insn(ctypes.Structure): 290 _fields_ = ( 291 ('id', ctypes.c_uint), 292 ('address', ctypes.c_uint64), 293 ('size', ctypes.c_uint16), 294 ('bytes', ctypes.c_ubyte * 16), 295 ('mnemonic', ctypes.c_char * 32), 296 ('op_str', ctypes.c_char * 160), 297 ('detail', ctypes.POINTER(_cs_detail)), 298 ) 299 300# callback for SKIPDATA option 301CS_SKIPDATA_CALLBACK = ctypes.CFUNCTYPE(ctypes.c_size_t, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t, ctypes.c_size_t, ctypes.c_void_p) 302 303class _cs_opt_skipdata(ctypes.Structure): 304 _fields_ = ( 305 ('mnemonic', ctypes.c_char_p), 306 ('callback', CS_SKIPDATA_CALLBACK), 307 ('user_data', ctypes.c_void_p), 308 ) 309 310 311# setup all the function prototype 312def _setup_prototype(lib, fname, restype, *argtypes): 313 getattr(lib, fname).restype = restype 314 getattr(lib, fname).argtypes = argtypes 315 316_setup_prototype(_cs, "cs_open", ctypes.c_int, ctypes.c_uint, ctypes.c_uint, ctypes.POINTER(ctypes.c_size_t)) 317_setup_prototype(_cs, "cs_disasm", ctypes.c_size_t, ctypes.c_size_t, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t, \ 318 ctypes.c_uint64, ctypes.c_size_t, ctypes.POINTER(ctypes.POINTER(_cs_insn))) 319_setup_prototype(_cs, "cs_free", None, ctypes.c_void_p, ctypes.c_size_t) 320_setup_prototype(_cs, "cs_close", ctypes.c_int, ctypes.POINTER(ctypes.c_size_t)) 321_setup_prototype(_cs, "cs_reg_name", ctypes.c_char_p, ctypes.c_size_t, ctypes.c_uint) 322_setup_prototype(_cs, "cs_insn_name", ctypes.c_char_p, ctypes.c_size_t, ctypes.c_uint) 323_setup_prototype(_cs, "cs_group_name", ctypes.c_char_p, ctypes.c_size_t, ctypes.c_uint) 324_setup_prototype(_cs, "cs_op_count", ctypes.c_int, ctypes.c_size_t, ctypes.POINTER(_cs_insn), ctypes.c_uint) 325_setup_prototype(_cs, "cs_op_index", ctypes.c_int, ctypes.c_size_t, ctypes.POINTER(_cs_insn), ctypes.c_uint, ctypes.c_uint) 326_setup_prototype(_cs, "cs_errno", ctypes.c_int, ctypes.c_size_t) 327_setup_prototype(_cs, "cs_option", ctypes.c_int, ctypes.c_size_t, ctypes.c_int, ctypes.c_void_p) 328_setup_prototype(_cs, "cs_version", ctypes.c_int, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) 329_setup_prototype(_cs, "cs_support", ctypes.c_bool, ctypes.c_int) 330_setup_prototype(_cs, "cs_strerror", ctypes.c_char_p, ctypes.c_int) 331 332 333# access to error code via @errno of CsError 334class CsError(Exception): 335 def __init__(self, errno): 336 self.errno = errno 337 338 if _python2: 339 def __str__(self): 340 return _cs.cs_strerror(self.errno) 341 342 else: 343 def __str__(self): 344 return _cs.cs_strerror(self.errno).decode() 345 346 347# return the core's version 348def cs_version(): 349 major = ctypes.c_int() 350 minor = ctypes.c_int() 351 combined = _cs.cs_version(ctypes.byref(major), ctypes.byref(minor)) 352 return (major.value, minor.value, combined) 353 354 355# return the binding's version 356def version_bind(): 357 return (CS_API_MAJOR, CS_API_MINOR, (CS_API_MAJOR << 8) + CS_API_MINOR) 358 359 360def cs_support(query): 361 return _cs.cs_support(query) 362 363 364# dummy class resembling Cs class, just for cs_disasm_quick() 365# this class only need to be referenced to via 2 fields: @csh & @arch 366class _dummy_cs(object): 367 def __init__(self, csh, arch): 368 self.csh = csh 369 self.arch = arch 370 self._detail = False 371 372 373# Quick & dirty Python function to disasm raw binary code 374# This function return CsInsn objects 375# NOTE: you might want to use more efficient Cs class & its methods. 376def cs_disasm_quick(arch, mode, code, offset, count=0): 377 # verify version compatibility with the core before doing anything 378 (major, minor, _combined) = cs_version() 379 if major != CS_API_MAJOR or minor != CS_API_MINOR: 380 # our binding version is different from the core's API version 381 raise CsError(CS_ERR_VERSION) 382 383 csh = ctypes.c_size_t() 384 status = _cs.cs_open(arch, mode, ctypes.byref(csh)) 385 if status != CS_ERR_OK: 386 raise CsError(status) 387 388 all_insn = ctypes.POINTER(_cs_insn)() 389 res = _cs.cs_disasm(csh, code, len(code), offset, count, ctypes.byref(all_insn)) 390 if res > 0: 391 try: 392 for i in range(res): 393 yield CsInsn(_dummy_cs(csh, arch), all_insn[i]) 394 finally: 395 _cs.cs_free(all_insn, res) 396 else: 397 status = _cs.cs_errno(csh) 398 if status != CS_ERR_OK: 399 raise CsError(status) 400 return 401 yield 402 403 status = _cs.cs_close(ctypes.byref(csh)) 404 if status != CS_ERR_OK: 405 raise CsError(status) 406 407 408# Another quick, but lighter function to disasm raw binary code. 409# This function is faster than cs_disasm_quick() around 20% because 410# cs_disasm_lite() only return tuples of (address, size, mnemonic, op_str), 411# rather than CsInsn objects. 412# NOTE: you might want to use more efficient Cs class & its methods. 413def cs_disasm_lite(arch, mode, code, offset, count=0): 414 # verify version compatibility with the core before doing anything 415 (major, minor, _combined) = cs_version() 416 if major != CS_API_MAJOR or minor != CS_API_MINOR: 417 # our binding version is different from the core's API version 418 raise CsError(CS_ERR_VERSION) 419 420 if cs_support(CS_SUPPORT_DIET): 421 # Diet engine cannot provide @mnemonic & @op_str 422 raise CsError(CS_ERR_DIET) 423 424 csh = ctypes.c_size_t() 425 status = _cs.cs_open(arch, mode, ctypes.byref(csh)) 426 if status != CS_ERR_OK: 427 raise CsError(status) 428 429 all_insn = ctypes.POINTER(_cs_insn)() 430 res = _cs.cs_disasm(csh, code, len(code), offset, count, ctypes.byref(all_insn)) 431 if res > 0: 432 try: 433 for i in range(res): 434 insn = all_insn[i] 435 yield (insn.address, insn.size, insn.mnemonic.decode('ascii'), insn.op_str.decode('ascii')) 436 finally: 437 _cs.cs_free(all_insn, res) 438 else: 439 status = _cs.cs_errno(csh) 440 if status != CS_ERR_OK: 441 raise CsError(status) 442 return 443 yield 444 445 status = _cs.cs_close(ctypes.byref(csh)) 446 if status != CS_ERR_OK: 447 raise CsError(status) 448 449 450# Python-style class to disasm code 451class CsInsn(object): 452 def __init__(self, cs, all_info): 453 self._raw = copy_ctypes(all_info) 454 self._cs = cs 455 if self._cs._detail and self._raw.id != 0: 456 # save detail 457 self._detail = copy_ctypes(self._raw.detail.contents) 458 459 # return instruction's ID. 460 @property 461 def id(self): 462 return self._raw.id 463 464 # return instruction's address. 465 @property 466 def address(self): 467 return self._raw.address 468 469 # return instruction's size. 470 @property 471 def size(self): 472 return self._raw.size 473 474 # return instruction's machine bytes (which should have @size bytes). 475 @property 476 def bytes(self): 477 return bytearray(self._raw.bytes)[:self._raw.size] 478 479 # return instruction's mnemonic. 480 @property 481 def mnemonic(self): 482 if self._cs._diet: 483 # Diet engine cannot provide @mnemonic. 484 raise CsError(CS_ERR_DIET) 485 486 return self._raw.mnemonic.decode('ascii') 487 488 # return instruction's operands (in string). 489 @property 490 def op_str(self): 491 if self._cs._diet: 492 # Diet engine cannot provide @op_str. 493 raise CsError(CS_ERR_DIET) 494 495 return self._raw.op_str.decode('ascii') 496 497 # return list of all implicit registers being read. 498 @property 499 def regs_read(self): 500 if self._raw.id == 0: 501 raise CsError(CS_ERR_SKIPDATA) 502 503 if self._cs._diet: 504 # Diet engine cannot provide @regs_read. 505 raise CsError(CS_ERR_DIET) 506 507 if self._cs._detail: 508 return self._detail.regs_read[:self._detail.regs_read_count] 509 510 raise CsError(CS_ERR_DETAIL) 511 512 # return list of all implicit registers being modified 513 @property 514 def regs_write(self): 515 if self._raw.id == 0: 516 raise CsError(CS_ERR_SKIPDATA) 517 518 if self._cs._diet: 519 # Diet engine cannot provide @regs_write 520 raise CsError(CS_ERR_DIET) 521 522 if self._cs._detail: 523 return self._detail.regs_write[:self._detail.regs_write_count] 524 525 raise CsError(CS_ERR_DETAIL) 526 527 # return list of semantic groups this instruction belongs to. 528 @property 529 def groups(self): 530 if self._raw.id == 0: 531 raise CsError(CS_ERR_SKIPDATA) 532 533 if self._cs._diet: 534 # Diet engine cannot provide @groups 535 raise CsError(CS_ERR_DIET) 536 537 if self._cs._detail: 538 return self._detail.groups[:self._detail.groups_count] 539 540 raise CsError(CS_ERR_DETAIL) 541 542 def __gen_detail(self): 543 arch = self._cs.arch 544 if arch == CS_ARCH_ARM: 545 (self.usermode, self.vector_size, self.vector_data, self.cps_mode, self.cps_flag, self.cc, self.update_flags, \ 546 self.writeback, self.mem_barrier, self.operands) = arm.get_arch_info(self._detail.arch.arm) 547 elif arch == CS_ARCH_ARM64: 548 (self.cc, self.update_flags, self.writeback, self.operands) = \ 549 arm64.get_arch_info(self._detail.arch.arm64) 550 elif arch == CS_ARCH_X86: 551 (self.prefix, self.opcode, self.rex, self.addr_size, \ 552 self.modrm, self.sib, self.disp, \ 553 self.sib_index, self.sib_scale, self.sib_base, self.sse_cc, \ 554 self.avx_cc, self.avx_sae, self.avx_rm, self.operands) = x86.get_arch_info(self._detail.arch.x86) 555 elif arch == CS_ARCH_MIPS: 556 self.operands = mips.get_arch_info(self._detail.arch.mips) 557 elif arch == CS_ARCH_PPC: 558 (self.bc, self.bh, self.update_cr0, self.operands) = \ 559 ppc.get_arch_info(self._detail.arch.ppc) 560 elif arch == CS_ARCH_SPARC: 561 (self.cc, self.hint, self.operands) = sparc.get_arch_info(self._detail.arch.sparc) 562 elif arch == CS_ARCH_SYSZ: 563 (self.cc, self.operands) = systemz.get_arch_info(self._detail.arch.sysz) 564 elif arch == CS_ARCH_XCORE: 565 (self.operands) = xcore.get_arch_info(self._detail.arch.xcore) 566 567 568 def __getattr__(self, name): 569 if not self._cs._detail: 570 raise CsError(CS_ERR_DETAIL) 571 572 attr = object.__getattribute__ 573 if not attr(self, '_cs')._detail: 574 raise AttributeError(name) 575 _dict = attr(self, '__dict__') 576 if 'operands' not in _dict: 577 self.__gen_detail() 578 if name not in _dict: 579 raise AttributeError(name) 580 return _dict[name] 581 582 # get the last error code 583 def errno(self): 584 return _cs.cs_errno(self._cs.csh) 585 586 # get the register name, given the register ID 587 def reg_name(self, reg_id): 588 if self._raw.id == 0: 589 raise CsError(CS_ERR_SKIPDATA) 590 591 if self._cs._diet: 592 # Diet engine cannot provide register name 593 raise CsError(CS_ERR_DIET) 594 595 if reg_id == 0: 596 return "(invalid)" 597 598 return _cs.cs_reg_name(self._cs.csh, reg_id).decode('ascii') 599 600 # get the instruction name 601 def insn_name(self): 602 if self._cs._diet: 603 # Diet engine cannot provide instruction name 604 raise CsError(CS_ERR_DIET) 605 606 if self._raw.id == 0: 607 return "(invalid)" 608 609 return _cs.cs_insn_name(self._cs.csh, self.id).decode('ascii') 610 611 # get the group name 612 def group_name(self, group_id): 613 if self._raw.id == 0: 614 raise CsError(CS_ERR_SKIPDATA) 615 616 if self._cs._diet: 617 # Diet engine cannot provide register name 618 raise CsError(CS_ERR_DIET) 619 620 if group_id == 0: 621 return "(invalid)" 622 623 return _cs.cs_group_name(self._cs.csh, group_id).decode('ascii') 624 625 626 # verify if this insn belong to group with id as @group_id 627 def group(self, group_id): 628 if self._raw.id == 0: 629 raise CsError(CS_ERR_SKIPDATA) 630 631 if self._cs._diet: 632 # Diet engine cannot provide group information 633 raise CsError(CS_ERR_DIET) 634 635 return group_id in self.groups 636 637 # verify if this instruction implicitly read register @reg_id 638 def reg_read(self, reg_id): 639 if self._raw.id == 0: 640 raise CsError(CS_ERR_SKIPDATA) 641 642 if self._cs._diet: 643 # Diet engine cannot provide regs_read information 644 raise CsError(CS_ERR_DIET) 645 646 return reg_id in self.regs_read 647 648 # verify if this instruction implicitly modified register @reg_id 649 def reg_write(self, reg_id): 650 if self._raw.id == 0: 651 raise CsError(CS_ERR_SKIPDATA) 652 653 if self._cs._diet: 654 # Diet engine cannot provide regs_write information 655 raise CsError(CS_ERR_DIET) 656 657 return reg_id in self.regs_write 658 659 # return number of operands having same operand type @op_type 660 def op_count(self, op_type): 661 if self._raw.id == 0: 662 raise CsError(CS_ERR_SKIPDATA) 663 664 c = 0 665 for op in self.operands: 666 if op.type == op_type: 667 c += 1 668 return c 669 670 # get the operand at position @position of all operands having the same type @op_type 671 def op_find(self, op_type, position): 672 if self._raw.id == 0: 673 raise CsError(CS_ERR_SKIPDATA) 674 675 c = 0 676 for op in self.operands: 677 if op.type == op_type: 678 c += 1 679 if c == position: 680 return op 681 682 683class Cs(object): 684 def __init__(self, arch, mode): 685 # verify version compatibility with the core before doing anything 686 (major, minor, _combined) = cs_version() 687 if major != CS_API_MAJOR or minor != CS_API_MINOR: 688 self.csh = None 689 # our binding version is different from the core's API version 690 raise CsError(CS_ERR_VERSION) 691 692 self.arch, self._mode = arch, mode 693 self.csh = ctypes.c_size_t() 694 status = _cs.cs_open(arch, mode, ctypes.byref(self.csh)) 695 if status != CS_ERR_OK: 696 self.csh = None 697 raise CsError(status) 698 699 try: 700 import ccapstone 701 # rewire disasm to use the faster version 702 self.disasm = ccapstone.Cs(self).disasm 703 except: 704 pass 705 706 if arch == CS_ARCH_X86: 707 # Intel syntax is default for X86 708 self._syntax = CS_OPT_SYNTAX_INTEL 709 else: 710 self._syntax = None 711 712 self._detail = False # by default, do not produce instruction details 713 self._diet = cs_support(CS_SUPPORT_DIET) 714 self._x86reduce = cs_support(CS_SUPPORT_X86_REDUCE) 715 716 # default mnemonic for SKIPDATA 717 self._skipdata_mnem = ".byte" 718 self._skipdata = False 719 720 721 722 # destructor to be called automatically when object is destroyed. 723 def __del__(self): 724 if self.csh: 725 try: 726 status = _cs.cs_close(ctypes.byref(self.csh)) 727 if status != CS_ERR_OK: 728 raise CsError(status) 729 except: # _cs might be pulled from under our feet 730 pass 731 732 733 # def option(self, opt_type, opt_value): 734 # return _cs.cs_option(self.csh, opt_type, opt_value) 735 736 737 # is this a diet engine? 738 @property 739 def diet(self): 740 return self._diet 741 742 743 # is this engine compiled with X86-reduce option? 744 @property 745 def x86_reduce(self): 746 return self._x86reduce 747 748 749 # return assembly syntax. 750 @property 751 def syntax(self): 752 return self._syntax 753 754 755 # syntax setter: modify assembly syntax. 756 @syntax.setter 757 def syntax(self, style): 758 status = _cs.cs_option(self.csh, CS_OPT_SYNTAX, style) 759 if status != CS_ERR_OK: 760 raise CsError(status) 761 # save syntax 762 self._syntax = style 763 764 765 # return current skipdata status 766 @property 767 def skipdata(self): 768 return self._skipdata 769 770 771 # setter: modify skipdata status 772 @skipdata.setter 773 def skipdata(self, opt): 774 if opt == False: 775 status = _cs.cs_option(self.csh, CS_OPT_SKIPDATA, CS_OPT_OFF) 776 else: 777 status = _cs.cs_option(self.csh, CS_OPT_SKIPDATA, CS_OPT_ON) 778 if status != CS_ERR_OK: 779 raise CsError(status) 780 781 # save this option 782 self._skipdata = opt 783 784 785 def skipdata_setup(self, opt): 786 _skipdata_opt = _cs_opt_skipdata() 787 _mnem, _cb, _ud = opt 788 _skipdata_opt.mnemonic = _mnem.encode() 789 _skipdata_opt.callback = CS_SKIPDATA_CALLBACK(_cb) 790 _skipdata_opt.user_data = ctypes.cast(_ud, ctypes.c_void_p) 791 status = _cs.cs_option(self.csh, CS_OPT_SKIPDATA_SETUP, ctypes.cast(ctypes.byref(_skipdata_opt), ctypes.c_void_p)) 792 if status != CS_ERR_OK: 793 raise CsError(status) 794 795 self._skipdata_opt = _skipdata_opt 796 797 798 # check to see if this engine supports a particular arch, 799 # or diet mode (depending on @query). 800 def support(self, query): 801 return cs_support(query) 802 803 804 # is detail mode enable? 805 @property 806 def detail(self): 807 return self._detail 808 809 810 # modify detail mode. 811 @detail.setter 812 def detail(self, opt): # opt is boolean type, so must be either 'True' or 'False' 813 if opt == False: 814 status = _cs.cs_option(self.csh, CS_OPT_DETAIL, CS_OPT_OFF) 815 else: 816 status = _cs.cs_option(self.csh, CS_OPT_DETAIL, CS_OPT_ON) 817 if status != CS_ERR_OK: 818 raise CsError(status) 819 # save detail 820 self._detail = opt 821 822 823 # return disassembly mode of this engine. 824 @property 825 def mode(self): 826 return self._mode 827 828 829 # modify engine's mode at run-time. 830 @mode.setter 831 def mode(self, opt): # opt is new disasm mode, of int type 832 status = _cs.cs_option(self.csh, CS_OPT_MODE, opt) 833 if status != CS_ERR_OK: 834 raise CsError(status) 835 # save mode 836 self._mode = opt 837 838 839 # Disassemble binary & return disassembled instructions in CsInsn objects 840 def disasm(self, code, offset, count=0): 841 all_insn = ctypes.POINTER(_cs_insn)() 842 '''if not _python2: 843 print(code) 844 code = code.encode() 845 print(code)''' 846 # Hack, unicorn's memory accessors give you back bytearrays, but they 847 # cause TypeErrors when you hand them into Capstone. 848 if isinstance(code, bytearray): 849 code = bytes(code) 850 res = _cs.cs_disasm(self.csh, code, len(code), offset, count, ctypes.byref(all_insn)) 851 if res > 0: 852 try: 853 for i in range(res): 854 yield CsInsn(self, all_insn[i]) 855 finally: 856 _cs.cs_free(all_insn, res) 857 else: 858 status = _cs.cs_errno(self.csh) 859 if status != CS_ERR_OK: 860 raise CsError(status) 861 return 862 yield 863 864 865 # Light function to disassemble binary. This is about 20% faster than disasm() because 866 # unlike disasm(), disasm_lite() only return tuples of (address, size, mnemonic, op_str), 867 # rather than CsInsn objects. 868 def disasm_lite(self, code, offset, count=0): 869 if self._diet: 870 # Diet engine cannot provide @mnemonic & @op_str 871 raise CsError(CS_ERR_DIET) 872 873 all_insn = ctypes.POINTER(_cs_insn)() 874 res = _cs.cs_disasm(self.csh, code, len(code), offset, count, ctypes.byref(all_insn)) 875 if res > 0: 876 try: 877 for i in range(res): 878 insn = all_insn[i] 879 yield (insn.address, insn.size, insn.mnemonic.decode('ascii'), insn.op_str.decode('ascii')) 880 finally: 881 _cs.cs_free(all_insn, res) 882 else: 883 status = _cs.cs_errno(self.csh) 884 if status != CS_ERR_OK: 885 raise CsError(status) 886 return 887 yield 888 889 890# print out debugging info 891def debug(): 892 # is Cython there? 893 try: 894 from . import ccapstone 895 return ccapstone.debug() 896 except: 897 # no Cython, fallback to Python code below 898 pass 899 900 if cs_support(CS_SUPPORT_DIET): 901 diet = "diet" 902 else: 903 diet = "standard" 904 905 archs = { "arm": CS_ARCH_ARM, "arm64": CS_ARCH_ARM64, \ 906 "mips": CS_ARCH_MIPS, "ppc": CS_ARCH_PPC, "sparc": CS_ARCH_SPARC, \ 907 "sysz": CS_ARCH_SYSZ, 'xcore': CS_ARCH_XCORE } 908 909 all_archs = "" 910 keys = archs.keys() 911 for k in sorted(keys): 912 if cs_support(archs[k]): 913 all_archs += "-%s" % k 914 915 if cs_support(CS_ARCH_X86): 916 all_archs += "-x86" 917 if cs_support(CS_SUPPORT_X86_REDUCE): 918 all_archs += "_reduce" 919 920 (major, minor, _combined) = cs_version() 921 922 return "python-%s%s-c%u.%u-b%u.%u" % (diet, all_archs, major, minor, CS_API_MAJOR, CS_API_MINOR) 923