免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
如果看不懂、不知道现在做的什么,那就跟着做完看效果,代码看不懂是正常的,只要会抄就行,抄着抄着就能懂了
内容参考于:易道云信息技术研究院
上一个内容:92.利用哈希表实现快速读取文本内容
码云版本号:a2dce46124a3dc34cd6331459ec15b8b73aa4291
代码下载地址,在 titan 目录下,文件名为:titan-增强技能信息显示后进行分析.zip
链接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg
提取码:q9n5
--来自百度网盘超级会员V4的分享
HOOK引擎,文件名为:黑兔sdk升级版.zip
链接:https://pan.baidu.com/s/1IB-Zs6hi3yU8LC2f-8hIEw
提取码:78h8
--来自百度网盘超级会员V4的分享
以 92.利用哈希表实现快速读取文本内容 它的代码为基础进行修改
现在已经能够把技能名字读出来了,所以把之前的英文代号翻译之后打印出来
首先提一个东西
下图是在 87.技能名称显示的逆向分析 里分析技能id对应的中文名时看到的,这里它把技能id前面加上了desc_后面加上了一个_1,所以我们要用语言包的时候也要加这俩东西
如下图,加上之后技能名可以显示,但是装备、衣服等这些东西没法显示了,所以装备、衣服等这些东西以后要特殊处理
然后登陆游戏
选择一个1级的,选择1级的目的是为了看解锁技能的数据包
进入游戏之后,可以看到现在所有技能的中文名字了
然后接下来看一看升级之后解锁技能
下图4级解锁,接下来升到4级
到4级解锁了冲击火环技能
然后使用 DataAnly.exe 工具搜索冲击火环技能id找解锁它的数据包,下图是技能id
搜索
然后就能看到下图红框里的俩数据包,下方的两个数据包在 84.筛选与技能有关的数据包 最后提过,它俩是在升级之后解锁了新技能时出现的,那时候没法解,完全不知道是什么,现在突然灵光一闪,数据结构就出来了
首先是13数据包,初步推测的结构
中文是装备技能的意思
然后数据前面的01 00 几,这样的写法又像是数据解析约定,具体什么意思怎么用,后面再写,现在只知道有这样的事就行,看了之后忘了也没事,用的时候会来看,如果后面用到了会带着当前文章的链接
然后是11数据包,这个数据包,equip_skill_rec中文意思装备技能,上方13数据包是装备全部技能,也就是说可以有多个,11数据包应该只能一次装备一个,之前解不出来的数据包,现在也能解出来了,但是值的意思还不知道,但是结构以及有了一个大体的形象
GameAnly.cpp文件的修改:修改了 AnlyData函数
#include "pch.h"
#include "GameAnly.h"
#include <iostream>
#include <fstream>
#ifdef Anly
// 它会生成一个结构体,详情看效果图
void GameAnly::AnlyBuff(char* start, char* end, int MsgId, char index)
{
CStringA txt;
CStringA tmp;
CString utmp;
EnCode _coder;
GBYTE* _bytecoder;
GSHORT* _shortcoder;
GINT* _intcoder;
GFLOAT* _floatcoder;
GDOUBLE* _doublecoder;
GCHAR* _asccoder;
GUTF16* _utfcoder;
GINT64* _int64coder;
while (start < end) {
_coder.Init(start, index);
CStringA _opname = data_desc[_coder.index][_coder.op].name;
// _opname.MakeLower()是变为小写字母,会影响 _opname它的值
// 所以又写了一边 data_desc[_coder.index][_coder.op].name
tmp.Format("%s %s;//", data_desc[_coder.index][_coder.op].name, _opname.MakeLower().GetBuffer());
txt = txt + tmp;
if (_coder.index == 0) {
switch (_coder.op)
{
case 1:
_shortcoder = (GSHORT*)&_coder;
tmp.Format("%d\r\n", _shortcoder->value());
txt = txt + tmp;
break;
case 2:
_intcoder = (GINT*)&_coder;
tmp.Format("%d\r\n", _intcoder->value());
txt = txt + tmp;
break;
case 4:
_floatcoder = (GFLOAT*)&_coder;
tmp.Format("%f\r\n", _floatcoder->value());
txt = txt + tmp;
break;
case 6:
_bytecoder = (GBYTE*)&_coder;
tmp.Format("%d\r\n", _bytecoder->value());
txt = txt + tmp;
break;
case 7:
_utfcoder = (GUTF16*)&_coder;
utmp.Format(L"[%s]\r\n", _utfcoder->value());
tmp = utmp;
txt = txt + tmp;
break;
// 5号之前分析的忘记截图了,现在找不到它的数据包了,如果后面再见到05的时候再详细补充说明
// 之前的分析05就是double类型
case 5:
_doublecoder = (GDOUBLE*)&_coder;
tmp.Format("%lf\r\n", _doublecoder->value());
txt = txt + tmp;
break;
case 8:
case 3:
_int64coder = (GINT64*)&_coder;
tmp.Format("%lld\r\n", _int64coder->value());
txt = txt + tmp;
break;
default:
break;
}
}
if (_coder.index == 1) {
switch (_coder.op)
{
case 1:
_shortcoder = (GSHORT*)&_coder;
tmp.Format("%d\r\n", _shortcoder->value());
txt = txt + tmp;
break;
case 2:
_intcoder = (GINT*)&_coder;
tmp.Format("%d\r\n", _intcoder->value());
txt = txt + tmp;
break;
case 4:
_floatcoder = (GFLOAT*)&_coder;
tmp.Format("%f\r\n", _floatcoder->value());
txt = txt + tmp;
break;
case 6:
_asccoder = (GCHAR*)&_coder;
tmp.Format("%s\r\n", _asccoder->value());
txt = txt + tmp;
break;
case 7:
_utfcoder = (GUTF16*)&_coder;
utmp.Format(L"[%s]\r\n", _utfcoder->value());
tmp = utmp;
txt = txt + tmp;
break;
case 5:
_doublecoder = (GDOUBLE*)&_coder;
tmp.Format("%lf\r\n", _doublecoder->value());
txt = txt + tmp;
break;
case 8:
case 3:
_int64coder = (GINT64*)&_coder;
tmp.Format("%lld\r\n", _int64coder->value());
txt = txt + tmp;
break;
default:
break;
}
}
}
anly->SendData(TTYPE::I_DIS, MsgId, txt.GetBuffer(), txt.GetAllocLength() + 1);
}
void GameAnly::AnlyData(char* start, char* end, int count, int MsgId, POBJ_DESC desc)
{
int iProc = 0;
int value;
long long llvalue;
float fvalue;
double dbval;
CStringA szTmp, _tmp, szTxt, _tmp1;
CString wTmp;
while ((iProc < count) && (start <end)) {
short* index = (short*)start;
int type = desc[index[0]].type;
char* name = desc[index[0]].name;
switch (type)
{
case 0:
AfxMessageBox(L"0号信息!"); break;
case 1:
value = ToChar(start);
szTmp.Format("%s = %d", name, value);
break;
case 2:
value = ToShort(start);
szTmp.Format("%s = %d", name, value);
break;
case 3:
value = ToInt(start);
szTmp.Format("%s = %d", name, value);
break;
case 4:
llvalue = ToLLong(start);
szTmp.Format("%s = %lld", name, llvalue);
break;
case 5:
fvalue = ToFloat(start);
szTmp.Format("%s = %f", name, fvalue);
break;
case 6:
dbval = ToDouble(start);
szTmp.Format("%s = %lf", name, dbval);
break;
case 7:
_tmp = ToAscii(start);
_tmp1 = name;
if (_tmp1 == "ConfigID") {
_tmp = "desc_" + _tmp + "_1";
wTmp = txtManger->ReadTextById(_tmp);
_tmp1 = wTmp;
}
szTmp.Format("%s = %s\r\ntext=%s", name, _tmp.GetBuffer(), _tmp1.GetBuffer());
break;
case 8:
wTmp = ToUniode(start);
_tmp = wTmp;
szTmp.Format("%s = %s", name, _tmp.GetBuffer());
break;
case 9:
llvalue = ToLLong(start);
szTmp.Format("%s = %llX", name, llvalue);
break;
default:
break;
}
szTxt = szTxt + szTmp + "\r\n";
iProc++;
}
anly->SendData(TTYPE::I_DIS, MsgId, szTxt.GetBuffer(), szTxt.GetAllocLength() + 1);
//CStringA tmpA;
//CStringA szTxt, szTmp;
//szTmp.Format("id:%lld\r\n", head->lId);
//szTxt = szTxt + szTmp;
//szTmp.Format("x:%f h:%f y:%f\r\n", head->x, head->h, head->y);
//szTxt = szTxt + szTmp;
//char* buffStart = (char*)head + sizeof(NR_OBNJECT_INIT) - 2;
//int icount = head->icount;
//int iProc = 0;
//while (iProc < icount) {
// short* type = (short*)buffStart;
// char* _name = ObjectTable[type[0]].name;
// int _type = ObjectTable[type[0]].type;
// char* _byte;
// short* _short;
// int* _int;
// float* _float;
// long long* _llong;
// double* _double;
// int lenth;
// CString _txt;
// /*
// 1B 00 type[0] buffStart + 2;
// 0C 00 00 00 CA 4E 5A 66 53 62 01 80 4E 86 00 00
// 1D 00 type[0]
// 00 00 48 42 buffStart + 2;
// 01 00 type[0]
// 02 buffStart + 2;
// 02 00 type[0]
// 01 buffStart + 2;
// 03 00 2E 00 00 00 67 75 69 5C 42 47 5F 74 65 61 6D 5C 54 65 61 6D 52 6F 6C 65 5C 54 65 61 6D 72 6F 6C 65 5F 7A 71 5F 68 75 6D 46 5F 30 30 31 2E 50 4E 47 00
// 04 00 01 00 00 00
// 05 00 01 00 00 00
// 06 00 01 00 00 00
// 07 00 01 00 00 00
// 08 00 00 B1 9E 00
// */
// buffStart = buffStart + 2;
// switch (_type)
// {
// case 0:
// AfxMessageBox(L"0号信息!"); break;
// case 1:
// _byte = buffStart;
// szTmp.Format("%s = %d", _name, _byte[0]);
// buffStart = buffStart + 1;
// break;
// case 2:
// _short = (short*)buffStart;
// szTmp.Format("%s = %d", _name, _short[0]);
// buffStart = buffStart + 2;
// break;
// case 3:
// _int = (int*)buffStart;
// szTmp.Format("%s = %d", _name, _int[0]);
// buffStart = buffStart + 4;
// break;
// case 4:
// _llong = (long long*)buffStart;
// szTmp.Format("%s = %lld", _name, _llong[0]);
// buffStart = buffStart + 8;
// break;
// case 5:
// _float = (float*)buffStart;
// szTmp.Format("%s = %f", _name, _float[0]);
// buffStart = buffStart + 4;
// break;
// case 6:
// _double = (double*)buffStart;
// szTmp.Format("%s = %lf", _name, _double[0]);
// buffStart = buffStart + 8;
// break;
// case 7:
// _int = (int*)buffStart;
// lenth = _int[0];
// // szTmp = buffStart + 4;
// szTmp.Format("%s = %s", _name, buffStart + 4);
// buffStart = buffStart + 4 + lenth;
// break;
// case 8:
// _int = (int*)buffStart;
// lenth = _int[0];
// _txt = (wchar_t*)(buffStart + 4);
// tmpA = _txt;
// szTmp.Format("%s = %s", _name, tmpA);
// buffStart = buffStart + 4 + lenth;
// break;
// case 9:MessageBoxA(0, buffStart, buffStart, MB_OK); return true;
// default:
// break;
// }
// szTxt = szTxt + szTmp + "\r\n";
// iProc++;
//}
//anly->SendData(TTYPE::I_DIS, S_OBJECT_INIT, szTxt.GetBuffer(), szTxt.GetAllocLength() + 1);
}
void GameAnly::CreateObjectfiles(POBJ_DESC desc, int icount)
{
/*char* _GameOBJECThpp = "F:\\代码存放地\\c\\titan\\tilib\\GameOBJECT.h";
char* _GameOBJECTcpp = "F:\\代码存放地\\c\\titan\\tilib\\GameOBJECT.cpp";
char* _GameOBJECTdef = "F:\\代码存放地\\c\\titan\\tilib\\GameOBJECTDef.h";*/
char* _GameOBJECThpp = "D:\\代码存放地\\c\\titan\\tilib\\GameOBJECT.h";
char* _GameOBJECTcpp = "D:\\代码存放地\\c\\titan\\tilib\\GameOBJECT.cpp";
char* _GameOBJECTdef = "D:\\代码存放地\\c\\titan\\tilib\\GameOBJECTDef.h";
std::ofstream ofs(_GameOBJECThpp); // 根据09数据包生成类的头文件
std::ofstream ofCpp(_GameOBJECTcpp); // 根据09数据包生成类的cpp文件
std::ofstream ofDef(_GameOBJECTdef);// 生成宏
if (ofs.bad() || ofCpp.bad() || ofDef.bad()) {
ofs.close();
ofCpp.close();
ofDef.close();
return;
}
else
{
// 定义CPP文件头部
ofCpp << "#include \"pch.h\"" << std::endl;
ofCpp << "#include \"GameOBJECT.h\"" << std::endl;
ofCpp << "#include \"GameOBJECTDef.h\"" << std::endl;
ofCpp << "void GAMEOBJECT::UpdateData(char*& buffStart)" << std::endl;
ofCpp << "{ " << std::endl;
ofCpp << " short* id = (short*)buffStart;" << std::endl;
ofCpp << " Isfree = false;" << std::endl;
ofCpp << " /* " << std::endl;
ofCpp << " 1B 00 buffStart " << std::endl;
ofCpp << " 0C 00 00 00 buffStart + 2 " << std::endl;
ofCpp << " CA 4E 5A 66 53 62 01 80 4E 86 00 00 1D 00 " << std::endl;
ofCpp << " */ " << std::endl;
ofCpp << " buffStart = buffStart + 2;" << std::endl;
ofCpp << " switch (id[0])" << std::endl;
ofCpp << " {" << std::endl;
// 定义文件头部区域
ofDef << "#pragma once" << std::endl;
// 头部生成区域
ofs << "#pragma once" << std::endl;
ofs << "#define GASCII CStringA" << std::endl;
ofs << "#define GUNICODE CString" << std::endl;
ofs << "#define GOBJECT long long // LastObject" << std::endl;
ofs << "typedef class GAMEOBJECT{" << std::endl;
ofs << "public:" << std::endl;
ofs << " bool Isfree = true;" << std::endl;
// 变量声明
// i = 1的原因是游戏的数据类型表里(接收的09数据包)第一个是NONE
for (int i = 1; i < icount; i++)
{
char* valueName = desc[i].name;
int valueType = desc[i].type;
char* valueTypeName = data_desc[2][valueType].name;
int valueSize = data_desc[2][valueType].lenth;
ofs << " " << valueTypeName << " " << valueName << ";" << std::endl;
ofDef << "#define INDEX_" << valueName << " " << i << std::endl;
ofCpp << " case INDEX_" << valueName << ":" << std::endl;
ofCpp << " return Set" << valueName << "(buffStart);" << std::endl;
}
ofCpp << " }" << std::endl;
ofCpp << "}" << std::endl;
// 函数声明
ofs << " void virtual UpdateData(char*& buffStart);" << std::endl;
ofs << " void virtual Release();" << std::endl;
ofs << "protected:" << std::endl;
for (int i = 1; i < icount; i++)
{
char* valueName = desc[i].name;
int valueType = desc[i].type;
char* valueTypeName = data_desc[2][valueType].name;
int valueSize = data_desc[2][valueType].lenth;
ofs << " void virtual Set" << valueName << "(char*& buffStart);" << std::endl;
ofCpp << "void GAMEOBJECT::Set" << valueName << "(char*& buffStart)" << std::endl;
ofCpp << "{" << std::endl;
if(valueType == 7){
ofCpp << " int* lenth = (int*)buffStart;" << std::endl;
ofCpp << " buffStart += 4;" << std::endl;
ofCpp << " " << valueName << " = (char*)buffStart; " << std::endl;
ofCpp << " buffStart += lenth[0];" << std::endl;
}
else if(valueType == 8) {
ofCpp << " int* lenth = (int*)buffStart;" << std::endl;
ofCpp << " buffStart += 4;" << std::endl;
ofCpp << " " << valueName << " = (wchar_t*)buffStart; " << std::endl;
ofCpp << " buffStart += lenth[0];" << std::endl;
}
else {
ofCpp << " " << valueTypeName << "* value = (" << valueTypeName << "*)buffStart;" << std::endl;
ofCpp << " buffStart += sizeof(" << valueTypeName << ");" << std::endl;
ofCpp << " " << valueName << " = value[0];" << std::endl;
}
ofCpp << "}" << std::endl;
}
ofCpp << "void GAMEOBJECT::Release()" << std::endl;
ofCpp << "{ " << std::endl;
for (int i = 1; i < icount; i++)
{
char* valueName = desc[i].name;
int valueType = desc[i].type;
char* valueTypeName = data_desc[2][valueType].name;
int valueSize = data_desc[2][valueType].lenth;
if (valueType == 7) {
ofCpp << " " << valueName << " = \"\";" << std::endl;
}
else if (valueType == 8) {
ofCpp << " " << valueName << " = L\"\";" << std::endl;
}
else {
ofCpp << " " << valueName << " = 0;" << std::endl;
}
}
ofCpp << " Isfree = true;" << std::endl;
ofCpp << "}" << std::endl;
ofs << "}*PGAMEOBJ;" << std::endl;
}
ofs.close();
ofCpp.close();
ofDef.close();
}
void GameAnly::CreateStructfile(PSTRUCT_DESC desc, int icount)
{
char* _GameStructhpp = "F:\\代码存放地\\c\\titan\\tilib\\GameSTRUCT.h";
std::ofstream ofs(_GameStructhpp); // 根据0A数据包生成类的头文件
if (ofs.bad()) {
return;
}
else {
ofs << "#pragma once" << std::endl;
ofs << "#define GASCII CStringA" << std::endl;
ofs << "#define GUNICODE CString" << std::endl;
ofs << "#define GOBJECT long long" << std::endl;
for (int i = 1; i < icount; i++) {
char* structName = desc[i].name;
ofs << "// [" << std::hex << i << "][" << structName << "]" << std::endl;
ofs << "typedef class " << structName << "{" << std::endl;
ofs << "public:" << std::endl;
for (int l = 0; l < desc[i].count; l++) {
char valueType = desc[i].buff[l];
char* valueTypeName = data_desc[2][valueType].name;
ofs << " " << valueTypeName << " " << "value_" << l << ";" << std::endl;
}
ofs << "}*P" << structName << ";" << std::endl;
}
}
}
char GameAnly::ToChar(char*& start)
{
char result = start[0];
start = start + 3;
return result;
}
short GameAnly::ToShort(char*& start)
{
short* result = (short*)(start + 2);
start = start + 2 + 2;
return result[0];
}
int GameAnly::ToInt(char*& start)
{
int* result = (int*)(start + 2);
start = start + 2 + 4;
return result[0];
}
float GameAnly::ToFloat(char*& start)
{
float* result = (float*)(start + 2);
start = start + 2 + 4;
return result[0];
}
double GameAnly::ToDouble(char*& start)
{
double* result = (double*)(start + 2);
start = start + 2 + 8;
return result[0];
}
long long GameAnly::ToLLong(char*& start)
{
long long* result = (long long*)(start + 2);
start = start + 2 + 8;
return result[0];
}
char* GameAnly::ToAscii(char*& start)
{
int* lenth = (int*)(start + 2);
char* result = start + 2 + 4; // +4这个操作是跳过 lenth的值
start = start + 2 + 4 + lenth[0];
return result;
}
wchar_t* GameAnly::ToUniode(char*& start)
{
int* lenth = (int*)(start + 2);
wchar_t* result = (wchar_t*)(start + 2 + 4); // +4这个操作是跳过 lenth的值
start = start + 2 + 4 + lenth[0];
return result;
}
#endif // Anly