This repository has been archived by the owner on May 27, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
/
main.py
197 lines (159 loc) · 6.27 KB
/
main.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
import xxtea
import os
from traveDir import depthIteratePath
import sys
import random
from loguru import logger
from io import BytesIO
import zipfile
dIP = depthIteratePath([".luac"])
"""1.Print Log"""
try:
from shutil import get_terminal_size as get_terminal_size
except:
try:
from backports.shutil_get_terminal_size import get_terminal_size as get_terminal_size
except:
pass
try:
import click
except:
class click:
@staticmethod
def secho(message=None, **kwargs):
print(message)
@staticmethod
def style(**kwargs):
raise Exception("unsupported style")
banner = """
ooo ooooo .oooo.
`88. .888' d8P'`Y8b
888b d'888 .oooo. .oooo.o 888 888 ooo. .oo.
8 Y88. .P 888 `P )88b d88( "8 888 888 `888P"Y88b
8 `888' 888 .oP"888 `"Y88b. 888 888 888 888
8 Y 888 d8( 888 o. )88b `88b d88' 888 888
o8o o888o `Y888""8o 8""888P' `Y8bd8P' o888o o888o
Running Start
\n"""
def show_banner():
colors = ['bright_red', 'bright_green', 'bright_blue', 'cyan', 'magenta']
try:
click.style('color test', fg='bright_red')
except:
colors = ['red', 'green', 'blue', 'cyan', 'magenta']
try:
columns = get_terminal_size().columns
if columns >= len(banner.splitlines()[1]):
for line in banner.splitlines():
if line:
fill = int((columns - len(line)) / 2)
line = line[0] * fill + line
line += line[-1] * fill
click.secho(line, fg=random.choice(colors))
except:
pass
class ColorPrinter:
@staticmethod
def print_red_text(content, end="\n"):
print("\033[1;31m %s \033[0m" % content, end=end),
@staticmethod
def print_green_text(content, end="\n"):
print("\033[1;32m %s \033[0m" % content, end=end),
@staticmethod
def print_blue_text(content, end="\n"):
print("\033[1;34m %s \033[0m" % content, end=end),
@staticmethod
def print_cyan_text(content, end="\n"):
print("\033[1;36m %s \033[0m" % content, end=end),
@staticmethod
def print_white_text(content, end="\n"):
print("\033[1;37m %s \033[0m" % content, end=end),
def readJscFile(path):
"""Read .jsc file in this path."""
f = open(path, "rb")
data = f.read()
f.close()
return data
def saveFile(saveData, fileDir):
"""Save the decrypted data on the same relative path."""
rootPath = os.path.split(fileDir)[0]
if not os.path.exists(rootPath):
try:
os.makedirs(rootPath)
except OSError:
if not os.path.exists(rootPath):
raise Exception("Error: create directory %s failed." % rootPath)
if fileDir.endswith("c"):
file = fileDir[:-1]
else:
file = fileDir
with open(file, "wb") as fd:
fd.write(saveData)
fd.close()
def decrypt(filePath, key, sign):
"""The main process to decryption."""
data = readJscFile(path=filePath)
# 1.xxtea decrypt
if key == "NONE":
key = "\x00" * 16
elif len(key) < 16:
key += "\0" * (16 - len(key)) # padding \0
dec_data = xxtea.decrypt(data=data[len(sign):], key=key[:16], padding=False, rounds=0)
# 2.determine file type
dec_data = bytes(dec_data)
return dec_data
def batchDecrypt(srcDir, xxteaKey, sign):
if not os.path.exists(srcDir): # path exist
logger.error("FileNotFound")
exit(-1)
isFile = os.path.isfile(srcDir) # is files or dirs
dirPath = os.path.dirname(srcDir) # dir name ...xx/a.luac => ...xx/
outPath = os.path.join(dirPath, "out") # out path xx/out
if isFile:
filePathArr = [srcDir] # get single file
else:
filePathArr = dIP.getDepthDir(srcDir) # get fileTrees
for filePath in filePathArr:
decData = decrypt(filePath, xxteaKey, sign) # decrypt core
if decData[:2] == b"PK":
logger.info("decrypt file is ZIP, decompressing...")
fileBaseName = os.path.basename(filePath) # xxx/game.zip => game.zip
zipDirName = os.path.splitext(fileBaseName)[0] # game.zip => game
decompressPath = os.path.join(outPath, zipDirName) # zip decompress path
if not os.path.exists(outPath):
os.mkdir(outPath) # make dir
if not os.path.exists(decompressPath):
os.mkdir(decompressPath) # make dir
fio = BytesIO(decData) # read bytesIO
fzip = zipfile.ZipFile(file=fio) # func zip
for fileName in fzip.namelist():
fzip.extract(fileName, decompressPath) # save file in zip
logger.success("Save flie: {0}".format(os.path.join(decompressPath, fileName)))
else:
saveFilePath = outPath + filePath.split(srcDir)[1] # save path
saveFile(decData, saveFilePath) # save file
logger.success("Save flie: {0}".format(saveFilePath))
def main():
if len(sys.argv) != 5:
print("\nThis is decrypt for Coco2d-luac .luac.")
ColorPrinter.print_white_text("Usage : ")
print(" python {0} [-d] [xxteaKey] [sign] [jscDir/zipFile]".format(sys.argv[0]))
ColorPrinter.print_white_text("Example : ")
print(r" python {0} -d e73c83539f2e65ab159 b4d6f1b968 C:\DecJsc-master\src".format(sys.argv[0]))
print(r" python {0} -d e73c83539f2e65ab159 b4d6f1b968 C:\DecJsc-master\game.zip".format(sys.argv[0]))
ColorPrinter.print_white_text("Tips : ")
print(" -d or -decrypt [decrypt]")
print(" If the TEA is 16 bytes of \\x00, please fill in NONE")
print(" Supports folders and individual LUAC or ZIP files")
print(" If you have any questions, please contact [ MasonShi@88.com ]\n")
exit(1)
instruct = sys.argv[1]
xxtea_key = sys.argv[2]
sign = sys.argv[3]
srcDir = sys.argv[4]
if instruct[1:2] == "d":
show_banner()
batchDecrypt(srcDir=srcDir, xxteaKey=xxtea_key, sign=sign)
ColorPrinter.print_white_text("\n Running exit...\n")
if __name__ == "__main__":
main()