File: pydistorm.py

package info (click to toggle)
pyew 2.0-3
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, wheezy
  • size: 2,252 kB
  • ctags: 1,722
  • sloc: python: 10,791; makefile: 8; sh: 1
file content (129 lines) | stat: -rw-r--r-- 3,596 bytes parent folder | download | duplicates (2)
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
"""
:[diStorm64 1.7.29}:
Copyright RageStorm (C) 2007, Gil Dabah

diStorm is licensed under the BSD license.
http://ragestorm.net/distorm/
---
Python binding for diStorm64 written by Victor Stinner
"""

import platform
from ctypes import cdll, c_long, c_ulong, c_int, c_uint, c_char, c_char_p, POINTER, c_byte, Structure, addressof, byref, c_void_p, create_string_buffer, sizeof, cast

# Define (u)int32_t and (u)int64_t types
int32_t = c_int
uint32_t = c_uint
if sizeof(c_ulong) == 8:
    int64_t = c_long
    uint64_t = c_ulong
else:
    from ctypes import c_longlong, c_ulonglong
    assert sizeof(c_longlong) == 8
    assert sizeof(c_ulonglong) == 8
    int64_t = c_longlong
    uint64_t = c_ulonglong

SUPPORT_64BIT_OFFSET = True
if SUPPORT_64BIT_OFFSET:
    _OffsetType = uint64_t
else:
    _OffsetType = uint32_t

osVer = platform.system()
if osVer == "Windows":
    LIB_FILENAME = "distorm64.dll"
else:
    LIB_FILENAME = 'libdistorm64.so.1'

distorm = cdll.LoadLibrary(LIB_FILENAME)
Decode16Bits = 0
Decode32Bits = 1
Decode64Bits = 2
DECODERS = (Decode16Bits, Decode32Bits, Decode64Bits)

if osVer == "Windows":
    if SUPPORT_64BIT_OFFSET:
        decode_func = distorm.distorm_decode64
    else:
        decode_func = distorm.distorm_decode32
else:
    decode_func = distorm.internal_decode

DECRES_NONE = 0
DECRES_SUCCESS = 1
DECRES_MEMORYERR = 2
DECRES_INPUTERR = 3

MAX_INSTRUCTIONS = 100
MAX_TEXT_SIZE = 60

class _WString(Structure):
    _fields_ = (
        ("pos", c_uint), # Unused.
        ("p", c_char * MAX_TEXT_SIZE),
    )
    def __str__(self):
        return self.p

class _DecodedInst(Structure):
    _fields_ = (
        ("mnemonic", _WString),
        ("operands", _WString),
        ("instructionHex", _WString),
        ("size", c_uint),
        ("offset", _OffsetType),
    )
    def __str__(self):
        return "%s %s" % (self.mnemonic, self.operands)

decode_func.argtypes = (_OffsetType, c_void_p, c_int, c_int, c_void_p, c_uint, POINTER(c_uint))

def Decode(codeOffset, code, dt=Decode32Bits):
    """
    Errors: TypeError, IndexError, MemoryError, ValueError
    """
    # Check arguments
    if not isinstance(codeOffset, (int, long)):
        raise TypeError("codeOffset have to be an integer")
    if not isinstance(code, str):
        raise TypeError("code have to be a string")
    if dt not in DECODERS:
        raise IndexError("Decoding-type must be either Decode16Bits, Decode32Bits or Decode64Bits.")

    # Allocate memory for decoder
    code_buffer = create_string_buffer(code)
    decodedInstructionsCount = c_uint()
    result = create_string_buffer(sizeof(_DecodedInst)*MAX_INSTRUCTIONS)

    # Prepare arguments
    codeLen = len(code)
    code = addressof(code_buffer)
    while codeLen:
        # Call internal decoder
        res = decode_func(codeOffset, code, codeLen, dt, result, MAX_INSTRUCTIONS, byref(decodedInstructionsCount))

        # Check for errors
        if res == DECRES_INPUTERR:
            raise ValueError("Invalid argument")
        count = decodedInstructionsCount.value
        if res == DECRES_MEMORYERR and not count:
            raise MemoryError()

        # No more instruction
        if not count:
            break

        # Yield instruction and compute decoded size
        size = 0
        instr_array = cast(result, POINTER(_DecodedInst))
        for index in xrange(count):
            instr = instr_array[index]
            size += instr.size
            yield instr

        # Update parameters to move to next instructions
        code += size
        codeOffset += size
        codeLen -= size