62.网游逆向分析与插件开发-游戏增加自动化助手接口-游戏公告类的C++还原

内容来源于:易道云信息技术研究院VIP课

上一个内容:游戏红字公告功能的逆向分析-CSDN博客

码云地址(master分支):https://gitee.com/dye_your_fingers/sro_-ex.git

码云版本号:0888e34878d9e7dd0acd08ef045184a44c9ef567

代码下载地址,在 SRO_EX 目录下,文件名为:SRO_Ex-游戏公告类的C++还原.zip

链接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg

提取码:q9n5

--来自百度网盘超级会员V4的分享

HOOK引擎,文件名为:黑兔sdk.zip

链接:https://pan.baidu.com/s/1IB-Zs6hi3yU8LC2f-8hIEw

提取码:78h8

--来自百度网盘超级会员V4的分享

以 游戏红字公告功能的逆向分析-CSDN博客它的代码为基础进行修改

根据之前的分析,发现一个新的类,现在有三个函数,848580黑色文字公告函数,844E40红色文字公告函数,844E80游戏聊天框打印文字(公告打印到聊天框)函数,详情看项目里的分析记录.txt文件

效果图:三个公告全部正常弹出

注意的点0x1256E3C这个地址是在游戏全部初始化完才有值的,所以根据现在的hook位置只有自动药水设定按钮才满足条件,之后再找更合适的初始化位置。

GameEx.cpp文件的修改,修改了 GameEx构造函数,ExitGame函数,AutoHelper函数

#include "pch.h"
#include "GameEx.h"
#include "htdHook2.h"
#include "GameProtect.h"
#include "extern_all.h"

extern int client;
extern GameProtect* _protect;
extern unsigned _stdcall GetFunctionAddress(int index);
htd::hook::htdHook2 hooker;

#include <windows.h>
#include<stdio.h>
#include<TlHelp32.h>

/**
  声明要拦截的函数地址
*/
auto h = GetModuleHandle(NULL);
DWORD address = (DWORD)h;
DWORD addRExit = address + 0x88C77E;

size_t 被拦截修改的函数的地址 = (size_t)addRExit;

LONG NTAPI 异常回调(struct _EXCEPTION_POINTERS* Excep)
{
    printf("异常回调1\n");

    /**
      判断出异常的地方是否为 我们修改的地方
    */
    if ((size_t)Excep->ExceptionRecord->ExceptionAddress == 被拦截修改的函数的地址) {

        //const char* szStr = "nei Rong Bei Xiu Gai";
        //*(DWORD*)(Excep->ContextRecord->Esp + 0x8) = (DWORD)szStr;
        //szStr = "biao Ti Bei Xiu Gai";
        //*(DWORD*)(Excep->ContextRecord->Esp + 0xC) = (DWORD)szStr;

        AfxMessageBox(L"游戏退出!");
        DWORD* _esp = (DWORD*)Excep->ContextRecord->Esp;
        DWORD _val = _esp[1];

        if (_val == 0x1035D0C) {
            AfxMessageBox(L"游戏退出2!");
            auto hMuls = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, L"system_seamp");
            if (hMuls) ReleaseSemaphore(hMuls, 1, 0);
            ExitProcess(0);
        }

        Excep->ContextRecord->Eip = *(DWORD *) Excep->ContextRecord->Esp;
        Excep->ContextRecord->Esp += 8;
        return EXCEPTION_CONTINUE_EXECUTION;
    }
    else {
        /**
          防止被其它地方修改了函数地址
        */
        Excep->ContextRecord->Dr0 = 被拦截修改的函数的地址;
        Excep->ContextRecord->Dr7 = 0x405;
        return EXCEPTION_CONTINUE_SEARCH;
    }

}

VOID 设置线程的dr寄存器(HANDLE 线程句柄) {

    printf("设置线程的dr寄存器1\n");
    CONTEXT ctx;
    ctx.ContextFlags = CONTEXT_ALL;
    GetThreadContext(线程句柄, &ctx);
    ctx.Dr0 = 被拦截修改的函数的地址;
    ctx.Dr7 = 0x1;
    SetThreadContext(线程句柄, &ctx);
    printf("设置线程的dr寄存器2\n");
}

