Skip to content
Merged
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
2 changes: 1 addition & 1 deletion src/memory/all.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
#include "handle.hpp"
#include "module.hpp"
#include "pattern.hpp"
#include "pattern_batch.hpp"
#include "batch.hpp"
#include "range.hpp"
78 changes: 78 additions & 0 deletions src/memory/batch.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include "batch.hpp"

#include "common.hpp"
#include "range.hpp"
#include "util/is_enhanced.hpp"

#include <future>//std::async

static std::mutex s_entry_mutex;
static std::vector<std::future<bool>> g_futures;

namespace memory
{
void batch::add(std::string name, pattern pattern, std::function<void(handle)> callback)
{
m_entries.emplace_back(std::move(name), std::move(pattern), std::move(callback));
}
void batch::add(std::string name, pattern pattern, int min_version, int max_version, eGameBranch game_branch, std::function<void(memory::handle)> callback)
{
m_entries.emplace_back(std::move(name), std::move(pattern), min_version, max_version, game_branch, std::move(callback));
}

bool scan_pattern_and_execute_callback(range region, memory::batch::entry entry)
{
if (auto result = region.scan(entry.m_pattern))
{
if (entry.m_callback)
{
std::lock_guard<std::mutex> lock(s_entry_mutex);// Acquire a lock on the mutex to synchronize access.

std::invoke(std::move(entry.m_callback), *result);
LOG(INFO) << "Found '" << entry.m_name << "' GTA5.exe+"
<< HEX_TO_UPPER(result->as<DWORD64>() - region.begin().as<DWORD64>());

return true;
}
}

LOG(WARNING) << "Failed to find '" << entry.m_name << "'.";

return false;
}

bool batch::run(range region)
{
for (auto& entry : m_entries)
{
if (entry.m_game_branch != eGameBranch::DontCare && entry.m_game_branch != big::get_game_branch())
{
continue;
}
if (entry.m_min_version != -1 && entry.m_min_version > big::g_game_version) // g_game_version is not implemented
{
continue;
}
if (entry.m_max_version != -1 && entry.m_max_version < big::g_game_version)
{
continue;
}

g_futures.emplace_back(std::async(&scan_pattern_and_execute_callback, region, entry));
}

bool found_all_patterns = true;
for (auto& future : g_futures)
{
future.wait();

if (!future.get())
found_all_patterns = false;
}

m_entries.clear();
g_futures.clear();

return found_all_patterns;
}
}
18 changes: 14 additions & 4 deletions src/memory/pattern_batch.hpp → src/memory/batch.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/**
* @file batch.hpp
*
* @copyright GNU General Public License Version 2.
* This file is part of YimMenu.
* YimMenu is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
* YimMenu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with YimMenu. If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once
#include "pattern.hpp"

Expand All @@ -6,15 +16,15 @@

namespace memory
{
class pattern_batch
class batch
{
public:
explicit pattern_batch() = default;
~pattern_batch() noexcept = default;
explicit batch() = default;
~batch() noexcept = default;

void add(std::string name, pattern pattern, std::function<void(memory::handle)> callback);
void add(std::string name, pattern pattern, int min_version, int max_version, eGameBranch game_branch, std::function<void(memory::handle)> callback);
void run(range region);
bool run(range region);

struct entry
{
Expand Down
2 changes: 1 addition & 1 deletion src/memory/fwddec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ namespace memory
class range;
class module;
class pattern;
class pattern_batch;
class batch;
}
34 changes: 22 additions & 12 deletions src/memory/handle.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/**
* @file handle.hpp
*
* @copyright GNU General Public License Version 2.
* This file is part of YimMenu.
* YimMenu is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
* YimMenu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with YimMenu. If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once
#include <cstddef>
#include <cstdint>
Expand All @@ -12,21 +22,21 @@ namespace memory
explicit handle(std::uintptr_t ptr);

template<typename T>
std::enable_if_t<std::is_pointer_v<T>, T> as();
std::enable_if_t<std::is_pointer_v<T>, T> as() const;

template<typename T>
std::enable_if_t<std::is_lvalue_reference_v<T>, T> as();
std::enable_if_t<std::is_lvalue_reference_v<T>, T> as() const;

template<typename T>
std::enable_if_t<std::is_same_v<T, std::uintptr_t>, T> as();
std::enable_if_t<std::is_same_v<T, std::uintptr_t>, T> as() const;

template<typename T>
handle add(T offset);
handle add(T offset) const;

template<typename T>
handle sub(T offset);
handle sub(T offset) const;

handle rip();
handle rip() const;

explicit operator bool();

Expand All @@ -48,36 +58,36 @@ namespace memory
}

template<typename T>
inline std::enable_if_t<std::is_pointer_v<T>, T> handle::as()
inline std::enable_if_t<std::is_pointer_v<T>, T> handle::as() const
{
return reinterpret_cast<T>(ptr);
}

template<typename T>
inline std::enable_if_t<std::is_lvalue_reference_v<T>, T> handle::as()
inline std::enable_if_t<std::is_lvalue_reference_v<T>, T> handle::as() const
{
return *static_cast<std::add_pointer_t<std::remove_reference_t<T>>>(ptr);
}

template<typename T>
inline std::enable_if_t<std::is_same_v<T, std::uintptr_t>, T> handle::as()
inline std::enable_if_t<std::is_same_v<T, std::uintptr_t>, T> handle::as() const
{
return reinterpret_cast<std::uintptr_t>(ptr);
}

template<typename T>
inline handle handle::add(T offset)
inline handle handle::add(T offset) const
{
return handle(as<std::uintptr_t>() + offset);
}

template<typename T>
inline handle handle::sub(T offset)
inline handle handle::sub(T offset) const
{
return handle(as<std::uintptr_t>() - offset);
}

inline handle handle::rip()
inline handle handle::rip() const
{
return add(as<std::int32_t&>()).add(4);
}
Expand Down
97 changes: 48 additions & 49 deletions src/memory/pattern.cpp
Original file line number Diff line number Diff line change
@@ -1,72 +1,71 @@
/**
* @file pattern.cpp
*
* @copyright GNU General Public License Version 2.
* This file is part of YimMenu.
* YimMenu is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
* YimMenu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with YimMenu. If not, see <https://www.gnu.org/licenses/>.
*/

