Visual Studio 2013 如何使用TitanEngine引擎库调试

前文已详细讲解泰坦引擎的编译生成方法,本章将进阶实操泰坦引擎应用开发,聚焦零基础实现C++调用泰坦引擎、进程附加分析核心能力。本文基于静态链接库模式编译生成的TitanEngine.lib库,搭配官方TitanEngine.h头文件完成环境配置,以打印PE节表信息为实战案例,手把手讲解C++接入泰坦引擎、实现简单进程附加分析的完整流程,补齐泰坦引擎从编译搭建到功能落地的实操教程,帮助开发者快速掌握引擎调用与基础逆向分析技巧。

使用静态链接库模式编译泰坦引擎,然后会生成TitanEngine.lib库,此时下载TitanEngine-2025.08.18.zip文件,并提取出内部的TitanEngine.h文件,将其直接放入到我们自定义的文件夹内,这里的文件夹如下所示。

打开Visual Studio 2013 新建控制台项目,并引入头文件及库文件。

接着在代码生成部分,修改运行库为多线程MT模式,保存。

导入泰坦引擎,并使用如下代码测试

c 复制代码
#include <iostream>
#include <cstring>
#include <windows.h>
#include <TitanEngine.h>

#pragma comment(lib,"TitanEngine.lib")
#pragma comment(lib, "ntdll.lib")
#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "dbghelp.lib")
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "distorm.lib")

// OEP入口断点标准回调
void __stdcall OEP_Callback()
{
	printf("==================== 命中程序原始入口OEP ====================\n");

	ULONG_PTR entryRipEip = GetContextData(UE_CIP);
	ULONG_PTR eax = GetContextData(UE_EAX);
	ULONG_PTR ebx = GetContextData(UE_EBX);
	ULONG_PTR ecx = GetContextData(UE_ECX);
	ULONG_PTR edx = GetContextData(UE_EDX);
	printf("EAX=0x%08X | EBX=0x%08X | ECX=0x%08X | EDX=0x%08X\n", eax, ebx, ecx, edx);

	const char* disasmText = (const char*)Disassemble((LPVOID)entryRipEip);
	printf("入口指令:%s\n\n", disasmText);

	// 获取进程信息结构体
	PROCESS_INFORMATION* procInfo = (PROCESS_INFORMATION*)TitanGetProcessInformation();

	// 静态读取镜像基址
	const char targetExe[] = R"(e://win32.exe)";
	ULONG_PTR moduleBase = GetPE32Data(targetExe, 0, UE_IMAGEBASE);
	printf("进程句柄: %p 模块基址:0x%08X\n", procInfo->hProcess, moduleBase);

	// 读取入口附近内存
	unsigned char buf[16] = { 0 };
	SIZE_T readLen = 0;
	bool readOk = MemoryReadSafe(procInfo->hProcess, (LPVOID)entryRipEip, buf, 16, &readLen);
	if (readOk)
	{
		printf("入口附近16字节: ");
		for (int i = 0; i < 16; i++)
			printf("%02X ", buf[i]);
		printf("\n");
	}

	printf("\n分析完成,停止调试\n");
	StopDebug();
}

// 静态读取并打印PE基础信息
void PrintPEInfo(const char* filePath)
{
	printf("========= 读取PE基础信息 =========\n");
	ULONG_PTR imageBase = GetPE32Data(filePath, 0, UE_IMAGEBASE);
	ULONG_PTR oepRva = GetPE32Data(filePath, 0, UE_OEP);
	ULONG_PTR sizeImage = GetPE32Data(filePath, 0, UE_SIZEOFIMAGE);
	ULONG sectionCount = GetPE32Data(filePath, 0, UE_SECTIONNUMBER);
	ULONG checkSum = GetPE32Data(filePath, 0, UE_CHECKSUM);

	printf("镜像基址 ImageBase: 0x%08X\n", imageBase);
	printf("原始入口RVA OEP: 0x%08X  真实入口VA:0x%08X\n", oepRva, imageBase + oepRva);
	printf("镜像总大小 SizeOfImage: 0x%08X\n", sizeImage);
	printf("节区数量 SectionCount: %lu\n", sectionCount);
	printf("PE头校验和 CheckSum: 0x%08X\n\n");
}

// 打印全部节表信息
void PrintAllSections(const char* filePath)
{
	printf("==================== PE 全部节表信息 ====================\n");
	// 获取节总数
	ULONG sectionTotal = (ULONG)GetPE32Data(filePath, 0, UE_SECTIONNUMBER);
	if (sectionTotal == 0)
	{
		printf("未读取到任何节信息!\n");
		return;
	}
	printf("节总数:%u\n\n", sectionTotal);
	printf("节名\t虚拟偏移RVA\t虚拟大小\t文件偏移\t原始大小\t节标志(0x)\n");
	printf("------------------------------------------------------------------------\n");

	// 循环读取每一节信息
	for (DWORD i = 0; i < sectionTotal; i++)
	{
		// 节名称(字符串指针)
		char* szSecName = (char*)GetPE32Data(filePath, i, UE_SECTIONNAME);
		// 虚拟偏移 RVA
		ULONG_PTR secRva = GetPE32Data(filePath, i, UE_SECTIONVIRTUALOFFSET);
		// 虚拟大小
		ULONG_PTR secVirSize = GetPE32Data(filePath, i, UE_SECTIONVIRTUALSIZE);
		// 文件原始偏移
		ULONG_PTR secRawOff = GetPE32Data(filePath, i, UE_SECTIONRAWOFFSET);
		// 文件原始大小
		ULONG_PTR secRawSize = GetPE32Data(filePath, i, UE_SECTIONRAWSIZE);
		// 节权限标志
		ULONG_PTR secFlags = GetPE32Data(filePath, i, UE_SECTIONFLAGS);

		printf("%-8s\t0x%08llX\t0x%08llX\t0x%08llX\t0x%08llX\t0x%08llX\n",
			szSecName, secRva, secVirSize, secRawOff, secRawSize, secFlags);
	}
	printf("========================================================================\n\n");
}

int main()
{
	const char targetExe[] = R"(e://win32.exe)";

	// 关闭PE加载弹窗报错
	SetErrorModel(FALSE);

	PrintPEInfo(targetExe);
	PrintAllSections(targetExe);

	LPVOID procInfoRaw = InitDebugEx(targetExe, "", ".", OEP_Callback);
	if (procInfoRaw == nullptr)
	{
		printf("错误:InitDebugEx 创建调试进程失败!\n");
		system("pause");
		return -1;
	}

	printf("调试进程创建成功,等待执行至入口点...\n");

	// 阻塞调试主循环
	DebugLoop();

	printf("\n全部分析流程结束\n");
	system("pause");
	return 0;
}

编译将通过,并能够正确读取出特定内存信息,泰坦引擎的调用就是如此简单。