-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathdecrypt_strings.py
135 lines (105 loc) · 4.48 KB
/
decrypt_strings.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
134
135
from __main__ import *
import struct
from collections import namedtuple
from itertools import cycle, chain
from ghidra.program.model.mem import MemoryAccessException
from ghidra.program.model.listing import CodeUnit
SearchResult = namedtuple('SearchResult', ['instruction', 'data_addr'])
def decrypt_string(enc_data_addr, raw=False):
key = getInt(enc_data_addr)
xored_length = getInt(enc_data_addr.add(4))
original_length = key ^ xored_length
enc = getBytes(enc_data_addr.add(8), original_length).tostring()
dec = [ord(k) ^ ord(v) for k, v in zip(cycle(struct.pack('<I', key)), enc)]
if raw is True:
return dec
return ''.join([chr(d) for d in dec])
def add_bookmark_comment(addr, comment):
cu = currentProgram.getListing().getCodeUnitAt(addr)
createBookmark(addr, "decrypted_str", comment)
cu.setComment(CodeUnit.EOL_COMMENT, comment)
def get_instructions_before(addr, n=1):
r = []
for _ in range(n):
inst = getInstructionBefore(addr)
r.append(inst)
addr = inst.getAddress()
return r
def is_valid_address(addr):
try:
getInt(toAddr(addr))
return True
except MemoryAccessException:
return False
def is_call(inst):
return str(inst).startswith('CALL')
def is_mov_with_fastcall(inst):
s_inst = str(inst)
return s_inst.startswith('MOV EDX,0x') or s_inst.startswith('MOV ECX,0x')
def is_push(inst):
return str(inst).startswith('PUSH 0x')
def get_argument_value(inst):
if is_mov_with_fastcall(inst):
return inst.getOpObjects(1)[0].getValue()
elif is_push(inst):
return inst.getOpObjects(0)[0].getValue()
def find_decrypt_string_func():
'''
00773675 8b d9 MOV EBX,param_1
00773677 2b de SUB EBX,ESI
00773679 83 c3 03 ADD EBX,0x3
0077367c c1 eb 02 SHR EBX,0x2
0077367f 3b f1 CMP ESI,param_1
'''
asm = '\\x8b.{1}\\x2b.{1}\\x83.{1}\\x03\\xc1.{1}\\x02\\x3b.{1}'
found = findBytes(None, asm, -1)
if not found:
raise RuntimeError('decrypt_string function is not found')
suspicious_decrypt_string_func = set([getFunctionContaining(sus_inst) for sus_inst in found])
return list(suspicious_decrypt_string_func)
def find_encrypted_data_addr_ptn1():
decrypt_string_funcs = find_decrypt_string_func()
for decrypt_string_func in decrypt_string_funcs:
# get callee address of decrypt_string function
for xref in getReferencesTo(decrypt_string_func.getEntryPoint()):
# get instructions before callee address
insts = get_instructions_before(xref.getFromAddress(), 50)
# find instruction that passes
# address of encrypted data via EDX or ECX
for inst in insts:
if is_call(inst):
break
data_addr = get_argument_value(inst)
if data_addr and is_valid_address(data_addr):
yield SearchResult(instruction=inst, data_addr=toAddr(data_addr))
break
def find_encrypted_data_addr_ptn2():
# find rsa key decryption pattern instructions
'''
10006ff8 33 d0 XOR EDX,EAX
10006ffa 89 44 24 3c MOV dword ptr [ESP + local_14],EAX
10006ffe 8b c2 MOV EAX,EDX
10007000 89 54 24 40 MOV dword ptr [ESP + local_10],EDX
10007004 83 e0 fc AND EAX,0xfffffffc
'''
asm = '\\x33.{1}\\x89.{3}\\x8b.{1}\\x89.{3}\\x83.{1}\\xfc'
founds = findBytes(None, asm, -1)
if founds:
for found in founds:
# get address on operand in two steps before
inst = getInstructionBefore(getInstructionBefore(found))
data_addr = inst.getOpObjects(1)[0]
yield SearchResult(instruction=inst, data_addr=data_addr)
def find_encrypted_data_addr():
result_ptn1 = find_encrypted_data_addr_ptn1()
result_ptn2 = find_encrypted_data_addr_ptn2()
return chain(result_ptn1, result_ptn2)
def decrypt_all_strings(add_comment=True):
for found in find_encrypted_data_addr():
decrypted_str = decrypt_string(found.data_addr)
print('[*] found at {} : {!r}'.format(found.instruction.getAddress(), decrypted_str))
if add_comment:
# add comment and add to bookmark
add_bookmark_comment(found.instruction.getAddress(), decrypted_str)
if __name__ == '__main__':
decrypt_all_strings()