Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 105 additions & 7 deletions src/EA/IO/FileStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,117 @@

#include "FileStream.h"

#include "../../core/system/Logger.h"

namespace EA::IO {
FileStream::FileStream(const std::filesystem::path &path): path(path) {

FileError MapWindowsErrorToFileError(DWORD errorCode) {
switch (errorCode) {
case ERROR_SUCCESS:
return FileError::Success;
case ERROR_INVALID_HANDLE:
return FileError::InvalidHandle;
case ERROR_OUTOFMEMORY:
case ERROR_NOT_ENOUGH_MEMORY:
return FileError::OutOfMemory;
case ERROR_FILE_NOT_FOUND:
return FileError::FileNotFound;
case ERROR_PATH_NOT_FOUND:
case ERROR_INVALID_DRIVE:
return FileError::PathNotFound;
case ERROR_ACCESS_DENIED:
return FileError::AccessDenied;
case ERROR_WRITE_PROTECT:
return FileError::WriteProtect;
case ERROR_CURRENT_DIRECTORY:
return FileError::CurrentDirectory;
case ERROR_NOT_READY:
return FileError::NotReady;
case ERROR_CRC:
return FileError::CRC;
default:
return FileError::Other;
}
}

FileStream::FileStream(const std::filesystem::path &path, const AccessFlags access_flags, const CD cd): path(path), cd(cd), accessFlags(access_flags) {
DWORD wCd = 0;
DWORD wAccess = 0;
DWORD wFileShare = 0;

switch (cd) {
case CD::CreateNew:
wCd = CREATE_NEW;
break;
case CD::CreateAlways:
wCd = CREATE_ALWAYS;
break;
case CD::OpenExisting:
wCd = OPEN_EXISTING;
break;
case CD::OpenAlways:
wCd = OPEN_ALWAYS;
break;
case CD::TruncateExisting:
wCd = TRUNCATE_EXISTING;
break;
default:
case CD::LoadAllFiles:
case CD::Default:
wCd = OPEN_EXISTING;
break;
}

switch (access_flags) {
case AccessFlags::Read:
wAccess = GENERIC_READ;
wFileShare = FILE_SHARE_READ;
break;
case AccessFlags::Write:
wAccess = GENERIC_WRITE;
wFileShare = FILE_SHARE_WRITE;
break;
case AccessFlags::ReadWrite:
wAccess = GENERIC_READ | GENERIC_WRITE;
wFileShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
break;
default:
case AccessFlags::None:
wAccess = GENERIC_READ;
wFileShare = FILE_SHARE_READ;
break;
}

hFile = CreateFileW(
path.c_str(),
GENERIC_READ,
FILE_SHARE_READ,
wAccess,
wFileShare,
nullptr,
OPEN_EXISTING,
wCd,
FILE_ATTRIBUTE_NORMAL,
nullptr
);

fileError = MapWindowsErrorToFileError(GetLastError());

if (hFile == INVALID_HANDLE_VALUE) {
MSML_LOG_ERROR("Failed to open file %s", path.string().c_str());
}
}

FileStream::FileStream(const std::filesystem::path &path): FileStream(path, AccessFlags::Read, CD::Default) {
}

uint32_t FileStream::GetType() const {
return Type;
}

AccessFlags FileStream::GetAccessFlags() const {
return (hFile != INVALID_HANDLE_VALUE) ? AccessFlags::Read : AccessFlags::None;
return (hFile != INVALID_HANDLE_VALUE) ? accessFlags : AccessFlags::None;
}

FileError FileStream::GetState() const {
return (hFile != INVALID_HANDLE_VALUE) ? FileError::Success : FileError::InvalidHandle;
return fileError;
}

bool FileStream::Close() {
Expand Down Expand Up @@ -100,6 +188,8 @@ namespace EA::IO {
if (ReadFile(hFile, pData, static_cast<DWORD>(nSize), &bytesRead, nullptr))
return bytesRead;

fileError = MapWindowsErrorToFileError(GetLastError());

return -1;
}

Expand All @@ -109,7 +199,15 @@ namespace EA::IO {
}

size_t FileStream::Write(const void *pData, size_t nSize) {
return 0;
if (hFile == INVALID_HANDLE_VALUE || pData == nullptr) return -1;

DWORD bytesWritten = 0;
if (WriteFile(hFile, pData, static_cast<DWORD>(nSize), &bytesWritten, nullptr))
return bytesWritten;

fileError = MapWindowsErrorToFileError(GetLastError());

return -1;
}

std::filesystem::path FileStream::GetPath() {
Expand Down
4 changes: 4 additions & 0 deletions src/EA/IO/FileStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ namespace EA::IO {
class FileStream final : public IStream {
std::filesystem::path path;
HANDLE hFile = INVALID_HANDLE_VALUE;
CD cd = CD::Default;
AccessFlags accessFlags = AccessFlags::None;
FileError fileError = FileError::Success;

public:
static constexpr uint32_t Type = 0xb7faadfe;
FileStream(const std::filesystem::path &path, AccessFlags access_flags, CD cd);
explicit FileStream(const std::filesystem::path &path);

[[nodiscard]] uint32_t GetType() const override;
Expand Down
18 changes: 18 additions & 0 deletions src/EA/IO/IStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,24 @@ namespace EA::IO {
stream_name->Write((str), sizeof(char) * strlen(str)); \
} while (0)

#define WRITE_LEN_STRING(stream_name, str) \
do { \
WRITE_VALUE(stream_name, uint32_t, sizeof(char) * strlen(str)); \
stream_name->Write((str), sizeof(char) * strlen(str)); \
} while (0)

#define READ_LEN_STRING(stream_name, out_str) \
do { \
uint32_t __len = 0; \
stream_name->Read(&__len, sizeof(uint32_t)); \
if (__len > 0) { \
(out_str).resize(__len); \
stream_name->Read(&(out_str)[0], __len); \
} else { \
(out_str).clear(); \
} \
} while (0)

#define READ_CSTRING(stream_name, str) \
do { \
std::vector<char> _tmp_str; \
Expand Down
3 changes: 3 additions & 0 deletions src/core/hooks/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@

#include "Hooks.h"
#include "MinHook.h"
#include "../modloader/ModLoader.h"
#include "../system/Logger.h"

namespace msml::core::Hooks {
void Install(void* target, void *detour, void** original) {
if (target == nullptr) {
MSML_LOG_ERROR("Failed to install hook");
ModLoader::SoftCrash();
}

if (MH_CreateHook(target, detour, original) != MH_OK) {
MSML_LOG_ERROR("Failed to install hook");
ModLoader::SoftCrash();
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/modloader/ModLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ namespace msml::core {

void ModLoader::SoftCrash() {
MessageBox(nullptr, "The application is going to crash, check the logs.", "ModLoader::SoftCrash", 1);
exit(0);
exit(1);
}

ModLoader::ModLoader() {
Expand Down
96 changes: 48 additions & 48 deletions src/core/signatures/Signatures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,17 @@

#include "windows.h"
#include "sigdef.h"
#include "../../Version.h"
#include "../../EA/IO/FileStream.h"
#include "../../EA/IO/MemoryStream.h"
#include "../../include/hash_sha256.h"
#include "../system/Logger.h"
#include "../util/StreamUtil.h"

namespace msml::core {

static constexpr uint32_t SIGNATURE_VERSION = 0;

Signatures & Signatures::GetInstance() {
static Signatures signatures;
return signatures;
Expand Down Expand Up @@ -48,7 +53,7 @@ namespace msml::core {
return false;
}

void Signatures::Append(std::string name, SigSearchBase* sig){
void Signatures::Append(const std::string& name, SigSearchBase* sig){
signatures.emplace(name, sig);
}

Expand All @@ -72,16 +77,16 @@ namespace msml::core {
bool Signatures::SearchAll() {
const auto start = std::chrono::high_resolution_clock::now();

if (!LoadDatabase()) {
for(const auto &val: signatures | std::views::values) {
if (!val->Search()) {
return false;
}
LoadDatabase();

for(const auto &val: signatures | std::views::values) {
if (val->GetAddress() == nullptr && !val->Search()) {
return false;
}
}

auto elapsed = std::chrono::high_resolution_clock::now() - start;
double elapsed_ms = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count() / 1000.0;
const auto elapsed = std::chrono::high_resolution_clock::now() - start;
const double elapsed_ms = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count() / 1000.0;
MSML_LOG_INFO("Search time: %.3f milliseconds", elapsed_ms);

SaveDatabase();
Expand All @@ -94,83 +99,78 @@ namespace msml::core {
context = target.in_module("MySims.exe");
}

#define READ_BIN(var) infile.read((char*)&var, sizeof(var));
#define WRITE_BIN(var) outfile.write((char*)&var, sizeof(var))

#define SIGCACHE_DB_NAME "sigcache.db"

bool Signatures::LoadDatabase() {
#ifndef NDEBUG
return false;
#endif
const auto stream = new EA::IO::FileStream("signatures.db");

uint32_t sig_version = UINT32_MAX;
READ(stream, sig_version);

std::ifstream infile(SIGCACHE_DB_NAME, std::ios::in | std::ios::binary);
if (!infile.good()) {
MSML_LOG_ERROR("Failed to open sigcache");
if (sig_version != SIGNATURE_VERSION) {
return false;
}

std::string msml_version;
READ_LEN_STRING(stream, msml_version);

std::array<uint8_t, 32U> checksum{};
for (auto i = 0; i < 32U; i++) {
READ_BIN(checksum[i]);
READ(stream, checksum[i]);
}

if (std::array<uint8_t, 32U> currentChecksum = GetCheckSum(); checksum != currentChecksum) {
if (const std::array<uint8_t, 32U> currentChecksum = GetCheckSum(); checksum != currentChecksum) {
MSML_LOG_ERROR("Checksum mismatch, searching for new signatures");
return false;
}

uint32_t sigCount;
READ_BIN(sigCount);
for (uint32_t i = 0; i < sigCount; i++) {
uint32_t length;
READ_BIN(length);

char name[1024];
infile.read(name, length);
READ(stream, sigCount);

auto name_str = std::string(name, length);
for (int i =0; i < sigCount; i++) {
std::string sig_name;
READ_LEN_STRING(stream, sig_name);
uint64_t address;
READ(stream, address);

uintptr_t addr;
READ_BIN(addr);

if (signatures.contains(name_str)) {
signatures[name_str]->ApplyAddress(reinterpret_cast<void *>(addr));
if (signatures.contains(sig_name)) {
signatures[sig_name]->ApplyAddress(reinterpret_cast<void *>(address));
} else {
MSML_LOG_ERROR("Failed to find signatures with name %s", name_str);
MSML_LOG_ERROR("Failed to find signatures with name %s", sig_name.c_str());
return false;
}
}

MSML_LOG_INFO("Read %d signatures from signatures.db", sigCount);

stream->Close();

return true;
}

void Signatures::SaveDatabase() {
void Signatures::SaveDatabase() const {
#ifndef NDEBUG
return;
#endif
const auto stream = new EA::IO::FileStream("signatures.db", EA::IO::AccessFlags::Write, EA::IO::CD::CreateAlways);

std::ofstream outfile(SIGCACHE_DB_NAME, std::ios::out | std::ios::binary);

std::array<uint8_t, 32U> checksum = GetCheckSum();
size_t count = signatures.size();
WRITE(stream, SIGNATURE_VERSION);
WRITE_LEN_STRING(stream, MSML_VERSION);

const std::array<uint8_t, 32U> checksum = GetCheckSum();
for (auto i = 0; i < 32U; i++) {
WRITE_BIN(checksum[i]);
WRITE(stream, checksum[i]);
}
WRITE_BIN(count);

for (const auto &sig: signatures) {
std::string name = sig.first;
size_t length = name.length();
auto addr = reinterpret_cast<uintptr_t>(sig.second->GetAddress());

WRITE_BIN(length);
outfile.write(name.c_str(), length);
WRITE_BIN(addr);
WRITE_VALUE(stream, uint32_t, signatures.size());
for (const auto& signature : signatures) {
WRITE_LEN_STRING(stream, signature.first.c_str());
WRITE_VALUE(stream, uint64_t, reinterpret_cast<uint64_t>(signature.second->GetAddress()));
}

MSML_LOG_INFO("Signature cache saved");

outfile.close();
stream->Close();
}
}
Loading
Loading