36.第二阶段x64游戏实战-代码实现劫持网络数据包(封包)

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!

本次游戏没法给

内容参考于:微尘网络安全

上一个内容:35.x64汇编写法(二)

效果图:

首先打开之前的项目,然后添加一个类

名字叫Hook

然后把它俩拖到通用里面

然后Hook.h文件写下图红框的内容

然后StartData.h文件里面下图红框里的代码

然后StartData.cpp文件添加下图红框的代码,这样就可以全局使用Hook了

要Hook的位置地址

ws2_32.dll的基址

偏移0x00007FFE95F0740F - 0x00007FFE95F00000 = 0x740F

然后在 InitInstance 函数中获取

然后g_HookAddress的初始化

然后g_HookAddress的声明

然后Hook.cpp里

然后添加一个asm

然后 ASMCall.asm

然后添加 ASMCall.asm 后设置依赖项

然后勾选

然后设置 ASMCall.asm 属性

然后属性选择下图红框

HookCall函数

ASMCall.asm文件的内容

extern g_Calladdr:far
extern g_mingwenaddr:far
extern g_size:far
.code


	HookCall proc

		mov qword ptr[g_mingwenaddr],rdx ;明文包数据
		mov qword ptr[g_size],r8 ; 明文包大小


		push rax
		push rbx
		push rcx
		push rdx
		push rsi
		push rdi
		push r8
		push r9
		push r10
		push r11
		push r12
		push r13
		push r14
		push r15

		mov r15,qword ptr[g_Calladdr];用来调试输出的call,也就是执行 Hook.cpp 里的OutPutcall函数
		call r15

		pop r15
		pop r14
		pop r13
		pop r12
		pop r11
		pop r10
		pop r9
		pop r8
		pop rdi
		pop rsi
		pop rdx
		pop rcx
		pop rbx
		pop rax

		; 跳转回去
		mov rax,qword ptr [rsp]
		add rsp,8

		; 执行被劫持位置的原本代码
		push rdi
		push r14
		push r15
		sub rsp,80h

		jmp rax



	HookCall endp


end

然后添加一个按钮

按钮名字

然后双击按钮创建 鼠标左键单击时执行的函数

劫持后(Hook后)使用x64dbg查看代码情况,注意x64dbg代码不是实时的,就是修改之后在x64dbg看到的还是原来的代码,需要设置一下断点,触发断点才可以显示最新的代码,有时候只设置一下断点它就会更新

获取明文包和把明文放到 vector 里(g_Calladdr)

代码逻辑说明

首先点击 hook明文包按钮

触发下图红框的函数

然后又触发,劫持数据包函数和打印数据包函数

然后劫持数据包函数触发 HookCall函数(汇编代码)

HookCall汇编代码,又触发把数据包放到 vector 里逻辑

OutPutcall 把数据包放到 vector 里逻辑,到这数据包的获取就结束了,然后在看定时器

下图红框位置设置每500毫秒触发定时器

定时器代码,读取 pData->m_Pack.p_data

MyDialog.cpp文件的修改:修改 OnTimer函数,新加 OnBnClickedButton5函数(hook明文包按钮)