#include "pattern.hpp"

#include "common.hpp"

namespace memory
{
pattern::pattern(std::string_view ida_sig)
std::optional<uint8_t> to_hex(char const c)
{
auto to_upper = [](char c) -> char {
return c >= 'a' && c <= 'z' ? static_cast<char>(c + ('A' - 'a')) : static_cast<char>(c);
};

auto to_hex = [&](char c) -> std::optional<std::uint8_t> {
switch (to_upper(c))
{
case '0': return static_cast<std::uint8_t>(0);
case '1': return static_cast<std::uint8_t>(1);
case '2': return static_cast<std::uint8_t>(2);
case '3': return static_cast<std::uint8_t>(3);
case '4': return static_cast<std::uint8_t>(4);
case '5': return static_cast<std::uint8_t>(5);
case '6': return static_cast<std::uint8_t>(6);
case '7': return static_cast<std::uint8_t>(7);
case '8': return static_cast<std::uint8_t>(8);
case '9': return static_cast<std::uint8_t>(9);
case 'A': return static_cast<std::uint8_t>(10);
case 'B': return static_cast<std::uint8_t>(11);
case 'C': return static_cast<std::uint8_t>(12);
case 'D': return static_cast<std::uint8_t>(13);
case 'E': return static_cast<std::uint8_t>(14);
case 'F': return static_cast<std::uint8_t>(15);
default: return std::nullopt;
}
};
switch (c)
{
case '0': return static_cast<uint8_t>(0x0);
case '1': return static_cast<uint8_t>(0x1);
case '2': return static_cast<uint8_t>(0x2);
case '3': return static_cast<uint8_t>(0x3);
case '4': return static_cast<uint8_t>(0x4);
case '5': return static_cast<uint8_t>(0x5);
case '6': return static_cast<uint8_t>(0x6);
case '7': return static_cast<uint8_t>(0x7);
case '8': return static_cast<uint8_t>(0x8);
case '9': return static_cast<uint8_t>(0x9);
case 'a': return static_cast<uint8_t>(0xa);
case 'b': return static_cast<uint8_t>(0xb);
case 'c': return static_cast<uint8_t>(0xc);
case 'd': return static_cast<uint8_t>(0xd);
case 'e': return static_cast<uint8_t>(0xe);
case 'f': return static_cast<uint8_t>(0xf);
case 'A': return static_cast<uint8_t>(0xA);
case 'B': return static_cast<uint8_t>(0xB);
case 'C': return static_cast<uint8_t>(0xC);
case 'D': return static_cast<uint8_t>(0xD);
case 'E': return static_cast<uint8_t>(0xE);
case 'F': return static_cast<uint8_t>(0xF);
default: return std::nullopt;
}
}

for (std::size_t i = 0; i < ida_sig.size(); ++i)
pattern::pattern(std::string_view ida_sig)
{
const auto size_minus_one = ida_sig.size() - 1;
m_bytes.reserve(size_minus_one / 2);
for (size_t i = 0; i != size_minus_one; ++i)
{
if (ida_sig[i] == ' ')
continue;

bool last = (i == ida_sig.size() - 1);
if (ida_sig[i] != '?')
{
if (!last)
auto c1 = to_hex(ida_sig[i]);
auto c2 = to_hex(ida_sig[i + 1]);
if (c1 && c2)
{
auto c1 = to_hex(ida_sig[i]);
auto c2 = to_hex(ida_sig[i + 1]);

if (c1 && c2)
{
m_bytes.emplace_back(static_cast<std::uint8_t>((*c1 * 0x10) + *c2));
}
m_bytes.emplace_back(static_cast<uint8_t>((*c1 * 0x10) + *c2));
}
}
else
{
m_bytes.push_back(std::nullopt);
m_bytes.push_back({});
}
}
}

pattern::pattern(const void* bytes, std::string_view mask)
{
for (std::size_t i = 0; i < mask.size(); ++i)
{
if (mask[i] != '?')
m_bytes.emplace_back(static_cast<const std::uint8_t*>(bytes)[i]);
else
m_bytes.push_back(std::nullopt);
}
}
}
5 changes: 2 additions & 3 deletions src/memory/pattern.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,17 @@ namespace memory
{
class pattern
{
friend pattern_batch;
friend batch;
friend range;

public:
pattern(std::string_view ida_sig);
explicit pattern(const void* bytes, std::string_view mask);

inline pattern(const char* ida_sig) :
pattern(std::string_view(ida_sig))
{
}

std::vector<std::optional<std::uint8_t>> m_bytes;
std::vector<std::optional<uint8_t>> m_bytes;
};
}
Loading