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; }