-
-
Notifications
You must be signed in to change notification settings - Fork 45
/
decrypt_dropshot.py
103 lines (76 loc) · 3.39 KB
/
decrypt_dropshot.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
# -*- coding: utf-8 -*-
"""Dropshot / StoneDrill Decrypter
This is a r2pipe based script which will be used to demonstrate the capabilities
of radare2 and Cutter (@r2gui). The script will be oficially published on a blogpost
on https://www.megabeets.net as part of series of article about radare2.
"""
__author__ = "Itay Cohen, aka Megabeets"
__copyright__ = "Do whatever you want with this code"
__website__ = "https://www.megabeets.net"
import cutter
import zlib
# Rotate right lambda
def ror(val, r_bits, max_bits): return \
((val & (2**max_bits-1)) >> r_bits % max_bits) | \
(val << (max_bits-(r_bits % max_bits)) & (2**max_bits-1))
def decode_strings(verbose=True):
if verbose:
print("\n%s\n\tStarting the decode of the encrypted strings\n%s\n\n" %
('~'*60, '~'*60))
# Declaration of decryption-table related variables
decryption_table = 0x41BA3C
decryption_table_end = 0x41BA77
decryption_table_len = decryption_table_end - decryption_table
decryption_function = 0x4012A0
# Analyze the binary to better detect functions and x-refs
cutter.cmd('aa')
# Rename the decryption function
cutter.cmd('afn decryption_function %d' % decryption_function)
# Dump the decryption table to a variable
decryption_table_content = cutter.cmdj(
"pxj %d @ %d" % (decryption_table_len, decryption_table))
# Iterate x-refs to the decryption function
for xref in cutter.cmdj('axtj %d' % decryption_function):
# Get the arguments passed to the decryption function: length and encrypted string
length_arg, offsets_arg = cutter.cmdj('pdj -2 @ %d' % (xref['from']))
# String variable to store the decrypted string
decrypted_string = ""
# Guard rail to avoid exception
if (not 'val' in length_arg):
continue
# Manually decrypt the encrypted string
for i in range(0, length_arg['val']):
decrypted_string += chr(decryption_table_content[cutter.cmdj(
'pxj 1 @ %d' % (offsets_arg['val'] + (i*2)))[0]])
# Print the decrypted and the address it was referenced to the console
if verbose:
print(decrypted_string + " @ " + hex(xref['from']))
# Add comments to each call of the decryption function
cutter.cmd('CC Decrypted: %s @ %d' % (decrypted_string, xref['from']))
# This function was added in the 2nd part of the series about dropshot
def decrypt_resource(verbose=True):
if verbose:
print("\n%s\n\tStarting the decryption of the resource\n%s\n" %
('~'*60, '~'*60))
# Get information on all resources in JSON format
rsrcs = cutter.cmdj('iRj')
rsrc_101 = {}
# Locate resource 101 and dump it to an array
for rsrc in rsrcs:
if rsrc['name'] == 101:
rsrc_101 = cutter.cmdj("pxj %d @ %d" %
(rsrc['size'], rsrc['vaddr']))
# Decompress the zlibbed array
decompressed_data = zlib.decompress(bytes(rsrc_101))
decrypted_payload = []
# Decrypt the payload
for b in decompressed_data:
decrypted_payload.append((ror(b, 3, 8)))
# Write the payload (a PE binary) to a file
open(r'./decrypted_rsrc.bin', 'wb').write(bytearray(decrypted_payload))
if verbose:
print("Saved the PE to ./decrypted_rsrc.bin")
decode_strings()
decrypt_resource()
# Refresh the interface to load changes
cutter.refresh()