首页
社区
课程
招聘
[旧帖] 如何利用映像回调(PsSetLoadImageNotifyRoutine)来拦截dll加载 0.00雪花
发表于: 2016-3-4 07:11 14770

[旧帖] 如何利用映像回调(PsSetLoadImageNotifyRoutine)来拦截dll加载 0.00雪花

2016-3-4 07:11
14770
WCHAR      pModuleName[216]={0};

VOID LoadImageNotifyRoutine
(
    __in_opt PUNICODE_STRING  FullImageName,
    __in HANDLE  ProcessId,
    __in PIMAGE_INFO  ImageInfo
)
{
        PVOID pDrvEntry;
        PEPROCESS ProcessObj=NULL;  
        char*    pname;
        PSIZE_T         pdata[2]={0};
        NTSTATUS st=STATUS_UNSUCCESSFUL;
        char szFullImageName[260]={0};
        int i=0;
        if(FullImageName!=NULL && MmIsAddressValid(FullImageName))
        {

           if(ProcessId!=0){
                   st = PsLookupProcessByProcessId(ProcessId, &ProcessObj);
                   if (PsGetProcessImageFileName!=NULL)
                   {
                           pname = PsGetProcessImageFileName(ProcessObj);
                           if (pname==NULL)
                                   goto fun_ret;
                           pname= _strlwr(pname);
                           if (strstr(browser,pname)!=NULL){
                   if(FullImageName->Length<=216){
                                           wcsncpy(pModuleName,FullImageName->Buffer,FullImageName->Length);
                                           for( i = 0; i < FullImageName->Length; i++)
                                                   pModuleName[i] = tolower(pModuleName[i]);         
                                           if (wcsstr(pModuleName,L"\\dll.dll")!=NULL){
                                   DbgPrint("进程:%s PID:%d 模块:%ws",pname,ProcessId,pModuleName);

pDrvEntry=GetDriverEntryByImageBase(ImageInfo->ImageBase);//得到dll入口
                                                        pdata[0]=ProcessObj;
                                                          

                                                        pdata[1]=pDrvEntry;
                                                        DenyLoadDll(pdata);

                                           }                                               

                                       
                                           }
                       
                           }
                         
                          

                   }
          
                 

           }

               
        }
        fun_ret:
                return;
               
}

void DenyLoadDll(PSIZE_T data)
{
        PEPROCESS dld_ep=(PEPROCESS)(data[0]);
        PVOID DriverEntry=(PVOID)(data[1]);
        UCHAR fuck64[]="\xB8\x00\x00\x00\x00\xC3";
        UCHAR fuck32[]="\xB8\x00\x00\x00\x00\xC2\x08\x00";
        PVOID BaseAddress=DriverEntry;
        ULONG OldProtect;
        SIZE_T RegionSize;
        NTSTATUS st;
        KAPC_STATE ks={0};
        if((ULONG64)DriverEntry<(ULONG64)0x7FFFFFFF)
        {
                RegionSize=sizeof(fuck32);
        }
        else
        {
                RegionSize=sizeof(fuck64);
        }
        KeStackAttachProcess(dld_ep,&ks);
        st=NtProtectVirtualMemory((HANDLE)-1,&BaseAddress,&RegionSize,PAGE_EXECUTE_READWRITE,&OldProtect);
                DbgPrint("st:%x",st);//NtProtectVirturalMemorry调用后返回值c0000005
        if(NT_SUCCESS(st))
        {
                __try
                {
                                 DbgPrint("成功!\n");
                        if((ULONG64)DriverEntry<(ULONG64)0x7FFFFFFF)
                        {
                                memcpy(DriverEntry,fuck32,sizeof(fuck32));
                        }
                        else
                        {
                                memcpy(DriverEntry,fuck64,sizeof(fuck64));
                        }
                }
                __except(1)
                {
                        ;
                }
        }
        KeUnstackDetachProcess(&ks);
        PsTerminateSystemThread(STATUS_SUCCESS);
}

求大家帮忙能不能看出哪里出问题!主要是想拦截进程第三方dll的加载

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

