首页
社区
课程
招聘
[原创]某公司DLP产品通过驱动注入DLL分析
发表于: 2016-2-27 17:22 22660

[原创]某公司DLP产品通过驱动注入DLL分析

2016-2-27 17:22
22660

最近在分析某公司DLP产品,里边文档控制相关功能,出于好奇分析了一下原理。
      应用层的权限控制一般通过全局Hook注入DLL进行权限控制,使用工具PCHunder发现,除了WH_KEYBOARD_LL消息Hook,没有其它消息Hook,最后通过PCHunder发现是通过驱动层进行设置PsSetCreateProcessNotifyRoutine回调注入Shellcode实现。
      具体IDA分析如下图:

bool __stdcall sub_15D40(HANDLE ProcessHandle, wchar_t *wzDllPath)
{
  int v3; // [sp+0h] [bp-488h]@21
  int v4; // [sp+4h] [bp-484h]@11
  char v5; // [sp+8h] [bp-480h]@11
  int v6; // [sp+14h] [bp-474h]@12
  int v7; // [sp+18h] [bp-470h]@13
  unsigned __int8 v8; // [sp+240h] [bp-248h]@2
  int v9; // [sp+241h] [bp-247h]@2
  unsigned __int8 v10; // [sp+245h] [bp-243h]@2
  int v11; // [sp+246h] [bp-242h]@2
  unsigned __int16 v12; // [sp+24Ah] [bp-23Eh]@2
  int v13; // [sp+24Ch] [bp-23Ch]@2
  int v14; // [sp+250h] [bp-238h]@2
  int v15; // [sp+254h] [bp-234h]@3
  __int16 v16; // [sp+25Dh] [bp-22Bh]@5
  __int16 v17; // [sp+25Fh] [bp-229h]@5
  int v18; // [sp+261h] [bp-227h]@5
  wchar_t v19; // [sp+265h] [bp-223h]@5
  int v20; // [sp+46Dh] [bp-1Bh]@5
  int v21; // [sp+471h] [bp-17h]@5
  unsigned __int8 v22; // [sp+478h] [bp-10h]@8
  int v23; // [sp+479h] [bp-Fh]@11
  bool v24; // [sp+483h] [bp-5h]@1
  int v25; // [sp+484h] [bp-4h]@1

  v24 = 0;
  v25 = (int)MyAllocateVirtualMemory(ProcessHandle, 0x2BBu, 0);
  if ( v25 )
  {
    v8 = 0xB8u;                                  // MOV EAX,XXXXXXXX
    v9 = v25;
    v10 = 0xB9u;                                // MOV ECX,XXXXXXXX
    v11 = v25 + 565;
    v12 = 0xD1FFu;                            // CALL ECX
    v13 = 0x4C69636D;                     // 特征码
    v14 = 0;
    v15 = pfnNtTestAlert ? pfnNtTestAlert : sub_15570(ProcessHandle);
    v16 = 2 * wcslen(wzDllPath);                // UNICODE_STRING ++0 Length
    v17 = v16 + 2;                                    // UNICODE_STRING ++2 MaxmumLength
    v18 = v25 + 0x25;                              // UNICODE_STRING ++4 Buffer
    wcscpy(&v19, wzDllPath);                    // 将wzDllPath拷贝进ShellCode
    v20 = pfnNtProtectVirtualMemory;
    v21 = pfnLdrLoadDll;
    if ( v15 )
    {
      if ( MyWriteVirtualMemory((int)ProcessHandle, v25, (int)&v8, 566)
        && MyWriteVirtualMemory((int)ProcessHandle, v25 + 0x235, (int)sub_10420, 133)
        && MyReadVirtualMemory((int)ProcessHandle, v15, (int)&v22, 5)// 读取pfnNtTestAlert函数前5个字节备份到ShellCode中
        && MyWriteVirtualMemory((int)ProcessHandle, v25 + 0x18, (int)&v22, 5) )
      {
        if ( v22 == 0xE9 )                      // 构造要插入dll的链表ShellCode
        {
          v4 = v15 + v23 + 5;
          if ( MyReadVirtualMemory((int)ProcessHandle, v4, (int)&v5, 566) && v6 == 0x4C69636D )
          {
            while ( v7 )
            {
              v4 = v7;
              if ( !MyReadVirtualMemory((int)ProcessHandle, v7, (int)&v5, 566) || v6 != 0x4C69636D )
              {
                v4 = 0;
                break;
              }
            }
            if ( v4 )
            {
              v7 = v25;
              v24 = MyWriteVirtualMemory((int)ProcessHandle, v4, (int)&v5, 566);
            }
          }
        }
        if ( !v24 && MyProtectVirutalMemory((int)ProcessHandle, v15, 5, 64, (int)&v3) )// 修改pfnNtTestAlert函数前面5个字节为jmp XXXX,其中XXXX为Shellcode入口地址
        {
          v22 = 0xE9u;
          v23 = v25 - v15 - 5;
          MyWriteVirtualMemory((int)ProcessHandle, v15, (int)&v22, 5);
          MyProtectVirutalMemory((int)ProcessHandle, v15, 5, v3, (int)&v3);
          v24 = 1;
        }
      }
    }
  }
  return v24;
}
seg000:00000000 seg000          segment byte public 'CODE' use32
seg000:00000000                 assume cs:seg000
seg000:00000000                 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
seg000:00000000                 mov     eax, 40000h
seg000:00000005
seg000:00000005 loc_5:
seg000:00000005                 mov     ecx, 40235h
seg000:0000000A                 call    ecx
seg000:0000000A ; ---------------------------------------------------------------------------
seg000:0000000C                 dd 4C69636Dh            ; 特征码
seg000:00000010                 dd 0                    ; 下一个ShellCode地址
seg000:00000014                 dd 76EC5D30h            ; pfnNtTestAlert
seg000:00000018 ; ---------------------------------------------------------------------------
seg000:00000018                 mov     eax, 174h
seg000:00000018 ; ---------------------------------------------------------------------------
seg000:0000001D                 UNICODE_STRING <5Eh, 60h, 40025h>
seg000:00000025 aCProgramFilesM:
seg000:00000025                 unicode 0, <C:\Program Files\XXXXX\DLP\Agent\fcagcbh32.dll>,0
....
seg000:0000022D                 dd 76EC5360h            ; pfnNtProtectVirtualMemory
seg000:00000231                 dd 76EDF585h            ; pfnLdrLoadDll
seg000:00000235
seg000:00000235 ; =============== S U B R O U T I N E =======================================
seg000:00000235
seg000:00000235 ; Attributes: bp-based frame
seg000:00000235
seg000:00000235 sub_235         proc near
seg000:00000235
seg000:00000235 var_C           = dword ptr -0Ch
seg000:00000235 var_8           = dword ptr -8
seg000:00000235 var_4           = dword ptr -4
seg000:00000235
seg000:00000235                 push    ebp
seg000:00000236                 mov     ebp, esp
seg000:00000238                 add     esp, 0FFFFFFF4h
seg000:0000023B                 push    ebx
seg000:0000023C                 mov     ebx, eax        ; 参数基址
seg000:0000023E                 mov     [ebp+var_4], ebp
seg000:00000241                 mov     eax, [ebp+var_4]
seg000:00000244                 add     eax, 4          ; 指向栈上函数返回地址
seg000:00000247                 mov     edx, [ebx+14h]
seg000:0000024A                 mov     [eax], edx      ; 修改函数返回地址为pfnNtTestAlert
seg000:0000024C                 mov     eax, [ebx+14h]
seg000:0000024F                 mov     [ebp+var_C], eax
seg000:00000252                 mov     [ebp+var_4], 5
seg000:00000259                 lea     eax, [ebp+var_8]
seg000:0000025C                 push    eax             ; OldProtect
seg000:0000025D                 push    40h ; '@'       ; PAGE_EXECUTE_READWRITE
seg000:0000025F                 lea     eax, [ebp+var_4]
seg000:00000262                 push    eax             ; RegionSize
seg000:00000263                 lea     eax, [ebp+var_C]
seg000:00000266                 push    eax             ; BaseAddress
seg000:00000267                 push    0FFFFFFFFh      ; ProcessHandle
seg000:00000269                 call    dword ptr [ebx+22Dh] ; NtProtectVirtualMemory
seg000:0000026F                 mov     eax, [ebx+14h]
seg000:00000272                 mov     edx, [ebx+18h]
seg000:00000275                 mov     [eax], edx
seg000:00000277                 mov     dl, [ebx+1Ch]   ; 修改NtTestAlert函数前5个字节为MOV EAX, 174h
seg000:0000027A                 mov     [eax+4], dl
seg000:0000027D                 mov     [ebp+var_4], 5
seg000:00000284                 lea     eax, [ebp+var_8]
seg000:00000287                 push    eax             ; OldProtect
seg000:00000288                 mov     eax, [ebp+var_8]
seg000:0000028B                 push    eax             ; NewProtectWin32
seg000:0000028C                 lea     eax, [ebp+var_4]
seg000:0000028F                 push    eax             ; RegionSize
seg000:00000290                 lea     eax, [ebp+var_C]
seg000:00000293                 push    eax             ; BaseAddress
seg000:00000294                 push    0FFFFFFFFh      ; ProcessHandle
seg000:00000296                 call    dword ptr [ebx+22Dh] ; NtProtectVirtualMemory
seg000:0000029C
seg000:0000029C loc_29C:                                ; CODE XREF: sub_235+7Ej
seg000:0000029C                 lea     eax, [ebp+var_4]
seg000:0000029F                 push    eax
seg000:000002A0                 lea     eax, [ebx+1Dh]
seg000:000002A3                 push    eax
seg000:000002A4                 push    0
seg000:000002A6                 push    0
seg000:000002A8                 call    dword ptr [ebx+231h] ; LdrLoadDll
seg000:000002AE                 mov     ebx, [ebx+10h]
seg000:000002B1                 test    ebx, ebx
seg000:000002B3                 jnz     short loc_29C
seg000:000002B5                 pop     ebx
seg000:000002B6                 mov     esp, ebp
seg000:000002B8                 pop     ebp
seg000:000002B9                 retn
seg000:000002B9 sub_235         endp
seg000:000002B9
seg000:000002B9 ; ---------------------------------------------------------------------------
seg000:000002BA                 align 1000h
seg000:000002BA seg000          ends
seg000:000002BA
seg000:000002BA
seg000:000002BA                 end

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 6
支持
分享
最新回复 (61)
雪    币: 7
活跃值: (353)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
2
这个方案存在同步问题吧?
进程监控通知到注入这个期间,应用程序和注入不是同步的吧
2016-2-27 18:05
0
雪    币: 7
活跃值: (353)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
3
方便把安装包上传下嘛?
2016-2-27 18:07
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
我也这样搞搞过,但是用 NtProtectVirtualMemory 就蓝屏  我是在这个操作 PsSetLoadImageNotifyRoutine
附加到程序
2016-2-27 19:02
0
雪    币: 608
活跃值: (648)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
不要在ImageNotify里调用ZwProtectVirtualMemory
2016-2-28 08:27
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
这兄弟怎么说,为什么会这样,要在ProcessNotify才行是吧
2016-2-28 10:00
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
是要在ProcessNotify 才行是吧
2016-2-28 10:01
0
雪    币: 14
活跃值: (320)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
驱动在进程通知的时候注入的ShellCode,ShellCode是在应用层线程执行时调用,没有同步问题。
2016-2-28 10:03
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
我想知道,那个驱动修改那个ntdll API为 e9 的时机是什么

