BOOL IATHookInjector::HookFunction(DWORD dwProcessId, CHAR* pModuleName, CHAR* pFunctionName, PVOID pHandler, DWORD dwHandlerSize) const
{
	//PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE
	auto hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwProcessId);
	if (!hProcess)
	{
		printf("Error opening process\r\n");
		return FALSE;
	}

	auto dwPEBAddress = FindRemotePEB(hProcess);
	if (!dwPEBAddress)
	{
		printf("Error finding remote PEB\r\n");
		return FALSE;
	}

	auto pPEB = ReadRemotePEB(hProcess);
	if (!pPEB)
	{
		printf("Error reading remote PEB\r\n");
		return FALSE;
	}

	auto pImage = ReadRemoteImage(hProcess, pPEB->ImageBaseAddress);
	if (!pImage)
	{
		printf("Error reading remote image\r\n");
		return FALSE;
	}

	auto pImportDescriptors = ReadRemoteImportDescriptors(hProcess, pPEB->ImageBaseAddress, pImage->FileHeader->OptionalHeader.DataDirectory);
	if (!pImportDescriptors)
	{
		printf("Error reading remote import descriptors\r\n");
		return FALSE;
	}

	for (DWORD i = 0; i < 0x2000; i++)
	{
		auto descriptor = pImportDescriptors[i];
		auto pName = ReadRemoteDescriptorName(hProcess, pPEB->ImageBaseAddress, &descriptor);

		if (!pName)
		{
			printf("Error reading remote descriptor name\r\n");
			return FALSE;
		}

		if (!_stricmp(pName, pModuleName))
		{
			DWORD dwThunkArrayLen = BUFFER_SIZE / sizeof(IMAGE_THUNK_DATA32);

			auto pILT = ReadRemoteILT(hProcess, pPEB->ImageBaseAddress, &descriptor);

			if (!pILT)
			{
				printf("Error reading remote ILT\r\n");
				return FALSE;
			}

			DWORD dwOffset = 0;

			for (dwOffset = 0; dwOffset < dwThunkArrayLen; dwOffset++)
			{
				auto pImportByName = ReadRemoteImportByName(hProcess, pPEB->ImageBaseAddress, &pILT[dwOffset]);
				if (!pImportByName)
				{
					printf("Error reading remote import by name\r\n");
					return FALSE;
				}

				if (!strcmp(static_cast<char*>(pImportByName->Name), pFunctionName))
					break;
			}

			auto pIAT = ReadRemoteIAT(hProcess, pPEB->ImageBaseAddress, &descriptor);
			if (!pIAT)
			{
				printf("Error reading remote IAT\r\n");
				return FALSE;
			}

			auto dwOriginalAddress = pIAT[dwOffset].u1.AddressOfData;
			printf("Original import address: 0x%x\r\n", dwOriginalAddress);


			auto pImportImageBase = FindRemoteImageBase(hProcess, pPEB, pModuleName);

			if (!pImportImageBase)
			{
				printf("Could not find remote image base for %s\r\n", pModuleName);
				return FALSE;
			}

			auto pImportImage = ReadRemoteImage(hProcess, pImportImageBase);

			if (!pImportImage)
			{
				printf("Could not find remote image at 0x%p\r\n", pImportImageBase);
				return FALSE;
			}

			auto pImportTextHeader = FindSectionHeaderByName(pImportImage->Sections, pImportImage->NumberOfSections, ".text");
			if (!pImportTextHeader)
			{
				printf("Could not find section header\r\n");
				return FALSE;
			}

			auto pHandlerBuffer = new BYTE[dwHandlerSize];

			memcpy(pHandlerBuffer, pHandler, dwHandlerSize);

			auto bSuccess = PatchDWORD(pHandlerBuffer, dwHandlerSize, 0xDEADBEEF, dwOriginalAddress);

			if (!bSuccess)
			{
				printf("Error patching import address into handler");
				return FALSE;
			}

			auto dwHandlerAddress = DWORD(pImportImageBase) + pImportTextHeader->VirtualAddress + pImportTextHeader->SizeOfRawData - dwHandlerSize;

			// Write handler to text section
			bSuccess = WriteProcessMemory(hProcess, LPVOID(dwHandlerAddress), pHandlerBuffer, dwHandlerSize, nullptr);
			if (!bSuccess)
			{
				printf("Error writing process memory");
				return FALSE;
			}

			printf("Handler address: 0x%x\r\n", dwHandlerAddress);

			auto pAddress = LPVOID(DWORD(pPEB->ImageBaseAddress) + descriptor.FirstThunk + (dwOffset * sizeof(IMAGE_THUNK_DATA32)));

			// Write IAT
			bSuccess = WriteProcessMemory(hProcess, pAddress, &dwHandlerAddress, 4, nullptr);

			if (!bSuccess)
			{
				printf("Error writing process memory");
				return FALSE;
			}

			return TRUE;
		}
		if (!descriptor.Characteristics)
		{
			return FALSE;
		}
	}

	return FALSE;
}
void Encoder::Encode(DWORD ID, DWORD Class, DWORD CTNumber, DWORD MType)
{
	BOOL bInsertSurfaceNode = FALSE;
	BOOL bInsertTextureNode = FALSE;
	m_pCurrentNode = m_pRootNode;
	
	// COBRA - RED - Missing Last Texture Initialization to INVALID
	DWORD		dwCurrentTexture=-1;
	DWORD		dwCurrentzBias=0;
	NodeType	LastType=ROOT;
	DXFlagsType	LastFlags;

	LastFlags.w=0x00;
	bool		ChangeSurface=false;

	while(m_pCurrentNode != NULL)
	{
		IdleMode();
		NodeType	Type=m_pCurrentNode->Type;
		DXFlagsType	Flags;
		Flags.w=m_pCurrentNode->Flags.w;
	
		// Make all checks here
		ChangeSurface=false;
		if(Type!=LastType || Type==DOF || Type==CLOSEDOF || Type==SLOT ) ChangeSurface = true;
		if(Flags.b.Texture && m_pCurrentNode->Texture!=dwCurrentTexture) ChangeSurface = true;
		if(Flags.b.Texture != LastFlags.b.Texture) ChangeSurface=true;
		if(Flags.b.Alpha != LastFlags.b.Alpha) ChangeSurface=true;
		if(Flags.b.Gouraud != LastFlags.b.Gouraud ) ChangeSurface=true;
		if(Flags.b.Lite != LastFlags.b.Lite ) ChangeSurface=true;
		if((Flags.b.VColor) != (LastFlags.b.VColor)) ChangeSurface=true;
		if(Flags.b.zBias != LastFlags.b.zBias) ChangeSurface=true;
		if(Flags.b.zBias && m_pCurrentNode->dwzBias!=dwCurrentzBias) ChangeSurface=true;
		if(Flags.b.ChromaKey != LastFlags.b.ChromaKey) ChangeSurface=true;

		// if any change
		if(ChangeSurface){
			
			// Patch the segments
			PatchDWORD();

			switch (Type){

				case	DOT:
				case	LINE:
				case	TRIANGLE:	// Check if a Textured new surace and last texture still valid
									if(Flags.b.Texture && m_pCurrentNode->Texture!=dwCurrentTexture){
										// No moer used Texture node
										//WriteTextureNode(m_pCurrentNode);
										dwCurrentTexture=m_pCurrentNode->Texture;
									}
									dwCurrentzBias=m_pCurrentNode->dwzBias;
									// Write the new Surface
									WriteSurfaceNode(m_pCurrentNode, dwCurrentTexture);
									// New ID
									m_dwNodeID++;
									break;

				case	DOF:		// We've to insert a new DOF node
									{DXDof *pDof = (DXDof*)m_pCurrentNode;	WriteDofNode(pDof);}
									// and reset surfaces properties
									Flags.w=0;
									dwCurrentTexture=-1;
									// New ID
									m_dwNodeID++;
									break;

				case	SLOT:		// We've to insert a new SLOT node
									WriteSlotNode((DXSlot*)m_pCurrentNode);
									// New ID
									m_dwNodeID++;
									break;

		
				case CLOSEDOF:		// We've to insert a new END DOF node
									WriteDofEndNode();
									// and reset surfaces properties
									Flags.w=0;
									dwCurrentTexture=-1;
									// New ID
									m_dwNodeID++;
									break;

				default	:			MessageBox(NULL, "Unknown SURFACE TYPE!!", "Encoder", 0);
			}

			ChangeSurface=false;
			LastFlags=Flags;
			LastType=Type;

		}


		switch(Type)
		{
			case DOT:
			{
				DXVertex *pVertex = (DXVertex*)m_pCurrentNode;
				D3DVERTEXEX dxVertex;
				InitializeVertex(&dxVertex);

				CopyVertex(&(pVertex->Vertex), pVertex->VColor, &dxVertex);
				/*memcpy((void*)&dxVertex, (const void*)&pVertex->Vertex, sizeof(pVertex->Vertex));
				memcpy((void*)(&dxVertex + sizeof(pVertex->Vertex)), (const void*)&pVertex->VColor, sizeof(pVertex->VColor));*/

				// Add vertex in NON INDEXED MODE
				Int16 iIndex = AddVertexToPool(&dxVertex, false);
				WriteBuffer((const void*)&iIndex, sizeof(iIndex));
			}
			break;

			case LINE:
			{
				DXLine *pLine = (DXLine*)m_pCurrentNode;

				for(int i=0; i<2; i++)
				{
					D3DVERTEXEX dxVertex;
					InitializeVertex(&dxVertex);

					CopyVertex(&(pLine->Vertex[i]), pLine->VColor[i], &dxVertex);
					/*memcpy((void*)&dxVertex, (const void*)&pLine->Vertex[i], sizeof(pLine->Vertex[i]));
					memcpy((void*)(&dxVertex + sizeof(pLine->Vertex[i])), (const void*)&pLine->VColor[i], sizeof(pLine->VColor[0]));*/

					Int16 iIndex = AddVertexToPool(&dxVertex);
					WriteBuffer((const void*)&iIndex, sizeof(iIndex));
				}
			}
			break;

			case TRIANGLE:
			{
				DXTriangle *pTriangle = (DXTriangle*)m_pCurrentNode;

				for(int i=0; i<3; i++)
				{
					D3DVERTEXEX dxVertex;
					InitializeVertex(&dxVertex);
					
					CopyVertex(&(pTriangle->Vertex[i]), pTriangle->VColor[i], &dxVertex);
					
					/*BYTE *pVertex = (BYTE*)&dxVertex;
					memcpy((void*)&dxVertex, (const void*)&pTriangle->Vertex[i], sizeof(pTriangle->Vertex[i]));
					memcpy((void*)(pVertex + sizeof(pTriangle->Vertex[i])), (const void*)&pTriangle->VColor[i], sizeof(pTriangle->VColor[0]));*/

					Int16 iIndex = AddVertexToPool(&dxVertex);
					WriteBuffer((const void*)&iIndex, sizeof(iIndex));
				}
			}
			break;

		}
		// Update pointers
		//m_pPreviousNode = m_pCurrentNode;
		m_pCurrentNode  = m_pCurrentNode->Next;
		//m_pNextNode     = m_pCurrentNode != NULL ? m_pCurrentNode->Next : NULL;
	}

	//// Set last node total size (Node + Data (total indexes size))
	//DWORD dwTotalNodeSize = (m_dwTotalSurfaceVertexes*sizeof(Int16) + sizeof(DxSurfaceType));
	//memcpy((void*)m_pLastSurfaceNode, (const void*)&dwTotalNodeSize, sizeof(dwTotalNodeSize));
	//// Add last node Vertex Counter to last surface node
	//memcpy(m_pLastSurfaceNode + 12, (const void*)&m_dwTotalSurfaceVertexes, sizeof(m_dwTotalSurfaceVertexes));

	// Patch the segments
	PatchDWORD();

	// Write ENDMODEL node
	DxEndModelType dxEndModelNode;
	dxEndModelNode.h.dwNodeSize = sizeof(DxEndModelType);
	dxEndModelNode.h.Type = DX_MODELEND;
 	WriteBuffer((void*)&dxEndModelNode, sizeof(dxEndModelNode));

	// Write total number of nodes
	((DxDbHeader*)m_pHeader)->dwNodesNr=m_dwTotalNodeCount;

	// Write other header fields
	//DWORD dwVertexesPoolStart = (DWORD)(m_pBuffer + m_dwBufferOffset);
	((DxDbHeader*)m_pHeader)->pVPool=m_dwBufferOffset;
	((DxDbHeader*)m_pHeader)->dwPoolSize=m_dwVertexesPoolSize;
	((DxDbHeader*)m_pHeader)->dwNVertices=m_dwVertexesNumber;

	// Copy vertexes pool after nodes section
	WriteBuffer((const void*)m_pVertexesPool, m_dwVertexesPoolSize);

	((DxDbHeader*)m_pHeader)->Id=ID;
	((DxDbHeader*)m_pHeader)->ModelSize= m_dwBufferOffset;
	((DxDbHeader*)m_pHeader)->VBClass=Class;
	((DxDbHeader*)m_pHeader)->Version=MODEL_VERSION|((MODEL_VERSION^0xffff)<<16);

	// Assign Materials Features
	m_dwBufferOffset=AssignSurfaceFeatures(m_pBuffer, CTNumber, MType);

#ifdef	CRYPTED_MODELS
	TheVbManager.Encrypt((DWORD*)m_pBuffer);
#endif
	// Write file
	//WriteFile();
}
BOOL HookFunction(DWORD dwProcessId, CHAR* pModuleName, CHAR* pFunctionName, 
				  PVOID pHandler, DWORD dwHandlerSize)
{
	HANDLE hProcess = OpenProcess
	(
		PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_OPERATION | 
			PROCESS_VM_READ | PROCESS_VM_WRITE, 
		0, 
		dwProcessId
	);

	if (!hProcess)
	{
		printf("Error opening process\r\n");
		return FALSE;
	}

	DWORD dwPEBAddress = FindRemotePEB(hProcess);

	if (!dwPEBAddress)
	{
		printf("Error finding remote PEB\r\n");
		return FALSE;
	}

	PEB* pPEB = ReadRemotePEB(hProcess);

	if (!pPEB)
	{
		printf("Error reading remote PEB\r\n");
		return FALSE;
	}

	PLOADED_IMAGE pImage = ReadRemoteImage(hProcess, pPEB->ImageBaseAddress);

	if (!pImage)
	{
		printf("Error reading remote image\r\n");
		return FALSE;
	}

	PIMAGE_IMPORT_DESCRIPTOR pImportDescriptors = ReadRemoteImportDescriptors
	(
		hProcess, 
		pPEB->ImageBaseAddress,
		pImage->FileHeader->OptionalHeader.DataDirectory
	);

	if (!pImportDescriptors)
	{
		printf("Error reading remote import descriptors\r\n");
		return FALSE;
	}

	for (DWORD i = 0; i < 0x2000; i++)
	{
		IMAGE_IMPORT_DESCRIPTOR descriptor = pImportDescriptors[i];

		char* pName = ReadRemoteDescriptorName
		(
			hProcess,
			pPEB->ImageBaseAddress,
			&descriptor
		);

		if (!pName)
		{
			printf("Error reading remote descriptor name\r\n");
			return FALSE;
		}

		BOOL bSuccess;

		if (!_stricmp(pName, pModuleName))
		{
			DWORD dwThunkArrayLen = BUFFER_SIZE / sizeof(IMAGE_THUNK_DATA32);

			PIMAGE_THUNK_DATA32 pILT = ReadRemoteILT
			(
				hProcess, 
				pPEB->ImageBaseAddress, 
				&descriptor
			);

			if (!pILT)
			{
				printf("Error reading remote ILT\r\n");
				return FALSE;
			}

			DWORD dwOffset = 0;

			for (dwOffset = 0; dwOffset < dwThunkArrayLen; dwOffset++)
			{
				PIMAGE_IMPORT_BY_NAME pImportByName = ReadRemoteImportByName
				(
					hProcess, 
					pPEB->ImageBaseAddress, 
					&pILT[dwOffset]
				);

				if (!pImportByName)
				{
					printf("Error reading remote import by name\r\n");
					return FALSE;
				}

				if (!strcmp((char*)pImportByName->Name, pFunctionName))
					break;				
			}

			PIMAGE_THUNK_DATA32 pIAT = ReadRemoteIAT
			(
				hProcess,
				pPEB->ImageBaseAddress,
				&descriptor
			);

			if (!pIAT)
			{
				printf("Error reading remote IAT\r\n");
				return FALSE;
			}

			DWORD dwOriginalAddress = pIAT[dwOffset].u1.AddressOfData;

			printf("Original import address: 0x%p\r\n", dwOriginalAddress);


			PVOID pImportImageBase = FindRemoteImageBase
			(
				hProcess, 
				pPEB, 
				pModuleName
			);

			if (!pImportImageBase)
			{
				printf("Could not find remote image base for %s\r\n", pModuleName);
				return FALSE;
			}

			PLOADED_IMAGE pImportImage = ReadRemoteImage
			(
				hProcess,
				pImportImageBase
			);

			if (!pImportImage)
			{
				printf("Could not find remote image at 0x%p\r\n", pImportImageBase);
				return FALSE;
			}

			PIMAGE_SECTION_HEADER pImportTextHeader = FindSectionHeaderByName
			(
				pImportImage->Sections, 
				pImportImage->NumberOfSections, 
				".text"
			);

			if (!pImportTextHeader)
			{
				printf("Could not find section header\r\n");
				return FALSE;
			}

			BYTE* pHandlerBuffer = new BYTE[dwHandlerSize];

			memcpy(pHandlerBuffer, pHandler, dwHandlerSize);

			BOOL bSuccess = PatchDWORD
			(
				pHandlerBuffer, 
				dwHandlerSize, 
				0xDEADBEEF, 
				dwOriginalAddress
			);

			if (!bSuccess)
			{
				printf("Error patching import address into handler");
				return FALSE;
			}

			DWORD dwHandlerAddress = (DWORD)pImportImageBase + 
				pImportTextHeader->VirtualAddress + 
				pImportTextHeader->SizeOfRawData - 
				dwHandlerSize;

			// Write handler to text section
			bSuccess = WriteProcessMemory
			(
				hProcess,
				(LPVOID)dwHandlerAddress, 
				pHandlerBuffer, 
				dwHandlerSize, 
				0
			);

			if (!bSuccess)
			{
				printf("Error writing process memory");
				return FALSE;
			}

			printf("Handler address: 0x%p\r\n", dwHandlerAddress);

			LPVOID pAddress = (LPVOID)((DWORD)pPEB->ImageBaseAddress + 
				descriptor.FirstThunk + (dwOffset * sizeof(IMAGE_THUNK_DATA32)));

			// Write IAT
			bSuccess = WriteProcessMemory
			(
				hProcess,
				pAddress,
				&dwHandlerAddress, 
				4, 
				0
			);

			if (!bSuccess)
			{
				printf("Error writing process memory");
				return FALSE;
			}	

			return TRUE;
		}
		else if (!descriptor.Characteristics)
			return FALSE;
	}

	return FALSE;
}