mirror of
https://github.com/rbmm/INJECT
synced 2026-06-08 17:02:59 +00:00
722 lines
18 KiB
C++
722 lines
18 KiB
C++
#include "StdAfx.h"
|
|
|
|
_NT_BEGIN
|
|
|
|
//#define _PRINT_CPP_NAMES_
|
|
#include "../inc/asmfunc.h"
|
|
|
|
LONG gFlags;
|
|
|
|
extern "C" {
|
|
PDRIVER_OBJECT g_DriverObject;
|
|
}
|
|
|
|
enum{
|
|
flImageNotifySet,
|
|
};
|
|
|
|
#pragma intrinsic(_lrotr, _lrotl)
|
|
|
|
#define RUN_ONCE_STATUS_TO_CONTEXT(status) ((PVOID)(ULONG_PTR)(_lrotl(status, 4) & ~((1 << RTL_RUN_ONCE_CTX_RESERVED_BITS) - 1)))
|
|
#define RUN_ONCE_CONTEXT_TO_STATUS(Context) ((NTSTATUS)_lrotr((ULONG)(ULONG_PTR)Context, 4))
|
|
|
|
/*++
|
|
|
|
NTSTATUS DLL_INFORMATION::MapSection(PVOID& hmod);
|
|
|
|
if DLL section mapped not at preferred base (STATUS_IMAGE_NOT_AT_BASE, STATUS_IMAGE_AT_DIFFERENT_BASE):
|
|
|
|
1.) system need relocate image to new base, as result modify it pages
|
|
(allocate new private physical pages for modification), after this pages already not shared
|
|
|
|
2.) win10 1703+: system by unknown reason unload it, insert task to LdrpRetryQueue and return STATUS_RETRY
|
|
and then tryed load it again (by using full path (!!) instead known section handle).
|
|
|
|
so mapping DLL not at preferred base have serious penalty
|
|
|
|
for avoid this - map our shellcode at different base - for not occupying preferred base
|
|
|
|
note that because our shellcode is based-independent - any base (STATUS_IMAGE_NOT_AT_BASE) is ok for us.
|
|
we not need relocated this mapping
|
|
|
|
for force shellcode not occupy preferred base:
|
|
1.) before map section - reserve preffered memory range with ZwAllocateVirtualMemory (MEM_RESERVE, PAGE_NOACCESS)
|
|
2.) map section (waited return status - STATUS_IMAGE_NOT_AT_BASE)
|
|
3.) free reserved range
|
|
|
|
however if load native 64-bit dll in wow64 process - preferred DLL base almost certainly will be in wow reserved memory range
|
|
|
|
-------------------------------------------------------------------------------
|
|
difference between STATUS_IMAGE_NOT_AT_BASE and STATUS_IMAGE_AT_DIFFERENT_BASE:
|
|
if section can not be mapped at base:
|
|
|
|
when in ZwMapViewOfSection:
|
|
AllocationType containing MEM_DIFFERENT_IMAGE_BASE_OK flag(used inside LdrLoadDll) -
|
|
section RELOCATED and returned STATUS_IMAGE_AT_DIFFERENT_BASE
|
|
otherwise - section NOT relocated and STATUS_IMAGE_NOT_AT_BASE returned.
|
|
|
|
when STATUS_IMAGE_NOT_AT_BASE returned need process relocs
|
|
when STATUS_IMAGE_AT_DIFFERENT_BASE relocs already applied (in kernel) - not need relocate
|
|
|
|
we use base-independed code in section, we not need relocation
|
|
|
|
so better not use MEM_DIFFERENT_IMAGE_BASE_OK and got unrelocated view
|
|
|
|
--*/
|
|
|
|
struct DLL_INFORMATION
|
|
{
|
|
RTL_RUN_ONCE SectionStatus;
|
|
PVOID Section, PreferredAddress;
|
|
ULONG rva_1, SizeOfImage;
|
|
|
|
NTSTATUS CreateDllSection();
|
|
|
|
NTSTATUS GetSection(PVOID* pSection)
|
|
{
|
|
union {
|
|
PVOID Context;
|
|
NTSTATUS status;
|
|
};
|
|
|
|
if (RtlRunOnceBeginInitialize(&SectionStatus, 0, &Context) == STATUS_PENDING)
|
|
{
|
|
KAPC_STATE as;
|
|
KeStackAttachProcess(PsInitialSystemProcess, &as);
|
|
Context = RUN_ONCE_STATUS_TO_CONTEXT(CreateDllSection());
|
|
KeUnstackDetachProcess(&as);
|
|
RtlRunOnceComplete(&SectionStatus, 0, Context);
|
|
}
|
|
|
|
status = RUN_ONCE_CONTEXT_TO_STATUS(Context);
|
|
|
|
*pSection = Section;
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS MapSection(PVOID& hmod)
|
|
{
|
|
PVOID ReservedAddress = PreferredAddress, BaseAddress = 0;
|
|
SIZE_T RegionSize = SizeOfImage, ViewSize = 0;
|
|
NTSTATUS status = ZwAllocateVirtualMemory(NtCurrentProcess(), &ReservedAddress, 0, &RegionSize, MEM_RESERVE, PAGE_NOACCESS);
|
|
|
|
bool bFreeMemory = false;
|
|
switch (status)
|
|
{
|
|
case STATUS_SUCCESS:
|
|
bFreeMemory = true;
|
|
case STATUS_CONFLICTING_ADDRESSES:
|
|
static LARGE_INTEGER ZeroOffset;
|
|
|
|
if (0 <= (status = MmMapViewOfSection(Section, IoGetCurrentProcess(),
|
|
&BaseAddress, 0, 0, &ZeroOffset, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE)))
|
|
{
|
|
hmod = BaseAddress;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
DbgPrint("MapSection[%x]: %x %p\n", status, bFreeMemory, BaseAddress);
|
|
|
|
if (bFreeMemory)
|
|
{
|
|
ZwFreeVirtualMemory(NtCurrentProcess(), &ReservedAddress, &RegionSize, MEM_RELEASE);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
};
|
|
|
|
namespace DLL_32
|
|
{
|
|
#include "../dlldemo/md5_32.h" // autogenerated file, on post-build step for DllDemo
|
|
|
|
DLL_INFORMATION di {};
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
|
|
namespace DLL_64
|
|
{
|
|
#include "../dlldemo/md5_64.h" // autogenerated file, on post-build step for DllDemo
|
|
|
|
DLL_INFORMATION di {};
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef _WIN64
|
|
#define NATIVE_DLL DLL_64
|
|
#define WOW_DLL DLL_32
|
|
#else
|
|
#define NATIVE_DLL DLL_32
|
|
#endif
|
|
|
|
// RtlAddressInSectionTable not exported in kernel
|
|
|
|
PVOID AddressInSectionTable
|
|
(
|
|
PIMAGE_NT_HEADERS NtHeaders,
|
|
PVOID Base,
|
|
ULONG Rva
|
|
)
|
|
{
|
|
if (ULONG NumberOfSections = NtHeaders->FileHeader.NumberOfSections)
|
|
{
|
|
PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(NtHeaders);
|
|
|
|
do
|
|
{
|
|
ULONG o = Rva - pish->VirtualAddress;
|
|
if (o < pish->Misc.VirtualSize)
|
|
{
|
|
return (PBYTE)Base + pish->PointerToRawData + o;
|
|
}
|
|
|
|
} while (pish++, --NumberOfSections);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
NTSTATUS MapPeAsData(HANDLE hFile, PVOID* BaseAddress, PSIZE_T ViewSize)
|
|
{
|
|
HANDLE hSection;
|
|
|
|
NTSTATUS status = ZwCreateSection(&hSection, SECTION_MAP_READ, 0, 0, PAGE_READONLY, SEC_COMMIT, hFile);
|
|
|
|
if (0 <= status)
|
|
{
|
|
status = ZwMapViewOfSection(hSection, NtCurrentProcess(), BaseAddress, 0, 0, 0, ViewSize, ViewUnmap, 0, PAGE_READONLY);
|
|
}
|
|
|
|
ZwClose(hSection);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS IsFileOk(HANDLE hFile, PVOID _md5, ULONG FileSize, PULONG rva, PULONG AddressOfEntryPoint, PULONG SizeOfImage)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
BCRYPT_ALG_HANDLE hAlgorithm;
|
|
|
|
if (0 <= (status = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_MD5_ALGORITHM, 0, 0)))
|
|
{
|
|
union {
|
|
ULONG64 align;
|
|
UCHAR md5[16];
|
|
};
|
|
BCRYPT_HASH_HANDLE hHash;
|
|
|
|
if (0 <= (status = BCryptCreateHash(hAlgorithm, &hHash, 0, 0, 0, 0, 0)))
|
|
{
|
|
PVOID BaseAddress = 0;
|
|
SIZE_T ViewSize = 0;
|
|
|
|
if (0 <= (status = MapPeAsData(hFile, &BaseAddress, &ViewSize)))
|
|
{
|
|
status = FileSize > ViewSize ? STATUS_INVALID_IMAGE_HASH : BCryptHashData(hHash, (PUCHAR)BaseAddress, FileSize, 0);
|
|
|
|
if (0 <= status && 0 <= (status = BCryptFinishHash(hHash, md5, sizeof(md5), 0)))
|
|
{
|
|
DbgPrint("md5_0: %016I64x%016I64x\nmd5_1: %016I64x%016I64x\n",
|
|
*(1 + (PULONG64)_md5), *(PULONG64)_md5,
|
|
*(1 + (PULONG64)md5), *(PULONG64)md5);
|
|
|
|
if (memcmp(md5, _md5, sizeof(md5)))
|
|
{
|
|
status = STATUS_INVALID_IMAGE_HASH;
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_INVALID_IMAGE_FORMAT;
|
|
|
|
if (PIMAGE_NT_HEADERS pinth = RtlImageNtHeader(BaseAddress))
|
|
{
|
|
status = STATUS_PROCEDURE_NOT_FOUND;
|
|
|
|
ULONG size, Ordinal = 1;
|
|
PIMAGE_EXPORT_DIRECTORY pied = (PIMAGE_EXPORT_DIRECTORY)
|
|
RtlImageDirectoryEntryToData(BaseAddress, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size);
|
|
|
|
if (pied && size >= sizeof(IMAGE_EXPORT_DIRECTORY) && (Ordinal -= pied->Base) < pied->NumberOfFunctions)
|
|
{
|
|
if (PULONG AddressOfFunctions = (PULONG)AddressInSectionTable(pinth, BaseAddress, pied->AddressOfFunctions))
|
|
{
|
|
*rva = AddressOfFunctions[Ordinal];
|
|
*AddressOfEntryPoint = pinth->OptionalHeader.AddressOfEntryPoint;
|
|
*SizeOfImage = pinth->OptionalHeader.SizeOfImage;
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
|
|
}
|
|
|
|
BCryptDestroyHash(hHash);
|
|
}
|
|
|
|
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
|
|
}
|
|
|
|
DbgPrint("IsFileOk=%x\n", status);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS CreateKnownSection(HANDLE hFile, PCOBJECT_ATTRIBUTES poaKernel32, PCUNICODE_STRING My, PVOID* pTransferAddress, PVOID *pSection)
|
|
{
|
|
ULONG cb = 0, rcb = 256;
|
|
|
|
static volatile UCHAR guz;
|
|
|
|
PVOID stack = alloca(guz);
|
|
|
|
HANDLE hSection;
|
|
|
|
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, const_cast<PUNICODE_STRING>(My), OBJ_CASE_INSENSITIVE|OBJ_PERMANENT };
|
|
|
|
// look for system (smss.exe) assigned SD for known dlls
|
|
|
|
NTSTATUS status = ZwOpenSection(&hSection, READ_CONTROL, const_cast<POBJECT_ATTRIBUTES>(poaKernel32));
|
|
|
|
if (0 <= status)
|
|
{
|
|
do
|
|
{
|
|
if (cb < rcb)
|
|
{
|
|
cb = RtlPointerToOffset(oa.SecurityDescriptor = alloca(rcb - cb), stack);
|
|
}
|
|
|
|
status = ZwQuerySecurityObject(hSection,
|
|
PROCESS_TRUST_LABEL_SECURITY_INFORMATION|
|
|
DACL_SECURITY_INFORMATION|LABEL_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION,
|
|
oa.SecurityDescriptor, cb, &rcb);
|
|
|
|
} while (status == STATUS_BUFFER_TOO_SMALL);
|
|
|
|
ZwClose(hSection);
|
|
|
|
if (0 <= status)
|
|
{
|
|
status = ZwCreateSection(&hSection, SECTION_MAP_EXECUTE|SECTION_QUERY, &oa, 0, PAGE_EXECUTE, SEC_IMAGE, hFile);
|
|
|
|
if (0 <= status)
|
|
{
|
|
SECTION_IMAGE_INFORMATION sii;
|
|
|
|
status = ZwQuerySection(hSection, SectionImageInformation, &sii, sizeof(sii), 0);
|
|
|
|
DbgPrint("[%08x]:%wZ<%p> at %p\n", status, My, hSection, sii.TransferAddress);
|
|
|
|
PVOID Section = 0;
|
|
|
|
if (0 <= status)
|
|
{
|
|
status = ObReferenceObjectByHandle(hSection, 0, 0, KernelMode, &Section, 0);
|
|
}
|
|
|
|
ZwClose(hSection);
|
|
|
|
if (0 <= status)
|
|
{
|
|
*pTransferAddress = sii.TransferAddress;
|
|
*pSection = Section;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS DLL_INFORMATION::CreateDllSection()
|
|
{
|
|
ULONG FileSize;
|
|
PVOID md5;
|
|
PCOBJECT_ATTRIBUTES poaKernel32, poaDLL;
|
|
PCUNICODE_STRING pMy;
|
|
|
|
#ifdef _WIN64
|
|
if (this == &WOW_DLL::di)
|
|
{
|
|
STATIC_UNICODE_STRING(My, "\\KnownDlls32\\{EBB50DDB-F6AA-492d-94E3-1D51B299F627}.DLL");
|
|
STATIC_OBJECT_ATTRIBUTES(oaKernel32, "\\KnownDlls32\\kernel32.dll");
|
|
STATIC_OBJECT_ATTRIBUTES(oaDLL, "\\systemroot\\syswow64\\{EBB50DDB-F6AA-492d-94E3-1D51B299F627}.DLL");
|
|
|
|
poaKernel32 = &oaKernel32, pMy = &My, poaDLL = &oaDLL;
|
|
FileSize = WOW_DLL::FileSize;
|
|
md5 = &WOW_DLL::md5;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
STATIC_UNICODE_STRING(My, "\\KnownDlls\\{EBB50DDB-F6AA-492d-94E3-1D51B299F627}.DLL");
|
|
STATIC_OBJECT_ATTRIBUTES(oaKernel32, "\\KnownDlls\\kernel32.dll");
|
|
STATIC_OBJECT_ATTRIBUTES(oaDLL, "\\systemroot\\system32\\{EBB50DDB-F6AA-492d-94E3-1D51B299F627}.DLL");
|
|
|
|
poaKernel32 = &oaKernel32, pMy = &My, poaDLL = &oaDLL;
|
|
FileSize = NATIVE_DLL::FileSize;
|
|
md5 = &NATIVE_DLL::md5;
|
|
}
|
|
|
|
HANDLE hFile;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
NTSTATUS status = ZwOpenFile(&hFile, FILE_GENERIC_READ|FILE_EXECUTE,
|
|
const_cast<POBJECT_ATTRIBUTES>(poaDLL), &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
DbgPrint("OpenFile(%wZ)=%x %p\n", poaDLL->ObjectName, status, hFile);
|
|
|
|
if (0 <= status)
|
|
{
|
|
FILE_STANDARD_INFORMATION fsi;
|
|
|
|
if (0 <= (status = ZwQueryInformationFile(hFile, &iosb, &fsi, sizeof(fsi), FileStandardInformation)))
|
|
{
|
|
DbgPrint("EndOfFile=%I64x\n_FileSize=%x\n", fsi.EndOfFile.QuadPart, FileSize);
|
|
|
|
if (fsi.EndOfFile.QuadPart == FileSize)
|
|
{
|
|
ULONG AddressOfEntryPoint;
|
|
if (0 <= (status = IsFileOk(hFile, md5, FileSize, &rva_1, &AddressOfEntryPoint, &SizeOfImage)))
|
|
{
|
|
PVOID TransferAddress;
|
|
status = CreateKnownSection(hFile, poaKernel32, pMy, &TransferAddress, &Section);
|
|
PreferredAddress = (PBYTE)TransferAddress - AddressOfEntryPoint;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_INVALID_IMAGE_HASH;
|
|
}
|
|
}
|
|
|
|
ZwClose(hFile);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID CALLBACK RundownRoutine(PKAPC )ASM_FUNCTION;
|
|
VOID CALLBACK KernelRoutine(PKAPC , PKNORMAL_ROUTINE *, PVOID * , PVOID * ,PVOID * )ASM_FUNCTION;
|
|
VOID CALLBACK NormalRoutine(PVOID , PVOID ,PVOID )ASM_FUNCTION;
|
|
|
|
VOID CALLBACK _RundownRoutine(PKAPC Apc)
|
|
{
|
|
CPP_FUNCTION;
|
|
|
|
DbgPrint("--Apc<%p>\n", Apc);
|
|
delete Apc;
|
|
}
|
|
|
|
extern "C"
|
|
NTSYSAPI
|
|
BOOLEAN NTAPI KeTestAlertThread ( IN KPROCESSOR_MODE AlertMode );
|
|
|
|
|
|
VOID CALLBACK _NormalRoutine (
|
|
PKAPC Apc,
|
|
PVOID Section,
|
|
DLL_INFORMATION* pdi
|
|
)
|
|
{
|
|
CPP_FUNCTION;
|
|
|
|
DbgPrint("NormalRoutine(%p, %p, %p)\n", Apc, Section, pdi);
|
|
|
|
PVOID BaseAddress;
|
|
|
|
NTSTATUS status = pdi->MapSection(BaseAddress);
|
|
|
|
ObfDereferenceObject(Section);
|
|
|
|
if (status != STATUS_IMAGE_NOT_AT_BASE)
|
|
{
|
|
DbgPrint("!!!!! MapViewOfSection = %x, %p\n", status, BaseAddress);
|
|
}
|
|
|
|
if (0 <= status)
|
|
{
|
|
union {
|
|
PVOID pvNormalRoutine;
|
|
PKNORMAL_ROUTINE NormalRoutine;
|
|
};
|
|
|
|
PVOID NormalContext = BaseAddress;
|
|
pvNormalRoutine = (PBYTE)BaseAddress + pdi->rva_1;
|
|
|
|
// pvNormalRoutine is valid for CFG because this is exported address from image,
|
|
// which have IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT and
|
|
// pvNormalRoutine was in GuardCFFunctionTable (__guard_fids_table)
|
|
|
|
#ifdef _WIN64
|
|
if (pdi == &WOW_DLL::di) PsWrapApcWow64Thread(&NormalContext, &pvNormalRoutine);
|
|
#endif
|
|
|
|
KeInitializeApc(Apc, KeGetCurrentThread(), OriginalApcEnvironment,
|
|
KernelRoutine, RundownRoutine, NormalRoutine, UserMode, NormalContext);
|
|
|
|
ObfReferenceObject(g_DriverObject);
|
|
|
|
if (KeInsertQueueApc(Apc, NtCurrentProcess(), BaseAddress, IO_NO_INCREMENT))
|
|
{
|
|
DbgPrint("InsertQueueApc(%p, %p, %p)\n", BaseAddress, NormalContext, NormalRoutine);
|
|
|
|
// force call user mode apc
|
|
KeTestAlertThread(UserMode);
|
|
|
|
return ;
|
|
}
|
|
|
|
ObfDereferenceObject(g_DriverObject);
|
|
|
|
MmUnmapViewOfSection(IoGetCurrentProcess(), BaseAddress);
|
|
}
|
|
|
|
DbgPrint("!!!!!!!!!!!!!!!!!!! _NormalRoutine\n");
|
|
|
|
// delete Apc;
|
|
_RundownRoutine(Apc);
|
|
}
|
|
|
|
VOID CALLBACK _KernelRoutine(
|
|
PKAPC Apc,
|
|
PKNORMAL_ROUTINE * /*NormalRoutine*/,
|
|
PVOID * /*NormalContext*/,
|
|
PVOID * /*SystemArgument1*/,
|
|
PVOID * /*SystemArgument2*/
|
|
)
|
|
{
|
|
CPP_FUNCTION;
|
|
|
|
DbgPrint("_KernelRoutine(%p, %x)\n", Apc, Apc->ApcMode);
|
|
|
|
if (Apc->ApcMode == KernelMode)
|
|
{
|
|
// stage #1 - kernel mode apc
|
|
ObfReferenceObject(g_DriverObject);//NormalRoutine will be called
|
|
|
|
return ;
|
|
}
|
|
|
|
// stage #2 - user mode apc, free Apc object
|
|
_RundownRoutine(Apc);
|
|
}
|
|
|
|
BOOLEAN SuffixUnicodeString(PCUNICODE_STRING FullName, PCUNICODE_STRING ShortName)
|
|
{
|
|
if (ShortName->Length < FullName->Length)
|
|
{
|
|
UNICODE_STRING us = {
|
|
ShortName->Length, us.Length,
|
|
(PWSTR)RtlOffsetToPointer(FullName->Buffer, FullName->Length - us.Length)
|
|
};
|
|
|
|
return RtlEqualUnicodeString(&us, ShortName, TRUE);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*++
|
|
we called because somebody call ZwMapViewOfSection with SEC_IMAGE
|
|
but this can be not true load library: (ArbitraryUserPointer -> L"*\\kernel32.dll" in true load lib)
|
|
smss.exe map kernel32.dll during create \\KnownDlls (ArbitraryUserPointer == 0 in this case)
|
|
wow64 process several time map kernel32.dll (32 and 64 bit) with WOW64_IMAGE_SECTION or NOT_AN_IMAGE
|
|
--*/
|
|
|
|
BOOLEAN IsByLdrLoadDll(PCUNICODE_STRING ShortName)
|
|
{
|
|
UNICODE_STRING Name;
|
|
|
|
__try
|
|
{
|
|
PNT_TIB Teb = (PNT_TIB)PsGetCurrentThreadTeb();
|
|
|
|
if (!Teb || !(Name.Buffer = (PWSTR)Teb->ArbitraryUserPointer))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ProbeForRead(Name.Buffer, sizeof(WCHAR), __alignof(WCHAR));
|
|
|
|
Name.Length = (USHORT)wcsnlen(Name.Buffer, MAXSHORT);
|
|
|
|
if (Name.Length == MAXSHORT)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Name.MaximumLength = Name.Length <<= 1;
|
|
|
|
DbgPrint("ArbitraryUserPointer=%wZ\n", &Name);
|
|
|
|
return SuffixUnicodeString(&Name, ShortName);
|
|
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
DbgPrint("!!! IsByLdrLoadDll\n");
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN IsTargetProcess()
|
|
{
|
|
PEPROCESS Process = IoGetCurrentProcess();
|
|
PCSTR name = PsGetProcessImageFileName(Process);
|
|
return PsIsProcessBeingDebugged(Process) || !_stricmp("notepad.exe", name);
|
|
}
|
|
|
|
void BeginInject(DLL_INFORMATION* pdi)
|
|
{
|
|
PVOID Section;
|
|
|
|
if (0 <= pdi->GetSection(&Section))
|
|
{
|
|
// for do main job out of critical region
|
|
if (PKAPC Apc = new(NonPagedPool) KAPC)
|
|
{
|
|
KeInitializeApc(Apc, KeGetCurrentThread(), OriginalApcEnvironment,
|
|
KernelRoutine, RundownRoutine, NormalRoutine, KernelMode, Apc);
|
|
|
|
DbgPrint("++Apc<%p> \n", Apc);
|
|
|
|
ObfReferenceObject(g_DriverObject);
|
|
|
|
ObfReferenceObject(Section);
|
|
|
|
if (!KeInsertQueueApc(Apc, Section, pdi, IO_NO_INCREMENT))
|
|
{
|
|
ObfDereferenceObject(Section);
|
|
|
|
RundownRoutine(Apc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID CALLBACK OnLoadImage(
|
|
IN PUNICODE_STRING FullImageName,
|
|
IN HANDLE ProcessId, // where image is mapped
|
|
IN PIMAGE_INFO ImageInfo
|
|
)
|
|
{
|
|
#if 0
|
|
DbgPrint("%x %p(%p) %p %x %wZ\n",
|
|
#ifdef _WIN64
|
|
IoIs32bitProcess(0),
|
|
#else
|
|
0,
|
|
#endif
|
|
ProcessId, PsGetCurrentProcessId(), ImageInfo->ImageBase, ImageInfo->ImageSize, FullImageName);
|
|
#endif
|
|
|
|
STATIC_UNICODE_STRING(kernel32, "\\kernel32.dll");
|
|
|
|
if (
|
|
!ImageInfo->SystemModeImage &&
|
|
ProcessId == PsGetCurrentProcessId() && // section can be "remote" mapped from another process
|
|
SuffixUnicodeString(FullImageName, &kernel32) &&
|
|
IsByLdrLoadDll(&kernel32) //&& IsTargetProcess()
|
|
)
|
|
{
|
|
#if 0 // insert native or wow dll in process
|
|
DLL_INFORMATION* pdi;
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(0))
|
|
{
|
|
pdi = &WOW_DLL::di;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
pdi = &NATIVE_DLL::di;
|
|
}
|
|
|
|
BeginInject(pdi);
|
|
|
|
#else // insert both native and wow dll in wow64 process (just for demo)
|
|
|
|
BeginInject(&NATIVE_DLL::di);
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(0)) BeginInject(&WOW_DLL::di);
|
|
#endif
|
|
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void FreeLoadImageData()
|
|
{
|
|
if (_bittestandreset(&gFlags, flImageNotifySet)) PsRemoveLoadImageNotifyRoutine(OnLoadImage);
|
|
|
|
PVOID Context;
|
|
|
|
if (STATUS_SUCCESS == RtlRunOnceBeginInitialize(&NATIVE_DLL::di.SectionStatus, RTL_RUN_ONCE_CHECK_ONLY, &Context))
|
|
{
|
|
if (0 <= RUN_ONCE_CONTEXT_TO_STATUS(Context))
|
|
{
|
|
// we access di.Section only inside OnLoadImage
|
|
// but it already completed and no more will be called (PsRemoveLoadImageNotifyRoutine)
|
|
// NormalRoutine yet can be executing, but it have own referenced Section pointer
|
|
DbgPrint("delete section %p\n", NATIVE_DLL::di.Section);
|
|
ObMakeTemporaryObject(NATIVE_DLL::di.Section);
|
|
ObfDereferenceObject(NATIVE_DLL::di.Section);
|
|
}
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
if (STATUS_SUCCESS == RtlRunOnceBeginInitialize(&WOW_DLL::di.SectionStatus, RTL_RUN_ONCE_CHECK_ONLY, &Context))
|
|
{
|
|
if (0 <= RUN_ONCE_CONTEXT_TO_STATUS(Context))
|
|
{
|
|
// we access di.Section only inside OnLoadImage
|
|
// but it already completed and no more will be called (PsRemoveLoadImageNotifyRoutine)
|
|
// NormalRoutine yet can be executing, but it have own referenced Section pointer
|
|
DbgPrint("delete section %p\n", WOW_DLL::di.Section);
|
|
ObMakeTemporaryObject(WOW_DLL::di.Section);
|
|
ObfDereferenceObject(WOW_DLL::di.Section);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void NTAPI DriverUnload(PDRIVER_OBJECT DriverObject)
|
|
{
|
|
FreeLoadImageData();
|
|
|
|
DbgPrint("DriverUnload(%p)\n", DriverObject);
|
|
}
|
|
|
|
extern "C" NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
|
|
{
|
|
DbgPrint("DriverLoad(%p, %wZ)\n", DriverObject, RegistryPath);
|
|
|
|
g_DriverObject = DriverObject;
|
|
|
|
DriverObject->DriverUnload = DriverUnload;
|
|
|
|
NTSTATUS status = PsSetLoadImageNotifyRoutine(OnLoadImage);
|
|
|
|
if (0 <= status)
|
|
{
|
|
_bittestandset(&gFlags, flImageNotifySet);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
_NT_END
|