void MyDialog::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (nIDEvent == 1) {
		Role_Stu Role = pData->Updata_Role(0);//更新角色
		CString str;
		str.Format("角色对象:%p\n角色名字:%s\n角色等级:%d\n角色状态:%d\n角色的ID:%d\n角色血量:%d/%d\n角色蓝量:%d/%d\n角色活力:%d/%d\n角色精力:%d/%d\n角色经验:%d/%d\n角色坐标 x:%f  z:%f  y:%f\n角色体力:%d\n角色定力:%d\n角色身法:%d\n角色潜能:%d\n角色力量:%d\n角色灵气:%d\n外功攻击:%d\n内功攻击:%d\n外功防御:%d\n内功防御:%d\n角色命中:%d\n角色闪避:%d\n会心攻击:%d\n会心防御:%d", Role.m_Objadr, Role.m_Name.c_str(), Role.m_Lv, Role.m_State, Role.m_ID, Role.m_HP.min, Role.m_HP.max, Role.m_MP.min, Role.m_MP.max, Role.m_Vitality.min, Role.m_Vitality.max, Role.m_Energy.min, Role.m_Energy.max, Role.m_Exp.min, Role.m_Exp.max, Role.fPos.x, Role.fPos.z, Role.fPos.y, Role.m_PStrength, Role.m_CStrength, Role.m_Footwork, Role.m_Potential, Role.m_power, Role.m_Reiki, Role.m_Out_attack, Role.m_In_attack, Role.m_Out_Defense, Role.m_In_Defense, Role.m_hit, Role.m_dodge, Role.m_HeartAttack, Role.m_HeartDefense);
		SetDlgItemText(IDC_STATIC, str);
	}

	if (nIDEvent == 2)
	{
		VDataStu vt = pData->Updata_Around();//更新数据
		CString str;
		for (size_t i = 0; i < 1000; i++)
		{

			if (vt.m_data.size() <= i) {
				m_list.SetItemText(i, 0, "");
				m_list.SetItemText(i, 1, "");
				m_list.SetItemText(i, 2, "");
				m_list.SetItemText(i, 3, "");
				m_list.SetItemText(i, 4, "");
				m_list.SetItemText(i, 5, "");
			}
			else {
				str.Format("%p", vt.m_data[i].m_Objadr);
				m_list.SetItemText(i, 0, str);
				str.Format("%p", vt.m_data[i].m_ID);
				m_list.SetItemText(i, 1, str);
				str.Format("%s", vt.m_data[i].m_Name.c_str());
				m_list.SetItemText(i, 2, str);
				str.Format("%d", vt.m_data[i].m_HP.ptr);
				m_list.SetItemText(i, 3, str);
				str.Format("%f %f %f", vt.m_data[i].fPos.x, vt.m_data[i].fPos.z, vt.m_data[i].fPos.y);
				m_list.SetItemText(i, 4, str);
				str.Format("%s", vt.m_data[i].type_name.c_str());
				m_list.SetItemText(i, 5, str);

			}

		}
	}

	if (nIDEvent == 3)
	{
		VDataStu* vt = pData->Updata_Backpack();//更新数据
		CString str;

		int m_size = vt[0].m_data.size() + vt[1].m_data.size() + vt[2].m_data.size();
		int j = 0;
		int k = 0;
		for (size_t i = 0; i < 1000; i++)
		{

			if (m_size <= i) {
				m_list.SetItemText(i, 0, "");
				m_list.SetItemText(i, 1, "");
				m_list.SetItemText(i, 2, "");
				m_list.SetItemText(i, 3, "");
				m_list.SetItemText(i, 4, "");

			}
			else {

				if (i >= vt[0].m_data.size() && i < vt[0].m_data.size() + vt[1].m_data.size()) {
					j = 1;
					k = i - vt[0].m_data.size();
				}
				else
				{
					if (i >= vt[0].m_data.size() + vt[1].m_data.size()) {
						j = 2;
						k = i - vt[0].m_data.size() - vt[1].m_data.size();
						break;
					}
					k = i;
				}


				str.Format("%p", vt[j].m_data[k].m_Objadr);
				m_list.SetItemText(i, 0, str);
				str.Format("%x", vt[j].m_data[k].m_ID);
				m_list.SetItemText(i, 1, str);
				str.Format("%s", vt[j].m_data[k].m_Name.c_str());
				m_list.SetItemText(i, 2, str);
				str.Format("%d", vt[j].m_data[k].m_Lv);
				m_list.SetItemText(i, 3, str);
				str.Format("%s", vt[j].m_data[k].type_name.c_str());
				m_list.SetItemText(i, 4, str);


			}

		}

	}

	if (nIDEvent == 4)
	{
		VDataStu vt = pData->Updata_Skill();//更新数据

		QWORD addrs = 0;


		CString str;
		for (size_t i = 0; i < 1000; i++)
		{

			if (vt.m_data.size() <= i) {
				m_list.SetItemText(i, 0, "");
				m_list.SetItemText(i, 1, "");
				m_list.SetItemText(i, 2, "");
				m_list.SetItemText(i, 3, "");
				m_list.SetItemText(i, 4, "");

			}
			else {
				str.Format("%p", vt.m_data[i].m_Objadr);
				m_list.SetItemText(i, 0, str);
				str.Format("%p", vt.m_data[i].m_ID);
				m_list.SetItemText(i, 1, str);
				str.Format("%s", vt.m_data[i].m_Name.c_str());
				m_list.SetItemText(i, 2, str);
				str.Format("%d", vt.m_data[i].m_Lv);
				m_list.SetItemText(i, 3, str);
				str.Format("%d", vt.m_data[i].Countdown);
				m_list.SetItemText(i, 4, str);

			}

		}
	}

	if (nIDEvent == 5)
	{
		CStringA str;
		int m_size = pData->m_Pack.p_data.size();
		str.Format("调试--m_size %d  p_size %d", m_size, p_size);
	
		if (m_size > p_size) {
		
			//m_list.DeleteAllItems();
			for (size_t i = 0; i < (m_size - p_size); i++)
			{
				LogA(str.GetBuffer());
				m_list.InsertItem(i, "");

				str.Format("%x", pData->m_Pack.p_data[i + p_size].Pack_long);
				m_list.SetItemText(i, 0, str);
				str.Format("%s", pData->m_Pack.p_data[i + p_size].Pack.c_str());
				m_list.SetItemText(i, 1, str);
				int nItemCount = m_list.GetItemCount();
				int nLastIndex = nItemCount - 1;
				m_list.EnsureVisible(nLastIndex, FALSE);
			}
			p_size = m_size;

		}

	}

	CDialogEx::OnTimer(nIDEvent);
}

