近年来,安卓应用加固语法“结实”,加密函数又期初的jar层转向jni,使用IDA等工具将so反编译为arm汇编,再者以OLLVM混淆so机制越发普遍,反写算法已经是一项耗时耗力的事情。本文介绍一种构建loader直接调用so函数。
一、定义Jni参数
JavaVM* vm;
JNIEnv* env;
jint res;
JavaVMInitArgs vm_args;
JavaVMOption options[1];
options[0].optionString = "-Djava.class.path=.";
vm_args.version=0x00010002;
vm_args.options=options;
vm_args.nOptions =1;
vm_args.ignoreUnrecognized=JNI_TRUE;
二、加载so并获取函数地址
printf("[+] dlopen libdvm.so\n");
void *handle = dlopen("/system/lib/libdvm.so", RTLD_LAZY);//RTLD_LAZY RTLD_NOW
if(!handle){
printf("[-] dlopen libdvm.so failed!!\n");
return 0;
}
typedef int (*JNI_CreateJavaVM_Type)(JavaVM**, JNIEnv**, void*);
JNI_CreateJavaVM_Type JNI_CreateJavaVM_Func = (JNI_CreateJavaVM_Type)dlsym(handle, "JNI_CreateJavaVM");
if(!JNI_CreateJavaVM_Func){
printf("[-] dlsym failed\n");
return 0;
}
res=JNI_CreateJavaVM_Func(&vm,&env,&vm_args);
dlopen("dependence1.so",RTLD_LAZY);//直接加载依赖so
dlopen("dependence2.so",RTLD_LAZY);
soinfo* si= (soinfo *)dlopen("main.so",RTLD_LAZY);
if(si == NULL)
{
printf("dlopen err!\n");
return 0;
}
三、调用相应地址函数
typedef char* (*FUN1)(char* plain);
//void *addr=(void*)(*(int*)((size_t)si+0x8c)+your_address);
void *addr=(void*)(si->base+your_address);
printf("%x\n",(size_t)si);
printf("%x\n",si->base);
FUN1 func=(FUN1)addr;
if(func==NULL)
{
printf("can't find func\n");
return 0;
}
char *plain="your_param"
char* ret=func(plain);
printf("%s\n",ret);
开源:代码