Hi
I am injecting a dll into a process by using APC. I am sending Process ID, Thread ID, dll path and virtual address of LdrLoadDll in the target process to my driver.
Below is the code
In user mode I am not checking if the thread is alertable or not. Is it necessary as I am setting KETHREAD.ApcState.UserApcPending to 1 in Kernel mode? Also in windows 7 the "APCKernelRoutine" is called 10-15 seconds after DeviceIoControl returns.
Thanks
I am injecting a dll into a process by using APC. I am sending Process ID, Thread ID, dll path and virtual address of LdrLoadDll in the target process to my driver.
Below is the code
Code: Select all
This is working fine in XP and Vista but the target process crashes in Windows 7. I am not able to figure out why.void APCKernelRoutine(PKAPC pKAPC,
PKNORMAL_ROUTINE pUserAPC,
PVOID pContext,
PVOID pSysArg1,
PVOID pSysArg2)
{
DbgPrint("APCKernelRoutine Entered\n");
ExFreePool(pKAPC);
}
NTSTATUS InjectDllByAPC(ULONG TargetPid, ULONG TargetTid, PUNICODE_STRING usDllPath, ULONG LdrMethodAddress)
{
ULONG size;
PKTHREAD TargetThread;
PEPROCESS TargetProcess;
KAPC_STATE ApcState;
ULONG arg1 = 0;
ULONG arg2 = 0;
ULONG arg3 = 0;
DbgPrint("Inside InjectDllByAPC...\n");
size = (unsigned char*)APCMdlCodeEnd - (unsigned char*)APCMdlCode;
DbgPrint("Allocating MDL (1)...\n");
pMDLApcCode = IoAllocateMdl(APCMdlCode, size, FALSE, FALSE, NULL);
if (!pMDLApcCode)
{
return(STATUS_UNSUCCESSFUL);
}
MmProbeAndLockPages(pMDLApcCode, KernelMode, IoWriteAccess);
RtlZeroMemory(pAPCData, sizeof( pAPCData));
memcpy( (char*) pAPCData, usDllPath->Buffer, usDllPath->Length);
unicodeLengthInfo = *(ULONG*) usDllPath;
pMDLApcData = IoAllocateMdl (pAPCData, sizeof(pAPCData), FALSE,FALSE,NULL);
if (!pMDLApcData)
{
return STATUS_UNSUCCESSFUL;
}
MmProbeAndLockPages(pMDLApcData, KernelMode, IoWriteAccess);
PsLookupProcessByProcessId((HANDLE)TargetPid, &TargetProcess);
DbgPrint("Pid: %d, PEPROCESS: 0X%X\n", TargetPid, TargetProcess);
PsLookupThreadByThreadId ((PVOID) TargetTid, &TargetThread);
DbgPrint("Tid: %d, PKTHREAD: 0X%X\n", TargetTid, TargetThread);
KeStackAttachProcess((PKPROCESS) TargetProcess, &ApcState);
pMappedCode = (PVOID*) MmMapLockedPagesSpecifyCache(pMDLApcCode, UserMode, MmCached, NULL, FALSE, NormalPagePriority);
pMappedData = (PVOID*) MmMapLockedPagesSpecifyCache(pMDLApcData, UserMode, MmCached, NULL, FALSE, NormalPagePriority);
KeUnstackDetachProcess (&ApcState);
arg1 = (ULONG) LdrMethodAddress;
arg2 = (ULONG) pMappedData;
arg3 = (ULONG) unicodeLengthInfo;
pKAPC = (PKAPC) ExAllocatePool( NonPagedPool, sizeof(KAPC) );
RtlZeroMemory(pKAPC, sizeof(KAPC));
KeInitializeApc(pKAPC, TargetThread, OriginalApcEnvironment,
(PKKERNEL_ROUTINE)APCKernelRoutine, NULL,
(PKNORMAL_ROUTINE) pMappedCode,
UserMode, (PVOID)arg1);
KeInsertQueueApc(pKAPC, (PVOID)arg2, (PVOID)arg3, 0);
//KETHREAD.ApcState.UserApcPending = 1
//*((unsigned char *)TargetThread + 0x4a) = 1; //XP, 2K3 RTM
//*((unsigned char *)TargetThread + 0x3e) = 1; //2K3 SP1, SP2
//*((unsigned char *)TargetThread + 0x4e) = 1; //Vista
*((unsigned char *)TargetThread + 0x56) = 1; //Win 7
if (pMDLApcCode)
{
MmUnlockPages(pMDLApcCode);
IoFreeMdl(pMDLApcCode);
}
if (pMDLApcData)
{
MmUnlockPages(pMDLApcData);
IoFreeMdl(pMDLApcData);
}
ObDereferenceObject(TargetProcess);
ObDereferenceObject(TargetThread);
return STATUS_SUCCESS;
}
void APCMdlCode(PVOID lpLdrLoadDll, PVOID pwsDllPath, PVOID pwsDllPathLength)
{
UNICODE_STRING usDllName;
ULONG DllCharacteristics = 0;
PVOID DllHandle = 0;
usDllName.Length = (USHORT) pwsDllPathLength;
usDllName.MaximumLength = usDllName.Length + 2;
usDllName.Buffer = (USHORT*) pwsDllPath;
__asm
{
pushad
lea eax, DllHandle
push eax
lea eax, usDllName
push eax
lea eax, DllCharacteristics
push eax
push 0
call [lpLdrLoadDll]
nop
nop
popad
}
}
void APCMdlCodeEnd()
{
}
In user mode I am not checking if the thread is alertable or not. Is it necessary as I am setting KETHREAD.ApcState.UserApcPending to 1 in Kernel mode? Also in windows 7 the "APCKernelRoutine" is called 10-15 seconds after DeviceIoControl returns.
Thanks