load 与 loadLibrary

本文对比分析了JNI中System.load与System.loadLibrary两种方法的区别,包括加载路径的不同及是否自动加载依赖库。前者直接从文件系统加载指定路径的库文件,后者从java.library.path加载并能自动处理依赖关系。

JNI 使用 Native 库时 一般用load 与 loadLibrary 两个方法,它们的区别主要如下分析。
加载的路径不同:System.load(String filename) 是从作为动态库的本地文件系统中以指定的文件名加载代码文件,文件名参数必须是完整的路径名且带文件后缀;而 System.loadLibrary(String libname) 是加载由 libname 参数指定的系统库(系统库指的是 java.library.path,可以通过 System.getProperty(String key) 方法查看 java.library.path 指向的目录内容),将库名映射到实际系统库的方法取决于系统实现,譬如在 Android 平台系统会自动去系统目录、应用 lib 目录下去找 libname 参数拼接了 lib 前缀的库文件。
是否自动加载库的依赖库:譬如 libA.so 和 libB.so 有依赖关系,如果选择 System.load("/sdcard/path/libA.so"),即使 libB.so 也放在 /sdcard/path/ 路径下,load 方法还是会因为找不到依赖的 libB.so 文件而失败,因为虚拟机在载入 libA.so 的时候发现它依赖于 libB.so,那么会先去 java.library.path 下载入 libB.so,而 libB.so 并不位于 java.library.path 下,所以会报错。
解决的方案就是先 System.load("/sdcard/path/libB.so") 再 System.load("/sdcard/path/libA.so"),但是这种方式不太靠谱,因为必须明确知道依赖关系;另一种解决方案就是使用 System.loadLibrary(“A”),然后把 libA.so 和 libB.so 都放在 java.library.path 下即可。

### 实现或使用 Hook LoadLibrary Windows API 的方法 在 Windows 系统中,`LoadLibrary` 是一个用于加载动态链接库(DLL)的核心 API。通过 Hook `LoadLibrary`,可以拦截并控制 DLL 的加载过程,从而实现对特定行为的监控、修改或增强。以下是实现或使用 Hook `LoadLibrary` 的具体方法: #### 1. 使用 Deviare2 框架实现 Hook Deviare2 是一种强大的工具,可用于 Hook Windows API[^1]。以下是一个基本的实现步骤: - 创建一个 Hook 对象,并指定目标函数为 `LoadLibrary`。 - 注册回调函数以处理被拦截的调用。 - 在回调函数中,可以根据需要修改参数或记录调用信息。 ```python from deviare2 import * def on_load_library(args): print(f"LoadLibrary called with argument: {args[0].value}") return args.call_info.default_return_value hook = Hook("kernel32.dll", "LoadLibraryA") hook.hook() hook.add_event(on_load_library) ``` #### 2. 使用全局 API Hook 技术 全局 API Hook 可以在操作系统级别拦截 `LoadLibrary` 调用[^2]。这种方法通常涉及以下步骤: - 编写一个代理函数来替换原始的 `LoadLibrary` 函数。 - 将代理函数注入到目标进程中。 - 修改目标进程的导入表(Import Address Table, IAT),使其指向代理函数。 ```cpp typedef HMODULE (WINAPI *PLoadLibrary)(LPCSTR); HMODULE WINAPI MyLoadLibrary(LPCSTR lpLibFileName) { static PLoadLibrary originalLoadLibrary = nullptr; if (!originalLoadLibrary) { originalLoadLibrary = (PLoadLibrary)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); } printf("LoadLibrary called with: %s\n", lpLibFileName); return originalLoadLibrary(lpLibFileName); } ``` #### 3. 使用代码注入技术 为了拦截目标进程中的 `LoadLibrary` 调用,通常需要将自定义代码注入到目标进程中[^3]。这可以通过以下方式实现: - 使用 `CreateRemoteThread` 或 `NtQueueApcThread` 向目标进程注入 DLL。 - 在注入的 DLL 中重写 `LoadLibrary` 的行为。 ```cpp BOOL InjectDLL(HANDLE hProcess, const char* dllPath) { SIZE_T bytesWritten = 0; LPVOID remoteString = VirtualAllocEx(hProcess, NULL, strlen(dllPath) + 1, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(hProcess, remoteString, (void*)dllPath, strlen(dllPath) + 1, &bytesWritten); HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA, remoteString, 0, NULL); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); VirtualFreeEx(hProcess, remoteString, 0, MEM_RELEASE); return TRUE; } ``` #### 4. 恢复原始 API 行为 在完成 Hook 操作后,可能需要恢复原始的 `LoadLibrary` 行为[^4]。这通常涉及以下步骤: - 使用 `VirtualProtectEx` 修改内存保护属性。 - 使用 `WriteProcessMemory` 恢复原始函数的字节码。 ```cpp DWORD oldProtect = 0; BYTE originalCode[5] = { /* 原始字节码 */ }; VirtualProtectEx(hProcess, pfOldLoadLibrary, 5, PAGE_READWRITE, &oldProtect); WriteProcessMemory(hProcess, pfOldLoadLibrary, originalCode, 5, NULL); VirtualProtectEx(hProcess, pfOldLoadLibrary, 5, oldProtect, NULL); ``` #### 5. Java 实现 Hook LoadLibrary 虽然 Java 并不直接支持 Hook Windows API,但可以通过 JNI(Java Native Interface)调用本地代码来实现类似功能[^5]。例如,可以编写一个 C++ 库来 Hook `LoadLibrary`,然后通过 JNI 在 Java 中调用该库。 ```java public class LoadLibraryHook { static { System.loadLibrary("native_hook_lib"); } public native void hookLoadLibrary(); public static void main(String[] args) { new LoadLibraryHook().hookLoadLibrary(); } } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值