安卓逆向笔记--android so加固(代码分析)

一、Android Studio NDK设置方法

如何编写一个so文件:教我兄弟学android逆向06
windows环境下,NDK编译需要添加的include头文件(根据编译的版本需要进行修改):
右击项目 --> Properties --> 左侧C/C++ General --> Paths and Symbols --> 右侧Includes --> GNU C++(.cpp) --> Add
${NDKROOT}\platforms\android-19\arch-arm\usr\include
${NDKROOT}\sources\cxx-stl\gnu-libstdc++\4.8\include
${NDKROOT}\sources\cxx-stl\gnu-libstdc++\4.8\libs\armeabi\include
${NDKROOT}\toolchains\arm-Linux-androideabi-4.8\prebuilt\windows\lib\gcc\arm-linux-androideabi\4.8\include
具体配置: https://github.com/boyliang/ndk-patch (将下载的文件解压后复制到自己所需要ndk的androdi版本目录下)

二、androidkiller中插入调用so的语句

在java中调用so库的代码:

//这里是静态加载,在生成so文件时,系统添加了lib前缀和.so后缀,这里参数就没有前缀和后缀
    static{
        System.loadLibrary("mylib");
    }

在smali语法中调用so库的代码是

	const-string v0, "mylib"
	invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V

ps:在一个成品软件逆向过程中插入so时,需要将编译好的so文件复制到apk的lib目录下。

三、Android so 加固

因为android 调用so的时候用的时system.loadLibrary,所以要从这里的下手,下面是流程
安卓逆向笔记--android so加固(代码分析)_第1张图片

具体代码分析

作者源代码

1、用mmap函数映射so文件到内存
phdr_num_ = header_.e_phnum;
// Like the kernel, we only accept prograa header tables that 
// are smaller than 64KiB.
	if (phdr_num_ < 1 | | phdr_num_ > 65536/sizeof (Elf32_Phdr)) { 
		DL.ERR("\"%s\" has invalid e_phnum:%d", name_, phdr_num_);
		return false;
	}
	Elf32_Addr page_min = PAGE_START (header_.e_phoff);
	Elf32_Addr page_max = PAGE_END (header_.e_phoff + (phdr_num_ * sizeof (Elf32_Phdr))); 
	Elf32_Addr page_offset = PAGE_OFFSET (header_.e_phoff);

	phdr_size_ = page_max - page_min;
	
	void* mmap_result =mmap(NULL, phdr_size_, PROT_READ, MAP_PRIVATE,fd_, page_min)
	if (mmap_result = MAP_FAILED) { 
		DL-ERR("\"%s\" phdr mmap failed: %s", strerror(error));
		return false;
	}
	PROT.READ, HAP.PRIVATE, fd_, pagejitm); 
	phdr_mmap_ = mmap_result;
	phdr_table_ = reinterpret_cast(reinterpret_cast(mmap_result) + phdr_offset);
	return true;
2、映射内存根地址
	Elf32_Addr min_vaddr;
	load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
	if (load_size_ = 0) {
		DL_ERR("\"%s\" has no loadable segments", name_) ;
	return false:
	}
	uint8_t* addr = reinterpret_cast (min_vaddr);
	int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
	void* start = mmap (addr, load_size_, PR0T_N0NE, mmap_flags, -1, 0) ;
	if (start == MAP_FAILED) {
	DL_ERR(" couldn’t reserve %d bytes of address space for \"%s\"", load_size_,)
	return false:
	}

	load_start_ = start;
	load_bias_ = reinterpret_cast (start) - addr;
	return true;