void MyDialog::OnBnClickedButton5()// hook明文包按钮
{
	CString str;
	CString str1;
	GetDlgItemText(IDC_BUTTON5, str);
	str1 = "Hook明文包";
	if (str == str1) {
		str = "还原明文包";
		SetDlgItemText(IDC_BUTTON5, str);
		for (size_t i = 0; i < 6; i++)
		{
			m_list.DeleteColumn(0);//清空标题

		}

		m_list.DeleteAllItems();//清空所有行



		/*插入标题列*/
		CString head[] = { TEXT("包长"),TEXT("包内容") };

		m_list.InsertColumn(0, head[0], LVCFMT_CENTER, 50, NULL);
		m_list.InsertColumn(1, head[1], LVCFMT_LEFT, 800, NULL);




		pMsg->HookBegin();

		SetTimer(5, 500, NULL);
	}
	else {
		KillTimer(5);
		pMsg->HookEnd();
		SetDlgItemText(IDC_BUTTON5, str1);
	}
}

Hook.cpp文件的内容

#include "pch.h"

extern "C" UINT64 HookCall;
extern "C" UINT64 g_mingwenaddr = 0; // 明文包数据
extern "C" UINT64 g_size = 0; // 明文包大小
extern "C" UINT64 g_Calladdr = (UINT64)&OutPutcall;
void CMessage::HookBegin()// hook代码
{
	/**
		0x48 0xB8的汇编代码是 mov rax,0
		0xFF, 0xD0的汇编代码是 call rax
		ff d0
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 这些是要跳转的内存地址,也就是之前说的send位置
	*/
	char HookText[0xc] = { 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0 };// 把游戏代码修改成为跳转到 asm

	QWORD a = (QWORD)&HookCall; // HookCall 是劫持之后执行的函数地址

	memcpy_s(&HookText[2], 8, &a, 8);// 把 HookCall 地址写到跳转里

	DWORD old = 0;

	MessageBeep(1);

	// 修改内存属性为可读可写可执行
	VirtualProtect((LPVOID)g_HookAddress, 0x100, PAGE_EXECUTE_READWRITE, &old);

	// g_HookAddress这个是 (QWORD)GetModuleHandle("ws2_32.dll") + 0x740F; 被劫持的位置
	// 通过 memcpy_s 把被劫持位置的代码写成 HookText,也就是
	// mov rax, &HookCall
	// push rax
	memcpy_s((LPVOID)g_HookAddress, 0xc, HookText, 0xc);

	// 还原内存属性
	VirtualProtect((LPVOID)g_HookAddress, 0x100, old, &old);

}
void CMessage::HookEnd() // 恢复代码
{
	/*
	{ 0x57, 0x41, 0x56, 0x41, 0x57, 0x48, 0x81, 0xEC, 0x80, 0x00, 0x00, 0x00 }的代码
		57                          | push rdi    
		41:56                       | push r14    
		41:57                       | push r15    
		48:81EC 80000000            | sub rsp,80  
	也就是劫持之前的代码,原本的代码
	*/
	BYTE old_CallCode[0xc] = { 0x57, 0x41, 0x56, 0x41, 0x57, 0x48, 0x81, 0xEC, 0x80, 0x00, 0x00, 0x00 };
	DWORD old = 0; //{0x57, 0x41, 0x56, 0x41, 0x57, 0x48, 0x81, 0xEC, 0x80, 0x00, 0x00, 0x00};
	VirtualProtect((LPVOID)g_HookAddress, 0x100, PAGE_EXECUTE_READWRITE, &old);
	memcpy_s((LPVOID)g_HookAddress, 0xc, &old_CallCode, 0xc);
	VirtualProtect((LPVOID)g_HookAddress, 0x100, old, &old);

}
void  OutPutcall() { // 把数据包放到 vector 里,然后就能显示到界面上了

	/**
		g_mingwenaddr 和 g_size 是从 ASMCall.asm 里的 HookCall 函数得到的
		g_mingwenaddr数据包内容
		g_size数据包大小

		ReadByte(g_mingwenaddr) 读取1字节明文内容
		0x9a有点频繁,心跳
		0x53是激活窗口就断的

	*/
	if (ReadByte(g_mingwenaddr) != 0x9a && ReadByte(g_mingwenaddr) != 0x53 && g_size < 0x100) {
		pData->pstu.Pack_long = g_size;
		pData->pstu.char_pack = (char*)g_mingwenaddr;
		// 通用_Byte数组转十六进制字串 显示十六进制的内容
		pData->pstu.Pack = 通用_Byte数组转十六进制字串((unsigned char*)g_mingwenaddr, g_size);
		pData->m_Pack.p_data.push_back(pData->pstu);
		LogA("----------%x----------", g_size);
		// 十六进制打印
		R_memory(g_mingwenaddr, g_size);
		LogA("%s", (char*)pData->pstu.Pack.c_str());

	}
}

Hook.h文件的内容

#pragma once
extern   "C" void OutPutcall();
class CMessage
{
public:

public:
	void HookBegin();
	void HookEnd();
};


img

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值