首页
社区
课程
招聘
[原创]挂钩KeUsermodeCallback函数来实现自己的“财产保镖“
发表于: 2012-1-19 13:06 18520

[原创]挂钩KeUsermodeCallback函数来实现自己的“财产保镖“

2012-1-19 13:06
18520

通过挂钩KeUserModeCallback这个未公开的函数可以实现对Ke_LoadLibrary、WH_KEYBOARD_LL等进行拦截,这个函数也可以用来在Ring0下调用Ring3代码,如果需要更进一步了解,可以去黑月教主的百度blog上去看看。下面我们来实现拦截dll注入的功能,解决两个问题:


一、        如何挂钩KeUserModeCallback函数,有两种方式IAT HOOK(QQ电脑管家)、inline HOOK(360保险箱)。


二、        如何拦截DLL注入,这个功能在KeUserModeCallback挂钩函数里实现。


实现的代码主要来源于对QQ电脑管家驱动文件TCSafeBox.sys的逆向分析,所以我尽量试着去还原TCSafeBox.sys的代码,核心代码如下:


ULONG StartHook(IN  PVOID fake_funcaddrss,OUT PULONG Original_funcaddrss)


{


    ULONG win32k_base;


        ULONG result;       


         if (fake_funcaddrss &&  Original_funcaddrss)


     {


        win32k_base = GetModuleBase("win32k.sys");


            if ( win32k_base>0 )                                 


             result = IATHook((PVOID)win32k_base,"ntoskrnl.exe", "KeUserModeCallback",fake_funcaddrss,Original_funcaddrss);  


         }


         else


      result = 0;


   return result;       


}



ULONG GetModuleBase(IN PCHAR ModuleName)


{


   ULONG result;


   ULONG   dwNeedSize=0;


   NTSTATUS status;


   PMODULES pModules;


   int i;


   char imagename[255]={0};



  ZwQuerySystemInformation(SystemModuleInformation,NULL,0,&dwNeedSize);


  pModules = ExAllocatePoolWithTag(NonPagedPool,dwNeedSize,0);


  if (pModules)


  {


    memset(pModules,0,dwNeedSize);          


    status = ZwQuerySystemInformation(SystemModuleInformation,pModules,dwNeedSize,NULL);


       


        if (NT_SUCCESS(status))


        {


     


      i = 0;


          while ( idwNumberOfModules )


      {


        strcpy(imagename,pModules->smi[i].ImageName + pModules->smi[i].ModuleNameOffset);



            if (!strncmp(imagename,ModuleName,strlen(ModuleName)))


            {


                result = (ULONG)pModules->smi[i].Base;


                    break;


                }


               


            i++;


          }


        }


     ExFreePoolWithTag(pModules,0);


  }


return result;


}



ULONG IATHook(IN PVOID ModlueBase,IN PCHAR ImportName,IN PCHAR ApiName,IN ULONG fakeFunctionAddr,OUT PULONG originalFuncAddr)


