typedef enum _InjectType { IT_Thread, IT_Apc, IT_MMap, } InjectType;
typedef enum _PolicyOpt { Policy_Disable, Policy_Enable, Policy_Keep, } PolicyOpt;
typedef struct _SET_PROC_PROTECTION { ULONG pid; PolicyOpt protection; PolicyOpt dynamicCode; PolicyOpt signature; } SET_PROC_PROTECTION, *PSET_PROC_PROTECTION;
NTSTATUS BBInjectDll( IN PINJECT_DLL pData ) { NTSTATUS status = STATUS_SUCCESS; NTSTATUS threadStatus = STATUS_SUCCESS; PEPROCESS pProcess = NULL;
status = PsLookupProcessByProcessId( (HANDLE)pData->pid, &pProcess ); if (NT_SUCCESS( status )) { KAPC_STATE apc; UNICODE_STRING ustrPath, ustrNtdll; SET_PROC_PROTECTION prot = { 0 }; PVOID pNtdll = NULL; PVOID LdrLoadDll = NULL; PVOID systemBuffer = NULL; BOOLEAN isWow64 = (PsGetProcessWow64Process( pProcess ) != NULL) ? TRUE : FALSE;
if (BBCheckProcessTermination( PsGetCurrentProcess() )) { DPRINT( "BlackBone: %s: Process %u is terminating. Abort\n", __FUNCTION__, pData->pid ); if (pProcess) ObDereferenceObject( pProcess );
return STATUS_PROCESS_IS_TERMINATING; }
if (pData->type == IT_MMap && pData->imageBase) { __try { ProbeForRead( (PVOID)pData->imageBase, pData->imageSize, 1 ); systemBuffer = ExAllocatePoolWithTag( PagedPool, pData->imageSize, BB_POOL_TAG ); RtlCopyMemory( systemBuffer, (PVOID)pData->imageBase, pData->imageSize ); } __except (EXCEPTION_EXECUTE_HANDLER) { DPRINT( "BlackBone: %s: AV in user buffer: 0x%p - 0x%p\n", __FUNCTION__, pData->imageBase, pData->imageBase + pData->imageSize );
if (pProcess) ObDereferenceObject( pProcess );
return STATUS_INVALID_USER_BUFFER; } }
KeStackAttachProcess( pProcess, &apc );
RtlInitUnicodeString( &ustrPath, pData->FullDllPath ); RtlInitUnicodeString( &ustrNtdll, L"Ntdll.dll" );
if (pData->type == IT_MMap) { MODULE_DATA mod = { 0 };
__try { status = BBMapUserImage( pProcess, &ustrPath, systemBuffer, pData->imageSize, pData->asImage, pData->flags, pData->initRVA, pData->initArg, &mod ); } __except (EXCEPTION_EXECUTE_HANDLER){ DPRINT( "BlackBone: %s: Fatal exception in BBMapUserImage. Exception code 0x%x\n", __FUNCTION__, GetExceptionCode() ); }
KeUnstackDetachProcess( &apc );
if (pProcess) ObDereferenceObject( pProcess );
return status; }
pNtdll = BBGetUserModule( pProcess, &ustrNtdll, isWow64 );
if (!pNtdll) { DPRINT( "BlackBone: %s: Failed to get Ntdll base\n", __FUNCTION__ ); status = STATUS_NOT_FOUND; }
if (NT_SUCCESS( status )) { LdrLoadDll = BBGetModuleExport( pNtdll, "LdrLoadDll", pProcess, NULL ); if (!LdrLoadDll) { DPRINT( "BlackBone: %s: Failed to get LdrLoadDll address\n", __FUNCTION__ ); status = STATUS_NOT_FOUND; } }
if (PsIsProtectedProcess( pProcess )) { prot.pid = pData->pid; prot.protection = Policy_Disable; prot.dynamicCode = Policy_Disable; prot.signature = Policy_Disable; BBSetProtection( &prot ); }
if (NT_SUCCESS( status )) { SIZE_T size = 0; PINJECT_BUFFER pUserBuf = isWow64 ? BBGetWow64Code( LdrLoadDll, &ustrPath ) : BBGetNativeCode( LdrLoadDll, &ustrPath );
if (pData->type == IT_Thread) { status = BBExecuteInNewThread( pUserBuf, NULL, THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER, pData->wait, &threadStatus );
if (!NT_SUCCESS( threadStatus )) { status = threadStatus; DPRINT( "BlackBone: %s: User thread failed with status - 0x%X\n", __FUNCTION__, status ); } else { if (pUserBuf->module != 0 && pData->initRVA != 0) { RtlCopyMemory( pUserBuf->buffer, pData->initArg, sizeof( pUserBuf->buffer ) ); BBExecuteInNewThread( (PUCHAR)pUserBuf->module + pData->initRVA, pUserBuf->buffer, THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER, TRUE, &threadStatus ); } else if (pUserBuf->module == 0) DPRINT( "BlackBone: %s: Module base = 0. Aborting\n", __FUNCTION__ ); } } else if (pData->type == IT_Apc) { status = BBApcInject( pUserBuf, pProcess, pData->initRVA, pData->initArg ); } else { DPRINT( "BlackBone: %s: Invalid injection type specified - %d\n", __FUNCTION__, pData->type ); status = STATUS_INVALID_PARAMETER; }
if (NT_SUCCESS( status )) { if (pData->unlink) BBUnlinkFromLoader( pProcess, pUserBuf->module, isWow64 );
if (pData->erasePE) { __try { PIMAGE_NT_HEADERS64 pHdr = RtlImageNtHeader( pUserBuf->module ); if (pHdr) { ULONG oldProt = 0; size = (pHdr->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) ? ((PIMAGE_NT_HEADERS32)pHdr)->OptionalHeader.SizeOfHeaders : pHdr->OptionalHeader.SizeOfHeaders;
if (NT_SUCCESS( ZwProtectVirtualMemory( ZwCurrentProcess(), &pUserBuf->module, &size, PAGE_EXECUTE_READWRITE, &oldProt ) )) { RtlZeroMemory( pUserBuf->module, size ); ZwProtectVirtualMemory( ZwCurrentProcess(), &pUserBuf->module, &size, oldProt, &oldProt );
DPRINT( "BlackBone: %s: PE headers erased. \n", __FUNCTION__ ); } } else DPRINT( "BlackBone: %s: Failed to retrieve PE headers for image\n", __FUNCTION__ ); } __except (EXCEPTION_EXECUTE_HANDLER) { DPRINT( "BlackBone: %s: Exception during PE header erease: 0x%X\n", __FUNCTION__, GetExceptionCode() ); } } }
ZwFreeVirtualMemory( ZwCurrentProcess(), &pUserBuf, &size, MEM_RELEASE ); }
if (prot.pid != 0) { prot.protection = Policy_Enable; prot.dynamicCode = Policy_Enable; prot.signature = Policy_Enable; BBSetProtection( &prot ); }
KeUnstackDetachProcess( &apc ); } else DPRINT( "BlackBone: %s: PsLookupProcessByProcessId failed with status 0x%X\n", __FUNCTION__, status );
if (pProcess) ObDereferenceObject( pProcess );
return status; }
|