首页
社区
课程
招聘
[原创]梆梆加固之防内存dump分析
发表于: 2017-12-15 00:32 15938

[原创]梆梆加固之防内存dump分析

2017-12-15 00:32
15938

本文仅限于技术讨论,不得用于非法途径,后果自负。

防内存dump比较笼统,本篇只介绍使用inotify相关实现(以BB为例)。

关于内存dump相关介绍,请参考如下链接:
1) 讨论android加固防内存dump的技术及vmp壳的防护强度:
https://bbs.pediy.com/thread-206293.htm。
2) android应用反调试以及反内存dump代码收集:
https://github.com/parkerpeng/DroidAnti。

关于inotify相关介绍,请参考如下链接:
1) inotify不生效问题:
http://blog.csdn.net/cool_way/article/details/22827433;
2) Linux inotify功能及实现原理:
http://blog.csdn.net/myarrow/article/details/7096460。

1)使用/proc/pid/mem访问其他进程的内存变量:
http://blog.csdn.net/guojin08/article/details/9454467
2)pagemap的解读:
http://blog.sina.com.cn/s/blog_628cc2b70101c8zu.html

我们先看一下BB在防篡改技术的介绍,下图是BB官网上关于防篡改的介绍。(https://www.bangcle.com/products/productindex?product_id=1)

#从官网上无法判断其采取何种措施,下面通过实际逆向分析来学习其相关防护策略。 首先介绍下其使用到的数据结构。

1)红黑树(二)之 C语言的实现:
https://www.cnblogs.com/skywang12345/p/3624177.html

其定义如下:

FileWatchKey结构用于保存监控的文件名以及对应的inotify_add_watch句柄。

该函数位于libdexhelp.so文件中。如下:

从上面的代码可以看到File_notify_threadProc为真正的处理函数。

该函数步骤如下:
1、调用 inotify_init_function函数用于初始化红黑树头信息
2、调用inotify_add_watchByPid(fatherPid)函数,将父进程的/proc/fatherpid/mem与/proc/fatherpid/pagemap纳入到监控中,同时将相应文件名和wd插入到红黑树中。
3、创建线程watchAllTask_threadProc,其将/proc/fatherpid/task/下的所有线程对应的mem与pagemap文件纳入到监控中,同时将 同时将相应文件名和wd插入到红黑树中。
4、调用read_filewatch_event函数对进行监控,如果没发生事件,则阻塞,如果发生事件,则函数返回。
5、调用filewatch_Delete移除监控事件。
6、结束watchAllTask_threadProc线程。
7、结束父进程。
8、线程退出。

该函数用于初始化文件监控相关信息。本函数经过了混淆,去除如下:

从上面可以看到其主要是调用inotifyfile_ini 用于初始化g_fileWatch_wd_root以及g_fileWatch_wd_root,对应的数据结构为RBRoot。
下面看看inotifyfile_ini函数:

从上面可以看到inotifyfile_ini用于malloc一个RBRoot结构,同时将初始化相关成员。其中g_inotify_node_NoValidFlag表示头结点无效。因为目前没有设置任何要监控的文件。
我们看一下2个用于比较的函数。is_same_inotify_wd与is_same_inotify_filename。

该函数用于比较红黑树的key为wd。

本函数主要用于判断新的节点是左节点还是右节点。返回0,是同一个节点,大于0是在右节点分支,小于0在左节点分支。

该函数用于比较红黑树的key为filename。

本函数主要用于判断新的节点是左节点还是右节点。返回0,是同一个节点,大于0是在右节点分支,小于0在左节点分支。

该函数做了如下事情:
1、调用DecodeString9解密字符串“/proc/%ld/mem”;
2、格式化字符串“ /proc/pid/mem”;
3、调用inotify_add_watch_insert_node 将对应文件纳入到监控中;
4、调用DecodeString9解密字符串“/proc/%ld/pagemap”;
5、格式化字符串“ /proc/pid/pagemap”;
6、调用inotify_add_watch_insert_node 将对应文件纳入到监控中;

本函数有如下步骤:
1、对输入的字符串数组进行inotify_add_watch;
2、调用JudeFileIsDir判断是否是目录
2、调用inotifyList_user_add_node将wd于文件名写入对应的红黑树中。

本函数有如下步骤:

下面我们看一getinotifyListByWDnode函数

getinotifyListByWDnode调用query_insert_node来进行查询。

query_insert_node函数进行如下操作:
1、遍历二叉树进行查找进行节点查找;
2、如果找到则返回对应节点;
3、如果没找到,并且不创建新节点则返回0;
4、malloc一个新的RBTree;
5、初始化其父节点;
6、初始化新的RBTree;
7、调用 rbtree_left_rotate和rbtree_right_rotate对红黑树进行修正。

上面完成了getinotifyListByWDnode函数的分析,继续分析insertNewNode。

该函数调用query_insert_node进行新节点的插入操作。
至此函数inotify_add_watchByPid分析完了。
下面看看watchAllTask_threadProc函数的工作。

