本人由于工作与爱好,基于论坛各位前辈的资料以及安卓5.10 linker源码实现了Arm32位的加壳加密, 由于最近7.0源码支持 Arm64,对于soinfo结构体进行了很大的变动,原先通过 void* handle = dlopen("libxxx.so",RTLD_NOW); 将 Loader_soinfo = (soinfo*)(handle), 可以获取到需要获取处理的so库的soinfo信息,并通过该结构体进行替换相关 .nbucket, .nchain, .bucket, .chain, .strtab, .symtab, .load_bias, .base, .size等系统维护的soinfo_list维护的字段,可以实现壳的实现。
由于linker7.0是基于c++14写的,引入了lambda表达式等, 对于结构体soinfo:
struct soinfo {
public:
typedef LinkedList<soinfo, SoinfoListAllocator> soinfo_list_t; // 请问该结构体 占内存空间吗?
typedef LinkedList<android_namespace_t, NamespaceListAllocator> android_namespace_list_t; // 请问该结构体 占内存空间吗?
#if defined(__work_around_b_24465209__)
private:
char old_name_[SOINFO_NAME_LEN]; // 该处为兼容Arm32位版本的 起始偏移地址
...
}
关于 LinkedList的定义大概如下:
template<typename T, typename Allocator>
class LinkedList {
public:
typedef LinkedListIterator<T> iterator;
typedef T* value_type;
LinkedList() : head_(nullptr), tail_(nullptr) {}
~LinkedList() {
clear();
}
LinkedList(LinkedList&& that) {
this->head_ = that.head_;
this->tail_ = that.tail_;
that.head_ = that.tail_ = nullptr;
}
.........
}
另外, 通过dlsym函数查看源码,发现:
static std::unordered_map<uintptr_t, soinfo*> g_soinfo_handles_map;
static soinfo* soinfo_from_handle(void* handle) {
if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
if (it == g_soinfo_handles_map.end()) {
return nullptr;
} else {
return it->second;
}
}
return static_cast<soinfo*>(handle);
}
应该是通过系统维护的g_soinfo_handles_map里, 映射着对应的handle与soinfo*信息吧,请问如果是这样,如何在外部获取系统维护的g_soinfo_handles_map信息, 用于获取已经打开的so的soinfo*获取,并修改替换以完成壳的功能, 即如何找到想要打开的so的soinfo信息,且和原先版本的变量偏移有区别吗?
经过翻阅源码与多次实验,发现soinfo结构是向前兼容的,因此32位的方法同样适用于64位Arm,不过需要注意的是64位机子的指针为64位,还有重定位时,Rela与Rela.plt多了一个r_addend字段, relative重定位时不是自增加,而是 so->load_bias+rela.r_addend 这样。 希望后人别踩这个坑。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课