修改jar中的class:杀戮尖塔修改教程 您所在的位置:网站首页 杀戮尖塔mod制作教程下载安装 修改jar中的class:杀戮尖塔修改教程

修改jar中的class:杀戮尖塔修改教程

2024-06-27 11:35| 来源: 网络整理| 查看: 265

缘起

作为一只程序猿,游戏自然是标配。自从入了杀戮尖塔的坑,几年来陆陆续续玩了几百小时。然而steam上的成就至今没刷完,发牌员和各路小怪次次都在针对我。在第 n n {n^n} nn次死于通往进阶20的三层小怪之手后,我感受到了出离的愤怒。 于是我决定,用技术怼它。

思路

杀戮尖塔是用java开发,其主程序是一个.jar文件。现在要修改铁甲战士的基础卡:打击。 在这里插入图片描述 打击的基础伤害是6,目标是将其修改为60。

使用Java Decompiler反编译.jar文件,找到目标class文件和目标代码。使用jclasslib的byecode viewer或插件分析目标class文件,对目标代码进行定位。创建java工程,引入jclasslib的jar包,载入目标class文件并进行修改。将最终生成的新class文件替换到主程序的.jar中。 分析 Java Decompiler反编译

打开游戏目录,可以看到一个desktop-1.0.jar。这就是游戏的主程序。 首先使用Java Decompiler对其进行反编译。打开jd-gui,将desktop-1.0.jar拖进来: 在这里插入图片描述 如上,进入目录:

desktop-1.0\com\megacrit\cardcrawl\cards\red\

这是卡片目录,red即红色,也就是铁甲战士的红色卡。 第一个文件叫Anger.class,也就是愤怒。我们向下找,可以到找到文件Strike_Red.class,从名称看,这就是要找的打击了。 在这里插入图片描述 选中后可以看到右侧的源码,其构造函数中有这样一行代码:

this.baseDamage = 6;

这行代码设置了打击的基础伤害是6。我们的目标是将其修改为60。 然而,Java Decompiler只能查看class文件反编译后的结果,并不能对其进行修改。 并且由于该class文件import了众多库,无法直接使用javac命令来对单个文件进行编译。于是就需要借助jclasslib。

jclasslib byecode viewer分析class文件

使用winrar对游戏目录下的desktop-1.0.jar进行解压。 在这里插入图片描述 上面已经定位了Strike_Red.class的路径。在解压desktop-1.0.jar后生成的文件夹中找到该class文件,打开jclasslib byecode viewer,将class拖进来。 在这里插入图片描述 可以看到这里是用Java虚拟机的结构来查看class文件的。此部分内容可以参考《Java虚拟机规范》。 左侧的Constatnt Pool即常量池,Methods即方法。 通过前面的分析可知,要修改的内容位于构造函数中。 于是打开Methods,其下的0号元素即构造函数。 在这里插入图片描述 注意上面右侧的信息,包含两个重要的内容:

Name: Descriptor: ()V

打开,其下的0号属性是Code(很重要),这就是构造函数的代码。点击Code,可以在右侧面板查看其具体的实现: 在这里插入图片描述

同样,右侧上方的Generic info中包含了一个重要信息:

Attribute name index: cp_info #58

其中#58指的是常量池的58号索引位置。其名称叫Attribute name index。 右侧下方是构造函数的虚拟机代码。里面的指令借助栈和变量表及常量表进行了各种操作。我们需要关心的就是哪一行为变量赋值了6。 很明显地,可以看到如下代码:

27 aload_0 28 bipush 6 30 putfield #11

关键是中间的28 bipush 6。该行代码的含义是:

该指令从code的第28号索引开始。指令为入栈一个int。入栈的int值为6。

同时要明确:

code是以byte为单位。每个指令占一个字节,比如这里的bipush。参考下一行代码,可知该行代码占2个字节,即28和29。

将code看做一个byte数组,28号索引即code[28],其内容为bipush指令。code[29]就是入栈的int值6。 于是,只要我们能拿到code[29],并将其修改为60即可。 注意这里入栈的int值只占1个字节,且为带符号数,因此其值不应超过127。 byecode viewer只能进行查看,不能进行修改。

修改

要修改class文件有两种方式:

借助二进制文件修改工具。创建一个java工程,使用第三方库。

对于方式1,看似简单,实际需要直接分析代码的十六进制值,且要考虑到文件的字节对齐和加密等情况。 对于方式2,需借助第三方库。而第三方库必须集成到java中使用。故而需要创建一个java的工程。

