吾爱汇编

 找回密码
 立即注册

QQ登录

绑定QQ避免忘记帐号

查看: 555|回复: 1

[原创逆向图文] 安卓9.0loadLibrary源码分析

[复制链接]
白云点缀的蓝 发表于 2025-3-28 12:07 | 显示全部楼层 |阅读模式

本帖最后由 白云点缀的蓝 于 2025-3-30 08:35 编辑

安卓源代码来自如下网站 http://androidxref.com/ 在这里插入图片描述 我就选最新的9.0系统分析了Pie - 9.0.0_r3 这里搜索LoadLibrary,右边select all 勾选上 在这里插入图片描述 然后点击Search,可以看到相关当前方法的调用。 在这里插入图片描述 在这之前先说一下LoadLibrary方法的用法 LoadLibrary来自System对象,所以调用时, 需要前面加上System,由于是直接调用的, 因此此对象不需要实例化,直接System.loadlibrary, loadlibrary方法会专门调用apk包中lib文件夹下的so文件, 下面拿一个安卓apk做示范, 在这里插入图片描述 这里我用的是360压缩直接打开的, apk文件结构如下 在这里插入图片描述 继续回到安卓系统源码上,搜索后,一个一个看, 看到类似的函数声明 此函数返回值为万能指针,能存放所有数据类型的空间, 第一个方法数据类型为字符型,是调用LoadLibrary函数的 so文件路径,在调用loadLibrary函数时安卓端省略了路径, 省略了lib前缀,省略了.so后缀,例如libLanAn.so 只需要输入System.loadLibrary(“LanAn”),即可,

193  void* (*loadLibrary)(const char* libpath, int flag);
194
195  // Get a native bridge trampoline for specified native method. The trampoline has same
196  // sigature as the native method.
197  //
198  // Parameters:
199  //   handle [IN] the handle returned from loadLibrary
200  //   shorty [IN] short descriptor of native method
201  //   len [IN] length of shorty
202  // Returns:
203  //   address of trampoline if successful, otherwise NULL

源码跟踪示例 在这里插入图片描述

在这里插入图片描述 点进去可以看到如下函数声明,这里只有声明 因此还需继续搜索,

 void* (*loadLibrary)(const char* libpath, int flag);

可以试试搜索 void* loadLibrary这个函数 如下是搜索这个函数找到的结果 在这里插入图片描述

30void *loadLibrary(const char *(&names)[n], const char *mustContainSymbol = nullptr)
31{
32    for(int i = 0; i < n; i++)
33    {
34        void *library = getLibraryHandle(names[i]);
35
36        if(library)
37        {
38            if(!mustContainSymbol || getProcAddress(library, mustContainSymbol))
39            {
40                return library;
41            }
42
43            freeLibrary(library);
44        }
45    }
46
47    for(int i = 0; i < n; i++)
48    {
49        void *library = loadLibrary(names[i]);
50
51        if(library)
52        {
53            if(!mustContainSymbol || getProcAddress(library, mustContainSymbol))
54            {
55                return library;
56            }
57
58            freeLibrary(library);
59        }
60    }
61
62    return nullptr;
63}

继续跟踪如下代码 代码意思是获取so文件句柄,没有句柄无法操作so文件

void *library = getLibraryHandle(names[i]);

如下是此函数getLibraryHandle的声明

24void *getLibraryHandle(const char *path);

下面是关键代码

65#if defined(_WIN32)
66    inline void *loadLibrary(const char *path)
67    {
68        return (void*)LoadLibrary(path);
69    }
70
71    inline void *getLibraryHandle(const char *path)
72    {
73        HMODULE module = NULL;
74        GetModuleHandleEx(0, path, &module);
75        return (void*)module;
76    }
77
78    inline void freeLibrary(void *library)
79    {
80        FreeLibrary((HMODULE)library);
81    }
82
83    inline void *getProcAddress(void *library, const char *name)
84    {
85        return (void*)GetProcAddress((HMODULE)library, name);
86    }
87#else
88    inline void *loadLibrary(const char *path)
89    {
90        return dlopen(path, RTLD_LAZY | RTLD_LOCAL);
91    }
92
93    inline void *getLibraryHandle(const char *path)
94    {
95        #ifdef __ANDROID__
96            // bionic doesn't support RTLD_NOLOAD before L
97            return dlopen(path, RTLD_NOW | RTLD_LOCAL);
98        #else
99            void *resident = dlopen(path, RTLD_LAZY | RTLD_NOLOAD | RTLD_LOCAL);
100
101           if(resident)
102           {
103               return dlopen(path, RTLD_LAZY | RTLD_LOCAL);   // Increment reference count
104           }
105
106           return nullptr;
107       #endif
108   }
109
110   inline void freeLibrary(void *library)
111   {
112       if(library)
113       {
114           dlclose(library);
115       }
116   }
117
118   inline void *getProcAddress(void *library, const char *name)
119   {
120       void *symbol = dlsym(library, name);
121
122       if(!symbol)
123       {
124           const char *reason = dlerror();   // Silence the error
125           (void)reason;
126       }
127
128       return symbol;
129   }
130#endif

继续搜寻,发现该函数的实现

93    inline void *getLibraryHandle(const char *path)
94    {
95        #ifdef __ANDROID__
96            // bionic doesn't support RTLD_NOLOAD before L
97            return dlopen(path, RTLD_NOW | RTLD_LOCAL);
98        #else
99            void *resident = dlopen(path, RTLD_LAZY | RTLD_NOLOAD | RTLD_LOCAL);
100
101           if(resident)
102           {
103               return dlopen(path, RTLD_LAZY | RTLD_LOCAL);   // Increment reference count
104           }
105
106           return nullptr;
107       #endif
108   }
109

