Java逆向基础之简单的补丁

本文参考:http://www.vuln.cn/7118

本文参考:《Reverse Engineering for Beginners》Dennis Yurichev著

本文需要用到IDA

简单的补丁

看一个例子

public class nag {
	public static void nag_screen() {
		System.out.println("This program is not registered");
	};

	public static void main(String[] args) {
		System.out.println("Greetings from the mega-software");
		nag_screen();
	}
}

我们怎样去掉打印"This program is not registered"这个字符串?

编译后用IDA载入class文件

作者的IDA view视图同步显示了hex的值,可能装了插件或者改了设置,这里的IDA view视图与hex需要切换视图

ALT+T,搜索文本This program is not registered,定位到相关指令附近

我们首先尝试将getstatic指令改成返回指令

点击getstatic,然后点击hex视图

可以看到B2 00 02对应这条指令

右键修改B2 为B1,然后右键应用更改

再切回IDA view视图

最后菜单点击Edit-->Patch Program-->Apply patches to input file,将更改应用到文件

在弹出的对话框点确定即可修改class文件

但是这么修改运行的时候会报错,可能是有一些栈和帧的校验

C:\Users\admin\Desktop>java nag
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.VerifyError: Expecting a stack map frame
Exception Details:
  Location:
    nag.nag_screen()V @1: nop
  Reason:
    Error exists in the bytecode
  Bytecode:
    0x0000000: b100 0212 03b6 0004 b1

        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
        at java.lang.Class.privateGetMethodRecursive(Unknown Source)
        at java.lang.Class.getMethod0(Unknown Source)
        at java.lang.Class.getMethod(Unknown Source)
        at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
        at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

原作者在JDK1.7下不工作,我在1.8下也是,报的是栈帧映射异常

既然此路不通,那么就选另一条路,去掉nag()方法的调用

找到main方法

中间的

.line 8

invokestatic nag.nag_screen()V

这一句就是调用nag()方法,查看对应的hex视图

其中的B8 00 06就是调用这个方法

改成00 00 00(填充3个NOP指令)

对应的IDA view视图

变成了3个nop指令

最后菜单点击Edit-->Patch Program-->Apply patches to input file,将更改应用到文件

修改完看运行效果

修改成功

再看第二个例子

这是一个简单的crackme的例子

public class password {
	public static void main(String[] args) {
		System.out.println("Please enter the password");
		String input = System.console().readLine();
		if (input.equals("secret"))
			System.out.println("password is correct");
		else
			System.out.println("password is not correct");
	}
}

反编译后的class用IDA打开

搜索字符串"secret"定位到判断代码附近

其中ifeq指令当栈顶int型数值等于0时跳转 ,栈顶存的是String.equals()方法的返回值

首先我们考虑改跳转的位置,改到line 6后面的getstatic指令那里,那么这个指令对应偏移块是多少呢

点击getstatic,状态栏会显示

这个偏移块是24

目标就是将ifeq met002_35修改成ifeq met002_24

ifeq指令所在偏移块是21,35-21=14对应16进制是E,找出hex视图对应的E

可以看到99 00 0E,所以我们要修改其中的E

那么改成多少呢,24-21=3对应16进制的3,所以将E改成3

再看看IDA view视图符不符合预期

最后菜单点击Edit-->Patch Program-->Apply patches to input file,将更改应用到文件

原作者的修改在JDK1.7下不工作,我这里的JDK1.8也报错了

