内核态下基于动态感染技术的应用程序执行保护(三 获取SSDT)

imageheaderstringdoshookfile

 
    (转载请注明博客地址:http://blog.csdn.net/hitetoshi

    前面我们经常提到SSDT,那么什么是SSDT呢?SSDT(SystemServices Descriptor Table):系统服务描述符表。要对它有清楚的认识,我们先以用户态下调用CreateThread来举个例子。

    如果你有兴趣,可以用OllyDbg在CreateThread上下断点,你会发现,经过一些简单的处理,CreateThread会调用CreateRemoteThread,按F7进入CreateRemoteThread,再经过一段跟踪,会发现CreateRemoteThread实际上又调用ZwCreateThread,再按F7跟踪进去,ZwCreateThread的代码非常简单:

7C92D1AE >  B8 35000000     MOV EAX,35

7C92D1B3    BA 0003FE7F     MOVEDX,7FFE0300

7C92D1B8    FF12            CALL DWORD PTR DS:[EDX]

7C92D1BA    C2 2000         RETN 20

    注意MOV EDX,7FFE0300/CALL DWORD PTRDS:[EDX]这两条指令,从OD上可以看到,这实际上是调用ntdll.dll中的KiFastSystemCall,KiFastSystemCall的代码也很简单:

7C92E510 >  8BD4            MOV EDX,ESP

7C92E512    0F34            SYSENTER

7C92E514 >  C3              RETN

    如果这时候你再用F7一步一步的跟,你会发现,到SYSENTER这条指令时,OllyDbg无法跟踪进去,而当这条指令执行完时,实际上ZwCreateThread的功能已经执行完成――用户态的一切玄机似乎都在SYSENTER这条指令上。SYSENTER指令在用户态下向内核态发起系统调用,此时代码切换到内核,因此OllyDbg这样的用户态调试器是无法调试的。和KiFastSystemCall类似,ntdll.dll中也有一个KiIntSystemCall。PII以前的处理器并不支持SYSENTER这条指令,因此KiIntSystemCall以一条INT 2E指令切换到内核。

    SYSENTER进入内核的KiFastCallEntry(该函数没有被ntoskrnl.exe导出,你可能需要下载ntoskrnl.exe的Symbol才能看到它),KiFastCallEntry大致进行的工作就是按照SSDT表找到对应服务函数的地址,并转入到服务函数,即内核NtCreateThread中去。SSDT包含在一个叫SDT(服务描述表)的结构中,SDT由ntoskrnl.exe(某些系统下可能不是这个文件名,例如多核处理器下可能是ntkrnlpa.exe,但为简便起见,下文都用ntoskrnl.exe来表述)以KeServiceDescriptorTable为名称导出,SDT的定义如下:

ServiceDescriptorEntry STRUCT

     pvSSDTBase             dd   ?        ;SSDT基地址

     pvServiceCounterTable  dd   ?        ;SSDT中每个服务被调用次数的表

     ulNumberOfServices     dd   ?        ;描述的服务的数目

     pvParamTableBase       dd   ?        ;每个系统服务参数的字节数的表

ServiceDescriptorEntry ENDS

    我们可以在LiveKd中用d nt!KeServiceDescriptorTable来观察内核中这个结构的数据:

 


    可见系统中有0x11C个SSDT项,基地址为0x80505480,我们来看看SSDT表的内容,用d 80505480命令:

 


    从0x80505480开始,存放每个系统服务项的函数地址,那么怎么确定内核NtCreateThread的地址呢?答案就在用户态下ZwCreateThread的mov eax,0x35这条指令,它指明了NtCreateThread在SSDT中是第0x35项,计算一下0x80505480+0x35*4=0x80505554,看一看:

 


    大约NtCreateThread应该在0x805D2018这个地址,用u nt!NtCreateThread命令看一下:

 


    正是这个地址!(大家肯定会比较奇怪NtCreateThread的第一条指令怎么会是Jmp,我也是今天写这篇稳当时才发现我的NtCreateThread居然被Inline hook了!NND!一看模块,IsDrv122.sys,原来是开着冰刃……)。

    出了冰刃这个事件也好,也就是我想跟大家说的Hook SSDT,刚才大家已经看到,冰刃对SSDT的NtCreateThread做了Inline hook,我曾经说过,我极不推荐做Inline hook,除非你技术实力非常强大。原因我会在后面的文章介绍。这里我们有一个思路,如果把0x80505554这个地址的内容替换了,换成我们的函数,不是一样达到HookNtCreateThread的效果了吗?这就是SSDT Hook。在SSDT上做Hook或者是InlineHook是非常强大的,因为用户态上所有CreateThread的调用最终都会进入这个函数。很多杀毒软件会Hook SSDT的这个位置,用来监视是否有进程试图用CreateRemoteThread向其它进程启动远程线程,这是防止远程线程的一个很有效的方法。不过我们Hook NtCreateThread的目的不是这个,我前面已经说了,我们要用它来监视进程的创建,并向进程中注入代码。

    今天的这篇文章我并不会完成Hook SSDT的代码,因为在我们的内核程序中还有很多事情要做:获取NtCreateThread的服务序号、获取保存NtCreateThread地址的位置以及获取NtCreateThread的地址。

    我们在上次的DynamicHook.asm的DriverEntry中加一些代码(红色部分是新加的代码):

DriverEntry   proc pDriverObject:PDRIVER_OBJECT,pusRegistryPath:PUNICODE_STRING

     local    status:NTSTATUS

     local    pDeviceObject:PDEVICE_OBJECT

 

     mov      status,STATUS_DEVICE_CONFIGURATION_ERROR

    

     invoke   IoCreateDevice,pDriverObject,0,addrg_usDeviceName,FILE_DEVICE_UNKNOWN,0,FALSE,addr pDeviceObject

     .if  eax==STATUS_SUCCESS

         invoke   IoCreateSymbolicLink,addrg_usSymbolicLinkName,addr g_usDeviceName

         .if  eax==STATUS_SUCCESS

 

              mov      eax,pDriverObject

              assume   eax:ptr DRIVER_OBJECT

              mov      [eax].DriverUnload,offset DriverUnload

              mov      [eax].MajorFunction[IRP_MJ_CREATE*(sizeof PVOID)],offsetDispatchCreateClose

              mov      [eax].MajorFunction[IRP_MJ_CLOSE*(sizeof PVOID)],offsetDispatchCreateClose

             

              invoke   DbgPrint,$CTA0("Driver entry")

             

invoke   HookNtCreateThread

              NT_SUCCESS    eax

              .if  eax

                   invoke   DbgPrint,$CTA0("Hook success")

                   mov      status,STATUS_SUCCESS

              .else

                   invoke   DbgPrint,$CTA0("Hook failure")

              .endif

 

              assume   eax:nothing

         .else

              invoke   IoDeleteDevice,pDeviceObject

         .endif

     .endif

@@:

     mov      eax,status

     ret

DriverEntry   endp

 

        在.const节中加入:

CCOUNTED_UNICODE_STRING "NtCreateThread",g_usNtCreateThread,4

        完成HookNtCreateThread函数:

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

HookNtCreateThread proc

     local    dwNtCreateThreadIndex

     local    dwNtCreateThreadAddress

     local    status:NTSTATUS

    

     mov      status,STATUS_UNSUCCESSFUL

 

     ;获取NtCreateThread服务序号

     invoke   GetSysCallIndex,addrg_usNtCreateThread

     .if  eax

         mov      dwNtCreateThreadIndex,eax

        

         ;获取NtCreteThread在内核中的地址

         invoke   GetSSDTOrigValue,dwNtCreateThreadIndex

         .if  eax

              mov      dwNtCreateThreadAddress,eax

              invoke   DbgPrint,$CTA0("NtCreateThreadindex:%08X,address:%08X"),dwNtCreateThreadIndex,dwNtCreateThreadAddress

              mov      status,STATUS_SUCCESS

         .endif

     .endif

    

     mov      eax,status

 

     ret

HookNtCreateThread endp

 

        为了完成GetSysCallIndex和GetSSDTOrigValue这两个函数,我增加了PEFile.asm和SSDT.asm两个文件以及对应的PEFile.inc、SSDT.inc和DyanmicHook.inc,你把这些文件加入进去时,注意要向上次那样设置PEFile.asm和SSDT.asm的汇编选项,设置各个文件的依赖项(自己看include去设置,就不详述了)。先把这五个文件的内容贴出来:

;PEFile.asm

 

         .386

         .model flat,stdcall

         option casemap:none

 

include  ntddk.inc

include  native.inc

include  hal.inc

include  ntoskrnl.inc

include  strings.mac

 

include  DynamicHook.inc

include  PEFile.inc

 

         .code

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetAlignedSize     proc uses edx  ecx  dwSize,dwAlignment

 

     xor      edx,edx

     mov      eax,dwSize

     mov      ecx,dwAlignment

     div      ecx

     .if  edx==0

         mov      eax,dwSize

     .else

         inc      eax

         mul      dwAlignment

     .endif

     ret

GetAlignedSize     endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetTotalImageSize  proc uses edi  edx  ecx  pDosHeader:PIMAGE_DOS_HEADER,pNtHeaders:PIMAGE_NT_HEADERS

     local    dwResult:DWORD

     local    dwAlignment:DWORD

     local    dwSections:DWORD

 

     and      dwResult,0

     mov      edi,pNtHeaders

     assume   edi:ptrIMAGE_NT_HEADERS

     M2M      dwAlignment,[edi].OptionalHeader.SectionAlignment

     xor      edx,edx

     mov      eax,[edi].OptionalHeader.SizeOfHeaders

     mov      ecx,dwAlignment

     div      ecx

     .if  edx==0

         mov      eax,[edi].OptionalHeader.SizeOfHeaders

         add      dwResult,eax

     .else

         inc      eax

         mul      dwAlignment

         add      dwResult,eax

     .endif

     mov      edi,pNtHeaders

     assume   edi:ptrIMAGE_NT_HEADERS

 

     movzx    eax,[edi].FileHeader.NumberOfSections

     mov      dwSections,eax

     add      edi,sizeofIMAGE_NT_HEADERS

     assume   edi:ptrIMAGE_SECTION_HEADER

     xor      edx,edx

     .while   edx<dwSections

         push edx

         mov      eax,[edi].Misc.VirtualSize

         .if  eax

              xor      edx,edx

              mov      ecx,dwAlignment

              div      ecx

              .if  edx==0

                   mov      eax,[edi].Misc.VirtualSize

                   add      dwResult,eax

              .else

                   inc      eax

                   mul      dwAlignment

                   add      dwResult,eax

              .endif

         .endif

         pop      edx

         add      edi,sizeofIMAGE_SECTION_HEADER

         inc      edx

     .endw

     assume   edi:nothing

     mov      eax,dwResult

     ret

GetTotalImageSize  endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetPEInfo proc uses edi  esi  pBase:PVOID,ppDosHeader:ptr PIMAGE_DOS_HEADER,ppNtHeaders:ptrPIMAGE_NT_HEADERS

     local    status:NTSTATUS

    

     mov      status,STATUS_UNSUCCESSFUL 

     mov      edi,pBase

     assume   edi:ptrIMAGE_DOS_HEADER

     .if  [edi].e_magic!=IMAGE_DOS_SIGNATURE

         jmp      @F

     .endif

     mov      esi,ppDosHeader

     .if  esi

         mov      dwordptr [esi],edi

     .endif

     add      edi,[edi].e_lfanew

     assume   edi:ptrIMAGE_NT_HEADERS

     .if  [edi].Signature!=IMAGE_NT_SIGNATURE

         jmp      @F

     .endif

     mov      esi,ppNtHeaders

     .if  esi

         mov      dwordptr [esi],edi

     .endif

 

     mov      status,STATUS_SUCCESS

@@:

     mov      eax,status

     ret

GetPEInfo endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

KLoadPEFile   proc uses edi  esi  pBaseAddress:PVOID,pLoadAddress:PVOID

     local    status:NTSTATUS

     local    pDosHeader:PIMAGE_DOS_HEADER

     local    pNtHeaders:PIMAGE_NT_HEADERS

     local    pPtr:PVOID

     local    dwSections:DWORD

     local    dwAlignment:DWORD

    

     mov      status,STATUS_UNSUCCESSFUL

     invoke   KeGetCurrentIrql

     .if  eax!=PASSIVE_LEVEL

         mov      status,STATUS_INVALID_LEVEL

         jmp      @F

     .endif

     M2M      pPtr,pLoadAddress

 

     invoke   GetPEInfo,pBaseAddress,addrpDosHeader,addr pNtHeaders

     .if  eax==STATUS_SUCCESS

         mov      edi,pNtHeaders

         assume   edi:ptrIMAGE_NT_HEADERS

         invoke   memcpy,pPtr,pBaseAddress,[edi].OptionalHeader.SizeOfHeaders

         M2M      dwAlignment,[edi].OptionalHeader.SectionAlignment

         invoke   GetAlignedSize,[edi].OptionalHeader.SizeOfHeaders,dwAlignment

         add      pPtr,eax

        

         movzx    eax,[edi].FileHeader.NumberOfSections

         mov      dwSections,eax

         add      edi,sizeofIMAGE_NT_HEADERS

         assume   edi:ptrIMAGE_SECTION_HEADER

         xor      edx,edx

         .while   edx<dwSections

              push edx

 

              mov      eax,[edi].SizeOfRawData

              .if  eax>0

                   .if  eax>[edi].Misc.VirtualSize

                       mov      eax,[edi].Misc.VirtualSize

                   .endif

                   mov      esi,pBaseAddress

                   add      esi,[edi].PointerToRawData

                   invoke   memcpy,pPtr,esi,eax

                   invoke   GetAlignedSize,[edi].Misc.VirtualSize,dwAlignment

                   add      pPtr,eax

              .endif

 

              pop      edx

              add      edi,sizeof IMAGE_SECTION_HEADER

              inc      edx

         .endw

         mov      status,STATUS_SUCCESS

         assume   edi:nothing

     .endif

@@:

     mov      eax,status

     ret

KLoadPEFile   endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;装载PE文件到内存并对齐

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

KLoadLibrary  proc pusFileName:PUNICODE_STRING

     local    oa:OBJECT_ATTRIBUTES

     local    iosb:IO_STATUS_BLOCK

     local    hFile:HANDLE

     local    dwFileSize:DWORD

     local    fsi:FILE_STANDARD_INFORMATION

     local    pFile:PVOID

     local    pDosHeader:PIMAGE_DOS_HEADER

     local    pNtHeaders:PIMAGE_NT_HEADERS

     local    dwImageSize

     local    pImage:PVOID

 

 

     and      pImage,0

     invoke   KeGetCurrentIrql

     .if  eax!=PASSIVE_LEVEL

         jmp      @F

     .endif

 

     InitializeObjectAttributes  addr oa,pusFileName,OBJ_CASE_INSENSITIVE orOBJ_KERNEL_HANDLE,NULL,NULL

     invoke   ZwOpenFile,addrhFile,FILE_READ_DATA or FILE_EXECUTE or SYNCHRONIZE,addr oa,addriosb,FILE_SHARE_READ,FILE_SYNCHRONOUS_IO_NONALERT

     NT_SUCCESS    eax

     .if  eax

         invoke   RtlZeroMemory,addrfsi,sizeof fsi

         invoke   ZwQueryInformationFile,hFile,addriosb,addr fsi,sizeof fsi,FileStandardInformation

         NT_SUCCESS    eax

         .if  eax

              M2M      dwFileSize,fsi.EndOfFile.LowPart

              ;分配内存

              invoke   ExAllocatePool,PagedPool,dwFileSize

              .if  eax

                   mov      pFile,eax

                   invoke   ZwReadFile,hFile,0,NULL,NULL,addr iosb,pFile,dwFileSize,0,NULL

                   NT_SUCCESS    eax

                   .if  eax

                       invoke   GetPEInfo,pFile,addr pDosHeader,addrpNtHeaders

                       .if  eax==STATUS_SUCCESS

                            invoke   GetTotalImageSize,pDosHeader,pNtHeaders

                            .if  eax

                                 mov      dwImageSize,eax

                                 invoke   ExAllocatePool,PagedPool,dwImageSize

                                 .if  eax

                                     mov      pImage,eax

                                     invoke   KLoadPEFile,pFile,pImage

                                     .if  eax!=STATUS_SUCCESS

                                          invoke   ExFreePool,pImage

                                          and      pImage,0

                                     .endif

                                 .endif

                            .endif

                       .endif

                   .endif

                   invoke   ExFreePool,pFile

              .endif

         .endif

 

         invoke   ZwClose,hFile

     .endif

@@:

     mov      eax,pImage

     ret

KLoadLibrary  endp

 

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetPEImageBase     proc uses edi  pBaseAddress:PVOID

     local    dwReturn:DWORD

 

     and      dwReturn,0

 

     mov      edi,pBaseAddress

     assume   edi:ptrIMAGE_DOS_HEADER

     .if  [edi].e_magic!=IMAGE_DOS_SIGNATURE

         jmp      @F

     .endif

     add      edi,[edi].e_lfanew

     assume   edi:ptrIMAGE_NT_HEADERS

     .if  [edi].Signature!=IMAGE_NT_SIGNATURE

         jmp      @F

     .endif

     M2M      dwReturn,[edi].OptionalHeader.ImageBase

     assume   edi:nothing

@@:

     mov      eax,dwReturn

     ret

GetPEImageBase     endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetFuncInfoByName  proc uses esi  edi  ecx  pusFuncName:PUNICODE_STRING,pBaseAddress:PVOID,pOrdinal:PDWORD

     local    dwAddress

     local    lpAddressOfNames

     local    lpAddressOfNameOrdinals

     local    dwIndex

     local    usExportFunctionName:UNICODE_STRING

     local    ansExportFunctionName:ANSI_STRING

 

     xor       eax,eax

     mov      dwAddress,eax

     mov      esi,pOrdinal

     .if  esi

         mov      dwordptr [esi],0

     .endif

 

     invoke   KeGetCurrentIrql

     .if  eax!=PASSIVE_LEVEL

         jmp      _RETURN

     .endif

 

     mov      esi,pBaseAddress

     assume   esi:ptrIMAGE_DOS_HEADER

     add      esi,[esi].e_lfanew

     assume   esi:ptrIMAGE_NT_HEADERS

     mov      eax,[esi].OptionalHeader.DataDirectory.VirtualAddress

     .if  !eax

         jmp      _RETURN

     .endif

     add      eax,pBaseAddress

     mov      edi,eax

     assume   edi:ptrIMAGE_EXPORT_DIRECTORY

 

     mov      eax,[edi].AddressOfNames

     add      eax,pBaseAddress

     mov      lpAddressOfNames,eax

     mov      eax,[edi].AddressOfNameOrdinals

     add      eax,pBaseAddress

     mov      lpAddressOfNameOrdinals,eax

     mov      eax,[edi].AddressOfFunctions

     add      eax,pBaseAddress

     mov      esi,eax

     mov      ecx,[edi].NumberOfFunctions

     mov      dwIndex,0

@@:

     pushad

     mov      eax,dwIndex

     push edi

     mov      ecx,[edi].NumberOfNames

     cld

     mov      edi,lpAddressOfNameOrdinals

     repnz    scasw

     .if  ZERO?

         sub      edi,lpAddressOfNameOrdinals

         sub      edi,2

         shl      edi,1

         add      edi,lpAddressOfNames

         mov      eax,dwordptr [edi]

         add      eax,pBaseAddress

 

         invoke   RtlInitAnsiString,addransExportFunctionName,eax

         invoke   RtlAnsiStringToUnicodeString,addrusExportFunctionName,addr ansExportFunctionName,TRUE

         invoke   RtlCompareUnicodeString,addrusExportFunctionName,pusFuncName,FALSE

         push eax

         invoke   RtlFreeUnicodeString,addrusExportFunctionName

         pop      eax

         .if  eax==0

              M2M      dwAddress,dwordptr [esi]

              pop      edi

              mov      esi,pOrdinal

              .if  esi

                   mov      ecx,dwIndex

                   add      ecx,[edi].nBase

                   mov      dword ptr [esi],ecx

              .endif

              popad

              jmp      _RETURN

         .endif

     .endif

 

     pop      edi

     popad

     add      esi,4

     inc      dwIndex

     loop @B

 

_RETURN:

     assume   esi:nothing

     mov      eax,dwAddress

     ret

GetFuncInfoByName  endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;获取DLL导出函数信息

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetFunctionInformation proc uses esi  edi     pusFuncName:PUNICODE_STRING,pusDllName:PUNICODE_STRING,pFuncInfo:PFUNCTION_INFORMATION

     local    status:NTSTATUS

     local    pBaseAddress:PVOID

 

     xor      eax,eax

     mov      pBaseAddress,eax

     mov      status,STATUS_UNSUCCESSFUL

 

     invoke   KeGetCurrentIrql

     .if  eax!=PASSIVE_LEVEL

         mov      status,STATUS_INVALID_LEVEL

         jmp      @F

     .endif

 

 

     invoke   KLoadLibrary,pusDllName

     .if  eax

         mov      pBaseAddress,eax

         mov      esi,pFuncInfo

         assume   esi:ptrFUNCTION_INFORMATION

         lea      edi,[esi].dwOridnal

         invoke   GetFuncInfoByName,pusFuncName,pBaseAddress,edi

         .if  eax

              lea      edi,[esi].dwAddress

              mov      dword ptr [edi],eax

              lea      edi,[esi].byEntryCode

              mov      esi,[esi].dwAddress

              add      esi,pBaseAddress

              invoke   memcpy,edi,esi,16

              mov      status,STATUS_SUCCESS

         .else

              mov      status,STATUS_UNSUCCESSFUL

         .endif

         invoke   ExFreePool,pBaseAddress

         assume   esi:nothing

     .endif

@@:

     mov      eax,status

     ret

GetFunctionInformation endp

 

     end

 

 

;SSDT.asm

         .386

         .model flat,stdcall

         option casemap:none

 

include  ntddk.inc

include  native.inc

include  ntoskrnl.inc

include  hal.inc

include  strings.mac

 

includePEFile.inc

include  DynamicHook.inc

include  SSDT.inc

 

         .const

CCOUNTED_UNICODE_STRING "\\Systemroot\\System32\\ntdll.dll",g_usntdllFileName,4

CCOUNTED_UNICODE_STRING "KeServiceDescriptorTable",g_usKeServiceDescriptorTable,4

 

         .code

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;获取内核文件名

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetKernel proc uses edi  pusFileName:PUNICODE_STRING

     local    dwLength:DWORD

     local    dwAddress:DWORD

     local    pBuffer

     local    szFileName[260]:byte

     local    ansFileName:ANSI_STRING

     local    dwBase:DWORD

 

     and      dwLength,0

     and      pBuffer,0

     and      dwAddress,0

     invoke   KeGetCurrentIrql

     .if  eax!=PASSIVE_LEVEL

         jmp      @F

     .endif

 

     invoke   ZwQuerySystemInformation,SystemModuleInformation,NULL,0,addrdwLength

     .if  dwLength

         invoke   ExAllocatePool,PagedPool,dwLength

         .if  eax

              mov      pBuffer,eax

              invoke   ZwQuerySystemInformation,SystemModuleInformation,pBuffer,dwLength,addrdwLength

              NT_SUCCESS    eax

              .if  eax

                   mov      eax,pBuffer

                   add      eax,4

                   assume   eax:ptr SYSTEM_MODULE_INFORMATION

                   M2M      dwBase,[eax].Base

                   lea      edi,[eax].ImageName

                   movzx    eax,[eax].ModuleNameOffset

                   add      edi,eax

                   assume   eax:nothing

                   invoke   RtlZeroMemory,addr szFileName,260

                   invoke   strcpy,addr szFileName,$CTA0("\\Systemroot\\System32\\")

                   invoke   strcat,addr szFileName,edi

                   invoke   RtlInitAnsiString,addr ansFileName,addr szFileName

                   .if  pusFileName!=NULL

                       invoke   RtlAnsiStringToUnicodeString,pusFileName,addransFileName,TRUE

                       M2M      dwAddress,dwBase

                   .endif

              .endif

              invoke   ExFreePool,pBuffer

         .endif

     .endif

@@:

     mov      eax,dwAddress

     ret

GetKernel endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

FindKiServiceTableEx   proc uses ecx  edi  esi  edx  hModule,dwKSDT

     local    dwReturn:DWORD

     local    bFirstChunk:BOOL

     local    dwCount:DWORD

     local    dwFixups:DWORD

     local    dwImageBase:DWORD

 

     and      dwReturn,0

     and      dwFixups,0

 

     mov      edi,hModule

     assume   edi:ptrIMAGE_DOS_HEADER

     .if  [edi].e_magic!=IMAGE_DOS_SIGNATURE

         jmp      @F

     .endif

     add      edi,[edi].e_lfanew

     assume   edi:ptrIMAGE_NT_HEADERS

     .if  [edi].Signature!=IMAGE_NT_SIGNATURE

         jmp      @F

     .endif

     push [edi].OptionalHeader.ImageBase

     pop      dwImageBase

     mov      eax,[edi].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC*sizeofIMAGE_DATA_DIRECTORY].VirtualAddress

     movzx    ecx,[edi].FileHeader.Characteristics

     and      ecx,IMAGE_FILE_RELOCS_STRIPPED

     .if  (eax)&& !(ecx)

         mov      edi,hModule

         add      edi,eax

         assume   edi:ptrIMAGE_BASE_RELOCATION

         mov      bFirstChunk,TRUE

         .while   bFirstChunk|| [edi].VirtualAddress

              mov      bFirstChunk,FALSE

              mov      esi,edi

              add      esi,sizeof IMAGE_BASE_RELOCATION

              assume   esi:ptr IMAGE_FIXUP_ENTRY

              mov      edx,[edi].SizeOfBlock

              sub      edx,sizeof IMAGE_BASE_RELOCATION

              ror      edx,1

              mov      dwCount,edx

              xor      edx,edx

              .while   edx<dwCount

                   push edx

 

                   mov      ax,word ptr [esi]

                   and      ax,0F000h

                   ror      ax,12

                   .if  ax==IMAGE_REL_BASED_HIGHLOW

                       inc      dwFixups

 

                       mov      ax,word ptr [esi]

                       and      ax,0FFFh

                       movzx    eax,ax

                       add      eax,[edi].VirtualAddress

                       add      eax,hModule

                       mov      ecx,eax

                       mov      eax,dword ptr [eax]

                       sub      eax,dwImageBase

                       .if  eax==dwKSDT

                            mov      eax,ecx

                            sub      eax,2

                            mov      ax,word ptr [eax]

                            .if  ax==5C7h

                                 mov      eax,ecx

                                 add      eax,4

                                 mov      eax,dword ptr [eax]

                                 sub      eax,dwImageBase

                                 mov      dwReturn,eax

                                 jmp      @F

                            .endif

                       .endif

                   .endif

 

                   pop      edx

                   inc      edx

                   add      esi,sizeof WORD

              .endw

              add      edi,[edi].SizeOfBlock

              assume   esi:nothing

         .endw

     .endif

     assume   edi:nothing

