deepdrink

导航

简单逆向Java程序

前置

来源

这个程序是我同学编写的一个学生分数管理系统,我将对这个已经编译的程序进行测试、逆向,找出其中的问题,并进行改进。


运行环境

  • macOS 15.4
  • IntelliJ IDEA 2024.2.3
  • OpenJDK 23.0.2
  • TomCat 11.0.4
  • Safari 15.4

运行结果

image
image
image
image
image


主要问题

在使用程序后发现:

  • 缺少绩点计算
  • 添加学生时没有对学号进行唯一性检查
  • 添加成绩时没有对成绩进行唯一性检查

接下来对这些问题进行改进。


逆向

由于没有源码,需要通过逆向方式恢复代码。

Java 的 .class 文件可以使用 FernFlower 反编译器(IDEA
内置)进行反编译。


Score.class

package com.example.javadzy;

import java.io.Serializable;

public class Score implements Serializable {
    private String course;
    private int grade;

    public Score(String course, int grade) {
        this.course = course;
        this.grade = grade;
    }

    public String getCourse() {
        return this.course;
    }

    public void setCourse(String course) {
        this.course = course;
    }

    public int getGrade() {
        return this.grade;
    }

    public void setGrade(int grade) {
        this.grade = grade;
    }
}

Student.class

package com.example.javadzy;

import java.io.Serializable;
import java.util.ArrayList;

public class Student implements Serializable {
    private String name;
    private ArrayList<Score> scores;

    public Student(String name) {
        this.name = name;
        this.scores = new ArrayList<>();
    }

    public String getName() {
        return this.name;
    }

    public ArrayList<Score> getScores() {
        return this.scores;
    }

    public void addScore(Score score) {
        this.scores.add(score);
    }
}

Statistics 统计类

public class Statistics {
    public float average = 0.0F;
    public int max = 0;
    public int min = 100;
    public float passRate = 0.0F;

    public Statistics(Student student) {
        int sum = 0;
        int passCount = 0;

        for (Score score : student.getScores()) {
            sum += score.getGrade();

            if (score.getGrade() > max) max = score.getGrade();
            if (score.getGrade() < min) min = score.getGrade();
            if (score.getGrade() >= 60) passCount++;
        }

        if (!student.getScores().isEmpty()) {
            average = (float) sum / student.getScores().size();
            passRate = (float) passCount / student.getScores().size();
        }
    }
}

数据存储

程序通过序列化保存学生数据。

ObjectOutputStream
ObjectInputStream

数据结构:

TreeMap<Integer, Student>

GPA计算改进

public double gpa(float score) {
    if (score >= 90) return 4;
    else if (score >= 85) return 3.7;
    else if (score >= 82) return 3.3;
    else if (score >= 78) return 3;
    else if (score >= 75) return 2.7;
    else if (score >= 72) return 2.3;
    else if (score >= 68) return 2;
    else if (score >= 64) return 1.5;
    else if (score >= 60) return 1;
    else return 0;
}

JSP页面展示

<p>
平均绩点:<%= stats.gpa %>
平均分:<%= stats.average %>
最高分:<%= stats.max %>
最低分:<%= stats.min %>
及格率:<%= stats.passRate %>
</p>

数据结构优化

原结构:

ArrayList<Score>

复杂度:

O(n)

优化为:

HashMap<String, Integer>

优势:

  • 查找 O(1)
  • 方便检测课程重复

新结构

private HashMap<String, Integer> scores;
public void addScore(String course, Integer score) {
    if (scores.containsKey(course)) {
        throw new RuntimeException("课程重复");
    }
    scores.put(course, score);
}

重构结果

image
image
image


总结

通过这次逆向工程:

  • 理解了 Java 反编译流程
  • 分析了程序结构
  • 重构了数据结构
  • 增加了 GPA 功能

这也是一次典型的 Java程序逆向 + 重构实践

posted on 2026-03-12 09:21  litroenade  阅读(13)  评论(0)    收藏  举报