////////////////////////////////////////////////////////////////////////////
////////////////////////      此为自写劫持补丁    //////////////////////////
////////////////////////        方法大杂烩        //////////////////////////
////////////////////////       拿来即可使用       //////////////////////////
////////////////////////    硬件断点、软件断点    //////////////////////////
////////////////////////    内存读取、字符转换    //////////////////////////
////////////////////////    加强版内存数据写入    //////////////////////////
////////////////////////    加强内存特征码搜索    //////////////////////////
////////////////////////     可搜索堆内存数据     //////////////////////////
////////////////////////    所有方法已详细注释    //////////////////////////
////////////////////////     如使用请保留出处     //////////////////////////
////////////////////////////////////////////////////////////////////////////

#include <Windows.h>
#include <locale.h>
#include <string>
#include <vector>

//调试输出总开关
//#define MYPRINT
//使用控制台输出，注释掉使用OutputDebugString输出
//#define DBGPRINT

//#ifdef _WIN64
//#pragma comment (lib,"HijackTingMix/dll/Release/HijackTingMix_x64.lib")
//#else
//#pragma comment (lib,"HijackTingMix/dll/Release/HijackTingMix_x86.lib")
//#endif

#ifdef _WIN64
#ifdef _DEBUG
#pragma comment (lib,"HijackTingMix/lib/Debug/MDd/HijackTingMix_x64.lib")
#else
#pragma comment (lib,"HijackTingMix/lib/Release/MD/HijackTingMix_x64.lib")
#endif
#else
#ifdef _DEBUG
#pragma comment (lib,"HijackTingMix/lib/Debug/MDd/HijackTingMix_x86.lib")
#else
#pragma comment (lib,"HijackTingMix/lib/Release/MD/HijackTingMix_x86.lib")
#endif
#endif

// 调用：((PEFLAGS)&ExceptionInfo->ContextRecord->EFlags)->ZF = 1;  //ZF标志位使用
typedef struct
{
	unsigned CF : 1;       //进位或错位
	unsigned Reserve1 : 1;
	unsigned PF : 1;       //计算结果低位包含偶数个1时，此标志为1
	unsigned Reserve2 : 1;
	unsigned AF : 1;       //辅助进位标志，当位3处有进位或借位标志时该标志为1
	unsigned Reserve3 : 1;
	unsigned ZF : 1;       //计算结果为0时，此标志为1
	unsigned SF : 1;       //符号标志，计算结果为负时该标志为1
	unsigned TF : 1;       //陷阱标志，此标志为1时，CPU每次仅会执行1条命令
	unsigned IF : 1;       //中断标志，为0时禁止响应（屏蔽中断），为1时恢复
	unsigned DF : 1;       //方向标志
	unsigned OF : 1;       //溢出标志，计算结果超出机器所表达范围时为1,否则为0
	unsigned IOPL : 2;       //用于标明当前任务的I/O特权级
	unsigned NT : 1;       //任务嵌套标志
	unsigned Reserve4 : 1;
	unsigned RF : 1;       //调试异常相应控制标志位，为1禁止响应指令断点异常
	unsigned VM : 1;       //为1时启用虚拟8086模式
	unsigned AC : 1;       //内存对齐检查标志
	unsigned VIF : 1;       //虚拟中断标志
	unsigned VIP : 1;       //虚拟中断标志
	unsigned ID : 1;       //CPUID检查标志
	unsigned reserved5 : 10; // 22-31
#ifdef AMD64
	unsigned reserved6 : 8;
	unsigned reserved7 : 8;
	unsigned reserved8 : 8;
	unsigned reserved9 : 8;
#endif
} EFLAGS, * PEFLAGS;

enum HWBP_TYPE
{
	TYPE_EXECUTE = 0,    //00  执行
	TYPE_WRITE = 1,      //01  写
	TYPE_READWRITE = 3   //11  读/写
};

enum HWBP_SIZE
{
	SIZE_1 = 0,         //00
	SIZE_2 = 1,         //01
	SIZE_8 = 2,         //10
	SIZE_4 = 3          //11
};

