6
6
import socket
7
7
import binascii
8
8
import subprocess
9
+ from typing import List
10
+ from concurrent .futures import ThreadPoolExecutor
9
11
from pathlib import Path
10
12
from random import randint
11
13
from Crypto .Cipher import AES
12
14
from Crypto .Hash import CMAC
13
15
14
16
15
- port = randint (20000 , 50000 )
16
- MAIN_EXE = (Path ('.' ) / 'main.exe' ).resolve ().as_posix ()
17
- p = subprocess .Popen (f'{ MAIN_EXE } { port } ' , shell = True , stdout = subprocess .PIPE , stderr = subprocess .STDOUT )
18
- time .sleep (1 )
19
- client = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
20
- client .connect (('127.0.0.1' , port ))
17
+ servers = []
18
+ clients = []
19
+ for i in range (5 ):
20
+ port = randint (20000 , 50000 )
21
+ MAIN_EXE = (Path ('.' ) / 'main.exe' ).resolve ().as_posix ()
22
+ p = subprocess .Popen (f'{ MAIN_EXE } { port } ' , shell = True , stdout = subprocess .PIPE , stderr = subprocess .STDOUT )
23
+ servers .append (p )
24
+ time .sleep (0.3 )
25
+ client = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
26
+ client .connect (('127.0.0.1' , port ))
27
+ clients .append (client )
21
28
22
29
23
30
def handle_exit (signum , frame ):
24
- p . kill ()
31
+ close ()
25
32
26
33
27
- def call_func (msg : bytes ):
28
- client .send (msg .encode ("utf-8" ))
34
+ def close ():
35
+ try :
36
+ [p .close () for p in clients ]
37
+ [p .kill () for p in servers ]
38
+ except Exception :
39
+ pass
40
+
41
+
42
+ def call_func (client , msg : bytes ):
43
+ client .send (msg )
29
44
resp = client .recv (1024 )
30
45
return resp .decode ('utf-8' ).strip ()
31
46
32
47
33
- def guessInput (text : str ):
34
- return call_func (f'guessInput|{ text } \n ' )
48
+ def multi_guessInput (bufs : List [bytes ]):
49
+ results = []
50
+ with ThreadPoolExecutor (max_workers = 5 ) as executor :
51
+ results = executor .map (guessInput , clients , bufs )
52
+ return results
53
+
54
+
55
+ def guessInput (client , buf : bytes ):
56
+ # return call_func(client, f'guessInput|{buf}\n')
57
+ return call_func (client , b'guessInput|' + buf + b'\n ' )
58
+
59
+
60
+ def getDeoaep (client , buf : bytes ):
61
+ # return call_func(client, f'getDeoaep|{buf}\n')
62
+ return call_func (client , b'getDeoaep|' + buf + b'\n ' )
35
63
36
64
37
- def getDeoaep (text : str ):
38
- return call_func (f'getDeoaep|{ text } \n ' )
65
+ def runv2 (hex_session_key : str ):
66
+ ts = time .time ()
67
+ encKey = binascii .a2b_hex (hex_session_key )
68
+ print (hex_session_key )
69
+ buf = [0 ] * 1026
70
+ offset = 2
71
+ while offset < 1026 :
72
+ print (f'[Progress] { (offset - 2 ) / 1024 * 100 :.2f} % time used { time .time () - ts :.2f} s' )
73
+ bt = math .floor ((offset - 2 ) / 4 )
74
+ offs = math .floor ((offset - 2 ) % 4 )
75
+ desired = (encKey [len (encKey ) - bt - 1 ] >> (offs * 2 )) & 3
76
+ destail = hex_session_key [len (hex_session_key ) - bt * 2 :len (hex_session_key )]
77
+ bufs = []
78
+ j = buf [offset ]
79
+ for _j in range (5 ):
80
+ buf [offset ] = _j
81
+ bufs .append (binascii .b2a_hex (bytes (buf )))
82
+ for _j , val in enumerate (multi_guessInput (bufs )):
83
+ sub = int (val [len (val ) - bt * 2 - 2 :len (val ) - bt * 2 ], 16 )
84
+ got = (sub >> (offs * 2 )) & 3
85
+ gtail = val [len (hex_session_key ) - bt * 2 :len (hex_session_key ) + bt * 2 ]
86
+ if got == desired and gtail == destail :
87
+ buf [offset ] = _j
88
+ j = buf [offset ]
89
+ break
90
+ if j == 8 :
91
+ buf [offset ] = 0
92
+ offset -= 1
93
+ if offset < 2 :
94
+ print ('Could not match input' )
95
+ assert 1 == 0 , "Could not find proper input encoding"
96
+ buf [offset ] += 1
97
+ while buf [offset ] == 8 :
98
+ buf [offset ] = 0
99
+ offset -= 1
100
+ if offset < 2 :
101
+ print ('Could not match input' )
102
+ assert 1 == 0 , "Could not find proper input encoding"
103
+ buf [offset ] += 1
104
+ else :
105
+ offset += 1
106
+ print (f'==> time used { time .time () - ts :.2f} s' )
107
+ print ("Output" , buf )
108
+ outp = getDeoaep (clients [0 ], binascii .b2a_hex (bytes (buf )))
109
+ print (outp )
110
+ if len (outp ) < 10 :
111
+ assert 1 == 0 , 'Could not remove padding, probably invalid key'
112
+ return outp
39
113
40
114
41
115
def run (hex_session_key : str ):
@@ -87,7 +161,6 @@ def run(hex_session_key: str):
87
161
if len (outp ) < 10 :
88
162
assert 1 == 0 , 'Could not remove padding, probably invalid key'
89
163
print (st )
90
- p .kill ()
91
164
return outp
92
165
93
166
@@ -110,9 +183,10 @@ def main():
110
183
if len (sys .argv ) == 2 :
111
184
path = sys .argv [1 ]
112
185
else :
113
- path = (Path ('.' ) / 'offline_config_yk .json' ).resolve ().as_posix ()
186
+ path = (Path ('.' ) / 'offline_config .json' ).resolve ().as_posix ()
114
187
config = json .loads (Path (path ).read_text (encoding = 'utf-8' ))
115
- clear_session_key = run (config ['enc_session_key' ])
188
+ clear_session_key = runv2 (config ['enc_session_key' ])
189
+ close ()
116
190
decrypt_license_keys (clear_session_key , config ['enc_key' ], config ['key_infos' ])
117
191
sys .stdin .read ()
118
192
0 commit comments