【Android 逆向】Android 进程注入工具开发 ( 远程进程注入动态库文件操作 | 注入动态库 加载 业务动态库 | 业务动态库启动 | pthread_create 线程开发 )
文章目錄
- 前言
- 一、加載 libnattive.so 動態庫
- 二、 libnattive.so 動態庫啟動
- 三、 pthread_create 線程開發
- 四、 線程執行函數
前言
libbridge.so 動態庫是 注入工具 使用 ptrace 函數強行向遠程進程 注入的 動態庫 , 這種方法侵入性極大 , 會破壞遠程進程的運行環境 , 因此該動態庫越簡潔越好 ;
注入動態庫 就執行一個操作 , 就是加載 包含真正的逆向業務邏輯的 libnattive.so 動態庫 , 然后啟動該動態庫即可 , 執行完畢后 , 馬上在遠程進程中銷毀注入的 libbridge.so 動態庫 ;
一、加載 libnattive.so 動態庫
通過 注入工具 , 將 libbridge.so 注入到遠程進程 后 , 遠程進程中 , 會 為 libbridge.so 動態庫分配一塊內存 , 并將其運行起來 ;
libbridge.so 動態庫的主要操作是 加載 libnattive.so 動態庫 , 并執行該動態庫的 invoke 方法 ;
libbridge.so 動態庫對應的 bridge.c 源碼如下 :
#include <unistd.h> #include <jni.h> #include <dlfcn.h>#include <android/log.h> #define LOG_TAG "DongNao" #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))/* 主要任務是加載 /data/system/debug/libnative.so 動態庫 , 加載完成后調用動態庫的 invoke 方法 */ int load() {LOGW("%s(%d):%s\n", __FILE__, __LINE__, __FUNCTION__);void* handle = dlopen("/data/system/debug/libnative.so", RTLD_GLOBAL);LOGW("%s(%d):%s handle=%p\n", __FILE__, __LINE__, __FUNCTION__, handle);/* 獲取啟動函數 invoke 的地址 */void* invoke = dlsym(handle, "invoke");LOGW("%s(%d):%s invoke=%p\n", __FILE__, __LINE__, __FUNCTION__, invoke);/* 調用 invoke 啟動函數 */((void(*)())invoke)();return 0; }二、 libnattive.so 動態庫啟動
在 libnattive.so 動態庫中 , 不能長時間維持 , 因為 注入工具 還要 獲取到遠程進程的控制權 , 退出 ptrace 函數調試狀態 , detach 解除注入工具對遠程進行的附著操作 , 之后 令遠程進程正常運行 , 才能開始針對遠程進行的調試 ;
因此在 libnattive.so 動態庫的 invoke 方法中 , 不能執行循環操作 , 該方法最好能立即返回 ;
在 libnattive.so 動態庫的 invoke 方法中 , 開啟了一個線程 , 該線程不斷地進行循環 , 并且每次循環都獲取一次 調試工具 發送過來的指令 , 根據執行執行相應操作 , 如修改內存 , 查找內存等操作 ;
/* 開啟了一個線程 , 立刻返回 , 返回后注入工具會獲得遠程進程控制權 */void invoke(/*const char* args*/){LOGW("native::invoke called!\n");/* 開啟線程執行后續操作 */pthread_t tid_t;int ret = pthread_create(&tid_t, NULL, (pthread_func)thread_entry, NULL/*(void*)args*/);if (ret != 0) {LOGW("thread create failed!\n");return;}}在 Linux C 中 , 啟動線程很簡單 , 準備一個線程函數 , 然后調用 pthread_create 系統接口 , 即可啟動一個線程 , 線程中執行 線程函數 ;
三、 pthread_create 線程開發
關于 Linux C 中線程開發 , 參考 【Android NDK 開發】JNI 線程 ( JNI 線程創建 | 線程執行函數 | 非 JNI 方法獲取 JNIEnv 與 Java 對象 | 線程獲取 JNIEnv | 全局變量設置 ) 博客 ;
線程創建方法函數原型 :
int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, (void*)(*start_rtn)(void*), void *arg)`;pthread_create 方法的 4 個參數 ;
- 參數 1 ( pthread_t *tidp ) : 線程標識符指針 , 該指針指向線程標識符 ;
- 參數 2 ( const pthread_attr_t *attr ) : 線程屬性指針 ;
- 參數 3 ( (void*)(*start_rtn)(void*) ) : 線程運行函數指針 , start_rtn 是一個函數指針 , 其參數和返回值類型是 void* 類型 ;
- 參數 4 ( void *arg ) : 參數 3 中的線程運行函數的參數 ;
pthread_create 方法返回值說明 :
- 線程創建成功 , 返回 0 ;
- 線程創建失敗 , 返回 錯誤代碼 ;
四、 線程執行函數
下面是線程中執行的線程函數 , 該函數中進行了無限循環 , 每隔 333 毫秒循環一次 ;
調試工具 將指令寫出到 /data/system/debug/command.json 文件中 , 線程函數每次循環讀取該文件 , 查詢是否有新的指令到達 , 如果有新的指令 , 則執行該指令 , 如果沒有 , 則執行下一次循環 ;
該線程函數開啟后 , 基本 無法終止 , 也沒有必要終止 ;
void* thread_entry(const char*args) {const size_t nsize = 64 * 1024;char* data = new char[nsize];LOGW("native start!\n");while (true) {usleep(1000 * 333);//333ms檢測一次文件//FILE* pFile = fopen(args, "r");FILE* pFile = fopen("/data/system/debug/command.json", "r");if (pFile != NULL) {memset(data, 0, nsize);fread(data, nsize, 1, pFile);fclose(pFile);try {deal_command(data);}catch (std::exception& e) {LOGW("execute command error!%s\n", e.what());}}else {LOGW("read failed!\n");}}delete[]data;}總結
以上是生活随笔為你收集整理的【Android 逆向】Android 进程注入工具开发 ( 远程进程注入动态库文件操作 | 注入动态库 加载 业务动态库 | 业务动态库启动 | pthread_create 线程开发 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 逆向】Android
- 下一篇: 【Android 逆向】Android