玩转Hook——Android权限管理功能探讨(一)
随着Android设备上的隐私安全问题越来越被公众重视,恶意软件对用户隐私,尤其是对电话、短信等私密信息的威胁日益突出,各大主流安全软件均推出了自己的隐私行为监控功能,在root情况下能有效防止恶意软件对用户隐私的窃取,那么这背后的技术原理是什么?我带着疑问开始一步步探索,如果要拦截恶意软件对电话、短信等API的调用,在Java或者Dalvik层面是不好进行的,因为这些层面都没有提供Hook的手段,而在Native层面,我认为可行的方案是对电话、短信的运行库so进行Hook(比如系统运行库\system\lib\libreference-ril.so或\system\lib\libril.so),如果注入自己的so到上述进程后,并通过dlopen()和dlsym()获取原有API地址,替换原有API地址为自己so中的API地址就可以达到Hook的目的。
Hook的前提是进程注入,而Linux下最便捷的进程注入手段——ptrace,是大名鼎鼎的调试工具GDB的关键技术点;本文参考自Pradeep Padala于2002年的博文http://www.linuxjournal.com/article/6100(国内很多博客有这篇文章的译文,不过本着获取“一手”知识的想法,还是细读了原版英文,确实发现了一些翻译得不够到位的地方,在此还是推荐各位能读原文就不要读译文),由于02年时还是ia32(32位Intel Architecture)时代,时至今日,在我ia64也就是x64的机器已经无法运行了,所以自己动手实现了x64版本。代码主要功能是注入子进程的地址空间,Hook住子进程执行系统调用时的参数,并反转其参数,从而逆序输出ls命令的结果。
代码如下:
/*
ptrace3.c
author: pengyiming
description:
1, child process need be traced by father process
2, father process reserve the result of "ls" command which executed by child process
*/ #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <sys/user.h>
#include <sys/syscall.h>
#include <unistd.h> #ifdef __x86_64__ #define OFFSET_UNIT 8 #else #define OFFSET_UNIT 4 #endif // converter long to char[]
union
{
long rawData;
char strData[sizeof(long)];
} converter; void getData(pid_t child, unsigned long long dataAddr, unsigned long long dataLen, char * const p_data)
{
// PEEKDATA counter
int counter = ;
// PEEKDATA max count
int maxCount = dataLen / sizeof(long);
if (dataLen % sizeof(long) != )
{
maxCount++;
}
// moving pointer
void * p_moving = p_data; while (counter < maxCount)
{
memset(&converter, , sizeof(long));
converter.rawData = ptrace(PTRACE_PEEKDATA, child, dataAddr + counter * sizeof(long), NULL);
if (converter.rawData < )
{
perror("ptrace peek data error : ");
} memcpy(p_moving, converter.strData, sizeof(long));
p_moving += sizeof(long);
counter++;
}
p_data[dataLen] = '\0';
} void setData(pid_t child, unsigned long long dataAddr, unsigned long long dataLen, char * const p_data)
{
// POKEDATA counter
int counter = ;
// POKEDATA max count
int maxCount = dataLen / sizeof(long);
// data left length (prevent out of range in memory when written)
int dataLeftLen = dataLen % sizeof(long);
// moving pointer
void * p_moving = p_data; // write part of data which align to sizeof(long)
int ret;
while (counter < maxCount)
{
memset(&converter, , sizeof(long));
memcpy(converter.strData, p_moving, sizeof(long));
ret = ptrace(PTRACE_POKEDATA, child, dataAddr + counter * sizeof(long), converter.rawData);
if (ret < )
{
perror("ptrace poke data error : ");
} p_moving += sizeof(long);
counter++;
} // write data left
if (dataLeftLen != )
{
memset(&converter, , sizeof(long));
memcpy(converter.strData, p_moving, dataLeftLen);
ret = ptrace(PTRACE_POKEDATA, child, dataAddr + counter * sizeof(long), converter.rawData);
if (ret < )
{
perror("ptrace poke data error : ");
}
}
} void reverseStr(char * p_str)
{
int strLen = strlen(p_str);
char * p_head = p_str;
char * p_tail = p_str + strLen - ;
char tempCh; // skip '\n'
if (*p_tail == '\n')
{
p_tail--;
} //exchange char
while (p_head < p_tail)
{
tempCh = *p_head;
*p_head = *p_tail;
*p_tail = tempCh; p_head++;
p_tail--;
}
} void debugRegs(struct user_regs_struct * p_regs )
{
printf("syscall param DS = %llu\n", p_regs->ds);
printf("syscall param RSI = %llu\n", p_regs->rsi);
printf("syscall param ES = %llu\n", p_regs->es);
printf("syscall param RDI = %llu\n", p_regs->rdi); printf("syscall return RAX = %llu\n", p_regs->rax);
printf("syscall param RBX = %llu\n", p_regs->rbx);
printf("syscall param RCX = %llu\n", p_regs->rcx);
printf("syscall param RDX = %llu\n", p_regs->rdx);
} int main()
{
pid_t child = fork();
if(child == )
{
ptrace(PTRACE_TRACEME, , NULL, NULL); // make a syscall(SYS_write)
execl("/bin/ls", "ls", NULL);
}
else
{
int status;
// SYS_write will be called twice, one is entry, another is exit, so we mark it
unsigned int calledCount = ; while ()
{
wait(&status);
if (WIFEXITED(status))
{
break;
} // PEEK regs to find the syscall(SYS_execve)
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, child, NULL, ®s); // catch it!
if (regs.orig_rax == SYS_write)
{
if (calledCount == )
{
calledCount = ; // debugRegs(®s); char * p_dataStr = (char *) malloc((regs.rdx + ) * sizeof(char));
if (p_dataStr == NULL)
{
return;
} getData(child, regs.ds * OFFSET_UNIT + regs.rsi, regs.rdx, p_dataStr);
reverseStr(p_dataStr);
setData(child, regs.ds * OFFSET_UNIT + regs.rsi, regs.rdx, p_dataStr);
}
else if (calledCount == )
{
// debugRegs(®s);
}
} ptrace(PTRACE_SYSCALL, child, NULL, NULL);
}
} return ;
}
代码执行结果:
可以看到工程目录下的文件名均被反转输出,已达到想要的效果,那么接下来解释代码中的几个关键点:
1,SYSCALL与orig_rax寄存器
不论是ia32还是ia64,orig_rax寄存器都存放着每一次系统调用的ID,为了方便开发和调试,我们可以在/usr/include/x86_64-linux-gnu/sys/syscall.h中找到系统调用的定义,比如#define SYS_write __NR_write,但是我们无法得知__NR_write具体代表的ID,进一步搜索,可以在/usr/include/x86_64-linux-gnu/asm/unistd_64.h中找到ia64下对__NR_write的定义,#define __NR_write 1,这样一来我们打印出orig_rax寄存器中的值就可以判断此时子进程正在进行何种操作了。
2,PTRACE_PEEKDATA与PTRACE_PEEKTEXT参数的选取
Linux进程的地址空间不存在独立的数据段和代码段(或叫正文段),二者位于同一空间,所以上述两个参数并无实际意义上的区别,不过为了标识我们是在读取数据段中的数据,还是使用PTRACE_PEEKDATA比较好,同理对应于PTRACE_POKEDATA和PTRACE_POKETEXT。
3,联合体converter
由于执行PTRACE_PEEKDATA操作时,返回值的二进制代表内存中的实际数据,我们可以利用“联合体中的变量有相同的初始地址”这一特性来帮助我们完成从二进制到字符串的转换。(这是一个做过嵌入式开发的人基本都知道的小技巧,考虑到做Android开发对这段代码可能会有疑惑,容我啰嗦两句)
4,数据段寻址
这是在实现x64版本时遇到的最大的困难,在getData()与setData()函数中,第二个参数表示数据在数据段中的地址,由于和ia32时寻址方式不一致,苦苦搜索几天,发现国内很多博客上的说法并不一致,最终在Intel官网上下载了Intel处理器开发手册《64-ia-32-architectures-software-developer-vol-1-manual.pdf》方才解答我的问题,寻址方式涉及两个寄存器,DS和RSI,参考手册的说法,DS表示数据段的selector,其实这个selector就是index索引的意思,由于x64下字长64bit,即8个字节,索引乘以8即得数据段在内存中的基址,RSI表示数据段内偏移地址,与基址相加即可得出数据的绝对地址,使用此地址直接访问内存就可以取出数据。
玩转Hook——Android权限管理功能探讨(一)的更多相关文章
- 玩转Hook——Android权限管理功能探讨(二)
距离我上一篇研究ptrace的随笔http://www.cnblogs.com/zealotrouge/p/3544147.html已经过去半年了,最近不忙的时候抽空继续研究了下.同样,参考了Prad ...
- Android权限管理之Android 6.0运行时权限及解决办法
前言: 今天还是围绕着最近面试的一个热门话题Android 6.0权限适配来总结学习,其实Android 6.0权限适配我们公司是在今年5月份才开始做,算是比较晚的吧,不过现在Android 6.0以 ...
- Android权限管理之Permission权限机制及使用
前言: 最近突然喜欢上一句诗:"宠辱不惊,看庭前花开花落:去留无意,望天空云卷云舒." 哈哈~,这个和今天的主题无关,最近只要不学习总觉得生活中少了点什么,所以想着围绕着最近面试过 ...
- Android权限管理之RxPermission解决Android 6.0 适配问题
前言: 上篇重点学习了Android 6.0的运行时权限,今天还是围绕着Android 6.0权限适配来总结学习,这里主要介绍一下我们公司解决Android 6.0权限适配的方案:RxJava+RxP ...
- android: Android 权限管理小结
一. 概述 感谢郭神,自从Android6.0发布以来,在权限上做出了很大的变动,不再是之前的只要在manifest设置就可以任意获取权限,而是更加的注重用户的隐私和体验,不会再强迫用户因拒绝不该拥有 ...
- Android权限管理PermissionsDispatcher2.3.2使用+原生6.0权限使用
PermissionsDispatcher2.3.2使用 Android6.0权限官网https://developer.android.com/about/versions/marshmallow/ ...
- Android 权限管理
从 Android 6.0(API 级别 23)开始,用户开始在应用运行时向其授予权限,而不是在应用安装时授予.此方法可以简化应用安装过程,因为用户在安装或更新应用时不需要授予权限.它还让用户可以对应 ...
- Android权限管理知识学习记录
一.Android权限背景知识 在Android 6.0之前,所申请的权限只需要在AndroidManifest.xml列举就可以了,从而容易导致一些安全隐患,因此,在Android 6.0时,Goo ...
- PHP实现权限管理功能
权限管理系统,它主要是为了给不同的用户设定不同的权限,从而实现不同权限的用户登录之后使用的功能不一样. 首先先看下数据库 总共有5张表,users,roles和roleswork 3张表与另外2张表形 ...
随机推荐
- MIT-6.824 MapReduce
概述 MapReduce是由JeffreyDean提出的一种处理大数据的编程模型,用户定义map和reduce函数,map函数处理原始数据生成一系列键值对中间数据,reduce函数并合相同key的键值 ...
- [文章存档]Azure上部署的java app在向第三方服务传送中文时出现乱码
https://docs.azure.cn/zh-cn/articles/azure-operations-guide/app-service-web/aog-app-service-web-java ...
- EOS开发基础之三:使用cleos命令行客户端操作EOS——关于钱包wallet和账户account
好了,上一节我们已经讲了关于wallet的一些基础操作,基本了解了怎么去创建一个钱包,怎么去查看钱包.上锁和解锁钱包等,这一节咱们就来开始操作账户account吧. 上一节讲到了每一个account都 ...
- PHP Lavavel 使用控制器 传递变量 以及调用 视图模板
控制器第一次入门使用 位置: 在app/Http/Controllers 目录下创建文件名格式:例如 UserController路由调用格式:Route::get('user/tom','UserC ...
- nginx反向代理tomcat应用,struts2网站程序redirect时导致请求地址错误的解决方法
一个使用struts2的网站在登录页面需要进行redirect跳转,大致如下: <package name="admin" extends="httl-defaul ...
- 简言MVC
什么是MVC? MVC是一种代码的组织结构,在一个工程项目中,将代码的数据处理,逻辑单元和交互部分分离开来达到一种低耦合的效果,便于工程的修改.MVC中M代表Model,V代表View,C代表Cont ...
- 11.12 Daily Scrum(保存草稿后忘了发布·····)
在实现过程中,我们发现要将不同人开发的组件整合起来并不是一件容易的事,于是我们调整了一下任务,修改了一下各自的程序: Today's tasks Tomorrow's tasks 丁辛 餐厅列表 ...
- 《Linux内核分析》课程第五周学习总结
姓名:何伟钦 学号:20135223 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...
- Linux内核设计(第一周)——从汇编语言出发理解计算机工作原理
Linux内核设计(第一周)——从汇编语言出发理解计算机工作原理 计算机工作原理 汇编指令 C语言代码汇编分析 by苏正生 原创作品转载请注明出处 <Linux内核分析>MOOC课程htt ...
- beta NO1
031602111 傅海涛 1.今天进展 笔记颜色统一,解决笔记的同步性和完整性 2.存在问题 office文档转换的时间问题 3.明天安排 增加新功能和完善之前的功能 4.心得体会 接口真难 031 ...