收藏
免费 0
支持
分享
最新回复 (19)
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
哇 和楼主一样的问题,那个 修改属性的,也差不多这错误,在 x64 求解
2016-3-4 08:57
0
雪    币: 1392
活跃值: (5197)
能力值: ( LV13,RANK:240 )
在线值:
发帖
回帖
粉丝
3
这么做难道系统没有卡死在这里?
2016-3-4 08:59
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
求解,特别是 那个修改属性的

我不是拦截DLL,我是修改程序的OEP

也不行
2016-3-4 09:03
0
雪    币: 2291
活跃值: (938)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
5
拦截不了,这个时候已经都加载了,回调只是通知你
2016-3-4 09:52
0
雪    币: 112
活跃值: (211)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
有啥方法吗,那个拦截截dll函数我在线程里执行,通过,但是像你说的,dll已经加载了
2016-3-4 13:56
0
雪    币: 2291
活跃值: (938)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
7
可以去看LoadLibraryEx内部流程,可以在关键位置挂钩拦截。我以前用过NtOpenFile这个点
2016-3-4 14:09
0
雪    币: 112
活跃值: (211)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
有卡住了,卡在NtProtectVirtualMemory
2016-3-4 14:56
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
路过路过。
2016-3-4 15:37
0
雪    币: 96
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
这些dll加载的回调 应该是在MiMapViewOfSection->MiMapViewOfImageSection里吧,首先在前者调用后者前 会KeAcquireGuardedMutex (&((PROCESS)->AddressCreationLock));来进行同步
NtProtectVirtualMemory->MiProtectVirtualMemory也会使用宏LOCK_ADDRESS_SPACE (Process);同样需要这个AddressCreationLock,可能会因此卡死吧。

由于前面看到回调处于MiMapViewOfImageSection的映射到根据一系列参数计算到当前进程的vad的位置并和MmCreateSection里搞定的ControlArea对象等都关联起来了,感觉所以想阻断dll加载比较困难?
2016-3-4 16:28
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
11
以前搞过,方法是硬编码释放这个锁,就可以Protect了,完事儿再加上……不是很完美
2016-3-4 16:54
0
雪    币: 112
活跃值: (211)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
这种现象是死锁造成的吗,怎么释放的呀,可否再说详细点
2016-3-4 18:35
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
13
以下部分内容来自WRK
先看两个宏
#define LOCK_ADDRESS_SPACE(PROCESS)                                  \
            KeAcquireGuardedMutex (&((PROCESS)->AddressCreationLock));
            
#define UNLOCK_ADDRESS_SPACE(PROCESS)                               \
            KeReleaseGuardedMutex (&((PROCESS)->AddressCreationLock));



这个锁的位置在EPROCESS里面,偏移在各个系统应该也不一样,所以要用的话得自己根据系统版本硬编码了。下面这个是XP的:
nt!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x06c ProcessLock      : _EX_PUSH_LOCK
   +0x070 CreateTime       : _LARGE_INTEGER
   +0x078 ExitTime         : _LARGE_INTEGER
   +0x080 RundownProtect   : _EX_RUNDOWN_REF
   +0x084 UniqueProcessId  : Ptr32 Void
   +0x088 ActiveProcessLinks : _LIST_ENTRY
   +0x090 QuotaUsage       : [3] Uint4B
   +0x09c QuotaPeak        : [3] Uint4B
   +0x0a8 CommitCharge     : Uint4B
   +0x0ac PeakVirtualSize  : Uint4B
   +0x0b0 VirtualSize      : Uint4B
   +0x0b4 SessionProcessLinks : _LIST_ENTRY
   +0x0bc DebugPort        : Ptr32 Void
   +0x0c0 ExceptionPort    : Ptr32 Void
   +0x0c4 ObjectTable      : Ptr32 _HANDLE_TABLE
   +0x0c8 Token            : _EX_FAST_REF
   +0x0cc WorkingSetLock   : _FAST_MUTEX
   +0x0ec WorkingSetPage   : Uint4B
   [COLOR="Red"][B]+0x0f0 AddressCreationLock : _FAST_MUTEX[/B][/COLOR]   
   +0x110 HyperSpaceLock   : Uint4B
   +0x114 ForkInProgress   : Ptr32 _ETHREAD
   +0x118 HardwareTrigger  : Uint4B
 

  

在加载PE文件时NtMapViewOfSection会调用这个:  
          
