登录  | 立即注册

游客您好!登录后享受更多精彩

查看: 140|回复: 0

纯驱动恢复SSDT

[复制链接]

31

主题

2

回帖

51

积分

版主

积分
51
发表于 2024-12-30 21:15:29 | 显示全部楼层 |阅读模式
*  SDT恢复是一个古老的技术了,这些天复习以前的知识,发现东西都忘了.正好找到了这份源码.
*  于是开始边注释边复习起来. 现在终于又把RING3下恢复SSDT的东西温习了一下,感觉很充实.
*  偶很菜,一开始看代码的时候,不知道如何下手,因为原作者的代码风格很乱,看得糊涂.于是偶
*  按照 M$ 的代码风格重新注释了一遍,方便以后温习. 如果你还木有看过这份源码的话,在偶注释
*  的基础上应该会理解的更快些了.
*  
*  搜索了下坛子,发现没有关于这份源码的相关细节.于是偶来补充下.
*  存档的主要目的是方便以后学习这些知识的同学更快的找到资源,少走弯路. 老鸟飘过~
*
* Description:
*  
*  在RING3获得 \device\physicalmemory 的读写权限(前提必须是Administrator). 从磁盘读取
*  ntoskrnl.exe,对齐后映射进内存(这需要我们自己来做),在其EAT中得到KeServiceDescriptorTable
*  相对于ntoskrnl.exe的偏移.把系统高端加载的ntoskrnl.exe 的SSDT地址映射到进程的虚拟地址空间里
*  推算出ServiseTable的地址后,把其所有内容映射到进程的虚拟地址空间里. 得到了ServiseTable的地址
*  但它里面的函数是否被HOOK过,并不知道.所以需要参照我们自己映射的ntoskrnl.exe中的ServiseTable
*  里函数的偏移来作比较.不相同,则被HOOK了,然后恢复之.
头文件


  1. #ifndef GLOBAL_NATIVE_API_DEF_SUDAMI
  2. #define GLOBAL_NATIVE_API_DEF_SUDAMI

  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif

  6. ////////////////////////////////////////////////////////////////////////
  7. ////////////////////////////////////////////////////////////////////////

  8. typedef long NTSTATUS, *PNTSTATUS;

  9. typedef unsigned long DWORD;
  10. typedef DWORD * PDWORD;
  11. typedef unsigned long ULONG;
  12. typedef unsigned long ULONG_PTR;
  13. typedef ULONG *PULONG;
  14. typedef unsigned short WORD;
  15. typedef unsigned char BYTE;
  16. typedef unsigned char UCHAR;
  17. typedef unsigned short USHORT;
  18. typedef void *PVOID;
  19. typedef int BOOL;
  20. typedef BYTE BOOLEAN;


  21. #define NT_SUCCESS(Status)                            ((NTSTATUS)(Status) >= 0)
  22. #define STATUS_SUCCESS                                        0x00000000
  23. #define STATUS_UNSUCCESSFUL                                0xC0000001
  24. #define STATUS_NOT_IMPLEMENTED          0xC0000002
  25. #define STATUS_INFO_LENGTH_MISMATCH     0xC0000004
  26. #define STATUS_INVALID_PARAMETER                0xC000000D
  27. #define STATUS_ACCESS_DENIED                        0xC0000022
  28. #define STATUS_BUFFER_TOO_SMALL                        0xC0000023
  29. #define STATUS_IO_DEVICE_ERROR          ((NTSTATUS) 0xC0000185)
  30. #define OBJ_KERNEL_HANDLE                                0x00000200

  31. #ifndef  LOWORD
  32. #define LOWORD(l)           ((unsigned short)(unsigned int)(l))
  33. #endif

  34. #ifndef HIWORD
  35. #define HIWORD(l)           ((unsigned short)((((unsigned int)(l)) >> 16) & 0xFFFF))
  36. #endif

  37. // 定义ioctl相关的,用于R3和R0间的通信
  38. #ifndef MAKELONG
  39. #define MAKELONG(a, b) ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))
  40. #endif

  41. #define MY_DEVICE_TYPE                 0x0000AA71   // 这地方可以自己改
  42. #define DRIVER_IO(code)         CTL_CODE (MY_DEVICE_TYPE, code, METHOD_BUFFERED, FILE_ANY_ACCESS)

  43. typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;


  44. /////////////////////////////////////////////////////////////////         --          --     
  45. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//     --     -      -     --
  46. //+                                                           +//     --      -   -       --
  47. //+                      结构体声明                           +//      --       -        --  
  48. //+                                                           +//       -     sudami     -   
  49. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//        --            --   
  50. /////////////////////////////////////////////////////////////////          --        --      
  51. //                                                                           --    --        
  52. //                                                                              --   

  53. #ifndef  ANSI_STRING
  54. typedef struct _STRING {
  55.   USHORT  Length;
  56.   USHORT  MaximumLength;
  57.   PCHAR  Buffer;
  58. } ANSI_STRING, *PANSI_STRING;
  59. #endif

  60. #ifndef  UNICODE_STRING
  61. typedef struct _UNICODE_STRING {
  62.   USHORT  Length;
  63.   USHORT  MaximumLength;
  64.   PWSTR  Buffer;
  65. } UNICODE_STRING, *PUNICODE_STRING;
  66. #endif

  67. /* SSDT */
  68. #pragma pack(1)
  69. typedef struct ServiceDescriptorEntry {
  70.         unsigned int        *ServiceTableBase;
  71.         unsigned int        *ServiceCounterTableBase;
  72.         unsigned int        NumberOfServices;
  73.         unsigned char   *ParamTableBase;
  74. } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;

  75. typedef struct ServiceDescriptorShadowEntry {
  76.         unsigned int        *Win32kTableBase;
  77.         unsigned int        *Win32kCounterTableBase;
  78.         unsigned int        NumberofWin32kServices;
  79.         unsigned char   *Win32kParamTableBase;
  80. } ServiceDescriptorTableShadowEntry_t, *PServiceDescriptorTableShadowEntry_t;
  81. #pragma pack()

  82. __declspec(dllimport)  ServiceDescriptorTableEntry_t    KeServiceDescriptorTable;
  83. PServiceDescriptorTableShadowEntry_t                                        KeServiceDescriptorTableShadow;

  84. // OBJECT_ATTRIBUTES
  85. typedef struct _OBJECT_ATTRIBUTES {
  86.         DWORD                         Length;
  87.         HANDLE                        RootDirectory;
  88.         PUNICODE_STRING               ObjectName;
  89.         DWORD                         Attributes;
  90.         PSECURITY_DESCRIPTOR          SecurityDescriptor;
  91.         PSECURITY_QUALITY_OF_SERVICE  SecurityQualityOfService;
  92. } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;



  93. // CLIENT_ID
  94. #ifndef  CLIENT_ID
  95. typedef struct _CLIENT_ID {
  96.         HANDLE     UniqueProcess;
  97.         HANDLE     UniqueThread;
  98. } CLIENT_ID, *PCLIENT_ID;
  99. #endif

  100. /*
  101. struct _SYSTEM_THREADS
  102. {
  103.         LARGE_INTEGER                KernelTime;
  104.         LARGE_INTEGER                UserTime;
  105.         LARGE_INTEGER                CreateTime;
  106.         ULONG                                WaitTime;
  107.         PVOID                                StartAddress;
  108.         CLIENT_ID                        ClientIs;
  109.         KPRIORITY                        Priority;
  110.         KPRIORITY                        BasePriority;
  111.         ULONG                                ContextSwitchCount;
  112.         ULONG                                ThreadState;
  113.         KWAIT_REASON                WaitReason;
  114. };

  115. struct _SYSTEM_PROCESSES
  116. {
  117.         ULONG                                NextEntryDelta;
  118.         ULONG                                ThreadCount;
  119.         ULONG                                Reserved[6];
  120.         LARGE_INTEGER                CreateTime;
  121.         LARGE_INTEGER                UserTime;
  122.         LARGE_INTEGER                KernelTime;
  123.         UNICODE_STRING                ProcessName;
  124.         KPRIORITY                        BasePriority;
  125.         ULONG                                ProcessId;
  126.         ULONG                                InheritedFromProcessId;
  127.         ULONG                                HandleCount;
  128.         ULONG                                Reserved2[2];
  129.         VM_COUNTERS                        VmCounters;
  130.         IO_COUNTERS                        IoCounters; //windows 2000 only
  131.         struct _SYSTEM_THREADS                Threads[1];
  132. };


  133. // PROCESS_BASIC_INFORMATION
  134. #ifdef  PROCESS_BASIC_INFORMATION
  135. #undef  PROCESS_BASIC_INFORMATION
  136. typedef struct _PROCESS_BASIC_INFORMATION {
  137.         NTSTATUS                ExitStatus;
  138.         ULONG                        PebBaseAddress;
  139.         ULONG_PTR                AffinityMask;
  140.         LONG                        BasePriority;
  141.         ULONG_PTR                UniqueProcessId;
  142.         ULONG_PTR                InheritedFromUniqueProcessId;
  143. } PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
  144. #endif


  145. // SYSTEM_HANDLE_INFORMATION
  146. typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO {
  147.      USHORT UniqueProcessId;
  148.      USHORT CreatorBackTraceIndex;
  149.      UCHAR ObjectTypeIndex;
  150.      UCHAR HandleAttributes;
  151.      USHORT HandleValue;   // 句柄
  152.      PVOID Object;         // 若HANDLE类型为线程,则它是ETHREAD结构
  153.      ULONG GrantedAccess;
  154. } SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;

  155. typedef struct _SYSTEM_HANDLE_INFORMATION {
  156.      ULONG NumberOfHandles;
  157.      SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
  158. } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
  159. */

  160. // SYSTEM_MODULE_INFORMATION
  161. typedef struct _SYSTEM_MODULE_INFORMATION {
  162.         ULONG        Reserved[2];
  163.         PVOID        Base;
  164.         ULONG        Size;
  165.         ULONG        Flags;
  166.         USHORT  Index;
  167.         USHORT  Unknown;
  168.         USHORT  LoadCount;
  169.         USHORT  ModuleNameOffset;
  170.         CHAR    ImageName[256];
  171. } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;


  172. typedef struct {
  173.     ULONG   dwNumberOfModules;
  174.     SYSTEM_MODULE_INFORMATION   smi;
  175. } MODULES, *PMODULES;


  176. // SYSTEM_BASIC_INFORMATION
  177. typedef struct _SYSTEM_BASIC_INFORMATION {
  178.         ULONG Unknown;                  //Always contains zero
  179.         ULONG MaximumIncrement;         //一个时钟的计量单位
  180.         ULONG PhysicalPageSize;         //一个内存页的大小
  181.         ULONG NumberOfPhysicalPages;    //系统管理着多少个页
  182.         ULONG LowestPhysicalPage;       //低端内存页
  183.         ULONG HighestPhysicalPage;      //高端内存页
  184.         ULONG AllocationGranularity;
  185.         ULONG LowestUserAddress;        //地端用户地址
  186.         ULONG HighestUserAddress;       //高端用户地址
  187.         ULONG ActiveProcessors;         //激活的处理器
  188.         UCHAR NumberProcessors;         //有多少个处理器
  189. } SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION;


  190. // SYSTEM_INFORMATION_CLASS
  191. typedef enum _SYSTEM_INFORMATION_CLASS {
  192.     SystemBasicInformation,
  193.     SystemProcessorInformation,
  194.     SystemPerformanceInformation,
  195.     SystemTimeOfDayInformation,
  196.     SystemPathInformation,
  197.     SystemProcessInformation,
  198.     SystemCallCountInformation,
  199.     SystemDeviceInformation,
  200.     SystemProcessorPerformanceInformation,
  201.     SystemFlagsInformation,
  202.     SystemCallTimeInformation,
  203.     SystemModuleInformation,  // 11
  204.     SystemLocksInformation,
  205.     SystemStackTraceInformation,
  206.     SystemPagedPoolInformation,
  207.     SystemNonPagedPoolInformation,
  208.     SystemHandleInformation,  // 0x10 -- 16
  209.     SystemObjectInformation,
  210.     SystemPageFileInformation,
  211.     SystemVdmInstemulInformation,
  212.     SystemVdmBopInformation,
  213.     SystemFileCacheInformation,
  214.     SystemPoolTagInformation,
  215.     SystemInterruptInformation,
  216.     SystemDpcBehaviorInformation,
  217.     SystemFullMemoryInformation,
  218.     SystemLoadGdiDriverInformation,
  219.     SystemUnloadGdiDriverInformation,
  220.     SystemTimeAdjustmentInformation,
  221.     SystemSummaryMemoryInformation,
  222.     SystemUnused1,
  223.     SystemPerformanceTraceInformation,
  224.     SystemCrashDumpInformation,
  225.     SystemExceptionInformation,
  226.     SystemCrashDumpStateInformation,
  227.     SystemKernelDebuggerInformation,
  228.     SystemContextSwitchInformation,
  229.     SystemRegistryQuotaInformation,
  230.     SystemExtendServiceTableInformation,
  231.     SystemPrioritySeperation,
  232.     SystemUnused3,
  233.     SystemUnused4,
  234.     SystemUnused5,
  235.     SystemUnused6,
  236.     SystemCurrentTimeZoneInformation,
  237.     SystemLookasideInformation,
  238.     SystemTimeSlipNotification,
  239.     SystemSessionCreate,
  240.     SystemSessionDetach,
  241.     SystemSessionInformation
  242. } SYSTEM_INFORMATION_CLASS;


  243. #ifndef  SECTION_INHERIT
  244. typedef enum _SECTION_INHERIT {
  245.         ViewShare = 1,
  246.         ViewUnmap = 2
  247. } SECTION_INHERIT;
  248. #endif



  249. /******************************************************
  250. *                                                     *
  251. *                   部分 PE 结构                      *
  252. *                                                     *
  253. ******************************************************/

  254. #ifndef IMAGE_DOS_SIGNATURE
  255. #define IMAGE_DOS_SIGNATURE 0x5a4d      // MZ
  256. #endif

  257. #ifndef IMAGE_NT_SIGNATURE
  258. #define IMAGE_NT_SIGNATURE  0x00004550  // PE00
  259. #endif

  260. // _IMAGE_DOS_HEADER
  261. struct MZHeader
  262. {
  263.         unsigned short signature; // "MZ"
  264.         unsigned short partPag;
  265.         unsigned short pageCnt;
  266.         unsigned short reloCnt;
  267.         unsigned short hdrSize;
  268.         unsigned short minMem;
  269.         unsigned short maxMem;
  270.         unsigned short reloSS;
  271.         unsigned short exeSP;
  272.         unsigned short chksum;
  273.         unsigned short exeIP;
  274.         unsigned short reloCS;
  275.         unsigned short tablOff;
  276.         unsigned short overlay;
  277.         unsigned char reserved[32];
  278.         unsigned long offsetToPE;
  279. };

  280. // DWORD signature + _IMAGE_FILE_HEADER. 不是完全的IMAGE_FILE_HEADER.
  281. struct PE_Header
  282. {
  283.         unsigned long signature; // "PE\0\0"
  284.         unsigned short machine;
  285.         unsigned short numSections;
  286.         unsigned long timeDateStamp;
  287.         unsigned long pointerToSymbolTable;
  288.         unsigned long numOfSymbols;
  289.         unsigned short sizeOfOptionHeader;
  290.         unsigned short characteristics;
  291. };

  292. // _IMAGE_OPTIONAL_HEADER
  293. struct PE_ExtHeader
  294. {
  295.         unsigned short magic;
  296.         unsigned char majorLinkerVersion;
  297.         unsigned char minorLinkerVersion;
  298.         unsigned long sizeOfCode;
  299.         unsigned long sizeOfInitializedData;
  300.         unsigned long sizeOfUninitializedData;
  301.         unsigned long addressOfEntryPoint;
  302.         unsigned long baseOfCode;
  303.         unsigned long baseOfData;
  304.         unsigned long imageBase;
  305.         unsigned long sectionAlignment;
  306.         unsigned long fileAlignment;
  307.         unsigned short majorOSVersion;
  308.         unsigned short minorOSVersion;
  309.         unsigned short majorImageVersion;
  310.         unsigned short minorImageVersion;
  311.         unsigned short majorSubsystemVersion;
  312.         unsigned short minorSubsystemVersion;
  313.         unsigned long reserved1;
  314.         unsigned long sizeOfImage;
  315.         unsigned long sizeOfHeaders;
  316.         unsigned long checksum;
  317.         unsigned short subsystem;
  318.         unsigned short DLLCharacteristics;
  319.         unsigned long sizeOfStackReserve;
  320.         unsigned long sizeOfStackCommit;
  321.         unsigned long sizeOfHeapReserve;
  322.         unsigned long sizeOfHeapCommit;
  323.         unsigned long loaderFlags;
  324.         unsigned long numberOfRVAAndSizes;
  325.         unsigned long exportTableAddress;
  326.         unsigned long exportTableSize;
  327.         unsigned long importTableAddress;
  328.         unsigned long importTableSize;
  329.         unsigned long resourceTableAddress;
  330.         unsigned long resourceTableSize;
  331.         unsigned long exceptionTableAddress;
  332.         unsigned long exceptionTableSize;
  333.         unsigned long certFilePointer;
  334.         unsigned long certTableSize;
  335.         unsigned long relocationTableAddress;
  336.         unsigned long relocationTableSize;
  337.         unsigned long debugDataAddress;
  338.         unsigned long debugDataSize;
  339.         unsigned long archDataAddress;
  340.         unsigned long archDataSize;
  341.         unsigned long globalPtrAddress;
  342.         unsigned long globalPtrSize;
  343.         unsigned long TLSTableAddress;
  344.         unsigned long TLSTableSize;
  345.         unsigned long loadConfigTableAddress;
  346.         unsigned long loadConfigTableSize;
  347.         unsigned long boundImportTableAddress;
  348.         unsigned long boundImportTableSize;
  349.         unsigned long importAddressTableAddress;
  350.         unsigned long importAddressTableSize;
  351.         unsigned long delayImportDescAddress;
  352.         unsigned long delayImportDescSize;
  353.         unsigned long COMHeaderAddress;
  354.         unsigned long COMHeaderSize;
  355.         unsigned long reserved2;
  356.         unsigned long reserved3;
  357. };

  358. // _IMAGE_SECTION_HEADER
  359. struct SectionHeader
  360. {
  361.         unsigned char sectionName[8];
  362.         unsigned long virtualSize;
  363.         unsigned long virtualAddress;
  364.         unsigned long sizeOfRawData;
  365.         unsigned long pointerToRawData;
  366.         unsigned long pointerToRelocations;
  367.         unsigned long pointerToLineNumbers;
  368.         unsigned short numberOfRelocations;
  369.         unsigned short numberOfLineNumbers;
  370.         unsigned long characteristics;
  371. };

  372. struct ImportDirEntry
  373. {
  374.         DWORD importLookupTable;
  375.         DWORD timeDateStamp;
  376.         DWORD fowarderChain;
  377.         DWORD nameRVA;
  378.         DWORD importAddressTable;
  379. };


  380. /******************************************************
  381. *                                                     *
  382. *                 结构体自定义区域                    *
  383. *                                                     *
  384. ******************************************************/


  385. typedef struct _MY_PROCESS_INFO {
  386.         ULONG     PID;
  387.         ULONG          KPEB;
  388.         ULONG     CR3;
  389.         CHAR      Name[16];
  390.         ULONG     Reserved;
  391. } MY_PROCESS_INFO, *PMY_PROCESS_INFO;



  392. /////////////////////////////////////////////////////////////////         --          --     
  393. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//     --     -      -     --
  394. //+                                                           +//     --      -   -       --
  395. //+                      函数原型声明                         +//      --       -        --  
  396. //+                                                           +//       -     sudami     -   
  397. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//        --            --   
  398. /////////////////////////////////////////////////////////////////          --        --      
  399. //                                                                           --    --        
  400. //                                                                              --

  401. NTSYSAPI
  402. NTSTATUS
  403. NTAPI
  404. NtCreateFile(
  405.   OUT PHANDLE             FileHandle,
  406.   IN ACCESS_MASK          DesiredAccess,
  407.   IN POBJECT_ATTRIBUTES   ObjectAttributes,
  408. //  OUT PIO_STATUS_BLOCK    IoStatusBlock,
  409.   IN PLARGE_INTEGER       AllocationSize OPTIONAL,
  410.   IN ULONG                FileAttributes,
  411.   IN ULONG                ShareAccess,
  412.   IN ULONG                CreateDisposition,
  413.   IN ULONG                CreateOptions,
  414.   IN PVOID                EaBuffer OPTIONAL,
  415.   IN ULONG                EaLength
  416.   );


  417. NTSYSAPI
  418. VOID
  419. NTAPI
  420. RtlInitUnicodeString(
  421.      PUNICODE_STRING DestinationString,
  422.      PCWSTR SourceString
  423.      );

  424. NTSYSAPI
  425. NTSTATUS
  426. NTAPI
  427. ZwOpenSection(
  428.      OUT PHANDLE SectionHandle,
  429.      IN ACCESS_MASK DesiredAccess,
  430.      IN POBJECT_ATTRIBUTES objectAttributes
  431.      );


  432. NTSYSAPI
  433. NTSTATUS
  434. NTAPI
  435. ZwMapViewOfSection(
  436.      IN HANDLE SectionHandle,
  437.      IN HANDLE ProcessHandle,
  438.      IN OUT PVOID *BaseAddress,
  439.      IN ULONG ZeroBits,
  440.      IN ULONG CommitSize,
  441.      IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
  442.      IN OUT PULONG ViewSize,
  443.      IN SECTION_INHERIT InheritDisposition,
  444.      IN ULONG AllocationType,
  445.      IN ULONG Protect
  446.      );


  447. NTSYSAPI
  448. NTSTATUS
  449. NTAPI
  450. ZwUnmapViewOfSection(
  451.      IN HANDLE ProcessHandle,
  452.      IN PVOID BaseAddress
  453.      );

  454. /*
  455. NTSYSAPI
  456. NTSTATUS
  457. NTAPI
  458. NtVdmControl(
  459.      IN ULONG ControlCode,
  460.      IN PVOID ControlData
  461.      );

  462. NTSYSAPI
  463. NTSTATUS
  464. PsLookupProcessByProcessId (
  465.     IN HANDLE ProcessId,
  466.     OUT PEPROCESS *Process
  467.     );

  468. NTSYSAPI
  469. NTSTATUS
  470. PsLookupThreadByThreadId (
  471.     IN HANDLE ThreadId,
  472.     OUT PETHREAD *Thread
  473.     );
  474. */


  475. NTSYSAPI
  476. NTSTATUS
  477. NTAPI
  478. NtQuerySystemInformation(

  479.   IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
  480.   OUT PVOID               SystemInformation,
  481.   IN ULONG                SystemInformationLength,
  482.   OUT PULONG              ReturnLength OPTIONAL
  483.   );




  484. //
  485. //
  486. //
  487. //

  488. VOID
  489. RtlFreeUnicodeString(
  490.     IN PUNICODE_STRING  UnicodeString
  491.     );

  492. NTSTATUS (WINAPI * _RtlAnsiStringToUnicodeString)
  493.         (PUNICODE_STRING  DestinationString,
  494.          IN PANSI_STRING  SourceString,
  495.          IN BOOLEAN);

  496. VOID (WINAPI *_RtlInitAnsiString)
  497.         (IN OUT PANSI_STRING  DestinationString,
  498.          IN PCHAR  SourceString);

  499. /////////////////////////////////////////////////////////////////         --          --     
  500. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//     --     -      -     --
  501. //+                                                           +//     --      -   -       --
  502. //+                    一些自定义必备函数                     +//      --       -        --  
  503. //+                                                           +//       -     sudami     -   
  504. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//        --            --   
  505. /////////////////////////////////////////////////////////////////          --        --      
  506. //                                                                           --    --        
  507. //                                                                              --


  508. // 写保护的开&关
  509. void WPOFF()
  510. {
  511.         __asm {   //去掉内存保护
  512.                 cli
  513.                 mov  eax,cr0
  514.                 and  eax,not 10000h
  515.                 mov  cr0,eax
  516.         }
  517. }

  518. void WPON()
  519. {
  520.         __asm {   //恢复内存保护  
  521.                 mov  eax,cr0
  522.                 or   eax,10000h
  523.                 mov  cr0,eax
  524.                 sti
  525.         }
  526. }

  527. //////////////////////////////////////////////////////////////////////////////////
  528. //////////////////////////////////////////////////////////////////////////////////

  529. #ifdef __cplusplus
  530. }
  531. #endif

  532. #endif