C:\Users\admin\Desktop>java password
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 24
Exception Details:
  Location:
    password.main([Ljava/lang/String;)V @21: ifeq
  Reason:
    Expected stackmap frame at this location.
  Bytecode:
    0x0000000: b200 0212 03b6 0004 b800 05b6 0006 4c2b
    0x0000010: 1207 b600 0899 0003 b200 0212 09b6 0004
    0x0000020: a700 0bb2 0002 120a b600 04b1
  Stackmap Table:
    append_frame(@35,Object[#20])
    same_frame(@43)

        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
        at java.lang.Class.privateGetMethodRecursive(Unknown Source)
        at java.lang.Class.getMethod0(Unknown Source)
        at java.lang.Class.getMethod(Unknown Source)
        at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
        at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

这里必须要提的是,这种改法再JDK1.6上是可以运行的

我们也尝试将if eq 这个占用3个字节的指令用0(NOP指令)填充,结果也是校验失败,不能工作

貌似再JDK1.7上比1.6多了更多的帧栈校验

接下来我们尝试替换整个equals方法,并用iconst_1将常数1压入栈顶,这样后面ifeq判断的时候值始终为flase,就不往偏移块35跳转了

iconst_1的指令是0x04

即将图中的2B 12 07 B6 00 08改成04 00 00 00 00 00

改完后看下IDA view视图

改完之后工作正常

原文地址:http://blog.51cto.com/7317859/2106049

时间: 2024-07-31 10:06:44

Java逆向基础之简单的补丁的相关文章

Java逆向基础之AspectJ的Around方法修改方法体

在逆向中,我们往往通过修改某个方法达到目的,在javaassist中有insertBefore,insertAfter,setBody,在AspectJ中也可以通过Around实现类似的功能. 看一个简单的例子 java文件Main.java //Main.java package com.vvvtimes; public class Main { public int add(int x, int y) { return x + y; } public int add(int x, int y

Java逆向基础之条件跳转位运算循环

本文参考:http://www.vuln.cn/7117 条件跳转的例子,绝对值 public class abs {     public static int abs(int a)     {         if (a<0)             return -a;         return a;     } } 编译 javac abs.java 反编译 javap -c -verbose abs.class   public static int abs(int);     d

Java逆向基础之数组

本文参考:http://www.vuln.cn/7116 本文参考:<Reverse Engineering for Beginners>Dennis Yurichev著 数组 简单的例子 创建一个长度是10的整型的数组,对其初始化 public class ArrayInit { public static void main(String[] args) { int a[] = new int[10]; for (int i = 0; i < 10; i++) a[i] = i; d

Java逆向基础之动态生成类

为什么有这个东西,一方面时AOP框架的需要,另一方面是增加软件逆向的难度 动态生成类的技术目前大体上分为两类,一类是通过操作字节码框架如cglib/Javassist去实现,另一类就是JNI方式,调用dll/so库,内存中动态还原.这两种方式都能实现隐藏类 看一个Javassist动态生成类的例子 package com.vvvtimes; import java.lang.reflect.Modifier; import javassist.ClassPool; import javassis

Java逆向基础之初识javaagent

首先说一下javaagent是什么 javaagent是一种能够在不影响正常编译的情况下,修改字节码. 在逆向中javaagent可以完成对类的拦截和增强. 看一个例子 在Eclipse新建如下MyAgent结构的项目 MyAgent.java文件内容 package com.vvvtimes.demo.agent; import java.lang.instrument.Instrumentation; public class MyAgent {     public static void

Java逆向基础之导出内存中的类一

为什么需要这个,因为在之前的博文中提到,为了增加逆向的难度,部分软件会对部分关键方法和类进行隐藏,所以我们需要把这个类从内存中拿出来. 本文介绍使用javaagent的方法,下一篇介绍dumpclass,两种方法各有利弊. 本文需要用到第三方jar为:javassist-3.20.0-GA.jar,不过我们需要的是它的源码javassist-3.20.0-GA-sources.jar 新建名为DumpClassAgent的项目,项目结构如下 将下载到的源码复制到src目录下 DumpClassA

Java逆向基础之JDB动态调试

本文参考:https://docs.oracle.com/javase/8/docs/technotes/tools/windows/jdb.html JDB在有源代码的时候可以实现调试远程机器上的java程序,但是在逆向中源码很难分析出来,不过还是能够调试得到一部分信息的 本文主要获取两个信息 1.动态调用混淆类中的方法,因为实践过程中我们去手动补全相关代码比较难 2.打印调用栈 以下例子以调试ZKM.jar为例 JDB无源代码调试调用方法 启动Xdebug调试 java -Xdebug -X

Java逆向基础之ODB动态调试

说明: 1在<透视JAVA-反编译修补和逆向工程技术>提到了这个工具,这里简单介绍一些 2ODB(即Omniscient Debugger)最新版本已经迁移到github上 3ODB支持的最高JDK版本是1.6,用来分析新版本的jar包和类会报各种异常,从内心的角度来说还是不太想介绍这个工具的 OmniscientDebugger ODB的使用 下载 github方式 https://github.com/OmniscientDebugger/LewisOmniscientDebugger/r

java集合基础篇 简单总结

昨天晚上看了编程思想4的持有对象,所以把学到看到的一些记记背背的方面给总结一下. java的容器主要分为两类,一个是实现了接口Collection的一类,还有一个是实现了Map接口的一类. 继承Collction接口的主要有List.Set接口还有Queue.Collection继承了Iterator接口,让实现类可以foreach遍历. 继承List接口的主要是ArrayList和LinkedList. ArrayList的优势在于随机访问,LinkedList的优势则是更好的插入删除,另外L