mirror of
https://github.com/EQEmu/Server.git
synced 2026-03-07 03:02:35 +00:00
Proof of concept file verification
This commit is contained in:
parent
c3a805923c
commit
923252dbcc
@ -28,6 +28,7 @@ SET(common_sources
|
|||||||
eqtime.cpp
|
eqtime.cpp
|
||||||
extprofile.cpp
|
extprofile.cpp
|
||||||
faction.cpp
|
faction.cpp
|
||||||
|
file_verify.cpp
|
||||||
guild_base.cpp
|
guild_base.cpp
|
||||||
guilds.cpp
|
guilds.cpp
|
||||||
ipc_mutex.cpp
|
ipc_mutex.cpp
|
||||||
@ -130,6 +131,7 @@ SET(common_headers
|
|||||||
extprofile.h
|
extprofile.h
|
||||||
faction.h
|
faction.h
|
||||||
features.h
|
features.h
|
||||||
|
file_verify.h
|
||||||
fixed_memory_hash_set.h
|
fixed_memory_hash_set.h
|
||||||
fixed_memory_variable_hash_set.h
|
fixed_memory_variable_hash_set.h
|
||||||
global_define.h
|
global_define.h
|
||||||
|
|||||||
@ -292,8 +292,6 @@ N(OP_LockoutTimerInfo),
|
|||||||
N(OP_Login),
|
N(OP_Login),
|
||||||
N(OP_LoginAccepted),
|
N(OP_LoginAccepted),
|
||||||
N(OP_LoginComplete),
|
N(OP_LoginComplete),
|
||||||
N(OP_LoginUnknown1),
|
|
||||||
N(OP_LoginUnknown2),
|
|
||||||
N(OP_Logout),
|
N(OP_Logout),
|
||||||
N(OP_LogoutReply),
|
N(OP_LogoutReply),
|
||||||
N(OP_LogServer),
|
N(OP_LogServer),
|
||||||
@ -527,8 +525,10 @@ N(OP_Weather),
|
|||||||
N(OP_Weblink),
|
N(OP_Weblink),
|
||||||
N(OP_WhoAllRequest),
|
N(OP_WhoAllRequest),
|
||||||
N(OP_WhoAllResponse),
|
N(OP_WhoAllResponse),
|
||||||
N(OP_World_Client_CRC1),
|
N(OP_World_SpellFileCheck),
|
||||||
N(OP_World_Client_CRC2),
|
N(OP_World_SkillFileCheck),
|
||||||
|
N(OP_World_BaseDataFileCheck),
|
||||||
|
N(OP_World_ExeFileCheck),
|
||||||
N(OP_WorldClientReady),
|
N(OP_WorldClientReady),
|
||||||
N(OP_WorldComplete),
|
N(OP_WorldComplete),
|
||||||
N(OP_WorldLogout),
|
N(OP_WorldLogout),
|
||||||
|
|||||||
123
common/file_verify.cpp
Normal file
123
common/file_verify.cpp
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
#include "global_define.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "file_verify.h"
|
||||||
|
#include "crc32.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
struct VerifyFileStruct
|
||||||
|
{
|
||||||
|
uint32 crc;
|
||||||
|
uint32 file_size;
|
||||||
|
uint32 offset[256];
|
||||||
|
uint32 data[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
EQEmu::FileVerify::FileVerify(const char *file_name) {
|
||||||
|
FILE *f = fopen(file_name, "rb");
|
||||||
|
if(!f) {
|
||||||
|
buffer = nullptr;
|
||||||
|
size = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(f, 0U, SEEK_END);
|
||||||
|
size = ftell(f);
|
||||||
|
rewind(f);
|
||||||
|
|
||||||
|
char *buffer = new char[size];
|
||||||
|
auto result = fread(buffer, 1, size, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if(result != size) {
|
||||||
|
safe_delete_array(buffer);
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EQEmu::FileVerify::~FileVerify() {
|
||||||
|
safe_delete_array(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EQEmu::FileVerify::Verify(const char *data, uint32 size) {
|
||||||
|
if(!buffer) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(size != sizeof(VerifyFileStruct)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VerifyFileStruct *vs = (VerifyFileStruct*)data;
|
||||||
|
if(size != vs->file_size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 crc = CRC32::GenerateNoFlip((uchar*)buffer, size);
|
||||||
|
if(vs->crc != crc) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 256; ++i) {
|
||||||
|
uint32 offset = vs->offset[i] * 4;
|
||||||
|
|
||||||
|
if((offset - 4) > size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 check = *(uint32*)(buffer + offset);
|
||||||
|
if(check != vs->data[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bool VerifyFile(const EQApplicationPacket *app, const char* filename) {
|
||||||
|
// FILE *f = fopen(filename, "rb");
|
||||||
|
// if(!f) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// VerifyFileStruct *vs = (VerifyFileStruct*)app->pBuffer;
|
||||||
|
//
|
||||||
|
// fseek(f, 0U, SEEK_END);
|
||||||
|
// auto size = ftell(f);
|
||||||
|
// rewind(f);
|
||||||
|
//
|
||||||
|
// if(size != vs->file_size || size < 1024) {
|
||||||
|
// fclose(f);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// char *buffer = new char[size];
|
||||||
|
// std::unique_ptr<char> data(buffer);
|
||||||
|
// auto result = fread(buffer, 1, size, f);
|
||||||
|
// fclose(f);
|
||||||
|
//
|
||||||
|
// if(result != size) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// uint32 crc = CRC32::GenerateNoFlip((uchar*)buffer, size);
|
||||||
|
//
|
||||||
|
// Log.Out(Logs::General, Logs::Status, "CRC %u vs %u", crc, vs->crc);
|
||||||
|
//
|
||||||
|
// for(int i = 0; i < 256; ++i) {
|
||||||
|
// uint32 offset = vs->check[i] * 4;
|
||||||
|
//
|
||||||
|
// Log.Out(Logs::General, Logs::Status, "Data: %c%c%c%c vs %c%c%c%c", vs->data[i * 4], vs->data[i * 4 + 1], vs->data[i * 4 + 2], vs->data[i * 4 + 3],
|
||||||
|
// buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3]);
|
||||||
|
//
|
||||||
|
// if(buffer[offset] != vs->data[i * 4] ||
|
||||||
|
// buffer[offset + 1] != vs->data[i * 4 + 1] ||
|
||||||
|
// buffer[offset + 2] != vs->data[i * 4 + 2] ||
|
||||||
|
// buffer[offset + 3] != vs->data[i * 4 + 3])
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return true;
|
||||||
|
//}
|
||||||
20
common/file_verify.h
Normal file
20
common/file_verify.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef EQEMU_COMMON_FILE_VERIFY_H
|
||||||
|
#define EQEMU_COMMON_FILE_VERIFY_H
|
||||||
|
|
||||||
|
namespace EQEmu
|
||||||
|
{
|
||||||
|
class FileVerify
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileVerify(const char *file_name);
|
||||||
|
~FileVerify();
|
||||||
|
|
||||||
|
bool Verify(const char *data, uint32 size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
char *buffer;
|
||||||
|
uint32 size;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -17,6 +17,7 @@
|
|||||||
#include "../common/clientversions.h"
|
#include "../common/clientversions.h"
|
||||||
#include "../common/random.h"
|
#include "../common/random.h"
|
||||||
#include "../common/shareddb.h"
|
#include "../common/shareddb.h"
|
||||||
|
#include "../common/file_verify.h"
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "worlddb.h"
|
#include "worlddb.h"
|
||||||
@ -60,6 +61,11 @@
|
|||||||
std::vector<RaceClassAllocation> character_create_allocations;
|
std::vector<RaceClassAllocation> character_create_allocations;
|
||||||
std::vector<RaceClassCombos> character_create_race_class_combos;
|
std::vector<RaceClassCombos> character_create_race_class_combos;
|
||||||
|
|
||||||
|
EQEmu::FileVerify spell_verify("verify/spells_us.txt");
|
||||||
|
EQEmu::FileVerify skills_verify("verify/SkillCaps.txt");
|
||||||
|
EQEmu::FileVerify basedata_verify("verify/BaseData.txt");
|
||||||
|
EQEmu::FileVerify eqgame_verify("verify/eqgame.exe");
|
||||||
|
|
||||||
extern ZSList zoneserver_list;
|
extern ZSList zoneserver_list;
|
||||||
extern LoginServerList loginserverlist;
|
extern LoginServerList loginserverlist;
|
||||||
extern ClientList client_list;
|
extern ClientList client_list;
|
||||||
@ -952,13 +958,48 @@ bool Client::HandlePacket(const EQApplicationPacket *app) {
|
|||||||
|
|
||||||
switch(opcode)
|
switch(opcode)
|
||||||
{
|
{
|
||||||
case OP_World_Client_CRC1:
|
case OP_World_SpellFileCheck:
|
||||||
case OP_World_Client_CRC2:
|
|
||||||
{
|
{
|
||||||
// There is no obvious entry in the CC struct to indicate that the 'Start Tutorial button
|
if(spell_verify.Verify((char*)app->pBuffer, app->Size())) {
|
||||||
// is selected when a character is created. I have observed that in this case, OP_EnterWorld is sent
|
Log.Out(Logs::General, Logs::Status, "Spell file verified.");
|
||||||
// before OP_World_Client_CRC1. Therefore, if we receive OP_World_Client_CRC1 before OP_EnterWorld,
|
} else {
|
||||||
// then 'Start Tutorial' was not chosen.
|
Log.Out(Logs::General, Logs::Status, "Spell file not verified.");
|
||||||
|
}
|
||||||
|
StartInTutorial = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OP_World_SkillFileCheck:
|
||||||
|
{
|
||||||
|
if(skills_verify.Verify((char*)app->pBuffer, app->Size())) {
|
||||||
|
Log.Out(Logs::General, Logs::Status, "Skill file verified.");
|
||||||
|
} else {
|
||||||
|
Log.Out(Logs::General, Logs::Status, "Skill file not verified.");
|
||||||
|
}
|
||||||
|
StartInTutorial = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OP_World_BaseDataFileCheck:
|
||||||
|
{
|
||||||
|
if(basedata_verify.Verify((char*)app->pBuffer, app->Size())) {
|
||||||
|
Log.Out(Logs::General, Logs::Status, "BaseData file verified.");
|
||||||
|
} else {
|
||||||
|
Log.Out(Logs::General, Logs::Status, "BaseData file not verified.");
|
||||||
|
}
|
||||||
|
|
||||||
|
StartInTutorial = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OP_World_ExeFileCheck:
|
||||||
|
{
|
||||||
|
if(eqgame_verify.Verify((char*)app->pBuffer, app->Size())) {
|
||||||
|
Log.Out(Logs::General, Logs::Status, "eqgame.exe verified.");
|
||||||
|
} else {
|
||||||
|
Log.Out(Logs::General, Logs::Status, "eqgame.exe not verified.");
|
||||||
|
}
|
||||||
|
|
||||||
StartInTutorial = false;
|
StartInTutorial = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1001,14 +1042,16 @@ bool Client::HandlePacket(const EQApplicationPacket *app) {
|
|||||||
// HoT sends this to world while zoning and wants it echoed back.
|
// HoT sends this to world while zoning and wants it echoed back.
|
||||||
return HandleZoneChangePacket(app);
|
return HandleZoneChangePacket(app);
|
||||||
}
|
}
|
||||||
case OP_LoginUnknown1:
|
|
||||||
case OP_LoginUnknown2:
|
|
||||||
case OP_CrashDump:
|
case OP_CrashDump:
|
||||||
case OP_WearChange:
|
case OP_WearChange:
|
||||||
case OP_LoginComplete:
|
case OP_LoginComplete:
|
||||||
case OP_ApproveWorld:
|
case OP_ApproveWorld:
|
||||||
case OP_WorldClientReady:
|
case OP_WorldClientReady:
|
||||||
{
|
{
|
||||||
|
//char buffer[64];
|
||||||
|
//app->build_header_dump(buffer);
|
||||||
|
//Log.Out(Logs::General, Logs::Status, "%s %s", buffer, DumpPacketToString(app).c_str());
|
||||||
|
|
||||||
// Essentially we are just 'eating' these packets, indicating
|
// Essentially we are just 'eating' these packets, indicating
|
||||||
// they are handled.
|
// they are handled.
|
||||||
return true;
|
return true;
|
||||||
@ -1016,6 +1059,10 @@ bool Client::HandlePacket(const EQApplicationPacket *app) {
|
|||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
Log.Out(Logs::Detail, Logs::World_Server,"Received unknown EQApplicationPacket");
|
Log.Out(Logs::Detail, Logs::World_Server,"Received unknown EQApplicationPacket");
|
||||||
|
|
||||||
|
//char buffer[64];
|
||||||
|
//app->build_header_dump(buffer);
|
||||||
|
//Log.Out(Logs::General, Logs::Status, "%s %s", buffer, DumpPacketToString(app).c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -575,8 +575,6 @@ luabind::scope lua_register_packet_opcodes() {
|
|||||||
luabind::value("EnterWorld", static_cast<int>(OP_EnterWorld)),
|
luabind::value("EnterWorld", static_cast<int>(OP_EnterWorld)),
|
||||||
luabind::value("PostEnterWorld ", static_cast<int>(OP_PostEnterWorld )),
|
luabind::value("PostEnterWorld ", static_cast<int>(OP_PostEnterWorld )),
|
||||||
luabind::value("SendSystemStats", static_cast<int>(OP_SendSystemStats)),
|
luabind::value("SendSystemStats", static_cast<int>(OP_SendSystemStats)),
|
||||||
luabind::value("World_Client_CRC1", static_cast<int>(OP_World_Client_CRC1)),
|
|
||||||
luabind::value("World_Client_CRC2", static_cast<int>(OP_World_Client_CRC2)),
|
|
||||||
luabind::value("SetChatServer", static_cast<int>(OP_SetChatServer)),
|
luabind::value("SetChatServer", static_cast<int>(OP_SetChatServer)),
|
||||||
luabind::value("SetChatServer2", static_cast<int>(OP_SetChatServer2)),
|
luabind::value("SetChatServer2", static_cast<int>(OP_SetChatServer2)),
|
||||||
luabind::value("ZoneServerInfo", static_cast<int>(OP_ZoneServerInfo)),
|
luabind::value("ZoneServerInfo", static_cast<int>(OP_ZoneServerInfo)),
|
||||||
@ -758,8 +756,6 @@ luabind::scope lua_register_packet_opcodes() {
|
|||||||
luabind::value("AdventureLeaderboardRequest", static_cast<int>(OP_AdventureLeaderboardRequest)),
|
luabind::value("AdventureLeaderboardRequest", static_cast<int>(OP_AdventureLeaderboardRequest)),
|
||||||
luabind::value("AdventureLeaderboardReply", static_cast<int>(OP_AdventureLeaderboardReply)),
|
luabind::value("AdventureLeaderboardReply", static_cast<int>(OP_AdventureLeaderboardReply)),
|
||||||
luabind::value("SetStartCity", static_cast<int>(OP_SetStartCity)),
|
luabind::value("SetStartCity", static_cast<int>(OP_SetStartCity)),
|
||||||
luabind::value("LoginUnknown1", static_cast<int>(OP_LoginUnknown1)),
|
|
||||||
luabind::value("LoginUnknown2", static_cast<int>(OP_LoginUnknown2)),
|
|
||||||
luabind::value("ItemViewUnknown", static_cast<int>(OP_ItemViewUnknown)),
|
luabind::value("ItemViewUnknown", static_cast<int>(OP_ItemViewUnknown)),
|
||||||
luabind::value("GetGuildMOTDReply", static_cast<int>(OP_GetGuildMOTDReply)),
|
luabind::value("GetGuildMOTDReply", static_cast<int>(OP_GetGuildMOTDReply)),
|
||||||
luabind::value("SetGuildRank", static_cast<int>(OP_SetGuildRank)),
|
luabind::value("SetGuildRank", static_cast<int>(OP_SetGuildRank)),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user