@@:

     mov      eax,dwReturn

     ret

FindKiServiceTableEx   endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;获取SSDT原始值

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetSSDTOrigValue   proc uses edi  dwIndex

     local    dwReturn:DWORD

     local    usKernelFileName:UNICODE_STRING

     local    dwKernelBase:DWORD

     local    pBaseAddress:PVOID

     local    dwImageBase:DWORD

 

     xor      eax,eax

     mov      dwReturn,eax

     mov      pBaseAddress,eax

     mov      dwKernelBase,eax

    

     invoke   KeGetCurrentIrql

     .if  eax!=PASSIVE_LEVEL

         jmp      @F

     .endif

     invoke   GetKernel,addrusKernelFileName

     .if  eax

         mov      dwKernelBase,eax

         ;映射PE文件

 

         invoke   KLoadLibrary,addrusKernelFileName

         .if  eax

              mov      pBaseAddress,eax

              invoke   GetPEImageBase,pBaseAddress

              .if  eax

                   mov      dwImageBase,eax

                   invoke   GetFuncInfoByName,addrg_usKeServiceDescriptorTable,pBaseAddress,NULL

                   .if  eax

                       invoke   FindKiServiceTableEx,pBaseAddress,eax

                       .if  eax

                            add      eax,pBaseAddress

                            mov      edi,eax

                            mov      eax,dwIndex

                            rol      eax,2

                            add      edi,eax

                            mov      eax,dword ptr [edi]

                            sub      eax,dwImageBase

                            add      eax,dwKernelBase

                            mov      dwReturn,eax

                       .endif

                   .endif

              .endif

              invoke   ExFreePool,pBaseAddress

          .endif

 

         invoke   RtlFreeUnicodeString,addrusKernelFileName

     .endif

 