VOID 使用dr寄存器拦截修改函数() {
    printf("使用dr寄存器拦截修改函数1\n");
    HANDLE 线程快照句柄 = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetCurrentProcessId());
    if (线程快照句柄 == INVALID_HANDLE_VALUE) {
        printf("线程快照创建失败");
        return;
    }

    THREADENTRY32* 线程结构体 = new THREADENTRY32;
    线程结构体->dwSize = sizeof(THREADENTRY32);

    /**
      Thread32First获取快照中第一个线程
       返回值bool类型
    */
    // Thread32First(线程快照句柄, &线程结构体);

    HANDLE 线程句柄 = NULL;

    printf("使用dr寄存器拦截修改函数2\n");

    /**
      Thread32Next获取线程快照中下一个线程
    */
    while (Thread32Next(线程快照句柄, 线程结构体))
    {
        if (线程结构体->th32OwnerProcessID == GetCurrentProcessId()) {
            printf("使用dr寄存器拦截修改函数3\n");
            线程句柄 = OpenThread(THREAD_ALL_ACCESS, FALSE, 线程结构体->th32ThreadID);
            printf("使用dr寄存器拦截修改函数4\n");
            设置线程的dr寄存器(线程句柄);
            printf("使用dr寄存器拦截修改函数5\n");
            CloseHandle(线程句柄);
        }
    }
}

SRO_String vip_notice;

bool AutoHelper(HOOKREFS2) {
    // 使用通过获取游戏中的sro_string结构
    //auto read = _pgamebase->SRO_Res->ReadTitle((wchar_t*)0xEBC968);
    // 使用自己创建的sro_string结构
    /**
        sro_string str;
        str.Ptitle = L"您还没有开通VIP服务,只能使用普通药水辅助功能,开通VIP可以使用更高级的自动化助手功能!";
        str.lenth = 47;
        str.size = 48 * 2 + 1;
        auto read = &str;
        unsigned* _ecx = (unsigned*)0x1256E3C;
        unsigned readEcx = _ecx[0];
        unsigned _call = 0x848580;
        _asm {
            mov ecx, readEcx
            push read
            call _call
        }
    */
    _pgamebase->Init();
    _pgamebase->SRO_Notice->NetNotice(&vip_notice);
    _pgamebase->SRO_Notice->ChatNotice(vip_notice.wcstr(), 0xFFFF0000);
    _pgamebase->SRO_Notice->NormalNotice(&vip_notice);

    bool vip = false;
    if (vip)return false;
    else return true;
}

bool ExitGame(HOOKREFS2) {
    //AfxMessageBox(L"ExitGame");
    //auto read = _pgamebase->SRO_Res->ReadTitle((wchar_t*)0xEBC968);
    //CString txt;
    //txt.Format(L"------ %s", read->wcstr());
     read->Ptitle = L"自动助手 [VIP] (%s)";
    //*read = L"自动助手 [VIP] (%s)";
    //AfxMessageBox(txt);

    // if (_protect->CheckDebugByNT())AfxMessageBox(L"检测到了DEBUG程序的存在");
	// AfxMessageBox(L"游戏退出2222!");
	DWORD* _esp = (DWORD*)_ESP;
	DWORD _val = _esp[1];

	if (_val == 0x1035D0C) {
		// AfxMessageBox(L"游戏退出!");
		auto hMuls = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, L"system_seamp");
		if (hMuls) ReleaseSemaphore(hMuls, 1, 0);
        client--;
		ExitProcess(0);
	}
	return true;
}

GameEx::GameEx()
{
    vip_notice = L"(自动化助手公告)您还没有海通VIP服务,只能使用普通的药水设定功能,开通VIP后可以享受全自动辅助功能!";
	// AfxMessageBox(L"注册hook!");
	// auto h = GetModuleHandle(NULL);
	// DWORD address = (DWORD)h;
    // DWORD* addRExit = (DWORD*)(address + 0x88C77E);
    /**addRExit = 0;*/
	// CString txt;
    // txt.Format(L"addRExit[0]D:%d,addRExit[0]X:%X,addRExit:%X", addRExit[0], addRExit[0], addRExit);
    // AfxMessageBox(txt);

    // hooker.SetHook((LPVOID)addRExit, 3, ExitGame);
    //AddVectoredExceptionHandler(1, 异常回调);
    //设置线程的dr寄存器(GetCurrentThread());
}

void GameEx::InitInterface()
{
    unsigned addr_cps =  GetFunctionAddress(0);
    hooker.SetHook((LPVOID)(addr_cps + 0x30 - 2), 0x3, ExitGame);
    hooker.SetHook((LPVOID)(addr_cps + 0x51 - 2), 0x3, ExitGame);

    unsigned addr_autohelper = GetFunctionAddress(1);
    hooker.SetHook((LPVOID)(addr_autohelper), 0x03, AutoHelper, (LPVOID)(addr_autohelper + 0x90));
}

