作为一个流氓程序猿,打劫放火的时候,经常需要修改别人已经编译的类,在一些,没有源代码,隔离内网,破解注册码,等特殊场景下。
1. 显而易见
想办法把源代码弄过来,导入项目,凑齐Jar包,然后。。没有了
2. 祭出神器
招式:使用字节码工具,比如 javassist,jbe 直接对class文件进行修改。屠龙宝刀在手,迎刃而解。
场景:修改hive-jdbc中文乱码问题的时候,当时在隔离内网,没法弄到源代码。
适用:密界最喜欢用的工具之一了吧,适合各种破解游戏,注册,验证一类的。俗称爆破
缺点:需要一点内功,要耍的动Java字节码。当然javassist要容易点。
代码:
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;
public class HivePatch {
/**
* DESC :fix about jdbc utf-8
*
* @param jarPath hive-jdbc-jar path
*
*/
public void patch(String jarPath){
try{
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(jarPath) ;
CtClass cc = pool.get("org.apache.hadoop.hive.jdbc.HiveQueryResultSet");
CtMethod ms=cc.getDeclaredMethod("next");
ms.instrument(
new ExprEditor() {
public void edit(MethodCall m) throws CannotCompileException
{
if (m.getClassName().equals("java.lang.String")
&& m.getMethodName().equals("getBytes")){
m.replace("{$_=rowStr.getBytes(\"UTF-8\");}");
System.out.println("line "+m.getLineNumber()+" change .");
}
}
});
cc.writeFile(jarPath);
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
new HivePatch().patch("/home/hive-jdbc-0.9.0.jar");
}
}
3. 返璞归真
招式:不用神功,手里也没有神器,一片叶子也能破敌,从没见过这么修改类的,颇有返璞归真的境界。
场景:修改elasticsearch-hadoop-1.3.0.M1 日期类型格式问题的时候,还在隔离内网,没法弄到源代码。
适用:实在字节码工具没有,源代码也没有的时候,空手套白狼吧。
缺点:要修改的类的依赖关系复杂的时候,工作量倍增。
代码:
public class HiveValueReader extends WritableValueReader {
@Override
protected Object date(String value) {
return new TimestampWritable(new Timestamp(DatatypeConverter.parseDateTime(value).getTimeInMillis()));
}
@Override
protected Class<? extends Writable> dateType() {
return TimestampWritable.class;
}
}
这里的date方法在格式化 yyyy-MM-dd HH:mm:ss.SSS 的时候会有问题,我们要修改date方法的时候,可以创建个项目,把这个类的依赖都创建空类
然后把所有的依赖方法都,创建空方法,如图
这样,我们就可以修改编译,我们的HiveValueReader类了