1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
|
# By Dang Hoang Vu <danghvu@gmail.com>, 2014
cimport pyx.ccapstone as cc
import capstone, ctypes
from capstone import arm, x86, mips, ppc, arm64, CsError
_diet = cc.cs_support(capstone.CS_SUPPORT_DIET)
class CsDetail(object):
def __init__(self, arch, raw_detail = None):
if not raw_detail:
return
detail = ctypes.cast(raw_detail, ctypes.POINTER(capstone._cs_detail)).contents
self.regs_read = detail.regs_read
self.regs_read_count = detail.regs_read_count
self.regs_write = detail.regs_write
self.regs_write_count = detail.regs_write_count
self.groups = detail.groups
self.groups_count = detail.groups_count
if arch == capstone.CS_ARCH_ARM:
(self.cc, self.update_flags, self.writeback, self.operands) = \
arm.get_arch_info(detail.arch.arm)
elif arch == capstone.CS_ARCH_ARM64:
(self.cc, self.update_flags, self.writeback, self.operands) = \
arm64.get_arch_info(detail.arch.arm64)
elif arch == capstone.CS_ARCH_X86:
(self.prefix, self.segment, self.opcode, self.op_size, self.addr_size, \
self.disp_size, self.imm_size, self.modrm, self.sib, self.disp, \
self.sib_index, self.sib_scale, self.sib_base, self.operands) = x86.get_arch_info(detail.arch.x86)
elif arch == capstone.CS_ARCH_MIPS:
self.operands = mips.get_arch_info(detail.arch.mips)
elif arch == capstone.CS_ARCH_PPC:
(self.bc, self.bh, self.update_cr0, self.operands) = \
ppc.get_arch_info(detail.arch.ppc)
cdef class CsInsn(object):
cdef cc.cs_insn _raw
cdef cc.csh _csh
cdef object _detail
def __cinit__(self, _detail):
self._detail = _detail
# defer to CsDetail structure for everything else.
def __getattr__(self, name):
_detail = self._detail
if not _detail:
raise CsError(capstone.CS_ERR_DETAIL)
return getattr(_detail, name)
# return instruction's operands.
@property
def operands(self):
return self._detail.operands
# return instruction's ID.
@property
def id(self):
return self._raw.id
# return instruction's address.
@property
def address(self):
return self._raw.address
# return instruction's size.
@property
def size(self):
return self._raw.size
# return instruction's machine bytes (which should have @size bytes).
@property
def bytes(self):
return bytearray(self._raw.bytes)[:self._raw.size]
# return instruction's mnemonic.
@property
def mnemonic(self):
if _diet:
# Diet engine cannot provide @mnemonic & @op_str
raise CsError(capstone.CS_ERR_DIET)
return self._raw.mnemonic
# return instruction's operands (in string).
@property
def op_str(self):
if _diet:
# Diet engine cannot provide @mnemonic & @op_str
raise CsError(capstone.CS_ERR_DIET)
return self._raw.op_str
# return list of all implicit registers being read.
@property
def regs_read(self):
if _diet:
# Diet engine cannot provide @regs_read
raise CsError(capstone.CS_ERR_DIET)
if self._detail:
detail = self._detail
return detail.regs_read[:detail.regs_read_count]
raise CsError(capstone.CS_ERR_DETAIL)
# return list of all implicit registers being modified
@property
def regs_write(self):
if _diet:
# Diet engine cannot provide @regs_write
raise CsError(capstone.CS_ERR_DIET)
if self._detail:
detail = self._detail
return detail.regs_write[:detail.regs_write_count]
raise CsError(capstone.CS_ERR_DETAIL)
# return list of semantic groups this instruction belongs to.
@property
def groups(self):
if _diet:
# Diet engine cannot provide @groups
raise CsError(capstone.CS_ERR_DIET)
if self._detail:
detail = self._detail
return detail.groups[:detail.groups_count]
raise CsError(capstone.CS_ERR_DETAIL)
# get the last error code
def errno(self):
return cc.cs_errno(self._csh)
# get the register name, given the register ID
def reg_name(self, reg_id):
if _diet:
# Diet engine cannot provide register's name
raise CsError(capstone.CS_ERR_DIET)
return cc.cs_reg_name(self._csh, reg_id)
# get the instruction string
def insn_name(self):
if _diet:
# Diet engine cannot provide instruction's name
raise CsError(capstone.CS_ERR_DIET)
return cc.cs_insn_name(self._csh, self.id)
# verify if this insn belong to group with id as @group_id
def group(self, group_id):
if _diet:
# Diet engine cannot provide @groups
raise CsError(capstone.CS_ERR_DIET)
return group_id in self.groups
# verify if this instruction implicitly read register @reg_id
def reg_read(self, reg_id):
if _diet:
# Diet engine cannot provide @regs_read
raise CsError(capstone.CS_ERR_DIET)
return reg_id in self.regs_read
# verify if this instruction implicitly modified register @reg_id
def reg_write(self, reg_id):
if _diet:
# Diet engine cannot provide @regs_write
raise CsError(capstone.CS_ERR_DIET)
return reg_id in self.regs_write
# return number of operands having same operand type @op_type
def op_count(self, op_type):
c = 0
for op in self._detail.operands:
if op.type == op_type:
c += 1
return c
# get the operand at position @position of all operands having the same type @op_type
def op_find(self, op_type, position):
c = 0
for op in self._detail.operands:
if op.type == op_type:
c += 1
if c == position:
return op
cdef class Cs(object):
cdef cc.csh csh
cdef object _cs
def __cinit__(self, _cs):
cdef version = cc.cs_version(NULL, NULL)
if (version != (capstone.CS_API_MAJOR << 8) + capstone.CS_API_MINOR):
# our binding version is different from the core's API version
raise CsError(capstone.CS_ERR_VERSION)
self.csh = <cc.csh> _cs.csh.value
self._cs = _cs
# destructor to be called automatically when object is destroyed.
def __dealloc__(self):
if self.csh:
status = cc.cs_close(&self.csh)
if status != capstone.CS_ERR_OK:
raise CsError(status)
# Disassemble binary & return disassembled instructions in CsInsn objects
def disasm(self, code, addr, count=0):
cdef cc.cs_insn *allinsn
cdef res = cc.cs_disasm_ex(self.csh, code, len(code), addr, count, &allinsn)
detail = self._cs.detail
arch = self._cs.arch
for i from 0 <= i < res:
if detail:
dummy = CsInsn(CsDetail(arch, <size_t>allinsn[i].detail))
else:
dummy = CsInsn(None)
dummy._raw = allinsn[i]
dummy._csh = self.csh
yield dummy
cc.cs_free(allinsn, res)
# Light function to disassemble binary. This is about 20% faster than disasm() because
# unlike disasm(), disasm_lite() only return tuples of (address, size, mnemonic, op_str),
# rather than CsInsn objects.
def disasm_lite(self, code, addr, count=0):
# TODO: dont need detail, so we might turn off detail, then turn on again when done
cdef cc.cs_insn *allinsn
if _diet:
# Diet engine cannot provide @mnemonic & @op_str
raise CsError(capstone.CS_ERR_DIET)
cdef res = cc.cs_disasm_ex(self.csh, code, len(code), addr, count, &allinsn)
for i from 0 <= i < res:
insn = allinsn[i]
yield (insn.address, insn.size, insn.mnemonic, insn.op_str)
cc.cs_free(allinsn, res)
# print out debugging info
def debug():
if cc.cs_support(capstone.CS_SUPPORT_DIET):
diet = "diet"
else:
diet = "standard"
archs = { "arm": capstone.CS_ARCH_ARM, "arm64": capstone.CS_ARCH_ARM64, \
"mips": capstone.CS_ARCH_MIPS, "ppc": capstone.CS_ARCH_PPC, \
"x86": capstone.CS_ARCH_X86 }
all_archs = ""
keys = archs.keys()
keys.sort()
for k in keys:
if cc.cs_support(archs[k]):
all_archs += "-%s" %k
(major, minor, _combined) = capstone.cs_version()
return "Cython-%s%s-c%u.%u-b%u.%u" %(diet, all_archs, major, minor, capstone.CS_API_MAJOR, capstone.CS_API_MINOR)
|