Android下通过hook技术实现透明加解密保障数据安全Word格式文档下载.docx
- 文档编号:13159908
- 上传时间:2022-10-07
- 格式:DOCX
- 页数:10
- 大小:85.02KB
Android下通过hook技术实现透明加解密保障数据安全Word格式文档下载.docx
《Android下通过hook技术实现透明加解密保障数据安全Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《Android下通过hook技术实现透明加解密保障数据安全Word格式文档下载.docx(10页珍藏版)》请在冰豆网上搜索。
一、前言
这将导致用户重要文件在设备上明文的存在,存在泄漏的风险。
而且根据笔者的调研,对于360隐私空间,应用程序对临时文件修改后不能再逆向加密回密文,导致加密操作只能一次进行。
LBE隐私空间,相对较好,但其临时文件存在生命周期过长。
因此笔者通过现有知识讨论一种采用hook技术实现的透明加解密方法,不需要在设备上生成临时文件,从而保护用户重要隐私。
二、技术要点
由于Android是基于linux内核的开源系统,根据语言环境不同可以分为Java层、NativeC层、LinuxKernel层。
Java层的安全是使用Java语言开发,基于SDK,能实现的功能相对简单。
LinuxKernel层安全,需要从源码做起,编译自己的系统,通用性不强。
因此在NativeC层,通过JNI开发,可以使用linux提供的函数实现更多的功能。
在hookAPI方面与linux的hook类似使用ptrace函数与plt表实现,还可以采用Inlinehook的方式实现,但是不是很稳定,操作难度大。
其本质都是劫持函数调用。
但是由于处于Linux用户态,每个进程都有自己独立的进程空间,所以必须先注入到所要hook的进程空间,修改其内存中的进程代码,替换其中过程表的符号地址,因此其生存空间是所注入的进程,只能对某一进程进行HOOK。
Ptrace函数是调试程序所用,功能强大,不仅可以附加某一进程(PTRACE_ATTACH),而且可以任意修改目标进程的内存空间(PTRACE_PEEKDATA,读内存。
PTRACE_POKEDATA,写内存),甚至是寄存器(PTRACE_SETREGS,PTRACE_GETREGS)
基本流程是利用寄存器指令中断:
①PTRACE_ATTACH,绑定目标进程。
②PTRACE_GETREGS,获取目标进程寄存器状态,并保存。
③PTRACE_PEEKDATA与PTRACE_POKEDATA配合,保存原代码,写入要注入的代码到当前运行位置。
④PTRACE_SETREGS,恢复寄存器状态,并继续执行,这是注入的代码开始在目标进程内执行,注入代码完成HOOK,过程与Windows下相似。
⑤在HOOK完成后,注入的代码执行int3被ptrace捕获,目标进程再次暂停执行。
⑥PTRACE_GETREGS,再次保存寄存器。
⑦PTRACE_PEEKDATA与PTRACE_POKEDATA配合还原代码。
⑧PTRACE_SETREGS,恢复寄存器,目标进程继续执行。
⑨PTRACE_DETACH,撤销绑定目标进程。
参考LBE实现原理和看雪上关于HookIoctl的文章都基本上按照这种流程实现HOOK。
在明白hook工作机制后,对于实现Android上的透明加解密需要找到open和close函数的符号存在哪个动态链接库中,hook该应用程序的这个动态链接库,在open操作进行的时候,将密文文件分块解密到内存中,并将该内存中的文件标识符返回。
在close操作进行的时候将内存中的明文加密到本地密文存储。
三、关键流程
1、阅读Android代码查找打开文件和关闭文件过程。
这是我们实现透明加解密的关键。
参考
可以发现读取文件流的函数最终通过JNI方式的read函数实现,同样打开文件的操作最终都归结于open函数。
而实现Java代码的JNI支持的动态库是nativehelper.so因此我们需要hook的动态库即nativehelper.so。
注:
在Android早期版本即android2.3、Android4.0上open和close符号在nativehelper.so中,该文件有140k大小。
而在android4.1版本以上,谷歌重写了android原生库的实现,nativehelper.so被拆分,笔者在4.0平台进行的开发并没有阅读寻找4.1版本之上的。
2、进行进程注入和ELF节替换
进程注入就是将一段代码拷贝到目标进程,然后让目标进程执行这段代码的技术。
由于这样的代码构造起来比较复杂,所以实际情况下,只将很少的代码注入到目标进程,而将真正做事的代码放到一个共享库中,即.so文件。
被注入的那段代码只负责加载这个.so,并执行里面的函数。
由于.so中的函数是在目标进程中执行的,所以在.so中的函数可以修改目标进程空间的任何内存,当然也可以加钩子,从而达到改变目标进程工作机制的目的。
当然不是任何进程都有权限执行注入操作的。
Android平台上的进程注入是基于ptrace()的,要调用ptrace()需要有root权限。
目前市面上的主流安全软件也都是基于进程注入来管理和控制其他应用进程的。
这也就是为什么这些安全软件需要获得root权限的原因。
关于如何.so注入的实现,可以参考看雪论坛的上的一个注入库LibInject和洗大师的一个开源项目AndroidInjectorLibrary。
笔者对这种两种方式都有实验,对于Libinject,就是向目标进程中注入libhook.so,首先调用ptrace()函数,挂起该进程。
然后遍历进程加载的libc.so,通过dlopen和dlsym函数修改arm寄存器的值,然后压入参数,so路径,并将之前找到的dlopen地址压入寄存器,直接操作blx,就可以让目标进程调用dlopen加载我们的so,同理dlsym调用我们的so里的函数。
注入完成后,会调用libhook.so库中的hook_entry()函数,该函数实现加载hook函数实现的动态库,并对libnativehelper.so的got表和plt表的遍历和修改。
修改为自己编写的实现open函数和close函数的动态库中的符号地址。
因此需要注入两个库,因为libhook.so在执行完后需要detach目标进程,从而释放,而具体操作的动态库需要常驻内存。
实现常驻内存需要在hook_entry()函数中显式加载动态库。
以上注入以后的过程都由自己编程实现,能够加深对ELF格式理解。
而采用AndroidInjectorLibrary则相对简单,在调用可执行程序的主函数中实现即可:
这个文件编译生成注入入口和符号表替换逻辑。
*1、在该函数中加载libhook.so通过其中的do_hook函数返回原来的open和close地址以及要替换的新的open和close函数地址
*2、然后静态打开libnativehelper动态库,读取其结构遍历节表,找到全局符号表(GOT表),该表存储了外部依赖符号的地址
*3、遍历GOT表找到原先的open函数和close函数地址,分别替换为新的open函数和新的close函数即可
3、在学习这一过程中,需要了解linux的ELF格式,以下是学习ELF的笔记:
参见《程序员的自我修养》如果熟悉则可跳过。
ehdr->
e_shstrndx索引指向shstrtab的节,可以用来索引节头的字符串名称描述。
shstrtab表(SectionHeaderStringTable)保存段表中用到的字符串,最常见的就是段名、
常用的段名说明
.rodata1ReadOnlyData,这种段里存放的是只读数据,比如字符串常量、全局const变量。
跟”.rodata”一样
.comment存放的是编译器版本信息
.debug调试信息
.dynamic动态链接信息
.hash符号哈希表
.line调试时的行号表
.note额外的编译器信息。
比如程序的公司名、发布版本号等
.strtabStringTable.字符串表
.symtabSymbolTable.符号表
.shstrtabSectionStringTable.段名表
.plt.got动态链接的跳转表和全局入口表
.init.fini程序初始化与终结代码段
符号节,遍历节头时候。
判断每一个节的类型是不是SHT_SYMTAB或SHT_DYNSYM,那么对应的节就是符号节。
符号节存放的是一张符号表,符号表也是一个连续存储的结构数组.
编程过程中用到的变量和函数都可以称之为符号,一个ELF文件中并不只有一个符号节,通常是两个,一个为”.dynsym”的动态节类型为SHT_DYNSYM,所有引入的外部符号在这里有所体现,另一个为SHT_SYMTAB,名字为“.symtab”保存了所有有用符号信息。
SymbolTable符号表保存了一个程序在定位和重定位时需要的定义和引用的信息。
一个符号表索引是相应的下标。
符号表的存在意义是体现在多个目标文件进行链接的时候,在链接中,目标文件之间相互拼合实际上是目标文件之间对地址的引用,即对函数和变量的地址的引用,而函数和变量可以统称为符号(Symbol),函数名或变量名就是符号名(SymbolName)。
我们可以将符号看作是是链接中的粘合剂,整个链接过程就是基于符号才能够正确完成。
在符号表”.symtab“中,其也是像段表的结构一样,是一个数组,每个数组元素是一个固定的结构来保存符号的相关信息,比如符号名(不是字符串,而是该符号名在字符串表的下标)、符号对应的值(可能是段中的偏移,也可能是符号的虚拟地址)、符号大小(数据类型的大小)等等。
符号表中记录的一般是全局符号,比如全局变量、全局函数等等。
目标文件的符号表包含定位或重定位程序符号定义和引用时所需要的信息。
符号表入口结构定义如下:
typedefstruct{
Elf32_Wordst_name;
Elf32_Addrst_value;
Elf32_Wordst_size;
Unsignedcharst_info;
Unsignedcharst_other;
Elf32_Halfst_shndx;
}Elf32_Sym;
其中st_name包含指向符号表字符串表(strtab)中的索引,从而可以获得符号名。
St_value指出符号的值,可能是一个绝对值、地址等。
St_size指出符号相关的内存大小,比如一个数据结构包含的字节数等。
St_info规定了符号的类型和绑定属性,指出这个符号是一个数据名、函数名、section名还是源文件名;
并且指出该符号的绑定属性是local、global还是weak。
GOT表和PLT表
GOT(GlobalOffsetTable)表中每一项都是本运行模块要引用的一个全局变量或函数的地址。
可以用GOT表来间接引用全局变量、函数,也可以把GOT表的首地址作为一个基准,用相对于该基准的偏移量来引用静态变量、静态函数。
由于加载器不会把运行模块加载到固定地址,在不同进程的地址空间中,各运行模块的绝对地址、相对位置都不同。
这种不同反映到GOT表上,就是每个进程的每个运行模块都有独立的GOT表,所以进程间不能共享GOT表。
动态链接机制
首先回顾
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android 通过 hook 技术 实现 透明 解密 保障 数据 安全