#ifdef __cplusplus
extern "C" {
#endif
	/************************************************************************
	函数名称: CustomNtFunction，InitHookFunction，GetFunctionAddressByName
	函数功能: 通过函数名获取ntdll函数地址，避免被hook
	输入参数: functionName  函数名
	返    回: 函数地址
	调    用: GetFunctionAddressByName("ZwProtectVirtualMemory");
	/************************************************************************/
	ULONG_PTR CustomNtFunction(const char* functionName);
	ULONG_PTR InitHookNtFunction(const char* functionName);
	ULONG_PTR GetFunctionAddressByName(const char* functionName);

	/************************************************************************
	函数名称: SetHwBreakpoint
	函数功能: 设置线程硬件断点
	输入参数: ThreadId 线程ID，0为所有线程下断，否则指定线程下断
			  Type:    参考 enum HWBP_TYPE
			  Size:    参考 enum HWBP_SIZE
			  bpAddr   断点位置
	返    回: 当前断点位置
	调    用: SetHwBreakpoint(GetCurrentThreadId(), TYPE_EXECUTE, SIZE_1, bpAddr);
	/************************************************************************/
	ULONG_PTR SetHwBreakpoint(int ThreadId, HWBP_TYPE Type, HWBP_SIZE Size, ULONG_PTR dwAddr);

	/************************************************************************
	函数名称: DelHwBreakpoint
	函数功能: 删除硬件断点
	输入参数: context  PCONTEXT指针：ExceptionInfo->ContextRecord
			  dwAddr   断点地址：0x123456
	返    回: 成功返回ture，否则返回false
	调    用: DelHwBreakpoint(ExceptionInfo->ContextRecord, 0x123456);
	/************************************************************************/
	bool DelHwBreakpoint(PCONTEXT context, ULONG_PTR dwAddr);

	/*************************************************************************************
	函数名称: PatternFindEx
	函数功能: 通用特征码搜索 根据CPU自动选择Sunday、SSE2、AVX2进行搜索
	输入参数: resultList   保存搜索结果的集合
			  hProcess   进程句柄 HANDLE hProcess = GetCurrentProcess();
			  module     0或者NULL全进程搜索（支持堆内存），否则搜索模块 HMODULE hModule = GetModuleHandle(L"模块名称");
			  pattern    搜索特征码，支持通配符??或8?或?8 格式为：std::string pattern = "?5 ?? 77 ?8 ?? AA BB";
			  searchNum  搜索个数，0为搜索整个模块
	返    回: 找到地址的集合
	调    用: std::vector<ULONG_PTR> resultList，PatternFindEx(resultList，hProcess, hModule, pattern, 10, 0);
	*************************************************************************************/
	bool PatternFindEx(std::vector<ULONG_PTR>& resultList, HANDLE hProcess, HMODULE module, std::string pattern, ULONG_PTR searchNum);
	bool SundayPatternFind(std::vector<ULONG_PTR>& resultList, HANDLE hProcess, ULONG_PTR startAddress, ULONG_PTR endAddress, std::string pattern, int searchNum);
	bool SSE2PatternFind(std::vector<ULONG_PTR>& resultList, HANDLE hProcess, ULONG_PTR startAddress, ULONG_PTR endAddress, std::string pattern, int searchNum);

	/***********************************************************************
	函数名称: WriteMemoryData WriteMemoryDataEx支持加壳程序不允许修改内存
	函数功能: 替换内存中的字符
	输入参数: memAddress 内存地址 ULONG_PTR memAddress = 0x7C5C;
			  hexData 替换数据 std::string hexData = "55 ?? 77 88 ?? AA BB"; 可用通配符
	返    回: 替换成功返回首字节(可用于int3断点首字节恢复)，否则返回""
	调    用: std::string returnStr = "";设置int3断点 returnStr = WriteMemoryData(bp,"CC");
			  returnStr = WriteMemoryData(memAddress, replaceData);
			  unicode编码的内容用"0000"截断，Ansi编码的内容用"00"截断，replaceData + "0000"
	***********************************************************************/
	std::string WriteMemoryData(ULONG_PTR memAddress, std::string hexData);
	std::string WriteMemoryDataEx(ULONG_PTR memAddress, std::string hexData);

	/***********************************************************************
	函数名称: ReadMemoryData
	函数功能: 读取内存中的字符串
	输入参数: memAddress 内存地址
			  unicode 编码，默认为unicode,否则其它
	返    回: 成功返回字符串，否则为""
	调    用: ULONG_PTR memAddress = 0x7C5C;
			  std::string result = "";
			  result = ReadMemoryData(memAddress);
			  #include <string>   #include <windows.h>
			  32位内存地址计算：*(int*)(breakpoint + 1)
			  64位内存地址计算：*(int*)(breakpoint + 3) + breakpoint + 7
	***********************************************************************/
	std::string ReadMemoryData(ULONG_PTR memAddress, bool unicode);

	/***********************************************************************
	函数名称: HexToAnsiString
	函数功能: 十六进制字符串转换为askii字符串
	输入参数: hex 十六进制字符串
	返    回: 成功返回字符串
	调    用: std::string hex_str = "D7A2B2E1";或者std::string hex_str = "D7 A2 B2 E1";
			  std::string result = "";
			  result = HexToAnsiString(hex_str);  返回：注册
			  #include <string>
	***********************************************************************/
	std::string HexToAnsiString(std::string hex);

	/***********************************************************************
	函数名称: AnsiStringToHex
	函数功能: ascii字符串转换为十六进制字符串
	输入参数: str 字符串
	返    回: 成功返回十六进制字符串
	调    用: std::string ascii_str = "注册";
			  std::string result = "";
			  result = AnsiStringToHex(ascii_str);  返回：D7A2B2E1
			  #include <string>
	***********************************************************************/
	std::string AnsiStringToHex(std::string str);

	/***********************************************************************
	函数名称: HexToUnicodeString
	函数功能: 十六进制字符串转换为Unicode字符串
	输入参数: hex 十六进制字符串
	返    回: 成功返回字符串
	调    用: std::string hex_str = "E86C8C51";或者std::string hex_str = "E8 6C 8C 51";
			  std::string result = "";
			  result = HexToUnicodeString(hex_str);
			  #include <string>  #include <windows.h>
	***********************************************************************/
	std::string HexToUnicodeString(std::string hex);

	/***********************************************************************
	函数名称: UnicodeStringToHex
	函数功能: Unicode字符串转换为十六进制字符串
	输入参数: str 字符串
	返    回: 成功返回十六进制字符串
	调    用: std::wstring unicode_str = L"注册";
			  std::string result = "";
			  result = UnicodeStringToHex(unicode_str);  返回：E86C8C51
			  #include <string>
	***********************************************************************/
	std::string UnicodeStringToHex(std::wstring str);

	/***********************************************************************
	函数名称: string2wstring
	函数功能: 单字符串转为宽字符串
	输入参数: str 单字符串
	返    回: 成功返回宽字符串
	调    用: std::wstring wstr = string2wstring("注册");
	***********************************************************************/
	std::wstring string2wstring(std::string str);

	/***********************************************************************
	函数名称: wstring2string
	函数功能: 宽字符串转为单字符串
	输入参数: wstr 宽字符串
	返    回: 成功返回单字符串
	调    用: std::string str = wstring2string(L"注册");
	***********************************************************************/
	std::string wstring2string(std::wstring wstr);

	/***********************************************************************
	函数名称: SplitString
	函数功能: 字符串分割
	输入参数: vectorStr 保存分割的集合
			  sourceStr 源字符串
			  splitSymbol 分割字符
	返    回: 成功返回分割好的集合
	调    用: std::vector<std::string> vec; SplitString(vec, "001=225=77865=38", "=");
	***********************************************************************/
	bool SplitString(std::vector<std::string>& vectorStr, std::string sourceStr, std::string splitSymbol);

	/***********************************************************************
	函数名称: HexToString
	函数功能: 十六进制转字符串
	输入参数: hexValue 十六进制 0xFF
	返    回: 成功返回字符串
	调    用: std::string str = HexToString(0xFF);
	***********************************************************************/
	std::string HexToString(BYTE hexValue);

	/***********************************************************************
	函数名称: VAToFOA
	函数功能: VA虚拟地址转FOA文件偏移位置
	输入参数: hModule 模块
			  dwVA VA虚拟地址
	返    回: 成功返回文件偏移位置
	调    用: HMODULE hModule = GetModuleHandle(L"模块名称");或者LoadLibrary(L"模块名称");
			  ULONG_PTR address = VAToFOA(hModule, 0x123456);
	***********************************************************************/
	ULONG_PTR VAToFOA(HMODULE hModule, ULONG_PTR dwVA);

	/***********************************************************************
	函数名称: FOAToVA
	函数功能: FOA文件偏移位置转VA虚拟地址
	输入参数: hModule 模块
			  dwFOA FOA文件偏移位置
	返    回: 成功返回模块虚拟地址
	调    用: HMODULE hModule = GetModuleHandle(L"模块名称");或者LoadLibrary(L"模块名称");
			  ULONG_PTR address = FOAToVA(hModule, 0x123456);
	***********************************************************************/
	ULONG_PTR FOAToVA(HMODULE hModule, ULONG_PTR dwFOA);

	/***********************************************************************
	函数名称: IsContains
	函数功能: 字符串包含某个字符
	输入参数: sourceStr 源字符串
			  findStr 要查找的字符串
	返    回: 成功返回查找到包含字符串
	调    用: bool isContains = IsContains("content", "ten");
	***********************************************************************/
	bool IsContains(std::string sourceStr, std::string findStr);
#ifdef __cplusplus
}
#endif