我在 x64 老是蓝屏

这个方法比修改 OEP 感觉好点
2016-2-28 12:35
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
你说的这个产品,怎么感觉和我的工程这么像,不会就是逆向我的吧,make!,
2016-3-1 16:12
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
哈哈哈,兄弟开源注入吧,其他不要

我好想知道为什么我那个蓝
2016-3-1 20:47
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
不行哦,这是公司商业代码,不方便
2016-3-2 10:32
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
能不能解答下,为什么我用修改内存的那API在内核修改ring3内存,会蓝屏哦
2016-3-2 12:12
0
雪    币: 14
活跃值: (320)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
在64环境中看你启动的是32位程序还是64程序,如果启动的64位程序就在ProcessNotify中进行ShellCode插入,还有就是确认下你的ZwProtectVirtualMemory函数地址是否正确。如果你启动的是32位程序,需要在ImageNotify等待32位ntdll装入后插入ShellCode并修改E9。在ImageNotify再等待32位ntdll注入后启动一个WorkItem进行ShellCode插入。
2016-3-2 13:19
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
是在 64注入到 32程序

我是这样搞的 ProcessNotify 里设置有目标进程出现,就在全局设置为1

然后 ImageNotify 比较 unicode 的模块名字,是主进程的名字,就分配内存

