在运行时修补Java

本文将重点介绍如何解决与第三方库相关的问题
  • 不能被规避
  • 难以排除/绕过/替换
  • 只需不提供错误修正

在这种情况下,解决问题仍然是一项艰巨的任务。

作为这种情况的诱因,请考虑对“哈希索引”数据结构的攻击,例如java.util.Hashtable和java.util.HashMap (对于不熟悉此类攻击的人,我建议查看以下内容28C3: 对Web应用程序进行拒绝服务攻击变得容易( )。

长话短说,核心问题是使用非加密哈希函数(在其中查找冲突很容易)。 根本原因隐藏在java.lang.String.hashCode()函数中。 显而易见的方法是修补java.lang.String类,这很困难,原因有两个:

  1. 它包含本机代码
  2. 它属于Java核心类,这些Java核心类随Java安装一起提供,因此不受我们的控制

第一点将迫使我们修补体系结构和特定于OS的库,我们应该在可能的情况下规避这些库。 第二点是正确的,但是它会更灵活一些,我们将在下面看到。

好的,让我们重新考虑:修补本机很脏,我们不急于采用这种方式–我们必须为不愿意修复其代码的其他人(在本例中为SDK SDK库)做一些工作。

尝试:
哈希问题涉及到java.util.Hashtablejava.util.HashMap类,它们不使用任何本机代码。 修补这些类非常容易,因为足以为所有体系结构和OS提供一个编译的类。 我们可以使用提供的错误解决方案之一,并用固定版本调整(或替换)原始类。 困难在于在不接触核心库的情况下修补VM –我想如果用户必须更改其JVM安装的一部分,或者更糟糕的是,我们的应用程序在安装过程中自动执行此操作,用户将非常失望。 在某些情况下,进一步引入新的自定义类加载器可能会很困难。

我们需要的是一种动态修补我们的单个应用程序的解决方案–替换有问题的类,不要碰其他任何东西。 如果我们透明地执行此操作,则其他软件部件甚至都不会识别任何更改(在最佳情况下),并保持与类的接口,而无需进行任何修改。

可以通过滥用Java Instrumentation API轻松地完成此操作。 引用JavaDoc

“提供允许Java编程语言代理检测运行在JVM上的程序的服务。”

这正是我们所需要的!

概念证明
首先,我们需要一个示例应用程序来演示该概念:

public class StringChanger {public static void main(String[] args) {System.out.println(A.shout());}}public class A {public static String shout() {return "A";}
}

运行此类时,它仅输出:A
应用我们的“补丁”之后,我们希望获得以下输出:已补丁

“修补的代码如下所示:

public class A {public static String shout() {return "Apatched";}
}

进一步,我们需要一个“代理”来管理所使用的类并修补正确的类:

final public class PatchingAgent implements ClassFileTransformer {private static byte[] PATCHED_BYTES;private static final String PATH_TO_FILE = "Apatched.class";private static final String CLASS_TO_PATCH = "stringchanger/A";public PatchingAgent() throws FileNotFoundException, IOException {if (PATCHED_BYTES == null) {PATCHED_BYTES = readPatchedCode(PATH_TO_FILE);}}public static void premain(String agentArgument,final Instrumentation instrumentation) { System.out.println("Initializing hot patcher...");PatchingAgent agent = null;try {agent = new PatchingAgent();} catch(Exception e) {System.out.println("terrible things happened....");}instrumentation.addTransformer(agent);}@Overridepublic byte[] transform(final ClassLoader loader, String className,final Class classBeingRedefined, final ProtectionDomain protectionDomain,final byte[] classfileBuffer) throws IllegalClassFormatException {byte[] result = null;if (className.equals(CLASS_TO_PATCH)) {System.out.println("Patching... " + className);result = PATCHED_BYTES;}return result;}private byte[] readPatchedCode(final String path)throws FileNotFoundException, IOException {...}
}

不用担心–我不会在实施细节上打扰您,因为这只是PoC代码,远非完美,巧妙,快速而简洁。 除了我因为此时太懒而赶上 Exception以外,我不过滤输入,构建深拷贝(防御性编程作为流行语),这实际上不应被视为生产代码。

公共PatchingAgent()
初始化代理(在这种情况下,将获取修补的A.class文件的字节。修补的类已编译并存储在我们可以访问它的位置。

公共静态无效premain(…)
在JVM初始化并准备代理后,将调用此方法。

公共字节[]变换(…)
每当定义一个类时(例如,通过ClassLoader.defineClass (…)),该函数都将被调用,并且可以转换已处理的类字节 []( classfileBuffer )。 可以看出,我们将为stringchanger包中的A类执行此操作。 您不受限制如何转换类(只要它仍然是有效的Java )–例如,您可以利用字节码修改框架…–为使事情简单,我们假设我们将旧字节 []替换为修补的类之一(只需将完整的修补A.class文件缓存到字节 []中)。

这就是修补程序编码部分的全部内容……最后,我们必须用一个特殊的manifest.mf文件构建一个jar容器,该文件告诉JVM如何调用该代理。

清单版本:1.0
X-COMMENT:Main-Class将通过构建自动添加
Premain-Class:stringchanger.PatchingAgent

构建完这个jar之后,我们可以尝试PoC应用程序。 首先,我们将在没有调用代理的必要JVM参数的情况下调用它:

跑:
一个
建立成功(总时间:0秒)

它的行为符合预期,并输出未修补类定义的输出。

现在,我们将使用神奇的JVM参数来尝试调用代理-javaagent:StringChanger.jar:

跑:
初始化热补丁程序…
读取修补文件。 修补…换弦器/ A 已分配 建立成功(总时间:0秒)

Voilà,该代码已成功进行了实时修补!

如我们所见,可以动态地对JVM进行热补丁而不用触摸交付的代码。 必须要做的是开发修补程序和修补的类。 目前,我还不了解性能评估数据。 因此,我不确定该解决方案对生产系统的实用性以及对应用程序性能的影响程度。

明确地说,这不是一个优雅的解决方案–至少它很脏! 最好的方法是修补根本原因,但只要没有供应商修复程序,开发人员就可以通过热修补来防止其软件运行,而无需重写使用易受攻击类的每一行。

最后,我希望提出意见,改进或只是更好的解决方案。 非常感谢Juraj Somorovsky与我在这个问题上共同努力。

参考: JCG合作伙伴 在运行时修补Java   Christopher Meyer讨论了Java安全性和相关主题 。


翻译自: https://www.javacodegeeks.com/2012/02/patching-java-at-runtime.html

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

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

相关文章

php return直接输出,PHP中return用法详细解读

原标题:PHP中return用法详细解读在大部分编程语言中,return关键字可以将函数的执行结果返回,PHP中return的用法也大同小异,对初学者来说,掌握PHP中return的用法也是学习PHP的一个开始。首先,它的意思就是返…

并行执行,没用到过,写到这里免得搞忘

/// <summary>/// /// </summary>class Program{static void Main(string[] args){simultaneous();Console.ReadKey();}static void simultaneous(){//尽可能并行执行提供的每个操作Parallel.Invoke(() > ComplexMethod("1"),() > ComplexMethod(&…

UIViewController生命周期

UIViewController生命周期 UIViewController生命周期 posted on 2016-04-07 20:15 相而勿绝 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/fmdxiangdui/p/5365249.html

Spring的REST分页

这是有关使用Spring 3.1和Spring Security 3.1和基于Java的配置来建立安全的RESTful Web Service的系列文章的第七篇。 本文将重点介绍RESTful Web服务中的分页实现 。 REST with Spring系列&#xff1a; 第1部分– 使用Spring 3.1和基于Java的配置引导Web应用程序 第2部分–…

众筹源码 php,助创cms众筹源码系统v1.0

什么是助创cms众筹系统?使用“预约团购”的众筹方式给自己的创意争取大家的关注和支持&#xff0c;是近年来非常火热的一种融资模式&#xff0c;助创cms众筹系统可以10分钟帮你打造一个和京东众筹一样的平台&#xff0c;包含产品众筹和公益众筹两个部分&#xff0c;可以直接拿…

Linq to SQL 的增删改查操作

Linq&#xff0c;全称Language Integrated Query&#xff0c;作为C#3.0新语法&#xff0c;是C#语言的一个扩展&#xff0c;可以将数据查询直接集成到编程语言本身中。 Linq表达式和SQL语句差不多&#xff0c;说白了就是颠倒sql语法&#xff0c; from where select ...&#xff…

扩展您的JPA POJO

可扩展性是许多体系结构的重要特征。 它衡量是否容易&#xff08;或困难&#xff09; 它是在不影响现有核心系统功能的情况下添加或更改功能。 让我们举一个简单的例子。 假设您的公司拥有一个核心产品来跟踪体育俱乐部中的所有用户。 在您的产品体系结构中&#xff0c;您有一个…

web框架--flask

flask介绍Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架&#xff0c;对于Werkzeug本质是Socket服务端&#xff0c;其用于接收http请求并对请求进行预处理&#xff0c;然后触发Flask框架&#xff0c;开发人员基于Flask框架提供的功能对请求进行…

php spider shell,ScrapyShell使用

Scrapy ShellScrapy终端是一个交互终端&#xff0c;我们可以在未启动spider的情况下尝试及调试代码&#xff0c;也可以用来测试XPath或CSS表达式&#xff0c;查看他们的工作方式&#xff0c;方便我们爬取的网页中提取的数据。如果安装了 IPython &#xff0c;Scrapy终端将使用 …

69 个经典 Spring 面试题和答案

Spring 概述 什么是spring?Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用&#xff0c;但是有些扩展是针对构建J2EE平台的web应用。Spring 框架目标是简化Java企业级应用开发&#xff0c;并通过POJO为基础的编程模型促进良好的编程习惯。使用Spring框架…

高性能MySql

1、索引是对DB优化最有效的方式 varchar(10)定义的是字符的个数&#xff0c;如果是utf-8的话&#xff0c;最大是3X10个字节 二、索引类型 1、MySql的索引是在存储引擎层实现的&#xff0c;各个存储引擎的的索引方式也是不同的 2、B-Tree索引 MyISAM索引通过数据的物理位置引用被…

Java Swing井字游戏

大家好&#xff01; 哇&#xff0c;自从我在这里发布了东西以来已经有一段时间了&#xff01; 我必须说我真的很想写东西&#xff0c;而且我保证我不会再陷入“作家的障碍”。 希望 ..最近两个月发生了很多事情&#xff0c;我有很多话要说。 但是在这篇文章中&#xff0c;我只是…

Java小青蛙跳台街,算法-青蛙跳台阶详解

/*[跳台阶][题目]一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。[解析]与斐波那契数列的求解过程类似。典型的动态规划问题。对于第 n 级台阶&#xff0c;我们可以从第 n-1 级台阶一步到达&#xff0c;也可以从第 n-2 级…

apache服务器配置Net的实践

前置&#xff1a; 在xp系统中&#xff0c;打补丁之类或啥子操作引起或多或少的问题&#xff0c;最终导致iis不能使用&#xff1b; 不想装系统...忍着... 最近突发事件导致&#xff0c;需要摸一下apache服务器处理&#xff0c;好吧&#xff0c;那就搜索下吧..... 目标&#xff1…

TestNG或JUnit

多年以来&#xff0c;无论何时使用Java代码进行单元测试&#xff0c;我始终会回到TestNG。 每当我拿起TestNG时&#xff0c;人们都问我为什么要继续使用TestNG&#xff0c;尤其是默认开发环境&#xff08;例如Eclipse或Maven&#xff09;提供的JUnit时。 继续进行同样的战斗&am…

event php,PHP event 事件机制

/** PHP 事件机制*/class baseClass{private $_e;public function __set($name,$value){if( strncasecmp($name,"on",2) 0 ){if(!isset($this->_e[$name]))$this->_e[$name] array();return array_push($this->_e[$name] , $value);}}public function __g…

Android JNI编程(五)——C语言的静态内存分配、动态内存分配、动态创建数组...

版权声明&#xff1a;本文出自阿钟的博客&#xff0c;转载请注明出处:http://blog.csdn.net/a_zhon/。 目录(?)[] 一&#xff1a;什么是静态内存什么又是动态内存呢&#xff1f; 静态内存&#xff1a;是指在程序开始运行时由编译器分配的内存&#xff0c;它的分配是在程序开始…

Visual Studio-C#-20160411

函数的四个要素包括&#xff1a;名称&#xff0c;输入&#xff0c;输出&#xff0c;加工 注释的方式&#xff1a;//只注释一行&#xff1b;/**/注释一段区域&#xff1b; namespace ConsoleApplication6 ---------//命名空间{ class Program ---------------------------//类…

配置MyBatis 3

MyBatis是一个非常流行且也是最有效的SQL映射框架。 MyBatis可用于Java和.net语言。 MyBatis并不是Hibernate的真正替代品&#xff0c;但是我们可以使用该框架来减少MyBatis提供的高效和高性能的数据库相关代码。 本教程将向您展示使用数据库配置MyBatis 3的步骤。 MyBatis 3支…

php获取src,PHP读取文件

本文概述PHP提供了各种功能来从文件读取数据。有多种功能允许你读取所有文件数据, 逐行读取数据以及逐字符读取数据。下面提供了可用的PHP文件读取功能。fread()fgets()fgetc()PHP读取文件-fread()PHP fread()函数用于读取文件的数据。它需要两个参数&#xff1a;文件资源和文件…