调用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));
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Android ,C++ 代码可以被编译成共享库(.so 文件),然后通过 Java 代码调用。以下是一些简单的步骤: 1. 在 C++ 编写代码,将其编译成共享库文件(.so 文件)。 2. 将共享库文件放置在 Android 项目的“jniLibs”文件夹。 3. 在 Java 代码使用 System.loadLibrary() 方法加载共享库文件。 4. 在 Java 声明 native 方法,并使用 JNI 接口与 C++ 代码进行通信。 下面是一个示例: 首先,在 C++ 编写一个简单的函数: ```c++ #include <jni.h> extern "C" JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_helloFromCpp(JNIEnv *env, jobject /* this */) { return env->NewStringUTF("Hello from C++"); } ``` 然后将其编译成共享库文件,例如 “libhello.so”。 接下来,在 Android Studio 项目创建一个“jniLibs”目录,并将共享库文件放置在该目录。 最后,在 Java 代码声明 native 方法并加载共享库文件: ```java public class MainActivity extends AppCompatActivity { static { System.loadLibrary("hello"); } public native String helloFromCpp(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String hello = helloFromCpp(); Log.d("MainActivity", hello); } } ``` 这里我们通过 System.loadLibrary() 方法加载共享库文件,并在 MainActivity 类声明了一个 native 方法 helloFromCpp(),该方法会调用我们在 C++ 编写的函数。 注意:在使用 JNI 接口与 C++ 代码进行通信时,需要注意数据类型的匹配,并且需要进行内存管理。具体的使用方法可以参考 JNI 的文档和示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值