@@:

     mov      eax,dwReturn

     ret

GetSSDTOrigValue   endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;获取函数的Service Index

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetSysCallIndex    proc pusFuncName:PUNICODE_STRING

     local    FuncInfo:FUNCTION_INFORMATION

 

     invoke   GetFunctionInformation,pusFuncName,addrg_usntdllFileName,addr FuncInfo

     .if  eax==STATUS_SUCCESS

         lea      eax,FuncInfo.byEntryCode

         .if  byteptr [eax]==0B8h

              inc      eax

              mov      eax,dword ptr [eax]

              ret

         .endif

     .endif

     xor      eax,eax

     ret

GetSysCallIndex    endp

 

     end

 

 

;SSDT.inc

IFNDEF   __SSDT_INC__

__SSDT_INC__  equ  <1>

 

ServiceDescriptorEntry STRUCT

     pvSSDTBase                  dd   ?

     pvServiceCounterTable  dd   ?

     ulNumberOfServices     dd   ?

     pvParamTableBase       dd   ?

ServiceDescriptorEntry ENDS

 

GetSysCallIndex        proto    :PUNICODE_STRING

GetSSDTOrigValue   proto    :DWORD

GetKernel proto    :PUNICODE_STRING

 

ENDIF

 

;PEFile.inc