新加SRO_String.cpp文件

#include "pch.h"
#include "SRO_String.h"

int SRO_String::stringlength(const wchar_t* str)
{
	for (lenth = 0; str[lenth]; lenth++);
	size = lenth * 2 + 1;
	return size;
}

wchar_t* SRO_String::wcstr()
{
	if (size < 0x8) {
		return title;
	}
	else {
		return Ptitle;
	}
}

SRO_String& SRO_String::operator=(const wchar_t* _txt)
{
	int _size = stringlength(_txt);

	if (_size > 8) {
		Ptitle = (wchar_t*)_txt;
	}
	else {
		memcpy(title, _txt, _size);
	}

	return *this;
}

新加SRO_String.h文件

#pragma once

typedef class SRO_String
{
private:
	int un1;
	union {
		wchar_t title[0x4];
		wchar_t* Ptitle;
	};
	int un2[0x2];

	unsigned lenth;
	unsigned size;
	int stringlength(const wchar_t* str);
public:
	wchar_t* wcstr();
	SRO_String& operator=(const wchar_t* _txt);
}*PSROSTRING;

Res.cpp文件的修改,修改函数的返回值为PSROSTRING类型

#include "pch.h"
#include "Res.h"
// 这里为了给 _ReadTitle 默认值,防止编译不通过
Res::PROC_WCHAR1 Res::_ReadTitle{};
PSROSTRING Res::ReadTitle(wchar_t* index)
{
	/**
		获取按钮文字通过逆向分析,看出是一个thiscall
		在调用获取文字函数时给ecx赋值了,这是典型的thiscall方式
		下方(this->*_ReadTitle)(index)写法翻译成汇编就会是
		mov ecx,this
		mov eax, [ecx+xxx];
		push index
		call eax
		大概就会变成上方四行代码,也就是一个thiscall
		如果穿插汇编代码,会很lou,这样用c++写就很优雅
	*/
	return (this->*_ReadTitle)(index);
}

Res.h文件的修改,新加SRO_String.h文件并使用

#pragma once
#include "SRO_String.h"
// sro_string通过逆向分析,文字获取方式得到的一个结构体
typedef class Res
{
	// 定义一个函数指针
	typedef PSROSTRING(Res::* PROC_WCHAR1)(wchar_t*);
public:
	// 给函数指针声明一个变量
	static PROC_WCHAR1 _ReadTitle;
	// 封装 _ReadTitle 使用时比较好用
	PSROSTRING ReadTitle(wchar_t* index);

}*PRes;

新加Notice类

Notice.h文件

#pragma once
#include "SRO_String.h"
typedef class Notice
{
	typedef void (Notice::* PROC_PSROSTR)(PSROSTRING);
	typedef void (Notice::* PROC_D_PWSTR_D_D)(int, wchar_t*, int, int);
public:
	static PROC_PSROSTR _NormalNotice;
	static PROC_PSROSTR _NetNotice;
	static PROC_D_PWSTR_D_D _ChatNotice;
public:
	void NormalNotice(PSROSTRING _txt);
	void NetNotice(PSROSTRING _txt);
	void ChatNotice(wchar_t* _txt, int color=0xFFFFAEC3, int type1=0x3, int type2=0x1);
}*PNotice;

Notice.cpp文件

#include "pch.h"
#include "Notice.h"

Notice::PROC_PSROSTR Notice::_NormalNotice{};
Notice::PROC_PSROSTR Notice::_NetNotice{};
Notice::PROC_D_PWSTR_D_D Notice::_ChatNotice{};

void Notice::NormalNotice(PSROSTRING _txt)
{
	(this->*_NormalNotice)(_txt);
}

void Notice::NetNotice(PSROSTRING _txt)
{
	(this->*_NetNotice)(_txt);
}

/**
	type1 默认0x3
	type2 默认0x1
*/
void Notice::ChatNotice(wchar_t* _txt, int color, int type1, int type2)
{
	(this->*_ChatNotice)(type1, _txt, color, type2);
}

GameBase.cpp文件的修改,修改Init函数

#include "pch.h"
#include "GameBase.h"

GameBase* _pgamebase;

void GameBase::Init()
{
	unsigned* addrRead = (unsigned*)0x1256E3C;

	SRO_Res = (PRes)0x1036518;
	SRO_Notice = (PNotice)addrRead[0];
	
	InitClassProc(&Res::_ReadTitle, 0x9A46C0);
	InitClassProc(&Notice::_NormalNotice, 0x848580);
	InitClassProc(&Notice::_NetNotice, 0x844E40);
	InitClassProc(&Notice::_ChatNotice, 0x844E80);

}

