大家都知道private變量是無法訪問的,一編譯就報錯根本無法訪問啊。本文教你如何破解這種限制。
實現的原理是利用了Java的反射機制。
首先定義一個最簡單的類,只有一個私有變量和一個公開的方法。代碼如下:
class Foo { private String message = "This is a Foo."; public void show() { System.out.println(message); } }
正常情況下調用show函數會輸出“This is a Foo.”。下面這段代碼通過setAccessible方法繞過了Java的權限檢測。
Class<foo> fooClass = (Class<foo>) foo.getClass(); Field messageField = fooClass.getDeclaredField("message"); messageField.setAccessible(true); // 繞過權限檢測!
setAccessble接受一個布爾類型的參數,true表示繞過Java的權限檢測機制,false表示啟用權限檢測。上面調用了setAccessible(true)因此Java在訪問的時候不會檢測權限。這個方法在調用時需要虛擬機的ReflectPermission("suppressAccessChecks")權限。
為什么要訪問private變量呢?因為有時候在串行化的時候必須要訪問私有變量。
訪問私有的方法也是類似。但是這種代碼不宜使用太多,否則會造成程序混亂,無法維護。
下面是完整的代碼:
import java.lang.reflect.*; public class AccessPrivate { public static void main(String[] argv) throws Exception { // 定義一個測試對象 Foo foo = new Foo(); // 正常情況,測試函數 foo.show(); // 繞過Java權限檢測 Class<foo> fooClass = (Class<foo>) foo.getClass(); Field messageField = fooClass.getDeclaredField("message"); messageField.setAccessible(true); // 繞過權限檢測! System.out.println("Foo is hacked!"); // 修改message變量 messageField.set(foo, "This is a Bar."); // 再次調用測試函數 foo.show(); } } class Foo { private String message = "This is a Foo."; public void show() { System.out.println(message); } }
另外,還有一種方法,就是通過編寫native庫進行訪問,因為native中所有的訪問都不需要權限檢測。