IFNDEF   __PEFILE_INC__

__PEFILE_INC__     equ  <1>

 

FUNCTION_INFORMATION   STRUCT

     byEntryCode        db   16 dup (?)    ;前16字节

     dwOridnal     dd   ?

     dwAddress     dd   ?

FUNCTION_INFORMATION   ENDS

 

PFUNCTION_INFORMATION  typedef  ptr  FUNCTION_INFORMATION

 

 

IMAGE_DOS_SIGNATURE                                equ 5A4Dh

IMAGE_NT_SIGNATURE                             equ 00004550h

IMAGE_SIZEOF_SHORT_NAME                        equ 8

IMAGE_FILE_RELOCS_STRIPPED                     equ  0001h

IMAGE_REL_BASED_HIGHLOW                        equ  3

 

IMAGE_DIRECTORY_ENTRY_EXPORT                equ    0

IMAGE_DIRECTORY_ENTRY_BASERELOC                equ  5

IMAGE_NUMBEROF_DIRECTORY_ENTRIES            equ    16

 

IMAGE_DOS_HEADERSTRUCT

  e_magic           WORD      ?

  e_cblp            WORD      ?

  e_cp              WORD      ?

  e_crlc            WORD      ?

  e_cparhdr         WORD      ?

  e_minalloc        WORD      ?

  e_maxalloc        WORD      ?

  e_ss              WORD      ?

  e_sp              WORD      ?

  e_csum            WORD      ?

  e_ip              WORD      ?

  e_cs              WORD      ?

  e_lfarlc          WORD      ?

  e_ovno            WORD      ?

  e_res             WORD   4 dup(?)

  e_oemid           WORD      ?

  e_oeminfo         WORD      ?

  e_res2            WORD  10 dup(?)

  e_lfanew          DWORD      ?

IMAGE_DOS_HEADERENDS

 

PIMAGE_DOS_HEADER  typedef  ptr  IMAGE_DOS_HEADER

 

IMAGE_DATA_DIRECTORYSTRUCT

  VirtualAddress    DWORD     ?

  isize            DWORD      ?

IMAGE_DATA_DIRECTORYENDS

 

IMAGE_OPTIONAL_HEADER32STRUCT

  Magic                         WORD       ?

  MajorLinkerVersion            BYTE       ?

  MinorLinkerVersion            BYTE       ?

  SizeOfCode                    DWORD      ?

  SizeOfInitializedData         DWORD      ?

  SizeOfUninitializedData       DWORD      ?

  AddressOfEntryPoint           DWORD      ?

  BaseOfCode                    DWORD      ?

  BaseOfData                    DWORD      ?

  ImageBase                     DWORD     ?

  SectionAlignment              DWORD      ?

  FileAlignment                 DWORD      ?

  MajorOperatingSystemVersion   WORD      ?

  MinorOperatingSystemVersion   WORD      ?

  MajorImageVersion             WORD       ?

  MinorImageVersion             WORD       ?

  MajorSubsystemVersion         WORD       ?

  MinorSubsystemVersion         WORD       ?

  Win32VersionValue             DWORD      ?

  SizeOfImage                   DWORD      ?

  SizeOfHeaders                 DWORD      ?

  CheckSum                      DWORD      ?

  Subsystem                     WORD       ?

  DllCharacteristics            WORD       ?

  SizeOfStackReserve            DWORD      ?

  SizeOfStackCommit             DWORD      ?

  SizeOfHeapReserve             DWORD      ?

  SizeOfHeapCommit              DWORD      ?

  LoaderFlags                   DWORD      ?

  NumberOfRvaAndSizes           DWORD      ?

  DataDirectory                 IMAGE_DATA_DIRECTORYIMAGE_NUMBEROF_DIRECTORY_ENTRIES dup(<>)

IMAGE_OPTIONAL_HEADER32ENDS

 

IMAGE_OPTIONAL_HEADER  equ <IMAGE_OPTIONAL_HEADER32>

PIMAGE_OPTIONAL_HEADER typedef  ptr  IMAGE_OPTIONAL_HEADER

 

IMAGE_EXPORT_DIRECTORYSTRUCT

  Characteristics           DWORD      ?

  TimeDateStamp             DWORD      ?

  MajorVersion             WORD       ?

  MinorVersion              WORD       ?

  nName                     DWORD      ?

  nBase                     DWORD      ?

  NumberOfFunctions         DWORD      ?

  NumberOfNames             DWORD      ?

  AddressOfFunctions        DWORD     ?

  AddressOfNames            DWORD      ?

  AddressOfNameOrdinals     DWORD     ?

IMAGE_EXPORT_DIRECTORYENDS

 

IMAGE_FILE_HEADERSTRUCT

  Machine               WORD    ?

  NumberOfSections      WORD   ?

  TimeDateStamp         DWORD  ?

  PointerToSymbolTable  DWORD  ?

  NumberOfSymbols       DWORD  ?

  SizeOfOptionalHeader  WORD   ?

  Characteristics       WORD   ?

IMAGE_FILE_HEADERENDS

 

IMAGE_NT_HEADERSSTRUCT

  Signature         DWORD                   ?

  FileHeader        IMAGE_FILE_HEADER       <>

  OptionalHeader    IMAGE_OPTIONAL_HEADER32 <>

IMAGE_NT_HEADERSENDS

 

PIMAGE_NT_HEADERS  typedef  ptr  IMAGE_NT_HEADERS

 

IMAGE_SECTION_HEADERSTRUCT

    Name1 db IMAGE_SIZEOF_SHORT_NAME dup(?)

    union Misc

        PhysicalAddress dd  ?

        VirtualSize dd      ?

    ends

    VirtualAddress dd       ?

    SizeOfRawData dd        ?

    PointerToRawData dd     ?

    PointerToRelocations dd ?

    PointerToLinenumbers dd ?

    NumberOfRelocations dw  ?

    NumberOfLinenumbers dw  ?

    Characteristics dd      ?

IMAGE_SECTION_HEADERENDS

 

PIMAGE_SECTION_HEADER  typedef  ptr  IMAGE_SECTION_HEADER

 

IMAGE_BASE_RELOCATIONSTRUCT

    VirtualAddress dd   ?

    SizeOfBlock dd      ?

IMAGE_BASE_RELOCATIONENDS

 

PIMAGE_BASE_RELOCATION typedef  ptr  IMAGE_BASE_RELOCATION

 

GetFunctionInformation proto    :PUNICODE_STRING,:PUNICODE_STRING,:PFUNCTION_INFORMATION

GetFuncInfoByName  proto    :PUNICODE_STRING,:PVOID,:PDWORD

GetPEImageBase     proto    :PVOID

GetPEImageLength   proto    :PUNICODE_STRING

KLoadLibrary  proto    :PUNICODE_STRING

 

ENDIF

 

;SSDT.inc

 

;DyanmicHook.inc

 

IFNDEF   __DYNAMICHOOK_INC__

__DYNAMICHOOK_INC__         equ  <1>

 

 

OPEN_EXISTING                       equ 3

INVALID_HANDLE_VALUE                equ -1

FILE_MAP_READ                       equ SECTION_MAP_READ

MAX_PATH                             equ  260

 

M2M  macro    M1,M2

     push M2

     pop      M1

ENDM

 

NT_SUCCESS    macro    status

     mov      eax,status

     and      eax,80000000h

     .if  eax

         mov      eax,FALSE

     .else

         mov      eax,TRUE

     .endif

ENDM

 

ENDIF

 

    先贴代码,再来讲原理。根据我们刚才对SSDT的认识,要顺利找到SSDT的位置,首先要确定NtCreateThread的服务序号。不幸的是我尚未找到有效准确的获取方式。我唯一的思路是在ntdll.dll中找到ZwCreateThread,判断如果它的第一字节为0xB8(汇编代码MOV EAX,XXXXXXXX)那么它第二字节开始的双字就是其服务序号。用C语言描述应该是:SysCallIndex = *( (WORD*)((DWORD)GetProcAddress(ntdll,ZwCreateThread)+ 1) );

    为此,专门写了PEFile.asm这个文件,这个文件提供了一些函数:

GetFunctionInformation proto    :PUNICODE_STRING,:PUNICODE_STRING,:PFUNCTION_INFORMATION

GetFuncInfoByName  proto    :PUNICODE_STRING,:PVOID,:PDWORD

GetPEImageBase     proto    :PVOID

GetPEImageLength   proto    :PUNICODE_STRING

KLoadLibrary  proto    :PUNICODE_STRING

    其中,KLoadLibrary将PE文件按加载到内存中(不是读取到内存中,类似PE加载器一样按照PE结构中的描述对其进行加载,以便通过导出表分析导出函数在内存中的位置),其它几个函数就顾名思义了。这些函数的意思我就不再详细解释,因为这也是我3年前的代码,我也记不得太清楚。有了这几个函数,你就能够理解SSDT.asm中的GetSysCallIndex这个函数的原理。当然,我讲了这是我唯一的思路,也希望大家不吝赐教,把你知道的方法告诉我(你别说用0x35硬编码就行)

    确定了NtCreateThread的服务序号,下面我们就要在SSDT中寻找NtCreateThread的存放位置以及原始的函数地址。其实这比获取服务序号简单多了,因为一切秘密都在KeDescriptorTable这个导出符号中。需要注意的是前面我们已经说了,并不是所有系统中内核文件名都叫ntoskrnl.exe,所以先用ZwQuerySystemInformation获取一下当前系统中的内核文件名,通过对导出符号KeDescriptorTable的分析,顺利获得NtCreateThread的真实地址。具体的代码在SSDT.asm中,函数比较少,看名字就懂意思,具体我也不详细解释了,再解释又扯得很远,而且这是我3年前的代码。

    好了,打开DebugView,用KmdManager加载一下我们生成的内核程序:

 


    与前面LiveKd看到的一样,貌似一切都很顺利。
    这一章就讲完了,下一章我们就完成HookSSDT、UnHookSSDT这两个函数,我们把NtCreateThread函数Hook住,监视一下进程的创建,同时我在下一章告诉大家为什么我极不推荐普通人对SSDT使用Inline Hook,虽然它的功能更加强大!顺便希望大家检查下我的代码,谢谢。
 

 

 分类: 技术--汇编
 