复制代码
.c文件



  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <windows.h>
  4. #include <aclapi.h>
  5. #include "rootkit.h"

  6. ////////////////////////////////////////////////////////////////////

  7. #pragma comment (lib, "F:\\WINDDK\\lib\\wxp\\i386\\ntdll.lib")

  8. ////////////////////////////////////////////////////////////////////

  9. #define OBJ_CASE_INSENSITIVE                        0x00000040L
  10. #define PAGE_READONLY                                        0x02
  11. #define PAGE_READWRITE                                        0x04
  12. #define DEF_KERNEL_BASE                                        0x80400000L
  13. #define PROT_MEMBASE                                        0x80000000


  14. DWORD gWinVersion;

  15. struct FixupBlock
  16. {
  17.         ULONG pageRVA;
  18.         ULONG blockSize;
  19. };

  20. /*++

  21. 3个函数,就不用注解了

  22. --*/
  23. BOOL GetNativeAPIs ()
  24. {
  25.         HMODULE hntdll;

  26.         hntdll = GetModuleHandle("ntdll.dll");
  27.                        
  28.         *(FARPROC *)&_RtlAnsiStringToUnicodeString =
  29.                         GetProcAddress(hntdll, "RtlAnsiStringToUnicodeString");

  30.         *(FARPROC *)&_RtlInitAnsiString =
  31.                         GetProcAddress(hntdll, "RtlInitAnsiString");

  32.         if (_RtlAnsiStringToUnicodeString && _RtlInitAnsiString) {
  33.                 return TRUE;
  34.         }

  35.         return FALSE;
  36. }

  37. DWORD myStrlenA (char *ptr)
  38. {
  39.         DWORD len = 0;
  40.         while(*ptr) {
  41.                 len++;
  42.                 ptr++;
  43.         }

  44.         return len;
  45. }

  46. BOOL myStrcmpA (char *str1, char *str2)
  47. {
  48.         while(*str1 && *str2) {
  49.                 if(*str1 == *str2) {
  50.                         str1++;
  51.                         str2++;
  52.                 } else {
  53.                         return FALSE;
  54.                 }
  55.         }

  56.         if (*str1 && !*str2) {
  57.                 return FALSE;
  58.         } else if (*str2 && !*str1){
  59.                 return FALSE;
  60.         }

  61.         return TRUE;       
  62. }


  63. //----------------------                         ----------------------                    
  64. //                      -------------------------                      ---------------------
  65. BOOL
  66. ReadPEInfo (
  67.   char *modulePos,
  68.   MZHeader *outMZ,
  69.   PE_Header *outPE,
  70.   PE_ExtHeader *outpeXH,
  71.   SectionHeader **outSecHdr
  72.   )

  73. /*++

  74. 学习者 : sudami [xiao_rui_119@163.com]
  75. 时间   : 08/01/11

  76. 功能   :
  77.   得到映射到内存的PE结构中各部分的地址

  78. 参数   :
  79.   
  80.   modulePos - [IN] 将磁盘上的文件读出来后,映射到进程的虚拟地址空间中,对齐后得到其起始地址.
  81.   outMZ - [OUT] 保存MZ头 IMAGE_DOS_HEADER
  82.   outPE - [OUT] 保存PE头 IMAGE_FILE_HEADER
  83.   outpeXH - [OUT] 保存扩展PE头 IMAGE_OPTIONAL_HEADER
  84.   outSecHdr - [OUT] 2级指针,保存Section头 IMAGE_SECTION_HEADER

  85. 返回 :
  86.   
  87.   TRUE -  读取成功
  88.   FALSE - 不是有效的PE文件,读取失败

  89. --*/
  90. {
  91.         MZHeader *mzH = (MZHeader *)modulePos;

  92.         if (mzH->signature != IMAGE_DOS_SIGNATURE) {
  93.                 printf("File does not have MZ header\n");
  94.                 return false;
  95.         }

  96.         PE_Header *peH = (PE_Header *)(modulePos + mzH->offsetToPE);

  97.         // 通过 sizeOfOptionHeader 验证PE文件的合法性(它是 _IMAGE_OPTIONAL_HEADER 的尺寸)
  98.         if (peH->sizeOfOptionHeader != sizeof (PE_ExtHeader)) {
  99.                 printf("Unexpected option header size.\n");
  100.                 return false;
  101.         }

  102.         PE_ExtHeader *peXH = (PE_ExtHeader *)((char *)peH + sizeof(PE_Header));
  103.         SectionHeader *secHdr = (SectionHeader *)((char *)peXH + sizeof(PE_ExtHeader));

  104.         *outMZ      =  *mzH;
  105.         *outPE      =  *peH;
  106.         *outpeXH    =  *peXH;
  107.         *outSecHdr  =  secHdr;

  108.         return true;
  109. }

  110. //----------------------                         ----------------------                    
  111. //                      -------------------------                      ---------------------
  112. int
  113. CalcTotalImageSize (
  114.   MZHeader *inMZ,
  115.   PE_Header *inPE,
  116.   PE_ExtHeader *inpeXH,
  117.   SectionHeader *inSecHdr
  118.   )

  119. /*++

  120. 学习者 : sudami [xiao_rui_119@163.com]
  121. 时间   : 08/01/11

  122. 功能 :
  123.   计算PE文件加载到内存所需要占用的空间: 所有的文件头长度 + 所有的节长度

  124. 返回 :
  125.   PE在内存中对齐后需要的大小

  126. --*/
  127. {
  128.         int result = 0;
  129.         int val    = 0;

  130.         /* (1) 统计所有文件头在内存中对齐后所需空间 */
  131.         // sectionAlignment 为段加载后在内存中的对齐方式 4KB
  132.         int alignment = inpeXH->sectionAlignment;

  133.         // 如果所有的文件头长度之和 是4KB整数倍。则留给它的空间就是sizeOfHeaders
  134.         if (inpeXH->sizeOfHeaders % alignment == 0) {

  135.                 result += inpeXH->sizeOfHeaders;
  136.         } else { // 如果所有的文件头长度之和 非4KB整数倍。则需要对齐后申请空间

  137.             val = inpeXH->sizeOfHeaders / alignment;
  138.                 val++;
  139.                 result += (val * alignment);
  140.         }

  141.         /* (2) 统计所有节在内存中对齐后所需空间 */
  142.         for (int i = 0; i < inPE->numSections; i++) {

  143.                 // virtualSize 是 块对齐前的真实长度
  144.                 if (inSecHdr[i].virtualSize) {
  145.                         if (inSecHdr[i].virtualSize % alignment == 0) {
  146.                                 result += inSecHdr[i].virtualSize;
  147.                         } else {
  148.                                 val = inSecHdr[i].virtualSize / alignment;
  149.                                 val++;
  150.                                 result += (val * alignment);
  151.                         }
  152.                 }
  153.         }

  154.         return result;
  155. }

  156. //----------------------                         ----------------------                    
  157. //                      -------------------------                      ---------------------
  158. ULONG
  159. GetAlignedSize (
  160.   ULONG curSize,
  161.   ULONG alignment
  162.   )

  163. /*++

  164. 功能 :
  165.   得到对齐后的文件大小

  166. 参数 :
  167.   curSize - 未对齐前的大小
  168.   alignment - 段加载后在内存中的对齐方式,一般为4KB

  169. 返回 :
  170.   对齐后的大小

  171. --*/
  172. {       
  173.         if (curSize % alignment == 0) { // 如果不存在对齐方式,则不对齐,直接返回原大小
  174.                 return curSize;
  175.         } else {
  176.                 int val = curSize / alignment;
  177.                 val++;
  178.                 return (val * alignment);
  179.         }
  180. }

  181. //----------------------                         ----------------------                    
  182. //                      -------------------------                      ---------------------
  183. BOOL
  184. LoadPE (
  185.   char *exePtr,
  186.   MZHeader *inMZ,
  187.   PE_Header *inPE,
  188.   PE_ExtHeader *inpeXH,
  189.   SectionHeader *inSecHdr,
  190.   LPVOID ptrLoc
  191.   )

  192. /*++

  193. 学习者 : sudami [xiao_rui_119@163.com]
  194. 时间   : 08/01/11

  195. 功能 :
  196.   加载从磁盘读取的文件到内存,需要自己对齐

  197.            <PE加载到内存对齐后的示意图>
  198.           所有文件头      节1      节2     ...     节N
  199.          ------------------------------------------------
  200.         |aa...aa######| a...a##| a...a###| ... | a...a##|
  201.          ------------------------------------------------
  202.   注: a 表示实际数据; # 表示空隙,是内存中对齐后留出的空隙

  203. 参数 :
  204.   exePtr - PE文件在磁盘中时起始的地址.还没有经过对齐.所以需要把它映射到内存
  205.   ...
  206.   ptrLoc - 根据内存中PE的大小调用HeapAlloc而分配的一块空闲内存区域.

  207. 返回 : TRUE

  208. --*/
  209. {
  210.         char *outPtr = (char *)ptrLoc;

  211.         // 把所有文件头的数据全部拷贝到ptrLoc指向的地址处
  212.         // 然后地址按照PE在内存中的对齐方式往后挪
  213.         memcpy (outPtr, exePtr, inpeXH->sizeOfHeaders);
  214.         outPtr += GetAlignedSize (inpeXH->sizeOfHeaders, inpeXH->sectionAlignment);

  215.         // 拷贝所有的节数据到新的地址处. 复制的时候要知道每个节在文件中的实际大小.而不是在内存在对齐后的大小
  216.         for (int i = 0; i < inPE->numSections; i++) {

  217.                 if (inSecHdr[i].sizeOfRawData > 0) { // sizeOfRawData 是节对齐后的长度
  218.                         ULONG toRead = inSecHdr[i].sizeOfRawData;

  219.                         if (toRead > inSecHdr[i].virtualSize) {
  220.                                 toRead = inSecHdr[i].virtualSize;
  221.                         }

  222.                         // 拷贝没个节的实际数据,然后把指针挪到每个节在内存中对齐后的位置处
  223.                         memcpy (outPtr, exePtr + inSecHdr[i].pointerToRawData, toRead);

  224.                         outPtr += GetAlignedSize (inSecHdr[i].virtualSize, inpeXH->sectionAlignment);
  225.                 }
  226.         }

  227.         return true;
  228. }

  229. //----------------------                         ----------------------                    
  230. //                      -------------------------                      ---------------------
  231. LPVOID
  232. LoadDLL (
  233.   char *dllName
  234.   )

  235. /*++

  236. 学习者 : sudami [xiao_rui_119@163.com]
  237. 时间   : 08/01/11

  238. 功能 :
  239.   将指定模块从磁盘读取,然后映射进内存,按照对齐的方式映射.这需要我们自己来做.
  240.   这个过程是调用 自定义函数 LoadPE

  241. 流程 :
  242.   CreateFile 打开指定的文件 --> GetFileInformationByHandle 获得文件的大小信息a -->
  243.   HeapAlloc 分配大小为a的内存 --> ReadFile 将文件读入此内存区域中 --> ReadPEInfo 获得
  244.   PE文件各结构地址 --> CalcTotalImageSize 计算此文件映射到内存对齐后的总大小b  -->
  245.   HeapAlloc 分配大小为b的内存 --> LoadPE加载之

  246. 参数 :
  247.   exePtr - 指定的模块名称,不包含路径.所以一般是系统目录下的文件


  248. 返回 : 完成加载后,对齐后的PE在进程空间中一段内存的起始地址

  249. --*/
  250. {
  251.         MZHeader mzH2;
  252.         PE_Header peH2;
  253.         PE_ExtHeader peXH2;
  254.         SectionHeader *secHdr2;
  255.         char moduleFilename[MAX_PATH + 1];
  256.         LPVOID ptrLoc = NULL;

  257.         GetSystemDirectory (moduleFilename, MAX_PATH);
  258.         if (moduleFilename[MAX_PATH - 1] != '\\') {
  259.                 strcat (moduleFilename, "\");
  260.         }

  261.         if ((myStrlenA (moduleFilename) + myStrlenA (dllName)) >= MAX_PATH)
  262.                 return NULL;

  263.         strcat (moduleFilename, dllName);

  264.     // 调用CreateFile打开要映射的文件
  265.         HANDLE fp = CreateFile (moduleFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
  266.        
  267.         if (fp != INVALID_HANDLE_VALUE) {

  268.                 // 通过打开的文件句柄得到文件的信息: 主要是文件的大小
  269.                 BY_HANDLE_FILE_INFORMATION  fileInfo;
  270.                 GetFileInformationByHandle (fp, &fileInfo);
  271.                 DWORD fileSize = fileInfo.nFileSizeLow;
  272.                
  273.                 // 得到了磁盘文件的大小后,为其分配内存
  274.                 if (fileSize) {
  275.                         // 在当前进程的Heap中为其分配一段空间
  276.                         LPVOID exePtr = HeapAlloc (GetProcessHeap(), 0, fileSize);

  277.                         if (exePtr) {
  278.                                 DWORD read;

  279.                                 // read = 保存的是实际读入的大小. 如果完全读完了.就计算PE在内存中对齐后的大小.
  280.                                 if ( ReadFile (fp, exePtr, fileSize, &read, NULL) && read == fileSize) {                                       
  281.                                         if ( ReadPEInfo ((char *)exePtr, &mzH2, &peH2, &peXH2, &secHdr2)) {
  282.                                                 int imageSize = CalcTotalImageSize(&mzH2, &peH2, &peXH2, secHdr2);                                       
  283.                                                 ptrLoc = HeapAlloc(GetProcessHeap(), 0, imageSize);

  284.                                                 if (ptrLoc) {       
  285.                                                         LoadPE ((char *)exePtr, &mzH2, &peH2, &peXH2, secHdr2, ptrLoc);
  286.                                                 }
  287.                                         }

  288.                                 }
  289.                         }

  290.                         HeapFree (GetProcessHeap(), 0, exePtr);
  291.                 }

  292.                 CloseHandle (fp);
  293.         }

  294.         return ptrLoc;
  295. }


  296. //----------------------                         ----------------------                    
  297. //                      -------------------------                      ---------------------
  298. DWORD
  299. ProcAPIExportAddr (
  300.   DWORD hModule,
  301.   char *apiName
  302.   )

  303. /*++

  304. 学习者 : sudami [xiao_rui_119@163.com]
  305. 时间   : 08/01/11

  306. 功能 :
  307.   得到指定模块EAT中的指定函数相对于ntoskrnl.exe的偏移

  308. 参数 :
  309.   hModule - 模块地址

  310.   apiName - 指定函数名

  311. 返回 :

  312.   0 - 如果传进来的参数不正确,则返回0
  313.   # - 指定模块EAT中的指定函数相对于ntoskrnl.exe的偏移

  314. --*/
  315. {       
  316.         if (!hModule || !apiName) {
  317.                 return 0;
  318.         }

  319.         char *ptr = (char *)hModule;
  320.         ptr += 0x3c;
  321.        
  322.         ptr = (char *)(*(DWORD *)ptr) + hModule + 0x78; // 此时ptr保存的是EAT的偏移
  323.         ptr = (char *)(*(DWORD *)ptr) + hModule;                // 此时ptr指向EAT

  324.         DWORD numEntries = *(DWORD *)(ptr + 24);        // 24-->0x18 NumberOfNames
  325.         DWORD *ExportNamePointerTable = (DWORD *)(*(DWORD *)(ptr + 32) + hModule); // 32-->0x20  AddressOfNames       
  326.         DWORD ordinalBase = *((DWORD *)(ptr + 16));         // 16-->0x10  Base
  327.         WORD *ExportOrdinalTable = (WORD *)((*(DWORD *)(ptr + 36)) + hModule);           // 36-->0x24  AddressOfNameOrdinals
  328.         DWORD *ExportAddrTable = (DWORD *)((*(DWORD *)(ptr + 28)) + hModule);      // 28-->0x1C  AddressOfFunctions

  329.         // 遍历每个有名字的函数 (有的函数没有名字)
  330.         for(DWORD i = 0; i < numEntries; i++)
  331.         {
  332.                 // 得到函数的名字
  333.                 char *exportName = (char *)(ExportNamePointerTable[i] + hModule);

  334.                 if (myStrcmpA (exportName, apiName) == TRUE) {               
  335.                         // 得到函数在AddressOfFunctions中的索引号
  336.                         WORD ordinal = ExportOrdinalTable[i];

  337.                         return (DWORD)(ExportAddrTable[ordinal]);
  338.                 }               
  339.         }

  340.         return 0;
  341. }


  342. //----------------------                         ----------------------                    
  343. //                      -------------------------                      ---------------------
  344. BOOL
  345. BuildNativeAPITable (
  346.   DWORD hModule,
  347.   char *nativeAPINames[],
  348.   DWORD numNames
  349.   )

  350. /*++

  351. 学习者 : sudami [xiao_rui_119@163.com]
  352. 时间   : 08/01/11

  353. 功能 :
  354.   从ntdll.dll的EAT中搜索,建立一张 API 函数表

  355. 参数 :
  356.   hModule - 模块地址

  357.   nativeAPINames[] - [OUT]保存函数名的数组

  358.   numNames -

  359. 返回 : TRUE | FALSE  

  360. --*/
  361. {
  362.         if(!hModule) {
  363.                 return FALSE;
  364.         }

  365.         char *ptr = (char *)hModule;
  366.         ptr += 0x3c;
  367.        
  368.         ptr = (char *)(*(DWORD *)ptr) + hModule + 0x78; // 此时ptr保存的是EAT的偏移

  369.         ptr = (char *)(*(DWORD *)ptr) + hModule;                // 此时ptr指向EAT

  370.         DWORD numEntries = *(DWORD *)(ptr + 24);        // 24-->0x18 NumberOfNames
  371.         DWORD *ExportNamePointerTable = (DWORD *)(*(DWORD *)(ptr + 32) + hModule); // 32-->0x20  AddressOfNames       
  372.         DWORD ordinalBase = *((DWORD *)(ptr + 16));                                    // 16-->0x10  Base
  373.         WORD *ExportOrdinalTable = (WORD *)((*(DWORD *)(ptr + 36)) + hModule);           // 36-->0x24  AddressOfNameOrdinals
  374.         DWORD *ExportAddrTable = (DWORD *)((*(DWORD *)(ptr + 28)) + hModule);      // 28-->0x1C  AddressOfFunctions


  375.         for (DWORD i = 0; i < numEntries; i++)
  376.         {               
  377.                 // i now contains the index of the API in the Ordinal Table
  378.                 // ptr points to Export directory table

  379.                 WORD ordinalValue = ExportOrdinalTable[i];               
  380.                 DWORD apiAddr = (DWORD)ExportAddrTable[ordinalValue] + hModule;
  381.                 char *exportName = (char *)(ExportNamePointerTable[i] + hModule);
  382.                
  383.                 // Win2K
  384.                 if (gWinVersion == 0 &&
  385.                    *((UCHAR *)apiAddr) == 0xB8 &&
  386.                    *((UCHAR *)apiAddr + 9) == 0xCD &&
  387.                    *((UCHAR *)apiAddr + 10) == 0x2E) {

  388.                         DWORD serviceNum = *(DWORD *)((char *)apiAddr + 1);

  389.                         if(serviceNum < numNames){
  390.                                 nativeAPINames[serviceNum] = exportName;
  391.                         }
  392.                 }
  393.                
  394.                 // WinXP
  395.                 else if (gWinVersion == 1 &&
  396.                                 *((UCHAR *)apiAddr) == 0xB8 &&
  397.                                 *((UCHAR *)apiAddr + 5) == 0xBA &&
  398.                                 *((UCHAR *)apiAddr + 6) == 0x00 &&
  399.                                 *((UCHAR *)apiAddr + 7) == 0x03 &&
  400.                                 *((UCHAR *)apiAddr + 8) == 0xFE &&
  401.                                 *((UCHAR *)apiAddr + 9) == 0x7F) {

  402.                         DWORD serviceNum = *(DWORD *)((char *)apiAddr + 1);

  403.                         if(serviceNum < numNames) {
  404.                                 nativeAPINames[serviceNum] = exportName;
  405.                         }
  406.                 }
  407.         }

  408.         return TRUE;
  409. }




  410. //----------------------                         ----------------------                    
  411. //                      -------------------------                      ---------------------
  412. HANDLE
  413. OpenPhyMem(
  414.                    )

  415. /*++

  416. 学习者 : sudami [xiao_rui_119@163.com]
  417. 时间   : 08/01/11

  418. 功能 :
  419.   从用户态获得 \device\physicalmemory 的句柄

  420. 参数 : NULL

  421. 返回 : \device\physicalmemory 的句柄
  422.   
  423. --*/
  424. {
  425.         HANDLE hPhyMem;
  426.         OBJECT_ATTRIBUTES oAttr;
  427.         ANSI_STRING aStr;
  428.                
  429.         _RtlInitAnsiString (&aStr, "\\device\\physicalmemory");
  430.                                                
  431.         UNICODE_STRING uStr;

  432.         if (_RtlAnsiStringToUnicodeString (&uStr, &aStr, TRUE) != STATUS_SUCCESS){               
  433.                 return INVALID_HANDLE_VALUE;       
  434.         }

  435.     oAttr.Length                         =  sizeof(OBJECT_ATTRIBUTES);
  436.     oAttr.RootDirectory                 =  NULL;
  437.     oAttr.Attributes                 =  OBJ_CASE_INSENSITIVE;
  438.     oAttr.ObjectName                 =  &uStr;
  439.     oAttr.SecurityDescriptor =  NULL;
  440.     oAttr.SecurityQualityOfService = NULL;

  441.         if (ZwOpenSection (&hPhyMem, SECTION_MAP_READ | SECTION_MAP_WRITE, &oAttr ) != STATUS_SUCCESS) {               
  442.                 return INVALID_HANDLE_VALUE;
  443.         }

  444.         return hPhyMem;
  445. }

  446. //----------------------                         ----------------------                    
  447. //                      -------------------------                      ---------------------
  448. BOOL
  449. MapPhyMem (
  450.   HANDLE hPhyMem,
  451.   DWORD *phyAddr,
  452.   DWORD *length,
  453.   PVOID *virtualAddr
  454.   )

  455. /*++

  456. 学习者 : sudami [xiao_rui_119@163.com]
  457. 时间   : 08/01/11

  458. 功能 :
  459.   从用户态获得 \device\physicalmemory 的句柄
  460.   映射系统地址空间内的一部分数据到用户的地址空间.前提当然是用户对这段空间有读写权限
  461.   映射结束后 phyAddr 的值发生了变化,它挪到了映射结束的地方

  462. 参数 :  
  463.   hPhyMem - \device\physicalmemory 的句柄
  464.   phyAddr - [IN OUT] 从系统地址范围内的指定位置处开始映射
  465.   length  - 指定映射的大小
  466.   virtualAddr - 进程的虚拟地址空间中保存映射的起始地址

  467. 返回 :
  468.   
  469. --*/
  470. {
  471.         NTSTATUS                        ntStatus;
  472.         PHYSICAL_ADDRESS        viewBase;

  473.         *virtualAddr = 0;
  474.         viewBase.QuadPart = (ULONGLONG) (*phyAddr);

  475.         ntStatus = ZwMapViewOfSection (
  476.                 hPhyMem,
  477.                 (HANDLE)-1,
  478.                 virtualAddr, // 指定接收映射的起始地址
  479.                 0,
  480.                 *length,     // 指定映射的大小
  481.                 &viewBase,   // 指定从哪儿开始映射
  482.                 length,      // 保存实际的映射大小
  483.                 ViewShare,   // 指定继承性
  484.                 0,
  485.                 PAGE_READWRITE
  486.                 );

  487.         if (ntStatus != STATUS_SUCCESS) {
  488.                 printf("Failed to map physical memory view of length %X at %X!", *length, *phyAddr);
  489.                 return FALSE;                                       
  490.         }

  491.         *phyAddr = viewBase.LowPart;
  492.         return TRUE;
  493. }


  494. // Unmap section of physical memory
  495. void UnMapPhyMem(DWORD virtualAddr)
  496. {
  497.         NTSTATUS status;

  498.         status = ZwUnmapViewOfSection ((HANDLE)-1, (PVOID)virtualAddr);
  499.         if (status != STATUS_SUCCESS) {
  500.                 printf("Unmapping view failed!\n");
  501.         }
  502. }

  503. //----------------------                         ----------------------                    
  504. //                      -------------------------                      ---------------------
  505. BOOL
  506. AssignACL (
  507.                    )

  508. /*++

  509. 学习者 : sudami [xiao_rui_119@163.com]
  510. 时间   : 08/01/11

  511. 功能 :
  512.   使当前的用户对 \device\physicalmemory 有写的权限
  513.   btw: 此部分需要参考MSDN,里面的数据结构太多.

  514. 参数 :  NULL

  515. 返回 : TRUE | FALSE
  516.   
  517. --*/
  518. {
  519.         HANDLE             hPhyMem;
  520.         ANSI_STRING        aStr;
  521.         UNICODE_STRING     uStr;
  522.         OBJECT_ATTRIBUTES  oAttr;
  523.         BOOL               result = FALSE;
  524.                
  525.         _RtlInitAnsiString(&aStr, "\\device\\physicalmemory");

  526.         if (_RtlAnsiStringToUnicodeString (&uStr, &aStr, TRUE) != STATUS_SUCCESS) {               
  527.                 return FALSE;
  528.         }

  529.     oAttr.Length                                   = sizeof(OBJECT_ATTRIBUTES);
  530.     oAttr.RootDirectory                           = NULL;
  531.     oAttr.Attributes                           = OBJ_CASE_INSENSITIVE;
  532.     oAttr.ObjectName                           = &uStr;
  533.     oAttr.SecurityDescriptor           = NULL;
  534.     oAttr.SecurityQualityOfService = NULL;

  535.         if (ZwOpenSection (&hPhyMem, READ_CONTROL | WRITE_DAC, &oAttr ) != STATUS_SUCCESS) {               
  536.                 return FALSE;
  537.         } else {
  538.                 PACL dacl;
  539.                 PSECURITY_DESCRIPTOR  sd;

  540.                 if ( GetSecurityInfo (hPhyMem, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL,
  541.                                                 &dacl, NULL, &sd) == ERROR_SUCCESS) {

  542.                         EXPLICIT_ACCESS ea;

  543.                         // 得到当前进程的用户名
  544.                         char userName[MAX_PATH];
  545.                         DWORD userNameSize = MAX_PATH-1;
  546.                         GetUserName (userName, &userNameSize);

  547.                         // 设置精确的权限
  548.                         ea.grfAccessPermissions                = SECTION_MAP_WRITE;
  549.                         ea.grfAccessMode                        = GRANT_ACCESS;
  550.                         ea.grfInheritance                        = NO_INHERITANCE;
  551.                         ea.Trustee.pMultipleTrustee = NULL;
  552.                         ea.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  553.                         ea.Trustee.TrusteeForm                = TRUSTEE_IS_NAME;
  554.                         ea.Trustee.TrusteeType                = TRUSTEE_IS_USER;
  555.                         ea.Trustee.ptstrName                = userName;

  556.                         // 建立新的ACL
  557.                         PACL newDacl;
  558.                         if ( SetEntriesInAcl(1, &ea, dacl, &newDacl) == ERROR_SUCCESS)        {
  559.                                 // 用新的DACL重新设置当前对象的安全权限
  560.                                 if( SetSecurityInfo (hPhyMem, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL,
  561.                                                                 newDacl, NULL) == ERROR_SUCCESS) {               
  562.                                         result = TRUE;
  563.                                 }

  564.                                 LocalFree(newDacl);
  565.                         }
  566.                 }
  567.         }

  568.         return result;       
  569. }

  570. //----------------------                         ----------------------                    
  571. //                      -------------------------                      ---------------------
  572. DWORD
  573. GetKernelBase (
  574.                            void
  575.                            )

  576. /*++

  577. 学习者 : sudami [xiao_rui_119@163.com]
  578. 时间   : 08/01/11

  579. 功能 :
  580.   为NtQuerySystemInformation传递11号参数,得到SYSTEM_MODULE_INFORMATION信息,遍历之,得到ntoskrnl.exe的基址

  581. 参数 :  NULL

  582. 返回 : TRUE | FALSE
  583.   
  584. --*/
  585. {
  586.         HANDLE hHeap = GetProcessHeap();
  587.        
  588.         NTSTATUS Status;
  589.     ULONG cbBuffer = 0x8000;
  590.     PVOID pBuffer = NULL;
  591.         DWORD retVal = DEF_KERNEL_BASE; // 0x80400000

  592.         // 这样申请内存 - cbBuffer *= 2;,不错不错.学习~
  593.     do {
  594.                 pBuffer = HeapAlloc (hHeap, 0, cbBuffer);
  595.                 if (pBuffer == NULL) {
  596.                         return DEF_KERNEL_BASE;
  597.                 }

  598.                 Status = NtQuerySystemInformation (SystemModuleInformation,        pBuffer, cbBuffer, NULL);

  599.                 if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  600.                         HeapFree (hHeap, 0, pBuffer);
  601.                         cbBuffer *= 2;
  602.                 } else if (Status != STATUS_SUCCESS) {
  603.                         HeapFree(hHeap, 0, pBuffer);
  604.                         return DEF_KERNEL_BASE;
  605.                 }
  606.     }
  607.     while (Status == STATUS_INFO_LENGTH_MISMATCH);

  608.         // 其实没必要这样写哦. 得到系统模块的地址后,第一个就是ntoskrnl.exe的了
  609.         DWORD numEntries = *((DWORD *)pBuffer);
  610.         SYSTEM_MODULE_INFORMATION *smi = (SYSTEM_MODULE_INFORMATION *)((char *)pBuffer + sizeof(DWORD));

  611.         for (DWORD i = 0; i < numEntries; i++) {
  612.                 if (strcmpi(smi->ImageName, "ntoskrnl.exe")) {
  613.                         retVal = (DWORD)(smi->Base);
  614.                         break;
  615.                 }

  616.                 smi++;
  617.         }

  618.         HeapFree(hHeap, 0, pBuffer);

  619.         return retVal;
  620. }

  621. //----------------------                         ----------------------                    
  622. //                      -------------------------                      ---------------------
  623. // Thanks to 90210 for this excellent way of getting the KiServiceTable address from the disk image of
  624. // ntoskrnl.exe
  625. // http://www.rootkit.com/newsread.php?newsid=176
  626. DWORD
  627. getKiServiceTableAddr (
  628.   PVOID exeAddr,
  629.   DWORD sdtAddr,
  630.   PE_ExtHeader *peXH2
  631.   )

  632. /*--
  633. 学习者 :  sudami [xiao_rui_119@163.com]
  634. 时间   :  08/01/11

  635. 参数   :  
  636.   exeAddr - 从磁盘中读取指定的文件.在进程的heap当中分配一段空间,按照PE在内存中的对齐方式
  637.             将文件映射到内存.得到的这个地址(这里用的是PVOID exeAddr = LoadDLL("\\ntoskrnl.exe"))

  638.   sdtAddr - sdt在ntoskrnl.exe中的偏移量

  639.   peXH2 - IMAGE_OPTIONAL_HEADER

  640. 返回  :  TRUE | FALSE

  641. 功能    :  得到真实的SDT地址
  642.            btw: 此方法得到的不一定准确.系统出问题,后果自负~

  643. --*/
  644. {
  645.         // 如果重定位表存在
  646.         if ( peXH2->relocationTableAddress && peXH2->relocationTableSize ) {
  647.                 //
  648.                 // fixBlk保存的是当前数据块BLOCK[0]的起始地址
  649.                 // fixBlk+1 所指向的内容便是这个数据块BLOCK[0]的 VirtualAddress。它指向第一个数据包
  650.                 //
  651.                 FixupBlock *fixBlk = (FixupBlock *)((char *)exeAddr + peXH2->relocationTableAddress);               

  652.                 // 其实是一个BLOCK[n]数组。当fixBlk->blockSize不存在时,数组就遍历完了
  653.                 while(fixBlk->blockSize) {
  654.                         // 一个BLOCK数组中数据包的个数 = (一个数据块的大小 - 8) / 2
  655.                         int numEntries = (fixBlk->blockSize - sizeof(FixupBlock)) >> 1;
  656.        
  657.                         //
  658.                         // offsetPtr指向的是这个BLOCK数组中第一个数据包开始处的地址,然后依次+1。
  659.                         // 直到把一个BLOCK遍历完。对每个数据包,判断里面的Type是否为3。如果是,把地址
  660.                         // 转化为重定位后的地址
  661.                         //
  662.                         unsigned short *offsetPtr = (unsigned short *)(fixBlk + 1);

  663.                         for(int i = 0; i < numEntries; i++)        {               
  664.                                 // 得到每个数据包的重定位类型
  665.                                 // *offsetPtr & 0xF000 得到的正是Type,右移12位得到它的大小
  666.                                 int relocType = (*offsetPtr & 0xF000) >> 12;
  667.                                
  668.                                 if(relocType == 3) { // 如果是 IMAGE_REL_BASED_HIGHLOW (3)       

  669.                                         // 计算代码的重定位地址
  670.                                         // *offsetPtr & 0x0FFF 保存的是偏移量
  671.                                         DWORD sudami  = (DWORD) (fixBlk->pageRVA + (*offsetPtr & 0x0FFF));
  672.                                         DWORD *codeLoc = (DWORD *)((char *)exeAddr + sudami);                                       

  673.                                         // *codeLoc 保存的是重定位后sdt在内存中的地址
  674.                                         if (*codeLoc == sdtAddr + peXH2->imageBase &&
  675.                                                 *(WORD *)((DWORD)codeLoc - 2) == 0x05c7) {

  676.                                                 DWORD kiServiceTableAddr = *(DWORD *)((DWORD)codeLoc + 4);
  677.                                                
  678.                                                 // checks for presence of found address in the relocation table
  679.                                                 if( sudami  + peXH2->imageBase == kiServiceTableAddr) {
  680.                                                         return sudami ;
  681.                                                 }
  682.                                         }                                               
  683.                                 }

  684.                                 offsetPtr++;
  685.                         }

  686.                         fixBlk = (FixupBlock *)offsetPtr;
  687.                 }
  688.         }
  689.         return 0;
  690. }

  691. //
  692. // 主函数入口
  693. //
  694. int main (int argc, char* argv[])
  695. {
  696.         MZHeader mzH2;
  697.         PE_Header peH2;
  698.         PE_ExtHeader peXH2;
  699.         SectionHeader *secHdr2;

  700.         ::system ("title = SDTrestore V 0.2 [Learned by sudami] 08/01/12");
  701.         printf("Author : SIG^2 G-TEC (www.security.org.sg)\n");
  702.         printf("Learner: sudami [xiao_rui_119@163.com] \n\n");

  703.         // 得到系统的版本信息
  704.         OSVERSIONINFO ov;
  705.         ov.dwOSVersionInfoSize = sizeof(ov);
  706.         GetVersionEx (&ov);

  707.         if (ov.dwMajorVersion != 5) {
  708.                 printf("Sorry, this version supports only Win2K and WinXP.\n");
  709.                 return 1;
  710.         }

  711.         if (ov.dwMinorVersion != 0 && ov.dwMinorVersion != 1) {
  712.                 printf("Sorry, this version supports only Win2K and WinXP.\n");
  713.                 return 1;
  714.         }

  715.         gWinVersion = ov.dwMinorVersion;

  716.         if (!GetNativeAPIs()) {
  717.                 printf("Failed to get addresses of Native APIs!\n");
  718.                 return 1;
  719.         }

  720.         // 提升权限。使user能读写内存
  721.         AssignACL();
  722.         HANDLE hPhyMem = OpenPhyMem();

  723.         if ( hPhyMem == INVALID_HANDLE_VALUE) {
  724.                 AssignACL();
  725.         }

  726.         hPhyMem = OpenPhyMem();
  727.         if (hPhyMem == INVALID_HANDLE_VALUE) {
  728.                         printf("Could not open physical memory device!\n \
  729.                                    Make sure you are running as Administrator.\n");
  730.                         return 1;
  731.         }

  732.         // 映射 ntoskrnl.exe 到用户的进程空间中。对齐
  733.         PVOID exeAddr = LoadDLL("ntoskrnl.exe");
  734.         if (!exeAddr){
  735.                 printf("Failed to load ntoskrnl.exe!\n");
  736.                 return 1;
  737.         }

  738.         // 在其的EAT中得到SDT相对于ntoskrnl.exe的偏移
  739.         DWORD sdtAddr = ProcAPIExportAddr ((DWORD)exeAddr, "KeServiceDescriptorTable");
  740.         if (!sdtAddr) {
  741.                 printf("Failed to get address of KeServiceDescriptorTable!\n");
  742.                 return 1;
  743.         }
  744.        
  745.         // 得到其映射后各部分的地址
  746.         if (!ReadPEInfo((char *)exeAddr, &mzH2, &peH2, &peXH2, &secHdr2)) {
  747.                 printf("Failed to get PE header of ntoskrnl.exe!\n");
  748.                 return 1;
  749.         }

  750.         // kernelPhyBase 为系统加载ntoskrnl.exe后,相对于0x80000000的偏移(对齐了的)
  751.         DWORD kernelPhyBase = GetKernelBase() - PROT_MEMBASE; //#define PROT_MEMBASE 0x80000000

  752.         // kernelOffset 即是RVA
  753.         DWORD kernelOffset = kernelPhyBase - peXH2.imageBase;
  754.         printf ("KeServiceDescriptorTable\t\t%X\n", sdtAddr + GetKernelBase());

  755.         /**********************************************************************************

  756.         此时已经得到SSDT相对于ntoskrnl.exe的偏移了,保存于sdtAddr.采用普通的方法-->

  757.         从磁盘读ntoskrnl.exe,计算对齐后的大小.将其对齐后映射到用户进程空间.在其EAT中得到
  758.         SSDT相对于ntoskrnl.exe的偏移

  759.         ***********************************************************************************/
  760.         UCHAR *ptr = NULL;
  761.         DWORD pAddr = sdtAddr + kernelPhyBase;
  762.         DWORD wantedAddr = pAddr;
  763.         DWORD len = 0x2000;

  764.         // 第一次映射
  765.         // 把系统加载的ntoskrnl.exe的SSDT地址映射到进程的虚拟地址空间里面去
  766.         if (MapPhyMem(hPhyMem, &pAddr, &len, (LPVOID *)&ptr)) {
  767.                
  768.                 DWORD serviceTableAddr, sdtCount;

  769.                 // 现在start保存的是 已经映射的内容的大小
  770.                 // 其实是KeServiceDecriptorTable.base从开始到结束的这段大小
  771.                 DWORD start        = wantedAddr - pAddr;

  772.                 // 本来要映射len = 0x2000大小的,但实际上只映射了start大小
  773.                 // wantedBytes 是没有按期望映射的差值
  774.                 DWORD wantedBytes  = len - start;
  775. /*--
  776. typedef struct _KSERVICE_TABLE_DESCRIPTOR {
  777.     PULONG_PTR Base;
  778.     PULONG Count;
  779.     ULONG Limit;
  780.     PUCHAR Number;
  781. } KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
  782. ++*/

  783.                 if (wantedBytes >= 4) {

  784.                         serviceTableAddr = *((DWORD *)(&ptr[start]));
  785.                         printf("KeServiceDecriptorTable.ServiceTable\t%X\n", serviceTableAddr);

  786.                         if (wantedBytes >= 12) {

  787.                                 // &ptr[start] 是指针,此时指向Base结束的地方,Base中保存了很长一段的数据
  788.                                 // ((DWORD *)(&ptr[start])) + 2也是指针,指向KeServiceDescriptorTable.ServiceLimit
  789.                                 sdtCount = *(((DWORD *)(&ptr[start])) + 2);
  790.                                 printf("KeServiceDescriptorTable.ServiceLimit\t%d\n", sdtCount);
  791.                         }
  792.                 } else {
  793.                         printf("Sorry, an unexpected situation occurred!\n");
  794.                         return 1;
  795.                 }

  796.                 UnMapPhyMem ((DWORD)ptr);

  797.                 printf("\n");

  798.                 if (sdtCount >= 300)        {
  799.                         printf("Sorry, an unexpected error occurred! SDT Count > 300???\n");
  800.                         return 1;
  801.                 }

  802.                 pAddr = serviceTableAddr - PROT_MEMBASE; // 0x80000000
  803.                 wantedAddr = pAddr;
  804.                 ptr = NULL;
  805.                 len = 0x2000;

  806.                 // 第2次映射
  807.                 // 把系统加载的ntoskrnl.exe的KeServiceDecriptorTable.base中的所有内容映射到进程的虚拟地址空间里面去
  808.                 if (MapPhyMem(hPhyMem, &pAddr, &len, (LPVOID *)&ptr)) {

  809.                         //
  810.                         start = wantedAddr - pAddr;
  811.                         DWORD numEntries = (len - start) >> 2;

  812.                         if (numEntries >= sdtCount) {

  813.                                 // 为ST表分配名字所占用的空间
  814.                                 char **nativeApiNames = NULL;
  815.                                 nativeApiNames = (char **)malloc(sizeof(char *) * sdtCount);

  816.                                 if(!nativeApiNames) {
  817.                                         printf("Failed to allocate memory for Native API name table.\n");
  818.                                         return 1;
  819.                                 }

  820.                                 memset (nativeApiNames, 0, sizeof(char *) * sdtCount);

  821.                                 // 映射ntdll.dll到内存,对齐
  822.                                 PVOID ntdll = LoadDLL("\\ntdll.dll");

  823.                                 if(!ntdll) {
  824.                                         printf("Failed to load ntdll.dll!\n");
  825.                                         return 1;
  826.                                 }

  827.                                 // 建立API名称表表
  828.                                 BuildNativeAPITable ((DWORD)ntdll, nativeApiNames, sdtCount);

  829.                                 // *serviceTable 是系统地址空间内的ST表的地址.它是否被HOOK过还不晓得.
  830.                                 // 所以要拿它和我们自己从文件中读到的偏移相比较
  831.                                 DWORD *serviceTable = (DWORD *)(&ptr[start]);

  832.                                 /***********************************
  833.                                 *                                  *
  834.                 *    这里得到了真实的ST地址啦      *
  835.                                 *                                  *
  836.                                 ***********************************/
  837.                                 // wantedAddr = serviceTableAddr - 0x80000000;
  838.                     // wantedAddr - kernelOffset. 即是ST表中系统范围内的地址 - RVA = ST在文件中的偏移
  839.                                 // *fileServiceTable 保存的是真实的ST表中每个函数的偏移
  840.                                 DWORD *fileServiceTable = (DWORD *)((DWORD)exeAddr + wantedAddr - kernelOffset - peXH2.imageBase);
  841.                                
  842.                                 // calculate address based on 90210's suggestion
  843.                                 DWORD fileAddr2 = (DWORD)exeAddr + getKiServiceTableAddr(exeAddr, sdtAddr, &peXH2);                               
  844.                                
  845.                             // start...
  846.                                 if (!IsBadReadPtr(fileServiceTable, sizeof(DWORD)) &&
  847.                                    !IsBadReadPtr(&fileServiceTable[sdtCount-1], sizeof(DWORD)))        {

  848.                                         DWORD hookCount = 0;
  849.                                         for (DWORD i = 0; i < sdtCount; i++) {       

  850.                                                 // 这里就是真正判断是否被HOOK 的地方
  851.                                                 if ( (serviceTable[i] - PROT_MEMBASE - kernelOffset) != fileServiceTable[i]) {
  852.                                                         printf("%-25s %3X --[hooked by unknown at %X]--\n",
  853.                                                                   (nativeApiNames[i] ? nativeApiNames[i] : "Unknown API"),
  854.                                                                   i, serviceTable[i]);
  855.                                                         hookCount++;
  856.                                                 }
  857.                                                
  858.                                         }

  859.                                         printf("\nNumber of Service Table entries hooked = %u\n", hookCount);
  860.                                        
  861.                                         if (hookCount) {
  862.                                                 printf("\nFix SDT Entries (Y/N)? : ");
  863.        
  864.                                                 char inputReply[10];
  865.                                                 memset(inputReply, 0, sizeof(inputReply));
  866.                                                 fgets(inputReply, sizeof(inputReply) - 1, stdin);
  867.                                                 printf("\n");
  868.                                                                                
  869.                                                 // 恢复被HOOK的SDT
  870.                                                 if (stricmp(inputReply, "y\n") == 0) {

  871.                                                         ::system ("cls");
  872.                                                         for(DWORD i = 0; i < sdtCount; i++)        {

  873.                                                                 if((serviceTable[i] - PROT_MEMBASE - kernelOffset) != fileServiceTable[i]) {
  874.                                                                        
  875.                                                                         // 就这一句就搞定啦~
  876.                                                                         serviceTable[i] = fileServiceTable[i] + PROT_MEMBASE + kernelOffset;

  877.                                                                         printf("[+] Patched SDT entry %.2X to %.8X\n", i,
  878.                                                                                 fileServiceTable[i] + PROT_MEMBASE + kernelOffset);
  879.                                                                 }
  880.                                                         }

  881.                                                         printf("\n\n[+] SDT Recover is done,but if there is a KTIMER,the SDT may be re-HOOKED again\n");
  882.                                                         ::getchar ();
  883.                                                 } else {
  884.                                                         printf("[-] SDT Entries NOT fixed.\n");
  885.                                                         ::getchar ();
  886.                                                 }
  887.                                         }
  888.                                 } else {
  889.                                         printf("It's likely that the SDT service table has been relocated.\n"
  890.                                                    "This POC code cannot support patching of relocated SDT service table.\n");
  891.                                         ::getchar ();
  892.                                 }

  893.                         }

  894.                         UnMapPhyMem((DWORD)ptr);
  895.                 }
  896.         }

  897.         return 0;
  898. }

  899. //////////////////////////////////// END OF FILE /////////////////////////////////////////////
复制代码


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|断点社区 |网站地图

GMT+8, 2025-1-18 19:09 , Processed in 0.064990 second(s), 26 queries .

Powered by XiunoBBS

Copyright © 2001-2025, 断点社区.

快速回复 返回顶部 返回列表