
// stdafx.cpp : 只包括标准包含文件的源文件
// WeChats.pch 将作为预编译头
// stdafx.obj 将包含预编译类型信息

#include "stdafx.h"


HANDLE DuplicateHandleEx(DWORD pid, HANDLE h, DWORD flags)
{
	HANDLE hHandle = NULL;
	HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
	if(hProc)
	{
		if(!DuplicateHandle(hProc,(HANDLE)h, GetCurrentProcess(),&hHandle, 0, FALSE, flags))
		{
			hHandle = NULL;
		}
	}

	CloseHandle(hProc);
	return hHandle;
}


int GetProcIds(LPTSTR Name, DWORD* Pids)
{
	PROCESSENTRY32 pe32 = {sizeof(pe32)};
	int num = 0;

	HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if(hSnap)
	{
		if(Process32First(hSnap, &pe32))
		{
			do {
				//if(!wcsicmp(Name, pe32.szExeFile))
				if(!_tcsicmp(Name, pe32.szExeFile))
				{
					if(Pids)
					{
						Pids[num++] = pe32.th32ProcessID;
					}
				}
			} while(Process32Next(hSnap, &pe32));
		}
		CloseHandle(hSnap);
	}

	return num;
}

BOOL IsTargetPid(DWORD Pid, DWORD* Pids, int num)
{
	for(int i=0; i<num; i++)
	{
		if(Pid == Pids[i])
		{
			return TRUE;
		}
	}
	return FALSE;
}

int PatchWeChat()
{
	DWORD dwSize = 0;
	POBJECT_NAME_INFORMATION pNameInfo;
	POBJECT_NAME_INFORMATION pNameType;
	PVOID pbuffer = NULL;
	NTSTATUS Status;
	int nIndex = 0;
	DWORD dwFlags = 0;
	char szType[128] = {0};
	char szName[512] = {0};

	DWORD Pids[100] = {0};

	DWORD Num = GetProcIds(_T("WeChat.exe"), Pids);
	if(Num == 0)
	{
		return 0;
	}

	if(!ZwQuerySystemInformation)
	{
		goto Exit0;
	}

	pbuffer = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE);

	if(!pbuffer)
	{
		goto Exit0;
	}

	Status = ZwQuerySystemInformation(SystemHandleInformation, pbuffer, 0x1000, &dwSize);

	if(!NT_SUCCESS(Status))
	{
		if (STATUS_INFO_LENGTH_MISMATCH != Status)
		{
			goto Exit0;
		}
		else
		{
			// 这里大家可以保证程序的正确性使用循环分配稍好
			if (NULL != pbuffer)
			{
				VirtualFree(pbuffer, 0, MEM_RELEASE);
			}

			if (dwSize*2 > 0x4000000)  // MAXSIZE
			{
				goto Exit0;
			}

			pbuffer = VirtualAlloc(NULL, dwSize*2, MEM_COMMIT, PAGE_READWRITE);

			if(!pbuffer)
			{
				goto Exit0;
			}

			Status = ZwQuerySystemInformation(SystemHandleInformation, pbuffer, dwSize*2, NULL);

			if(!NT_SUCCESS(Status))
			{
				goto Exit0;    
			}
		}
	}

	PSYSTEM_HANDLE_INFORMATION1 pHandleInfo = (PSYSTEM_HANDLE_INFORMATION1)pbuffer;

	for(nIndex = 0; nIndex < pHandleInfo->NumberOfHandles; nIndex++)
	{
		if(IsTargetPid(pHandleInfo->Handles[nIndex].UniqueProcessId, Pids, Num))
		{
			//
			HANDLE hHandle = DuplicateHandleEx(pHandleInfo->Handles[nIndex].UniqueProcessId, 
				(HANDLE)pHandleInfo->Handles[nIndex].HandleValue,
				DUPLICATE_SAME_ACCESS
				);
			if(hHandle == NULL) continue;

			Status = NtQueryObject(hHandle, ObjectNameInformation, szName, 512, &dwFlags);

			if (!NT_SUCCESS(Status))
			{
				CloseHandle(hHandle);
				continue;
			}

			Status = NtQueryObject(hHandle, ObjectTypeInformation, szType, 128, &dwFlags);

			if (!NT_SUCCESS(Status))
			{
				CloseHandle(hHandle);
				continue;
			}

			pNameInfo = (POBJECT_NAME_INFORMATION)szName;
			pNameType = (POBJECT_NAME_INFORMATION)szType;

			WCHAR TypName[1024] = {0};
			WCHAR Name[1024] = {0};

			wcsncpy(TypName, (WCHAR*)pNameType->Name.Buffer, pNameType->Name.Length/2);
			wcsncpy(Name, (WCHAR*)pNameInfo->Name.Buffer, pNameInfo->Name.Length/2);

			// 匹配是否为需要关闭的句柄名称
			if (0 == wcscmp(TypName, L"Mutant"))
			{
				//WeChat_aj5r8jpxt_Instance_Identity_Mutex_Name
				//if (wcsstr(Name, L"_WeChat_App_Instance_Identity_Mutex_Name"))
				if (wcsstr(Name, L"_WeChat_") &&
					wcsstr(Name, L"_Instance_Identity_Mutex_Name"))
				{
					CloseHandle(hHandle);

					hHandle = DuplicateHandleEx(pHandleInfo->Handles[nIndex].UniqueProcessId, 
						(HANDLE)pHandleInfo->Handles[nIndex].HandleValue,
						DUPLICATE_CLOSE_SOURCE
						);

					if(hHandle)
					{
						printf("+ Patch wechat success!\n");
						CloseHandle(hHandle);
					}
					else
					{
						printf("- Patch error: %d\n", GetLastError());
					}

					goto Exit0;
				}
			}

			CloseHandle(hHandle);
		}

	}

Exit0:
	if (NULL != pbuffer)
	{
		VirtualFree(pbuffer, 0, MEM_RELEASE);
	}

	return 0;
}
