5
5
import java .io .*;
6
6
import java .lang .instrument .ClassFileTransformer ;
7
7
import java .lang .instrument .IllegalClassFormatException ;
8
- import java .security .NoSuchAlgorithmException ;
9
8
import java .security .ProtectionDomain ;
10
- import java .security .spec .InvalidKeySpecException ;
11
9
import java .util .HashMap ;
12
10
import java .util .Map ;
13
11
@@ -16,17 +14,19 @@ public class ClassTransformer implements ClassFileTransformer {
16
14
private Map <String , String > encryptKeyMap = new HashMap <>();
17
15
private String machineCode ;
18
16
private Long expireTs ;
19
- private static final String DEFAULTALGORITHM = "AES" ;
20
- private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding" ;
21
- public static final byte [] m_datapadding = {0x7F };
22
- public static final byte [] m_ending = {0x00 };
23
- private static final String [] CONFUSEDSTRS = {"i" , "I" , "l" , "O" , "0" , "1" };
17
+ private final String DEFAULTALGORITHM = "AES" ;
18
+ private final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding" ;
19
+ private final byte [] m_datapadding = {0x7F };
24
20
25
- public static final byte [] mzHeader = new byte [ 19 ] ;
21
+ private final String [] CONFUSEDSTRS = { "i" , "I" , "l" , "O" , "0" , "1" } ;
26
22
27
- public ClassTransformer (){
23
+ private final byte [] mzHeader = new byte [19 ];
24
+ private final char spacebyteVal =20 ;
25
+
26
+ public ClassTransformer () {
28
27
init ();
29
28
}
29
+
30
30
private void init () {
31
31
try (DataInputStream dInput = new DataInputStream (getClass ().getClassLoader ().getResourceAsStream ("META-INF/config.bin" ))) {
32
32
dInput .read (mzHeader );
@@ -38,7 +38,7 @@ private void init() {
38
38
machineCode = bytesToHexString (machineCodeByte );
39
39
expireTs = dInput .readLong ();
40
40
checkExpire ();
41
- int classNameBytesLen ;
41
+ int classNameBytesLen ;
42
42
while (dInput .available () > 0 ) {
43
43
dInput .read (paddingbyte );
44
44
checkPadding (paddingbyte );
@@ -47,20 +47,21 @@ private void init() {
47
47
dInput .read (classNameEncryptBytes );
48
48
byte [] decryptClassNameBytes = decryptByte (classNameEncryptBytes , machineCode .getBytes ());
49
49
String className = new String (decryptClassNameBytes );
50
- byte [] posByte = new byte [16 ];
50
+ byte [] posByte = new byte [16 ];
51
51
dInput .read (posByte );
52
- String confusedName = decodeConfusedNameByCode (new String ( posByte ) );
52
+ String confusedName = decodeConfusedNameByCode (posByte );
53
53
int keyLength = dInput .readInt ();
54
54
byte [] keyEncryptByte = new byte [keyLength ];
55
55
dInput .read (keyEncryptByte );
56
56
byte [] keyDecryptByte = decryptByte (keyEncryptByte , machineCode .getBytes ());
57
57
String key = new String (keyDecryptByte );
58
- encryptKeyMap .put (className , confusedName + "|" + key );
58
+ encryptKeyMap .put (className , confusedName + "|" + key );
59
59
}
60
60
} catch (Exception ex ) {
61
61
ex .printStackTrace ();
62
62
}
63
63
}
64
+
64
65
private void checkPadding (byte [] paddingbyte ) {
65
66
if (paddingbyte [0 ] != m_datapadding [0 ]) {
66
67
System .err .println ("jar package corrupted" );
@@ -74,15 +75,15 @@ private void checkExpire() {
74
75
System .exit (1 );
75
76
}
76
77
}
78
+
77
79
private byte [] loadEncryptDataStream (String confusedName ) throws IOException {
78
80
ByteArrayOutputStream outputStream = new ByteArrayOutputStream ();
79
81
doCopy (getClass ().getClassLoader ().getResourceAsStream ("META-INF/ext/" + confusedName ), outputStream );
80
82
return outputStream .toByteArray ();
81
83
}
82
84
83
85
84
-
85
- private static void doCopy (InputStream is , OutputStream os ) throws IOException {
86
+ private void doCopy (InputStream is , OutputStream os ) throws IOException {
86
87
byte [] bytes = new byte [2048 ];
87
88
int numBytes ;
88
89
while ((numBytes = is .read (bytes )) != -1 ) {
@@ -93,7 +94,7 @@ private static void doCopy(InputStream is, OutputStream os) throws IOException {
93
94
is .close ();
94
95
}
95
96
96
- private static byte [] decryptByte (byte [] bytes , byte [] key ) {
97
+ private byte [] decryptByte (byte [] bytes , byte [] key ) {
97
98
try {
98
99
Cipher cipher = Cipher .getInstance (DEFAULT_CIPHER_ALGORITHM );
99
100
cipher .init (Cipher .DECRYPT_MODE , toKey (key ));
@@ -103,8 +104,14 @@ private static byte[] decryptByte(byte[] bytes, byte[] key) {
103
104
}
104
105
return null ;
105
106
}
106
-
107
- private static String bytesToHexString (byte [] bytes ) {
107
+ private String bytesToIndex (byte [] bytes ){
108
+ StringBuilder builder =new StringBuilder ();
109
+ for (byte bytes1 :bytes ){
110
+ builder .append ((char )((int )bytes1 +spacebyteVal ));
111
+ }
112
+ return builder .toString ();
113
+ }
114
+ private String bytesToHexString (byte [] bytes ) {
108
115
StringBuilder builder = new StringBuilder ();
109
116
for (byte b : bytes ) {
110
117
builder .append (String .format ("%02X" , b ));
@@ -113,39 +120,40 @@ private static String bytesToHexString(byte[] bytes) {
113
120
}
114
121
115
122
116
- private static SecretKeySpec toKey (byte [] keybyte ) {
123
+ private SecretKeySpec toKey (byte [] keybyte ) {
117
124
return new SecretKeySpec (keybyte , DEFAULTALGORITHM );
118
125
}
119
126
120
- private static String decodeConfusedNameByCode (String code ) {
127
+ private String decodeConfusedNameByCode (byte [] bytes ) {
128
+ String index =bytesToIndex (bytes );
121
129
StringBuilder builder = new StringBuilder ();
122
- for (char input : code .toCharArray ()) {
123
- builder .append (CONFUSEDSTRS [Integer .parseInt (String .valueOf (input ))- 1 ]);
130
+ for (char input : index .toCharArray ()) {
131
+ builder .append (CONFUSEDSTRS [Integer .parseInt (String .valueOf (input )) - 1 ]);
124
132
}
125
133
return builder .toString ();
126
134
}
127
135
128
136
@ Override
129
137
public byte [] transform (ClassLoader loader , String className , Class <?> classBeingRedefined , ProtectionDomain protectionDomain , byte [] classfileBuffer ) throws IllegalClassFormatException {
130
138
try {
131
- String loadClass = className .replace ("/" ,"." );
139
+ String loadClass = className .replace ("/" , "." );
132
140
if (encryptKeyMap .containsKey (loadClass )) {
133
- // System.out.println("load class "+className);
134
- if (loadedClassPool .containsKey (loadClass )){
141
+ System .out .println ("load class " +className );
142
+ if (loadedClassPool .containsKey (loadClass )) {
135
143
return loadedClassPool .get (loadClass );
136
144
}
137
145
String [] arr = encryptKeyMap .get (loadClass ).split ("\\ |" );
138
146
byte [] encryptBytes = loadEncryptDataStream (arr [0 ]);
139
- byte [] machineDecr = decryptByte (encryptBytes ,machineCode .getBytes ());
140
- byte [] decryptByte = decryptByte (machineDecr ,arr [1 ].getBytes ());
147
+ byte [] machineDecr = decryptByte (encryptBytes , machineCode .getBytes ());
148
+ byte [] decryptByte = decryptByte (machineDecr , arr [1 ].getBytes ());
141
149
if (decryptByte != null && decryptByte [0 ] == -54 && decryptByte [1 ] == -2 && decryptByte [2 ] == -70 && decryptByte [3 ] == -66 ) {
142
- loadedClassPool .put (loadClass ,decryptByte );
150
+ loadedClassPool .put (loadClass , decryptByte );
143
151
return decryptByte ;
144
- }else {
152
+ } else {
145
153
throw new RuntimeException ("decrypt error!" );
146
154
}
147
155
}
148
- }catch (Exception ex ){
156
+ } catch (Exception ex ) {
149
157
ex .printStackTrace ();
150
158
}
151
159
return classfileBuffer ;
0 commit comments