3、映射so代码load内存
// reserve the address space range for the library.
// TODO: assert assumption.
bool ELfReader: :LoadSegnents() {
	for (size_t i = 0: i < phdr_num_: ++i) { 
		const Elf32_Phdr* phdr = &phdr_table_[i];
		if (phdr->p_type != PT_LOAD) { 
			continue;
		}
	}
	// Segment addresses in memory.
	Elf32_Addr seg_start = phdr->p_vaddr + load_bias_; 
	Elf32_Addr seg_end = seg_start + phdr->p_memsz;
	Elf32_Addr seg_page_start = PAGE_START (seg_start); 
	Elf32_Addr seg_page_end = PAGEJBND (seg_end) ;
	Elf32_Addr seg_file_end = seg_start + phdr->p_filesz;
	// File offsets.
	Elf32_Addr file_start - phdr~>p_offset;
	Elf32_Addr file_end - file_start + phdr->p_filesz;
	Elf32_Addr filejpage.start = PAGE.START (file.start): 
	Elf32_Addr file_length = file_end • file_page_start;
	if (file_length != 0) { 
		void* seg_addr = mmap ((void*4)seg page start,fileJLength,
		PFLAGS_TO_PSOT(phdr->p_flags),HAP_FIXED|MAP_PRIVATE,fd_,
		file_page_start);

4、映射soinfo结构体和重定向
static bool soinfo_link_image(soinfo* si) { 
	/* "base" might wrap around UINT32_MAX.*/
	Elf32_Addr base = si->load_bias;
	const Elf32 Phdr *phdr = si->phdr;
	int phnum = si->phnum;
	bool relocating_linker = (si->fLags & FLAG_LINKER) ! = 0;
	/* We can t debug anything until the linker is relocated */ 
	if (! relocating_linker) {
	IHF0("[ linking %s ]", si->name);
	DEBUG ("si->base = 0x%08x si->flags = 0x%08x", si~>base, si->flags);
	}
 	/*Extract dynamic section */
 	size_t dynamc_count;
	Elf32_Word dynamic_flags;
	phdr_table_get_dynami c_secti on (phdr, phntun, base, &si->dynamic,
	Adynajnic_cormt, &dynamic_£Lags) ;
	if (si->dynamic == HULL) {
		if Grelocating linker) {
			DL.ERR ("missing PT.DYNAMIC in \"%s\"", si->name);
		}
	return false;
}
5、重定向系统函数
soinfo** needed = (soinfo**) alloca((l + needed_count) * sizeof (soinfo*)); 
soinfo** pneeded = needed;

for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) { 
	if (d->d_tag == DT.NEEDED) {
		const char* library_name = si->strtab + d->d_un.d_val;
		DEBUG("%s needs %s", si->name, library_name) ; 
		soinfo* lsi = find_library(library_name); 
		if(lsi == HULL) {
			strlcpy (tmp_err_buf, linker_get_error_buffer(),sizeof(tmp_err_buf)); 
			DL_ERR ("could not load library \"%s\" needed by \"%s\*; caused by %s", 
				library_name, si->name, tmp_err_buf): 
			return false;
		}
		*pneeded++ = lsi;
}
6、调用初始化函数和函数数组
void soinfo: :CallArray(const char* array_name UNUSED, linker_function_t* functions, size_t count, bool reverse) {
	if (functions == NULL) {
		return;
	}
	TRACE ("[ Celling %s (size %d) @ ftp for ' %s' ]", array_name, count, functions, name);
	int begin = reverse ? (count - 1) : 0;
	int end = reverse ? -1 : count;
	int step = reverse ? -1 : 1;

	for (int i = begin; i != end; i += step) {
		TRACE ("[ %s[ftd] == ftp ]", array_name, i, functions [i]):
		CallFunction(" function", functions[i]) ;
	}
	TRACE ("[ Done celling %s for ' %s' ]", array_name, name) ;
}
	 
void soinfo: :CellFunction(const char* function_name UNUSED, linker_function_t function) {
	if (function == NULL || reinterpret_cast(function) == static_cast(-l)) {
		return;
	}
	TRACE ("[ Celling %s Q ftp for ' %s' ]", function_name, function, name);
	function();
	TRACE ("[ Done celling %s 6 ftp for ' %s' ]", function_name, function, name);
	// The function may have celled dlopen(3) or diclose (3), so we need to ensure our date structures
	// ere still writable.This happens with our debug malloc (see http://b/7941716)
	set_soinfo_pool_protection(PROT_READ | PR0T_WRITE);
	}
7、还原系统权限
set_soinfo_jpool_protection (PR0T_READ | PROT_WRITE);
8、单个函数加密
const char target_fun[] = "JNI_0nload"; 
	funclnfo info;
	int i;
	// unsigned int npage, base * getLibAddr(); 
	unsigned int npage, base=baseParam;
	__android_log_print(ANDROID_LOG_INFO, "liumeng", "base addr * 0x%x", base);
	if(getTargetFuncInfo(base, target_fun, &info) == -1){ 
		print_debug(MFind 3NI_OnLoad failed*'); 
		return ;
	}
	npage = info.st.size / PAGE_SIZE + ((info.st_size % PAGE.SIZE == 0) ? 0 : 1);
	if(mprotect((void *) ((base + info.st.value) / PAGE.SIZE * PAGE.SIZE), npage, PROT_READ | PROT.EXEC | PROT_VJRITE 
	print_debug('*mem privilege change failed");
	}
	for(i=0;i< info.st_size - 1; i++){
		char *addr = (char*)(base + info.st_value -1 + i);
		*addr = ~(*addr);
	}
	if(mprotect((void *) ((base + info.st.value) / PAGE.SIZE * PAGE_SIZE), npage, PROT.READ | PROT.EXEC) ! = 0){ 
		print_debug("mem privilege change failed");
	}
	print_debug("mem success”);

你可能感兴趣的:(安卓逆向笔记,android逆向)