---
# System prepended metadata

title: Tìm hiểu  về Java Reflection
tags: [java, java101]

---

# Java Reflection 


## **1. Khái niệm Java Reflection**
- Java Reflection là một tính năng cho phép truy cập và thao tác với thông tin của các đối tượng (tên class, field, method) trong thời gian chạy (runtime).
- Có thể chỉnh sửa các field, kể cả những field private.
- Ứng dụng trong bảo mật: Bypass filter/sandbox, thay đổi giá trị field trong gadget chain của lỗ hổng Java Deserialization.




## **2. Bypass Filter sử dụng Reflection**
**Ví dụ:** Khi `Runtime.getRuntime().exec("command")` bị filter, có thể dùng Reflection để bypass. Ví dụ trong đoạn code sau:

```java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println("Hello world!");
        try {
            //Process process = Runtime.getRuntime().exec("whoami");
            Process process = (Process) String.class.getClass()
                    .forName("java.l" + "ang.Ru" + "ntime")
                    .getMethod("ex" + "ec", String.class)
                    .invoke(
                            String.class.getClass()
                                    .forName("java.l" + "ang.Ru" + "ntime")
                                    .getMethod("getRu" + "ntime")
                                    .invoke(
                                            String.class.getClass()
                                                    .forName("java.l" + "ang.Ru" + "ntime"))
                            ,"whoami");
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine())!= null) {
                System.out.println(line);
            }
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
```

Kết quả:

![image](https://hackmd.io/_uploads/ry3MEPPvxg.png)

Các Reflection APi xuất hiện trong đoạn code trên:
- **`Object.getClass()`**: Lấy Class object từ một instance.
- **`Class.forName("className")`:** Lấy Class object từ tên class.  
- **`getMethod("methodName", parameterTypes)`:** Lấy method cụ thể.  
- **`Method.invoke(obj, args)`:** Gọi method trên đối tượng.  





**Các bước thực hiện Bypass:**
1. **Tìm Entry Point (`java.lang.Class`)**: Mọi thao tác của Reflection API đều bắt đầu từ đối tượng `java.lang.Class`. 
    Ta có thể lấy đối tượng này từ bất kỳ class hoặc đối tượng nào có sẵn. Cách làm phổ biến và khó bị filter là sử dụng một chuỗi ký tự bất kỳ, ví dụ: 

    `String.class.getClass()` hoặc `"a".getClass().getClass()`. Thao tác này sẽ trả về đối tượng của chính class `java.lang.Class`. 


2. **Lấy đối tượng Class `java.lang.Runtime`**:

    Khi đã có entry point, ta dùng method `forName(<tên-class>)`. 
    Vì forName nhận tham số là một chuỗi, ta có thể tạo chuỗi `"java.lang.Runtime"` bằng nhiều cách khác nhau để né bộ filter (ví dụ: nối chuỗi, decode base64...).

    Payload ví dụ: 

      `String.class.getClass().forName("java.l" + "ang.Ru" + "ntime")` sẽ trả về đối tượng class `Runtime`. 

3. **Lấy đối tượng Method `getRuntime` và `exec`**:

    Sử dụng `getMethod(<tên-method>, <kiểu-tham-số>)` để lấy một method cụ thể từ một class. 

    Ví dụ, để lấy method `exec(String)` từ class `Runtime`:
`String.class.getClass().forName("java.l" + "ang.Ru" + "ntime").getMethod("ex"+"ec", String.class)`

    Việc chỉ định `String.class` là cần thiết để phân biệt với các method exec khác có tham số khác (nếu có). 

4. **Thực thi Method bằng `invoke()`**:

    Method `invoke(Object obj, Object[] args)` được dùng để gọi một method đã được lấy ra. 

    - obj: Đối tượng mà method sẽ được gọi trên đó.
    - args: Mảng các tham số truyền vào method.

    Để thực thi `exec("whoami")`, chúng ta cần gọi nó trên một instance của Runtime. Payload hoàn chỉnh sẽ tương đương với:


    `exec.invoke(Runtime.getRuntime(), "whoami")`
    Tương đương với
    `String.class.getClass().forName("java.l" + "ang.Ru" + "ntime").getMethod("ex"+"ec", String.class).invoke(Runtime.getRuntime(), "whoami")`

    Vì chúng ta giả sử rằng`"Runtime"` và `"exec"` bị filter nên một lần nữa sử dụng Java Reflection để tạo `getRuntime()` từ `Runtime`

    `exec.invoke(Runtime.getRuntime(), "whoami")`
    Sẽ trở thành
    `exec.invoke(String.class.getClass().forName("java.l" + "ang.Ru" + "ntime").getMethod("getRu" + "ntime").invoke( String.class.getClass().forName("java.l" + "ang.Ru" + "ntime")), "whoami")`
    Tương đương với:
    `String.class.getClass().forName("java.l" + "ang.Ru" + "ntime").getMethod("ex"+"ec", String.class).invoke(String.class.getClass().forName("java.l" + "ang.Ru" + "ntime").getMethod("getRu" + "ntime").invoke( String.class.getClass().forName("java.l" + "ang.Ru" + "ntime")), "whoami")`
    
    Format lại cho dễ nhìn:
    
    ```java
    String.class.getClass()
        .forName("java.l" + "ang.Ru" + "ntime")
        .getMethod("ex" + "ec", String.class)
        .invoke(
            String.class.getClass()
                .forName("java.l" + "ang.Ru" + "ntime")
                .getMethod("getRu" + "ntime")
                .invoke(
                    String.class.getClass()
                        .forName("java.l" + "ang.Ru" + "ntime"))
            ,"whoami");
    ```


## 3. Reflection API - Các Method Introspection Chính

### Class Methods
| Method Name | Description |
|-------------|-------------|
| `Class.forName(String)` | Lấy `Class object` từ `fully qualified class name`. |
| `Object.getClass()` | Lấy `Class object` từ một `instance`. |
| `Class.getSimpleName()` | Lấy `simple name` của `class` (không bao gồm package). |
| `Class.getName()` | Lấy `fully qualified name` của `class`. |
| `Class.getCanonicalName()` | Lấy `canonical name` của `class`. |
| `Class.getModifiers()` | Lấy các `modifier` dưới dạng một `integer` (public, private, static, final, v.v.). |
| `Class.getPackage()` | Lấy thông tin `Package object` chứa `class` này. |
| `Class.getSuperclass()` | Lấy `Class object` của `superclass` (lớp cha trực tiếp). |
| `Class.getInterfaces()` | Lấy mảng các `Class object` của các `interface` mà `class` này implement trực tiếp. |
| `Class.isInterface()` | Kiểm tra xem `class` này có phải là một `interface` hay không. |
| `Class.isEnum()` | Kiểm tra xem `class` này có phải là một `enum` hay không. |
| `Class.isArray()` | Kiểm tra xem `class` này có phải là một `array type` hay không. |

### Field Methods
| Method Name | Description |
|-------------|-------------|
| `Class.getDeclaredFields()` | Lấy tất cả các `Field object` được khai báo trong `class` này (không bao gồm inherited fields). |
| `Class.getFields()` | Lấy tất cả các `public Field object` (bao gồm cả inherited fields). |
| `Class.getDeclaredField(String)` | Lấy `Field object` cụ thể được khai báo trong `class` này theo tên. |
| `Class.getField(String)` | Lấy `public Field object` cụ thể theo tên (bao gồm cả inherited). |
| `Field.getName()` | Lấy tên của `field`. |
| `Field.getType()` | Lấy `Class object` đại diện cho `data type` của `field`. |
| `Field.getModifiers()` | Lấy các `modifier` của `field` dưới dạng `integer`. |
| `Field.get(Object)` | Lấy giá trị của `field` từ một `object instance` cụ thể. |
| `Field.set(Object, Object)` | Thiết lập giá trị của `field` trên một `object instance` cụ thể. |
| `Field.setAccessible(boolean)` | Cho phép hoặc không cho phép bỏ qua `access control check` (truy cập `private field`). |

### Method Methods
| Method Name | Description |
|-------------|-------------|
| `Class.getDeclaredMethods()` | Lấy tất cả các `Method object` được khai báo trong `class` này (không bao gồm inherited methods). |
| `Class.getMethods()` | Lấy tất cả các `public Method object` (bao gồm cả inherited methods). |
| `Class.getDeclaredMethod(String, Class...)` | Lấy `Method object` cụ thể được khai báo trong `class` này theo tên và parameter types. |
| `Class.getMethod(String, Class...)` | Lấy `public Method object` cụ thể theo tên và parameter types (bao gồm cả inherited). |
| `Method.getName()` | Lấy tên của `method`. |
| `Method.getReturnType()` | Lấy `Class object` đại diện cho `return type` của `method`. |
| `Method.getParameterTypes()` | Lấy mảng `Class object` đại diện cho `data type` của các `parameter`. |
| `Method.getParameterCount()` | Lấy số lượng `parameter` của `method`. |
| `Method.getModifiers()` | Lấy các `modifier` của `method` dưới dạng `integer`. |
| `Method.invoke(Object, Object...)` | Gọi `method` trên một `object instance` cụ thể với các `argument` được cung cấp. |
| `Method.setAccessible(boolean)` | Cho phép hoặc không cho phép bỏ qua `access control check` (gọi `private method`). |

### Constructor Methods
| Method Name | Description |
|-------------|-------------|
| `Class.getDeclaredConstructors()` | Lấy tất cả các `Constructor object` được khai báo trong `class` này. |
| `Class.getConstructors()` | Lấy tất cả các `public Constructor object` của `class` này. |
| `Class.getDeclaredConstructor(Class...)` | Lấy `Constructor object` cụ thể theo parameter types. |
| `Class.getConstructor(Class...)` | Lấy `public Constructor object` cụ thể theo parameter types. |
| `Constructor.getParameterTypes()` | Lấy mảng `Class object` đại diện cho `data type` của các `parameter` trong `constructor`. |
| `Constructor.getParameterCount()` | Lấy số lượng `parameter` của `constructor`. |
| `Constructor.newInstance(Object...)` | Tạo một `instance` mới của `class` bằng cách sử dụng `constructor` này với các `argument` được cung cấp. |
| `Constructor.setAccessible(boolean)` | Cho phép hoặc không cho phép bỏ qua `access control check` (gọi `private constructor`). |

### Utility Methods (Modifier Class)
| Method Name | Description |
|-------------|-------------|
| `Modifier.isPublic(int)` | Kiểm tra xem `modifier value` có chứa `public` modifier hay không. |
| `Modifier.isPrivate(int)` | Kiểm tra xem `modifier value` có chứa `private` modifier hay không. |
| `Modifier.isProtected(int)` | Kiểm tra xem `modifier value` có chứa `protected` modifier hay không. |
| `Modifier.isStatic(int)` | Kiểm tra xem `modifier value` có chứa `static` modifier hay không. |
| `Modifier.isFinal(int)` | Kiểm tra xem `modifier value` có chứa `final` modifier hay không. |
| `Modifier.isAbstract(int)` | Kiểm tra xem `modifier value` có chứa `abstract` modifier hay không. |
| `Modifier.toString(int)` | Chuyển đổi `modifier value` thành `String` representation. |

### Deprecated Methods
| Method Name | Description |
|-------------|-------------|
| `Class.newInstance()` | **[DEPRECATED từ Java 9]** Tạo một `instance` mới của `class` sử dụng `default constructor`. Thay thế bằng `Constructor.newInstance()`. |

### Note:
- **Declared methods**: Chỉ lấy các member được khai báo trực tiếp trong class đó (không bao gồm inherited).
- **Non-declared methods**: Lấy các public member bao gồm cả inherited từ superclass và interface.
- **setAccessible(true)**: Cho phép truy cập các private/protected member, nhưng có thể bị hạn chế bởi Security Manager.
- **Modifier values**: Sử dụng bitwise operations, có thể kết hợp nhiều modifier trong một integer.