byOpen是一個繞過移動端系統限制的加強版dlfunctions庫。java
支持App中加載和使用Android系統庫接口(即便maps中尚未被加載也支持)。android
Android 7以上dlopen, System.load都是被限制調用的,雖然目前網上有Nougat_dlfunctions等庫經過從maps中找so庫來繞過加載限制。ios
不過對於app中還沒被加載到maps的so庫,這種方式就不行了。git
而byOpen不只支持fake dlopen方式從maps加載,還能夠將還沒加載到maps的so庫繞過系統限制強行加載進來使用,實現更加通用化得dlopen。github
注:目前的實現方式理論上仍是比較通用的,至少我這Android 10上測試ok,但還沒完整詳細測試過,是否使用請自行評估。api
具體實現原理仍是比較簡單的,主要仍是借鑑了一種繞過Android P對非SDK接口限制的簡單方法的思想和實現方式。安全
雖然這篇文章中主要目的是爲了繞過hide api,不過它裏面使用的將本身僞裝成系統調用的方式,同樣能夠用到System.loadLibrary
上去,讓系統覺得是系統自身在調用System.loadLibrary
app
從而繞過Android N的classloader-namespace限制,將系統/system/lib中任意so庫加載到maps中,而後再經過fake dlopen的方式去dlsym。curl
關於fake dlopen的方式實現,網上已有不少實現,好比:iphone
byOpen參考了裏面的實現,從新實現了一遍,而且作了一些小改進:
Android相關測試App例子在:Android Sample
注:目前自帶的App測試例子裏面的系統庫我寫死了,有些系統版本上有可能不存在,請先改爲用戶本身的庫和符號名,再編譯測試
public class MainActivity extends AppCompatActivity { private static final String SYSTEM_LIBRARY = "curl"; private static final String SYMBOL_NAME = "curl_version";
除了Native版本dlopen接口,byOpen額外提供了java版本的System.loadLibrary接口在java層直接繞過系統庫加載。
關鍵代碼以下:
static public boolean loadLibrary(String libraryName) { Method forName = Class.class.getDeclaredMethod("forName", String.class); Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class); Class<?> systemClass = (Class<?>) forName.invoke(null, "java.lang.System"); Method loadLibrary = (Method) getDeclaredMethod.invoke(systemClass, "loadLibrary", new Class[]{String.class}); loadLibrary.invoke(systemClass, libraryName); }
而native版本的dlopen_android.c實現中,我將這段繞過的系統加載的方式,經過jni從新實現了一遍,而後和fake dlopen無縫結合到了一塊兒。
雖然ios能夠直接使用dlopen,可是審覈上會有風險,蘋果有可能會對提交AppStore的app掃描相關dlopen/dlsym等調用,來判斷是否存在一些敏感的私有調用。
爲了在經過調用一些私有接口的時候避免被蘋果檢測到,byOpen也經過本身實現dlopen/dlsym直接從已經加載進來的images列表裏面直接查找對應symbol地址來調用。
固然,爲了更加安全,相關調用的庫符號硬編碼字符串等,用戶能夠自行作層變換加密,不要直接編譯進app。
相關靜態庫和接口在:dlopen.h
相關使用方式跟原生dlopen徹底相同:
typedef by_char_t const* (*curl_version_t)(); by_pointer_t handle = by_dlopen("libcurl.so", BY_RTLD_LAZY); if (handle) { by_pointer_t addr = by_dlsym(handle, "curl_version"); if (addr) { curl_version_t curl_version = (curl_version_t)addr; by_print("curl_version: %s", curl_version()); } by_dlclose(handle); }
編譯須要先安裝:xmake
$ xmake f -p android --ndk=~/file/android-ndk-r20b $ xmake
$ cd src/android $ ./gradlew app:assembleDebug
$ xmake apk_build
$ xmake apk_test
$ xmake f -p iphoneos -a [armv7|arm64] $ xmake
咱們也能夠在macOS下編譯測試,也是支持的:
$ xmake $ xmake run