本文将重点介绍如何解决与第三方库相关的问题

  • 不能被规避
  • 难以排除/绕过/替换
  • 只需不提供错误修正

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

作为这种情况的诱因,请考虑对“哈希索引”数据结构的攻击,例如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.Hashtable和java.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

在运行时修补Java相关推荐

  1. java运行库一键修复_在运行时修补Java

    java运行库一键修复 本文将重点介绍如何解决与第三方库相关的问题 不能被规避 难以排除/绕过/更换 只需不提供错误修正 在这种情况下,解决问题仍然是一项艰巨的任务. 作为这种情况的诱因,请考虑对&q ...

  2. 常见运行时异常 java 114982568

    常见运行时异常 java 114982568 空指针异常 类型转换异常 算术异常 数组下标越界异常

  3. 常见的运行时异常 java 1615309080

    常见的运行时异常 java 1615309080 空指针异常 变量没赋值时,引发 数组越界异常 类型转换异常 数字格式化异常 算术异常 检查时异常

  4. 2020 idea 查看内存消耗_查看运行时某个java对象占用JVM大小及通过idea查看java的内存占用情况...

    一.如果想看运行时某个java对象占用JVM内存大小,可以先将对象转换成字节类型,然后计算: List bizGroupRelatedEventInfos = bizEventVersionMappe ...

  5. 解决:flash cs5运行时出现“java运行时环境初始化时出现错误,你可能需要重装Flash”

    我安装时遇到这个问题,并已成功解决. 解决办法: 确定C:/Documents and Settings/All Users/Application Data/Adobe/CS5/jre下有相关jav ...

  6. java获取运行时对象,java 面向对象(四十一):反射(五)反射应用二:获取运行时类的完整结构...

    我们可以通过反射,获取对应的运行时类中所有的属性.方法.构造器.父类.接口.父类的泛型.包.注解.异常等.... 典型代码: @Test public void test1(){ Class claz ...

  7. Android程序运行时出现java.lang.OutOfMemoryError 错误

    写了一个用Paint和Canvas画图的类,画完之后将所画内容保存到手机sd卡上. 1>代码如下: package me.linkcube.taku.ui.share;import java.i ...

  8. 鸿蒙应用开发DevEco运行时出现java.io.IOException: Invalid keystore format

    Failed to load signer "signer #1" java.io.IOException: Invalid keystore format 开发鸿蒙系统组件时新建 ...

  9. MapReduce运行时出现java.lang.NoClassDefFoundError

    最近在编写MapReduce程序时遇到了一个错误,错误提示信息为: Error: java.lang.ClassNotFoundException: org.apache.hadoop.hbase.H ...

最新文章

  1. php self this parent
  2. istringstream
  3. 【PAT乙级】1040 有几个PAT (25 分)
  4. Qt 串口类QSerialPort 使用笔记
  5. TiKV 源码解析系列 - Raft 的优化
  6. OpenGL入门-2-颜色
  7. C++ 返回类型协变
  8. PC端稳定性测试探索
  9. 使用windows 10 安装中文版语言
  10. H5视频播放demo
  11. 永久禁用software reporter 进程,占用高解决方法。【永久禁用software_reporter_tool.exe程序】
  12. 怎么在计算机上搭建远程桌面,创建远程桌面连接的方法
  13. 我的世界服务器无限制区块,我的世界所有区块同时加载,内存多惊人?162万个100T硬盘装不下...
  14. redit mysql_开发者经常用到的75 个功能强大的 jQuery插件和教程汇总(上篇)
  15. design pattern Builder 建造者设计模式
  16. SYN Flood攻击原理及防御技术
  17. 计算机网络多项式的定义,使用多项式方法定义一个圆
  18. 使用计算机打印资料时需要安装打印机驱动,安装打印机驱动时提示确认打印机已连接的问题分析及解决办法...
  19. 北京电大c语言实验作业二,大学大一c语言程序设计实验室上机题全部代码答案(实验报告).doc...
  20. Webots平台下NAO机器人仿真环境的搭建

热门文章

  1. drools 规则流_约束流–没有Drools规则语言的现代Java约束
  2. 手动编译 lombok_Lombok,一种编译时Java注释预处理器,可最大程度地减少代码大小...
  3. 有效Java第三版的源代码已更新为使用较新的功能
  4. jvm分配内存_为JVM分配内存:一个案例研究
  5. 程序员的前20个搜索和排序算法面试问题
  6. Spark Run本地设计模式
  7. spring安全_Spring安全–幕后
  8. JDK Bug系统浪费时间
  9. web 项目集成福昕_项目学生:Web服务集成
  10. Java应用程序中的验证