-
Notifications
You must be signed in to change notification settings - Fork 90
/
tscookie_data_decode.py
140 lines (118 loc) · 5.15 KB
/
tscookie_data_decode.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
136
137
138
139
140
#!/usr/bin/env python
#
# LICENSE
# the GNU General Public License version 2
#
import sys
import pefile
import re
import argparse
from struct import unpack, unpack_from
# MZ Header
MZ_HEADER = b"\x4D\x5A\x90\x00"
RC4_KEY_LENGTH = 0x80
KEY_END = b"\x92\x5A\x76\x5D"
# Config pattern
CONFIG_PATTERNS = [re.compile("\x68(....)\xE8(....)\x59\x6A\x01\x58\xC3", re.DOTALL),
re.compile("\x68(....)\xE8(....)\x59", re.DOTALL)]
CONFIG_SIZE = 0xBF0
CONNECT_MODE = {0 : 'TCP' , 1 : 'HTTP with Credentials' , 2 : 'HTTP with Credentials', 3 : 'HTTP with Credentials', 5 : 'HTTP',
6 : 'HTTPS' , 7 : 'HTTPS' , 8 : 'HTTPS' ,}
PROXY_MODE = {0 : 'Detect proxy settings' , 1 : 'Use config'}
INJECTION_MODE = {0 : 'Create process' , 1 : 'Injection running process'}
PROCESS_NAME = {0 : 'svchost.exe', 1 : 'iexplorer.exe', 2 : 'explorer.exe', 3 : 'Default browser' , 4: 'Setting process'}
parser = argparse.ArgumentParser(description="TSCookie Data Config Parser")
parser.add_argument("file", type=str, metavar="FILE", help="TSCookie Data file")
args = parser.parse_args()
# RC4
def rc4(data, key):
x = 0
box = range(256)
for i in range(256):
x = (x + box[i] + ord(key[i % len(key)])) % 256
box[i], box[x] = box[x], box[i]
x = 0
y = 0
out = []
for char in data:
x = (x + 1) % 256
y = (y + box[x]) % 256
box[x], box[y] = box[y], box[x]
out.append(chr(ord(char) ^ box[(box[x] + box[y]) % 256]))
return ''.join(out)
# helper function for formatting string
def __format_string(data):
return data.split("\x00")[0]
# Parse config
def parse_config(config):
print("\n[Config data]")
print("{0}\n".format("-" * 50))
print("Server name : {0}".format(__format_string(unpack_from("<1024s", config, 0)[0])))
print("KEY : 0x{0:X}".format(unpack_from(">I", config, 0x400)[0]))
print("Sleep count : {0}".format(unpack_from("<H", config, 0x404)[0]))
print("Mutex : {0}".format(unpack_from("<32s", config, 0x40c)[0]))
mode = unpack_from("<H", config, 0x44c)[0]
print("Connect mode : {0} ({1})".format(mode, CONNECT_MODE[mode]))
print("Connect keep : {0}".format(unpack_from("<H", config, 0x454)[0]))
icmp = unpack_from("<H", config, 0x458)[0]
if icmp == 100:
print("ICMP mode : {0}".format("Enable"))
print("ICMP bind IP : {0}".format(__format_string(unpack_from("<330s", config, 0x4D4)[0])))
else:
print("ICMP mode : {0}".format("Disable"))
injection = unpack_from("<H", config, 0x624)[0]
print("Injection mode: {0} ({1})".format(injection, INJECTION_MODE[injection]))
print(" Process name: {0}".format(PROCESS_NAME[unpack_from("<H", config, 0x628)[0]]))
print(" Custom name : {0}".format(__format_string(unpack_from("<256s", config, 0x62c)[0])))
if config[0x72c] != "\x00":
print("Proxy server : {0}".format(__format_string(unpack_from("<64s", config, 0x72c)[0])))
print(" port : {0}".format(unpack_from("<H", config, 0x76c)[0]))
print(" UserName : {0}".format(__format_string(unpack_from("<64s", config, 0x770)[0])))
print(" Password : {0}".format(__format_string(unpack_from("<64s", config, 0x790)[0])))
proxy = unpack_from("<H", config, 0x7b0)[0]
print("Proxy mode : {0} ({1})".format(proxy, PROXY_MODE[proxy]))
print("AuthScheme : {0}".format(unpack_from("<H", config, 0x7b4)[0]))
# Decode data
def decode_data(data, fname):
try:
enc_data = data[:-RC4_KEY_LENGTH]
rc4key = data[-RC4_KEY_LENGTH:-4] + KEY_END
dec_data = rc4(enc_data, rc4key)
open(fname, "wb").write(dec_data)
print("[*] Successful decoding data : {0}".format(fname))
except:
sys.exit("[!] Faild to resource decoding.")
return dec_data
def main():
with open(args.file, "rb") as fb:
data = fb.read()
dec_data = decode_data(data, args.file + ".decode")
dll_index = dec_data.find(MZ_HEADER)
if dll_index:
dll_data = dec_data[dll_index:]
dll = pefile.PE(data=dll_data)
print("[*] Found main DLL : 0x{0:X}".format(dll_index))
else:
sys.exit("[!] DLL data not found in decoded resource.")
for pattern in CONFIG_PATTERNS:
mc = re.search(pattern, dll_data)
if mc:
try:
(config_rva, ) = unpack("=I", dll_data[mc.start() + 1:mc.start() + 5])
config_addr = dll.get_physical_by_rva(config_rva - dll.NT_HEADERS.OPTIONAL_HEADER.ImageBase)
enc_config_data = dll_data[config_addr:config_addr + CONFIG_SIZE]
print("[*] Found config data : 0x{0:X}".format(config_rva))
except:
sys.exit("[!] Config data not found in DLL.")
try:
enc_config = enc_config_data[RC4_KEY_LENGTH:]
rc4key = enc_config_data[:RC4_KEY_LENGTH]
config = rc4(enc_config, rc4key)
open(args.file + ".config", "wb").write(config)
print("[*] Successful decoding config: {0}".format(args.file + ".config"))
except:
sys.exit("[!] Faild to decoding config data.")
parse_config(config)
print("\n[*] Done.")
if __name__ == "__main__":
main()