{


   ULONG reslut;       


   ULONG size;


   PIMAGE_IMPORT_DESCRIPTOR pImportModuleDirectory;


   DWORD dwRVAModuleName;


   PCHAR ModuleName;


   CHAR RvAModuleNameIsZory;


   ULONG *OriginalFirstThunk;


   ULONG *FirstThunk;


   int i;


   PIMAGE_IMPORT_BY_NAME Imageimportbyname;


   ULONG result;



   result = 0;


   if (ModlueBase && ImportName && ApiName && fakeFunctionAddr && originalFuncAddr && !KeGetCurrentIrql())


   {


        __try


        {


           size = 0;


           pImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ModlueBase,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&size);   


       


           if (pImportModuleDirectory)


           {


              while (pImportModuleDirectory && pImportModuleDirectory->Name)


              {


                  dwRVAModuleName = pImportModuleDirectory->Name;    //模块的dll名称


                      RvAModuleNameIsZory = ((CHAR *)ModlueBase + dwRVAModuleName) == 0;


                  ModuleName = (CHAR *)ModlueBase + dwRVAModuleName;


                     


                          //先找到模块,再在模块里查找函数


                          if (!RvAModuleNameIsZory && !_strnicmp(ModuleName,ImportName,sizeof(ImportName)))


              {


                   //得到输入表结构里指向INT和IAT的VA


                                   OriginalFirstThunk    = (ULONG *)((CHAR *)ModlueBase + pImportModuleDirectory->OriginalFirstThunk);


                                   FirstThunk            = (ULONG *)((CHAR *)ModlueBase + pImportModuleDirectory->FirstThunk);


                      


                               for (i=0;FirstThunk[i];i++)


                               {


                                  Imageimportbyname =  OriginalFirstThunk[i];     



                                          if ( Imageimportbyname < (ULONG)ModlueBase )


                                              Imageimportbyname += (ULONG)ModlueBase;


                                      if (Imageimportbyname)


                                      {


                                                  //以函数名称方式输入


                                                  if ( !_strnicmp((PCHAR)&Imageimportbyname->Name[0],ApiName,strlen(ApiName))


                                                          && MmIsAddressValid(FirstThunk[i]))


                                         {      


                                                                                                                     


                                                        /* DbgPrint("i=%d,funcname=[%s]----hookfunc=[%s]\n",i,(PCHAR)&Imageimportbyname->Name[0],ApiName);


                                                                  这里请注意Imageimportbyname->Name得到的是函数名称的首字母*/


                                                          DbgPrint("IAT ENTRY=0x%x,IatAddress=0x%X,funcname=[%s]----hookfunc=[%s]\n",(ULONG *)((CHAR *)ModlueBase + pImportModuleDirectory->FirstThunk+i*4),FirstThunk[i],(PCHAR)&Imageimportbyname->Name[0],ApiName);


                                                             


                                                          *originalFuncAddr = (ULONG)FirstThunk[i];


                                                          reslut = HookFunc(&FirstThunk[i],fakeFunctionAddr);


                              goto Exit;                                                             


                                                         


                                                 }                                                                                                                                                               


                                          }                                                                                                     


                                   }


                                   break;


                          }


      


                     pImportModuleDirectory++;


                  }


           }


        }


    __except(EXCEPTION_EXECUTE_HANDLER)


        {


         reslut =0;


        }


   }


   else


     reslut =0;



Exit:   


  return result;


}



ULONG HookFunc(IN PVOID ImportFuncVA,IN ULONG fake_func)


{      


   PMDL   ImportFuncThunkEntry_MDL;


   PVOID  ImportFuncMapAddress;



   PVOID  ImportFuncThunkEntry;     //导入表函数的THUNK地址--指针地址


   ULONG  result;


   BOOL   IsMapped;


   IsMapped = 0;


  


  if (ImportFuncVA && fake_func)


  {


      ImportFuncThunkEntry = (PVOID)ImportFuncVA;



      ImportFuncThunkEntry_MDL = IoAllocateMdl(ImportFuncThunkEntry,sizeof(ULONG),FALSE,FALSE,NULL);


          


      if (ImportFuncThunkEntry_MDL)


      {         


                  MmProbeAndLockPages(ImportFuncThunkEntry_MDL,KernelMode,IoWriteAccess);


                  IsMapped =1;


                  if (ImportFuncThunkEntry_MDL->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA|MDL_SOURCE_IS_NONPAGED_POOL))


                    ImportFuncMapAddress = ImportFuncThunkEntry_MDL->MappedSystemVa;


                  else


                    ImportFuncMapAddress = MmMapLockedPagesSpecifyCache(ImportFuncThunkEntry_MDL,KernelMode,MmCached,NULL,NULL,NormalPagePriority);



           if ( MmIsAddressValid(ImportFuncMapAddress) )


                   {


                            InterlockedExchangePointer(ImportFuncMapAddress,fake_func);


                            result = 1;       


                   }  


          }


          if (IsMapped)


        MmUnlockPages(ImportFuncThunkEntry_MDL);


  }else


   result = 0;


  return result;


}