如下代码打开了so文件,并且返回了文件句柄

return dlopen(path, RTLD_NOW | RTLD_LOCAL);

继续跟踪dlopen函数

在这里插入图片描述 如下是dlopen函数的实现

void *dlopen(char *filename, int flags)
70/* load a dynamic-link library and return handle */
71void *dlopen(char *filename, int flags)
72{
73    HMODULE hm;
74    DLLchain tmp;
75    char err[256];
76    char *errtxt;
77    int rc = 0, set_chain = 0;
78
79    for (tmp = dlload; tmp; tmp = tmp->next)
80        if (strnicmp(tmp->name, filename, 999) == 0)
81            break;
82
83    if (!tmp)
84    {
85        tmp = (DLLchain) malloc(sizeof(tDLLchain));
86        if (!tmp)
87            goto nomem;
88        tmp->name = strdup(filename);
89        tmp->next = dlload;
90        set_chain = 1;
91    }
92
93    switch (rc = DosLoadModule((PSZ)&err, sizeof(err), filename, &hm))
94    {
95        case NO_ERROR:
96            tmp->handle = hm;
97            if (set_chain)
98            {
99                do
100                    last_id++;
101                while ((last_id == 0) || (find_id(last_id)));
102                tmp->id = last_id;
103                dlload = tmp;
104            }
105            return tmp->id;
106        case ERROR_FILE_NOT_FOUND:
107        case ERROR_PATH_NOT_FOUND:
108            errtxt = "module `%s' not found";
109            break;
110        case ERROR_TOO_MANY_OPEN_FILES:
111        case ERROR_NOT_ENOUGH_MEMORY:
112        case ERROR_SHARING_BUFFER_EXCEEDED:
113nomem:
114            errtxt = "out of system resources";
115            break;
116        case ERROR_ACCESS_DENIED:
117            errtxt = "access denied";
118            break;
119        case ERROR_BAD_FORMAT:
120        case ERROR_INVALID_SEGMENT_NUMBER:
121        case ERROR_INVALID_ORDINAL:
122        case ERROR_INVALID_MODULETYPE:
123        case ERROR_INVALID_EXE_SIGNATURE:
124        case ERROR_EXE_MARKED_INVALID:
125        case ERROR_ITERATED_DATA_EXCEEDS_64K:
126        case ERROR_INVALID_MINALLOCSIZE:
127        case ERROR_INVALID_SEGDPL:
128        case ERROR_AUTODATASEG_EXCEEDS_64K:
129        case ERROR_RELOCSRC_CHAIN_EXCEEDS_SEGLIMIT:
130            errtxt = "invalid module format";
131            break;
132        case ERROR_INVALID_NAME:
133            errtxt = "filename doesn't match module name";
134            break;
135        case ERROR_SHARING_VIOLATION:
136        case ERROR_LOCK_VIOLATION:
137            errtxt = "sharing violation";
138            break;
139        case ERROR_INIT_ROUTINE_FAILED:
140            errtxt = "module initialization failed";
141            break;
142        default:
143            errtxt = "cause `%s', error code = %d";
144            break;
145    }
146    snprintf(dlerr, sizeof(dlerr), errtxt, &err, rc);
147    if (tmp)
148    {
149        if (tmp->name)
150            free(tmp->name);
151        free(tmp);
152    }
153    return 0;
154}

这里看关键代码 这里选择跟踪函数参数,filename为so的文件名字, 也是dlopen函数的参数, 如下代码在对比文件名字

80        if (strnicmp(tmp->name, filename, 999) == 0)
81            break;

继续跟踪 这里关键代码为

88        tmp->name = strdup(filename);
83    if (!tmp)
84    {
85        tmp = (DLLchain) malloc(sizeof(tDLLchain));
86        if (!tmp)
87            goto nomem;
88        tmp->name = strdup(filename);
89        tmp->next = dlload;
90        set_chain = 1;
91    }
92

函数声明如下

char *strdup(const char *str) 

该函数?在复制字符串, 如下函数把字符串赋值给了tmp空间里面的name参数,

88        tmp->name = strdup(filename);

下面是dlopen代码的最终结束段。

105            return tmp->id;
93    switch (rc = DosLoadModule((PSZ)&err, sizeof(err), filename, &hm))
94    {
95        case NO_ERROR:
96            tmp->handle = hm;
97            if (set_chain)
98            {
99                do
100                    last_id++;
101                while ((last_id == 0) || (find_id(last_id)));
102                tmp->id = last_id;
103                dlload = tmp;
104            }
105            return tmp->id;

此函数返回了句柄

 DosLoadModule((PSZ)&err, sizeof(err), filename, &hm)

到此分析完毕, 有了句柄就能调用里面的函数了。

1.png

评分

参与人数 1HB +2 THX +1 收起 理由
美好映像 + 2 + 1

查看全部评分

吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
学编程的闹钟 发表于 2025-3-29 19:57 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

警告:本站严惩灌水回复,尊重自己从尊重他人开始!

1层
2层

免责声明

吾爱汇编(www.52hb.com)所讨论的技术及相关工具仅限用于研究学习,皆在提高软件产品的安全性,严禁用于不良动机。任何个人、团体、组织不得将其用于非法目的,否则,一切后果自行承担。吾爱汇编不承担任何因为技术滥用所产生的连带责任。吾爱汇编内容源于网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除。如有侵权请邮件或微信与我们联系处理。

站长邮箱:SharkHeng@sina.com
站长QQ:1140549900


QQ|RSS|手机版|小黑屋|帮助|吾爱汇编 ( 京公网安备11011502005403号 , 京ICP备20003498号-6 )|网站地图

Powered by Discuz!

吾爱汇编 www.52hb.com

快速回复 返回顶部 返回列表