MmMapViewOfSection
{
//
    // Get the address creation mutex to block multiple threads
    // creating or deleting address space at the same time.
    //
  
    LOCK_ADDRESS_SPACE (Process);
    
    //Map Image
    status = [COLOR="Red"][B]MiMapViewOfImageSection [/B][/COLOR](ControlArea,
              Process,
              CapturedBase,
              SectionOffset,
              CapturedViewSize,
              Section,
              InheritDisposition,
              ZeroBits,
              AllocationType,
              ImageCommitment);
                                              
  UNLOCK_ADDRESS_SPACE (Process);

}

//在这个函数里调用回调
MiMapViewOfImageSection
{
    ......
    [COLOR="red"][B]PsCallImageNotifyRoutines[/B][/COLOR]();//此时锁是Lock状态
    ......
}




所以,你要在NotifyRoutine里先UNLOCK_ADDRESS_SPACE,然后调用ZwProtectVirturlMemory修改属性,完事儿再LOCK_ADDRESS_SPACE,这样就可以愉快地Patch了。
但是用了硬编码,感觉就不完美了。。。

另外,DllMain是三个参数:
.text:10001000 ; BOOL __stdcall [COLOR="red"][B]DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)[/B][/COLOR]
.text:10001000
.text:10001000 hinstDLL        = dword ptr  4
.text:10001000 fdwReason       = dword ptr  8
.text:10001000 lpvReserved     = dword ptr  0Ch
.text:10001000
.text:10001000                 cmp     [esp+fdwReason], 1
.text:10001005                 jnz     short loc_1000101C
.text:10001007                 push    0               ; lpThreadId
.text:10001009                 push    0               ; dwCreationFlags
.text:1000100B                 push    0               ; lpParameter
.text:1000100D                 push    offset ThreadShow(void *) ; lpStartAddress
.text:10001012                 push    0               ; dwStackSize
.text:10001014                 push    0               ; lpThreadAttributes
.text:10001016                 call    ds:CreateThread(x,x,x,x,x,x)
.text:1000101C
.text:1000101C loc_1000101C:                           ; CODE XREF: DllMain(x,x,x)+5j
.text:1000101C                 mov     eax, 1
.text:10001021                 [COLOR="red"][B]retn    0Ch[/B][/COLOR].text:10001021 __stdcall DllMain(x, x, x) endp


你Patch成retn 08就不怕崩了吗少年?

还有吧,你这eax清零的写法编译器看了会笑的:
01056217      33C0             xor eax,eax
01056219      C2 0C00          retn 0C
2016-3-5 12:39
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
14
是加载了,但DllMain还没有执行,所以可以Patch
2016-3-5 12:44
0
雪    币: 112
活跃值: (211)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
这段代码在内核线程里执行就通过,
KEVENT s_event; 全局变量
//这句在DriverEntry 初始化同步事件
        KeInitializeEvent(&s_event,SynchronizationEvent,TRUE);

映像回调函数里
                                           if (wcsstr(pModuleName,L"\\dll.dll")!=NULL){
                                                    pDrvEntry=GetDriverEntryByImageBase(ImageInfo->ImageBase);
                                                        DbgPrint("进程:%s PID:%d 模块:%ws 入口:%x PEPROCESS:%x\n",pname,ProcessId,pModuleName,pDrvEntry,ProcessObj);
                                                        pdata[0]=NULL;
                                                        pdata[1]=NULL;
                                                        pdata[0]=ProcessObj;
                                                        pdata[1]=pDrvEntry;
                                                        status=PsCreateSystemThread(&thread,THREAD_ALL_ACCESS,NULL,NULL,NULL,DenyLoadDll,(PVOID)pdata);
                                                        if(!NT_SUCCESS(status)){
                                                           DbgPrint("error");
                                                        }

                                                  //等待信号  
                                                    KeWaitForSingleObject (&s_event,Executive,KernelMode,FALSE,0);      
                                                    DbgPrint("Create Thread has return");  
                                                    ZwClose(thread);  
                                           }