NTSTATUS fake_KeUserModeCallback(IN ULONG ApiNumber,IN PVOID InputBuffer,IN ULONG InputLength,OUT ULONG OutputBuffer,IN PULONG OutputLength)


{


        UNICODE_STRING   uniDllPath={0};


        STRING           aniDLLPath={0};


        CHAR             outDllPath[MAX_PATH]={0};


        ULONG            PID;   


        CHAR             FullPath[MAX_PATH]={0};   //被注入DLL的进程全路径


   


        if (g_IsDLLDefendMon &&


                !KeGetCurrentIrql() &&


            ApiNumber == LOAD_IMAGE_API_NUM &&


                InputLength >= LOAD_IMAGE_APINAME_OFFSET &&


                MmIsAddressValid(InputBuffer)  &&


                InputBuffer


           )


   {


       PID = (ULONG)PsGetCurrentProcessId();



           uniDllPath.Length = *(WORD *)((CHAR *)InputBuffer + LOAD_IMAGE_APINAMELENGTH_OFFSET);


           uniDllPath.MaximumLength = *(WORD *)((CHAR *)InputBuffer +  LOAD_IMAGE_APINAMEMAXLENGTH_OFFSET);


           uniDllPath.Buffer =  (PWSTR)((CHAR *)InputBuffer + LOAD_IMAGE_APINAME_OFFSET);  //这里得到加载的dll的符号全路径


          


           aniDLLPath.Buffer =  (PCHAR)&outDllPath;


           aniDLLPath.Length =  256;


           aniDLLPath.MaximumLength = 256;


          


           RtlUnicodeStringToAnsiString(&aniDLLPath, &uniDllPath, FALSE);


           GetFullPathFromPID(PID,&FullPath,256);


       if (VoteModule(FullPath,outDllPath)==1)


            return STATUS_UNSUCCESSFUL;


        }



return g_KeUserModeCallback(ApiNumber,InputBuffer,InputLength,OutputBuffer,OutputLength);


}



[注意]看雪招聘,专注安全领域的专业人才平台!

收藏
免费 6
支持
分享
最新回复 (14)
雪    币: 12
活跃值: (783)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
黑防是不是倒闭了??
2012-1-19 13:22
0
雪    币: 603
活跃值: (40)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
3
先占座。。。。。。
2012-1-19 13:35
0
雪    币: 14208
活跃值: (4517)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
膜拜      
2012-1-19 13:59
0
雪    币: 379
活跃值: (152)
能力值: ( LV12,RANK:330 )
在线值:
发帖
回帖
粉丝
5
黑防没有倒闭,有兴趣去他网站看看
2012-1-19 14:15
0
雪    币: 1015
活跃值: (235)
能力值: ( LV12,RANK:440 )
在线值:
发帖
回帖
粉丝
6
先占位,再看贴。
2012-1-19 14:38
0
雪    币: 210
活跃值: (221)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
7
写得不错 赞一个
2012-1-19 21:31
0
雪    币: 1737
活跃值: (110)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
现在还看不懂呢,慢慢来吧~~
2012-1-21 08:14
0
雪    币: 219
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
marking /.......
2012-1-24 15:20
0
雪    币: 878
活跃值: (496)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
好。。。。
KeXXXXXXXXX
2012-1-24 21:32
0
雪    币: 220
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
不错,看一下
2012-1-25 18:35
0
雪    币: 639
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
好多概念不懂啊,HOOK,上下文切换....不过代码量好少,编程这么多年,渐渐觉得程序有些意思了哈哈,继续学习
2012-1-30 11:15
0
雪    币: 22
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
不太懂,留个记号
2012-1-30 22:07
0
雪    币: 949
活跃值: (18)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
14
mark一下
2012-1-31 12:19
0
雪    币: 342
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
膜拜啊 能提供完整代码研究下吗?
2012-2-14 12:10
0
游客
登录 | 注册 方可回帖
返回