imageheaderstringdoshookfile

 
    (转载请注明博客地址:http://blog.csdn.net/hitetoshi

    前面我们经常提到SSDT,那么什么是SSDT呢?SSDT(SystemServices Descriptor Table):系统服务描述符表。要对它有清楚的认识,我们先以用户态下调用CreateThread来举个例子。

    如果你有兴趣,可以用OllyDbg在CreateThread上下断点,你会发现,经过一些简单的处理,CreateThread会调用CreateRemoteThread,按F7进入CreateRemoteThread,再经过一段跟踪,会发现CreateRemoteThread实际上又调用ZwCreateThread,再按F7跟踪进去,ZwCreateThread的代码非常简单:

7C92D1AE >  B8 35000000     MOV EAX,35

7C92D1B3    BA 0003FE7F     MOVEDX,7FFE0300

7C92D1B8    FF12            CALL DWORD PTR DS:[EDX]

7C92D1BA    C2 2000         RETN 20

    注意MOV EDX,7FFE0300/CALL DWORD PTRDS:[EDX]这两条指令,从OD上可以看到,这实际上是调用ntdll.dll中的KiFastSystemCall,KiFastSystemCall的代码也很简单:

7C92E510 >  8BD4            MOV EDX,ESP

7C92E512    0F34            SYSENTER

7C92E514 >  C3              RETN

    如果这时候你再用F7一步一步的跟,你会发现,到SYSENTER这条指令时,OllyDbg无法跟踪进去,而当这条指令执行完时,实际上ZwCreateThread的功能已经执行完成――用户态的一切玄机似乎都在SYSENTER这条指令上。SYSENTER指令在用户态下向内核态发起系统调用,此时代码切换到内核,因此OllyDbg这样的用户态调试器是无法调试的。和KiFastSystemCall类似,ntdll.dll中也有一个KiIntSystemCall。PII以前的处理器并不支持SYSENTER这条指令,因此KiIntSystemCall以一条INT 2E指令切换到内核。

    SYSENTER进入内核的KiFastCallEntry(该函数没有被ntoskrnl.exe导出,你可能需要下载ntoskrnl.exe的Symbol才能看到它),KiFastCallEntry大致进行的工作就是按照SSDT表找到对应服务函数的地址,并转入到服务函数,即内核NtCreateThread中去。SSDT包含在一个叫SDT(服务描述表)的结构中,SDT由ntoskrnl.exe(某些系统下可能不是这个文件名,例如多核处理器下可能是ntkrnlpa.exe,但为简便起见,下文都用ntoskrnl.exe来表述)以KeServiceDescriptorTable为名称导出,SDT的定义如下:

ServiceDescriptorEntry STRUCT

     pvSSDTBase             dd   ?        ;SSDT基地址

     pvServiceCounterTable  dd   ?        ;SSDT中每个服务被调用次数的表

     ulNumberOfServices     dd   ?        ;描述的服务的数目

     pvParamTableBase       dd   ?        ;每个系统服务参数的字节数的表

ServiceDescriptorEntry ENDS

    我们可以在LiveKd中用d nt!KeServiceDescriptorTable来观察内核中这个结构的数据:

 


    可见系统中有0x11C个SSDT项,基地址为0x80505480,我们来看看SSDT表的内容,用d 80505480命令:

 


    从0x80505480开始,存放每个系统服务项的函数地址,那么怎么确定内核NtCreateThread的地址呢?答案就在用户态下ZwCreateThread的mov eax,0x35这条指令,它指明了NtCreateThread在SSDT中是第0x35项,计算一下0x80505480+0x35*4=0x80505554,看一看:

 


    大约NtCreateThread应该在0x805D2018这个地址,用u nt!NtCreateThread命令看一下:

 


    正是这个地址!(大家肯定会比较奇怪NtCreateThread的第一条指令怎么会是Jmp,我也是今天写这篇稳当时才发现我的NtCreateThread居然被Inline hook了!NND!一看模块,IsDrv122.sys,原来是开着冰刃……)。

    出了冰刃这个事件也好,也就是我想跟大家说的Hook SSDT,刚才大家已经看到,冰刃对SSDT的NtCreateThread做了Inline hook,我曾经说过,我极不推荐做Inline hook,除非你技术实力非常强大。原因我会在后面的文章介绍。这里我们有一个思路,如果把0x80505554这个地址的内容替换了,换成我们的函数,不是一样达到HookNtCreateThread的效果了吗?这就是SSDT Hook。在SSDT上做Hook或者是InlineHook是非常强大的,因为用户态上所有CreateThread的调用最终都会进入这个函数。很多杀毒软件会Hook SSDT的这个位置,用来监视是否有进程试图用CreateRemoteThread向其它进程启动远程线程,这是防止远程线程的一个很有效的方法。不过我们Hook NtCreateThread的目的不是这个,我前面已经说了,我们要用它来监视进程的创建,并向进程中注入代码。

    今天的这篇文章我并不会完成Hook SSDT的代码,因为在我们的内核程序中还有很多事情要做:获取NtCreateThread的服务序号、获取保存NtCreateThread地址的位置以及获取NtCreateThread的地址。

    我们在上次的DynamicHook.asm的DriverEntry中加一些代码(红色部分是新加的代码):

DriverEntry   proc pDriverObject:PDRIVER_OBJECT,pusRegistryPath:PUNICODE_STRING

     local    status:NTSTATUS

     local    pDeviceObject:PDEVICE_OBJECT

 

     mov      status,STATUS_DEVICE_CONFIGURATION_ERROR

    

     invoke   IoCreateDevice,pDriverObject,0,addrg_usDeviceName,FILE_DEVICE_UNKNOWN,0,FALSE,addr pDeviceObject

     .if  eax==STATUS_SUCCESS

         invoke   IoCreateSymbolicLink,addrg_usSymbolicLinkName,addr g_usDeviceName

         .if  eax==STATUS_SUCCESS

 

              mov      eax,pDriverObject

              assume   eax:ptr DRIVER_OBJECT

              mov      [eax].DriverUnload,offset DriverUnload

              mov      [eax].MajorFunction[IRP_MJ_CREATE*(sizeof PVOID)],offsetDispatchCreateClose

              mov      [eax].MajorFunction[IRP_MJ_CLOSE*(sizeof PVOID)],offsetDispatchCreateClose

             

              invoke   DbgPrint,$CTA0("Driver entry")

             

invoke   HookNtCreateThread

              NT_SUCCESS    eax

              .if  eax

                   invoke   DbgPrint,$CTA0("Hook success")

                   mov      status,STATUS_SUCCESS

              .else

                   invoke   DbgPrint,$CTA0("Hook failure")

              .endif

 

              assume   eax:nothing

         .else

              invoke   IoDeleteDevice,pDeviceObject

         .endif

     .endif

@@:

     mov      eax,status

     ret

DriverEntry   endp

 

        在.const节中加入:

CCOUNTED_UNICODE_STRING "NtCreateThread",g_usNtCreateThread,4

        完成HookNtCreateThread函数:

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

HookNtCreateThread proc

     local    dwNtCreateThreadIndex

     local    dwNtCreateThreadAddress

     local    status:NTSTATUS

    

     mov      status,STATUS_UNSUCCESSFUL

 

     ;获取NtCreateThread服务序号

     invoke   GetSysCallIndex,addrg_usNtCreateThread

     .if  eax

         mov      dwNtCreateThreadIndex,eax

        

         ;获取NtCreteThread在内核中的地址

         invoke   GetSSDTOrigValue,dwNtCreateThreadIndex

         .if  eax

              mov      dwNtCreateThreadAddress,eax

              invoke   DbgPrint,$CTA0("NtCreateThreadindex:%08X,address:%08X"),dwNtCreateThreadIndex,dwNtCreateThreadAddress

              mov      status,STATUS_SUCCESS

         .endif

     .endif

    

     mov      eax,status

 

     ret

HookNtCreateThread endp

 

        为了完成GetSysCallIndex和GetSSDTOrigValue这两个函数,我增加了PEFile.asm和SSDT.asm两个文件以及对应的PEFile.inc、SSDT.inc和DyanmicHook.inc,你把这些文件加入进去时,注意要向上次那样设置PEFile.asm和SSDT.asm的汇编选项,设置各个文件的依赖项(自己看include去设置,就不详述了)。先把这五个文件的内容贴出来:

;PEFile.asm

 

         .386

         .model flat,stdcall

         option casemap:none

 

include  ntddk.inc

include  native.inc

include  hal.inc

include  ntoskrnl.inc

include  strings.mac

 

include  DynamicHook.inc

include  PEFile.inc

 

         .code

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetAlignedSize     proc uses edx  ecx  dwSize,dwAlignment

 

     xor      edx,edx

     mov      eax,dwSize

     mov      ecx,dwAlignment

     div      ecx

     .if  edx==0

         mov      eax,dwSize

     .else

         inc      eax

         mul      dwAlignment

     .endif

     ret

GetAlignedSize     endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetTotalImageSize  proc uses edi  edx  ecx  pDosHeader:PIMAGE_DOS_HEADER,pNtHeaders:PIMAGE_NT_HEADERS

     local    dwResult:DWORD

     local    dwAlignment:DWORD

     local    dwSections:DWORD

 

     and      dwResult,0

     mov      edi,pNtHeaders

     assume   edi:ptrIMAGE_NT_HEADERS

     M2M      dwAlignment,[edi].OptionalHeader.SectionAlignment

     xor      edx,edx

     mov      eax,[edi].OptionalHeader.SizeOfHeaders

     mov      ecx,dwAlignment

     div      ecx

     .if  edx==0

         mov      eax,[edi].OptionalHeader.SizeOfHeaders

         add      dwResult,eax

     .else

         inc      eax

         mul      dwAlignment

         add      dwResult,eax

     .endif

     mov      edi,pNtHeaders

     assume   edi:ptrIMAGE_NT_HEADERS

 

     movzx    eax,[edi].FileHeader.NumberOfSections

     mov      dwSections,eax

     add      edi,sizeofIMAGE_NT_HEADERS

     assume   edi:ptrIMAGE_SECTION_HEADER

     xor      edx,edx

     .while   edx<dwSections

         push edx

         mov      eax,[edi].Misc.VirtualSize

         .if  eax

              xor      edx,edx

              mov      ecx,dwAlignment

              div      ecx

              .if  edx==0

                   mov      eax,[edi].Misc.VirtualSize

                   add      dwResult,eax

              .else

                   inc      eax

                   mul      dwAlignment

                   add      dwResult,eax

              .endif

         .endif

         pop      edx

         add      edi,sizeofIMAGE_SECTION_HEADER

         inc      edx

     .endw

     assume   edi:nothing

     mov      eax,dwResult

     ret

GetTotalImageSize  endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetPEInfo proc uses edi  esi  pBase:PVOID,ppDosHeader:ptr PIMAGE_DOS_HEADER,ppNtHeaders:ptrPIMAGE_NT_HEADERS

     local    status:NTSTATUS

    

     mov      status,STATUS_UNSUCCESSFUL 

     mov      edi,pBase

     assume   edi:ptrIMAGE_DOS_HEADER

     .if  [edi].e_magic!=IMAGE_DOS_SIGNATURE

         jmp      @F

     .endif

     mov      esi,ppDosHeader

     .if  esi

         mov      dwordptr [esi],edi

     .endif

     add      edi,[edi].e_lfanew

     assume   edi:ptrIMAGE_NT_HEADERS

     .if  [edi].Signature!=IMAGE_NT_SIGNATURE

         jmp      @F

     .endif

     mov      esi,ppNtHeaders

     .if  esi

         mov      dwordptr [esi],edi

     .endif

 

     mov      status,STATUS_SUCCESS

@@:

     mov      eax,status

     ret

GetPEInfo endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

KLoadPEFile   proc uses edi  esi  pBaseAddress:PVOID,pLoadAddress:PVOID

     local    status:NTSTATUS

     local    pDosHeader:PIMAGE_DOS_HEADER

     local    pNtHeaders:PIMAGE_NT_HEADERS

     local    pPtr:PVOID

     local    dwSections:DWORD

     local    dwAlignment:DWORD

    

     mov      status,STATUS_UNSUCCESSFUL

     invoke   KeGetCurrentIrql

     .if  eax!=PASSIVE_LEVEL

         mov      status,STATUS_INVALID_LEVEL

         jmp      @F

     .endif

     M2M      pPtr,pLoadAddress

 

     invoke   GetPEInfo,pBaseAddress,addrpDosHeader,addr pNtHeaders

     .if  eax==STATUS_SUCCESS

         mov      edi,pNtHeaders

         assume   edi:ptrIMAGE_NT_HEADERS

         invoke   memcpy,pPtr,pBaseAddress,[edi].OptionalHeader.SizeOfHeaders

         M2M      dwAlignment,[edi].OptionalHeader.SectionAlignment

         invoke   GetAlignedSize,[edi].OptionalHeader.SizeOfHeaders,dwAlignment

         add      pPtr,eax

        

         movzx    eax,[edi].FileHeader.NumberOfSections

         mov      dwSections,eax

         add      edi,sizeofIMAGE_NT_HEADERS

         assume   edi:ptrIMAGE_SECTION_HEADER

         xor      edx,edx

         .while   edx<dwSections

              push edx

 

              mov      eax,[edi].SizeOfRawData

              .if  eax>0

                   .if  eax>[edi].Misc.VirtualSize

                       mov      eax,[edi].Misc.VirtualSize

                   .endif

                   mov      esi,pBaseAddress

                   add      esi,[edi].PointerToRawData

                   invoke   memcpy,pPtr,esi,eax

                   invoke   GetAlignedSize,[edi].Misc.VirtualSize,dwAlignment

                   add      pPtr,eax

              .endif

 

              pop      edx

              add      edi,sizeof IMAGE_SECTION_HEADER

              inc      edx

         .endw

         mov      status,STATUS_SUCCESS

         assume   edi:nothing

     .endif

@@:

     mov      eax,status

     ret

KLoadPEFile   endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;装载PE文件到内存并对齐

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

KLoadLibrary  proc pusFileName:PUNICODE_STRING

     local    oa:OBJECT_ATTRIBUTES

     local    iosb:IO_STATUS_BLOCK

     local    hFile:HANDLE

     local    dwFileSize:DWORD

     local    fsi:FILE_STANDARD_INFORMATION

     local    pFile:PVOID

     local    pDosHeader:PIMAGE_DOS_HEADER

     local    pNtHeaders:PIMAGE_NT_HEADERS

     local    dwImageSize

     local    pImage:PVOID

 

 

     and      pImage,0

     invoke   KeGetCurrentIrql

     .if  eax!=PASSIVE_LEVEL

         jmp      @F

     .endif

 

     InitializeObjectAttributes  addr oa,pusFileName,OBJ_CASE_INSENSITIVE orOBJ_KERNEL_HANDLE,NULL,NULL

     invoke   ZwOpenFile,addrhFile,FILE_READ_DATA or FILE_EXECUTE or SYNCHRONIZE,addr oa,addriosb,FILE_SHARE_READ,FILE_SYNCHRONOUS_IO_NONALERT

     NT_SUCCESS    eax

     .if  eax

         invoke   RtlZeroMemory,addrfsi,sizeof fsi

         invoke   ZwQueryInformationFile,hFile,addriosb,addr fsi,sizeof fsi,FileStandardInformation

         NT_SUCCESS    eax

         .if  eax

              M2M      dwFileSize,fsi.EndOfFile.LowPart

              ;分配内存

              invoke   ExAllocatePool,PagedPool,dwFileSize

              .if  eax

                   mov      pFile,eax

                   invoke   ZwReadFile,hFile,0,NULL,NULL,addr iosb,pFile,dwFileSize,0,NULL

                   NT_SUCCESS    eax

                   .if  eax

                       invoke   GetPEInfo,pFile,addr pDosHeader,addrpNtHeaders

                       .if  eax==STATUS_SUCCESS

                            invoke   GetTotalImageSize,pDosHeader,pNtHeaders

                            .if  eax

                                 mov      dwImageSize,eax

                                 invoke   ExAllocatePool,PagedPool,dwImageSize

                                 .if  eax

                                     mov      pImage,eax

                                     invoke   KLoadPEFile,pFile,pImage

                                     .if  eax!=STATUS_SUCCESS

                                          invoke   ExFreePool,pImage

                                          and      pImage,0

                                     .endif

                                 .endif

                            .endif

                       .endif

                   .endif

                   invoke   ExFreePool,pFile

              .endif

         .endif

 

         invoke   ZwClose,hFile

     .endif

@@:

     mov      eax,pImage

     ret

KLoadLibrary  endp

 

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetPEImageBase     proc uses edi  pBaseAddress:PVOID

     local    dwReturn:DWORD

 

     and      dwReturn,0

 

     mov      edi,pBaseAddress

     assume   edi:ptrIMAGE_DOS_HEADER

     .if  [edi].e_magic!=IMAGE_DOS_SIGNATURE

         jmp      @F

     .endif

     add      edi,[edi].e_lfanew

     assume   edi:ptrIMAGE_NT_HEADERS

     .if  [edi].Signature!=IMAGE_NT_SIGNATURE

         jmp      @F

     .endif

     M2M      dwReturn,[edi].OptionalHeader.ImageBase

     assume   edi:nothing

@@:

     mov      eax,dwReturn

     ret

GetPEImageBase     endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetFuncInfoByName  proc uses esi  edi  ecx  pusFuncName:PUNICODE_STRING,pBaseAddress:PVOID,pOrdinal:PDWORD

     local    dwAddress

     local    lpAddressOfNames

     local    lpAddressOfNameOrdinals

     local    dwIndex

     local    usExportFunctionName:UNICODE_STRING

     local    ansExportFunctionName:ANSI_STRING

 

     xor       eax,eax

     mov      dwAddress,eax

     mov      esi,pOrdinal

     .if  esi

         mov      dwordptr [esi],0

     .endif

 

     invoke   KeGetCurrentIrql

     .if  eax!=PASSIVE_LEVEL

         jmp      _RETURN

     .endif

 

     mov      esi,pBaseAddress

     assume   esi:ptrIMAGE_DOS_HEADER

     add      esi,[esi].e_lfanew

     assume   esi:ptrIMAGE_NT_HEADERS

     mov      eax,[esi].OptionalHeader.DataDirectory.VirtualAddress

     .if  !eax

         jmp      _RETURN

     .endif

     add      eax,pBaseAddress

     mov      edi,eax

     assume   edi:ptrIMAGE_EXPORT_DIRECTORY

 

     mov      eax,[edi].AddressOfNames

     add      eax,pBaseAddress

     mov      lpAddressOfNames,eax

     mov      eax,[edi].AddressOfNameOrdinals

     add      eax,pBaseAddress

     mov      lpAddressOfNameOrdinals,eax

     mov      eax,[edi].AddressOfFunctions

     add      eax,pBaseAddress

     mov      esi,eax

     mov      ecx,[edi].NumberOfFunctions

     mov      dwIndex,0

@@:

     pushad

     mov      eax,dwIndex

     push edi

     mov      ecx,[edi].NumberOfNames

     cld

     mov      edi,lpAddressOfNameOrdinals

     repnz    scasw

     .if  ZERO?

         sub      edi,lpAddressOfNameOrdinals

         sub      edi,2

         shl      edi,1

         add      edi,lpAddressOfNames

         mov      eax,dwordptr [edi]

         add      eax,pBaseAddress

 

         invoke   RtlInitAnsiString,addransExportFunctionName,eax

         invoke   RtlAnsiStringToUnicodeString,addrusExportFunctionName,addr ansExportFunctionName,TRUE

         invoke   RtlCompareUnicodeString,addrusExportFunctionName,pusFuncName,FALSE

         push eax

         invoke   RtlFreeUnicodeString,addrusExportFunctionName

         pop      eax

         .if  eax==0

              M2M      dwAddress,dwordptr [esi]

              pop      edi

              mov      esi,pOrdinal

              .if  esi

                   mov      ecx,dwIndex

                   add      ecx,[edi].nBase

                   mov      dword ptr [esi],ecx

              .endif

              popad

              jmp      _RETURN

         .endif

     .endif

 

     pop      edi

     popad

     add      esi,4

     inc      dwIndex

     loop @B

 

_RETURN:

     assume   esi:nothing

     mov      eax,dwAddress

     ret

GetFuncInfoByName  endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;获取DLL导出函数信息

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetFunctionInformation proc uses esi  edi     pusFuncName:PUNICODE_STRING,pusDllName:PUNICODE_STRING,pFuncInfo:PFUNCTION_INFORMATION

     local    status:NTSTATUS

     local    pBaseAddress:PVOID

 

     xor      eax,eax

     mov      pBaseAddress,eax

     mov      status,STATUS_UNSUCCESSFUL

 

     invoke   KeGetCurrentIrql

     .if  eax!=PASSIVE_LEVEL

         mov      status,STATUS_INVALID_LEVEL

         jmp      @F

     .endif

 

 

     invoke   KLoadLibrary,pusDllName

     .if  eax

         mov      pBaseAddress,eax

         mov      esi,pFuncInfo

         assume   esi:ptrFUNCTION_INFORMATION

         lea      edi,[esi].dwOridnal

         invoke   GetFuncInfoByName,pusFuncName,pBaseAddress,edi

         .if  eax

              lea      edi,[esi].dwAddress

              mov      dword ptr [edi],eax

              lea      edi,[esi].byEntryCode

              mov      esi,[esi].dwAddress

              add      esi,pBaseAddress

              invoke   memcpy,edi,esi,16

              mov      status,STATUS_SUCCESS

         .else

              mov      status,STATUS_UNSUCCESSFUL

         .endif

         invoke   ExFreePool,pBaseAddress

         assume   esi:nothing

     .endif

@@:

     mov      eax,status

     ret

GetFunctionInformation endp

 

     end

 

 

;SSDT.asm

         .386

         .model flat,stdcall

         option casemap:none

 

include  ntddk.inc

include  native.inc

include  ntoskrnl.inc

include  hal.inc

include  strings.mac

 

includePEFile.inc

include  DynamicHook.inc

include  SSDT.inc

 

         .const

CCOUNTED_UNICODE_STRING "\\Systemroot\\System32\\ntdll.dll",g_usntdllFileName,4

CCOUNTED_UNICODE_STRING "KeServiceDescriptorTable",g_usKeServiceDescriptorTable,4

 

         .code

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;获取内核文件名

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetKernel proc uses edi  pusFileName:PUNICODE_STRING

     local    dwLength:DWORD

     local    dwAddress:DWORD

     local    pBuffer

     local    szFileName[260]:byte

     local    ansFileName:ANSI_STRING

     local    dwBase:DWORD

 

     and      dwLength,0

     and      pBuffer,0

     and      dwAddress,0

     invoke   KeGetCurrentIrql

     .if  eax!=PASSIVE_LEVEL

         jmp      @F

     .endif

 

     invoke   ZwQuerySystemInformation,SystemModuleInformation,NULL,0,addrdwLength

     .if  dwLength

         invoke   ExAllocatePool,PagedPool,dwLength

         .if  eax

              mov      pBuffer,eax

              invoke   ZwQuerySystemInformation,SystemModuleInformation,pBuffer,dwLength,addrdwLength

              NT_SUCCESS    eax

              .if  eax

                   mov      eax,pBuffer

                   add      eax,4

                   assume   eax:ptr SYSTEM_MODULE_INFORMATION

                   M2M      dwBase,[eax].Base

                   lea      edi,[eax].ImageName

                   movzx    eax,[eax].ModuleNameOffset

                   add      edi,eax

                   assume   eax:nothing

                   invoke   RtlZeroMemory,addr szFileName,260

                   invoke   strcpy,addr szFileName,$CTA0("\\Systemroot\\System32\\")

                   invoke   strcat,addr szFileName,edi

                   invoke   RtlInitAnsiString,addr ansFileName,addr szFileName

                   .if  pusFileName!=NULL

                       invoke   RtlAnsiStringToUnicodeString,pusFileName,addransFileName,TRUE

                       M2M      dwAddress,dwBase

                   .endif

              .endif

              invoke   ExFreePool,pBuffer

         .endif

     .endif

@@:

     mov      eax,dwAddress

     ret

GetKernel endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

FindKiServiceTableEx   proc uses ecx  edi  esi  edx  hModule,dwKSDT

     local    dwReturn:DWORD

     local    bFirstChunk:BOOL

     local    dwCount:DWORD

     local    dwFixups:DWORD

     local    dwImageBase:DWORD

 

     and      dwReturn,0

     and      dwFixups,0

 

     mov      edi,hModule

     assume   edi:ptrIMAGE_DOS_HEADER

     .if  [edi].e_magic!=IMAGE_DOS_SIGNATURE

         jmp      @F

     .endif

     add      edi,[edi].e_lfanew

     assume   edi:ptrIMAGE_NT_HEADERS

     .if  [edi].Signature!=IMAGE_NT_SIGNATURE

         jmp      @F

     .endif

     push [edi].OptionalHeader.ImageBase

     pop      dwImageBase

     mov      eax,[edi].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC*sizeofIMAGE_DATA_DIRECTORY].VirtualAddress

     movzx    ecx,[edi].FileHeader.Characteristics

     and      ecx,IMAGE_FILE_RELOCS_STRIPPED

     .if  (eax)&& !(ecx)

         mov      edi,hModule

         add      edi,eax

         assume   edi:ptrIMAGE_BASE_RELOCATION

         mov      bFirstChunk,TRUE

         .while   bFirstChunk|| [edi].VirtualAddress

              mov      bFirstChunk,FALSE

              mov      esi,edi

              add      esi,sizeof IMAGE_BASE_RELOCATION

              assume   esi:ptr IMAGE_FIXUP_ENTRY

              mov      edx,[edi].SizeOfBlock

              sub      edx,sizeof IMAGE_BASE_RELOCATION

              ror      edx,1

              mov      dwCount,edx

              xor      edx,edx

              .while   edx<dwCount

                   push edx

 

                   mov      ax,word ptr [esi]

                   and      ax,0F000h

                   ror      ax,12

                   .if  ax==IMAGE_REL_BASED_HIGHLOW

                       inc      dwFixups

 

                       mov      ax,word ptr [esi]

                       and      ax,0FFFh

                       movzx    eax,ax

                       add      eax,[edi].VirtualAddress

                       add      eax,hModule

                       mov      ecx,eax

                       mov      eax,dword ptr [eax]

                       sub      eax,dwImageBase

                       .if  eax==dwKSDT

                            mov      eax,ecx

                            sub      eax,2

                            mov      ax,word ptr [eax]

                            .if  ax==5C7h

                                 mov      eax,ecx

                                 add      eax,4

                                 mov      eax,dword ptr [eax]

                                 sub      eax,dwImageBase

                                 mov      dwReturn,eax

                                 jmp      @F

                            .endif

                       .endif

                   .endif

 

                   pop      edx

                   inc      edx

                   add      esi,sizeof WORD

              .endw

              add      edi,[edi].SizeOfBlock

              assume   esi:nothing

         .endw

     .endif

     assume   edi:nothing