这里使用方式2。故而先打开Intellij IDEA,新建一个JBoss工程。

依赖库安装

java常用于修改class文件内容的库有2个:jclasslib和javassist。

jclasslib:可通过虚拟机汇编方式查看class文件内容,且提供的jar能够对class文件进行修改。javassist:常用于动态编程。

两个库的安装方式如下。本篇采用jclasslib进行修改。

安装jclasslib 下载并安装

打开jclasslib的官方github进行下载:

https://github.com/ingokegel/jclasslib/releases

这里选择exe安装版本。下载后安装。 在这里插入图片描述

安装后,lib目录下为所有必要的jar包,修改class时需要将该文件夹导入到工程中作为依赖。

导入依赖到工程中

打开: File→Project Structure... 左侧选择Modules,右侧选择Dependencies标签,点最右侧**+**号,选择JARs or directories…,在弹出的窗口中选择jclasslib安装目录下的lib文件夹。 在这里插入图片描述

安装javassist 下载并安装

打开javassist的官方github进行下载:

http://www.javassist.org/

下载后是个zip压缩包,解压并复制到指定目录下。

导入依赖到工程中

打开: File→Project Structure... 左侧选择Modules,右侧选择Dependencies标签,点最右侧 + 号,选择JARs or directories…,在弹出的窗口中选择javassist目录下的javassist.jar文件。

修改class 准备工作 在桌面上创建一个Test文件夹,并将Strike_Red.class复制到这里。在Test文件夹下创建一个Change文件夹,用于存放修改后生成的Strike_Red.class文件。 编程进行修改和保存

实现代码:

import org.gjt.jclasslib.io.ClassFileWriter; import org.gjt.jclasslib.structures.AttributeInfo; import org.gjt.jclasslib.structures.ClassFile; import org.gjt.jclasslib.structures.MethodInfo; import org.gjt.jclasslib.structures.attributes.CodeAttribute; import java.io.DataInput; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; public class Main { public static void main(String[] args) throws Exception { String filePath = "C:\\Users\\Administrator\\Desktop\\Test\\Strike_Red.class"; FileInputStream fis = new FileInputStream(filePath); DataInput di = new DataInputStream(fis); ClassFile cf = new ClassFile(); cf.read(di); // 载入类文件数据 // 获取构造函数 MethodInfo mi = cf.getMethod("", "()V"); // 方法的所有属性 AttributeInfo[] attributes = mi.getAttributes(); // 0号属性为Code CodeAttribute codeAttribute = (CodeAttribute)attributes[0]; byte[] code = codeAttribute.getCode(); // 获取Code的二进制内容 code[29] = 60; // 修改29号索引内容 codeAttribute.setCode(code); // 重设方法的Code内容 fis.close(); // 保存修改后的ClassFile File f = new File("C:\\Users\\Administrator\\Desktop\\Test\\Change\\Strike_Red.class"); ClassFileWriter.writeToFile(f, cf); } }

整体思路为:

创建一个ClassFile,将class文件载入进来。获取构造函数,存放到一个MethodInfo对象中。这里用到的参数为构造函数的Name和Descriptor,前面的分析已经得知这两个值。获取构造函数所有的属性。0号属性即为Code,前面已经分析过。将获取到的0号属性转换为CodeAttribute。获取Code的二进制内容,是一个byte数组。要修改的内容位于29号索引,将其修改为60。这里若修改为>127的值IDEA会提示错误。将修改后的Code设置回构造函数的属性中。于是构造函数内容被修改,也就是当前ClassFile被修改。将修改后的ClassFile保存在Test/Change下。

运行后,即会在Test/Change下生成Strike_Red.class文件。 将这个生成的文件拖入到Byecode viewer中,查看构造函数的Code,可以看到baseDamage已经修改为60: 在这里插入图片描述

替换

现在需要将Strike_Red.class替换回desktop-1.0.jar。 首先将Java Decompiler和Byecode viewer都关闭,以防止对正在打开的文件进行修改。 然后用winrar打开desktop-1.0.jar(是打开不是解压),找到Strike_Red.class所在的路径: com\megacrit\cardcrawl\cards\red 将上一步生成的修改后的Strike_Red.class直接拖进来,替换。 这样修改就完成了。运行游戏看一下: 在这里插入图片描述

It’s Hammer Time!


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有