forked from joxeankoret/pyew
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pydistorm.py
executable file
·134 lines (114 loc) · 3.62 KB
/
pydistorm.py
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
"""
:[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 sys
import platform
from ctypes import cdll, c_long, c_ulong, c_int, c_uint, c_char, POINTER, \
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()
base_lib = "distorm64"
if osVer == "Windows":
LIB_FILENAME = "%s.dll" % base_lib
elif sys.platform.lower() == "darwin":
LIB_FILENAME = "%s.dylib" % base_lib
else:
LIB_FILENAME = 'lib%s.so' % base_lib
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 > -1:
# 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