欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]linux下调用共享库非导出函数

[原创]linux下调用共享库非导出函数

在逆向共享库(.so)时,有时候需要逐一的验证函数的正确性,需要单独调用共享库中的函数(解决该问题,可以更方便的验证逆向结果),对于导出函数,没什么可说,使用dlopen、dlsym等,可以直接调用,那么非导出函数怎么调用呢?
        解决该问题,可以从两方面入手:
        1.修改.so文件中各个函数的属性,把所有函数全部导出
        2.尝试获取到非导出函数在虚拟内存中的地址,使用函数地址调用该函数
        由于.so可能面临加密等问题,我们暂时不讨论第一种方法,本文先介绍第二种方法。导出函数和非导出函数的差别不外乎就是函数的visibility属性,直观上,我们可以获取到库的基址和导出函数的相对地址,这是我们的已知信息。
先做一下准备工作,1.建库---2.获取地址信息
共享库:share


#include <stdio.h>

///print大写的ABCD

 void PrintABCD()//__attribute__((visibility("hidden")))

{

  printf("ABCD\n");

  sleep(-1);

}

///print小写的abcd

__attribute__((visibility("hidden"))) void Printabcd()//

{

  printf("abcd\n");

  sleep(-1);

}

///根据参数来确定print ABCD or abcd

void PrintIt(int isPrintCapital)

{

  if(isPrintCapital)

  {

    PrintABCD();

  }

  else

  {

    Printabcd();

  }

  printf("over!\n");

}


生成共享库 share.so
gl-linux@ubuntu:~/Desktop/AYR$ gcc -fPIC -shared -o share.so share.c
测试代码:test.c

#include <stdio.h>

#include <dlfcn.h>

#include<unistd.h>

#define DLL_FILE_NAME "/home/gl-linux/Desktop/AYR/share.so"

 int main()

 {

    long long addr = 0;

    void (*func)(int);

    void *handle = dlopen(DLL_FILE_NAME, RTLD_NOW);

    if (handle == NULL)

    {

    fprintf(stderr, "Failed to open libaray %s error:%s\n", DLL_FILE_NAME, dlerror());

    return -1;

    }

    addr = (long long)dlsym(handle, "PrintABCD"); 

    printf("%lld ",addr);    

    addr = (long long)dlsym(handle, "Printabcd"); 

    printf("%lld ",addr);

    addr = (long long)dlsym(handle, "PrintIt"); 

    printf("%lld ",addr);

    func = addr;

    func(1);

    dlclose(handle);

    sleep(-1);

    return 0;

 }


gl-linux@ubuntu:~/Desktop/AYR$ gcc test.c -o test -ldl
运行可执行文件
gl-linux@ubuntu:~/Desktop/AYR$ ./test
139725025953621 0 139725025953687 ABCD
可以看到,三个函数的地址中,有一个是0,这个就是内部函数,后者我们称之为非导出函数
查看导出函数偏移:
gl-linux@ubuntu:~/Desktop/AYR$ nm -D share.so
0000000000201048 B __bss_start
                 w __cxa_finalize
0000000000201048 D _edata
0000000000201050 B _end
00000000000007cc T _fini
                 w __gmon_start__
00000000000005e8 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
0000000000000755 T PrintABCD
0000000000000797 T PrintIt

                 U puts
                 U sleep
gl-linux@ubuntu:~/Desktop/
已知导出函数的偏移地址,又知道模块基址,怎么能知道非导出函数的地址呢?
这时候我们需要借助IDA工具查看文件在内存中的情况(二进制指令是不变的)
PrintIt(int)入口地址片段
.text:0000000000000797 ; Attributes: bp-based frame
Printabcd()入口地址片段
.text:0000000000000776 ; Attributes: bp-based frame
PrintABCD()入口地址片段
.text:0000000000000755 ; Attributes: bp-based frame
通过IDA的显示,可以知道:非导出函数Printabcd()和导出函数PrintIt(int)地址偏移33,139725025953687 - 33即是非导出函数Printabcd()的虚拟地址,修改测试程序如下:
使用计算后的地址调用非导出函数Printabcd()

#include <stdio.h>

#include <dlfcn.h>

#include<unistd.h>

#define DLL_FILE_NAME "/home/gl-linux/Desktop/AYR/share.so"

 int main()

 {

    long long addr = 0;

    void (*func)();

    void *handle = dlopen(DLL_FILE_NAME, RTLD_NOW);

    if (handle == NULL)

    {

    fprintf(stderr, "Failed to open libaray %s error:%s\n", DLL_FILE_NAME, dlerror());

    return -1;

    }

    addr = (long long)dlsym(handle, "PrintABCD"); 

    printf("%lld ",addr);    

    addr = (long long)dlsym(handle, "Printabcd"); 

    printf("%lld ",addr);

    addr = (long long)dlsym(handle, "PrintIt"); 

    printf("%lld ",addr);

    func = addr-33;

    func();

    dlclose(handle);

    sleep(-1);

    return 0;

 }


运行结果:
gl-linux@ubuntu:~/Desktop/AYR$ ./TEST
139670664996693 0 139670664996759 abcd

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功