/***********************************************************************
函数名称: MyPrintf
函数功能: 调试输出
输入参数: 与 printf 类似
调    用: MyPrintf("%d,%s",123,"hello");
***********************************************************************/
#ifdef _UNICODE
#define MyPrintf MyPrintfW
#else
#define MyPrintf MyPrintfA
#endif
// 调试输出
BOOL isdbgprint = false;
BOOL InitConsoleWindow()
{
	FILE* pfile;
	BOOL ret = AllocConsole();
	if (ret)
	{
		//HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
		SetConsoleTitleA("Debug Output");
		setlocale(LC_ALL, "chs");
		freopen_s(&pfile, "CONOUT$", "w+t", stdout);
		freopen_s(&pfile, "CONOUT$", "w+t", stderr);
		freopen_s(&pfile, "CONIN$", "r+t", stdin);
	}
	return ret;
}
//MyOutputDebugStringA("%d,%s",123,"hello");
void MyPrintfA(const char* szOutputString, ...)
{
#ifdef MYPRINT
#ifdef DBGPRINT
	if (!isdbgprint)
	{
		isdbgprint = InitConsoleWindow();
	}
	va_list vlArgs;
	va_start(vlArgs, szOutputString);
	vprintf(szOutputString, vlArgs);
	va_end(vlArgs);
#else
	char szBuffer[4096] = { 0 };
	va_list vlArgs;
	va_start(vlArgs, szOutputString);
	_vsnprintf_s(szBuffer, sizeof(szBuffer) - 1, szOutputString, vlArgs);
	//vsprintf(szBuffer,szOutputString,vlArgs);
	va_end(vlArgs);
	char szPrint[4096] = { 0 };
	strcpy_s(szPrint, szBuffer);
	OutputDebugStringA(szPrint);
#endif
#endif
}
//MyOutputDebugStringW(L"%d,%s",456,L"world!");
void MyPrintfW(const wchar_t* szOutputString, ...)
{
#ifdef MYPRINT
#ifdef DBGPRINT
	if (!isdbgprint)
	{
		isdbgprint = InitConsoleWindow();
	}
	va_list vlArgs;
	va_start(vlArgs, szOutputString);
	vwprintf(szOutputString, vlArgs);
	va_end(vlArgs);
#else
	wchar_t szBuffer[4096] = { 0 };
	va_list vlArgs;
	va_start(vlArgs, szOutputString);
	_vsnwprintf_s(szBuffer, sizeof(szBuffer) - 2, szOutputString, vlArgs);
	//vswprintf(szBuffer,szOutputString,vlArgs);
	va_end(vlArgs);
	wchar_t szPrint[4096] = { 0 };
	wcscpy_s(szPrint, szBuffer);
	OutputDebugStringW(szPrint);
#endif
#endif
}
