Skip to content

Instantly share code, notes, and snippets.

@FlyingFish07
Last active June 21, 2017 15:05
Show Gist options
  • Select an option

  • Save FlyingFish07/b155d5fffe34c2c06413ed63922240a0 to your computer and use it in GitHub Desktop.

Select an option

Save FlyingFish07/b155d5fffe34c2c06413ed63922240a0 to your computer and use it in GitHub Desktop.
Fake time java agent
package com.zyh.ftmagent;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
public class FtmAgent {
public static void premain(String agentArgs, Instrumentation inst)
throws ClassNotFoundException, UnmodifiableClassException{
inst.addTransformer(new TimeTransformer());
}
}
Manifest-Version: 1.0
Premain-Class: com.zyh.ftmagent.FtmAgent
Boot-Class-Path: javassist-3.22.0-CR1.jar
package com.zyh.ftmagent;
import java.util.Date;
public class MyDate extends Date {
private static final long serialVersionUID = 1L;
public MyDate(){
super(MySystemTime.currentTimeMillis());
}
}
package com.zyh.ftmagent;
public class MySystemTime {
//默认为当前时间
private static final Long INIT_VALUE = 0l;
private static ThreadLocal<Long> timeDiff = new ThreadLocal<Long>() {
@Override
protected Long initialValue() {
return INIT_VALUE;
}
};
public static long currentTimeMillis() {
return System.currentTimeMillis() - timeDiff.get();
}
public static long nanoTime() {
return System.nanoTime() - timeDiff.get() * 1000;
}
/**
* 设置距离当前的时间,为正表示后退多少ms
*
* @param diff
*/
public static void setTimeDiff(long diff) {
timeDiff.set(diff);
}
}
package com.zyh.test;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyTestClass {
public void dateTest() {
long stTime = System.currentTimeMillis();
System.out.println("Now CurrentTimeMillis 1:" + stTime);
long nt = System.nanoTime();
System.out.println("Now nanoTime:" + nt);
System.out.println("Now CurrentTImeMillis 2:" + System.currentTimeMillis());
Date ct = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
String rslt = sdf.format(ct);
System.out.println("Now Date:" + rslt);
System.out.println("now Date2:" + sdf.format(new Date()));
Date ct2 = new Date(System.currentTimeMillis());
System.out.println("Now Date3:" + ct2);
}
}
<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>com.zyh</groupId>
<artifactId>ftmagent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ftmagent</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.22.0-CR1</version>
</dependency>
</dependencies>
</project>
java -javaagent=ftm-agent.jar -jar ftm-test.jar
package com.zyh.test;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.zyh.ftmagent.MySystemTime;
public class TestMain {
public static void main( String[] args ) throws Exception {
System.out.println("Real Time:" +System.currentTimeMillis());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Real Date2:" + sdf.format(new Date()));
MySystemTime.setTimeDiff(3000l);//时钟回拨3s
MyTestClass testClass = new MyTestClass();
testClass.dateTest();
}
}
package com.zyh.ftmagent;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.NotFoundException;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;
import javassist.expr.NewExpr;
public class TimeTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
// 仅对于com.zyh.test包下的类进行替换
if (className.startsWith("com/zyh/test")) {
byte[] transformed = null;
System.out.println("Transforming " + className);
ClassPool pool = ClassPool.getDefault();
CtClass cl = null;
try {
cl = pool.makeClass(new java.io.ByteArrayInputStream(classfileBuffer));
if (cl.isInterface() == false) {
CtBehavior[] methods = cl.getDeclaredBehaviors();
for (int i = 0; i < methods.length; i++) {
if (methods[i].isEmpty() == false) {
doMethod(methods[i]);
}
}
transformed = cl.toBytecode();
}
} catch (Exception e) {
System.err.println("Could not instrument " + className + ", exception : " + e.getMessage());
} finally {
if (cl != null) {
cl.detach();
}
}
return transformed;
}
return null;
}
private void doMethod(CtBehavior method) throws NotFoundException, CannotCompileException {
// 修改方法体的定义
method.instrument(new ExprEditor() {
// 修改一般的方法调用语句
public void edit(MethodCall m) throws CannotCompileException {
try {
if (m.getClassName().equals("java.lang.System")) {
if (m.getMethodName().equals("nanoTime")) {
m.replace("{long rslt = com.zyh.ftmagent.MySystemTime#nanoTime(); $_ = ($r)rslt; }");
} else if (m.getMethodName().equals("currentTimeMillis")) {
m.replace(
"{long rslt = com.zyh.ftmagent.MySystemTime#currentTimeMillis(); $_ = ($r)rslt; }");
}
}
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
// 修改new Date()这种格式的代码,替换其中的class类
public void edit(NewExpr e) throws CannotCompileException {
try {
if (e.getClassName().equals("java.util.Date")) {
e.replace("{$_ = new com.zyh.ftmagent.MyDate();}");
}
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment