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

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

2017-12-15 00:32
14832

 声明(打字好累)

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

 参考资料

  1. https://bbs.pediy.com/thread-206293.htm
  2. https://github.com/parkerpeng/DroidAnti
  3. http://blog.csdn.net/cool_way/article/details/22827433
  4. http://blog.csdn.net/myarrow/article/details/7096460
  5. http://blog.csdn.net/guojin08/article/details/9454467
  6. http://blog.sina.com.cn/s/blog_628cc2b70101c8zu.html
  7. https://www.cnblogs.com/skywang12345/p/3624177.html

 编写目的

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

写在前面

1.1内存dump介绍

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

1.2 inotify主要功能

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

1.3 /proc/pid/mem 与/proc/pid/pagemep

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

1.4 inotify防内存dump

从上面的知识可知,通过对目标进程文件/proc/pid/mem文件操作,可以获得其内存的数据。
而inotify可以监控文件系统的变化,当文件被打开、删除,读写等操作时,同时用户相应变化。
因此可以通过监控/proc/pid/mem 与/proc/pid/pagemep来防止内存dump。

1.5 BB对防内存dump的介绍

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

 

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

2算法与数据结构

防内存dump用到了红黑树的数据结构。下面是关于红黑树数据结构的介绍。

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

2.1自定义的结构变量

2.1.1 FileWatchKey结构

其定义如下:

typedef struct FileWatchKey
{
    char* fileName;                //监控的文件名
    int      wd;                    //inotify_add_watch 返回值
}FileWatchKey;

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

2.1.2 RBTree数据结构

这个结构用于保存所有监控文件的信息,其定义如下:
typedef struct  RBTree
{
    RBTree*    left;                       //红黑树左节点
    RBTree* right;                        //红黑树右节点
    RBTree* parent;                        //父节点
    int        color;                    //红节点 黑节点
    FileWatchKey* keybuf;                 //key
} RBTree;

2.1.3 RBRoot数据结构

本结构用于定义头结点以及用于节点比较的函数指针。
typedef struct RBRoot
{
    void* compareFun;                    //用于红黑树比较的函数
    int      const_0;                        //常量
    RBTree* treeHead;                    //红黑树头结点
}RBRoot;

3 逆向分析流程

3.1 创建线程用于文件监控

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

void __fastcall createFileWatch_thread(int fatherPid, pthread_t a2)  
{  
  int v2; // r4  
  signed int v3; // r5  
  _DWORD *pfatherPid; // r6  
  pthread_t newthread; // [sp+4h] [bp-14h]  

  newthread = a2;  
  v2 = fatherPid;  
  v3 = 31;  
  pfatherPid = malloc(4u);  
  *pfatherPid = v2;  
  while ( pthread_create(&newthread, 0, (void *(*)(void *))File_notify_threadProc, pfatherPid) )  
  {  
    if ( !--v3 )  
      break;  
    sleep(1u);  
  }  
}

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

3.2 File_notify_threadProc 函数

signed int __fastcall File_notify_threadProc(__pid_t *pfatherPid)  

int fatherPid; // r5  
unsigned int result; // r0  
signed int v3; // r6  
_DWORD *v4; // r7  
  struct inotify_event *inotifyeventStr; // r0  
  pthread_t newthread; // [sp+4h] [bp-1Ch]  

  fatherPid = *pfatherPid;  
  free(pfatherPid);  
  result = inotify_init_function();  
  if ( result )  
  {  
    inotify_add_watchByPid(fatherPid);  
    v3 = 0x1F;  
    v4 = malloc(4u);  
    *v4 = fatherPid;  
    while ( pthread_create(&newthread, 0, (void *(*)(void *))watchAllTask_threadProc, v4) )  
    {  
      if ( !--v3 )  
        break;  
      sleep(1u);  
    }  
    inotifyeventStr = (struct inotify_event *)read_filewatch_event(-1);  
    if ( inotifyeventStr )  
      GetFileWatchRBTreeKeyName(inotifyeventStr->wd);  
    filewatch_Delete(fatherPid);  
    pthread_kill(newthread, 10);  
    result = killProcess(fatherPid, 9); 
  }  
  return result;

该函数步骤如下:
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、线程退出。

3.3 inotify_init_function函数

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

signed int __fastcall inotify_init_function()  
{  
  signed int result; // r0  
  //如果初始化过,则直接返回。  
  if ( g_inotify_init_finshFlag )  
    return 1;  
  g_fileWatch_errno = 0;  
  //初始化文件监控  
  g_inotify_init = inotify_init();  
  if ( g_inotify_init < 0 )  
  {  
    result = 0;  
    g_fileWatch_errno = g_inotify_init;  
    return result;  
  }  
  //置位初始化完成标志  
  g_inotify_init_finshFlag = 1;           
  //初始化以监控句柄比较的红黑树RBRoot 结构  
  g_fileWatch_wd_root = (struct RBRoot *)inotifyfile_ini((int)is_same_inotify_wd, 0);  
  //初始化以监控文件名比较的红黑树RBRoot 结构  
  g_fileWatch_name_root = (struct RBRoot *)inotifyfile_ini((int)is_same_inotify_filename, 0);  
  return 1;  
}

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

truct RBRoot *__fastcall inotifyfile_ini(void *comparefun, int const_0)  
{  
  void *comparefun_1; // r5  
  int const_0_1; // r4  
  struct RBRoot *result; // r0  

  comparefun_1 = comparefun;  
  const_0_1 = const_0;  
  result = (struct RBRoot *)malloc(0xCu);  
  if ( result )  
  {  
    result->fun = comparefun_1;  
    result->const_0 = const_0_1;  
    result->root = (struct RBTree *)&g_inotify_node_NoValidFlag;  
  }  
  return result;  
}

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

3.3.1 is_same_inotify_wd函数

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

struct FileWatchKey *__fastcall is_same_inotify_wd(struct FileWatchKey *node, int a2)  
{  
  struct FileWatchKey *result; // r0  

  if ( node && a2 )  
    result = (struct FileWatchKey *)(node->wd - *(_DWORD *)(a2 + 4));  
  else  
    result = (struct FileWatchKey *)((char *)node - a2);  
  return result;  
}

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

3.3.2 is_same_inotify_filename函数

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

int __fastcall is_same_inotify_filename(struct FileWatchKey *node, const char *a2)  
{  
  int result; // r0  

  if ( node && a2 )  
    result = strcmp(node->name, *(const char **)a2);  
  else  
    result = (char *)node - a2;  
  return result;  
}

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

3.4 inotify_add_watchByPid

inotify_add_watchByPid函数将对应进程的mem与pagemap文件纳入到监控中,同时创建红黑树节点并插入到相应红黑树中。
int __fastcall inotify_add_watchByPid(int fatherPid)  
{  
  int fatherPid_1; // r7  
  int v3; // [sp+0h] [bp-140h]  
  char v4; // [sp+4h] [bp-13Ch]  
  char v5; // [sp+5h] [bp-13Bh]  
  char v6; // [sp+6h] [bp-13Ah]  
  char v7; // [sp+7h] [bp-139h]  
  char v8; // [sp+8h] [bp-138h]  
  char v9; // [sp+9h] [bp-137h]  
  char v10; // [sp+Ah] [bp-136h]  
  char v11; // [sp+Bh] [bp-135h]  
  char v12; // [sp+Ch] [bp-134h]  
  char v13; // [sp+Dh] [bp-133h]  
  char v14; // [sp+Eh] [bp-132h]  
  char v15; // [sp+10h] [bp-130h]  
  char v16; // [sp+11h] [bp-12Fh]  
  char v17; // [sp+12h] [bp-12Eh]  
  char v18; // [sp+13h] [bp-12Dh]  
  char v19; // [sp+14h] [bp-12Ch]  
  char v20; // [sp+15h] [bp-12Bh]  
  char v21; // [sp+16h] [bp-12Ah]  
  char v22; // [sp+17h] [bp-129h]  
  char v23; // [sp+18h] [bp-128h]  
  char v24; // [sp+19h] [bp-127h]  
  char v25; // [sp+1Ah] [bp-126h]  
  char v26; // [sp+1Bh] [bp-125h]  
  char v27; // [sp+1Ch] [bp-124h]  
  char v28; // [sp+1Dh] [bp-123h]  
  char v29; // [sp+1Eh] [bp-122h]  
  char v30; // [sp+1Fh] [bp-121h]  
  char v31; // [sp+20h] [bp-120h]  
  char v32; // [sp+21h] [bp-11Fh]  
  char v33; // [sp+22h] [bp-11Eh]  
  char procmemString; // [sp+24h] [bp-11Ch]  

  fatherPid_1 = fatherPid;  
  memset(&v3, 0, 0x10u);  
  v4 = -34;  
  v5 = -61;  
  v6 = -49;  
  v8 = -119;  
  v9 = -64;  
  BYTE1(v3) = 126;  
  v10 = -56;  
  HIWORD(v3) = -9085;  
  v7 = -125;  
  v11 = -125;  
  v13 = -55;  
  v12 = -63;  
  v14 = -63;  
  ((void (__fastcall *)(int *, signed int, signed int))DecodeString9)(&v3, 13, 0xD2);// /proc/%ld/mem  
  sprintf(&procmemString, (const char *)&v3, fatherPid_1);  
  inotify_add_watch_insert_node((int)&procmemString, 0xFFFu);  
  memset(&v15, 0, 0x14u);  
  v19 = -43;  
  v20 = -56;  
  v21 = -60;  
  v23 = -126;  
  v24 = -53;  
  v25 = -61;  
  v29 = -64;  
  v17 = -120;  
  v22 = -120;  
  v26 = -120;  
  v30 = -62;  
  v16 = 85;  
  v28 = -58;  
  v31 = -54;  
  v32 = -58;  
  v18 = -41;  
  v27 = -41;  
  v33 = -41;  
  ((void (__fastcall *)(char *, signed int, signed int))DecodeString9)(&v15, 17, 242);// /proc/%ld/pagemap  
  sprintf(&procmemString, &v15, fatherPid_1);  
  return inotify_add_watch_insert_node((int)&procmemString, 0xFFFu);  
}

该函数做了如下事情:
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 将对应文件纳入到监控中;

3.4.1 DecodeString9函数

字符串解密函数,如下:
char * DecodeString9(char *buf, int len, char key) 
{  
    int i; // r4  
    for(i = 0; i < len; i++)  
    {  
        buf[i]= buf[i + 2] ^key ^ buf[i+1];  
    }  
    buf[i]=0;  

    return buf;  
}

3.4.2 inotify_add_watch_insert_node函数

1.    signed int __fastcall inotify_add_watch_insert_node(int procmemString, uint32_t mask_2)  
2.    {  
3.      char *procmemString_1_1; // r6  
4.      int procmemString_1; // r4  
5.      const char *v4; // r1  
6.      int fd; // r0  
7.      int v6; // r4  
8.      int v7; // r5  
9.      uint32_t mask; // [sp+4h] [bp-1Ch]  
10.      
11.      procmemString_1 = procmemString;  
12.      mask = mask_2;  
13.      g_fileWatch_errno = 0;  
14.      for ( g_watchIndex = 0; ; ++g_watchIndex )  
15.      {  
16.        v4 = *(const char **)(4 * g_watchIndex + procmemString_1);  
17.        if ( !v4 )  
18.          return 1;  
19.        fd = inotify_add_watch(g_inotify_init, v4, mask);  
20.        g_fileWatch_fd = fd;  
21.        if ( fd < 0 )  
22.          break;  
23.        if ( !JudeFileIsDir(*(char **)(4 * g_watchIndex + procmemString_1))  
24.          || (v7 = *(_DWORD *)(4 * g_watchIndex + procmemString_1),  
25.              *(_BYTE *)(v7 + strlen(*(_DWORD *)(4 * g_watchIndex + procmemString_1)) - 1) == '/') )  
26.        {  
27.          procmemString_1_1 = strdup(*(const char **)(4 * g_watchIndex + procmemString_1));// 是文件或者是目录同时最后一个字符是\   
28.        }  
29.        inotifyList_user_add_node(g_fileWatch_fd, procmemString_1_1);  
30.        free(procmemString_1_1);  
31.      }  
32.      v6 = 0;  
33.      if ( fd == -1 )  
34.        g_fileWatch_errno = *(_DWORD *)_errno(-1);  
35.      return v6;  
36.    }

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

3.4.2.1 JudeFileIsDir函数

该函数去混淆后如下:
bool  JudeFileIsDir(char *file)  
{  
  bool result; // r0  
  if(lstat(file, &g_fileStatStruct)<0)  
      return false;  
  return (g_fileStatStruct.st_mode & 0xF000) - 0x4000 <= 0;    
}

3.4.2.2 inotifyList_user_add_node函数

_DWORD *__fastcall inotifyList_user_add_node(int fd, _DWORD *procmemString)  
{  
  _DWORD *inotifyfileKeyBuf; // r4  
  const char *v3; // r5  
  int v4; // r6  

  inotifyfileKeyBuf = 0;  
  if ( fd > 0 )  
  {  
    inotifyfileKeyBuf = procmemString;  
    if ( procmemString )  
    {  
      v3 = (const char *)procmemString;  
      v4 = fd;  
      inotifyfileKeyBuf = (_DWORD *)getinotifyListByWDnode(fd);  
      if ( !inotifyfileKeyBuf )  
      {  
        inotifyfileKeyBuf = calloc(1u, 0x40u);  
        inotifyfileKeyBuf[1] = v4;  
        *inotifyfileKeyBuf = strdup(v3);  
        insertNewNode((int)inotifyfileKeyBuf, (int)g_fileWatch_wd_root);  
        insertNewNode((int)inotifyfileKeyBuf, (int)g_fileWatch_name_root);  
      }  
    }  
  }  
  return inotifyfileKeyBuf;  
}

本函数有如下步骤:

1、调用getinotifyListByWDnode判断对应fd是否已经在红黑树中了;
2、如果在,则直接返回;
3、如果不在则调用insertNewNode插入到对应红黑树中。

下面我们看一getinotifyListByWDnode函数

int __fastcall getinotifyListByWDnode(int node_wd, struct RBRoot *rbroot)  
{  
  int result; // r0  
  int v3; // r0  

  if ( rbroot  
    && (void **)rbroot->root != &g_inotify_node_NoValidFlag  
    && (query_insert_node(0, node_wd, rbroot), (void **)v3 != &g_inotify_node_NoValidFlag) )  
  {  
    result = *(_DWORD *)(v3 + 0x10);  
  }  
  else  
  {  
    result = 0;  
  }  
  return result;  
}

getinotifyListByWDnode调用query_insert_node来进行查询。

void __fastcall query_insert_node(int createFlag, int inotifyfileKeyBuf, struct RBRoot *rbroot)  
{  
  struct RBRoot *rbroot_1; // r7  
  signed int find; // r5  
  struct RBTree *curNode; // r4  
  void **fatherNode; // r6  
  int result; // r0  
  struct RBTree *tempNode; // r3  
  struct RBTree *newNode; // r5  
  struct RBTree *newNode_1; // r4  
  struct RBTree *rootHead; // r3  
  struct RBTree *parent; // r6  
  struct RBTree *gparent; // r1  
  struct RBTree *v14; // r2  
  struct RBTree *v15; // r1  
  struct RBTree *v16; // [sp+4h] [bp-24h]  
  struct RBTree *root; // [sp+4h] [bp-24h]  
  int inotifyfileKeyBuf_1; // [sp+8h] [bp-20h]  
  int createFlag_1; // [sp+Ch] [bp-1Ch]  
  int v20; // [sp+18h] [bp-10h]  

  rbroot_1 = rbroot;  
  find = 0;  
  curNode = rbroot->root;  
  fatherNode = &g_inotify_node_NoValidFlag;  
  createFlag_1 = createFlag;  
  inotifyfileKeyBuf_1 = inotifyfileKeyBuf;  
  while ( curNode != (struct RBTree *)&g_inotify_node_NoValidFlag )  
  {  
    if ( find )  
      goto LABEL_35;  
    result = ((int (__fastcall *)(int, struct FileWatchKey *, int))rbroot_1->fun)(  
               inotifyfileKeyBuf_1,  
               curNode->keybuf,  
               rbroot_1->const_0);  
    if ( result >= 0 )  
    {  
      if ( result )  
      {  
        tempNode = curNode->right;  // 没找到,目标节点比当前节点大  
      }  
      else  
      {  
        tempNode = curNode;        // 找到了  
        find = 1;  
      }  
    }  
    else  
    {  
      tempNode = curNode->left;    // 没找到,比当前节点小  
    }  
    fatherNode = (void **)&curNode->left;  
    curNode = tempNode;  
  }  
  if ( find || !createFlag_1 || (newNode = (struct RBTree *)malloc(0x14u)) == 0 )  
LABEL_35:  
    JUMPOUT(__CS__, v20);          // 找到了或没找到但是不创建新节点,则返回  
  newNode->parent = (struct RBTree *)fatherNode;// 创建新节点,初始化  
  newNode->keybuf = (struct FileWatchKey *)inotifyfileKeyBuf_1;  
  if ( fatherNode == &g_inotify_node_NoValidFlag )  
  {  
    rbroot_1->root = newNode;     // 更新根节点  
  }  
  else if ( ((int (__fastcall *)(int, void *, int))rbroot_1->fun)(inotifyfileKeyBuf_1, fatherNode[4], rbroot_1->const_0) >= 0 )  
  {  
    fatherNode[1] = newNode;   // 比父节点大 更新父节点右节点  
  }  
  else  
  {  
    *fatherNode = newNode;      // 比父节点小更新父节点的右节点  
  }  
  newNode_1 = newNode;  
  newNode->left = (struct RBTree *)&g_inotify_node_NoValidFlag;// 初始化新节点  
  newNode->right = (struct RBTree *)&g_inotify_node_NoValidFlag;  
  newNode->color = 1;          // 先设置为红色  
  while ( 1 )  
  {  
    while ( 1 )  
    {  
      rootHead = rbroot_1->root;  
      if ( newNode_1 == rootHead || (parent = newNode_1->parent, parent->color != 1) )  
      {  
        rootHead->color = 0;// 新节点是跟节点 或者新节点的父节点颜色不是红色,则将当前节点设置成黑色并退出  
        goto LABEL_35;  
      }  
      gparent = parent->parent;  
      v14 = gparent->left;  
      if ( parent == gparent->left )  
        break;  
      if ( v14->color == 1 )  
      {  
        parent->color = 0;  
        v14->color = 0;  
        newNode_1->parent->parent->color = 1;  
LABEL_31:  
        newNode_1 = newNode_1->parent->parent;  
      }  
      else  
      {  
            root = (struct RBTree *)&rbroot_1->root;  
            if ( newNode_1 == parent->left )  
            {  
              rbtree_left_rotate(root, parent);  
              newNode_1 = parent;  
            }  
            newNode_1->parent->color = 0;  
            newNode_1->parent->parent->color = 1;  
            rbtree_right_rotate(root, newNode_1->parent->parent);  
          }  
        }  
        v15 = gparent->right;  
        if ( v15->color == 1 )  
        {  
          parent->color = 0;  
          v15->color = 0;  
          newNode_1->parent->parent->color = 1;  
          goto LABEL_31;  
        }  
        v16 = (struct RBTree *)&rbroot_1->root;  
        if ( newNode_1 == parent->right )  
        {  
          rbtree_right_rotate(v16, parent);  
          newNode_1 = parent;  
        }  
        newNode_1->parent->color = 0;  
        newNode_1->parent->parent->color = 1;  
        rbtree_left_rotate(v16, newNode_1->parent->parent);  
      }  
    } 
}

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

 

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

int __fastcall insertNewNode(int inotifyfileKeyBuf, int a2)  
{  
  int result; // r0  
  int v3; // r0  

  if ( a2 && (query_insert_node(1, inotifyfileKeyBuf, (struct RBRoot *)a2), (void **)v3 != &g_inotify_node_NoValidFlag) )  
    result = *(_DWORD *)(v3 + 16);  
  else  
    result = 0;  
  return result;  
}

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

3.5 watchAllTask_threadProc线程入口函数

void __fastcall __noreturn watchAllTask_threadProc(int *pfatherPid)  
{  
  struct dirent *v1; // r5  
  const char *v2; // r5  
  int v3; // r0  
  int threadID; // r0  
  DIR *dirp; // [sp+4h] [bp-2CCh]  
  int pfatherPid_1; // [sp+Ch] [bp-2C4h]  
  int dot; // [sp+14h] [bp-2BCh]  
  int dotdot; // [sp+18h] [bp-2B8h]  
  char v9; // [sp+1Ch] [bp-2B4h]  
  char v10; // [sp+20h] [bp-2B0h]  
  char v11; // [sp+21h] [bp-2AFh]  
  char v12; // [sp+22h] [bp-2AEh]  
  char v13; // [sp+23h] [bp-2ADh]  
  char v14; // [sp+24h] [bp-2ACh]  
  char v15; // [sp+25h] [bp-2ABh]  
  void (__noreturn *pthread_exit)(); // [sp+28h] [bp-2A8h]  
  char v17; // [sp+38h] [bp-298h]  
  __int16 v18; // [sp+48h] [bp-288h]  
  char v19; // [sp+A0h] [bp-230h]  
  char v20; // [sp+A1h] [bp-22Fh]  
  char v21; // [sp+A2h] [bp-22Eh]  
  char v22; // [sp+A3h] [bp-22Dh]  
  char v23; // [sp+A4h] [bp-22Ch]  
  char v24; // [sp+A5h] [bp-22Bh]  
  char v25; // [sp+A6h] [bp-22Ah]  
  char v26; // [sp+A7h] [bp-229h]  
  char v27; // [sp+A8h] [bp-228h]  
  char v28; // [sp+A9h] [bp-227h]  
  char v29; // [sp+AAh] [bp-226h]  
  char v30; // [sp+ABh] [bp-225h]  
  char v31; // [sp+ACh] [bp-224h]  
  char v32; // [sp+ADh] [bp-223h]  
  char v33; // [sp+AEh] [bp-222h]  
  char v34; // [sp+AFh] [bp-221h]  
  char v35; // [sp+B0h] [bp-220h]  
  char proctaskString; // [sp+B4h] [bp-21Ch]  
  char v37; // [sp+1B4h] [bp-11Ch]  

  pfatherPid_1 = *pfatherPid;  
  free(pfatherPid);  
  memset(&pthread_exit, 0, 0x10u);  
  pthread_exit = pthread_exit_0;  
  sigaction(10, (const struct sigaction *)&pthread_exit, 0);  
  memset(&v19, 0, 0x12u);  
  v22 = 30;  
  v23 = 28;  
  v24 = 1;  
  v25 = 13;  
  v27 = 75;  
  v28 = 2;  
  v29 = 10;  
  v31 = 26;  
  v33 = 29;  
  v20 = -88;  
  v34 = 5;  
  v21 = 65;  
  v26 = 65;  
  v30 = 65;  
  v32 = 15;  
  v35 = 65;  
  ((void (__fastcall *)(char *))DecodeString9)(&v19);// /proc/%ld/task/  
  sprintf(&proctaskString, &v19, pfatherPid_1);  
  while ( 1 )  
  {  
    do  
      dirp = opendir(&proctaskString);  
    while ( !dirp );  
    while ( 1 )  
    {  
      v1 = readdir(dirp);  
      if ( !v1 )  
        break;  
      dot = 0;  
      *(_WORD *)((char *)&dot + 1) = -25275;  
      ((void (__fastcall *)(int *, signed int, signed int))DecodeString9)(&dot, 1, 246);// .  
      dotdot = 0;  
      *(_WORD *)((char *)&dotdot + 1) = -21672;  
      v2 = &v1->d_name[8];  
      v9 = 0;  
      HIBYTE(dotdot) = -85;  
      ((void (__fastcall *)(int *, signed int, signed int))DecodeString9)(&dotdot, 2, 221);// ..  
      if ( strcmp(v2, (const char *)&dot) )  
      {  
        if ( strcmp(v2, (const char *)&dotdot) )  
        {  
          memset(&v37, 0, 0x100u);  
          memset(&v10, 0, 7u);  
          v11 = 23;  
          v12 = -127;  
          v14 = -127;  
          v13 = -41;  
          v15 = -41;  
          ((void (__fastcall *)(char *, signed int, signed int))DecodeString9)(&v10, 4, 179);// %s%s  
          sprintf(&v37, &v10, &proctaskString, v2);// /proc/15557/task/15557  
          if ( lstat(&v37, (struct stat *)&v17) != -1 && (v18 & 0xF000) == 0x4000 )  
          {  
            v3 = atoi(v2);  
                inotify_add_watchByPid(v3);  
                threadID = atoi(v2);  
                inotify_add_watchByTid(pfatherPid_1, threadID);  
              }  
            }  
          }  
        }  
        closedir(dirp);  
        sleep(2u);  
      }  
    }  
}

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。

思考:从上面可以看到线程会持续的对应用的所有线程下的mem与pagemap文件进行监控,是否可以在步骤13直接线程结束?

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

3.5.1 inotify_add_watchByTid函数

int __fastcall inotify_add_watchByTid(int fatherpid, int tid)  
{  
  int fatherpid_1; // ST00_4  
  int tid_1; // ST04_4  
  int v4; // ST00_4  
  int v5; // ST04_4  
  char s; // [sp+8h] [bp-158h]  
  char v8; // [sp+9h] [bp-157h]  
  char v9; // [sp+Ah] [bp-156h]  
  char v10; // [sp+Bh] [bp-155h]  
  char v11; // [sp+Ch] [bp-154h]  
  char v12; // [sp+Dh] [bp-153h]  
  char v13; // [sp+Eh] [bp-152h]  
  char v14; // [sp+Fh] [bp-151h]  
  char v15; // [sp+10h] [bp-150h]  
  char v16; // [sp+11h] [bp-14Fh]  
  char v17; // [sp+12h] [bp-14Eh]  
  char v18; // [sp+13h] [bp-14Dh]  
  char v19; // [sp+14h] [bp-14Ch]  
  char v20; // [sp+15h] [bp-14Bh]  
  char v21; // [sp+16h] [bp-14Ah]  
  char v22; // [sp+17h] [bp-149h]  
  char v23; // [sp+18h] [bp-148h]  
  char v24; // [sp+19h] [bp-147h]  
  char v25; // [sp+1Ah] [bp-146h]  
  char v26; // [sp+1Bh] [bp-145h]  
  char v27; // [sp+1Ch] [bp-144h]  
  char v28; // [sp+1Dh] [bp-143h]  
  char v29; // [sp+1Eh] [bp-142h]  
  char v30; // [sp+1Fh] [bp-141h]  
  char v31; // [sp+24h] [bp-13Ch]  
  char v32; // [sp+25h] [bp-13Bh]  
  char v33; // [sp+26h] [bp-13Ah]  
  char v34; // [sp+27h] [bp-139h]  
  char v35; // [sp+28h] [bp-138h]  
  char v36; // [sp+29h] [bp-137h]  
  char v37; // [sp+2Ah] [bp-136h]  
  char v38; // [sp+2Bh] [bp-135h]  
  char v39; // [sp+2Ch] [bp-134h]  
  char v40; // [sp+2Dh] [bp-133h]  
  char v41; // [sp+2Eh] [bp-132h]  
  char v42; // [sp+2Fh] [bp-131h]  
  char v43; // [sp+30h] [bp-130h]  
  char v44; // [sp+31h] [bp-12Fh]  
  char v45; // [sp+32h] [bp-12Eh]  
  char v46; // [sp+33h] [bp-12Dh]  
  char v47; // [sp+34h] [bp-12Ch]  
  char v48; // [sp+35h] [bp-12Bh]  
  char v49; // [sp+36h] [bp-12Ah]  
  char v50; // [sp+37h] [bp-129h]  
  char v51; // [sp+38h] [bp-128h]  
  char v52; // [sp+39h] [bp-127h]  
  char v53; // [sp+3Ah] [bp-126h]  
  char v54; // [sp+3Bh] [bp-125h]  
  char v55; // [sp+3Ch] [bp-124h]  
  char v56; // [sp+3Dh] [bp-123h]  
  char v57; // [sp+3Eh] [bp-122h]  
  char v58; // [sp+3Fh] [bp-121h]  
  char v59; // [sp+44h] [bp-11Ch]  

  fatherpid_1 = fatherpid;  
  tid_1 = tid;  
  memset(&s, 0, 0x19u);  
  v10 = 5;  
  v11 = 7;  
  v19 = 1;  
  v12 = 26;  
  v8 = -4;  
  v20 = 20;  
  v17 = 17;  
  v26 = 17;  
  v9 = 90;  
  v14 = 90;  
  v18 = 90;  
  v21 = 6;  
  v23 = 90;  
  v27 = 90;  
  v15 = 80;  
  v16 = 25;  
  v24 = 80;  
  v25 = 25;  
  v29 = 16;  
  v13 = 22;  
  v22 = 30;  
  v28 = 24;  
  v30 = 24;  
  ((void (__fastcall *)(char *))DecodeString9)(&s);  
  sprintf(&v59, &s, fatherpid_1, tid_1, fatherpid_1, tid_1);// /proc/16709/task/16709/mem  
  inotify_add_watch_insert_node((int)&v59, 0xFFFu);  
  memset(&v31, 0, 0x1Du);  
  v35 = -9;  
  v36 = -22;  
  v37 = -26;  
  v32 = 99;  
  v40 = -23;  
  v45 = -10;  
  v33 = -86;  
  v38 = -86;  
  v42 = -86;  
      v47 = -86;  
      v51 = -86;  
      v41 = -31;  
      v46 = -18;  
      v54 = -30;  
      v43 = -15;  
      v49 = -23;  
      v55 = -32;  
      v34 = -11;  
      v44 = -28;  
      v50 = -31;  
      v52 = -11;  
      v53 = -28;  
      v57 = -28;  
      v58 = -11;  
      v56 = -24;  
      v39 = -96;  
      v48 = -96;  
      ((void (__fastcall *)(char *, signed int, signed int))DecodeString9)(&v31, 26, 230);  
      sprintf(&v59, &v31, v4, v5);  
      return inotify_add_watch_insert_node((int)&v59, 0xFFFu);  
    }  
}

这个函数相对比较简单。

3.6 里程碑

至此将目标文件纳入到监控中的相关处理已经分析完了,下面看发生相关事件是的处理流程。

3.7 read_filewatch_event函数

int __fastcall read_filewatch_event1(int a1_FF, int const_1)  
{  
  char *v2; // r1  
  char *v3; // r3  
  struct timeval *timeout; // r4  
  int inotify_init; // r0  
  int v7; // r0  
  int v8; // r3  
  int a1_FF_1; // [sp+8h] [bp-20h]  
  int const_1_1; // [sp+Ch] [bp-1Ch]  

  if ( const_1 <= 0 )  
    return 0;  
  a1_FF_1 = a1_FF;  
  const_1_1 = const_1;  
  setjmp((struct __jmp_buf_tag *)&unk_53D04);  
  g_fileWatch_errno = 0;  
  if ( dword_53E04 )  
  {  
    if ( dword_53E04 <= dword_53E08 - 16 )  
    {  
      v2 = (char *)&dword_53E0C + dword_53E04;  
      dword_63E0C = (int)&dword_53E0C + dword_53E04;  
      v3 = (char *)&(*(struct inotify_event **)((char *)&dword_53E0C + dword_53E04 + 12))[1] + dword_53E04;  
      dword_53E04 = (int)v3;  
      if ( v3 == (char *)dword_53E08 )  
      {  
        dword_53E04 = 0;  
      }  
      else if ( (signed int)v3 > dword_53E08 )  
      {  
        dword_53E08 = (char *)&dword_53E0C + dword_53E08 - v2;  
        memcpy(&dword_53E0C, v2, dword_53E08);  
        return read_filewatch_event1(a1_FF_1, const_1_1);  
      }  
      if ( g_inotify_init_flag1 )  
        p9E01CAAA70B3E111F16A18AB1BC2AB55((int *)v2);  
      return dword_63E0C;  
    }  
  }  
  else  
  {  
    dword_53E08 = dword_53E04;  
  }  
  g_FF = a1_FF_1;  
  timeout = (struct timeval *)&g_FF;  
  dword_53D00 = 0;  
  if ( a1_FF_1 <= 0 )  
    timeout = 0;  
  dword_63E10 = (int)timeout;  
  memset(&g_fds, 0, 0x80u);  
  inotify_init = g_inotify_init;  
  *((_DWORD *)&unk_63DA8 + (g_inotify_init >> 5) + 0x1B) = 1 << (g_inotify_init & 0x1F);  
  v7 = select(inotify_init + 1, (fd_set *)&g_fds, 0, 0, timeout);//  //监控fd的事件。当有事件发生时,返回值>0  
  g_slect_returnValue = v7;  
  if ( v7 < 0 )  
    goto LABEL_21;  
  if ( !v7 )  
    return 0;  
  while ( 1 )  
  {  
    v7 = ioctl(g_inotify_init, 0x541Bu, &g_fileWatch_event_MaxLen);  
    g_slect_returnValue = v7;  
    if ( v7 )  
      break;  
    if ( g_fileWatch_event_MaxLen >= (unsigned int)(16 * const_1_1) )  
      goto LABEL_20;  
  }  
  if ( v7 == -1 )  
    goto LABEL_21;  
LABEL_20:  
  v7 = read(g_inotify_init, &(&dword_53E0C)[4 * dword_53E08], 0x10000 - dword_53E08);  
  g_fileWatch_event_readLen = v7;  
  if ( v7 < 0 )  
  {  
LABEL_21:  
    g_fileWatch_errno = *(_DWORD *)_errno(v7);  
    return 0;  
  }  
  if ( !v7 )  
    return 0;  
  dword_53E08 += v7;  
  dword_63E0C = (int)&dword_53E0C;  
  v8 = dword_53E18 + 0x10;  
  if ( dword_53E18 + 0x10 == dword_53E08 )  
    v8 = 0;  
  dword_53E04 = v8;  
  if ( g_inotify_init_flag1 )  
    p9E01CAAA70B3E111F16A18AB1BC2AB55((int *)&dword_53E0C);  
  return dword_63E0C;  
}

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

当发生事件时,就开始进行事件处理流程,首先调用filewatch_Delete清除watch。

3.8 filewatch_Delete函数

int __fastcall filewatch_Delete(int fatherPid)  
{  
  int fatherPid_1; // r7  
  int v3; // [sp+0h] [bp-140h]  
  char v4; // [sp+4h] [bp-13Ch]  
  char v5; // [sp+5h] [bp-13Bh]  
  char v6; // [sp+6h] [bp-13Ah]  
  char v7; // [sp+7h] [bp-139h]  
  char v8; // [sp+8h] [bp-138h]  
  char v9; // [sp+9h] [bp-137h]  
  char v10; // [sp+Ah] [bp-136h]  
  char v11; // [sp+Bh] [bp-135h]  
  char v12; // [sp+Ch] [bp-134h]  
  char v13; // [sp+Dh] [bp-133h]  
  char v14; // [sp+Eh] [bp-132h]  
  char v15; // [sp+10h] [bp-130h]  
  char v16; // [sp+11h] [bp-12Fh]  
  char v17; // [sp+12h] [bp-12Eh]  
  char v18; // [sp+13h] [bp-12Dh]  
  char v19; // [sp+14h] [bp-12Ch]  
  char v20; // [sp+15h] [bp-12Bh]  
  char v21; // [sp+16h] [bp-12Ah]  
  char v22; // [sp+17h] [bp-129h]  
  char v23; // [sp+18h] [bp-128h]  
  char v24; // [sp+19h] [bp-127h]  
  char v25; // [sp+1Ah] [bp-126h]  
  char v26; // [sp+1Bh] [bp-125h]  
  char v27; // [sp+1Ch] [bp-124h]  
  char v28; // [sp+1Dh] [bp-123h]  
  char v29; // [sp+1Eh] [bp-122h]  
  char v30; // [sp+1Fh] [bp-121h]  
  char v31; // [sp+20h] [bp-120h]  
  char v32; // [sp+21h] [bp-11Fh]  
  char v33; // [sp+22h] [bp-11Eh]  
  char v34; // [sp+24h] [bp-11Ch]  

  fatherPid_1 = fatherPid;  
  memset(&v3, 0, 0x10u);  
  v4 = -75;  
  v5 = -88;  
  v6 = -92;  
  v8 = -30;  
  v9 = -85;  
  BYTE1(v3) = 62;  
  v10 = -93;  
  HIWORD(v3) = -18456;  
  v7 = -24;  
  v11 = -24;  
  v13 = -94;  
  v12 = -86;  
  v14 = -86;  
  ((void (__fastcall *)(int *, signed int, signed int))DecodeString9)(&v3, 13, 249);  
  sprintf(&v34, (const char *)&v3, fatherPid_1);// /proc/1340/mem  
  filewatch_DeleteByFile((int)&v34);  
  memset(&v15, 0, 0x14u);  
  v19 = 10;  
  v20 = 23;  
  v21 = 27;  
  v23 = 93;  
  v24 = 20;  
  v25 = 28;  
  v29 = 31;  
  v17 = 87;  
  v22 = 87;  
  v26 = 87;  
  v30 = 29;  
  v16 = -111;  
  v28 = 25;  
  v31 = 21;  
  v32 = 25;  
  v18 = 8;  
  v27 = 8;  
  v33 = 8;  
  ((void (__fastcall *)(char *, signed int, signed int))DecodeString9)(&v15, 17, 233);  
  sprintf(&v34, &v15, fatherPid_1);  
  return filewatch_DeleteByFile((int)&v34);  
}

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

可能存在问题:只删除了进程的对应watch,对于/proc/tid/相关并没有删除。同时task目录下的也没有删除。
下面看一下filewatch_DeleteByFile函数。

3.8.1 filewatch_DeleteByFile函数

1.    filewatch_DeleteNode(keybuf, g_fileWatch_wd_root);  
2.    filewatch_DeleteNode(keybuf, g_fileWatch_name_root); 
3.    filewatch_rm(keybuf)  
4.    freeKeyBuf(keybuf);

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

 

函数filewatch_DeleteNode如下:

nt __fastcall filewatch_DeleteNode(struct FileWatchKey *keybuf, struct RBRoot *rbroot)  

 struct RBRoot *v3; // r6  
 int v4; // r0  
 int v5; // r7  
 void **v6; // r5  
 void **v7; // r4  
 void **v8; // r3  
 struct RBTree **v9; // r2  
 struct RBTree *v10; // r1  
 struct RBTree *v11; // r2  
 struct RBTree *v12; // r3  
 struct RBTree *v13; // r2  
 int v14; // [sp+4h] [bp-1Ch]  

 if ( !rbroot )  
   return 0;  
 v3 = rbroot;  
 query_insert_node(0, (int)keybuf, rbroot);  
 v5 = v4;  
 if ( (void **)v4 == &g_inotify_node_NoValidFlag )  
   return 0;  
 v6 = (void **)v4;  
 v14 = *(_DWORD *)(v4 + 16);  
 if ( *(void ***)v4 != &g_inotify_node_NoValidFlag && *(void ***)(v4 + 4) != &g_inotify_node_NoValidFlag )  
   v6 = sub_28F7C((void **)v4);  
 v7 = (void **)*v6;  
 if ( *v6 == &g_inotify_node_NoValidFlag )  
   v7 = (void **)v6[1];  
 v7[2] = v6[2];  
 v8 = (void **)v6[2];  
 if ( v8 == &g_inotify_node_NoValidFlag )  
 {  
   v3->root = (struct RBTree *)v7;  
 }  
 else if ( v6 == *v8 )  
 {  
   *v8 = v7;  
 }  
 else  
 {  
   v8[1] = v7;  
 }  
 if ( v6 != (void **)v5 )  
   *(_DWORD *)(v5 + 16) = v6[4];  
 if ( !v6[3] )  
 {  
   while ( 1 )  
   {  
     if ( v7 == (void **)v3->root || v7[3] )  
     {  
       v7[3] = 0;  
       break;  
     }  
     v9 = (struct RBTree **)v7[2];  
     v10 = *v9;  
     if ( v7 == (void **)*v9 )  
     {  
       v10 = v9[1];  
       if ( v10->color == 1 )  
       {  
         v10->color = 0;  
         *((_DWORD *)v7[2] + 3) = 1;  
         rbtree_right_rotate((struct RBTree *)&v3->root, (struct RBTree *)v7[2]);  
         v10 = (struct RBTree *)*((_DWORD *)v7[2] + 1);  
       }  
       v11 = v10->right;  
       if ( v10->left->color || v11->color )  
       {  
         if ( !v11->color )  
         {  
           v10->left->color = 0;  
           v10->color = 1;  
           rbtree_left_rotate((struct RBTree *)&v3->root, v10);  
           v10 = (struct RBTree *)*((_DWORD *)v7[2] + 1);  
         }  
         v10->color = *((_DWORD *)v7[2] + 3);  
         *((_DWORD *)v7[2] + 3) = 0;  
         v10->right->color = 0;  
         rbtree_right_rotate((struct RBTree *)&v3->root, (struct RBTree *)v7[2]);  
         goto LABEL_35;  
       }  
ABEL_31:  
       v10->color = 1;  
       v7 = (void **)v7[2];  
     }  
     else  
     {  
       if ( v10->color == 1 )  
       {  
         v10->color = 0;  
         *((_DWORD *)v7[2] + 3) = 1;  
         rbtree_left_rotate((struct RBTree *)&v3->root, (struct RBTree *)v7[2]);  
         v10 = *(struct RBTree **)v7[2];  
       }  
       v12 = v10->right;  
       v13 = v10->left;  
       if ( !v12->color && !v13->color )  
         goto LABEL_31;  
        if ( !v13->color )  
        {  
          v12->color = 0;  
          v10->color = 1;  
          rbtree_right_rotate((struct RBTree *)&v3->root, v10);  
          v10 = *(struct RBTree **)v7[2];  
        }  
        v10->color = *((_DWORD *)v7[2] + 3);  
        *((_DWORD *)v7[2] + 3) = 0;  
        v10->left->color = 0;  
        rbtree_left_rotate((struct RBTree *)&v3->root, (struct RBTree *)v7[2]);  
LABEL_35:  
        v7 = (void **)&v3->root->left;  
      }  
    }  
  }  
  free(v6);  
  return v14;  
}

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

igned int __fastcall filewatch_rm(struct FileWatchKey *keybuf)  

 int v1; // r1  
 int v2; // r0  
 signed int v3; // r3  

 v1 = keybuf->wd;  
 g_fileWatch_errno = 0;  
 v2 = inotify_rm_watch(g_inotify_init, v1);  
 v3 = 1;  
 if ( v2 < 0 )  
 {  
   v3 = 0;  
   g_fileWatch_errno = v2;  
 }  
 return v3;

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

void __fastcall freeKeyBuf(void *ptr)  
{  
  void *v1; // r4  
  void *v2; // r0  

  v1 = ptr;  
  v2 = *(void **)ptr;  
  if ( v2 )  
    free(v2);  
  free(v1);  
}

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

下面将开始进行终止线程和父进程相关操作。

3.9 进程线程终止

1.    pthread_kill(newthread, 10);  
2.    killProcess(fatherPid, 9);

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

unsigned int __fastcall killProcess(__pid_t a1, int a2)  
{  
  unsigned int result; // r0  

  result = linux_eabi_syscall(__NR_kill, a1, a2);  

  return result;  
}

4 bypass

其实 bypass文件监控的方法很多,具有可移植性的方法的是HOOK inotify_add_watch

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


[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

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



oooAooo

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