修改OEP,如果加壳了的,没蓝屏过,因为没用修改属性那API

我想出现了主进程 ntdll早就加载了吧,不需要判断了吧
2016-3-2 23:21
0
雪    币: 43
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
标记一下,未来看
2016-3-3 13:05
0
雪    币: 3643
活跃值: (1977)
能力值: ( LV6,RANK:93 )
在线值:
发帖
回帖
粉丝
17
comodo,火绒都用过这个方式,不过火绒3.0稍微改了下反而没以前兼容好了
2016-3-3 13:19
0
雪    币: 14
活跃值: (320)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
已上传测试代码,共同学习下!
2016-3-7 09:09
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
测试报告准备中,感谢楼主
2016-3-7 10:45
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
看了下,没有对特定进程过滤吧

加载的DLL是也没看到,就看到shellcode
2016-3-7 10:52
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
看了下,没有对特定进程过滤吧
2016-3-7 10:54
0
雪    币: 14
活跃值: (320)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
特定进程过滤是要走策略的。
2016-3-7 11:00
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
x64 系统 注入到 x86 进程

只对某个进程注入

修改了dll路径

发现没注入成功

BOOLEAN InjectDll(HANDLE ProcessHandle, WCHAR *DllPath)

信息可以到这个地方,继续测试中

OEP 和 NT那个函数没发现 shellcode影子

我看默认开启时 oep的方法?
2016-3-7 11:53
0
雪    币: 14
活跃值: (320)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
OEP默认没开启,没住人成功看你的DLL编译方式是不是依赖其他非系统库了。
2016-3-7 12:21
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
这个dll我经常用,其他驱动注入没问题的,加了upx壳

KERNEL32.DLL 就引用这个

但是在里面还有个memload另外的dll

有点诡异的是,我用OD调试,并没发现 shellcoe的影子
2016-3-7 12:30
0
游客
登录 | 注册 方可回帖
返回
//