简单的jar包解压class文件修改再编译成jar包
1. 需求
我们公司有一个项目演示的环境,这个环境是我们公司其他组的项目,我们组只有这个项目的前端,jar
,以及部分数据库结构表信息,现在我们已经启动服务可以正常访问,但是发起业务的时候发现,有很多接口需要调用外围接口,比如调用esb
系统,调用行内核心系统等,现在要将此部分进行注释才能进行后续调用,此处使用idea
工具进行操作,此处记录一下,方便后续如果要修改简单类方便查询。
2.具体实现过程
我们操作的过程主要还是分为三个步骤,需要解压原有包,修改文件再编译等,具体实现过程如下所示
2.1 解压原有包信息
我们使用java原生工具类jar命令解压clm.jar,获取到解压后的文件夹
解压后的文件目录,我们要修改的文件是clm-giving-credit-1.0.1.RELEASE.jar
中的文件,具体的目录位置为\BOOT-INF\lib
中,具体的修改文件为 org.git.gr.modules.clm.controller.company.CompanyApplyController
。
2.2 配置重写class环境
我们需要将解压后的全部包都导入到idea中,配置好maven信息,然后将clm.jar
解压的\BOOT-INF\lib
中的jar
导入到项目中,具体步骤如下:
- 新增一个maven项目
项目类型选择maven
类型,然后点击next
对maven项目设定名字路径以及坐标信息
之后获得一个空的maven项目
配置项目的maven
信息
我们开始添加之前clm.jar
解压后的全部jia
包,既\BOOT-INF\lib
中的全部jar
包
观察jar
包是否已经全部导入,然后再顺手配置一下jdk
版本信息为自己需要的版本,我们使用的是1.8
版本
2.3 重写class文件
我们需要重写一个与要修改的 org.git.gr.modules.clm.controller.company.CompanyApplyController
,同名同目录的一个类文件
然后使用java-decompiler反编译工具找到对应类,复制里面的内容信息到自己新增的类中
然后找到自己要修改的方法进行注释或者修改
修改之后使用Build Module
进行重新编译,然后在编译后的target中可以获取到编译后的class
文件
2.4 替换编译后的class文件
我们使用新编译的CompanyApplyController.class
替换掉clm-giving-credit-1.0.1.RELEASE.jar
中的CompanyApplyController.class
,我们使用360解压缩工具直接复制替换即可
2.5 重新编译clm.jar
我们上面已经获取到了修改之后的clm-giving-credit-1.0.1.RELEASE.jar
了,我们现在可以将修改后的clm-giving-credit-1.0.1.RELEASE.jar
重新替换回clm.jar
即可。我们使用jar -uvf0
命令更新指定jar
包内容
jar -uvf0 clm.jar .\BOOT-INF\lib\clm-giving-credit-1.0.1.RELEASE.jar
观察到此信息既表明jar包已经更新
如果不放心可以进入到clm.jar
中的clm-giving-credit-1.0.1.RELEASE.jar
包中查看信息是否已经修改,如下图所示,代码已经修改
至此,我们完成了class
文件的反编译修改再次编译成jar
的过程,这个过程中也有其他问题尚未解决,我这个编辑的类是相对简单的类,我发现有很多类比较复杂实现了多个接口,还有很多内部类,这样会导致一个java
文件编译之后形成多个class
文件,这样的情况就需要根据多个class
类还原java
文件详细信息了,这样的情况编译后的class
不太好还原,暂时无法处理,如有可以处理的方法希望评论区告知。
3. 2024-09-26 补充
本人想使用arthas
反编译带有内部类,多构造参数类,看看编译后的代码可读性是否可以满足
原始类内容:
package cn.git.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description:
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2024-09-26
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ParamDTO {
/**
* 用户名
*/
private String name;
/**
* 密码
*/
private String password;
/**
* 实体信息
*/
private EntityInfo entityInfo;
/**
* @description: 实体信息
* @program: bank-credit-sy
* @author: lixuchun
* @create: 2024-09-26
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class EntityInfo {
/**
* 性别
*/
private String sex;
/**
* 身高
*/
private Integer height;
}
}
反编译后类:
反编译命令如下:
[arthas@3333]$ sc *DTO
cn.git.dto.ParamDTO
Affect(row-cnt:1) cost in 11 ms.
[arthas@3333]$ jad cn.git.dto.ParamDTO
ClassLoader:
+-org.springframework.boot.loader.LaunchedURLClassLoader@685f4c2e
+-sun.misc.Launcher$AppClassLoader@70dea4e
+-sun.misc.Launcher$ExtClassLoader@b81eda8
Location:
file:/root/arthas/docker-hello-1.0-SNAPSHOT.jar!/BOOT-INF/classes!/
反编译后的代码内容如下:
/*
* Decompiled with CFR.
*
* Could not load the following classes:
* cn.git.dto.ParamDTO$EntityInfo
*/
package cn.git.dto;
import cn.git.dto.ParamDTO;
public class ParamDTO {
private String name;
private String password;
private EntityInfo entityInfo;
public void setEntityInfo(EntityInfo entityInfo) {
/*13*/ this.entityInfo = entityInfo;
}
public String getPassword() {
/*26*/ return this.password;
}
public void setPassword(String password) {
/*13*/ this.password = password;
}
protected boolean canEqual(Object other) {
/*13*/ return other instanceof ParamDTO;
}
public EntityInfo getEntityInfo() {
/*31*/ return this.entityInfo;
}
public ParamDTO(String name, String password, EntityInfo entityInfo) {
this.name = name;
this.password = password;
this.entityInfo = entityInfo;
}
public ParamDTO() {
}
public boolean equals(Object o) {
/*13*/ if (o == this) {
return true;
}
if (!(o instanceof ParamDTO)) {
return false;
}
ParamDTO other = (ParamDTO)o;
if (!other.canEqual(this)) {
return false;
}
String this$name = this.getName();
String other$name = other.getName();
if (this$name == null ? other$name != null : !this$name.equals(other$name)) {
return false;
}
String this$password = this.getPassword();
String other$password = other.getPassword();
if (this$password == null ? other$password != null : !this$password.equals(other$password)) {
return false;
}
EntityInfo this$entityInfo = this.getEntityInfo();
EntityInfo other$entityInfo = other.getEntityInfo();
return !(this$entityInfo == null ? other$entityInfo != null : !this$entityInfo.equals(other$entityInfo));
}
public String toString() {
return "ParamDTO(name=" + this.getName() + ", password=" + this.getPassword() + ", entityInfo=" + this.getEntityInfo() + ")";
}
public int hashCode() {
/*13*/ int PRIME = 59;
int result = 1;
String $name = this.getName();
result = result * 59 + ($name == null ? 43 : $name.hashCode());
String $password = this.getPassword();
result = result * 59 + ($password == null ? 43 : $password.hashCode());
EntityInfo $entityInfo = this.getEntityInfo();
result = result * 59 + ($entityInfo == null ? 43 : $entityInfo.hashCode());
return result;
}
public String getName() {
/*21*/ return this.name;
}
public void setName(String name) {
/*13*/ this.name = name;
}
}
Affect(row-cnt:1) cost in 149 ms.
[arthas@3333]$
结论: 发现整体展示代码可读性还是不佳