void GameBase::InitClassProc(LPVOID proc_addr, unsigned value)
{
	unsigned* uWrite = (unsigned*)proc_addr;
	uWrite[0] = value;
}

GameBase::GameBase()
{
	_pgamebase = this;
	// Init();// 初始化机制,完成游戏与我们dll的对接
}

GameBase.h文件的修改,修改了Init函数

#pragma once
#include "Res.h"
#include "Notice.h"

class GameBase
{
	void InitClassProc(LPVOID proc_addr, unsigned value);
public:
	void Init();
	GameBase();
	PRes SRO_Res;
	PNotice SRO_Notice;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/298426.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android Studio 最新版本首次下载和安装以及汉化教程【+第二次安装使用教程】

&#x1f31f;博主领域&#xff1a;嵌入式领域&人工智能&软件开发 前言&#xff1a;本教程详解首次安装和下载最新版本的Android Studio &#xff0c;以及汉化教程。另外详解当第二次下载使用时解决遇到的问题。 目录 1.Android Studio 下载 2.Android Studio 首次…

机器人相关知识

机器人学&#xff08;Robotics) 一些基础概念 位姿 位姿位置姿态 位姿的表示 刚体 刚性物体是一组粒子的集合&#xff0c;其中任意两个粒子之间的距离保持固定&#xff0c;不受物体运动或施加在物体上的力的影响。 “完全不可变形”的物体就是刚体。 刚体位置 刚性连杆 …

qt信号和槽

Qt是一个跨平台的C图形用户界面应用框架 91年奇趣科技开发 pro工程文件介绍 .pro就是工程文件(project)&#xff0c;它是qmake自动生成的用于生产makefile的配置文件 QT core gui //Qt包含的模块greaterThan(QT_MAJOR_VERSION, 4): QT widgets //大于4版本包含…

实时语义分割模型PP-LiteSeg论文解读

paper&#xff1a;PP-LiteSeg: A Superior Real-Time Semantic Segmentation Model official implementation&#xff1a;https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.8/paddleseg/models/pp_liteseg.py 本文的创新点 提出了一种灵活的轻量级解码器&#xf…

OCS2 入门教程(四)- 机器人示例

系列文章目录 前言 OCS2 包含多个机器人示例。我们在此简要讨论每个示例的主要特点。 System State Dim. Input Dim. Constrained Caching Double Integrator 2 1 No No Cartpole 4 1 Yes No Ballbot 10 3 No No Quadrotor 12 4 No No Mobile Manipul…

虾皮一键铺货软件:如何使用一键铺货软件在Shopee平台上上架商品

在如今竞争激烈的电商市场中&#xff0c;卖家们都希望能够快速上架商品&#xff0c;以节省时间和精力&#xff0c;并提高销售效率。而在Shopee&#xff08;虾皮&#xff09;平台上&#xff0c;一键铺货软件成为了许多卖家的首选工具。这些软件不仅可以帮助卖家快速将商品批量上…

Python Asyncio网络编程方法全面解析与实战应用!

更多Python学习内容&#xff1a;ipengtao.com Python的asyncio库是一种强大的异步编程工具&#xff0c;它使得编写高效的网络应用程序变得更加容易。在本文中&#xff0c;我们将深入探讨使用asyncio进行网络编程的方法&#xff0c;包括异步IO、协程、事件循环等方面的内容&…

Android学习(一):Android Studio安装与配置

Android学习&#xff08;一&#xff09;&#xff1a;Android Studio安装与配置 一、安装 下载地址 下载zip文件&#xff0c;免安装。 二、下载资源 启动后&#xff0c;出现该弹框&#xff0c;点击Cancel。 点击Next 默认&#xff0c;点击Next。 点击Next。 点击Finish 开始…

Danil Pristupov Fork(强大而易用的Git客户端) for Mac/Windows

在当今软件开发领域&#xff0c;团队协作和版本控制是非常重要的方面。在这个过程中&#xff0c;Git成为了最受欢迎的版本控制工具之一。然而&#xff0c;对于Git的使用&#xff0c;一个好的客户端是至关重要的。 今天&#xff0c;我们要为大家介绍一款强大而易用的Git客户端—…

大模型迎来“AppStore时刻”,OpenAI给2024的新想象

一夜之间&#xff0c;OpenAI公布了多个重磅消息&#xff0c;引发市场关注。 钛媒体App 1月5日消息&#xff0c;今晨&#xff0c;OpenAI公司向所有GPT开发者们发布一封邮件称&#xff0c;下周将上线自定义的“GPT Store”商店&#xff0c;这有望推动ChatGPT开发者生态不断完善。…

完美版视频网站模板 – 苹果CMS v10大橙子vfed主题

源码下载&#xff1a; https://download.csdn.net/download/m0_66047725/88700504 这次提供的大橙子 vfed 模板 已经完美&#xff0c;只去除了授权验证和正版主题神秘后门&#xff0c;不影响任何功能体验性。主题优化&#xff1a;全站响应式自带主题设置面板自带联盟资源库大全…

Docker nginx容器代理播放m3u8视频文件(HLS)

文章目录 Docker Nginx容器代理播放M3U8文件教程获取Nginx Docker镜像设置Nginx配置文件用 ffmpeg 将 MP4 文件转换成 m3u8 文件运行Docker容器测试M3U8流其他问题我用vlc都能播放http://192.168.121.50/forest4kTest.m3u8和http://192.168.121.50/forest4kTest.mp4&#xff0c…

MediaPipeUnityPlugin(最新版)摇摆拳人脸识别

1、从https://github.com/homuler/MediaPipeUnityPlugin 下载Release Package 目前是MediaPipeUnity.0.12.0.unitypackage 2、导入Unity工程 3、打开Face Detection场景&#xff0c;做一些设置修改 1、打开Bootstrap&#xff0c;图像源改成Video&#xff0c;把Solution拖拽到…

蓝桥杯备赛系列 高精度 acwing版

前言 hello&#xff0c;好久不见。元旦玩过后该收心了&#xff0c;我也倒计时一下蓝桥杯考试时间&#xff0c;大家一起复习&#xff0c;一起登顶。今天讲解高精度算法。 这个算法其实是给学c同学讲的&#xff0c;因为python自带高精度所以不需要&#xff0c;且我讲到所有内容…

STM32_HAL Freertos按键控制LED

设置GPIO引脚 根据电路图&#xff0c;K0为用户按键&#xff0c;连接在PA0引脚&#xff0c;当K0按下时接地&#xff0c;引脚电平低电平。在CubeMX中设置PA0&#xff0c;将IO设置为输入&#xff0c;上拉&#xff08;上拉外部悬空时&#xff0c;引脚为高电平&#xff09;。 添…

物联网云平台源码,Spring Cloud智慧工地源码,建筑施工智能化管理

智慧工地以物联网云平台为核心&#xff0c;基于智慧工地物联网云平台与现场多个子系统的互联&#xff0c;实现现场各类工况数据采集&#xff0c;存储、分析与应用。通过接入智慧工地物联网云平台的多个子系统板块&#xff0c;根据现场管理实际需求灵活组合&#xff0c;实现一体…

Mac Parallels19.1.0 Install CentOS7.9

0、资源准备 # centos7.9镜像一份 链接: https://pan.baidu.com/s/1acIjUnsTGhk_2cYCZLSoGg?pwd6666 提取码: 6666 --来自百度网盘超级会员v7的分享1、打开PD 2、选择镜像进行安装 指定镜像名称 创建 进行密码设置 安装目的地点开后直接点击完成 网络和主机名称 开…

cad快速看图软件免费版(手机在线cad快速看图)

cad快速看图软件免费版(手机在线cad快速看图) 很多机械设计师日常工作过程中涉及到多种格式的cad图纸&#xff0c;cad图纸大多都需要cad设计软件才能打开&#xff0c;然而很多小伙伴并没有下载相应的cad设计软件&#xff0c;这种情况下如何进行cad快速看图呢&#xff1f; 今天…

【开源项目】WPF 扩展组件 -- Com.Gitusme.Net.Extensiones.Wpf

一、项目简介 Com.Gitusme.Net.Extensiones.Wpf 是一款 Wpf 扩展组件。基于.Net Core 3.1 开发&#xff0c;当前最新 1.0.1 版本。包含 核心扩展库&#xff08;Com.Gitusme.Net.Extensiones.Core&#xff09;、视频渲染&#xff08;Com.Gitusme.Media.Video&#xff09;、串口…

刚学C/C++,使用的是CLion,想要在同一个项目里面运行多个相互独立脚本?

前言&#xff1a; 正常来说&#xff0c;一般一个项目只会有一个程序入口点。C和C程序的入口点是main函数。在一个项目中&#xff0c;只能有一个main函数&#xff0c;否则编译器会不知道从哪个main函数开始执行。 但是&#xff0c;作为初学者&#xff0c;我就是想用CLio…