内容参考于:易道云信息技术研究院VIP课
上一个内容:地图数据获取的逆向分析与C++代码还原
码云地址(游戏窗口化助手 分支):https://gitee.com/dye_your_fingers/sro_-ex.git
码云版本号:e85c0fc8b85895c8c2d3417ec3c75bcad8e7c41d
代码下载地址,在 SRO_EX 目录下,文件名为:SRO_Ex-窗口化助手显示与大小调整.zip
链接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg
提取码:q9n5
--来自百度网盘超级会员V4的分享
HOOK引擎,文件名为:黑兔sdk.zip
链接:https://pan.baidu.com/s/1IB-Zs6hi3yU8LC2f-8hIEw
提取码:78h8
--来自百度网盘超级会员V4的分享
以 地图数据获取的逆向分析与C++代码还原 它的代码为基础进行修改
效果图:点击自动助手之后,窗口化助手会贴于游戏窗口的右边,如果超出屏幕,会贴于游戏窗口右边的里面,窗口化助手目前可以隐藏显示游戏
添加按钮:
GameEx.cpp文件的修改:修改了 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;
bool vip = true;
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();
DWORD* desp = (DWORD*)_ESP;
if (vip) {
_ui_helper->Init();
_ui_helper->Show();
// _ui->UIShow();
return false;
}
else {
if (desp[1] == 1) {
_pgamebase->SRO_Control->NetNotice(&vip_notice);
_pgamebase->SRO_Control->ChatNotice(vip_notice.wcstr(), 0xFFFF0000);
_pgamebase->SRO_Control->NormalNotice(&vip_notice);
}
return true;
}
}
bool ExitGame(HOOKREFS2) {
if (vip) {
_pgamebase->Init();
auto read = _pgamebase->SRO_Res->ReadTitle((wchar_t*)0xEBC968);
*read = L"自动助手 [VIP] (%s)";
}
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));
}
CUI.cpp文件的修改:修改了 UIShow函数
// CUI.cpp: 实现文件
//
#include "pch.h"
#include "htdMfcDll.h"
#include "CUI.h"
#include "afxdialogex.h"
#include "extern_all.h"
// CUI 对话框
IMPLEMENT_DYNAMIC(CUI, CDialogEx)
CUI::CUI(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_MAIN, pParent)
{
}
CUI::~CUI()
{
}
void CUI::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_TAB1, mTab);
}
BOOL CUI::OnInitDialog()
{
CDialogEx::OnInitDialog();
InstallPage(new CUIWnd_0(), IDD_PAGE_0, L"角色", TRUE);
InstallPage(new CUIWnd_1(), IDD_PAGE_1, L"物品");
SetBackgroundColor(0xFFFFFFFF);
//PageINJ.Init(wAppPath);
//PageRAN.SetAppPath(wAppPath);
return TRUE;
}
bool CUI::InstallPage(CDialogEx* wnd, int IDD_WND, CString&& _Name, BOOL IsShow)
{
if (CurPage >= MAX_PAGE_MAIN) return false;
Pages[CurPage] = wnd;
Pages[CurPage]->Create(IDD_WND, this);
//Pages[CurPage]->SetParent(this);
Pages[CurPage]->ShowWindow(IsShow);
CRect rect;
mTab.GetClientRect(&rect);
rect.top += 26;
rect.left = 0;
rect.bottom -= 5;
rect.right -= 5;
Pages[CurPage]->MoveWindow(&rect);
mTab.InsertItem(CurPage, _Name);
CurPage++;
return true;
}
BEGIN_MESSAGE_MAP(CUI, CDialogEx)
ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, &CUI::OnTcnSelchangeTab1)
ON_WM_CLOSE()
END_MESSAGE_MAP()
// CUI 消息处理程序
void CUI::OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
int n = mTab.GetCurSel();
for (int i = 0; i < CurPage; i++)
{
Pages[i]->ShowWindow(i == n);
}
}
void CUI::UIShow()
{
auto hwndClient = ::FindWindow(L"CLIENT", L"SRO_CLIENT");
// ::SetParent(this->m_hWnd, hwndClient);
this->ShowWindow(ShowUI = !ShowUI);
// 把焦点还给游戏
::SetFocus(hwndClient);
// _ui_helper->ShowWindow(TRUE);
}
void CUI::OnClose()
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
UIShow();
// CDialogEx::OnClose();
}
CHelperUI.h文件的修改,添加 helper_Width变量、hwndGame变量、Init函数声明、MoveHelper函数声明、Show函数声明、OnBnClickedOk2函数声明
#pragma once
#include "afxdialogex.h"
#include "resource.h"
// CHelperUI 对话框
class CHelperUI : public CDialogEx
{
DECLARE_DYNAMIC(CHelperUI)
public:
CHelperUI(CWnd* pParent = nullptr); // 标准构造函数
virtual ~CHelperUI();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_HELPER };
#endif
protected:
virtual BOOL OnInitDialog();
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedOk();
// 血量条
CProgressCtrl HPBar;
// 魔法条
CProgressCtrl MPBar;
// 怒气条
CProgressCtrl RageBar;
// 升级经验值条
CProgressCtrl ExBar;
bool GameShow = true;
// 游戏句柄
HWND hwndGame{};
int helper_Width;
void Init();
void MoveHelper();
void ShowData();
void Show();
afx_msg void OnBnClickedOk2();
afx_msg void OnClose();
};
CHelperUI.cpp文件的修改,新加 OnBnClickedOk2函数、OnClose函数、Show函数、MoveHelper函数、Init函数、GetScreenResolution函数,OnBnClickedOk2函数是显示/隐藏按钮的点击事件处理函数,GetScreenResolution函数是用来获取窗口所在显示器的分辨率
// CHelperUI.cpp: 实现文件
//
#include "pch.h"
#include "CHelperUI.h"
#include "afxdialogex.h"
#include "extern_all.h"
void _stdcall TimeProcHelper(HWND, UINT, UINT_PTR, DWORD) {
if (_ui_helper)_ui_helper->ShowData();
}
//获取程序当前所在显示器的分辨率大小,可以动态的获取程序所在显示器的分辨率
SIZE GetScreenResolution(HWND hWnd) {
SIZE size{};
if (!hWnd)
return size;
//MONITOR_DEFAULTTONEAREST 返回值是最接近该点的屏幕句柄
//MONITOR_DEFAULTTOPRIMARY 返回值是主屏幕的句柄
//如果其中一个屏幕包含该点,则返回值是该屏幕的HMONITOR句柄。如果没有一个屏幕包含该点,则返回值取决于dwFlags的值
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
MONITORINFOEX miex;
miex.cbSize = sizeof(miex);
if (!GetMonitorInfo(hMonitor, &miex))
return size;
DEVMODE dm;
dm.dmSize = sizeof(dm);
dm.dmDriverExtra = 0;
//ENUM_CURRENT_SETTINGS 检索显示设备的当前设置
//ENUM_REGISTRY_SETTINGS 检索当前存储在注册表中的显示设备的设置
if (!EnumDisplaySettings(miex.szDevice, ENUM_CURRENT_SETTINGS, &dm))
return size;
size.cx = dm.dmPelsWidth;
size.cy = dm.dmPelsHeight;
return size;
}
IMPLEMENT_DYNAMIC(CHelperUI, CDialogEx)
CHelperUI::CHelperUI(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_HELPER, pParent)
{
}
CHelperUI::~CHelperUI()
{
}
BOOL CHelperUI::OnInitDialog()
{
CDialogEx::OnInitDialog();
this->SetBackgroundColor(RGB(255, 255, 255));
HPBar.SetBkColor(RGB(0 ,0, 0));
MPBar.SetBkColor(RGB(0 ,0, 0));
RageBar.SetBkColor(RGB(0 ,0, 0));
ExBar.SetBkColor(RGB(0 ,0, 0));
HPBar.SetBarColor(RGB(255 ,0, 0));
MPBar.SetBarColor(RGB(0x0, 0x0, 0x99));
RageBar.SetBarColor(RGB(0x66, 0x0, 0x66));
ExBar.SetBarColor(RGB(0x00, 0xFF, 0xCC));
HPBar.SetRange(0, 999);
MPBar.SetRange(0, 1000);
RageBar.SetRange(0, 5);
ExBar.SetRange(0, 1000);
//HPBar.SetPos(50);
//MPBar.SetPos(50);
//RageBar.SetPos(50);
//ExBar.SetPos(50);
::SetTimer(this->m_hWnd, 0x100002, 100, TimeProcHelper);
return TRUE;
}
void CHelperUI::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_PRO_HP, HPBar);
DDX_Control(pDX, IDC_PRO_MP, MPBar);
DDX_Control(pDX, IDC_PRO_RAGE, RageBar);
DDX_Control(pDX, IDC_PRO_RAGE2, ExBar);
}
BEGIN_MESSAGE_MAP(CHelperUI, CDialogEx)
ON_BN_CLICKED(IDOK, &CHelperUI::OnBnClickedOk)
ON_BN_CLICKED(IDOK2, &CHelperUI::OnBnClickedOk2)
ON_WM_CLOSE()
END_MESSAGE_MAP()
// CHelperUI 消息处理程序
void CHelperUI::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
// CDialogEx::OnOK();
//CString tmp;
//tmp.Format(L"%d", _pgamebase->SRO_Player->MapId);
//AfxMessageBox(tmp);
//
//CString city;
//city.Format(L"%s", _pgamebase->SRO_Res->ReadTitle(tmp.GetBuffer())->wcstr());
//AfxMessageBox(city);
}
void CHelperUI::Init()
{
if (hwndGame) return;
wchar_t buff[0xFF]{};
// 获取主窗口句柄
HWND _hwnd = ::GetActiveWindow();
// 获取窗口标题
::GetWindowText(_hwnd, buff, 0xFF);
CString _title = buff;
if (_title == L"SRO_CLIENT") {
hwndGame = _hwnd;
CRect rect_me;
// 获取当前窗口句柄
GetWindowRect(&rect_me);
helper_Width = rect_me.Width();
}
}
void CHelperUI::MoveHelper()
{
if (hwndGame) {
CRect rect;
// 获取游戏窗口(主窗口)样式
::GetWindowRect(hwndGame, &rect);
int helper_left = rect.left + rect.Width();
SIZE windowSize = GetScreenResolution(this->m_hWnd);
if ((helper_left + helper_Width) > windowSize.cx) {
helper_left -= helper_Width;
}
// 设置窗口大小
::MoveWindow(this->m_hWnd, helper_left, rect.top, helper_Width, rect.Height(), TRUE);
}
}
void CHelperUI::ShowData()
{
CString tmp;
CString city;
auto _player = _pgamebase->SRO_Player;
if (_player) {
tmp.Format(L"%s Lv %d", _player->Name.wcstrByName(), _player->Lv);
this->SetWindowText(tmp);
float hpStep = _player->HP * 1000;
hpStep = hpStep / _player->MaxHP;
HPBar.SetPos(hpStep);
float mpStep = _player->MP * 1000;
mpStep = mpStep / _player->MaxMP;
MPBar.SetPos(mpStep);
RageBar.SetPos(_player->Rage);
unsigned max_exp = _pgamebase->SRO_Core->GetLvMaxExp(_player->Lv)->Exp;
float expSetp = _player->Exp * 1000;
expSetp = expSetp / max_exp;
ExBar.SetPos(expSetp);
tmp.Format(L"%.1f %.1f %.1f", _player->x, _player->h, _player->y);
GetDlgItem(IDC_STATIC_CORD)->SetWindowText(tmp);
tmp.Format(L"%d", _pgamebase->SRO_Player->MapId);
city.Format(L"%s", _pgamebase->SRO_Res->ReadTitle(tmp.GetBuffer())->wcstr());
GetDlgItem(IDC_STATIC_MAP)->SetWindowText(city);
}
}
void CHelperUI::Show()
{
MoveHelper();
this->ShowWindow(TRUE);
}
void CHelperUI::OnBnClickedOk2()
{
if (hwndGame) {
::ShowWindow(hwndGame, GameShow = !GameShow);
}
}
void CHelperUI::OnClose()
{
if (hwndGame) {
::ShowWindow(hwndGame, GameShow = true);
this->ShowWindow(FALSE);
}
}