Java逆向基础之函数

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

本文提到的函数(function)和方法(method)为同一个意思

例子1,方法名的定义

public class HalfRandom
{
public static double f()
{
return Math.random()/2;
}
}

编译

javac HalfRandom.java

反编译

javap -c -verbose HalfRandom.class
...
major version: 52
...
#2 = Methodref          #16.#17        // java/lang/Math.random:()D
#3 = Double             2.0d
...
#12 = Utf8               ()D
...
#16 = Class              #20            // java/lang/Math
#17 = NameAndType        #21:#12        // random:()D
#18 = Utf8               HalfRandom
#19 = Utf8               java/lang/Object
#20 = Utf8               java/lang/Math
#21 = Utf8               random
...
public static double f();
descriptor: ()D
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=0, args_size=0
0: invokestatic  #2                  // Method java/lang/Math.random:()D
3: ldc2_w        #3                  // double 2.0d
6: ddiv
7: dreturn
LineNumberTable:
line 5: 0

invokestatic  #2  调用常量#2定义的函数

函数名定义在常量池的Methodref中,它定义类,方法名,方法返回类型

常量#2中,可以看到它是由#16.#17拼接,#16定义了类名 java/lang/Math,#17是方法名和返回类型名random:()D

常量#17中,它是由#21:#12拼接,#21定义了方法名random,#12定义了返回类型名()D

()D的解释 ,括号内没有东西表示括号内无参数,D表示返回类型为double,如果是V则为void

这种方式

1)JVM可以检查数据类型的正确性:

2)java反编译器可以从被编译的类文件中修改数据类型。

再看"hello,world!"的例子

public class HelloWorld
{
public static void main(String[] args)
{
System.out.println("Hello, World");
}
}

反编译

...
major version: 52
...
#2 = Fieldref           #16.#17        // java/lang/System.out:Ljava/io/PrintStream;
#3 = String             #18            // Hello, World
#4 = Methodref          #19.#20        // java/io/PrintStream.println:(Ljava/lang/String;)V
...
#16 = Class              #23            // java/lang/System
#17 = NameAndType        #24:#25        // out:Ljava/io/PrintStream;
#18 = Utf8               Hello, World
#19 = Class              #26            // java/io/PrintStream
#20 = NameAndType        #27:#28        // println:(Ljava/lang/String;)V
...
#23 = Utf8               java/lang/System
#24 = Utf8               out
#25 = Utf8               Ljava/io/PrintStream;
#26 = Utf8               java/io/PrintStream
#27 = Utf8               println
#28 = Utf8               (Ljava/lang/String;)V
...
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc           #3                  // String Hello, World
5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 5: 0
line 6: 8

getstatic  #2 获取System.out的引用入栈

ldc  #3 将字符串Hello, World入栈

invokevirtual #4 调用println()方法,这里需要传两个参数,参数从栈中获取,1先将Hello, World出栈传入(Ljava/lang/String;),2将System.out的引用出栈传入java/io/PrintStream的引用

再看beep的函数调用(输出计算机报警的蜂鸣声)

public class bee
{
public static void main(String[] args)
	{
		java.awt.Toolkit.getDefaultToolkit().beep();
	}
}

反编译

...
major version: 52
...
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=1
0: invokestatic  #2                  // Method java/awt/Toolkit.getDefaultToolkit:()Ljava/awt/Toolkit;
3: invokevirtual #3                  // Method java/awt/Toolkit.beep:()V
6: return
LineNumberTable:
line 5: 0
line 6: 6

invokestatic  #2 调用java.awt.Toolkit.getDefaultToolkit()方法并将返回结果的引用压入栈顶

invokevirtual #3 调用beep()函数,其中需要传引用,把objectref从栈顶弹出传入java/awt/Toolkit

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

时间: 2024-08-30 12:36:17

Java逆向基础之函数的相关文章

java script 基础 之 函数

函数 有一定功能代码体的合集,基本结构: function functionname(){  执行代码 } 基础函数.调用: function hanshu(){   alert"这是第一个函数"  } hanshu():函数调用 分类:带有参数的函数 : function hanshu(a){alert a}  // a是形参,形式参数. hanshu(b)//   b 是实参,实际参数.function hanshu sum(a,b){alert (a+b)} sum(2,3)//

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逆向基础之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/7115 本地变量和操作数栈 本地变量数组(Local Variable Array) 本地变量的数组包括方法执行所需要的所有变量,包括 this 的引用,所有方法参数和其他本地定义的变量.对于那些方法(静态方法 static method)参数是以零开始的,对于实例方法,零为 this 保留. 所有的类型都在本地变量数组中占一个槽(entry),而 long 和 double 会占两个连续的槽,因为它们有双倍宽度(64-bit 而不是 32-bi