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

本次游戏没法给

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

上一个内容: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();

};