java RASP攻击自免疫技术-初探字节码

2018-8-15 小屿 Java

rasp(Runtime Application self-protection)最近在国内比较流行,百度也开源了一个rasp的项目,相较于传统waf有许多优点,而我园长师傅也在搞这个,园长师傅博客的资料: http://www.p2j.cn/?p=1862


通过hook关键方法或者系统底层方法并解析修改字节码来实现恶意代码防护,所以学习java字节码必不可少,本文只作个人学习记录,对jvm不甚了解,如有错误感谢指正。


一个java程序执行需要从源码编译为class文件,再由虚拟机运行。所谓字节码就是虚拟机的指令形式。想要舒服的阅读字节码可以通过javap命令,例如javap -c xxx.class或者更详细的javap -v xxx.class,我个人觉得idea里面安装jclasslib比较好用。


javap命令下的字节码长这个样子(字节码实际上是一堆以cafebabe开头的遵循特定格式的字节),关于字节码指令可以参考:http://www.blogjava.net/DLevin/archive/2011/09/13/358497.html

bytecode1.png


java虚拟机通过栈保存方法的各种信息,方法调用时为方法创建栈帧,栈顶的栈帧是正在运行的方法,栈帧中又包括局部变量表,操作数栈等。

9.jpg


以一个简单的方法为例

public int test(){
    int i = 1;
    int j = 25;
    return i;
}

字节码:

bt3.png

0 iconst_1 将1压入操作数栈中

1 istore_1 从操作数栈中移到局部变量表,后面的1为索引值

2 bipush 25 将25压入压入操作数栈中,不同数值范围的入栈指令也有一些区别(取值-1~5为iconst,-128~127bipush,-32768~32767sipush,-2147483648~2147483647ldc)

4 istore_2 操作数栈中移到局部变量表,索引值为2

5 iload_1 从局部变量表将索引为1的数值压入操作数栈

6 ireturn 返回int结果


一个执行系统命令的方法为例:

public void test3(){
    try {
        Runtime.getRuntime().exec("whoami");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

字节码:

bc4.png

bc5.png

 0 invokestatic #4 <java/lang/Runtime.getRuntime> 调用静态方法java/lang/Runtime.getRuntime
 3 ldc #5 <whoami> 将whomai压入操作数栈
 5 invokevirtual #6 <java/lang/Runtime.exec> 调用java/lang/Runtime.exec方法并传入whoami
 8 pop 移除操作数栈栈顶的值
 9 goto 17 (+8) 跳到17处(指令前面的数字表示这条指令到方法开始处的偏移值)
12 astore_1
13 aload_1
14 invokevirtual #9 <java/io/IOException.printStackTrace>
17 return 返回空

Exception table是显式异常表,如果偏移值start pc到end pc出现catch type的异常将跳转到handler pc处理。


一个实例化对象的例子:

public void test5(){
    Test test = new Test();
}


字节码:

bc6.png

为什么实例化对象会用到dup指令?实例化对象invokespecial指令调用构造方法会消耗掉操作数栈的顶,构造方法是没有返回值的,当方法有返回值才会压入操作数栈的顶,所以需要用dup指令复制一份。


一个访问成员变量的例子:

public class Test {

    private int i = 1;

    public static void main(String[] args) {
        new Test().sb();
    }

    public void sb() {
        System.out.println(i);
    }
}

sb方法的字节码:

bt.png

第一次用asm取成员变量值的时候出了错误,原因是没有aload_0。刚开始没想明白这里getfield取值前面aload是在干嘛,实际上这里是aload的成员变量,毕竟引用的成员变量不是凭空来的。




未完待续

标签: rasp 字节码

发表评论:

Powered by xia0yu