@@:

     mov      eax,dwReturn

     ret

FindKiServiceTableEx   endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;获取SSDT原始值

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetSSDTOrigValue   proc uses edi  dwIndex

     local    dwReturn:DWORD

     local    usKernelFileName:UNICODE_STRING

     local    dwKernelBase:DWORD

     local    pBaseAddress:PVOID

     local    dwImageBase:DWORD

 

     xor      eax,eax

     mov      dwReturn,eax

     mov      pBaseAddress,eax

     mov      dwKernelBase,eax

    

     invoke   KeGetCurrentIrql

     .if  eax!=PASSIVE_LEVEL

         jmp      @F

     .endif

     invoke   GetKernel,addrusKernelFileName

     .if  eax

         mov      dwKernelBase,eax

         ;映射PE文件

 

         invoke   KLoadLibrary,addrusKernelFileName

         .if  eax

              mov      pBaseAddress,eax

              invoke   GetPEImageBase,pBaseAddress

              .if  eax

                   mov      dwImageBase,eax

                   invoke   GetFuncInfoByName,addrg_usKeServiceDescriptorTable,pBaseAddress,NULL

                   .if  eax

                       invoke   FindKiServiceTableEx,pBaseAddress,eax

                       .if  eax

                            add      eax,pBaseAddress

                            mov      edi,eax

                            mov      eax,dwIndex

                            rol      eax,2

                            add      edi,eax

                            mov      eax,dword ptr [edi]

                            sub      eax,dwImageBase

                            add      eax,dwKernelBase

                            mov      dwReturn,eax

                       .endif

                   .endif

              .endif

              invoke   ExFreePool,pBaseAddress

          .endif

 

         invoke   RtlFreeUnicodeString,addrusKernelFileName

     .endif

 

