安卓9.0loadLibrary源码分析
本帖最后由 白云点缀的蓝 于 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”),即可,
>
> ```c
> 193void* (*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 the handle returned from loadLibrary
> 200// shorty short descriptor of native method
> 201// len length of shorty
> 202// Returns:
> 203// address of trampoline if successful, otherwise NULL
> ```
> 源码跟踪示例
> 
>
> 
> 点进去可以看到如下函数声明,这里只有声明
> 因此还需继续搜索,
>
> ```c
>void* (*loadLibrary)(const char* libpath, int flag);
> ```
> 可以试试搜索 void* loadLibrary这个函数
> 如下是搜索这个函数找到的结果
> 
>
> ```c
> 30void *loadLibrary(const char *(&names), const char *mustContainSymbol = nullptr)
> 31{
> 32 for(int i = 0; i < n; i++)
> 33 {
> 34 void *library = getLibraryHandle(names);
> 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);
> 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文件
>
> ```c
> void *library = getLibraryHandle(names);
> ```
> 如下是此函数getLibraryHandle的声明
>
> ```c
> 24void *getLibraryHandle(const char *path);
> ```
> 下面是关键代码
>
> ```c
> 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
> ```
> 继续搜寻,发现该函数的实现
>
> ```c
> 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文件,并且返回了文件句柄
>
> ```c
> return dlopen(path, RTLD_NOW | RTLD_LOCAL);
> ```
> 继续跟踪dlopen函数
>
> 
> 如下是dlopen函数的实现
>
> ```c
> void *dlopen(char *filename, int flags)
> ```
> ```c
> 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;
> 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函数的参数,
> 如下代码在对比文件名字
>
> ```c
> 80 if (strnicmp(tmp->name, filename, 999) == 0)
> 81 break;
> ```
> 继续跟踪
> 这里关键代码为
>
> ```c
> 88 tmp->name = strdup(filename);
> ```
> ```c
> 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
> ```
> 函数声明如下
>
> ```c
> char *strdup(const char *str)
> ```
> 该函数?在复制字符串,
> 如下函数把字符串赋值给了tmp空间里面的name参数,
>
> ```c
> 88 tmp->name = strdup(filename);
> ```
> 下面是dlopen代码的最终结束段。
>
> ```c
> 105 return tmp->id;
> ```
> ```c
> 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;
> ```
> 此函数返回了句柄
>
> ```c
>DosLoadModule((PSZ)&err, sizeof(err), filename, &hm)
> ```
> 到此分析完毕,
> 有了句柄就能调用里面的函数了。
谢谢分享
页:
[1]