免責聲明:內容僅供學習參考,請合法利用知識,禁止進行違法犯罪活動!
如果看不懂、不知道現在做的什么,那就跟著做完看效果,代碼看不懂是正常的,只要會抄就行,抄著抄著就能懂了
內容參考于:易道云信息技術研究院
上一個內容: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].nametmp.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數據包)第一個是NONEfor (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