Files
dennisbabkin.com 79a52f2b4f Update DrvMain.cpp
2021-05-29 13:06:39 -07:00

251 lines
6.2 KiB
C++

//Main driver entry cpp file
//
// Test solution that demonstrates DLL injection into all running processes
// Copyright (c) 2021 www.dennisbabkin.com
//
// https://dennisbabkin.com/blog/?i=AAA10800
//
// Credit: Rbmm
//
// https://github.com/rbmm/INJECT
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
#include "CFunc.h" //Helper functions
#include "CSection.h" //Section/DLL specific
//Global variables
extern "C" {
PDRIVER_OBJECT g_DriverObject; //Driver object - read-only (for reference counting)
}
IMAGE_LOAD_FLAGS g_Flags; //Global notification flags
CSection sec; //Native section object
#ifdef _WIN64
CSection secWow; //WOW64 section object (used only for a 64-bit build)
#endif
void OnLoadImage(
PUNICODE_STRING FullImageName,
HANDLE ProcessId,
PIMAGE_INFO ImageInfo
)
{
//Called back notification that an image is loaded (or mapped in memory)
//'ProcessId' = process where the image is mapped into (or 0 for a driver)
UNREFERENCED_PARAMETER(FullImageName);
UNREFERENCED_PARAMETER(ProcessId);
UNREFERENCED_PARAMETER(ImageInfo);
NTSTATUS status;
ASSERT(FullImageName);
ASSERT(ImageInfo);
STATIC_UNICODE_STRING(kernel32, "\\kernel32.dll");
//We are looking for kernel32.dll only - skip the rest
if(!ImageInfo->SystemModeImage && //Skip anything mapped into kernel
ProcessId == PsGetCurrentProcessId() && //Our section can be mapped remotely into tis process - we don't need that
CFunc::IsSuffixedUnicodeString(FullImageName, &kernel32) && //Need kernel32.dll only
CFunc::IsMappedByLdrLoadDll(&kernel32) //Make sure that it's a call from the LdrLoadDll() function
#if defined(_DEBUG) && defined(LIMIT_INJECTION_TO_PROC)
&& CFunc::IsSpecificProcessW(ProcessId, LIMIT_INJECTION_TO_PROC, FALSE) //For debug build limit it to specific process only (for testing purposes)
#endif
)
{
#ifdef _WIN64
//Is it a 32-bit process running in a 64-bit OS
BOOLEAN bWowProc = IoIs32bitProcess(NULL);
#else
//Cannot be a WOW64 process on a 32-bit OS
BOOLEAN bWowProc = FALSE;
UNREFERENCED_PARAMETER(bWowProc);
#endif
//Now we can proceed with our injection
#ifdef DBG_VERBOSE_DRV
DbgPrintLine("Image load (WOW=%d) for PID=%u: \"%wZ\"", bWowProc, (ULONG)(ULONG_PTR)ProcessId, FullImageName);
#endif
//Get our (DLL) section to inject
DLL_STATS* pDS;
status = sec.GetSection(&pDS);
if(NT_SUCCESS(status))
{
//And inject now
status = sec.InjectDLL(pDS);
if(!NT_SUCCESS(status))
{
//Error
DbgPrintLine("ERROR: (0x%X) sec.InjectDLL, PID=%u", status, (ULONG)(ULONG_PTR)ProcessId);
}
}
else
{
//Error
DbgPrintLine("ERROR: (0x%X) sec.GetSection, PID=%u", status, (ULONG)(ULONG_PTR)ProcessId);
}
//The following only applies to a 64-bit build
//INFO: We need to inject our DLL into a 32-bit process too...
#ifdef _WIN64
if(bWowProc)
{
status = secWow.GetSection(&pDS);
if(NT_SUCCESS(status))
{
//And inject now
status = secWow.InjectDLL(pDS);
if(!NT_SUCCESS(status))
{
//Error
DbgPrintLine("ERROR: (0x%X) secWow.InjectDLL, PID=%u", status, (ULONG)(ULONG_PTR)ProcessId);
}
}
else
{
//Error
DbgPrintLine("ERROR: (0x%X) secWow.GetSection, PID=%u", status, (ULONG)(ULONG_PTR)ProcessId);
}
}
#endif
}
}
NTSTATUS FreeResources()
{
//Free our resources (must be called before unloading the driver)
NTSTATUS status = STATUS_SUCCESS;
//Remove the notification callback (only if it was set before)
if(_bittestandreset((LONG*)&g_Flags, flImageNotifySet))
{
status = PsRemoveLoadImageNotifyRoutine(OnLoadImage);
if(!NT_SUCCESS(status))
{
DbgPrintLine("CRITICAL: (0x%X) PsRemoveLoadImageNotifyRoutine", status);
}
}
//Free our native section
NTSTATUS status2 = sec.FreeSection();
if(!NT_SUCCESS(status2))
{
//Error
DbgPrintLine("ERROR: (0x%X) sec.FreeSection", status2);
if(NT_SUCCESS(status))
status = status2;
}
#ifdef _WIN64
//Free our WOW64 section
status2 = secWow.FreeSection();
if(!NT_SUCCESS(status2))
{
//Error
DbgPrintLine("ERROR: (0x%X) secWow.FreeSection", status2);
if(NT_SUCCESS(status))
status = status2;
}
#endif
return status;
}
void NTAPI DriverUnload(PDRIVER_OBJECT DriverObject)
{
//Routine that is called when driver is unloaded
NTSTATUS status = FreeResources();
DbgPrintLine("DriverUnload(0x%p), status=0x%x", DriverObject, status);
}
extern "C" NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
//Main driver entry routine
UNREFERENCED_PARAMETER(DriverObject);
UNREFERENCED_PARAMETER(RegistryPath);
DbgPrintLine("DriverLoad(0x%p, %wZ)", DriverObject, RegistryPath);
g_DriverObject = DriverObject;
//Initialize our section object
VERIFY(NT_SUCCESS(sec.Initialize(SEC_TP_NATIVE)));
#ifdef _WIN64
//Initialize our WOW64 section object
VERIFY(NT_SUCCESS(secWow.Initialize(SEC_TP_WOW)));
#endif
DriverObject->DriverUnload = DriverUnload;
//Set image-loading notification routine
NTSTATUS status = PsSetLoadImageNotifyRoutine(OnLoadImage);
if(NT_SUCCESS(status))
{
_bittestandset((LONG*)&g_Flags, flImageNotifySet);
}
else
{
//Error
DbgPrintLine("CRITICAL: (0x%X) PsSetLoadImageNotifyRoutine", status);
}
return status;
}