在32位系统不会造成死锁也可以拦截dll加载,但是在64位系统拦截不了dll,还有别的法子吗
2016-3-6 06:11
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
楼主,问题解决了吗?我在Win2008下查询到_EPROCESS结构偏移+0x218 处是AddressCreationLock,但调用FltReleasePushLock后,再调用ZwProtectVirtualMemory函数,系统立刻终止了。请@achillis,给指点一下。
2016-3-15 14:49
0
雪    币: 97
活跃值: (225)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
思路如下  在PsSetLoadImageNotifyRoutine回调处理:
1 判断是需要拦截的进程
2  KeAttachProcess 到进程
3 写 本地的一个空方法地址
int __stdcall sub_123D0(int a1, int a2, int a3)
{
  return 0;
}
到 DLLMain 去
MmGetPhysicalAddress(v7);
   ProbeForWrite(v7, 5u, 1u);
*v7 = sub_123D0;
4 看这样就可以咯

这个是我分析一个病毒文件得到的方案
具体病毒文件见附件(文件是sys 不能上传就改后缀名咯)
IsDrv122.txt
上传的附件:
2016-3-16 19:52
0
雪    币: 112
活跃值: (211)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
能否贴一段解锁和锁回的代码看看,我也调用了,成功编译,但是服务没能启动,把解锁那代码注释掉就可以
2016-7-27 11:48
0
雪    币: 989
活跃值: (106)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
铜球
2016-8-14 14:35
0
雪    币: 37
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
求大神贴个能成功执行的锁定代码~~~
我在win7 x64上成功获取了这个锁的地址:
ULONG AddressCreationLockOffset=0X218;//win7x64偏移
PEX_PUSH_LOCK PLOCK = &(*(EX_PUSH_LOCK*)((char*)myep + AddressCreationLockOffset));

然后执行KeReleaseGuardedMutex(PLOCK);
在这个函数里我继续跟踪:
fffff800`03edec60 4883ec28        sub     rsp,28h
fffff800`03edec64 488bd1          mov     rdx,rcx
fffff800`03edec67 48c7410800000000 mov     qword ptr [rcx+8],0
fffff800`03edec6f b801000000      mov     eax,1
fffff800`03edec74 f00fc101        lock xadd dword ptr [rcx],eax
fffff800`03edec78 85c0            test    eax,eax
fffff800`03edec7a 7521            jne     nt!KeReleaseGuardedMutex+0x3d (fffff800`03edec9d)
fffff800`03edec7c 65488b042588010000 mov   rax,qword ptr gs:[188h]
fffff800`03edec85 668380c601000001 add     word ptr [rax+1C6h],1
fffff800`03edec8d 7509            jne     nt!KeReleaseGuardedMutex+0x38 (fffff800`03edec98)
fffff800`03edec8f 4883c050        add     rax,50h
fffff800`03edec93 483900          cmp     qword ptr [rax],rax
fffff800`03edec96 751f            jne     nt!KeReleaseGuardedMutex+0x57 (fffff800`03edecb7)
fffff800`03edec98 4883c428        add     rsp,28h
fffff800`03edec9c c3              ret
fffff800`03edec9d a802            test    al,2
fffff800`03edec9f 75db            jne     nt!KeReleaseGuardedMutex+0x1c (fffff800`03edec7c)
fffff800`03edeca1 ffc0            inc     eax
fffff800`03edeca3 8d48fe          lea     ecx,[rax-2]
fffff800`03edeca6 f00fb10a        lock cmpxchg dword ptr [rdx],ecx
fffff800`03edecaa 75d0            jne     nt!KeReleaseGuardedMutex+0x1c (fffff800`03edec7c)
fffff800`03edecac 488d4a18        lea     rcx,[rdx+18h]
fffff800`03edecb0 e8e7b6faff      call    nt!KeSignalGateBoostPriority (fffff800`03e8a39c)fffff800`03edecb5 ebc5            jmp     nt!KeReleaseGuardedMutex+0x1c (fffff800`03edec7c)
fffff800`03edecb7 4883c428        add     rsp,28h
fffff800`03edecbb e9f08af9ff      jmp     nt!KiCheckForKernelApcDelivery (fffff800`03e777b0)

进入了 nt!KeSignalGateBoostPriority,随后在这个函数的:
mov     rsi,qword ptr [rbp] ss:0018:fffffa80`26a56d68=0000000000000000 //这里异常了
RBP地址内存储的数据为0,然后就不知道如何是好了~~求指导
上面获取的PEX_PUSH_LOCK 的地址是正确的,已查看过了
2016-8-25 11:28
0
游客
登录 | 注册 方可回帖
返回
//