0x0 創建工程html
配置好NDK環境後,直接使用ndk-build來快速生成原生程序。其中mk的配置以下linux
// BUILD_EXECUTABLE表示生成可執行文件(無後綴)shell
// BUILD_SHARED_LIBRARY生成動態庫.so文件數組
// BUILD_STATIC_LIBRARY生成靜態庫.a文件架構
2. 創建openso.c(注意跟mk裏面命名一致)函數
記錄幾個比較容易錯的地方,ui
好比spa
這裏爲RC4流密碼指針
這裏的char v4;code
__gnu_Unwind_2((int)&v1, 10, (int)&v4);
假如也像IDA這樣用,假如真的是訪問(&v4)這個地址的一個字節,是沒問題的(但也沒有初始化),可是這裏並非只訪問一個字節的內容,還會訪問接下來的內容,且會對接下來的內存作改變。這樣寫代碼多半會引起Segmentation fault,有關這個錯誤,更多可訪問Segmentation Fault in Linux。
因此須要本身分配內存,char * v4 = (char *)malloc(0x102);將&v4替換爲v4;
大端模式是指高字節數據MSB存放在低地址處,低字節數據放在高地址處。
小端模式是指低字節數據LSB存放在低地址處,高字節數據放在高地址處。
這裏的key保存爲
v1 = 0x89884546; [sp+4h]
v2 = 0x87879998; [sp+8h]
v3 = 0x8765u; [sp+Ch] //v3的地址最高
那麼寫程序時key以小端形式保存,就須要變爲
unsigned char key[] = { 0x46,0x45,0x88,0x89,0x98,0x99,0x87,0x87,0x65,0x87 };
//數組入棧,從右往左壓
具體這方面的知識參考,函數調用方式,CPU中的字節序
void * dlsym(void * handle,char * symbol)
若查找的符號是個函數,那麼就返回函數的地址;
如果個變量,它返回變量的地址;
若是這個符號是個常量,那麼它返回的是該常量的值。
在IDA中須要看Exports表,纔是真實的符號
也能夠經過在linux環境下,objdump -T myELFfile 來查看符號表
這個彷佛是沒有導出符號的,具體緣由暫時不知道,可是咱們能夠經過有符號的函數與它的偏移量來調用它
好比: .text : 00001234 exportfunc
而sub_1818爲: .text :00001818 sub_1818
sub_1818 = exportfunc + 0x5E4
(大體就是這個意思)
3. ndk-build
4. 代碼
a) 方案一 是運行解密函數,還須要本身找祕鑰
b) 方案二 運行函數後,直接dump內存就行
方案1:
#include<stdio.h> #include<stdlib.h> #include<dlfcn.h> int main() { void *handle; char *error; int (*func2) (int, signed int, int); char * (*func3) (char *, int, int); char *v4 = malloc(0x102); unsigned char key[] = { 0x46,0x45,0x88,0x89,0x98,0x99,0x87,0x87,0x65,0x87 }; handle = dlopen("/data/local/tmp/runso.so", RTLD_LAZY); if ((error = dlerror()) != NULL) { printf("%s",error); printf("open so error!\n"); return -1; } func2 = dlsym(handle, "_Z14__gnu_Unwind_2PhiP5str_1"); if ((error = dlerror()) != NULL) { printf("open func2 error!\n"); return -1; } func2((int)key, 10, (int)v4); char * data = dlsym(handle, "__gnu_Unwind_15"); if ((error = dlerror()) != NULL) { printf("open data error!\n"); return -1; } func3 = dlsym(handle, "_Z14__gnu_Unwind_3PhiP5str_1"); if ((error = dlerror()) != NULL) { printf("open func3 error!\n"); return -1; } func3(data, 0x55BF, (int)v4); FILE * outfile = fopen("/data/local/tmp/out.jar", "wb"); if (outfile != NULL) { fwrite(data, 1, 0x55BF, outfile); } else { printf("can't create file"); return -1; } return 0; }
方案二:
#include<stdio.h> #include<dlfcn.h> int main() { void *handle; char *error; void *(*func)();//創建一個函數指針 void *(*sub_func)(); handle = dlopen("/data/local/tmp/runso.so", RTLD_LAZY); if ((error = dlerror()) != NULL) { printf("%s", error); printf("open so error!\n"); return -1; } func = dlsym(handle, "_Z15__gnu_Unwind_16v");//隨意找了個函數,來定位sub開頭的函數 if ((error = dlerror()) != NULL) { printf("%s", error); printf("open offset func error!\n"); return -1; } int offset = 0x160;//計算出偏移量 sub_func = func - offset; sub_func();//調用sub_1818 char * data = dlsym(handle, "__gnu_Unwind_15"); if ((error = dlerror()) != NULL) { printf("open data error!\n"); return -1; } FILE * outfile = fopen("/data/local/tmp/out.jar", "wb"); if (outfile != NULL) { fwrite(data, 1, 0x55BF, outfile); } else { printf("can't create file"); return -1; } return 0; }