A forum for reverse engineering, OS internals and malware analysis 

Ask your beginner questions here.
 #16232  by utsav.0202
 Tue Oct 23, 2012 4:46 pm
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
Code: Select all
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()
{
}
This is working fine in XP and Vista but the target process crashes in Windows 7. I am not able to figure out why.
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
 #16419  by kmd
 Sun Nov 04, 2012 10:34 am
out of curiosity, where you found this trash-alike-code? :)
are u sure it works?
 #16421  by EP_X0FF
 Sun Nov 04, 2012 11:05 am
kmd wrote:out of curiosity, where you found this trash-alike-code? :)
are u sure it works?
Double that. I like ASM part. What is the purpose of this super duper code? With nops???
Code: Select all
    __asm
    {
        pushad

        lea eax, DllHandle
        push eax
        lea eax, usDllName
        push eax
        lea eax, DllCharacteristics
        push eax
        push 0

        call [lpLdrLoadDll]

      nop
      nop

        popad

    }
lpLdrLoadDll(NULL, &DllCharacteristics, &usDllName, &DllHadle)
<- this one not so elite to use?

Other errors are ridiculious, miltiple and noob. Beginning from invalid function declarations (hope you compile this with forced __stdcall) and ending with complete ignoring of most possible and required(!) function result values checking. Also check your wonderful return STATUS_UNSUCCESSFUL you copy-pasted twice without releasing previously allocated memory. Additionally your code can try to attach to undefined process object value (no return values checks - why bother?) resulting in wonderful BSOD.

Overall it too ugly even for complete test code.

Before you go do yet another BSOD generator like above ^^ try to learn something from this Agnitum article http://www.rsdn.ru/article/baseserv/InjectDll.xml + source to it http://files.rsdn.ru/8316/inject.zip
 #20033  by EP_X0FF
 Wed Jul 10, 2013 3:04 am
crazyskull wrote:. i modified the dll and put a DbgPrint so when its loaded it will show the output in dbgview.but when I load the driver its never show the statment i put IN DLL.
Try ODS instead.