调用so中的函数

背景

c++层,有时候提供的第三方so接口不满足需求,需要自定义调用so中的函数,大致分为:

  1. 调用未导出函数
  2. 调用导出函数

基础

获取so基地址

  1. 通过maps文件获取
/**
*	获取so文件基地址
*   @param pid:pid module_name:soName
*   @return 地址
*   @invoke get_module_base(getpid(),"libtest.so")
**/
unsigned long get_module_base( pid_t pid, const char* module_name )
{
    FILE *fp;
    unsigned long addr = 0;
    char *pch;
    char filename[32];
    char line[1024];

    if ( pid < 0 )
    {
        /* self process */
        snprintf( filename, sizeof(filename), "/proc/self/maps", pid );
    }
    else
    {
        snprintf( filename, sizeof(filename), "/proc/%d/maps", pid );
    }

    fp = fopen( filename, "r" );

    if ( fp != NULL )
    {
        while ( fgets( line, sizeof(line), fp ) )
        {
            if ( strstr( line, module_name ) )
            {
                pch = strtok( line, "-" );
                addr = strtoul( pch, NULL, 16 );
                break;
            }
        }
        fclose( fp ) ;
    }
    return addr;
}
  1. 通过获取so中某个导出函数,然后减去其偏移地址获取

unsigned long get_module_base_by_fun(char* soPath,char* funName){
	auto handler = dlopen(soPath,RTLD_LAZY);
	auto fun_addr = dlsym(handler,funName);
	// 注意地址的 +1 -1
	// 0xAAAA为传进来funName在so中的偏移地址
	auto base = (unsigned long)fun_addr - 0xAAAA ;
	return base;
}

调用未导出函数

// 0xE9E78为init函数的偏移地址,注意+1-1
auto init = (unsigned long) base + 0xE9E78 + 1;

/**方式一**/

// 获取函数地址指针
auto init_sym = (int (*)(char *, char *, int)) init;
//调用函数
int result = init_sym(p1, p2, 0);

/**方式二**/

// 获取函数地址指针
auto init_sym = reinterpret_cast<int (*)(char*,char*,int)>(init);
//调用函数
int result = reinterpret_cast<int>((*init_sym)(p1, p2, 0));

调用导出函数

// 地址获取
auto recognize = reinterpret_cast<int (*)(JNIEnv*,jclass,jobject)>(dlsym(handler,"nativeRecognize"));

// 函数调用
auto imgdata = reinterpret_cast<jbyteArray>((*recognize)(env, clazz, bitmap));

你可能感兴趣的:(移动安全)