#include <ntifs.h>
#include <windef.h>
#include <Aux_klib.h> //source里面要有TARGETLIBS=$(DDK_LIB_PATH)\Aux_klib.lib
/*
功能:获取内核中没有导出的SSDT函数的地址/ID。
思路:因为在NTDLL.DLL里必定有,而且必定是对应的关系。
而且NTDLL.DLL的地址在内核中是可以查询到的。
导出的函数是肯定能查询到的。
ID是根据一个宏获取的。
相应的套入SSDT即可获取那个函数的地址。注意是NT开头的。
注意:试验证明ZwCreateMutant,ZwOpenMutant,NtCreateMutant,NtOpenMutant在内核中都没有导出,用MmGetSystemRoutineAddress是获取不到地址的。
本文测试环境是32位系统,64位系统没有测试,可能需要稍微修改代码。
made by correy
made at 2015.03.16
*/
#define TAG 'tset' //test
#pragma pack(1)
typedef struct ServiceDescriptorEntry{
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase; //Used only in checked build
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()
extern __declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
#define SYSCALL_INDEX(_Function) (*(PULONG)((PUCHAR)_Function+1)) //获取SSDT函数的ID,X64没有测试和观察。
#define SYSTEMSERVICE(index) KeServiceDescriptorTable.ServiceTableBase[index]
DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
}
PVOID RtlImageDirectoryEntryToData (IN PVOID Base, IN BOOLEAN MappedAsImage, IN USHORT DirectoryEntry, OUT PULONG Size);
/*++
Routine Description:
This function locates a Directory Entry within the image header and returns either the virtual address or seek address of the data the Directory describes.
Arguments:
Base - Supplies the base of the image or data file.
MappedAsImage - FALSE if the file is mapped as a data file.
- TRUE if the file is mapped as an image.
DirectoryEntry - Supplies the directory entry to locate.
Size - Return the size of the directory.
Return Value:
NULL - The file does not contain data for the specified directory entry.
NON-NULL - Returns the address of the raw data the directory describes.
--*/
//{
// PIMAGE_NT_HEADERS NtHeaders;
//
// if (LDR_IS_DATAFILE(Base)) {
// Base = LDR_DATAFILE_TO_VIEW(Base);
// MappedAsImage = FALSE;
// }
//
// NtHeaders = RtlImageNtHeader(Base);
//
// if (!NtHeaders)
// return NULL;
//
// if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
// return (RtlpImageDirectoryEntryToData32(Base, MappedAsImage, DirectoryEntry, Size, (PIMAGE_NT_HEADERS32)NtHeaders));
// } else if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
// return (RtlpImageDirectoryEntryToData64(Base, MappedAsImage, DirectoryEntry, Size, (PIMAGE_NT_HEADERS64)NtHeaders));
// } else {
// return (NULL);
// }
//}
PVOID MiFindExportedRoutineByName (IN PVOID DllBase, IN PANSI_STRING AnsiImageRoutineName)
/*++
Routine Description:
This function searches the argument module looking for the requested exported function name.
Arguments:
DllBase - Supplies the base address of the requested module.
AnsiImageRoutineName - Supplies the ANSI routine name being searched for.
Return Value:
The virtual address of the requested routine or NULL if not found.
--*/
{
USHORT OrdinalNumber;
PULONG NameTableBase;
PUSHORT NameOrdinalTableBase;
PULONG Addr;
LONG High;
LONG Low;
LONG Middle;
LONG Result;
ULONG ExportSize;
PVOID FunctionAddress = 0;
PIMAGE_EXPORT_DIRECTORY ExportDirectory;
PAGED_CODE();
__try
{
FunctionAddress = *(PVOID *)DllBase;
FunctionAddress = 0;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return FunctionAddress;
}
//确保DllBase可以访问。否则蓝屏。
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) RtlImageDirectoryEntryToData (DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize);
if (ExportDirectory == NULL) {
return NULL;
}
NameTableBase = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames);// Initialize the pointer to the array of RVA-based ansi export strings.
NameOrdinalTableBase = (PUSHORT)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals);// Initialize the pointer to the array of USHORT ordinal numbers.
Low = 0;
Middle = 0;
High = ExportDirectory->NumberOfNames - 1;
while (High >= Low) // Lookup the desired name in the name table using a binary search.
{
Middle = (Low + High) >> 1;// Compute the next probe index and compare the import name with the export name entry.
Result = strcmp (AnsiImageRoutineName->Buffer, (PCHAR)DllBase + NameTableBase[Middle]);
if (Result < 0) {
High = Middle - 1;
} else if (Result > 0) {
Low = Middle + 1;
} else {
break;
}
}
// If the high index is less than the low index, then a matching table entry was not found.
// Otherwise, get the ordinal number from the ordinal table.
if (High < Low) {
return NULL;
}
OrdinalNumber = NameOrdinalTableBase[Middle];
// If the OrdinalNumber is not within the Export Address Table,then this image does not implement the function.
// Return not found.
if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions) {
return NULL;
}
// Index into the array of RVA export addresses by ordinal number.
Addr = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions);
FunctionAddress = (PVOID)((PCHAR)DllBase + Addr[OrdinalNumber]);
// Forwarders are not used by the kernel and HAL to each other.
ASSERT ((FunctionAddress <= (PVOID)ExportDirectory) || (FunctionAddress >= (PVOID)((PCHAR)ExportDirectory + ExportSize)));
return FunctionAddress;
}
PVOID get_module_image_base(__in UCHAR * name)
{
NTSTATUS status = 0;
ULONG modulesSize;
AUX_MODULE_EXTENDED_INFO * modules;
ULONG numberOfModules;
ULONG i;
PIMAGE_EXPORT_DIRECTORY pied = 0;
PVOID ImageBase = 0;
status = AuxKlibInitialize();
if (!NT_SUCCESS( status ))
{
KdPrint(( "AuxKlibInitialize fail %d\n", status));
return ImageBase;
}
status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), NULL);// Get the required array size.
if (!NT_SUCCESS(status) || modulesSize == 0) {
return ImageBase;
}
numberOfModules = modulesSize / sizeof(AUX_MODULE_EXTENDED_INFO);// Calculate the number of modules.
modules = (AUX_MODULE_EXTENDED_INFO*) ExAllocatePoolWithTag(PagedPool, modulesSize, TAG);// Allocate memory to receive data.
if (modules == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
return ImageBase;
}
RtlZeroMemory(modules, modulesSize);
status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), modules);// Obtain the module information.
if (!NT_SUCCESS(status)) {
ExFreePoolWithTag(modules,TAG);
return ImageBase;
}
for (i = 0;i<numberOfModules;i++)
{
UCHAR * pfilename = modules[i].FullPathName + modules[i].FileNameOffset;
if (_stricmp(pfilename, name) == 0)
{
ImageBase = modules[i].BasicInfo.ImageBase;
break;
}
}
ExFreePoolWithTag(modules,TAG);
return ImageBase;
}
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PVOID ImageBase = 0;
PVOID FunctionAddress;
//ANSI_STRING EngCreateBitmap = RTL_CONSTANT_STRING("EngCreateBitmap");//NT开头的函数竟然一个也没有导出。
ANSI_STRING test = RTL_CONSTANT_STRING("NtCreateMutant");
int index = 0;
PVOID p_NtCreateMutant = 0;
KdBreakPoint();
DriverObject->DriverUnload = Unload;
//ImageBase = get_module_image_base("WIN32k.sys");//注意这个的环境:有的线程不可以访问。不然地址不可访问。
ImageBase = get_module_image_base("ntdll.dll");
if (ImageBase == 0)
{
return status;
}
FunctionAddress = MiFindExportedRoutineByName (ImageBase, &test);
if (FunctionAddress == 0)
{
return status;
}
index = SYSCALL_INDEX(FunctionAddress);
KdPrint(( "NtCreateMutant ID: %d\n", index));
p_NtCreateMutant = (PVOID)SYSTEMSERVICE(index);
KdPrint(( "NtCreateMutant: %p\n", p_NtCreateMutant));
return status;
}
/*
结果如下:
0: kd> g
Mon Mar 16 18:16:28.216 2015 (UTC + 8:00): NtCreateMutant ID: 43
Mon Mar 16 18:16:28.216 2015 (UTC + 8:00):
Mon Mar 16 18:16:28.220 2015 (UTC + 8:00): NtCreateMutant: 80618822
分析如下:
0: kd> u nt!NtCreateMutant
nt!NtCreateMutant:
80618822 6a2c push 2Ch
80618824 6890e44d80 push offset nt!ExpLuidIncrement+0x108 (804de490)
80618829 e81245f2ff call nt!_SEH_prolog (8053cd40)
8061882e 33db xor ebx,ebx
80618830 895dfc mov dword ptr [ebp-4],ebx
80618833 64a124010000 mov eax,dword ptr fs:[00000124h]
80618839 8945d0 mov dword ptr [ebp-30h],eax
8061883c 8a8040010000 mov al,byte ptr [eax+140h]
看来获取的地址是对的。
0: kd> u nt!ZwCreateMutant
nt!ZwCreateMutant:
805010e4 b82b000000 mov eax,2Bh
805010e9 8d542404 lea edx,[esp+4]
805010ed 9c pushfd
805010ee 6a08 push 8
805010f0 e81c150400 call nt!KiSystemService (80542611)
805010f5 c21000 ret 10h
nt!ZwCreateNamedPipeFile:
805010f8 b82c000000 mov eax,2Ch
805010fd 8d542404 lea edx,[esp+4]
0: kd> ?2b
Evaluate expression: 43 = 0000002b
看来获取的ID是正确的。
0: kd> !process 0 0 explorer.exe
PROCESS 81b49020 SessionId: 0 Cid: 0694 Peb: 7ffdb000 ParentCid: 0654
DirBase: 02940200 ObjectTable: e1d1b3b8 HandleCount: 523.
Image: explorer.exe
PROCESS 82054620 SessionId: 0 Cid: 059c Peb: 7ffd6000 ParentCid: 0694
DirBase: 029402e0 ObjectTable: e1604900 HandleCount: 312.
Image: explorer.exe
0: kd> .process /r /p 82054620
Implicit process is now 82054620
.cache forcedecodeuser done
Loading User Symbols
................................................................
.......................
0: kd> u ntdll!ZwCreateMutant
ntdll!NtCreateMutant:
7c92d10e b82b000000 mov eax,2Bh
7c92d113 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c92d118 ff12 call dword ptr [edx]
7c92d11a c21000 ret 10h
7c92d11d 90 nop
ntdll!ZwCreateNamedPipeFile:
7c92d11e b82c000000 mov eax,2Ch
7c92d123 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c92d128 ff12 call dword ptr [edx]
0: kd> u ntdll!NtCreateMutant
ntdll!NtCreateMutant:
7c92d10e b82b000000 mov eax,2Bh
7c92d113 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c92d118 ff12 call dword ptr [edx]
7c92d11a c21000 ret 10h
7c92d11d 90 nop
ntdll!ZwCreateNamedPipeFile:
7c92d11e b82c000000 mov eax,2Ch
7c92d123 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c92d128 ff12 call dword ptr [edx]
*/
/*
1: kd> uf nt!Zwcreatefile
Flow analysis was incomplete, some code may be missing
nt!ZwCreateFile:
fffff800`018d8680 488bc4 mov rax,rsp
fffff800`018d8683 fa cli
fffff800`018d8684 4883ec10 sub rsp,10h
fffff800`018d8688 50 push rax
fffff800`018d8689 9c pushfq
fffff800`018d868a 6a10 push 10h
fffff800`018d868c 488d05dd270000 lea rax,[nt!KiServiceLinkage (fffff800`018dae70)]
fffff800`018d8693 50 push rax
fffff800`018d8694 b852000000 mov eax,52h 注意这个。
fffff800`018d8699 e9225f0000 jmp nt!KiServiceInternal (fffff800`018de5c0)
nt!KiServiceInternal:
fffff800`018de5c0 4883ec08 sub rsp,8
fffff800`018de5c4 55 push rbp
fffff800`018de5c5 4881ec58010000 sub rsp,158h
fffff800`018de5cc 488dac2480000000 lea rbp,[rsp+80h]
fffff800`018de5d4 48899dc0000000 mov qword ptr [rbp+0C0h],rbx
fffff800`018de5db 4889bdc8000000 mov qword ptr [rbp+0C8h],rdi
fffff800`018de5e2 4889b5d0000000 mov qword ptr [rbp+0D0h],rsi
fffff800`018de5e9 fb sti
fffff800`018de5ea 65488b1c2588010000 mov rbx,qword ptr gs:[188h]
fffff800`018de5f3 0f0d8bd8010000 prefetchw [rbx+1D8h]
fffff800`018de5fa 0fb6bbf6010000 movzx edi,byte ptr [rbx+1F6h]
fffff800`018de601 40887da8 mov byte ptr [rbp-58h],dil
fffff800`018de605 c683f601000000 mov byte ptr [rbx+1F6h],0
fffff800`018de60c 4c8b93d8010000 mov r10,qword ptr [rbx+1D8h]
fffff800`018de613 4c8995b8000000 mov qword ptr [rbp+0B8h],r10
fffff800`018de61a 4c8d1d3d010000 lea r11,[nt!KiSystemServiceStart (fffff800`018de75e)]
fffff800`018de621 41ffe3 jmp r11
1: kd> !process 0 0 explorer.exe
PROCESS fffffa801ad91910
SessionId: 1 Cid: 06a4 Peb: 7fffffdd000 ParentCid: 0680
DirBase: 66ef5000 ObjectTable: fffff8a0011323b0 HandleCount: 755.
Image: explorer.exe
1: kd> .process /p /r fffffa801ad91910
Implicit process is now fffffa80`1ad91910
.cache forcedecodeuser done
Loading User Symbols
................................................................
................................................................
...........
1: kd> uf ntdll!NtCreateFile
ntdll!ZwCreateFile:
00000000`77051860 4c8bd1 mov r10,rcx
00000000`77051863 b852000000 mov eax,52h 注意这个
00000000`77051868 0f05 syscall
00000000`7705186a c3 ret
知道64位SSDT的结构及地址,根据上面的示例不难写出X64的相应的例子。
*/
没有评论:
发表评论