项目中有一个类 cn.qy.fk.util.PluginStarter
, 当 org.hyperic.sigar.Sigar
的对象被 new 出来时, PluginStarter 整个类的方法都会被重载, 完整的代码我都贴在下面, 想问下大佬们我如果要修改方法内容, 应该如何操作呢?
想要修改方法的类 cn.qy.fk.util.PluginStarter
(从 jar 包中反编译得来):
package cn.qy.fk.util;
@CustomFunction(
type = 7
)
public class PluginStarter {
public PluginStarter() {
}
public boolean start() {
return (boolean)null;
}
public void end() {
}
}
项目运行时 cn.qy.fk.util.PluginStarter
实际的源码为:
package cn.qy.fk.util;
import cn.qy.fk.util.CustomFunction;
import cn.qy.fk.util.SystemProperties;
@CustomFunction(type=7)
public class PluginStarter {
public boolean start() {
String error;
if ((error = SystemProperties.get((String)"error")) != null) {
System.out.println(error);
return false;
}
System.out.println("Plugin Context is starting ...");
return true;
}
public void end() {
System.out.println("Plugin Context was started!");
}
}
注解 cn.qy.fk.util.CustomFunction
(从 jar 包中反编译得来):
package cn.qy.fk.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomFunction {
int type();
}
项目中用到了:
我通过 IDEA 的断点发现每当代码执行到了下面的 new Sigar();
时类就被重载了.
try {
Sigar sigar = new Sigar();
(new PluginStarter()).start();
}
项目的资源目录还发现了:
libsigar-amd64-freebsd-6.so
libsigar-amd64-linux.so
libsigar-amd64-solaris.so
libsigar-ia64-hpux-11.sl
libsigar-ia64-linux.so
libsigar-pa-hpux-11.sl
libsigar-ppc64-aix-5.so
libsigar-ppc64-linux.so
libsigar-ppc-aix-5.so
libsigar-ppc-linux.so
libsigar-s390x-linux.so
libsigar-sparc64-solaris.so
libsigar-sparc-solaris.so
libsigar-universal64-macosx.dylib
libsigar-universal-macosx.dylib
libsigar-x86-freebsd-5.so
libsigar-x86-freebsd-6.so
libsigar-x86-linux.so
libsigar-x86-solaris.so
sigar-amd64-winnt.dll
sigar-x86-winnt.dll
sigar-x86-winnt.lib
想问下这种是不是被 jni 给重载了呢?如果要改的话怎么入手?
1
kyrieIvring 2023-04-10 21:31:58 +08:00
一 看 classloader 是不是优先加载你这个 class ,如果是 强行改 classloader 的顺序
二 看这个 class 是不是被编译进各个系统 jar 包里面了,如果是,你要找到对应的 jar 包,修改一下,再把它放回原来的位置 |
2
biuaxia OP @kyrieIvring 确定不是 classloader 导致的,利用类加载机制覆盖也没法。
|
3
biuaxia OP @kyrieIvring 贴出来的代码都是从三方 jar 包中反编译出来的,然后运行时通过阿里 arthas(可能拼错)运行 jad 得到的源码
|
4
huyangq 2023-04-11 09:07:58 +08:00
不理解,什么叫类会被重载?我就知道函数(或者说方法、method)重载(overload)
|
5
huyangq 2023-04-11 09:13:57 +08:00
仔细又阅读了一下,你的意思是有一个类 PluginStarter ,直接反编译 jar 包,发现改类中的 start()、end()的实现逻辑是 A ,但是当运行之后,如果执行到一行代码:new Sigar()之后,类 PluginStarter 中的 start()、end()的实现逻辑却成了 B 。
|
6
huyangq 2023-04-11 09:14:47 +08:00
如果是这样,结合你的依赖包 asm 猜测是运行时修改了字节码实现的
|
8
huyangq 2023-04-11 09:55:53 +08:00
你可以先确认是不是改的字节码,既然你说执行 new Sigar()会修改函数实现,你可在执行 new Sigar()之前、之后调用一下 start()、end()用来确定是否真的在 Sigar 构造函数中修改了函数实现,然后,再去看 Sigar 构造函数的实现 看看里头是不是真的又修改函数实现的代码,如果有,那简单啊 执行构造函数之后,再改成你要的函数实现就可以了
|
9
vvtf 2023-04-11 09:59:57 +08:00
看下 java-agent 吧,
是用 instrumentation 实现的. |
10
dif 2023-04-11 10:56:49 +08:00
有个成熟的监控项目 pinpoint 用到了类似的技术,你可以参考下。都是通过 java-agent 实现的。
|
11
Aresxue 2023-04-11 21:58:48 +08:00
类不会重载,只是会被 retransform ,简而言之就是方法体里面的字节码会被替换掉,JVMTI 提供了这样的机制,一般都是各种 agent 在启动时就会修改指定方法的字节码,不过也有些剑走偏锋直接在框架中用 asm 或者 javasist 修改的,像 HikariCP 就使用了各种字节码的黑魔法,可以看下有没有使用这两个框架的 api 的地方
|