|
* 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了,然后恢复之.
头文件
- #ifndef GLOBAL_NATIVE_API_DEF_SUDAMI
- #define GLOBAL_NATIVE_API_DEF_SUDAMI
- #ifdef __cplusplus
- extern "C" {
- #endif
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- typedef long NTSTATUS, *PNTSTATUS;
- typedef unsigned long DWORD;
- typedef DWORD * PDWORD;
- typedef unsigned long ULONG;
- typedef unsigned long ULONG_PTR;
- typedef ULONG *PULONG;
- typedef unsigned short WORD;
- typedef unsigned char BYTE;
- typedef unsigned char UCHAR;
- typedef unsigned short USHORT;
- typedef void *PVOID;
- typedef int BOOL;
- typedef BYTE BOOLEAN;
- #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
- #define STATUS_SUCCESS 0x00000000
- #define STATUS_UNSUCCESSFUL 0xC0000001
- #define STATUS_NOT_IMPLEMENTED 0xC0000002
- #define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
- #define STATUS_INVALID_PARAMETER 0xC000000D
- #define STATUS_ACCESS_DENIED 0xC0000022
- #define STATUS_BUFFER_TOO_SMALL 0xC0000023
- #define STATUS_IO_DEVICE_ERROR ((NTSTATUS) 0xC0000185)
- #define OBJ_KERNEL_HANDLE 0x00000200
- #ifndef LOWORD
- #define LOWORD(l) ((unsigned short)(unsigned int)(l))
- #endif
- #ifndef HIWORD
- #define HIWORD(l) ((unsigned short)((((unsigned int)(l)) >> 16) & 0xFFFF))
- #endif
- // 定义ioctl相关的,用于R3和R0间的通信
- #ifndef MAKELONG
- #define MAKELONG(a, b) ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))
- #endif
- #define MY_DEVICE_TYPE 0x0000AA71 // 这地方可以自己改
- #define DRIVER_IO(code) CTL_CODE (MY_DEVICE_TYPE, code, METHOD_BUFFERED, FILE_ANY_ACCESS)
- typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
- ///////////////////////////////////////////////////////////////// -- --
- //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// -- - - --
- //+ +// -- - - --
- //+ 结构体声明 +// -- - --
- //+ +// - sudami -
- //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// -- --
- ///////////////////////////////////////////////////////////////// -- --
- // -- --
- // --
- #ifndef ANSI_STRING
- typedef struct _STRING {
- USHORT Length;
- USHORT MaximumLength;
- PCHAR Buffer;
- } ANSI_STRING, *PANSI_STRING;
- #endif
- #ifndef UNICODE_STRING
- typedef struct _UNICODE_STRING {
- USHORT Length;
- USHORT MaximumLength;
- PWSTR Buffer;
- } UNICODE_STRING, *PUNICODE_STRING;
- #endif
- /* SSDT */
- #pragma pack(1)
- typedef struct ServiceDescriptorEntry {
- unsigned int *ServiceTableBase;
- unsigned int *ServiceCounterTableBase;
- unsigned int NumberOfServices;
- unsigned char *ParamTableBase;
- } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
- typedef struct ServiceDescriptorShadowEntry {
- unsigned int *Win32kTableBase;
- unsigned int *Win32kCounterTableBase;
- unsigned int NumberofWin32kServices;
- unsigned char *Win32kParamTableBase;
- } ServiceDescriptorTableShadowEntry_t, *PServiceDescriptorTableShadowEntry_t;
- #pragma pack()
- __declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
- PServiceDescriptorTableShadowEntry_t KeServiceDescriptorTableShadow;
- // OBJECT_ATTRIBUTES
- typedef struct _OBJECT_ATTRIBUTES {
- DWORD Length;
- HANDLE RootDirectory;
- PUNICODE_STRING ObjectName;
- DWORD Attributes;
- PSECURITY_DESCRIPTOR SecurityDescriptor;
- PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
- } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
- // CLIENT_ID
- #ifndef CLIENT_ID
- typedef struct _CLIENT_ID {
- HANDLE UniqueProcess;
- HANDLE UniqueThread;
- } CLIENT_ID, *PCLIENT_ID;
- #endif
- /*
- struct _SYSTEM_THREADS
- {
- LARGE_INTEGER KernelTime;
- LARGE_INTEGER UserTime;
- LARGE_INTEGER CreateTime;
- ULONG WaitTime;
- PVOID StartAddress;
- CLIENT_ID ClientIs;
- KPRIORITY Priority;
- KPRIORITY BasePriority;
- ULONG ContextSwitchCount;
- ULONG ThreadState;
- KWAIT_REASON WaitReason;
- };
- struct _SYSTEM_PROCESSES
- {
- ULONG NextEntryDelta;
- ULONG ThreadCount;
- ULONG Reserved[6];
- LARGE_INTEGER CreateTime;
- LARGE_INTEGER UserTime;
- LARGE_INTEGER KernelTime;
- UNICODE_STRING ProcessName;
- KPRIORITY BasePriority;
- ULONG ProcessId;
- ULONG InheritedFromProcessId;
- ULONG HandleCount;
- ULONG Reserved2[2];
- VM_COUNTERS VmCounters;
- IO_COUNTERS IoCounters; //windows 2000 only
- struct _SYSTEM_THREADS Threads[1];
- };
- // PROCESS_BASIC_INFORMATION
- #ifdef PROCESS_BASIC_INFORMATION
- #undef PROCESS_BASIC_INFORMATION
- typedef struct _PROCESS_BASIC_INFORMATION {
- NTSTATUS ExitStatus;
- ULONG PebBaseAddress;
- ULONG_PTR AffinityMask;
- LONG BasePriority;
- ULONG_PTR UniqueProcessId;
- ULONG_PTR InheritedFromUniqueProcessId;
- } PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
- #endif
- // SYSTEM_HANDLE_INFORMATION
- typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO {
- USHORT UniqueProcessId;
- USHORT CreatorBackTraceIndex;
- UCHAR ObjectTypeIndex;
- UCHAR HandleAttributes;
- USHORT HandleValue; // 句柄
- PVOID Object; // 若HANDLE类型为线程,则它是ETHREAD结构
- ULONG GrantedAccess;
- } SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
- typedef struct _SYSTEM_HANDLE_INFORMATION {
- ULONG NumberOfHandles;
- SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
- } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
- */
- // SYSTEM_MODULE_INFORMATION
- typedef struct _SYSTEM_MODULE_INFORMATION {
- ULONG Reserved[2];
- PVOID Base;
- ULONG Size;
- ULONG Flags;
- USHORT Index;
- USHORT Unknown;
- USHORT LoadCount;
- USHORT ModuleNameOffset;
- CHAR ImageName[256];
- } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
- typedef struct {
- ULONG dwNumberOfModules;
- SYSTEM_MODULE_INFORMATION smi;
- } MODULES, *PMODULES;
- // SYSTEM_BASIC_INFORMATION
- typedef struct _SYSTEM_BASIC_INFORMATION {
- ULONG Unknown; //Always contains zero
- ULONG MaximumIncrement; //一个时钟的计量单位
- ULONG PhysicalPageSize; //一个内存页的大小
- ULONG NumberOfPhysicalPages; //系统管理着多少个页
- ULONG LowestPhysicalPage; //低端内存页
- ULONG HighestPhysicalPage; //高端内存页
- ULONG AllocationGranularity;
- ULONG LowestUserAddress; //地端用户地址
- ULONG HighestUserAddress; //高端用户地址
- ULONG ActiveProcessors; //激活的处理器
- UCHAR NumberProcessors; //有多少个处理器
- } SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION;
- // SYSTEM_INFORMATION_CLASS
- typedef enum _SYSTEM_INFORMATION_CLASS {
- SystemBasicInformation,
- SystemProcessorInformation,
- SystemPerformanceInformation,
- SystemTimeOfDayInformation,
- SystemPathInformation,
- SystemProcessInformation,
- SystemCallCountInformation,
- SystemDeviceInformation,
- SystemProcessorPerformanceInformation,
- SystemFlagsInformation,
- SystemCallTimeInformation,
- SystemModuleInformation, // 11
- SystemLocksInformation,
- SystemStackTraceInformation,
- SystemPagedPoolInformation,
- SystemNonPagedPoolInformation,
- SystemHandleInformation, // 0x10 -- 16
- SystemObjectInformation,
- SystemPageFileInformation,
- SystemVdmInstemulInformation,
- SystemVdmBopInformation,
- SystemFileCacheInformation,
- SystemPoolTagInformation,
- SystemInterruptInformation,
- SystemDpcBehaviorInformation,
- SystemFullMemoryInformation,
- SystemLoadGdiDriverInformation,
- SystemUnloadGdiDriverInformation,
- SystemTimeAdjustmentInformation,
- SystemSummaryMemoryInformation,
- SystemUnused1,
- SystemPerformanceTraceInformation,
- SystemCrashDumpInformation,
- SystemExceptionInformation,
- SystemCrashDumpStateInformation,
- SystemKernelDebuggerInformation,
- SystemContextSwitchInformation,
- SystemRegistryQuotaInformation,
- SystemExtendServiceTableInformation,
- SystemPrioritySeperation,
- SystemUnused3,
- SystemUnused4,
- SystemUnused5,
- SystemUnused6,
- SystemCurrentTimeZoneInformation,
- SystemLookasideInformation,
- SystemTimeSlipNotification,
- SystemSessionCreate,
- SystemSessionDetach,
- SystemSessionInformation
- } SYSTEM_INFORMATION_CLASS;
- #ifndef SECTION_INHERIT
- typedef enum _SECTION_INHERIT {
- ViewShare = 1,
- ViewUnmap = 2
- } SECTION_INHERIT;
- #endif
- /******************************************************
- * *
- * 部分 PE 结构 *
- * *
- ******************************************************/
- #ifndef IMAGE_DOS_SIGNATURE
- #define IMAGE_DOS_SIGNATURE 0x5a4d // MZ
- #endif
- #ifndef IMAGE_NT_SIGNATURE
- #define IMAGE_NT_SIGNATURE 0x00004550 // PE00
- #endif
- // _IMAGE_DOS_HEADER
- struct MZHeader
- {
- unsigned short signature; // "MZ"
- unsigned short partPag;
- unsigned short pageCnt;
- unsigned short reloCnt;
- unsigned short hdrSize;
- unsigned short minMem;
- unsigned short maxMem;
- unsigned short reloSS;
- unsigned short exeSP;
- unsigned short chksum;
- unsigned short exeIP;
- unsigned short reloCS;
- unsigned short tablOff;
- unsigned short overlay;
- unsigned char reserved[32];
- unsigned long offsetToPE;
- };
- // DWORD signature + _IMAGE_FILE_HEADER. 不是完全的IMAGE_FILE_HEADER.
- struct PE_Header
- {
- unsigned long signature; // "PE\0\0"
- unsigned short machine;
- unsigned short numSections;
- unsigned long timeDateStamp;
- unsigned long pointerToSymbolTable;
- unsigned long numOfSymbols;
- unsigned short sizeOfOptionHeader;
- unsigned short characteristics;
- };
- // _IMAGE_OPTIONAL_HEADER
- struct PE_ExtHeader
- {
- unsigned short magic;
- unsigned char majorLinkerVersion;
- unsigned char minorLinkerVersion;
- unsigned long sizeOfCode;
- unsigned long sizeOfInitializedData;
- unsigned long sizeOfUninitializedData;
- unsigned long addressOfEntryPoint;
- unsigned long baseOfCode;
- unsigned long baseOfData;
- unsigned long imageBase;
- unsigned long sectionAlignment;
- unsigned long fileAlignment;
- unsigned short majorOSVersion;
- unsigned short minorOSVersion;
- unsigned short majorImageVersion;
- unsigned short minorImageVersion;
- unsigned short majorSubsystemVersion;
- unsigned short minorSubsystemVersion;
- unsigned long reserved1;
- unsigned long sizeOfImage;
- unsigned long sizeOfHeaders;
- unsigned long checksum;
- unsigned short subsystem;
- unsigned short DLLCharacteristics;
- unsigned long sizeOfStackReserve;
- unsigned long sizeOfStackCommit;
- unsigned long sizeOfHeapReserve;
- unsigned long sizeOfHeapCommit;
- unsigned long loaderFlags;
- unsigned long numberOfRVAAndSizes;
- unsigned long exportTableAddress;
- unsigned long exportTableSize;
- unsigned long importTableAddress;
- unsigned long importTableSize;
- unsigned long resourceTableAddress;
- unsigned long resourceTableSize;
- unsigned long exceptionTableAddress;
- unsigned long exceptionTableSize;
- unsigned long certFilePointer;
- unsigned long certTableSize;
- unsigned long relocationTableAddress;
- unsigned long relocationTableSize;
- unsigned long debugDataAddress;
- unsigned long debugDataSize;
- unsigned long archDataAddress;
- unsigned long archDataSize;
- unsigned long globalPtrAddress;
- unsigned long globalPtrSize;
- unsigned long TLSTableAddress;
- unsigned long TLSTableSize;
- unsigned long loadConfigTableAddress;
- unsigned long loadConfigTableSize;
- unsigned long boundImportTableAddress;
- unsigned long boundImportTableSize;
- unsigned long importAddressTableAddress;
- unsigned long importAddressTableSize;
- unsigned long delayImportDescAddress;
- unsigned long delayImportDescSize;
- unsigned long COMHeaderAddress;
- unsigned long COMHeaderSize;
- unsigned long reserved2;
- unsigned long reserved3;
- };
- // _IMAGE_SECTION_HEADER
- struct SectionHeader
- {
- unsigned char sectionName[8];
- unsigned long virtualSize;
- unsigned long virtualAddress;
- unsigned long sizeOfRawData;
- unsigned long pointerToRawData;
- unsigned long pointerToRelocations;
- unsigned long pointerToLineNumbers;
- unsigned short numberOfRelocations;
- unsigned short numberOfLineNumbers;
- unsigned long characteristics;
- };
- struct ImportDirEntry
- {
- DWORD importLookupTable;
- DWORD timeDateStamp;
- DWORD fowarderChain;
- DWORD nameRVA;
- DWORD importAddressTable;
- };
- /******************************************************
- * *
- * 结构体自定义区域 *
- * *
- ******************************************************/
- typedef struct _MY_PROCESS_INFO {
- ULONG PID;
- ULONG KPEB;
- ULONG CR3;
- CHAR Name[16];
- ULONG Reserved;
- } MY_PROCESS_INFO, *PMY_PROCESS_INFO;
- ///////////////////////////////////////////////////////////////// -- --
- //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// -- - - --
- //+ +// -- - - --
- //+ 函数原型声明 +// -- - --
- //+ +// - sudami -
- //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// -- --
- ///////////////////////////////////////////////////////////////// -- --
- // -- --
- // --
- NTSYSAPI
- NTSTATUS
- NTAPI
- NtCreateFile(
- OUT PHANDLE FileHandle,
- IN ACCESS_MASK DesiredAccess,
- IN POBJECT_ATTRIBUTES ObjectAttributes,
- // OUT PIO_STATUS_BLOCK IoStatusBlock,
- IN PLARGE_INTEGER AllocationSize OPTIONAL,
- IN ULONG FileAttributes,
- IN ULONG ShareAccess,
- IN ULONG CreateDisposition,
- IN ULONG CreateOptions,
- IN PVOID EaBuffer OPTIONAL,
- IN ULONG EaLength
- );
- NTSYSAPI
- VOID
- NTAPI
- RtlInitUnicodeString(
- PUNICODE_STRING DestinationString,
- PCWSTR SourceString
- );
- NTSYSAPI
- NTSTATUS
- NTAPI
- ZwOpenSection(
- OUT PHANDLE SectionHandle,
- IN ACCESS_MASK DesiredAccess,
- IN POBJECT_ATTRIBUTES objectAttributes
- );
- NTSYSAPI
- NTSTATUS
- NTAPI
- ZwMapViewOfSection(
- IN HANDLE SectionHandle,
- IN HANDLE ProcessHandle,
- IN OUT PVOID *BaseAddress,
- IN ULONG ZeroBits,
- IN ULONG CommitSize,
- IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
- IN OUT PULONG ViewSize,
- IN SECTION_INHERIT InheritDisposition,
- IN ULONG AllocationType,
- IN ULONG Protect
- );
- NTSYSAPI
- NTSTATUS
- NTAPI
- ZwUnmapViewOfSection(
- IN HANDLE ProcessHandle,
- IN PVOID BaseAddress
- );
- /*
- NTSYSAPI
- NTSTATUS
- NTAPI
- NtVdmControl(
- IN ULONG ControlCode,
- IN PVOID ControlData
- );
- NTSYSAPI
- NTSTATUS
- PsLookupProcessByProcessId (
- IN HANDLE ProcessId,
- OUT PEPROCESS *Process
- );
- NTSYSAPI
- NTSTATUS
- PsLookupThreadByThreadId (
- IN HANDLE ThreadId,
- OUT PETHREAD *Thread
- );
- */
- NTSYSAPI
- NTSTATUS
- NTAPI
- NtQuerySystemInformation(
- IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
- OUT PVOID SystemInformation,
- IN ULONG SystemInformationLength,
- OUT PULONG ReturnLength OPTIONAL
- );
- //
- //
- //
- //
- VOID
- RtlFreeUnicodeString(
- IN PUNICODE_STRING UnicodeString
- );
- NTSTATUS (WINAPI * _RtlAnsiStringToUnicodeString)
- (PUNICODE_STRING DestinationString,
- IN PANSI_STRING SourceString,
- IN BOOLEAN);
- VOID (WINAPI *_RtlInitAnsiString)
- (IN OUT PANSI_STRING DestinationString,
- IN PCHAR SourceString);
- ///////////////////////////////////////////////////////////////// -- --
- //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// -- - - --
- //+ +// -- - - --
- //+ 一些自定义必备函数 +// -- - --
- //+ +// - sudami -
- //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// -- --
- ///////////////////////////////////////////////////////////////// -- --
- // -- --
- // --
- // 写保护的开&关
- void WPOFF()
- {
- __asm { //去掉内存保护
- cli
- mov eax,cr0
- and eax,not 10000h
- mov cr0,eax
- }
- }
- void WPON()
- {
- __asm { //恢复内存保护
- mov eax,cr0
- or eax,10000h
- mov cr0,eax
- sti
- }
- }
- //////////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////////
- #ifdef __cplusplus
- }
- #endif
- #endif
复制代码 .c文件
- #include <stdio.h>
- #include <stdlib.h>
- #include <windows.h>
- #include <aclapi.h>
- #include "rootkit.h"
- ////////////////////////////////////////////////////////////////////
- #pragma comment (lib, "F:\\WINDDK\\lib\\wxp\\i386\\ntdll.lib")
- ////////////////////////////////////////////////////////////////////
- #define OBJ_CASE_INSENSITIVE 0x00000040L
- #define PAGE_READONLY 0x02
- #define PAGE_READWRITE 0x04
- #define DEF_KERNEL_BASE 0x80400000L
- #define PROT_MEMBASE 0x80000000
- DWORD gWinVersion;
- struct FixupBlock
- {
- ULONG pageRVA;
- ULONG blockSize;
- };
- /*++
- 3个函数,就不用注解了
- --*/
- BOOL GetNativeAPIs ()
- {
- HMODULE hntdll;
- hntdll = GetModuleHandle("ntdll.dll");
-
- *(FARPROC *)&_RtlAnsiStringToUnicodeString =
- GetProcAddress(hntdll, "RtlAnsiStringToUnicodeString");
- *(FARPROC *)&_RtlInitAnsiString =
- GetProcAddress(hntdll, "RtlInitAnsiString");
- if (_RtlAnsiStringToUnicodeString && _RtlInitAnsiString) {
- return TRUE;
- }
- return FALSE;
- }
- DWORD myStrlenA (char *ptr)
- {
- DWORD len = 0;
- while(*ptr) {
- len++;
- ptr++;
- }
- return len;
- }
- BOOL myStrcmpA (char *str1, char *str2)
- {
- while(*str1 && *str2) {
- if(*str1 == *str2) {
- str1++;
- str2++;
- } else {
- return FALSE;
- }
- }
- if (*str1 && !*str2) {
- return FALSE;
- } else if (*str2 && !*str1){
- return FALSE;
- }
- return TRUE;
- }
- //---------------------- ----------------------
- // ------------------------- ---------------------
- BOOL
- ReadPEInfo (
- char *modulePos,
- MZHeader *outMZ,
- PE_Header *outPE,
- PE_ExtHeader *outpeXH,
- SectionHeader **outSecHdr
- )
- /*++
- 学习者 : sudami [xiao_rui_119@163.com]
- 时间 : 08/01/11
- 功能 :
- 得到映射到内存的PE结构中各部分的地址
- 参数 :
-
- modulePos - [IN] 将磁盘上的文件读出来后,映射到进程的虚拟地址空间中,对齐后得到其起始地址.
- outMZ - [OUT] 保存MZ头 IMAGE_DOS_HEADER
- outPE - [OUT] 保存PE头 IMAGE_FILE_HEADER
- outpeXH - [OUT] 保存扩展PE头 IMAGE_OPTIONAL_HEADER
- outSecHdr - [OUT] 2级指针,保存Section头 IMAGE_SECTION_HEADER
- 返回 :
-
- TRUE - 读取成功
- FALSE - 不是有效的PE文件,读取失败
- --*/
- {
- MZHeader *mzH = (MZHeader *)modulePos;
- if (mzH->signature != IMAGE_DOS_SIGNATURE) {
- printf("File does not have MZ header\n");
- return false;
- }
- PE_Header *peH = (PE_Header *)(modulePos + mzH->offsetToPE);
- // 通过 sizeOfOptionHeader 验证PE文件的合法性(它是 _IMAGE_OPTIONAL_HEADER 的尺寸)
- if (peH->sizeOfOptionHeader != sizeof (PE_ExtHeader)) {
- printf("Unexpected option header size.\n");
- return false;
- }
- PE_ExtHeader *peXH = (PE_ExtHeader *)((char *)peH + sizeof(PE_Header));
- SectionHeader *secHdr = (SectionHeader *)((char *)peXH + sizeof(PE_ExtHeader));
- *outMZ = *mzH;
- *outPE = *peH;
- *outpeXH = *peXH;
- *outSecHdr = secHdr;
- return true;
- }
- //---------------------- ----------------------
- // ------------------------- ---------------------
- int
- CalcTotalImageSize (
- MZHeader *inMZ,
- PE_Header *inPE,
- PE_ExtHeader *inpeXH,
- SectionHeader *inSecHdr
- )
- /*++
- 学习者 : sudami [xiao_rui_119@163.com]
- 时间 : 08/01/11
- 功能 :
- 计算PE文件加载到内存所需要占用的空间: 所有的文件头长度 + 所有的节长度
- 返回 :
- PE在内存中对齐后需要的大小
- --*/
- {
- int result = 0;
- int val = 0;
- /* (1) 统计所有文件头在内存中对齐后所需空间 */
- // sectionAlignment 为段加载后在内存中的对齐方式 4KB
- int alignment = inpeXH->sectionAlignment;
- // 如果所有的文件头长度之和 是4KB整数倍。则留给它的空间就是sizeOfHeaders
- if (inpeXH->sizeOfHeaders % alignment == 0) {
- result += inpeXH->sizeOfHeaders;
- } else { // 如果所有的文件头长度之和 非4KB整数倍。则需要对齐后申请空间
- val = inpeXH->sizeOfHeaders / alignment;
- val++;
- result += (val * alignment);
- }
- /* (2) 统计所有节在内存中对齐后所需空间 */
- for (int i = 0; i < inPE->numSections; i++) {
- // virtualSize 是 块对齐前的真实长度
- if (inSecHdr[i].virtualSize) {
- if (inSecHdr[i].virtualSize % alignment == 0) {
- result += inSecHdr[i].virtualSize;
- } else {
- val = inSecHdr[i].virtualSize / alignment;
- val++;
- result += (val * alignment);
- }
- }
- }
- return result;
- }
- //---------------------- ----------------------
- // ------------------------- ---------------------
- ULONG
- GetAlignedSize (
- ULONG curSize,
- ULONG alignment
- )
- /*++
- 功能 :
- 得到对齐后的文件大小
- 参数 :
- curSize - 未对齐前的大小
- alignment - 段加载后在内存中的对齐方式,一般为4KB
- 返回 :
- 对齐后的大小
- --*/
- {
- if (curSize % alignment == 0) { // 如果不存在对齐方式,则不对齐,直接返回原大小
- return curSize;
- } else {
- int val = curSize / alignment;
- val++;
- return (val * alignment);
- }
- }
- //---------------------- ----------------------
- // ------------------------- ---------------------
- BOOL
- LoadPE (
- char *exePtr,
- MZHeader *inMZ,
- PE_Header *inPE,
- PE_ExtHeader *inpeXH,
- SectionHeader *inSecHdr,
- LPVOID ptrLoc
- )
- /*++
- 学习者 : sudami [xiao_rui_119@163.com]
- 时间 : 08/01/11
- 功能 :
- 加载从磁盘读取的文件到内存,需要自己对齐
- <PE加载到内存对齐后的示意图>
- 所有文件头 节1 节2 ... 节N
- ------------------------------------------------
- |aa...aa######| a...a##| a...a###| ... | a...a##|
- ------------------------------------------------
- 注: a 表示实际数据; # 表示空隙,是内存中对齐后留出的空隙
- 参数 :
- exePtr - PE文件在磁盘中时起始的地址.还没有经过对齐.所以需要把它映射到内存
- ...
- ptrLoc - 根据内存中PE的大小调用HeapAlloc而分配的一块空闲内存区域.
- 返回 : TRUE
- --*/
- {
- char *outPtr = (char *)ptrLoc;
- // 把所有文件头的数据全部拷贝到ptrLoc指向的地址处
- // 然后地址按照PE在内存中的对齐方式往后挪
- memcpy (outPtr, exePtr, inpeXH->sizeOfHeaders);
- outPtr += GetAlignedSize (inpeXH->sizeOfHeaders, inpeXH->sectionAlignment);
- // 拷贝所有的节数据到新的地址处. 复制的时候要知道每个节在文件中的实际大小.而不是在内存在对齐后的大小
- for (int i = 0; i < inPE->numSections; i++) {
- if (inSecHdr[i].sizeOfRawData > 0) { // sizeOfRawData 是节对齐后的长度
- ULONG toRead = inSecHdr[i].sizeOfRawData;
- if (toRead > inSecHdr[i].virtualSize) {
- toRead = inSecHdr[i].virtualSize;
- }
- // 拷贝没个节的实际数据,然后把指针挪到每个节在内存中对齐后的位置处
- memcpy (outPtr, exePtr + inSecHdr[i].pointerToRawData, toRead);
- outPtr += GetAlignedSize (inSecHdr[i].virtualSize, inpeXH->sectionAlignment);
- }
- }
- return true;
- }
- //---------------------- ----------------------
- // ------------------------- ---------------------
- LPVOID
- LoadDLL (
- char *dllName
- )
- /*++
- 学习者 : sudami [xiao_rui_119@163.com]
- 时间 : 08/01/11
- 功能 :
- 将指定模块从磁盘读取,然后映射进内存,按照对齐的方式映射.这需要我们自己来做.
- 这个过程是调用 自定义函数 LoadPE
- 流程 :
- CreateFile 打开指定的文件 --> GetFileInformationByHandle 获得文件的大小信息a -->
- HeapAlloc 分配大小为a的内存 --> ReadFile 将文件读入此内存区域中 --> ReadPEInfo 获得
- PE文件各结构地址 --> CalcTotalImageSize 计算此文件映射到内存对齐后的总大小b -->
- HeapAlloc 分配大小为b的内存 --> LoadPE加载之
- 参数 :
- exePtr - 指定的模块名称,不包含路径.所以一般是系统目录下的文件
- 返回 : 完成加载后,对齐后的PE在进程空间中一段内存的起始地址
- --*/
- {
- MZHeader mzH2;
- PE_Header peH2;
- PE_ExtHeader peXH2;
- SectionHeader *secHdr2;
- char moduleFilename[MAX_PATH + 1];
- LPVOID ptrLoc = NULL;
- GetSystemDirectory (moduleFilename, MAX_PATH);
- if (moduleFilename[MAX_PATH - 1] != '\\') {
- strcat (moduleFilename, "\");
- }
- if ((myStrlenA (moduleFilename) + myStrlenA (dllName)) >= MAX_PATH)
- return NULL;
- strcat (moduleFilename, dllName);
- // 调用CreateFile打开要映射的文件
- HANDLE fp = CreateFile (moduleFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
-
- if (fp != INVALID_HANDLE_VALUE) {
- // 通过打开的文件句柄得到文件的信息: 主要是文件的大小
- BY_HANDLE_FILE_INFORMATION fileInfo;
- GetFileInformationByHandle (fp, &fileInfo);
- DWORD fileSize = fileInfo.nFileSizeLow;
-
- // 得到了磁盘文件的大小后,为其分配内存
- if (fileSize) {
- // 在当前进程的Heap中为其分配一段空间
- LPVOID exePtr = HeapAlloc (GetProcessHeap(), 0, fileSize);
- if (exePtr) {
- DWORD read;
- // read = 保存的是实际读入的大小. 如果完全读完了.就计算PE在内存中对齐后的大小.
- if ( ReadFile (fp, exePtr, fileSize, &read, NULL) && read == fileSize) {
- if ( ReadPEInfo ((char *)exePtr, &mzH2, &peH2, &peXH2, &secHdr2)) {
- int imageSize = CalcTotalImageSize(&mzH2, &peH2, &peXH2, secHdr2);
- ptrLoc = HeapAlloc(GetProcessHeap(), 0, imageSize);
- if (ptrLoc) {
- LoadPE ((char *)exePtr, &mzH2, &peH2, &peXH2, secHdr2, ptrLoc);
- }
- }
- }
- }
- HeapFree (GetProcessHeap(), 0, exePtr);
- }
- CloseHandle (fp);
- }
- return ptrLoc;
- }
- //---------------------- ----------------------
- // ------------------------- ---------------------
- DWORD
- ProcAPIExportAddr (
- DWORD hModule,
- char *apiName
- )
- /*++
- 学习者 : sudami [xiao_rui_119@163.com]
- 时间 : 08/01/11
- 功能 :
- 得到指定模块EAT中的指定函数相对于ntoskrnl.exe的偏移
- 参数 :
- hModule - 模块地址
- apiName - 指定函数名
- 返回 :
- 0 - 如果传进来的参数不正确,则返回0
- # - 指定模块EAT中的指定函数相对于ntoskrnl.exe的偏移
- --*/
- {
- if (!hModule || !apiName) {
- return 0;
- }
- char *ptr = (char *)hModule;
- ptr += 0x3c;
-
- ptr = (char *)(*(DWORD *)ptr) + hModule + 0x78; // 此时ptr保存的是EAT的偏移
- ptr = (char *)(*(DWORD *)ptr) + hModule; // 此时ptr指向EAT
- DWORD numEntries = *(DWORD *)(ptr + 24); // 24-->0x18 NumberOfNames
- DWORD *ExportNamePointerTable = (DWORD *)(*(DWORD *)(ptr + 32) + hModule); // 32-->0x20 AddressOfNames
- DWORD ordinalBase = *((DWORD *)(ptr + 16)); // 16-->0x10 Base
- WORD *ExportOrdinalTable = (WORD *)((*(DWORD *)(ptr + 36)) + hModule); // 36-->0x24 AddressOfNameOrdinals
- DWORD *ExportAddrTable = (DWORD *)((*(DWORD *)(ptr + 28)) + hModule); // 28-->0x1C AddressOfFunctions
- // 遍历每个有名字的函数 (有的函数没有名字)
- for(DWORD i = 0; i < numEntries; i++)
- {
- // 得到函数的名字
- char *exportName = (char *)(ExportNamePointerTable[i] + hModule);
- if (myStrcmpA (exportName, apiName) == TRUE) {
- // 得到函数在AddressOfFunctions中的索引号
- WORD ordinal = ExportOrdinalTable[i];
- return (DWORD)(ExportAddrTable[ordinal]);
- }
- }
- return 0;
- }
- //---------------------- ----------------------
- // ------------------------- ---------------------
- BOOL
- BuildNativeAPITable (
- DWORD hModule,
- char *nativeAPINames[],
- DWORD numNames
- )
- /*++
- 学习者 : sudami [xiao_rui_119@163.com]
- 时间 : 08/01/11
- 功能 :
- 从ntdll.dll的EAT中搜索,建立一张 API 函数表
- 参数 :
- hModule - 模块地址
- nativeAPINames[] - [OUT]保存函数名的数组
- numNames -
- 返回 : TRUE | FALSE
- --*/
- {
- if(!hModule) {
- return FALSE;
- }
- char *ptr = (char *)hModule;
- ptr += 0x3c;
-
- ptr = (char *)(*(DWORD *)ptr) + hModule + 0x78; // 此时ptr保存的是EAT的偏移
- ptr = (char *)(*(DWORD *)ptr) + hModule; // 此时ptr指向EAT
- DWORD numEntries = *(DWORD *)(ptr + 24); // 24-->0x18 NumberOfNames
- DWORD *ExportNamePointerTable = (DWORD *)(*(DWORD *)(ptr + 32) + hModule); // 32-->0x20 AddressOfNames
- DWORD ordinalBase = *((DWORD *)(ptr + 16)); // 16-->0x10 Base
- WORD *ExportOrdinalTable = (WORD *)((*(DWORD *)(ptr + 36)) + hModule); // 36-->0x24 AddressOfNameOrdinals
- DWORD *ExportAddrTable = (DWORD *)((*(DWORD *)(ptr + 28)) + hModule); // 28-->0x1C AddressOfFunctions
- for (DWORD i = 0; i < numEntries; i++)
- {
- // i now contains the index of the API in the Ordinal Table
- // ptr points to Export directory table
- WORD ordinalValue = ExportOrdinalTable[i];
- DWORD apiAddr = (DWORD)ExportAddrTable[ordinalValue] + hModule;
- char *exportName = (char *)(ExportNamePointerTable[i] + hModule);
-
- // Win2K
- if (gWinVersion == 0 &&
- *((UCHAR *)apiAddr) == 0xB8 &&
- *((UCHAR *)apiAddr + 9) == 0xCD &&
- *((UCHAR *)apiAddr + 10) == 0x2E) {
- DWORD serviceNum = *(DWORD *)((char *)apiAddr + 1);
- if(serviceNum < numNames){
- nativeAPINames[serviceNum] = exportName;
- }
- }
-
- // WinXP
- else if (gWinVersion == 1 &&
- *((UCHAR *)apiAddr) == 0xB8 &&
- *((UCHAR *)apiAddr + 5) == 0xBA &&
- *((UCHAR *)apiAddr + 6) == 0x00 &&
- *((UCHAR *)apiAddr + 7) == 0x03 &&
- *((UCHAR *)apiAddr + 8) == 0xFE &&
- *((UCHAR *)apiAddr + 9) == 0x7F) {
- DWORD serviceNum = *(DWORD *)((char *)apiAddr + 1);
- if(serviceNum < numNames) {
- nativeAPINames[serviceNum] = exportName;
- }
- }
- }
- return TRUE;
- }
- //---------------------- ----------------------
- // ------------------------- ---------------------
- HANDLE
- OpenPhyMem(
- )
- /*++
- 学习者 : sudami [xiao_rui_119@163.com]
- 时间 : 08/01/11
- 功能 :
- 从用户态获得 \device\physicalmemory 的句柄
- 参数 : NULL
- 返回 : \device\physicalmemory 的句柄
-
- --*/
- {
- HANDLE hPhyMem;
- OBJECT_ATTRIBUTES oAttr;
- ANSI_STRING aStr;
-
- _RtlInitAnsiString (&aStr, "\\device\\physicalmemory");
-
- UNICODE_STRING uStr;
- if (_RtlAnsiStringToUnicodeString (&uStr, &aStr, TRUE) != STATUS_SUCCESS){
- return INVALID_HANDLE_VALUE;
- }
- oAttr.Length = sizeof(OBJECT_ATTRIBUTES);
- oAttr.RootDirectory = NULL;
- oAttr.Attributes = OBJ_CASE_INSENSITIVE;
- oAttr.ObjectName = &uStr;
- oAttr.SecurityDescriptor = NULL;
- oAttr.SecurityQualityOfService = NULL;
- if (ZwOpenSection (&hPhyMem, SECTION_MAP_READ | SECTION_MAP_WRITE, &oAttr ) != STATUS_SUCCESS) {
- return INVALID_HANDLE_VALUE;
- }
- return hPhyMem;
- }
- //---------------------- ----------------------
- // ------------------------- ---------------------
- BOOL
- MapPhyMem (
- HANDLE hPhyMem,
- DWORD *phyAddr,
- DWORD *length,
- PVOID *virtualAddr
- )
- /*++
- 学习者 : sudami [xiao_rui_119@163.com]
- 时间 : 08/01/11
- 功能 :
- 从用户态获得 \device\physicalmemory 的句柄
- 映射系统地址空间内的一部分数据到用户的地址空间.前提当然是用户对这段空间有读写权限
- 映射结束后 phyAddr 的值发生了变化,它挪到了映射结束的地方
- 参数 :
- hPhyMem - \device\physicalmemory 的句柄
- phyAddr - [IN OUT] 从系统地址范围内的指定位置处开始映射
- length - 指定映射的大小
- virtualAddr - 进程的虚拟地址空间中保存映射的起始地址
- 返回 :
-
- --*/
- {
- NTSTATUS ntStatus;
- PHYSICAL_ADDRESS viewBase;
- *virtualAddr = 0;
- viewBase.QuadPart = (ULONGLONG) (*phyAddr);
- ntStatus = ZwMapViewOfSection (
- hPhyMem,
- (HANDLE)-1,
- virtualAddr, // 指定接收映射的起始地址
- 0,
- *length, // 指定映射的大小
- &viewBase, // 指定从哪儿开始映射
- length, // 保存实际的映射大小
- ViewShare, // 指定继承性
- 0,
- PAGE_READWRITE
- );
- if (ntStatus != STATUS_SUCCESS) {
- printf("Failed to map physical memory view of length %X at %X!", *length, *phyAddr);
- return FALSE;
- }
- *phyAddr = viewBase.LowPart;
- return TRUE;
- }
- // Unmap section of physical memory
- void UnMapPhyMem(DWORD virtualAddr)
- {
- NTSTATUS status;
- status = ZwUnmapViewOfSection ((HANDLE)-1, (PVOID)virtualAddr);
- if (status != STATUS_SUCCESS) {
- printf("Unmapping view failed!\n");
- }
- }
- //---------------------- ----------------------
- // ------------------------- ---------------------
- BOOL
- AssignACL (
- )
- /*++
- 学习者 : sudami [xiao_rui_119@163.com]
- 时间 : 08/01/11
- 功能 :
- 使当前的用户对 \device\physicalmemory 有写的权限
- btw: 此部分需要参考MSDN,里面的数据结构太多.
- 参数 : NULL
- 返回 : TRUE | FALSE
-
- --*/
- {
- HANDLE hPhyMem;
- ANSI_STRING aStr;
- UNICODE_STRING uStr;
- OBJECT_ATTRIBUTES oAttr;
- BOOL result = FALSE;
-
- _RtlInitAnsiString(&aStr, "\\device\\physicalmemory");
- if (_RtlAnsiStringToUnicodeString (&uStr, &aStr, TRUE) != STATUS_SUCCESS) {
- return FALSE;
- }
- oAttr.Length = sizeof(OBJECT_ATTRIBUTES);
- oAttr.RootDirectory = NULL;
- oAttr.Attributes = OBJ_CASE_INSENSITIVE;
- oAttr.ObjectName = &uStr;
- oAttr.SecurityDescriptor = NULL;
- oAttr.SecurityQualityOfService = NULL;
- if (ZwOpenSection (&hPhyMem, READ_CONTROL | WRITE_DAC, &oAttr ) != STATUS_SUCCESS) {
- return FALSE;
- } else {
- PACL dacl;
- PSECURITY_DESCRIPTOR sd;
- if ( GetSecurityInfo (hPhyMem, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL,
- &dacl, NULL, &sd) == ERROR_SUCCESS) {
- EXPLICIT_ACCESS ea;
- // 得到当前进程的用户名
- char userName[MAX_PATH];
- DWORD userNameSize = MAX_PATH-1;
- GetUserName (userName, &userNameSize);
- // 设置精确的权限
- ea.grfAccessPermissions = SECTION_MAP_WRITE;
- ea.grfAccessMode = GRANT_ACCESS;
- ea.grfInheritance = NO_INHERITANCE;
- ea.Trustee.pMultipleTrustee = NULL;
- ea.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
- ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
- ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
- ea.Trustee.ptstrName = userName;
- // 建立新的ACL
- PACL newDacl;
- if ( SetEntriesInAcl(1, &ea, dacl, &newDacl) == ERROR_SUCCESS) {
- // 用新的DACL重新设置当前对象的安全权限
- if( SetSecurityInfo (hPhyMem, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL,
- newDacl, NULL) == ERROR_SUCCESS) {
- result = TRUE;
- }
- LocalFree(newDacl);
- }
- }
- }
- return result;
- }
- //---------------------- ----------------------
- // ------------------------- ---------------------
- DWORD
- GetKernelBase (
- void
- )
- /*++
- 学习者 : sudami [xiao_rui_119@163.com]
- 时间 : 08/01/11
- 功能 :
- 为NtQuerySystemInformation传递11号参数,得到SYSTEM_MODULE_INFORMATION信息,遍历之,得到ntoskrnl.exe的基址
- 参数 : NULL
- 返回 : TRUE | FALSE
-
- --*/
- {
- HANDLE hHeap = GetProcessHeap();
-
- NTSTATUS Status;
- ULONG cbBuffer = 0x8000;
- PVOID pBuffer = NULL;
- DWORD retVal = DEF_KERNEL_BASE; // 0x80400000
- // 这样申请内存 - cbBuffer *= 2;,不错不错.学习~
- do {
- pBuffer = HeapAlloc (hHeap, 0, cbBuffer);
- if (pBuffer == NULL) {
- return DEF_KERNEL_BASE;
- }
- Status = NtQuerySystemInformation (SystemModuleInformation, pBuffer, cbBuffer, NULL);
- if (Status == STATUS_INFO_LENGTH_MISMATCH) {
- HeapFree (hHeap, 0, pBuffer);
- cbBuffer *= 2;
- } else if (Status != STATUS_SUCCESS) {
- HeapFree(hHeap, 0, pBuffer);
- return DEF_KERNEL_BASE;
- }
- }
- while (Status == STATUS_INFO_LENGTH_MISMATCH);
- // 其实没必要这样写哦. 得到系统模块的地址后,第一个就是ntoskrnl.exe的了
- DWORD numEntries = *((DWORD *)pBuffer);
- SYSTEM_MODULE_INFORMATION *smi = (SYSTEM_MODULE_INFORMATION *)((char *)pBuffer + sizeof(DWORD));
- for (DWORD i = 0; i < numEntries; i++) {
- if (strcmpi(smi->ImageName, "ntoskrnl.exe")) {
- retVal = (DWORD)(smi->Base);
- break;
- }
- smi++;
- }
- HeapFree(hHeap, 0, pBuffer);
- return retVal;
- }
- //---------------------- ----------------------
- // ------------------------- ---------------------
- // Thanks to 90210 for this excellent way of getting the KiServiceTable address from the disk image of
- // ntoskrnl.exe
- // http://www.rootkit.com/newsread.php?newsid=176
- DWORD
- getKiServiceTableAddr (
- PVOID exeAddr,
- DWORD sdtAddr,
- PE_ExtHeader *peXH2
- )
- /*--
- 学习者 : sudami [xiao_rui_119@163.com]
- 时间 : 08/01/11
- 参数 :
- exeAddr - 从磁盘中读取指定的文件.在进程的heap当中分配一段空间,按照PE在内存中的对齐方式
- 将文件映射到内存.得到的这个地址(这里用的是PVOID exeAddr = LoadDLL("\\ntoskrnl.exe"))
- sdtAddr - sdt在ntoskrnl.exe中的偏移量
- peXH2 - IMAGE_OPTIONAL_HEADER
- 返回 : TRUE | FALSE
- 功能 : 得到真实的SDT地址
- btw: 此方法得到的不一定准确.系统出问题,后果自负~
- --*/
- {
- // 如果重定位表存在
- if ( peXH2->relocationTableAddress && peXH2->relocationTableSize ) {
- //
- // fixBlk保存的是当前数据块BLOCK[0]的起始地址
- // fixBlk+1 所指向的内容便是这个数据块BLOCK[0]的 VirtualAddress。它指向第一个数据包
- //
- FixupBlock *fixBlk = (FixupBlock *)((char *)exeAddr + peXH2->relocationTableAddress);
- // 其实是一个BLOCK[n]数组。当fixBlk->blockSize不存在时,数组就遍历完了
- while(fixBlk->blockSize) {
- // 一个BLOCK数组中数据包的个数 = (一个数据块的大小 - 8) / 2
- int numEntries = (fixBlk->blockSize - sizeof(FixupBlock)) >> 1;
-
- //
- // offsetPtr指向的是这个BLOCK数组中第一个数据包开始处的地址,然后依次+1。
- // 直到把一个BLOCK遍历完。对每个数据包,判断里面的Type是否为3。如果是,把地址
- // 转化为重定位后的地址
- //
- unsigned short *offsetPtr = (unsigned short *)(fixBlk + 1);
- for(int i = 0; i < numEntries; i++) {
- // 得到每个数据包的重定位类型
- // *offsetPtr & 0xF000 得到的正是Type,右移12位得到它的大小
- int relocType = (*offsetPtr & 0xF000) >> 12;
-
- if(relocType == 3) { // 如果是 IMAGE_REL_BASED_HIGHLOW (3)
- // 计算代码的重定位地址
- // *offsetPtr & 0x0FFF 保存的是偏移量
- DWORD sudami = (DWORD) (fixBlk->pageRVA + (*offsetPtr & 0x0FFF));
- DWORD *codeLoc = (DWORD *)((char *)exeAddr + sudami);
- // *codeLoc 保存的是重定位后sdt在内存中的地址
- if (*codeLoc == sdtAddr + peXH2->imageBase &&
- *(WORD *)((DWORD)codeLoc - 2) == 0x05c7) {
- DWORD kiServiceTableAddr = *(DWORD *)((DWORD)codeLoc + 4);
-
- // checks for presence of found address in the relocation table
- if( sudami + peXH2->imageBase == kiServiceTableAddr) {
- return sudami ;
- }
- }
- }
- offsetPtr++;
- }
- fixBlk = (FixupBlock *)offsetPtr;
- }
- }
- return 0;
- }
- //
- // 主函数入口
- //
- int main (int argc, char* argv[])
- {
- MZHeader mzH2;
- PE_Header peH2;
- PE_ExtHeader peXH2;
- SectionHeader *secHdr2;
- ::system ("title = SDTrestore V 0.2 [Learned by sudami] 08/01/12");
- printf("Author : SIG^2 G-TEC (www.security.org.sg)\n");
- printf("Learner: sudami [xiao_rui_119@163.com] \n\n");
- // 得到系统的版本信息
- OSVERSIONINFO ov;
- ov.dwOSVersionInfoSize = sizeof(ov);
- GetVersionEx (&ov);
- if (ov.dwMajorVersion != 5) {
- printf("Sorry, this version supports only Win2K and WinXP.\n");
- return 1;
- }
- if (ov.dwMinorVersion != 0 && ov.dwMinorVersion != 1) {
- printf("Sorry, this version supports only Win2K and WinXP.\n");
- return 1;
- }
- gWinVersion = ov.dwMinorVersion;
- if (!GetNativeAPIs()) {
- printf("Failed to get addresses of Native APIs!\n");
- return 1;
- }
- // 提升权限。使user能读写内存
- AssignACL();
- HANDLE hPhyMem = OpenPhyMem();
- if ( hPhyMem == INVALID_HANDLE_VALUE) {
- AssignACL();
- }
- hPhyMem = OpenPhyMem();
- if (hPhyMem == INVALID_HANDLE_VALUE) {
- printf("Could not open physical memory device!\n \
- Make sure you are running as Administrator.\n");
- return 1;
- }
- // 映射 ntoskrnl.exe 到用户的进程空间中。对齐
- PVOID exeAddr = LoadDLL("ntoskrnl.exe");
- if (!exeAddr){
- printf("Failed to load ntoskrnl.exe!\n");
- return 1;
- }
- // 在其的EAT中得到SDT相对于ntoskrnl.exe的偏移
- DWORD sdtAddr = ProcAPIExportAddr ((DWORD)exeAddr, "KeServiceDescriptorTable");
- if (!sdtAddr) {
- printf("Failed to get address of KeServiceDescriptorTable!\n");
- return 1;
- }
-
- // 得到其映射后各部分的地址
- if (!ReadPEInfo((char *)exeAddr, &mzH2, &peH2, &peXH2, &secHdr2)) {
- printf("Failed to get PE header of ntoskrnl.exe!\n");
- return 1;
- }
- // kernelPhyBase 为系统加载ntoskrnl.exe后,相对于0x80000000的偏移(对齐了的)
- DWORD kernelPhyBase = GetKernelBase() - PROT_MEMBASE; //#define PROT_MEMBASE 0x80000000
- // kernelOffset 即是RVA
- DWORD kernelOffset = kernelPhyBase - peXH2.imageBase;
- printf ("KeServiceDescriptorTable\t\t%X\n", sdtAddr + GetKernelBase());
- /**********************************************************************************
- 此时已经得到SSDT相对于ntoskrnl.exe的偏移了,保存于sdtAddr.采用普通的方法-->
- 从磁盘读ntoskrnl.exe,计算对齐后的大小.将其对齐后映射到用户进程空间.在其EAT中得到
- SSDT相对于ntoskrnl.exe的偏移
- ***********************************************************************************/
- UCHAR *ptr = NULL;
- DWORD pAddr = sdtAddr + kernelPhyBase;
- DWORD wantedAddr = pAddr;
- DWORD len = 0x2000;
- // 第一次映射
- // 把系统加载的ntoskrnl.exe的SSDT地址映射到进程的虚拟地址空间里面去
- if (MapPhyMem(hPhyMem, &pAddr, &len, (LPVOID *)&ptr)) {
-
- DWORD serviceTableAddr, sdtCount;
- // 现在start保存的是 已经映射的内容的大小
- // 其实是KeServiceDecriptorTable.base从开始到结束的这段大小
- DWORD start = wantedAddr - pAddr;
- // 本来要映射len = 0x2000大小的,但实际上只映射了start大小
- // wantedBytes 是没有按期望映射的差值
- DWORD wantedBytes = len - start;
- /*--
- typedef struct _KSERVICE_TABLE_DESCRIPTOR {
- PULONG_PTR Base;
- PULONG Count;
- ULONG Limit;
- PUCHAR Number;
- } KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
- ++*/
- if (wantedBytes >= 4) {
- serviceTableAddr = *((DWORD *)(&ptr[start]));
- printf("KeServiceDecriptorTable.ServiceTable\t%X\n", serviceTableAddr);
- if (wantedBytes >= 12) {
- // &ptr[start] 是指针,此时指向Base结束的地方,Base中保存了很长一段的数据
- // ((DWORD *)(&ptr[start])) + 2也是指针,指向KeServiceDescriptorTable.ServiceLimit
- sdtCount = *(((DWORD *)(&ptr[start])) + 2);
- printf("KeServiceDescriptorTable.ServiceLimit\t%d\n", sdtCount);
- }
- } else {
- printf("Sorry, an unexpected situation occurred!\n");
- return 1;
- }
- UnMapPhyMem ((DWORD)ptr);
- printf("\n");
- if (sdtCount >= 300) {
- printf("Sorry, an unexpected error occurred! SDT Count > 300???\n");
- return 1;
- }
- pAddr = serviceTableAddr - PROT_MEMBASE; // 0x80000000
- wantedAddr = pAddr;
- ptr = NULL;
- len = 0x2000;
- // 第2次映射
- // 把系统加载的ntoskrnl.exe的KeServiceDecriptorTable.base中的所有内容映射到进程的虚拟地址空间里面去
- if (MapPhyMem(hPhyMem, &pAddr, &len, (LPVOID *)&ptr)) {
- //
- start = wantedAddr - pAddr;
- DWORD numEntries = (len - start) >> 2;
- if (numEntries >= sdtCount) {
- // 为ST表分配名字所占用的空间
- char **nativeApiNames = NULL;
- nativeApiNames = (char **)malloc(sizeof(char *) * sdtCount);
- if(!nativeApiNames) {
- printf("Failed to allocate memory for Native API name table.\n");
- return 1;
- }
- memset (nativeApiNames, 0, sizeof(char *) * sdtCount);
- // 映射ntdll.dll到内存,对齐
- PVOID ntdll = LoadDLL("\\ntdll.dll");
- if(!ntdll) {
- printf("Failed to load ntdll.dll!\n");
- return 1;
- }
- // 建立API名称表表
- BuildNativeAPITable ((DWORD)ntdll, nativeApiNames, sdtCount);
- // *serviceTable 是系统地址空间内的ST表的地址.它是否被HOOK过还不晓得.
- // 所以要拿它和我们自己从文件中读到的偏移相比较
- DWORD *serviceTable = (DWORD *)(&ptr[start]);
- /***********************************
- * *
- * 这里得到了真实的ST地址啦 *
- * *
- ***********************************/
- // wantedAddr = serviceTableAddr - 0x80000000;
- // wantedAddr - kernelOffset. 即是ST表中系统范围内的地址 - RVA = ST在文件中的偏移
- // *fileServiceTable 保存的是真实的ST表中每个函数的偏移
- DWORD *fileServiceTable = (DWORD *)((DWORD)exeAddr + wantedAddr - kernelOffset - peXH2.imageBase);
-
- // calculate address based on 90210's suggestion
- DWORD fileAddr2 = (DWORD)exeAddr + getKiServiceTableAddr(exeAddr, sdtAddr, &peXH2);
-
- // start...
- if (!IsBadReadPtr(fileServiceTable, sizeof(DWORD)) &&
- !IsBadReadPtr(&fileServiceTable[sdtCount-1], sizeof(DWORD))) {
- DWORD hookCount = 0;
- for (DWORD i = 0; i < sdtCount; i++) {
- // 这里就是真正判断是否被HOOK 的地方
- if ( (serviceTable[i] - PROT_MEMBASE - kernelOffset) != fileServiceTable[i]) {
- printf("%-25s %3X --[hooked by unknown at %X]--\n",
- (nativeApiNames[i] ? nativeApiNames[i] : "Unknown API"),
- i, serviceTable[i]);
- hookCount++;
- }
-
- }
- printf("\nNumber of Service Table entries hooked = %u\n", hookCount);
-
- if (hookCount) {
- printf("\nFix SDT Entries (Y/N)? : ");
-
- char inputReply[10];
- memset(inputReply, 0, sizeof(inputReply));
- fgets(inputReply, sizeof(inputReply) - 1, stdin);
- printf("\n");
-
- // 恢复被HOOK的SDT
- if (stricmp(inputReply, "y\n") == 0) {
- ::system ("cls");
- for(DWORD i = 0; i < sdtCount; i++) {
- if((serviceTable[i] - PROT_MEMBASE - kernelOffset) != fileServiceTable[i]) {
-
- // 就这一句就搞定啦~
- serviceTable[i] = fileServiceTable[i] + PROT_MEMBASE + kernelOffset;
- printf("[+] Patched SDT entry %.2X to %.8X\n", i,
- fileServiceTable[i] + PROT_MEMBASE + kernelOffset);
- }
- }
- printf("\n\n[+] SDT Recover is done,but if there is a KTIMER,the SDT may be re-HOOKED again\n");
- ::getchar ();
- } else {
- printf("[-] SDT Entries NOT fixed.\n");
- ::getchar ();
- }
- }
- } else {
- printf("It's likely that the SDT service table has been relocated.\n"
- "This POC code cannot support patching of relocated SDT service table.\n");
- ::getchar ();
- }
- }
- UnMapPhyMem((DWORD)ptr);
- }
- }
- return 0;
- }
- //////////////////////////////////// END OF FILE /////////////////////////////////////////////
复制代码
|
|