/***********************************
desc : This code was written for inject a dll named text.dll to the target process based on APC.
time : 2013
coder: ejoywx
***********************************/
#include <ntddk.h>
#include <ntimage.h>
#ifndef SEC_IMAGE
#define SEC_IMAGE 0x1000000 // winnt
#endif
extern
PUSHORT
NtBuildNumber;
PVOID
pfn_XxxDispatchAPC = NULL;
PVOID
pfn_LoadLibraryA = NULL;
PVOID
pszText_Kernel32 = NULL;
ULONG
Offset_szText = 0;
ULONG
Offset_LoadLibraryA = 0;
ULONG
Offset_BaseDispatchAPC = 0;
ULONG
Offset_RtlDispatchAPC = 0;
UNICODE_STRING gModuleName[] =
{
RTL_CONSTANT_STRING(L
"\\systemroot\\system32\\ntdll.dll"
),
RTL_CONSTANT_STRING(L
"\\systemroot\\system32\\kernel32.dll"
),
RTL_CONSTANT_STRING(L
"\\WINDOWS\\system32\\kernel32.dll"
),
RTL_CONSTANT_STRING(L
"\\systemroot\\system\\text.dll"
),
RTL_CONSTANT_STRING(L
"\\Device\\HarddiskVolume1\\WINDOWS\\system32\\notepad.exe"
)
};
PIMAGE_NT_HEADERS
NTAPI
RtlImageNtHeader(
PVOID
Base
);
NTSYSAPI
PVOID
NTAPI
RtlImageDirectoryEntryToData(
PVOID
BaseOfImage,
BOOLEAN
MappedAsImage,
USHORT
DirectoryEntry,
PULONG
Size
);
NTSTATUS (NTAPI* pfn_NtQueueApcThread)(
__in
HANDLE
ThreadHandle,
__in
PVOID
ApcRoutine,
__in_opt
PVOID
ApcArgument1,
__in_opt
PVOID
ApcArgument2,
__in_opt
PVOID
ApcArgument3
);
PVOID
NTAPI
TlLoadSysPEtoMem(
IN PUNICODE_STRING FilePath
)
{
OBJECT_ATTRIBUTES ObjectAttributes = {0};
IO_STATUS_BLOCK IoStatusBlock = {0};
HANDLE
FileHandle = NULL;
HANDLE
SectionHandle = NULL;
PVOID
ViewBase = NULL;
PVOID
MemBase = NULL;
SIZE_T
ViewSize = 0;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
InitializeObjectAttributes( &ObjectAttributes,
FilePath,
OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,
NULL,
NULL );
Status = ZwOpenFile ( &FileHandle,
FILE_GENERIC_READ,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE );
if
( NT_SUCCESS( Status ) )
{
InitializeObjectAttributes( &ObjectAttributes,
NULL,
OBJ_KERNEL_HANDLE,
NULL,
NULL );
Status = ZwCreateSection( &SectionHandle,
SECTION_MAP_READ,
&ObjectAttributes,
(PLARGE_INTEGER)NULL,
PAGE_READONLY,
SEC_IMAGE,
FileHandle);
if
( NT_SUCCESS( Status ) )
{
Status = ZwMapViewOfSection(SectionHandle,
ZwCurrentProcess(),
&ViewBase,
0L,
PAGE_SIZE,
NULL,
&ViewSize,
ViewUnmap,
MEM_TOP_DOWN,
PAGE_READWRITE);
if
( NT_SUCCESS( Status ) )
{
MemBase = ExAllocatePoolWithTag( NonPagedPool, ViewSize,
' dmC'
);
if
( MemBase )
{
RtlMoveMemory( MemBase, ViewBase, ViewSize );
}
ZwUnmapViewOfSection( ZwCurrentProcess(), ViewBase );
}
ZwClose( SectionHandle );
}
ZwClose( FileHandle );
}
return
MemBase;
}
PVOID
NTAPI
TlMapKnownDlltoMem(
IN PUNICODE_STRING FilePath
)
{
OBJECT_ATTRIBUTES ObjectAttributes = {0};
HANDLE
SectionHandle = NULL;
PVOID
ViewBase = NULL;
PVOID
MemBase = NULL;
SIZE_T
ViewSize = 0;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
InitializeObjectAttributes( &ObjectAttributes,
FilePath,
OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,
NULL,
NULL );
Status = ZwOpenSection( &SectionHandle,
SECTION_MAP_READ,
&ObjectAttributes
);
if
( NT_SUCCESS( Status ) )
{
Status = ZwMapViewOfSection(SectionHandle,
ZwCurrentProcess(),
&ViewBase,
0L,
PAGE_SIZE,
NULL,
&ViewSize,
ViewUnmap,
MEM_TOP_DOWN,
PAGE_READWRITE );
if
( NT_SUCCESS( Status ) )
{
MemBase = ExAllocatePoolWithTag( NonPagedPool, ViewSize,
' dmC'
);
if
( MemBase )
{
RtlMoveMemory( MemBase, ViewBase, ViewSize );
}
ZwUnmapViewOfSection( ZwCurrentProcess(), ViewBase );
}
ZwClose( SectionHandle );
}
return
MemBase;
}
PVOID
NTAPI
TlGetProcAddress(
IN
PVOID
ImageBase,
IN
PUCHAR
ApiName
)
{
PIMAGE_EXPORT_DIRECTORY ExpDir = NULL;
PULONG
AddressOfNames = NULL;
PULONG
AddressOfFunctions = NULL;
PUSHORT
AddressOfNameOrdinals = NULL;
PVOID
FuncAddress = NULL;
ULONG
ExpDirSize = 0;
ULONG
NumberOfNames = 0;
LONG
Idx = 0;
LONG
ret = 0;
LONG
low = 0;
LONG
mid = 0;
LONG
high = 0;
PCHAR
pName = NULL;
if
( !ImageBase )
return
NULL;
ExpDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(ImageBase,TRUE,IMAGE_DIRECTORY_ENTRY_EXPORT,&ExpDirSize );
if
( ExpDir )
{
AddressOfNames = (
PULONG
)( (
ULONG
)ImageBase + ExpDir->AddressOfNames );
AddressOfFunctions = (
PULONG
)( (
ULONG
)ImageBase + ExpDir->AddressOfFunctions );
AddressOfNameOrdinals = (
PUSHORT
)( (
ULONG
)ImageBase + ExpDir->AddressOfNameOrdinals );
NumberOfNames = ExpDir->NumberOfNames;
if
( (
ULONG
)ApiName & 0xFFFF0000 )
{
high = NumberOfNames-1;
while
(low <= high)
//二分查找,快速定位
{
mid = (high+low)>>1;
pName = (
PCHAR
)ImageBase+AddressOfNames[mid] ;
Idx = 0;
while
( pName[Idx] && pName[Idx] == ApiName[Idx] )
{
++Idx;
}
ret = pName[Idx] - ApiName[Idx];
if
( ret==0 )
{
(
PUCHAR
)FuncAddress=(
PUCHAR
)ImageBase + AddressOfFunctions[ AddressOfNameOrdinals[ mid ] ];
break
;
}
else
if
( ret > 0 )
{
high=mid-1;
}
else
{
low=mid+1;
}
}
}
else
{
(
PUCHAR
)FuncAddress=(
PUCHAR
)ImageBase + AddressOfFunctions[ (
ULONG
)ApiName & 0x0FFFF ];
}
}
return
FuncAddress;
}
ULONG
NTAPI
//just for winxp/win2003
GetOffsetForXxxDispatchApc(
IN
PVOID
pfn_QueueUserApc,
IN
PVOID
ImageBase
)
{
ULONG
Offset = 0;
PUCHAR
pMem = (
PUCHAR
)pfn_QueueUserApc;
PUCHAR
pLim = (
PUCHAR
)pfn_QueueUserApc + 0x100;
while
( pMem < pLim && *(
PULONG
)pMem != 0x90000CC2 ) pMem++;
if
( *(
PULONG
)pMem == 0x90000CC2 )
{
pLim = (
PUCHAR
)pfn_QueueUserApc;
while
( (--pMem) > pLim )
{
if
( *(
PUSHORT
)pMem == 0x75FF && *(
PUSHORT
)(pMem+3) == 0x15FF && *(pMem-5) == 0x68 )
{
Offset = *(
PULONG
)(pMem-4) - (
ULONG
)ImageBase;
break
;
}
}
}
return
Offset;
}
ULONG
NTAPI
GetOffsetForSpecialText(
IN
PVOID
ImageBase,
IN
PCSTR
szText
)
{
ULONG
Offset = 0;
PUCHAR
pMem = (
PUCHAR
)ImageBase;
PUCHAR
pLim = (
PUCHAR
)ImageBase + 0x400;
while
( pMem < pLim )
{
if
( _stricmp( szText, pMem) == 0 )
{
Offset = (
ULONG
)(pMem-(
PUCHAR
)ImageBase);
break
;
}
pMem++;
}
return
Offset;
}
PVOID
NTAPI
TlBuildNtFunc(
IN
ULONG
ServiceId
)
{
PVOID
NtFunc = NULL;
PVOID
pfn_KiSystemService;
PVOID
pfn_ZwQueryKey;
UNICODE_STRING RoutineName;
RtlInitUnicodeString( &RoutineName, L
"ZwQueryKey"
);
pfn_ZwQueryKey = MmGetSystemRoutineAddress( &RoutineName );
if
( pfn_ZwQueryKey )
{
NtFunc = ExAllocatePoolWithTag( NonPagedPool, 32,
' dmC'
);
if
( NtFunc )
{
(
PUCHAR
)pfn_KiSystemService = (
PUCHAR
)pfn_ZwQueryKey + 12 + 5 + *(
PULONG
)((
PUCHAR
)pfn_ZwQueryKey + 12 + 1);
RtlFillMemory( NtFunc, 32, 0xCC );
RtlMoveMemory( NtFunc, pfn_ZwQueryKey, 20 );
*(
PULONG
)((
PUCHAR
)NtFunc + 12 + 1 ) = (
ULONG
)((
PUCHAR
)pfn_KiSystemService - ((
PUCHAR
)NtFunc + 12 + 5));
*(
PULONG
)((
PUCHAR
)NtFunc + 1 ) = ServiceId;
}
}
return
NtFunc;
}
BOOLEAN
NTAPI
TlCheckFileExist(
IN PUNICODE_STRING FileName
)
{
OBJECT_ATTRIBUTES ObjectAttributes = {0};
IO_STATUS_BLOCK IoStatusBlock = {0};
HANDLE
FileHandle = NULL;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
InitializeObjectAttributes( &ObjectAttributes,
FileName,
OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,
NULL,
NULL );
Status = ZwOpenFile ( &FileHandle,
FILE_GENERIC_READ,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE );
if
( NT_SUCCESS( Status ) )
{
ZwClose( FileHandle );
}
return
NT_SUCCESS( Status );
}
VOID
LoadImageNotifyRoutine(
IN PUNICODE_STRING FullImageName,
IN
HANDLE
ProcessId,
IN PIMAGE_INFO ImageInfo
)
{
if
( !pfn_XxxDispatchAPC || !pfn_LoadLibraryA || !pszText_Kernel32 )
{
if
( !pfn_LoadLibraryA || !pszText_Kernel32 )
{
if
( RtlCompareUnicodeString( FullImageName, &gModuleName[2], TRUE ) == 0 )
{
(
PUCHAR
)pfn_LoadLibraryA = (
PUCHAR
)ImageInfo->ImageBase + Offset_LoadLibraryA;
(
PUCHAR
)pszText_Kernel32 = (
PUCHAR
)ImageInfo->ImageBase + Offset_szText;
if
( Offset_BaseDispatchAPC )
{
(
PUCHAR
)pfn_XxxDispatchAPC= (
PUCHAR
)ImageInfo->ImageBase + Offset_BaseDispatchAPC;
}
}
}
if
( Offset_RtlDispatchAPC && !pfn_XxxDispatchAPC )
{
if
( RtlCompareUnicodeString( FullImageName, &gModuleName[0], TRUE ) == 0 )
{
(
PUCHAR
)pfn_XxxDispatchAPC= (
PUCHAR
)ImageInfo->ImageBase + Offset_RtlDispatchAPC;
}
}
}
else
if
( pfn_NtQueueApcThread )
{
if
( RtlCompareUnicodeString( FullImageName, &gModuleName[4], TRUE ) == 0 )
{
pfn_NtQueueApcThread(
ZwCurrentThread(),
pfn_XxxDispatchAPC,
pfn_LoadLibraryA,
pszText_Kernel32,
NULL );
}
}
}
VOID
DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
PsRemoveLoadImageNotifyRoutine( LoadImageNotifyRoutine );
ExFreePool( pfn_NtQueueApcThread );
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
NTSTATUS Status = 0;
ULONG
ServiceId = -1;
PVOID
ImageBase_Ntdll ;
PVOID
ImageBase_Kernel;
PVOID
pfn;
ImageBase_Ntdll = TlLoadSysPEtoMem( &gModuleName[0] );
if
( ImageBase_Ntdll )
{
pfn = TlGetProcAddress( ImageBase_Ntdll,
"NtQueueApcThread"
);
if
( pfn )
{
ServiceId = *(
PULONG
)((
PUCHAR
)pfn + 1 );
}
if
( *NtBuildNumber == 7601 )
{
pfn = TlGetProcAddress( ImageBase_Ntdll, (
PUCHAR
)7 );
if
( pfn )
{
Offset_RtlDispatchAPC = (
ULONG
)pfn - (
ULONG
)ImageBase_Ntdll;
}
}
ExFreePool( ImageBase_Ntdll );
}
ImageBase_Kernel = TlLoadSysPEtoMem( &gModuleName[1] );
if
( ImageBase_Kernel )
{
PIMAGE_NT_HEADERS NtHdrs = RtlImageNtHeader( ImageBase_Kernel );
if
( *NtBuildNumber == 2600 )
{
pfn = TlGetProcAddress( ImageBase_Kernel,
"QueueUserAPC"
);
if
( pfn )
{
Offset_BaseDispatchAPC = GetOffsetForXxxDispatchApc( pfn, (
PVOID
)NtHdrs->OptionalHeader.ImageBase);
}
}
pfn = TlGetProcAddress( ImageBase_Kernel,
"LoadLibraryA"
);
if
( pfn )
{
Offset_LoadLibraryA = (
ULONG
)pfn - (
ULONG
)ImageBase_Kernel;
}
Offset_szText = GetOffsetForSpecialText( (
PUCHAR
)ImageBase_Kernel,
"text"
);
ExFreePool( ImageBase_Kernel );
}
Status = STATUS_NOT_SUPPORTED;
if
( Offset_LoadLibraryA && Offset_szText && (Offset_BaseDispatchAPC || Offset_RtlDispatchAPC) && ServiceId != -1 )
{
Status = STATUS_NO_SUCH_FILE;
//确保文件"systemroot\system\text.dll"存在
if
( TlCheckFileExist( &gModuleName[3] ) )
{
pfn_NtQueueApcThread = TlBuildNtFunc( ServiceId );
}
}
if
( pfn_NtQueueApcThread )
{
Status = PsSetLoadImageNotifyRoutine( LoadImageNotifyRoutine );;
}
if
( !NT_SUCCESS(Status) && pfn_NtQueueApcThread )
{
ExFreePool( pfn_NtQueueApcThread );
}
DriverObject->DriverUnload = DriverUnload;
return
Status;
}