diff --git a/README.md b/README.md index 16be916..eafb024 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,330 @@ -# Get-SSDT-Function-Index +# 内核内存映射文件之获取SSDT函数索引号 -内核内存映射文件之获取SSDT函数索引号 \ No newline at end of file +# 背景 + +很多时候,内核下的开发和用户层上的程序开发使用到的技术原理都是相同的,所以,我们可以通过类比学习,快速地对内核开发进行理解与熟悉。 + +正如本文讲解的内存映射文件技术,用户层上有专门的 WIN32 API 提供给我们开发使用。对于内核上,也有相对应的内核函数给我们调用,实现内存映射文件,把磁盘上的文件映射到内核内存空间中来。 + +本文要实现的就是使用内存映射文件技术,将磁盘上的 ntdll.dll 文件映射到内核内存空间中,并从导出表中获取导出函数地址,然后获取 SSDT 函数索引号。所以,这篇文章除了要对内存映射文件技术比较了解之外,还需要对 PE 结构也有一定得了解,否则很难理解透彻这篇文章。现在,我就把实现过程整理成文档,分享给大家。 + +# 函数介绍 + +## ZwOpenFile 函数 + +> 打开现有文件,目录,设备或卷。 +> +> 函数声明 +> +> ```c++ +> NTSTATUS ZwOpenFile( +> _Out_ PHANDLE FileHandle, +> _In_ ACCESS_MASK DesiredAccess, +> _In_ POBJECT_ATTRIBUTES ObjectAttributes, +> _Out_ PIO_STATUS_BLOCK IoStatusBlock, +> _In_ ULONG ShareAccess, +> _In_ ULONG OpenOptions +> ); +> ``` +> +> 参数 +> +> - FileHandle [out] +> 指向接收文件句柄的HANDLE变量的指针。 +> - DesiredAccess [in] +> 指定一个ACCESS_MASK值,用于确定请求的对象访问。有关详细信息,请参阅ZwCreateFile的DesiredAccess参数。其中,GENERIC_READ 包括权限有 STANDARD_RIGHTS_READ、FILE_READ_DATA、FILE_READ_ATTRIBUTES、FILE_READ_EA、以及 SYNCHRONIZE。 +> - ObjectAttributes [in] +> 指向OBJECT_ATTRIBUTES结构的指针,指定对象名称和其他属性。使用InitializeObjectAttributes初始化此结构。如果调用者未在系统线程上下文中运行,则调用InitializeObjectAttributes时必须设置OBJ_KERNEL_HANDLE属性。 +> - IoStatusBlock [out] +> 指向接收最终完成状态的IO_STATUS_BLOCK结构的指针以及有关所请求操作的信息。 +> - ShareAccess [in] +> 指定文件的共享访问类型。有关详细信息,请参阅ZwCreateFile的ShareAccess参数。其中,FILE_SHARE_READ 表示允许其它线程读此文件;FILE_SHARE_WRITE 表示允许其它线程写此文件。 +> - OpenOptions [in] +> 指定打开文件时要应用的选项。有关更多信息,请参阅ZwCreateFile的CreateOptions参数。其中,FILE_SYNCHRONOUS_IO_ALERT 表示文件中的所有操作都是同步执行的。 代表呼叫者的任何等待都会从提醒中提前终止。 该标志还使I / O系统保持文件位置指针。 如果设置此标志,则必须在DesiredAccess参数中设置SYNCHRONIZE标志。 +> +> 返回值 +> +> - 成功,则返回 STATUS_SUCCESS;否则,返回其它 NTSTATUS 错误码。 + +## ZwCreateSection 函数 + +> 创建一个节对象。 +> +> 函数声明 +> +> ```c++ +> NTSTATUS ZwCreateSection( +> _Out_ PHANDLE SectionHandle, +> _In_ ACCESS_MASK DesiredAccess, +> _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, +> _In_opt_ PLARGE_INTEGER MaximumSize, +> _In_ ULONG SectionPageProtection, +> _In_ ULONG AllocationAttributes, +> _In_opt_ HANDLE FileHandle +> ); +> ``` +> +> 参数 +> +> - SectionHandle [out] +> 指向接收段对象的句柄的HANDLE变量的指针。 +> +> - DesiredAccess [in] +> 指定一个ACCESS_MASK值,用于确定请求的对象访问。除了为所有类型的对象定义的访问权限(请参阅ACCESS_MASK)之外,调用者可以指定以下任何访问权限,这些访问权限特定于部分对象: +> DesiredAccess标志允许调用者执行此操作 +> SECTION_EXTEND_SIZE:动态扩展部分的大小。 +> SECTION_MAP_EXECUTE:执行该部分的视图。 +> SECTION_MAP_READ:读取该部分的视图。 +> SECTION_MAP_WRITE:编写该部分的视图。 +> SECTION_QUERY:查询节对象有关该部分的信息。驱动应该设置这个标志。 +> SECTION_ALL_ACCESS:包括上面所有的标志之外,还包括STANDARD_RIGHTS_REQUIRED。 +> +> - ObjectAttributes [in,可选] +> 指向OBJECT_ATTRIBUTES结构的指针,指定对象名称和其他属性。使用InitializeObjectAttributes初始化此结构。如果调用者未在系统线程上下文中运行,则调用InitializeObjectAttributes时必须设置OBJ_KERNEL_HANDLE属性。 +> +> - MaximumSize [in,可选] +> 指定部分的最大大小(以字节为单位)。 ZwCreateSection将此值转换为PAGE_SIZE的最接近的倍数。如果该部分由分页文件支持,则MaximumSize将指定该部分的实际大小。如果该部分由普通文件支持,则MaximumSize指定文件可以扩展或映射到的最大大小。 +> +> - SectionPageProtection [in] +> 指定在该部分的每个页面上放置的保护。使用以下四个值之一:PAGE_READONLY,PAGE_READWRITE,PAGE_EXECUTE或PAGE_WRITECOPY。有关这些值的说明,请参阅CreateFileMapping。其中,PAGE_READWRITE 表示允许将视图映射为只读、写时复制、读/写访问。必须使用 GENERIC_READ 和 GENERIC_WRITE 访问权限创建 hFile 参数指定的文件句柄。 +> +> - AllocationAttributes[in] +> 指定SEC_XXX标志的位掩码,以确定该部分的分配属性。有关这些标志的描述,请参阅CreateFileMapping。其中, +> SEC_COMMIT 是以 PE 结构中的 FileAlignment 大小对齐映射文件。 +> SEC_IMAGE 是以 PE 结构中的 SectionALignment 大小对齐映射文件。 +> +> - FileHandle [in,可选] +> 可选地指定打开的文件对象的句柄。如果FileHandle的值为NULL,则该段由分页文件支持。否则,该部分由指定的文件支持。 +> +> 返回值 +> +> - 成功,则返回 STATUS_SUCCESS;否则,返回其它 NTSTATUS 错误码。 + +## ZwMapViewOfSection 函数 + +> 将一个节表的视图映射到内核的虚拟地址空间。 +> +> 函数声明 +> +> ```c++ +> NTSTATUS ZwMapViewOfSection( +> _In_ HANDLE SectionHandle, +> _In_ HANDLE ProcessHandle, +> _Inout_ PVOID *BaseAddress, +> _In_ ULONG_PTR ZeroBits, +> _In_ SIZE_T CommitSize, +> _Inout_opt_ PLARGE_INTEGER SectionOffset, +> _Inout_ PSIZE_T ViewSize, +> _In_ SECTION_INHERIT InheritDisposition, +> _In_ ULONG AllocationType, +> _In_ ULONG Win32Protect +> ); +> ``` +> +> 参数 +> +> - SectionHandle [in] +> 节对象的句柄。该句柄是通过成功调用ZwCreateSection或ZwOpenSection创建的。 +> - ProcessHandle [in] +> 处理表示视图应该映射到进程的对象。使用ZwCurrentProcess宏来指定当前进程。必须使用PROCESS_VM_OPERATION访问(在Microsoft Windows SDK文档中描述)打开句柄。 +> - BaseAddress [in,out] +> 指向接收视图基地址的变量的指针。如果此参数的值不为NULL,则会从指定的虚拟地址开始分配视图,向下舍入到下一个64K字节的地址边界。 +> - ZeroBits[in] +> 指定截面视图基地址中必须为零的高位地址位数。此参数的值必须小于21,仅当BaseAddress为NULL时才使用 - 换句话说,当调用者允许系统确定在哪里分配视图时。 +> - CommitSize [in] +> 指定视图初始提交的区域的大小(以字节为单位)。 CommitSize仅对页面文件支持的部分有意义,并且四舍五入为PAGE_SIZE的最接近的倍数。 (对于映射文件的部分,数据和图像都将在段创建时提交。) +> - SectionOffset [in,out,optional] +> 指向变量的指针,该变量从字节开始到视图接收以字节为单位的偏移量。如果此指针不为NULL,则向左舍入到下一个分配粒度大小边界。 +> - ViewSize [in,out] +> 指向SIZE_T变量的指针。如果此变量的初始值为零,则ZwMapViewOfSection将在SectionOffset中开始的部分的视图映射到该部分的末尾。否则,初始值指定视图的大小(以字节为单位)。在映射视图之前,ZwMapViewOfSection始终将此值舍入到最接近PAGE_SIZE的倍数。 +> 返回时,该值接收视图的实际大小(以字节为单位)。 +> - InheritDisposition [in] +> 指定视图如何与子进程共享。可能的值是: +> ViewShare +> 该视图将映射到将来创建的任何子进程。 +> ViewUnmap +> 该视图将不会映射到子进程。 +> 驱动程序通常应为此参数指定ViewUnmap。 +> - AllocationType[in] +> 指定一组描述要为指定的页面区域执行的分配类型的标志。有效标志是MEM_LARGE_PAGES,MEM_RESERVE和MEM_TOP_DOWN。虽然不允许MEM_COMMIT,但是除非指定了MEM_RESERVE,否则是默认的。有关MEM_XXX标志的更多信息,请参阅VirtualAlloc例程的说明。MEM_TOP_DOWN 表示在尽可能高的地址分配内存。 +> - Win32Protect [in] +> 指定最初提交的页面区域的保护类型。设备和中间驱动程序应将此值设置为PAGE_READWRITE。 +> +> 返回值 +> +> - 成功,则返回 STATUS_SUCCESS;否则,返回其它 NTSTATUS 错误码。 + +# 实现原理 + +使用WIN32 API来实现内存映射文件,实现步骤如下: + +- 调用 CreatFile 打开想要映射的文件,获得句柄hFile。 + +- 调用 CreatFileMapping 函数生成一个建立在CreatFile函数创建的文件对象基础上的内存映射对象,得到句柄hFileMap。 + +- 调用 MapViewOfFile 函数把整个文件的一个区域或者整个区域映射到内存中,得到指向映射到内存的第一个字节的指针 lpMemory。 + +- 用该指针来读写文件。 + +- 调用 UnmapViewOfFile 来解除文件映射,传入参数为 lpMemory。 + +- 调用 CloseHandle 来关闭内存映射文件,传入参数为 hFileMap。 + +- 调用 CloseHandle 来关闭文件,传入函数为 hFile。 + +那么,在内核下的内存映射文件的实现步骤和用户层的也相同,只是使用的函数不相同而已: + +- 调用 ZwOpenFile 打开想要映射的文件,获得句柄 hFile。 + +- 调用 ZwCreatSection 函数生成一个建立在 ZwOpenFile 函数创建的文件对象基础上的内存映射对象,得到句柄 hSection。 + +- 调用 ZwMapViewOfSection 函数把整个文件的一个区域或者整个区域映射到内存中,得到指向映射到内存的第一个字节的指针 lpMemory。 + +- 用该指针来读写文件。 + +- 调用 ZwUnmapViewOfSection 来解除文件映射,传入参数为进程句柄以及 lpMemory。 + +- 调用 ZwClose 来关闭内存映射文件,传入参数为 hSection。 + +- 调用 ZwClose 来关闭文件,传入函数为 hFile。 + +其中,我们从导入表获取指定导出函数的导出地址的实现流程是: + +- 首先,将文件映射到内核内存后,我们便可以获取文件的映射基址。我们根据 PE 文结构体 IMAGE_DOS_HEADER 和 IMAGE_NT_HEADERS 计算出 OptionahlHeader,接着获取 DataDirectory 中的导出表 RVA 地址。这样,我们可以计算出导出表在内存中的地址。 + +- 然后,我们根据导出表结构 IMAGE_EXPORT_DIRECTORY 获取导出函数名称的个数以及导出函数名称的地址,以此遍历匹配是否是要查找的函数名称。若是,则从 AddressOfNamesOrdinal 中获取导出函数名称对应的导出函数索引值。有了这个导出函数索引值,我们直接就可以在 AddressOfFunctions 导出函数地址表中获取导出函数的地址。 + +- 最后,我们就可以根据 ntdll.dll 导出函数的地址,来获取 SSDT 函数索引号。 + + 其中,对于 32 位系统,ntdll.dll 导出函数总是以下面代码形式为开头: + + ```c++ + mov eax, 函数索引号(4字节) + ``` + + 对于 64 位系统,ntdll.dll 导出函数总是以下面代码形式为开头: + + ```c++ + mov r10, rcx + mov eax, 函数索引号(4字节) + ``` + + 所以,我们对于 32 位系统,只需对导出函数偏移 1 字节处获取 4 字节的数据,那么这 4 字节的数据就是 SSDT 函数索引号;对于 64 位系统,在导出函数的偏移为 4 字节,也是获取 4 字节数据,这 4 字节的数据就是 SSDT 函数索引号。 + +# 编码实现 + +## 内存映射文件 + +```c++ +// 内存映射文件 +NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress) +{ + NTSTATUS status = STATUS_SUCCESS; + HANDLE hFile = NULL; + HANDLE hSection = NULL; + OBJECT_ATTRIBUTES objectAttributes = { 0 }; + IO_STATUS_BLOCK iosb = { 0 }; + PVOID pBaseAddress = NULL; + SIZE_T viewSize = 0; + // 打开 DLL 文件, 并获取文件句柄 + InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, + FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT); + if (!NT_SUCCESS(status)) + { + KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status)); + return status; + } + // 创建一个节对象, 以 PE 结构中的 SectionALignment 大小对齐映射文件 + status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile); + if (!NT_SUCCESS(status)) + { + ZwClose(hFile); + KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status)); + return status; + } + // 映射到内存 + status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE); + if (!NT_SUCCESS(status)) + { + ZwClose(hSection); + ZwClose(hFile); + KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status)); + return status; + } + + // 返回数据 + *phFile = hFile; + *phSection = hSection; + *ppBaseAddress = pBaseAddress; + + return status; +} +``` + +## 根据导出表获取导出函数地址及获取SSDT函数索引号 + +```c++ +// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号 +ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName) +{ + ULONG ulFunctionIndex = 0; + // Dos Header + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress; + // NT Header + PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew); + // Export Table + PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress); + // 有名称的导出函数个数 + ULONG ulNumberOfNames = pExportTable->NumberOfNames; + // 导出函数名称地址表 + PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames); + PCHAR lpName = NULL; + // 开始遍历导出表 + for (ULONG i = 0; i < ulNumberOfNames; i++) + { + lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]); + // 判断是否查找的函数 + if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName))) + { + // 获取导出函数地址 + USHORT uHint = *(USHORT *)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i); + ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint); + PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr); + // 获取 SSDT 函数 Index +# ifdef _WIN64 + ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 4); +# else + ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 1); +# endif + break; + } + } + + return ulFunctionIndex; +} +``` + +# 程序测试 + +在 Win7 32 位系统下,驱动程序执行正常: + +![](http://www.write-bug.com/myres/static/uploads/2021/10/19/16a4b1d5fb35885f4e7b7c2bb9ee876f.writebug) + +在 Win10 64 位系统下,驱动程序执行正常: + +![](http://www.write-bug.com/myres/static/uploads/2021/10/19/9b672566cc4661b4f9afb5c29d62c309.writebug) + +# 总结 + +其中,我们要注意 3 个地方: + +一是,在调用 ZwCreateSection 函数的时候,第 6 个参数我们要设置为SEC_IMAGE,表示以 PE 结构中的 SectionALignment 大小对齐映射文件。这样映射到内存后,我们就可以直接从导出表中较为方便地获取 SSDT 函数索引值。 + +二是,SSDT 函数索引号在 32 位系统下和 64 位系统下,在 ntdll.dll 的导出函数中的偏移是不同的。32 位系统中,SSDT 函数索引号在 ntdll.dll 导出函数偏移 1 字节处;64 位系统中,SSDT 函数索引号在 ntdll.dll 导出函数偏移 4 字节处。 + +三是,内核下表示的文件或者目录路径要在路径前面加上 \\??\\,例如表示 C 盘下的 ntdll.dll文件路径:\\??\\C:\\Windows\\System32\\ntdll.dll。 + +# 参考 + +参考自《[Windows黑客编程技术详解](https://www.write-bug.com/article/1811.html "Windows黑客编程技术详解")》一书 \ No newline at end of file diff --git a/src/GetSSDTFunctionIndex_Test.sln b/src/GetSSDTFunctionIndex_Test.sln new file mode 100644 index 0000000..99f2e68 --- /dev/null +++ b/src/GetSSDTFunctionIndex_Test.sln @@ -0,0 +1,64 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.40629.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GetSSDTFunctionIndex_Test", "GetSSDTFunctionIndex_Test\GetSSDTFunctionIndex_Test.vcxproj", "{21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Win7 Debug|Win32 = Win7 Debug|Win32 + Win7 Debug|x64 = Win7 Debug|x64 + Win7 Release|Win32 = Win7 Release|Win32 + Win7 Release|x64 = Win7 Release|x64 + Win8 Debug|Win32 = Win8 Debug|Win32 + Win8 Debug|x64 = Win8 Debug|x64 + Win8 Release|Win32 = Win8 Release|Win32 + Win8 Release|x64 = Win8 Release|x64 + Win8.1 Debug|Win32 = Win8.1 Debug|Win32 + Win8.1 Debug|x64 = Win8.1 Debug|x64 + Win8.1 Release|Win32 = Win8.1 Release|Win32 + Win8.1 Release|x64 = Win8.1 Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win7 Debug|Win32.ActiveCfg = Win7 Debug|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win7 Debug|Win32.Build.0 = Win7 Debug|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win7 Debug|Win32.Deploy.0 = Win7 Debug|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win7 Debug|x64.ActiveCfg = Win7 Debug|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win7 Debug|x64.Build.0 = Win7 Debug|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win7 Debug|x64.Deploy.0 = Win7 Debug|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win7 Release|Win32.ActiveCfg = Win7 Release|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win7 Release|Win32.Build.0 = Win7 Release|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win7 Release|Win32.Deploy.0 = Win7 Release|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win7 Release|x64.ActiveCfg = Win7 Release|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win7 Release|x64.Build.0 = Win7 Release|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win7 Release|x64.Deploy.0 = Win7 Release|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8 Debug|Win32.ActiveCfg = Win8 Debug|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8 Debug|Win32.Build.0 = Win8 Debug|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8 Debug|Win32.Deploy.0 = Win8 Debug|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8 Debug|x64.ActiveCfg = Win8 Debug|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8 Debug|x64.Build.0 = Win8 Debug|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8 Debug|x64.Deploy.0 = Win8 Debug|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8 Release|Win32.ActiveCfg = Win8 Release|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8 Release|Win32.Build.0 = Win8 Release|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8 Release|Win32.Deploy.0 = Win8 Release|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8 Release|x64.ActiveCfg = Win8 Release|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8 Release|x64.Build.0 = Win8 Release|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8 Release|x64.Deploy.0 = Win8 Release|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8.1 Debug|Win32.ActiveCfg = Win8.1 Debug|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8.1 Debug|Win32.Build.0 = Win8.1 Debug|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8.1 Debug|Win32.Deploy.0 = Win8.1 Debug|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8.1 Debug|x64.ActiveCfg = Win8.1 Debug|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8.1 Debug|x64.Build.0 = Win8.1 Debug|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8.1 Debug|x64.Deploy.0 = Win8.1 Debug|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8.1 Release|Win32.ActiveCfg = Win8.1 Release|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8.1 Release|Win32.Build.0 = Win8.1 Release|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8.1 Release|Win32.Deploy.0 = Win8.1 Release|Win32 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8.1 Release|x64.ActiveCfg = Win8.1 Release|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8.1 Release|x64.Build.0 = Win8.1 Release|x64 + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E}.Win8.1 Release|x64.Deploy.0 = Win8.1 Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/GetSSDTFunctionIndex_Test.v12.suo b/src/GetSSDTFunctionIndex_Test.v12.suo new file mode 100644 index 0000000..80251ce Binary files /dev/null and b/src/GetSSDTFunctionIndex_Test.v12.suo differ diff --git a/src/GetSSDTFunctionIndex_Test/Driver.c b/src/GetSSDTFunctionIndex_Test/Driver.c new file mode 100644 index 0000000..4a0d25c --- /dev/null +++ b/src/GetSSDTFunctionIndex_Test/Driver.c @@ -0,0 +1,41 @@ +#include "Driver.h" +#include "SSDTFunctionIndex.h" + + +NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath) +{ + DbgPrint("Enter DriverEntry\n"); + + NTSTATUS status = STATUS_SUCCESS; + pDriverObject->DriverUnload = DriverUnload; + for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) + { + pDriverObject->MajorFunction[i] = DriverDefaultHandle; + } + + // ntdll.dll лȡ SSDT + UNICODE_STRING ustrDllFileName; + RtlInitUnicodeString(&ustrDllFileName, L"\\??\\C:\\Windows\\System32\\ntdll.dll"); + ULONG ulSSDTFunctionIndex = GetSSDTFunctionIndex(ustrDllFileName, "ZwOpenProcess"); + DbgPrint("ZwOpenProcess[%d]\n", ulSSDTFunctionIndex); + + DbgPrint("Leave DriverEntry\n"); + return status; +} + + + +VOID DriverUnload(PDRIVER_OBJECT pDriverObject) +{ +} + + +NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp) +{ + NTSTATUS status = STATUS_SUCCESS; + pIrp->IoStatus.Status = status; + pIrp->IoStatus.Information = 0; + IoCompleteRequest(pIrp, IO_NO_INCREMENT); + + return status; +} \ No newline at end of file diff --git a/src/GetSSDTFunctionIndex_Test/Driver.h b/src/GetSSDTFunctionIndex_Test/Driver.h new file mode 100644 index 0000000..0822089 --- /dev/null +++ b/src/GetSSDTFunctionIndex_Test/Driver.h @@ -0,0 +1,12 @@ +#ifndef _DRIVER_H_ +#define _DRIVER_H_ + + +#include + + +VOID DriverUnload(PDRIVER_OBJECT pDriverObject); +NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp); + + +#endif \ No newline at end of file diff --git a/src/GetSSDTFunctionIndex_Test/GetSSDTFunctionIndex_Test.inf b/src/GetSSDTFunctionIndex_Test/GetSSDTFunctionIndex_Test.inf new file mode 100644 index 0000000..2ce4c80 --- /dev/null +++ b/src/GetSSDTFunctionIndex_Test/GetSSDTFunctionIndex_Test.inf @@ -0,0 +1,32 @@ +; +; GetSSDTFunctionIndex_Test.inf +; + +[Version] +Signature="$WINDOWS NT$" +Class= +ClassGuid= +Provider= +DriverVer= +CatalogFile= + +[DestinationDirs] +DefaultDestDir = 12 + + +[SourceDisksNames] +1 = %DiskName%,,,"" + +[SourceDisksFiles] + + +[Manufacturer] +%ManufacturerName%=Standard,NT$ARCH$ + +[Standard.NT$ARCH$] + + +[Strings] +ManufacturerName="" +ClassName="" +DiskName="GetSSDTFunctionIndex_Test Source Disk" diff --git a/src/GetSSDTFunctionIndex_Test/GetSSDTFunctionIndex_Test.vcxproj b/src/GetSSDTFunctionIndex_Test/GetSSDTFunctionIndex_Test.vcxproj new file mode 100644 index 0000000..e5a9dd5 --- /dev/null +++ b/src/GetSSDTFunctionIndex_Test/GetSSDTFunctionIndex_Test.vcxproj @@ -0,0 +1,261 @@ + + + + + Win8.1 Debug + Win32 + + + Win8.1 Release + Win32 + + + Win8 Debug + Win32 + + + Win8 Release + Win32 + + + Win7 Debug + Win32 + + + Win7 Release + Win32 + + + Win8.1 Debug + x64 + + + Win8.1 Release + x64 + + + Win8 Debug + x64 + + + Win8 Release + x64 + + + Win7 Debug + x64 + + + Win7 Release + x64 + + + + {21BDE8C9-BD4A-4CB5-AB6D-91F5FE89FA1E} + {dd38f7fc-d7bd-488b-9242-7d8754cde80d} + v4.5 + 11.0 + Win8.1 Debug + Win32 + GetSSDTFunctionIndex_Test + + + + WindowsV6.3 + true + WindowsKernelModeDriver8.1 + Driver + WDM + + + WindowsV6.3 + false + WindowsKernelModeDriver8.1 + Driver + WDM + + + Windows8 + true + WindowsKernelModeDriver8.1 + Driver + WDM + + + Windows8 + false + WindowsKernelModeDriver8.1 + Driver + WDM + + + Windows7 + true + WindowsKernelModeDriver8.1 + Driver + WDM + + + Windows7 + false + WindowsKernelModeDriver8.1 + Driver + WDM + + + WindowsV6.3 + true + WindowsKernelModeDriver8.1 + Driver + WDM + + + WindowsV6.3 + false + WindowsKernelModeDriver8.1 + Driver + WDM + + + Windows8 + true + WindowsKernelModeDriver8.1 + Driver + WDM + + + Windows8 + false + WindowsKernelModeDriver8.1 + Driver + WDM + + + Windows7 + true + WindowsKernelModeDriver8.1 + Driver + WDM + + + Windows7 + false + WindowsKernelModeDriver8.1 + Driver + WDM + + + + + + + + + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + + Level3 + + + + + false + + + false + + + + + Level3 + + + + + false + + + false + + + + + Level3 + + + + + false + + + false + + + + + Level3 + + + + + false + + + false + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/GetSSDTFunctionIndex_Test/GetSSDTFunctionIndex_Test.vcxproj.filters b/src/GetSSDTFunctionIndex_Test/GetSSDTFunctionIndex_Test.vcxproj.filters new file mode 100644 index 0000000..baac145 --- /dev/null +++ b/src/GetSSDTFunctionIndex_Test/GetSSDTFunctionIndex_Test.vcxproj.filters @@ -0,0 +1,42 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {8E41214B-6785-4CFE-B992-037D68949A14} + inf;inv;inx;mof;mc; + + + + + Driver Files + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/src/GetSSDTFunctionIndex_Test/GetSSDTFunctionIndex_Test.vcxproj.user b/src/GetSSDTFunctionIndex_Test/GetSSDTFunctionIndex_Test.vcxproj.user new file mode 100644 index 0000000..14e421f --- /dev/null +++ b/src/GetSSDTFunctionIndex_Test/GetSSDTFunctionIndex_Test.vcxproj.user @@ -0,0 +1,15 @@ + + + + Off + + + Off + + + Off + + + Off + + \ No newline at end of file diff --git a/src/GetSSDTFunctionIndex_Test/SSDTFunctionIndex.c b/src/GetSSDTFunctionIndex_Test/SSDTFunctionIndex.c new file mode 100644 index 0000000..d320925 --- /dev/null +++ b/src/GetSSDTFunctionIndex_Test/SSDTFunctionIndex.c @@ -0,0 +1,116 @@ +#include "SSDTFunctionIndex.h" + + +// ntdll.dll лȡ SSDT +ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName) +{ + ULONG ulFunctionIndex = 0; + NTSTATUS status = STATUS_SUCCESS; + HANDLE hFile = NULL; + HANDLE hSection = NULL; + PVOID pBaseAddress = NULL; + + // ڴӳļ + status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress); + if (!NT_SUCCESS(status)) + { + KdPrint(("DllFileMap Error!\n")); + return ulFunctionIndex; + } + + // ݵȡַ, Ӷȡ SSDT + ulFunctionIndex = GetIndexFromExportTable(pBaseAddress, pszFunctionName); + + // ͷ + ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress); + ZwClose(hSection); + ZwClose(hFile); + + return ulFunctionIndex; +} + + +// ڴӳļ +NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress) +{ + NTSTATUS status = STATUS_SUCCESS; + HANDLE hFile = NULL; + HANDLE hSection = NULL; + OBJECT_ATTRIBUTES objectAttributes = { 0 }; + IO_STATUS_BLOCK iosb = { 0 }; + PVOID pBaseAddress = NULL; + SIZE_T viewSize = 0; + // DLL ļ, ȡļ + InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, + FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT); + if (!NT_SUCCESS(status)) + { + KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status)); + return status; + } + // һڶ, PE ṹе SectionALignment Сӳļ + status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile); + if (!NT_SUCCESS(status)) + { + ZwClose(hFile); + KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status)); + return status; + } + // ӳ䵽ڴ + status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE); + if (!NT_SUCCESS(status)) + { + ZwClose(hSection); + ZwClose(hFile); + KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status)); + return status; + } + + // + *phFile = hFile; + *phSection = hSection; + *ppBaseAddress = pBaseAddress; + + return status; +} + + +// ݵȡַ, Ӷȡ SSDT +ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName) +{ + ULONG ulFunctionIndex = 0; + // Dos Header + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress; + // NT Header + PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew); + // Export Table + PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress); + // Ƶĵ + ULONG ulNumberOfNames = pExportTable->NumberOfNames; + // Ƶַ + PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames); + PCHAR lpName = NULL; + // ʼ + for (ULONG i = 0; i < ulNumberOfNames; i++) + { + lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]); + // жǷҵĺ + if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName))) + { + // ȡַ + USHORT uHint = *(USHORT *)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i); + ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint); + PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr); + // ȡ SSDT Index +#ifdef _WIN64 + ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 4); +#else + ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 1); +#endif + break; + } + } + + return ulFunctionIndex; +} \ No newline at end of file diff --git a/src/GetSSDTFunctionIndex_Test/SSDTFunctionIndex.h b/src/GetSSDTFunctionIndex_Test/SSDTFunctionIndex.h new file mode 100644 index 0000000..6cbadc7 --- /dev/null +++ b/src/GetSSDTFunctionIndex_Test/SSDTFunctionIndex.h @@ -0,0 +1,19 @@ +#ifndef _SSDT_FUNCTION_INDEX_H_ +#define _SSDT_FUNCTION_INDEX_H_ + + +#include +#include + + +// ntdll.dll лȡ SSDT +ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName); + +// ڴӳļ +NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress); + +// ݵȡַ, Ӷȡ SSDT +ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName); + + +#endif \ No newline at end of file diff --git a/src/Win7Debug/GetSSDTFunctionIndex_Test.sys b/src/Win7Debug/GetSSDTFunctionIndex_Test.sys new file mode 100644 index 0000000..21eed41 Binary files /dev/null and b/src/Win7Debug/GetSSDTFunctionIndex_Test.sys differ diff --git a/src/x64/Win8.1Debug/GetSSDTFunctionIndex_Test.sys b/src/x64/Win8.1Debug/GetSSDTFunctionIndex_Test.sys new file mode 100644 index 0000000..7f0f901 Binary files /dev/null and b/src/x64/Win8.1Debug/GetSSDTFunctionIndex_Test.sys differ