本帖最后由 新手623937 于 2023-3-17 10:04 编辑
动态防护技术是面向App运行过程的防护,一方面可以通过App动态加固技术来实现,比如程序数据加解密保护、进程防动态调试保护、运行日志输出保护、用户信息输入保护等;另一方面需要开发者在App实现方案中采用保护技术,如客户端和服务器端通信过程的保护等。此次仅介绍App动态防护技术的实现思路,不讨论具体的实现方案细节。
1、防调试在对Android App进行逆向破解的过程中,动态调试是最常用也是最有效的方式。动态调试攻击是指攻击者利用调试器跟踪目标程序运行,查看、修改内存代码和数据,分析程序逻辑,进行攻击和破解等行为。比如对于金融类app,动态调试可以修改APP业务操作时的账号、金额等数据。相应的App防调试安全要求在之前章节已有描述,常用的动态调试工具有IDAPro gdb等,开发者通过提高App防调试的能力,能够增加App的破解难度。 由于Android平台没有禁止用于调试的ptrace系统调用,恶意程序在得到ROOT权限后,可以使用系统API对目标进程的内存、寄存器进行修改,达到执行shellcode、注入恶意模块的目的。在注入恶意模块后,攻击者就可以动态获取内存中的各种敏感信息,例如用户名、密码等。除了 ptrace系统调用外,Android 系统中的proc 文件也暴露了大量的程序进程信息,能够实现对内存的读写操作,因此对程序进行反调试的保护是非常有必要的。攻击者常常利用动态调试工具以及挂钩系统函数跟踪程序的执行流程,分析程序执行逻辑,查看并修改内存中的代码和数据。因此,本节主要介绍防调试和防挂钩方法的基本思路。 1.防调试方法 在Linux系统中,一个进程只能被附加一次,因此可以让App进程复制出子进程,然后对自已进行附加,这样就可以防止调试器在App运行过程中附加到App的进程中。 当一个进程被跟踪时,对应的进程status文件中的TracerPid字段会发生变化。当进程没有被跟踪或者调试时,TracerPid字段的默认值是0;如果进程被跟踪或者被调试,则该字段的值为跟踪进程的pid值。通过轮询/proc/app_pid/status文件,读取TracerPid的字段值,可以判断App当前是否被调试跟踪。以下是检查TracerPid的示例代码:
- char file [MAX_ _LEN], line[MAX_ _LEN];
- snprintf (file, MAX_ LEN -1, "/proc/%d/status",getpid());
- /*这些地方都需要进行下列检查
- /proc/<pid>/status
- /proc/<pid>/task/ <chdpid>/status,
- /proc/<pid>/stat
- /proc/ <pid>/task/ <chdpid>/stat
- /proc/<pid> /wchan
- /proc/ <pid>/task/ <chdpid> /wchan
- */
- FILE *fp = fopen (file, "r");
- while (fgets (line, MAX _LEN -1,fp)) {
- if (strncmp (line, "TracerPid:", 10) == 0) {
- if (0 != atoi (&line[10])) {
- //进程处于被调试之中
- }
- break;
- }
- }
- fclose (fp);
复制代码
利用Linux系统的inotify机制监测/proc目录,利用监听函数监测/proc目录是否阻塞在监听处,一旦有调试进程通过/proc文件系统对App进程内存进行读写操作,监听函数就会停止阻塞, 就可以判定有调试进程正在通过/proc文件系统。以下是inotify 监视/proc文件系统中maps是否被访问的示例代码:
- bool check_ inotify(){
- int ret, i;
- const int BUF_SIZE = 2048;
- char buf[BUF_ SIZE];
- int fd, wd;
- fd_ set readfds;
- fd = inotify_init();
- sprintf(buf, "/proc/%d/maps", getpid());
- wd = inotify_add_watch(fd, buf, IN_ ALL_EVENTS);
- if(wd>=0){
- while (1) {
- i= 0;
- FD_ ZERO(&readfds);
- FD_ SET(fd, &readfds);
- ret = select(fd + 1, &readfds, 0, 0, 0); if (ret == -1) {
- break;
- }
- if (ret) {
- while (i < read(fd, buf, BUF _SIZE)) {
- struct inotify_event *event = (struct inotify_event *) &buf[i];
- if ((event->mask & IN_ACCESS) || (event->mask & IN _OPEN)) {
- // maps被访问
- return true;
- }
- i+=sizeof(struct notify_event)+event->len;
- }
- }
- }
- }
- inotify_ rm _watch(fd, wd);
- close(fd);
- }
复制代码
|