@@:

     mov      eax,dwReturn

     ret

GetSSDTOrigValue   endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;获取函数的Service Index

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GetSysCallIndex    proc pusFuncName:PUNICODE_STRING

     local    FuncInfo:FUNCTION_INFORMATION

 

     invoke   GetFunctionInformation,pusFuncName,addrg_usntdllFileName,addr FuncInfo

     .if  eax==STATUS_SUCCESS

         lea      eax,FuncInfo.byEntryCode

         .if  byteptr [eax]==0B8h

              inc      eax

              mov      eax,dword ptr [eax]

              ret

         .endif

     .endif

     xor      eax,eax

     ret

GetSysCallIndex    endp

 

     end

 

 

;SSDT.inc

IFNDEF   __SSDT_INC__

__SSDT_INC__  equ  <1>

 

ServiceDescriptorEntry STRUCT

     pvSSDTBase                  dd   ?

     pvServiceCounterTable  dd   ?

     ulNumberOfServices     dd   ?

     pvParamTableBase       dd   ?

ServiceDescriptorEntry ENDS

 

GetSysCallIndex        proto    :PUNICODE_STRING

GetSSDTOrigValue   proto    :DWORD

GetKernel proto    :PUNICODE_STRING

 

ENDIF

 

;PEFile.inc