1、调用DecodeString9解密字符串“/proc/%ld/task/”;
2、格式化字符串“/proc/pid/task/”;
3、调用opendir 打开“/proc/pid/task/”目录;
4、调用readdir读取“/proc/pid/task/”目录;
5、如果返回空,则到步骤11;
6、返回不是空,过滤字符串“ .”与“ ..”;
7、调用DecodeString9解密字符串“/proc/pid/task/tid”;
8、调用inotify_add_watchByPid将tid下的mem与pagemap文件纳入监控中;
9、调用 inotify_add_watchByTid(pfatherPid_1, threadID); 将“/proc/pid/task/tid”中的mem与pagemap纳入到监控中;
10、重复步骤4-步骤9;
11、调用closedir关闭目录;
12、线程睡眠2秒;
13、重复步骤1-12。

这样是不行的,如果此时结束,对于后面新创建的线程则不能纳入到本进程中。对于已经被watch的文件再次watch将返回上次的wd,引用次数会加1。
这里面可能有个小问题是:如果线程被删除了则对应的红黑树链表的节点不会被删除,造成内存泄漏。极端情况应用一致持续不断的创建线程然后线程2秒后销毁,运行一段时间后内存会崩溃。
下面看一下inotify_add_watchByTid函数。

这个函数相对比较简单。

read_filewatch_event函数步骤如下:
1、调用select函数对inotify初始化句柄进行阻塞。当发生事件时,则线程唤醒;
2、调用ioctl函数获得对应事件的长度;
3、调用read函数将发生的事件信息读取到全局变量中。
4、返回对应的事件BUF。

filewatch_Delete函数步骤如下:
1、格式化字符/proc/pid/mem;
2、调用 filewatch_DeleteByFile删除/proc/pid/mem的watch;
3、格式化字符/proc/pid/pagemap;
4、调用 filewatch_DeleteByFile删除/proc/pid/pagemap的watch;

该函数调用步骤如下:
1、调用filewatch_DeleteNode删除wd相关watch;
2、调用filewatch_DeleteNode删除filename相关watch;
3、调用filewatch_rm移除wd;
4、调用freeKeyBuf释放FileWatchKey。

函数filewatch_DeleteNode如下:

filewatch_DeleteNode函数进行节点删除,以及红黑树调整相关操作。下面看一下函数filewatch_rm。

调用inotify_rm_watch进行wd移除。下面看一下freeKeyBuf函数。

freeKeyBuf函数进行内存释放工作。
至此删除文件监控分析结束。

先将监控所有task的线程结束。然后调用killProcess结束父进程。

对于防守方可以监控inotify_add_watch函数是否HOOK。
学习群号:211730239

 
 
 
从上面的知识可知,通过对目标进程文件/proc/pid/mem文件操作,可以获得其内存的数据。
而inotify可以监控文件系统的变化,当文件被打开、删除,读写等操作时,同时用户相应变化。
因此可以通过监控/proc/pid/mem 与/proc/pid/pagemep来防止内存dump。
防内存dump用到了红黑树的数据结构。下面是关于红黑树数据结构的介绍。
typedef struct FileWatchKey
{
    char* fileName;                //监控的文件名
    int      wd;                    //inotify_add_watch 返回值
}FileWatchKey;

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (10)
雪    币: 355
活跃值: (276)
能力值: ( LV11,RANK:190 )
在线值:
发帖
回帖
粉丝
2
谢享
2017-12-15 09:13
0
雪    币: 11
活跃值: (80)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享,好详细啊
2017-12-15 09:39
0
雪    币: 562
活跃值: (4347)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
不错,分析的很详细
2017-12-15 09:59
0
雪    币: 59
活跃值: (680)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
mark,很详细
2017-12-15 10:15
0
雪    币: 14872
活跃值: (6093)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
防内存篡改不等于防内存dump。
通篇看完没有看见防内存dump?只有防内存篡改。(唯有VMP解释smali算是防内存dump)
2017-12-15 14:29
0
雪    币: 19097
活跃值: (1345)
能力值: ( LV15,RANK:936 )
在线值:
发帖
回帖
粉丝
7
tDasm 防内存篡改不等于防内存dump。通篇看完没有看见防内存dump?只有防内存篡改。(唯有VMP解释smali算是防内存dump)
看:  编写目的
防内存dump比较笼统,本篇只介绍使用inotify相关实现(以BB为例)。 
2017-12-15 18:03
0
雪    币: 19097
活跃值: (1345)
能力值: ( LV15,RANK:936 )
在线值:
发帖
回帖
粉丝
8
tDasm 防内存篡改不等于防内存dump。通篇看完没有看见防内存dump?只有防内存篡改。(唯有VMP解释smali算是防内存dump)
PS:随着攻防升级,加固技术也在升级,并不是说DEX  VMP后其他的防护技术就不用了
2017-12-15 18:05
0
雪    币: 14872
活跃值: (6093)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9



oooAooo

看: 编写目的
防内存dump比较笼统,本篇只介绍使用inotify相关实现(以BB为例)。
防内存dump比较笼统?我认为什么是防内存dump已经很明确,只是你的理解问题。
2017-12-16 11:42
0
雪    币: 758
活跃值: (78)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
m
2019-11-14 09:59
0
雪    币: 163
活跃值: (1623)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
11
inotify只是对文件事件进行通知,比如打开,关闭。并没有告知读哪一部分。 这个如何和自己软件的正常读写区分开呢
2023-6-5 14:28
0
游客
登录 | 注册 方可回帖
返回
//