内容参考于:易道云信息技术研究院VIP课
上一个内容:显示游戏数据到小助手UI
码云地址(游戏窗口化助手 分支):https://gitee.com/dye_your_fingers/sro_-ex.git
码云版本号:852c339f5e4c103390b123e0eaed577c9afa4fc4
代码下载地址,在 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的分享
以 游戏窗口化助手的UI设计 它的代码为基础进行修改
然后打开 Cheat Engine 找升级经验
然后就找到了
然后接下来看访问,因为它一定是通过某种计算得出这个结果,然后显示出来,它得到的过程就是访问的过程,所以看访问,然后接下来就看它是指怎样把这个东西得出来的,然后又三个位置
这三个位置的代码都差不多,所以先根据第一个分析试试,然后打开x96dbg,先记录数据,好做条件断点,0x6D7C0B
然后可以看出这里好像只有升级经验会触发,它的返回值就是经验
然后它的入参是等级
然后0xA21F20函数的返回值,出了下图红框位置的数据是我们要的升级经验以外,其它都不认识
记录关键信息,0x1036590类,0xA21F20函数
效果图:
CHelperUI.cpp文件的修改:修改了 ShowData函数
// 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();
}
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)
END_MESSAGE_MAP()
// CHelperUI 消息处理程序
void CHelperUI::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
CDialogEx::OnOK();
}
void CHelperUI::ShowData()
{
CString tmp;
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);
}
}
GameBase.h文件的修改:新加 SRO_Core变量
#pragma once
#include "Res.h"
#include "Control.h"
#include "AIM.h"
#include "ITEM.h"
#include "Core.h"
class GameBase
{
void InitClassProc(LPVOID proc_addr, unsigned value);
public:
void Init();
GameBase();
PRes SRO_Res;
PControl SRO_Control;
PAIM SRO_Player;
PCore SRO_Core;
};
GameBase.cpp文件的修改:修改了 Init函数
#include "pch.h"
#include "GameBase.h"
GameBase* _pgamebase;
void GameBase::Init()
{
unsigned* addrRead = (unsigned*)0x1256E3C;
SRO_Res = (PRes)0x1036518;
SRO_Control = (PControl)addrRead[0];
addrRead = (unsigned*)0x1037D3C;
SRO_Player = (PAIM)addrRead[0];
SRO_Core = (PCore)0x1036590;
InitClassProc(&Res::_ReadTitle, 0x9A46C0);
InitClassProc(&Res::_ReadItemTitle, 0x9A4640);
InitClassProc(&Control::_NormalNotice, 0x848580);
InitClassProc(&Control::_NetNotice, 0x844E40);
InitClassProc(&Control::_ChatNotice, 0x844E80);
InitClassProc(&Control::_GetPPack, 0x866140);
InitClassProc(&Control::_UseItem, 0x85F640);
InitClassProc(&Control::_MangeItem, 0x864220);
InitClassProc(&ITEM::_GetItemRes, 0x995800);
InitClassProc(&Pack::_GetPackPack, 0x7722C0);
InitClassProc(&Pack::_GetEquipPack, 0x772300);
InitClassProc(&Core::_GetLvMaxExp, 0xA21F20);
}
void GameBase::InitClassProc(LPVOID proc_addr, unsigned value)
{
unsigned* uWrite = (unsigned*)proc_addr;
uWrite[0] = value;
}
GameBase::GameBase()
{
_pgamebase = this;
// Init();// 初始化机制,完成游戏与我们dll的对接
}
新加Core.cpp文件:
#include "pch.h"
#include "Core.h"
Core::PROC_D Core::_GetLvMaxExp{};
PLvData Core::GetLvMaxExp(unsigned lv)
{
return (PLvData)(this->*_GetLvMaxExp)(lv);
}
新加Core.h文件:
#pragma once
typedef struct LvData {
int un0[2];
unsigned Exp;
int un1;
}*PLvData;
typedef class Core
{
typedef int(Core::* PROC_D)(unsigned);
public:
static PROC_D _GetLvMaxExp;
PLvData GetLvMaxExp(unsigned lv);
}*PCore;