IFNDEF   __PEFILE_INC__

__PEFILE_INC__     equ  <1>

 

FUNCTION_INFORMATION   STRUCT

     byEntryCode        db   16 dup (?)    ;前16字节

     dwOridnal     dd   ?

     dwAddress     dd   ?

FUNCTION_INFORMATION   ENDS

 

PFUNCTION_INFORMATION  typedef  ptr  FUNCTION_INFORMATION

 

 

IMAGE_DOS_SIGNATURE                                equ 5A4Dh

IMAGE_NT_SIGNATURE                             equ 00004550h

IMAGE_SIZEOF_SHORT_NAME                        equ 8

IMAGE_FILE_RELOCS_STRIPPED                     equ  0001h

IMAGE_REL_BASED_HIGHLOW                        equ  3

 

IMAGE_DIRECTORY_ENTRY_EXPORT                equ    0

IMAGE_DIRECTORY_ENTRY_BASERELOC                equ  5

IMAGE_NUMBEROF_DIRECTORY_ENTRIES            equ    16

 

IMAGE_DOS_HEADERSTRUCT

  e_magic           WORD      ?

  e_cblp            WORD      ?

  e_cp              WORD      ?

  e_crlc            WORD      ?

  e_cparhdr         WORD      ?

  e_minalloc        WORD      ?

  e_maxalloc        WORD      ?

  e_ss              WORD      ?

  e_sp              WORD      ?

  e_csum            WORD      ?

  e_ip              WORD      ?

  e_cs              WORD      ?

  e_lfarlc          WORD      ?

  e_ovno            WORD      ?

  e_res             WORD   4 dup(?)

  e_oemid           WORD      ?

  e_oeminfo         WORD      ?

  e_res2            WORD  10 dup(?)

  e_lfanew          DWORD      ?

IMAGE_DOS_HEADERENDS

 

PIMAGE_DOS_HEADER  typedef  ptr  IMAGE_DOS_HEADER

 

IMAGE_DATA_DIRECTORYSTRUCT

  VirtualAddress    DWORD     ?

  isize            DWORD      ?

IMAGE_DATA_DIRECTORYENDS

 

IMAGE_OPTIONAL_HEADER32STRUCT

  Magic                         WORD       ?

  MajorLinkerVersion            BYTE       ?

  MinorLinkerVersion            BYTE       ?

  SizeOfCode                    DWORD      ?

  SizeOfInitializedData         DWORD      ?

  SizeOfUninitializedData       DWORD      ?

  AddressOfEntryPoint           DWORD      ?

  BaseOfCode                    DWORD      ?

  BaseOfData                    DWORD      ?

  ImageBase                     DWORD     ?

  SectionAlignment              DWORD      ?

  FileAlignment                 DWORD      ?

  MajorOperatingSystemVersion   WORD      ?

  MinorOperatingSystemVersion   WORD      ?

  MajorImageVersion             WORD       ?

  MinorImageVersion             WORD       ?

  MajorSubsystemVersion         WORD       ?

  MinorSubsystemVersion         WORD       ?

  Win32VersionValue             DWORD      ?

  SizeOfImage                   DWORD      ?

  SizeOfHeaders                 DWORD      ?

  CheckSum                      DWORD      ?

  Subsystem                     WORD       ?

  DllCharacteristics            WORD       ?

  SizeOfStackReserve            DWORD      ?

  SizeOfStackCommit             DWORD      ?

  SizeOfHeapReserve             DWORD      ?

  SizeOfHeapCommit              DWORD      ?

  LoaderFlags                   DWORD      ?

  NumberOfRvaAndSizes           DWORD      ?

  DataDirectory                 IMAGE_DATA_DIRECTORYIMAGE_NUMBEROF_DIRECTORY_ENTRIES dup(<>)

IMAGE_OPTIONAL_HEADER32ENDS

 

IMAGE_OPTIONAL_HEADER  equ <IMAGE_OPTIONAL_HEADER32>

PIMAGE_OPTIONAL_HEADER typedef  ptr  IMAGE_OPTIONAL_HEADER

 

IMAGE_EXPORT_DIRECTORYSTRUCT

  Characteristics           DWORD      ?

  TimeDateStamp             DWORD      ?

  MajorVersion             WORD       ?

  MinorVersion              WORD       ?

  nName                     DWORD      ?

  nBase                     DWORD      ?

  NumberOfFunctions         DWORD      ?

  NumberOfNames             DWORD      ?

  AddressOfFunctions        DWORD     ?

  AddressOfNames            DWORD      ?

  AddressOfNameOrdinals     DWORD     ?

IMAGE_EXPORT_DIRECTORYENDS

 

IMAGE_FILE_HEADERSTRUCT

  Machine               WORD    ?

  NumberOfSections      WORD   ?

  TimeDateStamp         DWORD  ?

  PointerToSymbolTable  DWORD  ?

  NumberOfSymbols       DWORD  ?

  SizeOfOptionalHeader  WORD   ?

  Characteristics       WORD   ?

IMAGE_FILE_HEADERENDS

 

IMAGE_NT_HEADERSSTRUCT

  Signature         DWORD                   ?

  FileHeader        IMAGE_FILE_HEADER       <>

  OptionalHeader    IMAGE_OPTIONAL_HEADER32 <>

IMAGE_NT_HEADERSENDS

 

PIMAGE_NT_HEADERS  typedef  ptr  IMAGE_NT_HEADERS

 

IMAGE_SECTION_HEADERSTRUCT

    Name1 db IMAGE_SIZEOF_SHORT_NAME dup(?)

    union Misc

        PhysicalAddress dd  ?

        VirtualSize dd      ?

    ends

    VirtualAddress dd       ?

    SizeOfRawData dd        ?

    PointerToRawData dd     ?

    PointerToRelocations dd ?

    PointerToLinenumbers dd ?

    NumberOfRelocations dw  ?

    NumberOfLinenumbers dw  ?

    Characteristics dd      ?

IMAGE_SECTION_HEADERENDS

 

PIMAGE_SECTION_HEADER  typedef  ptr  IMAGE_SECTION_HEADER

 

IMAGE_BASE_RELOCATIONSTRUCT

    VirtualAddress dd   ?

    SizeOfBlock dd      ?

IMAGE_BASE_RELOCATIONENDS

 

PIMAGE_BASE_RELOCATION typedef  ptr  IMAGE_BASE_RELOCATION

 

GetFunctionInformation proto    :PUNICODE_STRING,:PUNICODE_STRING,:PFUNCTION_INFORMATION

GetFuncInfoByName  proto    :PUNICODE_STRING,:PVOID,:PDWORD

GetPEImageBase     proto    :PVOID

GetPEImageLength   proto    :PUNICODE_STRING

KLoadLibrary  proto    :PUNICODE_STRING

 

ENDIF

 

;SSDT.inc

 

;DyanmicHook.inc

 

IFNDEF   __DYNAMICHOOK_INC__

__DYNAMICHOOK_INC__         equ  <1>

 

 

OPEN_EXISTING                       equ 3

INVALID_HANDLE_VALUE                equ -1

FILE_MAP_READ                       equ SECTION_MAP_READ

MAX_PATH                             equ  260

 

M2M  macro    M1,M2

     push M2

     pop      M1

ENDM

 

NT_SUCCESS    macro    status

     mov      eax,status

     and      eax,80000000h

     .if  eax

         mov      eax,FALSE

     .else

         mov      eax,TRUE

     .endif

ENDM

 

ENDIF

 

    先贴代码,再来讲原理。根据我们刚才对SSDT的认识,要顺利找到SSDT的位置,首先要确定NtCreateThread的服务序号。不幸的是我尚未找到有效准确的获取方式。我唯一的思路是在ntdll.dll中找到ZwCreateThread,判断如果它的第一字节为0xB8(汇编代码MOV EAX,XXXXXXXX)那么它第二字节开始的双字就是其服务序号。用C语言描述应该是:SysCallIndex = *( (WORD*)((DWORD)GetProcAddress(ntdll,ZwCreateThread)+ 1) );

    为此,专门写了PEFile.asm这个文件,这个文件提供了一些函数:

GetFunctionInformation proto    :PUNICODE_STRING,:PUNICODE_STRING,:PFUNCTION_INFORMATION

GetFuncInfoByName  proto    :PUNICODE_STRING,:PVOID,:PDWORD

GetPEImageBase     proto    :PVOID

GetPEImageLength   proto    :PUNICODE_STRING

KLoadLibrary  proto    :PUNICODE_STRING

    其中,KLoadLibrary将PE文件按加载到内存中(不是读取到内存中,类似PE加载器一样按照PE结构中的描述对其进行加载,以便通过导出表分析导出函数在内存中的位置),其它几个函数就顾名思义了。这些函数的意思我就不再详细解释,因为这也是我3年前的代码,我也记不得太清楚。有了这几个函数,你就能够理解SSDT.asm中的GetSysCallIndex这个函数的原理。当然,我讲了这是我唯一的思路,也希望大家不吝赐教,把你知道的方法告诉我(你别说用0x35硬编码就行)

    确定了NtCreateThread的服务序号,下面我们就要在SSDT中寻找NtCreateThread的存放位置以及原始的函数地址。其实这比获取服务序号简单多了,因为一切秘密都在KeDescriptorTable这个导出符号中。需要注意的是前面我们已经说了,并不是所有系统中内核文件名都叫ntoskrnl.exe,所以先用ZwQuerySystemInformation获取一下当前系统中的内核文件名,通过对导出符号KeDescriptorTable的分析,顺利获得NtCreateThread的真实地址。具体的代码在SSDT.asm中,函数比较少,看名字就懂意思,具体我也不详细解释了,再解释又扯得很远,而且这是我3年前的代码。

    好了,打开DebugView,用KmdManager加载一下我们生成的内核程序:

 


    与前面LiveKd看到的一样,貌似一切都很顺利。
    这一章就讲完了,下一章我们就完成HookSSDT、UnHookSSDT这两个函数,我们把NtCreateThread函数Hook住,监视一下进程的创建,同时我在下一章告诉大家为什么我极不推荐普通人对SSDT使用Inline Hook,虽然它的功能更加强大!顺便希望大家检查下我的代码,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值