Json added and necessary changes (#522)

* Fixed parameter error for x64 architecture.

* code cleanup and a few edits

* libcef library added

* Json added and necessary changes

* Update README.md

* Update README.md

* some fixes in json code

* added "contains" function to json class

* Added Install-VcRedist function

* MemoryScanner updated and some changes in code

---------

Co-authored-by: Yolilad <Yolilad@>
This commit is contained in:
Yolilad 2024-03-29 08:13:56 +03:00 committed by GitHub
parent 1992deedc0
commit 7fa48859e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 2454 additions and 1050 deletions

View file

@ -5,8 +5,8 @@
<h4 align="center">A multi-purpose adblocker and skip-bypass for the <strong>Spotify for Windows (64 bit)</strong> </h4> <h4 align="center">A multi-purpose adblocker and skip-bypass for the <strong>Spotify for Windows (64 bit)</strong> </h4>
<h5 align="center">Please support Spotify by purchasing premium</h5> <h5 align="center">Please support Spotify by purchasing premium</h5>
<p align="center"> <p align="center">
<strong>Last updated:</strong> 14 February 2024<br> <strong>Last updated:</strong> 18 March 2024<br>
<strong>Last tested version:</strong> Spotify for Windows (64 bit) 1.2.31.1205.g4d59ad7c <strong>Last tested version:</strong> Spotify for Windows (64 bit) 1.2.33.1039.g8ddb5918
</p> </p>
</center> </center>
@ -61,6 +61,17 @@ rm -fo $env:APPDATA\spotify\dpapi.dll
rm -fo $env:APPDATA\spotify\config.ini rm -fo $env:APPDATA\spotify\config.ini
``` ```
### Disabling Automatic Updates
The automatic update feature is enabled by default. To disable it:
1. Navigate to the directory where Spotify is installed: `%APPDATA%\Spotify`.
2. Open the `config.ini` file.
3. Set `Enable_Auto_Update` to `0` under the `[Config]` section.
4. Save your changes and close the file.
Automatic updates will now be disabled. If you wish to update, you'll need to do so manually.
### Additional Notes: ### Additional Notes:
* Installation script automatically detects if your Spotify client version is supported, or not. If the version is not supported, you will be prompted to update your Spotify client. To enforce client update, supply an optional parameter `UpdateSpotify` to the installation script. * Installation script automatically detects if your Spotify client version is supported, or not. If the version is not supported, you will be prompted to update your Spotify client. To enforce client update, supply an optional parameter `UpdateSpotify` to the installation script.

View file

@ -0,0 +1,96 @@
{
"Cef Offsets": {
"x64": {
"cef_request_t_get_url": 48,
"cef_zip_reader_t_get_file_name": 72,
"cef_zip_reader_t_read_file": 112
},
"x32": {
"cef_request_t_get_url": 24,
"cef_zip_reader_t_get_file_name": 36,
"cef_zip_reader_t_read_file": 56
}
},
"Developer": {
"x64": {
"Signature": "80 E3 01 48 8B 95 ?? ?? ?? ?? 48 83 FA 10",
"Value": "B3 01 90",
"Offset": 0,
"Address": 0
},
"x32": {
"Signature": "25 01 FF FF FF 89 ?? ?? ?? FF FF",
"Value": "B8 03 00",
"Offset": 0,
"Address": 0
}
},
"Zip Reader": {
"home-hpto.css": {
"hptocss": {
"Signature": ".WiPggcPDzbwGxoxwLWFf{display:-webkit-box;display:-ms-flexbox;display:flex;",
"Value": ".WiPggcPDzbwGxoxwLWFf{display:-webkit-box;display:-ms-flexbox;display:none;",
"Offset": 0,
"Fill": 0,
"Address": 0
}
},
"xpui.js": {
"adsEnabled": {
"Signature": "adsEnabled:!0",
"Value": "1",
"Offset": 12,
"Fill": 0,
"Address": 0
},
"ishptohidden": {
"Signature": "isHptoHidden:!0",
"Value": "1",
"Offset": 14,
"Fill": 0,
"Address": 0
},
"sponsorship": {
"Signature": ".set(\"allSponsorships\",t.sponsorships)}}(e,t);",
"Value": "\"",
"Offset": 5,
"Fill": 15,
"Address": 0
},
"skipsentry": {
"Signature": "sentry.io",
"Value": "localhost",
"Offset": 0,
"Fill": 0,
"Address": 0
},
"hptoEnabled": {
"Signature": "hptoEnabled:!0",
"Value": "1",
"Offset": 13,
"Fill": 0,
"Address": 0
},
"sp_localhost": {
"Signature": "sp://ads/v1/ads/",
"Value": "sp://localhost//",
"Offset": 0,
"Fill": 0,
"Address": 0
},
"premium_free": {
"Signature": "e.session?.productState?.catalogue?.toLowerCase()",
"Value": "\"\"",
"Offset": -1,
"Fill": 48,
"Address": 0
}
}
},
"Block List": [
"/ads/",
"/ad-logic/",
"/gabo-receiver-service/"
],
"Latest Release Date": ""
}

View file

@ -2,5 +2,6 @@
Block_Ads=1 Block_Ads=1
Block_Banner=1 Block_Banner=1
Enable_Developer=1 Enable_Developer=1
Enable_Auto_Update=1
;Log system ;Log system
Enable_Log=0 Enable_Log=0

View file

@ -265,6 +265,31 @@ $patchFiles = (Join-Path -Path $PWD -ChildPath 'dpapi.dll'), (Join-Path -Path $P
Copy-Item -LiteralPath $patchFiles -Destination "$spotifyDirectory" Copy-Item -LiteralPath $patchFiles -Destination "$spotifyDirectory"
function Install-VcRedist {
# https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170
$vcRedistX86Url = "https://aka.ms/vs/17/release/vc_redist.x86.exe"
$vcRedistX64Url = "https://aka.ms/vs/17/release/vc_redist.x64.exe"
if ([Environment]::Is64BitOperatingSystem) {
if (!(Test-Path 'HKLM:\Software\Microsoft\VisualStudio\14.0\VC\Runtimes\x64')) {
$vcRedistX64File = Join-Path -Path $PWD -ChildPath 'vc_redist.x64.exe'
Write-Host "Downloading and installing vc_redist.x64.exe..."
Get-File -Uri $vcRedistX64Url -TargetFile $vcRedistX64File
Start-Process -FilePath $vcRedistX64File -ArgumentList "/install /quiet /norestart" -Wait
}
}
else {
if (!(Test-Path 'HKLM:\Software\Microsoft\VisualStudio\14.0\VC\Runtimes\x86')) {
$vcRedistX86File = Join-Path -Path $PWD -ChildPath 'vc_redist.x86.exe'
Write-Host "Downloading and installing vc_redist.x86.exe..."
Get-File -Uri $vcRedistX86Url -TargetFile $vcRedistX86File
Start-Process -FilePath $vcRedistX86File -ArgumentList "/install /quiet /norestart" -Wait
}
}
}
Install-VcRedist
$tempDirectory = $PWD $tempDirectory = $PWD
Pop-Location Pop-Location

551
src/BasicUtils/Json.cpp Normal file
View file

@ -0,0 +1,551 @@
#include "Json.h"
#include "Utils.h"
#include "Logger.h"
#include <sstream>
#include <cwctype>
#include <iomanip>
Json& Json::operator[](const std::wstring& key)
{
if (auto* object_ptr = std::get_if<Object>(&m_value)) {
auto it = object_ptr->find(key);
if (it != object_ptr->end()) {
return it->second;
}
return (*object_ptr)[key];
}
m_value = Object();
return std::get<Object>(m_value)[key];
}
Json& Json::operator[](size_t index)
{
return at(index);
}
Json& Json::operator=(std::initializer_list<std::pair<std::wstring, Json>> list)
{
m_value = Object(list.begin(), list.end());
return *this;
}
Json& Json::operator=(std::initializer_list<Value> list)
{
m_value = Array(list.begin(), list.end());
return *this;
}
std::wostream& operator<<(std::wostream& os, const Json& json)
{
std::wostringstream oss;
json.dump_impl(oss, 0, 0);
os << oss.str();
return os;
}
std::wistream& operator>>(std::wistream& is, Json& json)
{
json = Json::parse(is);
return is;
}
bool operator==(const Json& lhs, const Json& rhs)
{
return lhs.m_value == rhs.m_value;
}
bool operator!=(const Json& lhs, const Json& rhs)
{
return !(lhs == rhs);
}
Json::Object::iterator Json::begin()
{
if (is_object()) {
return std::get<Object>(m_value).begin();
}
throw std::runtime_error("Json value is not an object");
}
Json::Object::const_iterator Json::begin() const
{
return const_cast<Json*>(this)->begin();
}
Json::Object::iterator Json::end()
{
if (is_object()) {
return std::get<Object>(m_value).end();
}
throw std::runtime_error("Json value is not an object");
}
Json::Object::const_iterator Json::end() const
{
return const_cast<Json*>(this)->end();
}
Json::Object::iterator Json::find(const std::wstring& key)
{
if (is_object()) {
return std::get<Object>(m_value).find(key);
}
throw std::runtime_error("Json value is not an object");
}
Json::Object::const_iterator Json::find(const std::wstring& key) const
{
return const_cast<Json*>(this)->find(key);
}
//Json::Array::iterator Json::begin()
//{
// if (is_array()) {
// return std::get<Array>(m_value).begin();
// }
// throw std::runtime_error("Json value is not an array");
//}
//
//Json::Array::iterator Json::end()
//{
// if (is_array()) {
// return std::get<Array>(m_value).end();
// }
// throw std::runtime_error("Json value is not an array");
//}
bool Json::is_null() const
{
return std::holds_alternative<nullptr_t>(m_value);
}
bool Json::is_integer() const
{
return std::holds_alternative<int>(m_value);
}
bool Json::is_float() const
{
return std::holds_alternative<float>(m_value);
}
bool Json::is_double() const
{
return std::holds_alternative<double>(m_value);
}
bool Json::is_boolean() const
{
return std::holds_alternative<bool>(m_value);
}
bool Json::is_string() const
{
return std::holds_alternative<std::wstring>(m_value);
}
bool Json::is_object() const
{
return std::holds_alternative<Object>(m_value);
}
bool Json::is_array() const
{
return std::holds_alternative<Array>(m_value);
}
int Json::get_integer() const
{
if (std::holds_alternative<int>(m_value)) {
return std::get<int>(m_value);
}
Log(L"JSON value is not an integer", LogLevel::Error);
return 0;
}
float Json::get_float() const
{
if (std::holds_alternative<float>(m_value)) {
return std::get<float>(m_value);
}
Log(L"JSON value is not an float", LogLevel::Error);
return 0.0f;
}
double Json::get_double() const
{
if (std::holds_alternative<double>(m_value)) {
return std::get<double>(m_value);
}
Log(L"JSON value is not a double", LogLevel::Error);
return 0.0;
}
bool Json::get_boolean() const
{
if (std::holds_alternative<bool>(m_value)) {
return std::get<bool>(m_value);
}
Log(L"JSON value is not a boolean", LogLevel::Error);
return false;
}
std::wstring Json::get_string() const
{
if (std::holds_alternative<std::wstring>(m_value)) {
return std::get<std::wstring>(m_value);
}
Log(L"JSON value is not a string", LogLevel::Error);
return L"";
}
Json::Object Json::get_object() const
{
if (std::holds_alternative<Object>(m_value)) {
return std::get<Object>(m_value);
}
Log(L"JSON value is not an object", LogLevel::Error);
return Object();
}
Json::Array Json::get_array() const
{
if (std::holds_alternative<Array>(m_value)) {
return std::get<Array>(m_value);
}
Log(L"JSON value is not an array", LogLevel::Error);
return Array();
}
Json& Json::at(const std::wstring& key)
{
if (auto* object_ptr = std::get_if<Object>(&m_value)) {
auto it = object_ptr->find(key);
if (it != object_ptr->end()) {
return it->second;
}
throw std::out_of_range("Key not found in JSON object");
}
throw std::runtime_error("Trying to access key in non-object JSON value");
}
const Json& Json::at(const std::wstring& key) const
{
return const_cast<Json&>(*this).at(key);
}
Json& Json::at(std::size_t index)
{
if (auto* array_ptr = std::get_if<Array>(&m_value)) {
if (index < array_ptr->size()) {
return (*array_ptr)[index];
}
throw std::out_of_range("Index out of range in JSON array");
}
throw std::out_of_range("Trying to access index in non-array JSON value");
}
const Json& Json::at(std::size_t index) const
{
return const_cast<Json&>(*this).at(index);
}
void Json::clear()
{
if (std::holds_alternative<Object>(m_value)) {
std::get<Object>(m_value).clear();
}
else if (std::holds_alternative<Array>(m_value)) {
std::get<Array>(m_value).clear();
}
}
bool Json::empty() const
{
if (std::holds_alternative<Object>(m_value)) {
return std::get<Object>(m_value).empty();
}
else if (std::holds_alternative<Array>(m_value)) {
return std::get<Array>(m_value).empty();
}
else if (std::holds_alternative<nullptr_t>(m_value)) {
return true;
}
return false;
}
std::size_t Json::size() const
{
if (std::holds_alternative<Object>(m_value)) {
return std::get<Object>(m_value).size();
}
else if (std::holds_alternative<Array>(m_value)) {
return std::get<Array>(m_value).size();
}
return 0;
}
bool Json::contains(const std::wstring& key) const
{
if (is_object()) {
const auto& object = std::get<Object>(m_value);
return object.find(key) != object.end();
}
return false;
}
std::wstring Json::dump(int indent) const
{
std::wostringstream os;
dump_impl(os, indent, indent);
return os.str();
}
void Json::dump_impl(std::wostream& os, int indent, int step) const
{
std::visit([&os, indent, step](const auto& value) {
if constexpr (std::is_same_v<std::decay_t<decltype(value)>, Object>) {
os << (indent == 0 ? L"{" : L"{\n");
bool first = true;
for (const auto& [key, val] : value) {
if (!first) {
os << (indent == 0 ? L", " : L",\n");
}
first = false;
os << std::wstring(indent, L' ') << L"\"" << key << L"\": ";
val.dump_impl(os, indent + step, step);
}
os << (indent == 0 ? L"}" : L"\n" + std::wstring(indent - step, L' ') + L"}");
}
else if constexpr (std::is_same_v<std::decay_t<decltype(value)>, Array>) {
os << (indent == 0 ? L"[" : L"[\n");
bool first = true;
for (const auto& val : value) {
if (!first) {
os << (indent == 0 ? L", " : L",\n");
}
first = false;
if (indent != 0)
os << std::wstring(indent, L' ');
val.dump_impl(os, indent + step, step);
}
os << (indent == 0 ? L"]" : L"\n" + std::wstring(indent - step, L' ') + L"]");
}
else {
if constexpr (std::is_same_v<std::decay_t<decltype(value)>, std::wstring>)
os << std::quoted(value);
else if constexpr (std::is_same_v<std::decay_t<decltype(value)>, bool>)
os << (value ? L"true" : L"false");
else if constexpr (std::is_same_v<std::decay_t<decltype(value)>, std::nullptr_t>)
os << L"null";
else
os << value;
}
}, m_value);
}
Json Json::parse(const std::wstring& json_text)
{
std::wistringstream iss(json_text);
return parse(iss);
}
Json Json::parse(std::wistream& is)
{
try {
wchar_t ch;
is >> ch;
is.unget();
if (ch == L'{') {
return parse_object(is);
}
else if (ch == L'[') {
return parse_array(is);
}
else if (ch == L'"') {
return parse_string(is);
}
else if (ch == L'-' || std::iswdigit(ch)) {
return parse_number(is);
}
else if (ch == L't' || ch == L'f') {
return parse_boolean(is);
}
else if (ch == L'n') {
return parse_null(is);
}
else {
throw std::runtime_error("Invalid JSON");
}
}
catch (const std::exception& e) {
Log(Utils::FormatString(L"{}", e.what()), LogLevel::Error);
return Json();
}
}
Json::Object Json::parse_object(std::wistream& is)
{
Object result;
wchar_t ch;
is >> ch;
while (is >> ch) {
if (ch == L'}') {
return result;
}
is.unget();
std::wstring key = parse_string(is);
is >> ch;
if (ch != L':') {
throw std::runtime_error("Expected ':' in JSON object");
}
Json value = parse(is);
result[key] = value;
is >> ch;
if (ch == L'}') {
return result;
}
else if (ch != L',') {
throw std::runtime_error("Expected ',' or '}' in JSON object");
}
}
throw std::runtime_error("Unexpected end of JSON object");
}
Json::Array Json::parse_array(std::wistream& is)
{
Array result;
wchar_t ch;
is >> ch;
while (is >> ch) {
if (ch == L']') {
return result;
}
is.unget();
Json value = parse(is);
result.push_back(value);
is >> ch;
if (ch == L']') {
return result;
}
else if (ch != L',') {
throw std::runtime_error("Expected ',' or ']' in JSON array");
}
}
throw std::runtime_error("Unexpected end of JSON array");
}
std::wstring Json::parse_string(std::wistream& is)
{
std::wstring result;
wchar_t ch;
is >> std::ws;
if (!(is >> ch) || ch != L'"') {
throw std::runtime_error("Expected opening quote in JSON string");
}
while (is.get(ch)) {
if (ch == L'\\') {
if (!(is.get(ch))) {
throw std::runtime_error("Unexpected end of JSON string");
}
switch (ch) {
case L'"': result += L'"'; break;
case L'\\': result += L'\\'; break;
case L'/': result += L'/'; break;
case L'b': result += L'\b'; break;
case L'f': result += L'\f'; break;
case L'n': result += L'\n'; break;
case L'r': result += L'\r'; break;
case L't': result += L'\t'; break;
case L'u': {
std::wstring hex_code;
for (int i = 0; i < 4; ++i) {
if (!(is.get(ch))) {
throw std::runtime_error("Incomplete Unicode escape sequence in JSON string");
}
hex_code += ch;
}
wchar_t unicode_char = static_cast<wchar_t>(std::stoi(hex_code, nullptr, 16));
result += unicode_char;
break;
}
default: throw std::runtime_error("Invalid JSON string escape sequence");
}
}
else if (ch == L'"') {
break;
}
else {
result += ch;
}
}
if (ch != L'"') {
throw std::runtime_error("Unexpected end of JSON string");
}
return result;
}
Json Json::parse_number(std::wistream& is)
{
wchar_t ch;
std::wstring number_str;
while (is >> ch && (std::iswdigit(ch) || ch == L'.' || ch == L'e' || ch == L'E' || ch == L'+' || ch == L'-')) {
number_str += ch;
}
is.unget();
std::wistringstream number_iss(number_str);
double number;
number_iss >> number;
if (number_iss.fail() || !number_iss.eof()) {
throw std::runtime_error("Invalid JSON number");
}
if (number_str.find(L'.') != std::wstring::npos || number_str.find(L'e') != std::wstring::npos || number_str.find(L'E') != std::wstring::npos) {
return number;
}
else {
return static_cast<int>(number);
}
}
Json Json::parse_boolean(std::wistream& is)
{
std::wstring boolean_str;
wchar_t ch;
for (int i = 0; i < 5; ++i) {
if (!(is.get(ch))) {
throw std::runtime_error("Unexpected end of JSON boolean");
}
boolean_str += ch;
if (boolean_str == L"true") {
return true;
}
else if (boolean_str == L"false") {
return false;
}
}
throw std::runtime_error("Invalid JSON boolean");
}
Json Json::parse_null(std::wistream& is)
{
std::wstring null_str;
wchar_t ch;
for (int i = 0; i < 4; ++i) {
if (!(is.get(ch))) {
throw std::runtime_error("Unexpected end of JSON null");
}
null_str += ch;
}
if (null_str == L"null") {
return Json();
}
else {
throw std::runtime_error("Invalid JSON null");
}
}

150
src/BasicUtils/Json.h Normal file
View file

@ -0,0 +1,150 @@
#ifndef JSON_H
#define JSON_H
#include <unordered_map>
#include <vector>
#include <variant>
#include <iostream>
#include <string>
template <typename T, template <typename...> class Template>
struct is_specialization : std::false_type {};
template <template <typename...> class Template, typename... Args>
struct is_specialization<Template<Args...>, Template> : std::true_type {};
template <typename T>
inline constexpr bool is_map_v = is_specialization<std::remove_cvref_t<T>, std::unordered_map>::value;
template <typename T>
inline constexpr bool is_vector_v = is_specialization<std::remove_cvref_t<T>, std::vector>::value;
class Json {
public:
using Object = std::unordered_map<std::wstring, Json>;
using Array = std::vector<Json>;
using Value = std::variant<std::nullptr_t, Object, Array, std::wstring, bool, int, float, double>;
template <typename T>
requires std::is_constructible_v<Value, T>
Json(T&& value) : m_value(std::forward<T>(value)) {}
template <typename T>
requires std::is_constructible_v<Value, T>
Json(const std::vector<T>& list) : m_value(Array(list.begin(), list.end())) {}
template <typename T>
requires std::is_constructible_v<Value, T>
Json(const std::initializer_list<T>& list) : m_value(Array(list.begin(), list.end())) {}
Json() : m_value(nullptr) {}
Json(std::initializer_list<std::pair<std::wstring, Json>> list) : m_value(Object(list.begin(), list.end())) {}
Json& operator[](const std::wstring& key);
Json& operator[](size_t index);
Json& operator=(std::initializer_list<std::pair<std::wstring, Json>> list);
Json& operator=(std::initializer_list<Value> list);
friend std::wostream& operator<<(std::wostream& os, const Json& json);
friend std::wistream& operator>>(std::wistream& is, Json& json);
friend bool operator==(const Json& lhs, const Json& rhs);
friend bool operator!=(const Json& lhs, const Json& rhs);
Object::iterator begin();
Object::const_iterator begin() const;
Object::iterator end();
Object::const_iterator end() const;
Object::iterator find(const std::wstring& key);
Object::const_iterator find(const std::wstring& key) const;
bool is_null() const;
bool is_integer() const;
bool is_float() const;
bool is_double() const;
bool is_boolean() const;
bool is_string() const;
bool is_object() const;
bool is_array() const;
int get_integer() const;
float get_float() const;
double get_double() const;
bool get_boolean() const;
std::wstring get_string() const;
Object get_object() const;
Array get_array() const;
template <typename T>
void get_to(T& value) const
{
if constexpr (std::is_same_v<T, Json>) {
value = *this;
}
else if constexpr (std::is_constructible_v<Value, T>) {
if (!std::holds_alternative<T>(m_value)) {
throw std::runtime_error("JSON value cannot be converted to the requested type");
}
value = std::get<T>(m_value);
}
else if constexpr (is_vector_v<T>) {
if (!std::holds_alternative<Array>(m_value)) {
throw std::runtime_error("JSON value is not an array");
}
const Array& array = std::get<Array>(m_value);
value.clear();
for (const Json& element : array) {
typename T::value_type element_value;
element.get_to(element_value);
value.push_back(element_value);
}
}
else if constexpr (is_map_v<T>) {
if (!std::holds_alternative<Object>(m_value)) {
throw std::runtime_error("JSON value is not an object");
}
const Object& object = std::get<Object>(m_value);
value.clear();
for (const auto& [key, element] : object) {
typename T::mapped_type element_value;
element.get_to(element_value);
value[key] = element_value;
}
}
else {
throw std::runtime_error("Unsupported type for conversion from JSON");
}
}
Json& at(const std::wstring& key);
const Json& at(const std::wstring& key) const;
Json& at(size_t index);
const Json& at(size_t index) const;
void clear();
bool empty() const;
size_t size() const;
bool contains(const std::wstring& key) const;
std::wstring dump(int indent = 0) const;
static Json parse(const std::wstring& json_text);
static Json parse(std::wistream& is);
private:
Value m_value;
void dump_impl(std::wostream& os, int indent, int step) const;
static Object parse_object(std::wistream& is);
static Array parse_array(std::wistream& is);
static std::wstring parse_string(std::wistream& is);
static Json parse_number(std::wistream& is);
static Json parse_boolean(std::wistream& is);
static Json parse_null(std::wistream& is);
};
#endif // JSON_H

View file

@ -7,11 +7,12 @@
#include <mutex> #include <mutex>
namespace Logger { namespace Logger {
std::mutex mtx;
std::wofstream file; std::wofstream file;
bool log_enabled = false; bool log_enabled = false;
bool has_error = false;
void Init(std::wstring_view log_file, bool enable_logging) { void Init(std::wstring_view log_file, bool enable_logging)
{
log_enabled = enable_logging; log_enabled = enable_logging;
if (log_enabled) { if (log_enabled) {
file.open(log_file.data(), std::ios::out | std::ios::trunc); file.open(log_file.data(), std::ios::out | std::ios::trunc);
@ -21,7 +22,8 @@ namespace Logger {
} }
} }
std::wstring GetLevelInfo(LogLevel level) { std::wstring GetLevelInfo(LogLevel level)
{
switch (level) { switch (level) {
case LogLevel::Info: case LogLevel::Info:
return L"INFO"; return L"INFO";
@ -32,14 +34,16 @@ namespace Logger {
} }
} }
void Log(std::wstring_view message, LogLevel level) { void Log(std::wstring_view message, LogLevel level)
#ifndef NDEBUG {
if (level == LogLevel::Error) { if (level == LogLevel::Error) {
has_error = true;
PrintError(L"{}", message); PrintError(L"{}", message);
} }
#endif
if (!log_enabled) return; if (!log_enabled) return;
static std::mutex mtx;
std::lock_guard<std::mutex> lock(mtx); std::lock_guard<std::mutex> lock(mtx);
if (file.is_open()) { if (file.is_open()) {
@ -50,4 +54,9 @@ namespace Logger {
file.flush(); file.flush();
} }
} }
bool HasError()
{
return has_error;
}
} }

View file

@ -8,6 +8,7 @@ namespace Logger
enum class LogLevel { Info, Error }; enum class LogLevel { Info, Error };
void Init(std::wstring_view file, bool enable); void Init(std::wstring_view file, bool enable);
void Log(std::wstring_view message, LogLevel level); void Log(std::wstring_view message, LogLevel level);
bool HasError();
} }
using Logger::LogLevel; using Logger::LogLevel;

View file

@ -24,13 +24,23 @@ namespace Memory {
return false; return false;
} }
bool Write(void* address, std::string_view& data) bool Write(void* address, const std::string_view& data)
{
return Write(address, data.data(), data.size());
}
bool Write(void* address, const std::wstring_view& data)
{ {
return Write(address, data.data(), data.size()); return Write(address, data.data(), data.size());
} }
bool Write(void* address, std::initializer_list<uint8_t>& data) bool Write(void* address, const std::initializer_list<uint8_t>& data)
{ {
return Write(address, data.begin(), data.size()); return Write(address, data.begin(), data.size());
} }
bool Write(void* address, const std::vector<uint8_t>& data)
{
return Write(address, data.data(), data.size());
}
} }

View file

@ -3,13 +3,16 @@
#include <string_view> #include <string_view>
#include <initializer_list> #include <initializer_list>
#include <vector>
namespace Memory { namespace Memory {
bool Read(void* address, void* buffer, size_t size); bool Read(void* address, void* buffer, size_t size);
bool Write(void* address, const void* data, size_t size); bool Write(void* address, const void* data, size_t size);
bool Write(void* address, std::string_view& data); bool Write(void* address, const std::string_view& data);
bool Write(void* address, std::initializer_list<uint8_t>& data); bool Write(void* address, const std::wstring_view& data);
bool Write(void* address, const std::initializer_list<uint8_t>& data);
bool Write(void* address, const std::vector<uint8_t>& data);
} }

View file

@ -1,296 +1,385 @@
#include "MemoryScanner.h" #include "MemoryScanner.h"
#include "Hooking.h" #include "Hooking.h"
#include "Utils.h" #include "Utils.h"
#include "Memory.h" #include "Memory.h"
#include <sstream> #include <sstream>
#include <Psapi.h> #include <Psapi.h>
#include <algorithm> #include <algorithm>
#include <Memory.h> #include <unordered_map>
#include <unordered_map> #include <execution>
namespace MemoryScanner namespace MemoryScanner
{ {
ModuleInfo GetModuleInfo(std::wstring_view module_name) ModuleInfo GetModuleInfo(std::wstring_view module_name)
{ {
static std::unordered_map<std::wstring_view, ModuleInfo> loaded_modules; static std::unordered_map<std::wstring_view, ModuleInfo> loaded_modules;
const auto module = loaded_modules.find(module_name); const auto module = loaded_modules.find(module_name);
if (module != loaded_modules.end()) { if (module != loaded_modules.end()) {
return module->second; return module->second;
} }
HMODULE module_handle = GetModuleHandleW(module_name.empty() ? nullptr : module_name.data()); HMODULE module_handle = GetModuleHandleW(module_name.empty() ? nullptr : module_name.data());
if (module_handle == nullptr) { if (module_handle == nullptr) {
return ModuleInfo(module_name, 0, 0); return ModuleInfo(module_name, 0, 0);
} }
MODULEINFO module_info; MODULEINFO module_info;
if (!GetModuleInformation(GetCurrentProcess(), module_handle, &module_info, sizeof(MODULEINFO))) { if (!GetModuleInformation(GetCurrentProcess(), module_handle, &module_info, sizeof(MODULEINFO))) {
return ModuleInfo(module_name, 0, 0); return ModuleInfo(module_name, 0, 0);
} }
const auto ret = ModuleInfo(module_name, reinterpret_cast<uintptr_t>(module_info.lpBaseOfDll), module_info.SizeOfImage); const auto ret = ModuleInfo(module_name, reinterpret_cast<uintptr_t>(module_info.lpBaseOfDll), module_info.SizeOfImage);
loaded_modules.emplace(module_name, ret); loaded_modules.emplace(module_name, ret);
return ret; return ret;
} }
ScanResult GetFunctionAddress(std::string_view module_name, std::string_view function_name) ScanResult GetFunctionAddress(std::string_view module_name, std::string_view function_name)
{ {
HMODULE module_handle = GetModuleHandleA(module_name.data()); HMODULE module_handle = GetModuleHandleA(module_name.data());
if (module_handle == nullptr) { if (module_handle == nullptr) {
module_handle = LoadLibraryA(module_name.data()); module_handle = LoadLibraryA(module_name.data());
if (module_handle == nullptr) { if (module_handle == nullptr) {
return ScanResult(0, 0, 0); return ScanResult(0, 0, 0);
} }
} }
FARPROC function_address = GetProcAddress(module_handle, function_name.data()); FARPROC function_address = GetProcAddress(module_handle, function_name.data());
if (function_address == nullptr) { if (function_address == nullptr) {
return ScanResult(0, 0, 0); return ScanResult(0, 0, 0);
} }
MODULEINFO module_info; MODULEINFO module_info;
if (!GetModuleInformation(GetCurrentProcess(), module_handle, &module_info, sizeof(MODULEINFO))) { if (!GetModuleInformation(GetCurrentProcess(), module_handle, &module_info, sizeof(MODULEINFO))) {
return ScanResult(reinterpret_cast<uintptr_t>(function_address), 0, 0); return ScanResult(reinterpret_cast<uintptr_t>(function_address), 0, 0);
} }
return ScanResult(reinterpret_cast<uintptr_t>(function_address), reinterpret_cast<uintptr_t>(module_info.lpBaseOfDll), module_info.SizeOfImage); return ScanResult(reinterpret_cast<uintptr_t>(function_address), reinterpret_cast<uintptr_t>(module_info.lpBaseOfDll), module_info.SizeOfImage);
} }
std::vector<uint8_t> SignatureToByteArray(std::wstring_view signature) std::vector<BytePattern> ParseBytePattern(std::wstring_view byte_pattern)
{ {
std::vector<uint8_t> signature_bytes; std::vector<BytePattern> parsed_pattern;
std::wstring word; bool is_hex = byte_pattern.find_first_not_of(L"0123456789ABCDEFabcdef? ") == std::wstring::npos;
std::wistringstream iss(signature.data()); if (is_hex) {
std::wistringstream iss(byte_pattern.data());
while (iss >> word) { std::wstring byte;
if (word.size() == 1 && word[0] == L'?') { while (iss >> byte) {
signature_bytes.push_back(0); BytePattern bp;
} if (byte.size() == 1 && byte[0] == L'?') {
else if (word.size() == 2 && word[0] == L'?' && word[1] == L'?') { bp.half_byte[0].wildcard = true;
signature_bytes.push_back(0); bp.half_byte[1].wildcard = true;
} }
else if (word.size() == 2 && std::isxdigit(word[0]) && std::isxdigit(word[1])) { else {
unsigned long value = std::stoul(word, nullptr, 16); if (byte[0] == L'?') {
if (value > 255) { bp.half_byte[0].wildcard = true;
return { 0 }; }
} else {
signature_bytes.push_back(static_cast<uint8_t>(value)); bp.half_byte[0].data = std::stoi(std::wstring(1, byte[0]), nullptr, 16);
} }
else {
for (wchar_t c : word) { if (byte[1] == L'?') {
if (c > 255) { bp.half_byte[1].wildcard = true;
return { 0 }; }
} else {
signature_bytes.push_back(static_cast<uint8_t>(c)); bp.half_byte[1].data = std::stoi(std::wstring(1, byte[1]), nullptr, 16);
} }
} }
} parsed_pattern.push_back(bp);
}
return signature_bytes; }
} else {
for (wchar_t ch : byte_pattern) {
std::vector<ScanResult> ScanAll(uintptr_t base_address, size_t image_size, const std::vector<uint8_t>& pattern_byte, bool only_first) BytePattern bp;
{ bp.half_byte[0].data = ch >> 4;
std::vector<ScanResult> matches; bp.half_byte[1].data = ch & 0xF;
parsed_pattern.push_back(bp);
size_t pattern_size = pattern_byte.size(); }
}
if (pattern_byte.empty()) {
return matches; return parsed_pattern;
} }
uint8_t* base_ptr = reinterpret_cast<uint8_t*>(base_address); std::vector<ScanResult> ScanAll(uintptr_t base_address, size_t image_size, const std::vector<BytePattern>& parsed_pattern, bool only_first)
uintptr_t end_address = base_address + image_size - pattern_size + 1; {
std::vector<ScanResult> result;
while (base_ptr < reinterpret_cast<uint8_t*>(end_address)) { const uint8_t* start = reinterpret_cast<const uint8_t*>(base_address);
base_ptr = static_cast<uint8_t*>(memchr(base_ptr, pattern_byte[0], end_address - reinterpret_cast<uintptr_t>(base_ptr))); const uint8_t* end = start + image_size;
if (!base_ptr) { const size_t pattern_size = parsed_pattern.size();
break; const BytePattern& first_pattern = parsed_pattern[0];
}
for (const uint8_t* it = start; it + pattern_size <= end; ++it) {
bool found = true; if ((first_pattern.half_byte[0].wildcard || ((it[0] & 0xF0) == (first_pattern.half_byte[0].data << 4))) &&
for (size_t i = 1; i < pattern_size; ++i) { (first_pattern.half_byte[1].wildcard || ((it[0] & 0x0F) == first_pattern.half_byte[1].data))) {
if (pattern_byte[i] != 0 && pattern_byte[i] != base_ptr[i]) {
found = false; bool found = true;
break; for (size_t i = 1; i < pattern_size; ++i) {
} const BytePattern& pattern = parsed_pattern[i];
} uint8_t byte = it[i];
if (found) { if (!(pattern.half_byte[0].wildcard || ((byte & 0xF0) == (pattern.half_byte[0].data << 4))) ||
matches.push_back(ScanResult(reinterpret_cast<uintptr_t>(base_ptr), base_address, image_size)); !(pattern.half_byte[1].wildcard || ((byte & 0x0F) == pattern.half_byte[1].data))) {
if (only_first) break; found = false;
} break;
}
++base_ptr; }
}
if (found) {
return matches; result.push_back(ScanResult(reinterpret_cast<uintptr_t>(it), base_address, image_size));
} if (only_first) {
break;
std::vector<ScanResult> ScanAll(uintptr_t base_address, size_t image_size, std::wstring_view signature) }
{ }
return ScanAll(base_address, image_size, SignatureToByteArray(signature)); }
} }
std::vector<ScanResult> ScanAll(std::wstring_view signature, std::wstring_view module_name) return result;
{ }
const auto mod = GetModuleInfo(module_name);
return ScanAll(mod.base_address, mod.module_size, signature); std::vector<ScanResult> ScanAll(uintptr_t base_address, size_t image_size, std::wstring_view pattern)
} {
return ScanAll(base_address, image_size, ParseBytePattern(pattern));
ScanResult ScanFirst(uintptr_t base_address, size_t image_size, const std::vector<uint8_t>& pattern_byte) }
{
const auto matches = ScanAll(base_address, image_size, pattern_byte, true); std::vector<ScanResult> ScanAll(std::wstring_view pattern, std::wstring_view module_name)
return matches.empty() ? ScanResult(0, 0, 0) : matches.at(0); {
} const auto module_info = GetModuleInfo(module_name);
return ScanAll(module_info.base_address, module_info.module_size, pattern);
ScanResult ScanFirst(uintptr_t base_address, size_t image_size, std::wstring_view signature) }
{
return ScanFirst(base_address, image_size, SignatureToByteArray(signature)); ScanResult ScanFirst(uintptr_t base_address, size_t image_size, const std::vector<BytePattern>& parsed_pattern)
} {
const auto addresses = ScanAll(base_address, image_size, parsed_pattern, true);
ScanResult ScanFirst(std::wstring_view signature, std::wstring_view module_name) return addresses.empty() ? ScanResult(0, 0, 0) : addresses.front();
{ }
const auto mod = GetModuleInfo(module_name);
return ScanFirst(mod.base_address, mod.module_size, signature); ScanResult ScanFirst(uintptr_t base_address, size_t image_size, std::wstring_view pattern)
} {
return ScanFirst(base_address, image_size, ParseBytePattern(pattern));
ScanResult::ScanResult(uintptr_t address, uintptr_t base, size_t size) : m_address(address), m_base_address(base), m_image_size(size) }
{
//... ScanResult ScanFirst(std::wstring_view pattern, std::wstring_view module_name)
} {
const auto module_info = GetModuleInfo(module_name);
ScanResult::operator uintptr_t() const return ScanFirst(module_info.base_address, module_info.module_size, pattern);
{ }
return m_address;
} ScanResult::ScanResult(uintptr_t address, uintptr_t base, size_t size, bool is_rva) : m_address(address), m_base_address(base), m_image_size(size)
{
bool ScanResult::is_valid(const std::vector<uint8_t>& value) const if (is_rva && address) {
{ m_address += m_base_address;
if (m_address == 0) { }
return false; }
}
ScanResult::ScanResult(uintptr_t address, std::wstring_view module_name, bool is_rva) : m_address(address), m_base_address(GetModuleInfo(module_name).base_address), m_image_size(GetModuleInfo(module_name).module_size)
for (size_t i = 0; i < value.size(); ++i) { {
if (*(reinterpret_cast<uint8_t*>(m_address) + i) != value[i]) if (is_rva && address) {
return false; m_address += m_base_address;
} }
}
return true;
} ScanResult::operator uintptr_t() const
{
uint8_t* ScanResult::data() const return m_address;
{ }
if (!is_valid()) {
return nullptr; bool ScanResult::is_valid(const std::vector<BytePattern>& parsed_pattern) const
} {
if (m_address == 0) {
return reinterpret_cast<uint8_t*>(m_address); return false;
} }
ScanResult ScanResult::rva() const for (size_t i = 0; i < parsed_pattern.size(); ++i) {
{ BytePattern pattern = parsed_pattern[i];
if (!is_valid()) { if (pattern.half_byte[0].wildcard && pattern.half_byte[1].wildcard) {
return ScanResult(0, m_base_address, m_image_size); continue;
} }
uintptr_t rva_address = m_address - m_base_address; uint8_t byte = *(reinterpret_cast<uint8_t*>(m_address) + i);
return ScanResult(rva_address, m_base_address, m_image_size); uint8_t pattern_byte = (pattern.half_byte[0].data << 4) | pattern.half_byte[1].data;
} bool match_high_nibble = pattern.half_byte[0].wildcard || (byte & 0xF0) == (pattern_byte & 0xF0);
bool match_low_nibble = pattern.half_byte[1].wildcard || (byte & 0x0F) == (pattern_byte & 0x0F);
ScanResult ScanResult::offset(std::ptrdiff_t offset_value) const
{ if (!(match_high_nibble && match_low_nibble)) {
if (!is_valid()) { return false;
return ScanResult(0, m_base_address, m_image_size); }
} }
uintptr_t new_address = m_address; return true;
if (offset_value >= 0) { }
new_address += static_cast<uintptr_t>(offset_value);
} bool ScanResult::is_valid(std::wstring_view pattern) const
else { {
new_address -= static_cast<uintptr_t>(-offset_value); return is_valid(ParseBytePattern(pattern));
} }
return ScanResult(new_address, m_base_address, m_image_size); uint8_t* ScanResult::data() const
} {
if (!is_valid()) {
ScanResult ScanResult::scan_first(std::wstring_view value) const return nullptr;
{ }
return is_valid() ? ScanFirst(m_address, m_image_size - rva(), value) : ScanResult(0, m_base_address, m_image_size);
} return reinterpret_cast<uint8_t*>(m_address);
}
bool ScanResult::write(const void* data, size_t size) const
{ ScanResult ScanResult::rva() const
return Memory::Write(reinterpret_cast<void*>(m_address), data, size); {
} if (!is_valid()) {
return ScanResult(0, m_base_address, m_image_size);
bool ScanResult::write(std::string_view data) const }
{
return Memory::Write(reinterpret_cast<void*>(m_address), data); return ScanResult(m_address - m_base_address, m_base_address, m_image_size);
} }
bool ScanResult::write(std::initializer_list<uint8_t> data) const ScanResult ScanResult::offset(std::ptrdiff_t offset_value) const
{ {
return Memory::Write(reinterpret_cast<void*>(m_address), data); if (!is_valid()) {
} return ScanResult(0, m_base_address, m_image_size);
}
PVOID* ScanResult::hook(PVOID hook_function) const
{ uintptr_t new_address = m_address;
return (is_valid() && Hooking::HookFunction(&(PVOID&)m_address, hook_function)) ? reinterpret_cast<PVOID*>(m_address) : NULL; if (offset_value >= 0) {
} new_address += static_cast<uintptr_t>(offset_value);
}
bool ScanResult::unhook() const else {
{ new_address -= static_cast<uintptr_t>(-offset_value);
return is_valid() ? Hooking::UnhookFunction(&(PVOID&)m_address) : false; }
}
return ScanResult(new_address, m_base_address, m_image_size);
std::vector<ScanResult> ScanResult::get_all_matching_codes(const std::vector<uint8_t>& pattern_byte, bool calculate_relative_offset, uintptr_t base_address, size_t image_size, bool only_first) const }
{
if (base_address == 0) base_address = m_base_address; ScanResult ScanResult::scan_first(std::wstring_view value) const
if (image_size == 0) image_size = m_image_size; {
return is_valid() ? ScanFirst(m_address, m_image_size - rva(), value) : ScanResult(0, m_base_address, m_image_size);
if (!calculate_relative_offset) { }
std::vector<uint8_t> new_pattern_byte = pattern_byte;
new_pattern_byte.insert(new_pattern_byte.end(), reinterpret_cast<const uint8_t*>(&m_address), bool ScanResult::write(const std::string_view& data) const
reinterpret_cast<const uint8_t*>(&m_address) + sizeof(m_address)); {
return is_valid() ? Memory::Write(reinterpret_cast<void*>(m_address), data) : false;
return ScanAll(base_address, image_size, new_pattern_byte, only_first); }
}
bool ScanResult::write(const std::wstring_view& data) const
std::vector<ScanResult> matches; {
const auto all_matches = ScanAll(base_address, image_size, pattern_byte); return is_valid() ? Memory::Write(reinterpret_cast<void*>(m_address), data) : false;
for (const auto& address : all_matches) { }
const auto offset_address = address + pattern_byte.size();
const auto relative_offset = static_cast<int32_t>(m_address) - static_cast<int32_t>(offset_address) - sizeof(int32_t); bool ScanResult::write(const std::initializer_list<uint8_t>& data) const
if (*reinterpret_cast<const int32_t*>(offset_address) == relative_offset) { {
matches.push_back(ScanResult(address, base_address, image_size)); return is_valid() ? Memory::Write(reinterpret_cast<void*>(m_address), data) : false;
if (only_first) break; }
}
} bool ScanResult::write(const std::vector<uint8_t>& data) const
{
return matches; return is_valid() ? Memory::Write(reinterpret_cast<void*>(m_address), data) : false;
} }
ScanResult ScanResult::get_first_matching_code(const std::vector<uint8_t>& pattern_byte, bool calculate_relative_offset, uintptr_t base_address, size_t image_size) const PVOID* ScanResult::hook(PVOID hook_function) const
{ {
const auto matches = get_all_matching_codes(pattern_byte, calculate_relative_offset, base_address, image_size, true); return (is_valid() && Hooking::HookFunction(&(PVOID&)m_address, hook_function)) ? reinterpret_cast<PVOID*>(m_address) : NULL;
return matches.empty() ? ScanResult(0, m_base_address, m_image_size) : matches.at(0); }
}
bool ScanResult::unhook() const
uintptr_t ScanResult::get_base_address() const {
{ return is_valid() ? Hooking::UnhookFunction(&(PVOID&)m_address) : false;
return m_base_address; }
}
std::vector<ScanResult> ScanResult::get_all_references(const std::vector<BytePattern>& parsed_pattern, bool calculate_relative_address, uintptr_t base_address, size_t image_size, bool only_first) const
size_t ScanResult::get_image_size() const {
{ if (base_address == 0) base_address = m_base_address;
return m_image_size; if (image_size == 0) image_size = m_image_size;
}
if (!calculate_relative_address) {
void ScanResult::print_address() const std::vector<BytePattern> new_parsed_pattern = parsed_pattern;
{ const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&m_address);
Print(L"{:x}", m_address); for (size_t i = 0; i < sizeof(uintptr_t); ++i) {
} BytePattern bp;
uint8_t byte = ptr[i];
bp.half_byte[0].data = byte >> 4;
bp.half_byte[1].data = byte & 0xF;
new_parsed_pattern.push_back(bp);
}
return ScanAll(base_address, image_size, new_parsed_pattern, only_first);
}
#if 0
std::vector<ScanResult> result;
const auto pattern_size = parsed_pattern.size();
for (const auto& address : ScanAll(base_address, image_size, parsed_pattern)) {
const auto offset_ptr = reinterpret_cast<int32_t*>(address.data() + pattern_size);
const auto relative_address = address + pattern_size + *offset_ptr + sizeof(int32_t);
if (relative_address == m_address) {
result.push_back(ScanResult(address, base_address, image_size));
if (only_first) break;
}
}
return result;
#else
std::vector<ScanResult> result;
const uint8_t* start = reinterpret_cast<const uint8_t*>(base_address);
const uint8_t* end = start + image_size;
const size_t pattern_size = parsed_pattern.size();
const BytePattern& first_pattern = parsed_pattern[0];
for (const uint8_t* it = start; it + pattern_size <= end; ++it) {
if ((first_pattern.half_byte[0].wildcard || ((it[0] & 0xF0) == (first_pattern.half_byte[0].data << 4))) &&
(first_pattern.half_byte[1].wildcard || ((it[0] & 0x0F) == first_pattern.half_byte[1].data))) {
bool found = true;
for (size_t i = 1; i < pattern_size; ++i) {
const BytePattern& pattern = parsed_pattern[i];
uint8_t byte = it[i];
if (!(pattern.half_byte[0].wildcard || ((byte & 0xF0) == (pattern.half_byte[0].data << 4))) ||
!(pattern.half_byte[1].wildcard || ((byte & 0x0F) == pattern.half_byte[1].data))) {
found = false;
break;
}
}
if (found) {
const auto offset_ptr = reinterpret_cast<int32_t*>(const_cast<uint8_t*>(it + pattern_size));
const auto relative_address = reinterpret_cast<uintptr_t>(it) + pattern_size + *offset_ptr + sizeof(int32_t);
if (relative_address == m_address) {
result.push_back(ScanResult(reinterpret_cast<uintptr_t>(it), base_address, image_size));
if (only_first) {
break;
}
}
}
}
}
return result;
#endif
}
std::vector<ScanResult> ScanResult::get_all_references(std::wstring_view pattern, bool calculate_relative_address, uintptr_t base_address, size_t image_size, bool only_first) const
{
return get_all_references(ParseBytePattern(pattern), calculate_relative_address, base_address, image_size, only_first);
}
ScanResult ScanResult::get_first_reference(const std::vector<BytePattern>& parsed_pattern, bool calculate_relative_address, uintptr_t base_address, size_t image_size) const
{
const auto references = get_all_references(parsed_pattern, calculate_relative_address, base_address, image_size, true);
return references.empty() ? ScanResult(0, 0, 0) : references.front();
}
ScanResult ScanResult::get_first_reference(std::wstring_view pattern, bool calculate_relative_address, uintptr_t base_address, size_t image_size) const
{
return get_first_reference(ParseBytePattern(pattern), calculate_relative_address, base_address, image_size);
}
uintptr_t ScanResult::get_base_address() const
{
return m_base_address;
}
size_t ScanResult::get_image_size() const
{
return m_image_size;
}
void ScanResult::print_address() const
{
Print(L"{:x}", m_address);
}
} }

View file

@ -1,61 +1,75 @@
#ifndef MEMORY_SCANNER_H #ifndef MEMORY_SCANNER_H
#define MEMORY_SCANNER_H #define MEMORY_SCANNER_H
#include <Windows.h> #include <Windows.h>
#include <string> #include <string>
#include <vector> #include <vector>
namespace MemoryScanner namespace MemoryScanner
{ {
struct ModuleInfo { struct ModuleInfo {
std::wstring_view module_name; std::wstring_view module_name;
uintptr_t base_address; uintptr_t base_address;
size_t module_size; size_t module_size;
}; };
class ScanResult { struct BytePattern {
public: struct HalfByte {
ScanResult() : m_address(0), m_base_address(0), m_image_size(0) {} uint8_t data{};
ScanResult(uintptr_t address, uintptr_t base, size_t size); bool wildcard{};
operator uintptr_t() const; } half_byte[2]{};
};
bool is_valid(const std::vector<uint8_t>& value = {}) const;
uint8_t* data() const; class ScanResult {
ScanResult rva() const; public:
ScanResult offset(std::ptrdiff_t offset_value) const; ScanResult() : m_address(0), m_base_address(0), m_image_size(0) {}
ScanResult scan_first(std::wstring_view value) const; ScanResult(uintptr_t address, uintptr_t base, size_t size, bool is_rva = false);
ScanResult(uintptr_t address, std::wstring_view module_name = {}, bool is_rva = false);
bool write(const void* data, size_t size) const; operator uintptr_t() const;
bool write(std::string_view data) const;
bool write(std::initializer_list<uint8_t> data) const; bool is_valid(const std::vector<BytePattern>& parsed_pattern = {}) const;
bool is_valid(std::wstring_view pattern) const;
PVOID* hook(PVOID hook_function) const; uint8_t* data() const;
bool unhook() const; ScanResult rva() const;
ScanResult offset(std::ptrdiff_t offset_value) const;
std::vector<ScanResult> get_all_matching_codes(const std::vector<uint8_t>& pattern_byte, bool calculate_relative_offset = true, uintptr_t base_address = 0, size_t image_size = 0, bool only_first = false) const; ScanResult scan_first(std::wstring_view value) const;
ScanResult get_first_matching_code(const std::vector<uint8_t>& pattern_byte, bool calculate_relative_offset = true, uintptr_t base_address = 0, size_t image_size = 0) const;
bool write(const std::string_view& data) const;
uintptr_t get_base_address() const; bool write(const std::wstring_view& data) const;
size_t get_image_size() const; bool write(const std::initializer_list<uint8_t>& data) const;
bool write(const std::vector<uint8_t>& data) const;
void print_address() const;
PVOID* hook(PVOID hook_function) const;
private: bool unhook() const;
uintptr_t m_address;
uintptr_t m_base_address; std::vector<ScanResult> get_all_references(const std::vector<BytePattern>& parsed_pattern, bool calculate_relative_address = true, uintptr_t base_address = 0, size_t image_size = 0, bool only_first = false) const;
size_t m_image_size; std::vector<ScanResult> get_all_references(std::wstring_view pattern, bool calculate_relative_address = true, uintptr_t base_address = 0, size_t image_size = 0, bool only_first = false) const;
};
ScanResult get_first_reference(const std::vector<BytePattern>& parsed_pattern, bool calculate_relative_address = true, uintptr_t base_address = 0, size_t image_size = 0) const;
ModuleInfo GetModuleInfo(std::wstring_view module_name = {}); ScanResult get_first_reference(std::wstring_view pattern, bool calculate_relative_address = true, uintptr_t base_address = 0, size_t image_size = 0) const;
ScanResult GetFunctionAddress(std::string_view module_name, std::string_view function_name);
uintptr_t get_base_address() const;
std::vector<ScanResult> ScanAll(uintptr_t base_address, size_t image_size, const std::vector<uint8_t>& pattern_byte, bool only_first = false); size_t get_image_size() const;
std::vector<ScanResult> ScanAll(uintptr_t base_address, size_t image_size, std::wstring_view signature);
std::vector<ScanResult> ScanAll(std::wstring_view signature, std::wstring_view module_name = {}); void print_address() const;
ScanResult ScanFirst(uintptr_t base_address, size_t image_size, const std::vector<uint8_t>& pattern_byte); private:
ScanResult ScanFirst(uintptr_t base_address, size_t image_size, std::wstring_view signature); uintptr_t m_address;
ScanResult ScanFirst(std::wstring_view signature, std::wstring_view module_name = {}); uintptr_t m_base_address;
} size_t m_image_size;
};
#endif // MEMORY_SCANNER_H
ModuleInfo GetModuleInfo(std::wstring_view module_name = {});
ScanResult GetFunctionAddress(std::string_view module_name, std::string_view function_name);
std::vector<BytePattern> ParseBytePattern(std::wstring_view pattern);
std::vector<ScanResult> ScanAll(uintptr_t base_address, size_t image_size, const std::vector<BytePattern>& parsed_pattern, bool only_first = false);
std::vector<ScanResult> ScanAll(uintptr_t base_address, size_t image_size, std::wstring_view pattern);
std::vector<ScanResult> ScanAll(std::wstring_view pattern, std::wstring_view module_name = {});
ScanResult ScanFirst(uintptr_t base_address, size_t image_size, const std::vector<BytePattern>& parsed_pattern);
ScanResult ScanFirst(uintptr_t base_address, size_t image_size, std::wstring_view pattern);
ScanResult ScanFirst(std::wstring_view pattern, std::wstring_view module_name = {});
}
#endif // MEMORY_SCANNER_H

View file

@ -1,194 +1,327 @@
#include "Utils.h" #include "Utils.h"
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
#include <cctype>
namespace Utils #include <cwctype>
{ #include <fstream>
std::string ToHexString(const std::vector<uint8_t>& byte_array, const bool insert_spaces) #include <winhttp.h>
{ #pragma comment(lib, "winhttp.lib")
std::ostringstream oss;
oss << std::hex << std::setfill('0'); namespace Utils
{
for (size_t i = 0; i < byte_array.size(); ++i) { std::string ToHexString(const std::vector<uint8_t>& byte_array, const bool insert_spaces)
if (i > 0 && insert_spaces) { {
oss << ' '; std::ostringstream oss;
} oss << std::hex << std::setfill('0');
oss << std::setw(2) << static_cast<int>(byte_array[i]);
} for (size_t i = 0; i < byte_array.size(); ++i) {
if (i > 0 && insert_spaces) {
std::string hex_string = oss.str(); oss << ' ';
std::transform(hex_string.begin(), hex_string.end(), hex_string.begin(), ::toupper); }
oss << std::setw(2) << static_cast<int>(byte_array[i]);
return hex_string; }
}
std::string hex_string = oss.str();
std::string ToHexString(const uint8_t* data, size_t size, const bool insert_spaces) std::transform(hex_string.begin(), hex_string.end(), hex_string.begin(), ::toupper);
{
if (data == nullptr) { return hex_string;
PrintError(L"ToHexString: The data pointer is null."); }
return std::string();
} std::string ToHexString(const uint8_t* data, size_t size, const bool insert_spaces)
{
if (size == 0) return ToHexString(std::vector<uint8_t>(data, data + size), insert_spaces);
size = std::strlen(reinterpret_cast<const char*>(data)); }
return ToHexString(std::vector<uint8_t>(data, data + size), insert_spaces); std::wstring ToHexWideString(const std::vector<uint8_t>& byte_array, const bool insert_spaces)
} {
std::wostringstream oss;
std::wstring ToHexWideString(const std::vector<uint8_t>& byte_array, const bool insert_spaces) oss << std::hex << std::setfill(L'0');
{
std::wostringstream oss; for (size_t i = 0; i < byte_array.size(); ++i) {
oss << std::hex << std::setfill(L'0'); if (i > 0 && insert_spaces) {
oss << L' ';
for (size_t i = 0; i < byte_array.size(); ++i) { }
if (i > 0 && insert_spaces) { oss << std::setw(2) << static_cast<int>(byte_array[i]);
oss << L' '; }
}
oss << std::setw(2) << static_cast<int>(byte_array[i]); std::wstring hex_string = oss.str();
} std::transform(hex_string.begin(), hex_string.end(), hex_string.begin(), ::towupper);
std::wstring hex_string = oss.str(); return hex_string;
std::transform(hex_string.begin(), hex_string.end(), hex_string.begin(), ::towupper); }
return hex_string; std::wstring ToHexWideString(const uint8_t* data, size_t size, const bool insert_spaces)
} {
return ToHexWideString(std::vector<uint8_t>(data, data + size), insert_spaces);
std::wstring ToHexWideString(const uint8_t* data, size_t size, const bool insert_spaces) }
{
if (data == nullptr) { std::vector<uint8_t> ToHexBytes(const std::string& hex_string)
PrintError(L"ToHexWideString: The data pointer is null."); {
return std::wstring(); std::vector<uint8_t> byte_array;
}
std::istringstream iss(hex_string);
if (size == 0) std::string hex_byte;
size = std::wcslen(reinterpret_cast<const wchar_t*>(data));
while (iss >> std::setw(2) >> hex_byte) {
return ToHexWideString(std::vector<uint8_t>(data, data + size), insert_spaces); uint8_t byte_value = static_cast<uint8_t>(std::stoi(hex_byte, nullptr, 16));
} byte_array.push_back(byte_value);
}
std::string ConvertUInt8ArrayToString(uint8_t* data)
{ return byte_array;
return std::string(reinterpret_cast<char*>(data), reinterpret_cast<char*>(data + std::strlen(reinterpret_cast<char*>(data)))); }
}
std::vector<uint8_t> ToHexBytes(const std::wstring& hex_wstring)
std::wstring ConvertUInt8ArrayToWideString(uint8_t* data) {
{ std::vector<uint8_t> byte_array;
return std::wstring(reinterpret_cast<wchar_t*>(data), reinterpret_cast<wchar_t*>(data + std::wcslen(reinterpret_cast<wchar_t*>(data))));
} std::wistringstream iss(hex_wstring);
std::wstring hex_byte;
std::string IntegerToHexString(uintptr_t integer_value)
{ while (iss >> std::setw(2) >> hex_byte) {
return std::format("{:x}", integer_value); uint8_t byte_value = static_cast<uint8_t>(std::stoi(hex_byte, nullptr, 16));
} byte_array.push_back(byte_value);
}
std::wstring IntegerToHexWideString(uintptr_t integer_value)
{ return byte_array;
return std::format(L"{:x}", integer_value); }
}
std::string IntegerToHexString(uintptr_t integer_value)
std::string ToString(std::wstring_view wide_string) {
{ return std::format("{:x}", integer_value);
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wide_string[0], (int)wide_string.size(), NULL, 0, NULL, NULL); }
std::string str_to(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &wide_string[0], (int)wide_string.size(), &str_to[0], size_needed, NULL, NULL); std::wstring IntegerToHexWideString(uintptr_t integer_value)
return str_to; {
} return std::format(L"{:x}", integer_value);
}
std::wstring ToString(std::string_view narrow_string)
{ std::string ToString(std::wstring_view wide_string)
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &narrow_string[0], (int)narrow_string.size(), NULL, 0); {
std::wstring wstr_to(size_needed, 0); int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wide_string[0], (int)wide_string.size(), NULL, 0, NULL, NULL);
MultiByteToWideChar(CP_UTF8, 0, &narrow_string[0], (int)narrow_string.size(), &wstr_to[0], size_needed); std::string str_to(size_needed, 0);
return wstr_to; WideCharToMultiByte(CP_UTF8, 0, &wide_string[0], (int)wide_string.size(), &str_to[0], size_needed, NULL, NULL);
} return str_to;
}
std::wstring ToString(std::u16string_view utf16_string)
{ std::wstring ToString(std::string_view narrow_string)
return std::wstring(utf16_string.begin(), utf16_string.end()); {
} int size_needed = MultiByteToWideChar(CP_UTF8, 0, &narrow_string[0], (int)narrow_string.size(), NULL, 0);
std::wstring wstr_to(size_needed, 0);
bool Contains(std::string_view str1, std::string_view str2, bool case_sensitive) MultiByteToWideChar(CP_UTF8, 0, &narrow_string[0], (int)narrow_string.size(), &wstr_to[0], size_needed);
{ return wstr_to;
auto it = std::search( }
str1.begin(), str1.end(),
str2.begin(), str2.end(), std::wstring ToString(std::u16string_view utf16_string)
[case_sensitive](char ch1, char ch2) { {
return case_sensitive ? ch1 == ch2 : std::toupper(ch1) == std::toupper(ch2); return std::wstring(utf16_string.begin(), utf16_string.end());
} }
);
return (it != str1.end()); bool Contains(std::string_view str1, std::string_view str2, bool case_sensitive)
} {
auto it = std::search(
bool Contains(std::wstring_view str1, std::wstring_view str2, bool case_sensitive) str1.begin(), str1.end(),
{ str2.begin(), str2.end(),
auto it = std::search( [case_sensitive](char ch1, char ch2) {
str1.begin(), str1.end(), return case_sensitive ? ch1 == ch2 : std::toupper(ch1) == std::toupper(ch2);
str2.begin(), str2.end(), }
[case_sensitive](wchar_t ch1, wchar_t ch2) { );
return case_sensitive ? ch1 == ch2 : std::toupper(ch1) == std::toupper(ch2); return (it != str1.end());
} }
);
return (it != str1.end()); bool Contains(std::wstring_view str1, std::wstring_view str2, bool case_sensitive)
} {
auto it = std::search(
bool Equals(std::string_view str1, std::string_view str2, bool case_sensitive) str1.begin(), str1.end(),
{ str2.begin(), str2.end(),
return std::equal(str1.begin(), str1.end(), str2.begin(), str2.end(), [case_sensitive](wchar_t ch1, wchar_t ch2) {
[case_sensitive](char ch1, char ch2) { return case_sensitive ? ch1 == ch2 : std::toupper(ch1) == std::toupper(ch2);
return case_sensitive ? ch1 == ch2 : std::toupper(ch1) == std::toupper(ch2); }
}); );
} return (it != str1.end());
}
bool Equals(std::wstring_view str1, std::wstring_view str2, bool case_sensitive)
{ bool Equals(std::string_view str1, std::string_view str2, bool case_sensitive)
return std::equal(str1.begin(), str1.end(), str2.begin(), str2.end(), {
[case_sensitive](wchar_t ch1, wchar_t ch2) { return std::equal(str1.begin(), str1.end(), str2.begin(), str2.end(),
return case_sensitive ? ch1 == ch2 : std::toupper(ch1) == std::toupper(ch2); [case_sensitive](char ch1, char ch2) {
}); return case_sensitive ? ch1 == ch2 : std::toupper(ch1) == std::toupper(ch2);
} });
}
void WriteIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key, std::wstring_view value)
{ bool Equals(std::wstring_view str1, std::wstring_view str2, bool case_sensitive)
WritePrivateProfileStringW(section.data(), key.data(), value.data(), ini_path.data()); {
} return std::equal(str1.begin(), str1.end(), str2.begin(), str2.end(),
[case_sensitive](wchar_t ch1, wchar_t ch2) {
std::wstring ReadIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key) return case_sensitive ? ch1 == ch2 : std::toupper(ch1) == std::toupper(ch2);
{ });
wchar_t value[255]; }
GetPrivateProfileStringW(section.data(), key.data(), L"", value, 255, ini_path.data());
return std::wstring(value); void WriteIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key, std::wstring_view value)
} {
WritePrivateProfileStringW(section.data(), key.data(), value.data(), ini_path.data());
#ifndef NDEBUG }
void MeasureExecutionTime(std::function<void()> func)
{ std::wstring ReadIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key)
const auto start_time = std::chrono::high_resolution_clock::now(); {
func(); wchar_t value[255];
const auto end_time = std::chrono::high_resolution_clock::now(); GetPrivateProfileStringW(section.data(), key.data(), L"", value, 255, ini_path.data());
const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count(); return std::wstring(value);
}
SetConsoleTitleW(FormatString(L"Execution time: {:d}ms", duration).c_str());
} bool ReadFile(const std::wstring_view filename, std::wstring& out)
{
void PrintSymbols(std::wstring_view module_name) std::wifstream file(filename.data(), std::ios::binary | std::ios::ate);
{ if (!file.is_open()) return false;
HMODULE hModule = GetModuleHandleW(module_name.data());
if (!hModule && !(hModule = LoadLibraryW(module_name.data()))) { out.resize(static_cast<std::wstring::size_type>(file.tellg()));
PrintError(L"PrintSymbols: Failed to load module."); file.seekg(0, std::ios::beg);
return; file.read(&out[0], out.size());
}
return !file.fail();
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; }
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)dosHeader + dosHeader->e_lfanew);
PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)dosHeader + ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); bool WriteFile(const std::wstring_view filename, const std::wstring_view content)
PDWORD functions = (PDWORD)((BYTE*)dosHeader + exportDirectory->AddressOfFunctions); {
PDWORD names = (PDWORD)((BYTE*)dosHeader + exportDirectory->AddressOfNames); std::wofstream file(filename.data(), std::ios::binary);
PWORD ordinals = (PWORD)((BYTE*)dosHeader + exportDirectory->AddressOfNameOrdinals); if (!file.is_open()) return false;
for (DWORD i = 0; i < exportDirectory->NumberOfNames; i++) { file.write(content.data(), content.size());
Print(L"{}", reinterpret_cast<const char*>((BYTE*)dosHeader + names[i]));
} return !file.fail();
} }
#endif // NDEBUG
std::wstring HttpGetRequest(std::wstring_view url)
{
std::wstring response;
auto session = WinHttpOpen(L"WinHTTP", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!session) {
PrintError(L"Failed to initialize WinHTTP session");
return response;
}
URL_COMPONENTS url_comp;
ZeroMemory(&url_comp, sizeof(url_comp));
url_comp.dwStructSize = sizeof(url_comp);
url_comp.dwHostNameLength = -1;
url_comp.dwUrlPathLength = -1;
if (!WinHttpCrackUrl(url.data(), static_cast<DWORD>(url.length()), 0, &url_comp)) {
PrintError(L"Failed to parse URL");
WinHttpCloseHandle(session);
return response;
}
std::wstring host(url_comp.lpszHostName, url_comp.dwHostNameLength);
std::wstring path(url_comp.lpszUrlPath, url_comp.dwUrlPathLength);
auto connect = WinHttpConnect(session, host.c_str(), url_comp.nPort, 0);
if (!connect) {
PrintError(L"Failed to connect to host");
WinHttpCloseHandle(session);
return response;
}
auto request = WinHttpOpenRequest(connect, L"GET", path.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES,
url_comp.nPort == INTERNET_DEFAULT_HTTPS_PORT ? WINHTTP_FLAG_SECURE : 0);
if (!request) {
PrintError(L"Failed to open request");
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
return response;
}
if (!WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) {
PrintError(L"Failed to send request");
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
return response;
}
if (!WinHttpReceiveResponse(request, NULL)) {
PrintError(L"Failed to receive response");
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
return response;
}
DWORD size = 0;
DWORD downloaded = 0;
std::vector<char> buffer(1024);
do {
if (!WinHttpQueryDataAvailable(request, &size)) {
PrintError(L"Failed to query data availability");
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
return response;
}
if (size == 0) {
break;
}
if (size > buffer.size()) {
buffer.resize(size);
}
if (WinHttpReadData(request, buffer.data(), size, &downloaded)) {
response.append(buffer.begin(), buffer.begin() + downloaded);
} else {
PrintError(L"Failed to read data");
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
return response;
}
} while (size > 0);
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
return response;
}
#ifndef NDEBUG
void MeasureExecutionTime(std::function<void()> func, bool total_duration)
{
static std::chrono::duration<double> total_diff;
const auto start_time = std::chrono::high_resolution_clock::now();
func();
const auto end_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = end_time - start_time;
if (total_duration) {
total_diff += diff;
SetConsoleTitleW((L"Total execution time: " + std::to_wstring(total_diff.count()) + L" seconds").c_str());
}
else {
SetConsoleTitleW((L"Execution time: " + std::to_wstring(diff.count()) + L" seconds").c_str());
}
}
void PrintSymbols(std::wstring_view module_name)
{
HMODULE hModule = GetModuleHandleW(module_name.data());
if (!hModule && !(hModule = LoadLibraryW(module_name.data()))) {
PrintError(L"PrintSymbols: Failed to load module.");
return;
}
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule;
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)dosHeader + dosHeader->e_lfanew);
PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)dosHeader + ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
PDWORD functions = (PDWORD)((BYTE*)dosHeader + exportDirectory->AddressOfFunctions);
PDWORD names = (PDWORD)((BYTE*)dosHeader + exportDirectory->AddressOfNames);
PWORD ordinals = (PWORD)((BYTE*)dosHeader + exportDirectory->AddressOfNameOrdinals);
for (DWORD i = 0; i < exportDirectory->NumberOfNames; i++) {
Print(L"{}", reinterpret_cast<const char*>((BYTE*)dosHeader + names[i]));
}
}
#endif // NDEBUG
}; };

View file

@ -1,165 +1,175 @@
#ifndef _UTILS_H #ifndef _UTILS_H
#define _UTILS_H #define _UTILS_H
#include <Windows.h> #include <Windows.h>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <format> #include <vector>
#include <functional> #include <format>
#include <functional>
namespace Utils #include <mutex>
{
std::string ToHexString(const std::vector<uint8_t>& byte_array, const bool insert_spaces); namespace Utils
std::string ToHexString(const uint8_t* data, size_t size, const bool insert_spaces); {
std::string ToHexString(const std::vector<uint8_t>& byte_array, const bool insert_spaces);
std::wstring ToHexWideString(const std::vector<uint8_t>& byte_array, const bool insert_spaces); std::string ToHexString(const uint8_t* data, size_t size, const bool insert_spaces);
std::wstring ToHexWideString(const uint8_t* data, size_t size, const bool insert_spaces);
std::wstring ToHexWideString(const std::vector<uint8_t>& byte_array, const bool insert_spaces);
std::string ConvertUInt8ArrayToString(uint8_t* data); std::wstring ToHexWideString(const uint8_t* data, size_t size, const bool insert_spaces);
std::wstring ConvertUInt8ArrayToWideString(uint8_t* data);
std::vector<uint8_t> ToHexBytes(const std::string& hex_string);
std::string IntegerToHexString(uintptr_t integer_value); std::vector<uint8_t> ToHexBytes(const std::wstring& hex_wstring);
std::wstring IntegerToHexWideString(uintptr_t integer_value);
std::string IntegerToHexString(uintptr_t integer_value);
std::string ToString(std::wstring_view wide_string); std::wstring IntegerToHexWideString(uintptr_t integer_value);
std::wstring ToString(std::string_view narrow_string);
std::wstring ToString(std::u16string_view utf16_string); std::string ToString(std::wstring_view wide_string);
std::wstring ToString(std::string_view narrow_string);
bool Contains(std::string_view str1, std::string_view str2, bool case_sensitive); std::wstring ToString(std::u16string_view utf16_string);
bool Contains(std::wstring_view str1, std::wstring_view str2, bool case_sensitive);
bool Contains(std::string_view str1, std::string_view str2, bool case_sensitive);
bool Equals(std::string_view str1, std::string_view str2, bool case_sensitive); bool Contains(std::wstring_view str1, std::wstring_view str2, bool case_sensitive);
bool Equals(std::wstring_view str1, std::wstring_view str2, bool case_sensitive);
bool Equals(std::string_view str1, std::string_view str2, bool case_sensitive);
void WriteIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key, std::wstring_view value); bool Equals(std::wstring_view str1, std::wstring_view str2, bool case_sensitive);
std::wstring ReadIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key);
void WriteIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key, std::wstring_view value);
#ifndef NDEBUG std::wstring ReadIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key);
//Example: MeasureExecutionTime([&]() { Function(arg1, arg2); });
void MeasureExecutionTime(std::function<void()> func); bool ReadFile(const std::wstring_view filename, std::wstring& out);
bool WriteFile(const std::wstring_view filename, const std::wstring_view content);
void PrintSymbols(std::wstring_view module_name);
#endif std::wstring HttpGetRequest(std::wstring_view url);
template<typename T> #ifndef NDEBUG
constexpr auto TypeConvert(const T& arg) void MeasureExecutionTime(std::function<void()> func, bool total_duration = true);
{ void PrintSymbols(std::wstring_view module_name);
if constexpr (std::is_same_v<T, const wchar_t*>) { #endif
return std::wstring_view(arg);
} template<typename T>
else if constexpr (std::is_same_v<T, const char*>) { constexpr auto TypeConvert(const T& arg)
return ToString(arg); {
} if constexpr (std::is_same_v<T, const wchar_t*>) {
else if constexpr (std::is_same_v < T, void*>) { return std::wstring_view(arg);
return reinterpret_cast<uintptr_t>(arg); }
} else if constexpr (std::is_same_v<T, const char*>) {
else if constexpr (std::is_pointer_v<T>) { return ToString(arg);
return *arg; }
} else if constexpr (std::is_same_v < T, void*>) {
else { return reinterpret_cast<uintptr_t>(arg);
return arg; }
} else if constexpr (std::is_pointer_v<T>) {
} return *arg;
}
std::string FormatString(std::string_view fmt, const auto&... args) else {
{ return arg;
return std::vformat(fmt, std::make_format_args(args...)); }
} }
std::wstring FormatString(std::wstring_view fmt, const auto&... args) std::string FormatString(std::string_view fmt, const auto&... args)
{ {
return std::vformat(fmt, std::make_wformat_args(TypeConvert(args)...)); return std::vformat(fmt, std::make_format_args(args...));
} }
enum class Color : WORD std::wstring FormatString(std::wstring_view fmt, const auto&... args)
{ {
Red = FOREGROUND_RED, return std::vformat(fmt, std::make_wformat_args(TypeConvert(args)...));
Green = FOREGROUND_GREEN, }
Blue = FOREGROUND_BLUE,
Yellow = FOREGROUND_RED | FOREGROUND_GREEN, enum class Color : WORD
Cyan = FOREGROUND_GREEN | FOREGROUND_BLUE, {
Magenta = FOREGROUND_RED | FOREGROUND_BLUE, Red = FOREGROUND_RED,
White = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, Green = FOREGROUND_GREEN,
Black = 0, Blue = FOREGROUND_BLUE,
Gray = FOREGROUND_INTENSITY, Yellow = FOREGROUND_RED | FOREGROUND_GREEN,
DarkRed = FOREGROUND_RED | FOREGROUND_INTENSITY, Cyan = FOREGROUND_GREEN | FOREGROUND_BLUE,
DarkGreen = FOREGROUND_GREEN | FOREGROUND_INTENSITY, Magenta = FOREGROUND_RED | FOREGROUND_BLUE,
DarkBlue = FOREGROUND_BLUE | FOREGROUND_INTENSITY, White = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
DarkYellow = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, Black = 0,
DarkCyan = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, Gray = FOREGROUND_INTENSITY,
DarkMagenta = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY DarkRed = FOREGROUND_RED | FOREGROUND_INTENSITY,
}; DarkGreen = FOREGROUND_GREEN | FOREGROUND_INTENSITY,
DarkBlue = FOREGROUND_BLUE | FOREGROUND_INTENSITY,
#if defined(_DEBUG) || defined(_CONSOLE) DarkYellow = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
void _Print(std::string_view fmt, const auto&... args) DarkCyan = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
{ DarkMagenta = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY
std::cout << FormatString(fmt, args...) << std::endl; };
}
#if defined(_DEBUG) || defined(_CONSOLE)
void _Print(std::wstring_view fmt, const auto&... args) static std::mutex console_mutex;
{ void _Print(std::string_view fmt, const auto&... args)
std::wcout << FormatString(fmt, args...) << std::endl; {
} std::lock_guard<std::mutex> lock(console_mutex);
std::cout << FormatString(fmt, args...) << std::endl;
void _Print(const std::vector<Color>& colors, std::wstring fmt, const auto&... args) }
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); void _Print(std::wstring_view fmt, const auto&... args)
if (hConsole == INVALID_HANDLE_VALUE) { {
throw std::runtime_error("Failed to get console handle"); std::lock_guard<std::mutex> lock(console_mutex);
} std::wcout << FormatString(fmt, args...) << std::endl;
}
size_t start = 0;
size_t pos = fmt.find(L"{"); void _Print(const std::vector<Color>& colors, std::wstring_view fmt, const auto&... args)
size_t color_index = 0; {
std::lock_guard<std::mutex> lock(console_mutex);
auto print_arg = [&](const auto& arg) { HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (pos != std::wstring::npos) { if (hConsole == INVALID_HANDLE_VALUE) {
std::wcout << fmt.substr(start, pos - start); throw std::runtime_error("Failed to get console handle");
if (color_index < colors.size()) { }
if (!SetConsoleTextAttribute(hConsole, static_cast<WORD>(colors[color_index]))) {
throw std::runtime_error("Failed to set console text attribute"); size_t start = 0;
} size_t pos = fmt.find(L"{");
++color_index; size_t color_index = 0;
}
auto print_arg = [&](const auto& arg) {
size_t end = fmt.find(L"}", pos); if (pos != std::wstring_view::npos) {
if (end != std::wstring::npos) { std::wcout << fmt.substr(start, pos - start);
std::wstring formatSpecifier = fmt.substr(pos, end - pos + 1); if (color_index < colors.size()) {
std::wcout << Utils::FormatString(formatSpecifier, arg); if (!SetConsoleTextAttribute(hConsole, static_cast<WORD>(colors[color_index]))) {
pos = fmt.find(L"{", end + 1); throw std::runtime_error("Failed to set console text attribute");
} }
else { ++color_index;
throw std::runtime_error("Invalid format string"); }
}
size_t end = fmt.find(L"}", pos);
if (!SetConsoleTextAttribute(hConsole, static_cast<WORD>(Color::White))) { if (end != std::wstring_view::npos) {
throw std::runtime_error("Failed to set console text attribute"); std::wstring_view format_specifier = fmt.substr(pos, end - pos + 1);
} std::wcout << FormatString(format_specifier, arg);
start = end + 1; pos = fmt.find(L"{", end + 1);
} }
else { else {
std::wcout << fmt.substr(start); throw std::runtime_error("Invalid format string");
} }
};
if (!SetConsoleTextAttribute(hConsole, static_cast<WORD>(Color::White))) {
(print_arg(args), ...); throw std::runtime_error("Failed to set console text attribute");
std::wcout << fmt.substr(start) << std::endl; }
} start = end + 1;
#endif }
}; else {
std::wcout << fmt.substr(start);
using Utils::Color; }
};
#if defined(_DEBUG) || defined(_CONSOLE)
#define Print(fmt, ...) Utils::_Print(fmt, __VA_ARGS__) (print_arg(args), ...);
#define PrintColor(colors, fmt, ...) Utils::_Print(colors, fmt, __VA_ARGS__) std::wcout << fmt.substr(start) << std::endl;
#define PrintError(fmt, ...) Utils::_Print({ Color::Red }, L"{} " fmt, L" -", __VA_ARGS__) }
#define PrintStatus(flag, label) Utils::_Print({ (flag) ? Color::Green : Color::Red }, L"{} " label, (flag) ? L" +" : L" -") #endif
#else };
#define Print(fmt, ...)
#define PrintColor(colors, fmt, ...) using Utils::Color;
#define PrintError(fmt, ...)
#define PrintStatus(flag, label) #if defined(_DEBUG) || defined(_CONSOLE)
#endif #define Print(fmt, ...) Utils::_Print(fmt, __VA_ARGS__)
#define PrintColor(colors, fmt, ...) Utils::_Print(colors, fmt, __VA_ARGS__)
#define PrintError(fmt, ...) Utils::_Print({ Color::Red }, L"{} {}", L" -", Utils::FormatString(fmt, __VA_ARGS__))
#define PrintStatus(flag, label) Utils::_Print({ (flag) ? Color::Green : Color::Red }, L"{} {}", (flag) ? L" +" : L" -", label)
#else
//#pragma warning(disable:4101)
#define Print(fmt, ...)
#define PrintColor(colors, fmt, ...)
#define PrintError(fmt, ...)
#define PrintStatus(flag, label)
#endif
#endif // _UTILS_H #endif // _UTILS_H

View file

@ -82,6 +82,7 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="BasicUtils\Hooking.h" /> <ClInclude Include="BasicUtils\Hooking.h" />
<ClInclude Include="BasicUtils\Json.h" />
<ClInclude Include="BasicUtils\Logger.h" /> <ClInclude Include="BasicUtils\Logger.h" />
<ClInclude Include="BasicUtils\Memory.h" /> <ClInclude Include="BasicUtils\Memory.h" />
<ClInclude Include="BasicUtils\MemoryScanner.h" /> <ClInclude Include="BasicUtils\MemoryScanner.h" />
@ -90,9 +91,11 @@
<ClInclude Include="framework.h" /> <ClInclude Include="framework.h" />
<ClInclude Include="Modify.h" /> <ClInclude Include="Modify.h" />
<ClInclude Include="pch.h" /> <ClInclude Include="pch.h" />
<ClInclude Include="SettingsManager.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="BasicUtils\Hooking.cpp" /> <ClCompile Include="BasicUtils\Hooking.cpp" />
<ClCompile Include="BasicUtils\Json.cpp" />
<ClCompile Include="BasicUtils\Logger.cpp" /> <ClCompile Include="BasicUtils\Logger.cpp" />
<ClCompile Include="BasicUtils\Memory.cpp" /> <ClCompile Include="BasicUtils\Memory.cpp" />
<ClCompile Include="BasicUtils\MemoryScanner.cpp" /> <ClCompile Include="BasicUtils\MemoryScanner.cpp" />
@ -101,6 +104,7 @@
<ClCompile Include="Debug.cpp" /> <ClCompile Include="Debug.cpp" />
<ClCompile Include="dllmain.cpp" /> <ClCompile Include="dllmain.cpp" />
<ClCompile Include="Modify.cpp" /> <ClCompile Include="Modify.cpp" />
<ClCompile Include="SettingsManager.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="chrome_elf.def" /> <None Include="chrome_elf.def" />

View file

@ -45,6 +45,12 @@
<ClInclude Include="BasicUtils\MemoryScanner.h"> <ClInclude Include="BasicUtils\MemoryScanner.h">
<Filter>BasicUtils</Filter> <Filter>BasicUtils</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="BasicUtils\Json.h">
<Filter>BasicUtils</Filter>
</ClInclude>
<ClInclude Include="SettingsManager.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Debug.cpp"> <ClCompile Include="Debug.cpp">
@ -74,6 +80,12 @@
<ClCompile Include="BasicUtils\MemoryScanner.cpp"> <ClCompile Include="BasicUtils\MemoryScanner.cpp">
<Filter>BasicUtils</Filter> <Filter>BasicUtils</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="BasicUtils\Json.cpp">
<Filter>BasicUtils</Filter>
</ClCompile>
<ClCompile Include="SettingsManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="chrome_elf.def"> <None Include="chrome_elf.def">

View file

@ -1,36 +1,48 @@
#include "pch.h" #include "pch.h"
#ifndef NDEBUG #ifndef NDEBUG
DWORD WINAPI Debug(LPVOID lpParam) DWORD WINAPI Debug(LPVOID lpParam)
{ {
try { try {
const auto cef_request_t_get_url = offsetof(cef_request_t, get_url); const auto cef_request_t_get_url = offsetof(cef_request_t, get_url);
const auto cef_zip_reader_get_file_name = offsetof(cef_zip_reader_t, get_file_name); const auto cef_zip_reader_t_get_file_name = offsetof(cef_zip_reader_t, get_file_name);
const auto cef_zip_reader_t_read_file = offsetof(cef_zip_reader_t, read_file); const auto cef_zip_reader_t_read_file = offsetof(cef_zip_reader_t, read_file);
if (cef_request_t_get_url != cef_request_t_get_url_offset) { if (cef_request_t_get_url != SettingsManager::m_cef_request_t_get_url_offset) {
PrintError(L"The offset of cef_request_t::get_url has changed: {}", cef_request_t_get_url); PrintError(L"The offset of cef_request_t::get_url has changed: {}", cef_request_t_get_url);
} }
if (cef_zip_reader_get_file_name != cef_zip_reader_get_file_name_offset) { if (cef_zip_reader_t_get_file_name != SettingsManager::m_cef_zip_reader_t_get_file_name_offset) {
PrintError(L"The offset of cef_zip_reader_t::get_file_name has changed: {}", cef_zip_reader_get_file_name); PrintError(L"The offset of cef_zip_reader_t::get_file_name has changed: {}", cef_zip_reader_t_get_file_name);
} }
if (cef_zip_reader_t_read_file != cef_zip_reader_t_read_file_offset) { if (cef_zip_reader_t_read_file != SettingsManager::m_cef_zip_reader_t_read_file_offset) {
PrintError(L"The offset of cef_zip_reader_t::read_file has changed: {}", cef_zip_reader_t_read_file); PrintError(L"The offset of cef_zip_reader_t::read_file has changed: {}", cef_zip_reader_t_read_file);
} }
//Utils::PrintSymbols(L"chrome_elf.dll"); // Utils::PrintSymbols(L"chrome_elf.dll");
Utils::MeasureExecutionTime([&]() { Utils::MeasureExecutionTime([&]() {
//for (const auto& pattern : MemoryScanner::ParseBytePattern((L"4? ?D 1?"))) {
// Print(L"HalfByte 1: Data = {}, Wildcard = {}", static_cast<int>(pattern.half_byte[0].data), pattern.half_byte[0].wildcard);
}); // Print(L"HalfByte 2: Data = {}, Wildcard = {}\n", static_cast<int>(pattern.half_byte[1].data), pattern.half_byte[1].wildcard);
//}
}
catch (const std::exception& e) { //MemoryScanner::ScanFirst(L"app-developer").get_first_reference(L"48 8D 15").print_address();
Print(e.what()); //MemoryScanner::ScanFirst(L"app-developer").get_first_reference(L"4? ?D 1?").print_address();
}
return 0; //for (const auto& it : MemoryScanner::ScanFirst(L"app-developer").get_all_references(L"68", false))
} //{
// it.print_address();
//}
//Print(L"{}", MemoryScanner::ScanFirst(L"55 8B EC 56 57 8B F1 33 C0 8B 4D 08 8B FE AB 8D 51 01 AB AB").get_all_references(L"E8").size());
});
}
catch (const std::exception& e) {
PrintError(L"{}", e.what());
}
return 0;
}
#endif #endif

View file

@ -1,244 +1,153 @@
#include "pch.h" #include "pch.h"
using _cef_urlrequest_create = void* (*)(void* request, void* client, void* request_context); using _cef_urlrequest_create = void* (*)(void* request, void* client, void* request_context);
static _cef_urlrequest_create cef_urlrequest_create_orig = nullptr; static _cef_urlrequest_create cef_urlrequest_create_orig = nullptr;
using _cef_string_userfree_utf16_free = void (*)(void* str); using _cef_string_userfree_utf16_free = void (*)(void* str);
static _cef_string_userfree_utf16_free cef_string_userfree_utf16_free_orig = nullptr; static _cef_string_userfree_utf16_free cef_string_userfree_utf16_free_orig = nullptr;
using _cef_zip_reader_create = void* (*)(void* stream); using _cef_zip_reader_create = void* (*)(void* stream);
static _cef_zip_reader_create cef_zip_reader_create_orig = nullptr; static _cef_zip_reader_create cef_zip_reader_create_orig = nullptr;
using _cef_zip_reader_t_read_file = int(__stdcall*)(void* self, void* buffer, size_t bufferSize); using _cef_zip_reader_t_read_file = int(__stdcall*)(void* self, void* buffer, size_t bufferSize);
static _cef_zip_reader_t_read_file cef_zip_reader_t_read_file_orig = nullptr; static _cef_zip_reader_t_read_file cef_zip_reader_t_read_file_orig = nullptr;
static constexpr std::array<std::wstring_view, 3> block_list = { L"/ads/", L"/ad-logic/", L"/gabo-receiver-service/" }; #ifndef NDEBUG
void* cef_urlrequest_create_hook(struct _cef_request_t* request, void* client, void* request_context)
#ifndef NDEBUG #else
void* cef_urlrequest_create_hook(struct _cef_request_t* request, void* client, void* request_context) void* cef_urlrequest_create_hook(void* request, void* client, void* request_context)
#else #endif
void* cef_urlrequest_create_hook(void* request, void* client, void* request_context) {
#endif #ifndef NDEBUG
{ cef_string_utf16_t* url_utf16 = request->get_url(request);
#ifndef NDEBUG std::wstring url = Utils::ToString(url_utf16->str);
cef_string_utf16_t* url_utf16 = request->get_url (request); #else
std::wstring url = Utils::ToString(url_utf16->str); const auto get_url = *(void* (__stdcall**)(void*))((uintptr_t)request + SettingsManager::m_cef_request_t_get_url_offset);
#else auto url_utf16 = get_url(request);
const auto get_url = *(void* (__stdcall**)(void*))((uintptr_t)request + cef_request_t_get_url_offset); std::wstring url = *reinterpret_cast<wchar_t**>(url_utf16);
auto url_utf16 = get_url(request); #endif
std::wstring url = *reinterpret_cast<wchar_t**>(url_utf16); for (const auto& block_url : SettingsManager::m_block_list) {
#endif if (std::wstring_view::npos != url.find(block_url)) {
for (const auto& blockurl : block_list) { Log(L"blocked - " + url, LogLevel::Info);
if (std::wstring_view::npos != url.find (blockurl)) { cef_string_userfree_utf16_free_orig((void*)url_utf16);
Log(L"blocked - " + url, LogLevel::Info); return nullptr;
cef_string_userfree_utf16_free_orig((void*)url_utf16); }
return nullptr; }
}
} cef_string_userfree_utf16_free_orig((void*)url_utf16);
cef_string_userfree_utf16_free_orig((void*)url_utf16); Log(L"allow - " + url, LogLevel::Info);
Log(L"allow - " + url, LogLevel::Info); return cef_urlrequest_create_orig(request, client, request_context);
return cef_urlrequest_create_orig (request, client, request_context); }
}
#ifndef NDEBUG
#ifndef NDEBUG int cef_zip_reader_t_read_file_hook(struct _cef_zip_reader_t* self, void* buffer, size_t bufferSize)
int cef_zip_reader_t_read_file_hook(struct _cef_zip_reader_t* self, void* buffer, size_t bufferSize) #else
#else int cef_zip_reader_t_read_file_hook(void* self, void* buffer, size_t bufferSize)
int cef_zip_reader_t_read_file_hook(void* self, void* buffer, size_t bufferSize) #endif
#endif {
{ int _retval = cef_zip_reader_t_read_file_orig(self, buffer, bufferSize);
int _retval = cef_zip_reader_t_read_file_orig(self, buffer, bufferSize);
#ifndef NDEBUG
#ifndef NDEBUG std::wstring file_name = Utils::ToString(self->get_file_name(self)->str);
std::wstring file_name = Utils::ToString(self->get_file_name(self)->str); #else
#else const auto get_file_name = (*(void* (__stdcall**)(void*))((uintptr_t)self + SettingsManager::m_cef_zip_reader_t_get_file_name_offset));
const auto get_file_name = (*(void* (__stdcall**)(void*))((uintptr_t)self + cef_zip_reader_get_file_name_offset)); std::wstring file_name = *reinterpret_cast<wchar_t**>(get_file_name(self));
std::wstring file_name = *reinterpret_cast<wchar_t**>(get_file_name(self)); #endif
#endif
if (SettingsManager::m_zip_reader.contains(file_name)) {
if (file_name == L"home-hpto.css") { for (auto& [name, data] : SettingsManager::m_zip_reader.at(file_name)) {
const auto hpto = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L".WiPggcPDzbwGxoxwLWFf{display:-webkit-box;display:-ms-flexbox;display:flex;"); const auto& sig = data.at(L"Signature").get_string();
if (hpto.is_valid()) { auto scan = MemoryScanner::ScanResult(data.at(L"Address").get_integer(), reinterpret_cast<uintptr_t>(buffer), bufferSize, true);
if (hpto.write(".WiPggcPDzbwGxoxwLWFf{display:-webkit-box;display:-ms-flexbox;display:none;")) { if (!scan.is_valid(sig)) {
Log(L"hptocss patched!", LogLevel::Info); scan = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, sig);
} data.at(L"Address") = static_cast<int>(scan.rva());
else { }
Log(L"hptocss patch failed!", LogLevel::Error);
} if (scan.is_valid()) {
} const auto& value = data.at(L"Value").get_string();
else { const auto& offset = data.at(L"Offset").get_integer();
Log(L"hptocss - failed not found!", LogLevel::Error); const auto& fill = data.at(L"Fill").get_integer();
}
} if (fill > 0) {
scan.offset(offset).write(Utils::ToString(std::wstring(fill, ' ').append(value))) ? Log(name + L" - patch success!", LogLevel::Info) : Log(name + L" - patch failed!", LogLevel::Error);
if (file_name == L"xpui.js") { }
const auto skipads = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L"adsEnabled:!0"); else {
if (skipads.is_valid()) { scan.offset(offset).write(Utils::ToString(value)) ? Log(name + L" - patch success!", LogLevel::Info) : Log(name + L" - patch failed!", LogLevel::Error);
if (skipads.offset(12).write("1")) { }
Log(L"adsEnabled patched!", LogLevel::Info); }
} else {
else { Log(name + L" - unable to find signature in memory!", LogLevel::Error);
Log(L"adsEnabled - patch failed!", LogLevel::Error); }
} }
} }
else { return _retval;
Log(L"adsEnabled - failed not found!", LogLevel::Error); }
}
#ifndef NDEBUG
const auto sponsorship = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L".set(\"allSponsorships\",t.sponsorships)}}(e,t);"); cef_zip_reader_t* cef_zip_reader_create_hook(cef_stream_reader_t* stream)
if (sponsorship.is_valid()) { #else
if (sponsorship.offset(5).write(std::string(15, ' ').append("\"").c_str())) { void* cef_zip_reader_create_hook(void* stream)
Log(L"sponsorship patched!", LogLevel::Info); #endif
} {
else { #ifndef NDEBUG
Log(L"sponsorship patch failed!", LogLevel::Error); cef_zip_reader_t* zip_reader = (cef_zip_reader_t*)cef_zip_reader_create_orig(stream);
} cef_zip_reader_t_read_file_orig = (_cef_zip_reader_t_read_file)zip_reader->read_file;
} #else
else { auto zip_reader = cef_zip_reader_create_orig(stream);
Log(L"sponsorship - failed not found!", LogLevel::Error); cef_zip_reader_t_read_file_orig = *(_cef_zip_reader_t_read_file*)((uintptr_t)zip_reader + SettingsManager::m_cef_zip_reader_t_read_file_offset);
} #endif
const auto skipsentry = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L"sentry.io"); if (!Hooking::HookFunction(&(PVOID&)cef_zip_reader_t_read_file_orig, (PVOID)cef_zip_reader_t_read_file_hook)) {
if (skipsentry.is_valid()) { Log(L"Failed to hook cef_zip_reader::read_file function!", LogLevel::Error);
if (skipsentry.write("localhost")) { }
Log(L"sentry.io -> localhost patched!", LogLevel::Info); else {
} Hooking::UnhookFunction(&(PVOID&)cef_zip_reader_create_orig);
else { }
Log(L"sentry.io -> localhost - patch failed!", LogLevel::Error);
} return zip_reader;
} }
else {
Log(L"sentry.io -> localhost - failed not found!", LogLevel::Error); DWORD WINAPI EnableDeveloper(LPVOID lpParam)
} {
auto& dev_data = SettingsManager::m_developer.at(SettingsManager::m_architecture);
const auto ishptoenable = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L"hptoEnabled:!0"); const auto& sig = dev_data.at(L"Signature").get_string();
if (ishptoenable.is_valid()) auto scan = MemoryScanner::ScanResult(dev_data.at(L"Address").get_integer(), L"", true);
{ if (!scan.is_valid(sig)) {
if (ishptoenable.offset(13).write("1")) { scan = MemoryScanner::ScanFirst(sig);
Log(L"hptoEnabled patched!", LogLevel::Info); dev_data.at(L"Address") = static_cast<int>(scan.rva());
} }
else {
Log(L"hptoEnabled - patch failed!", LogLevel::Error); if (scan.is_valid()) {
} if (scan.offset(dev_data.at(L"Offset").get_integer()).write(Utils::ToHexBytes(dev_data.at(L"Value").get_string()))) {
} Log(L"Developer - successfully patched!", LogLevel::Info);
else { }
Log(L"hptoEnabled - failed not found!", LogLevel::Error); else {
} Log(L"Developer - failed to patch!", LogLevel::Error);
}
const auto ishptohidden = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L"isHptoHidden:!0"); }
if (ishptohidden.is_valid()) { else {
if (ishptohidden.offset(14).write("1")) { Log(L"Developer - unable to find signature in memory!", LogLevel::Error);
Log(L"isHptoHidden patched!", LogLevel::Info); }
}
else { return 0;
Log(L"isHptoHidden - patch failed!", LogLevel::Error); }
}
} DWORD WINAPI BlockAds(LPVOID lpParam)
else { {
Log(L"isHptoHidden - failed not found!", LogLevel::Error); cef_string_userfree_utf16_free_orig = (_cef_string_userfree_utf16_free)MemoryScanner::GetFunctionAddress("libcef.dll", "cef_string_userfree_utf16_free").data();
} if (!cef_string_userfree_utf16_free_orig) {
Log(L"BlockAds - patch failed!", LogLevel::Error);
const auto sp_localhost = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L"sp://ads/v1/ads/"); return 0;
if (sp_localhost.is_valid()) { }
if (sp_localhost.write("sp://localhost//")) {
Log(L"sp://ads/v1/ads/ patched!", LogLevel::Info); cef_urlrequest_create_orig = (_cef_urlrequest_create)MemoryScanner::GetFunctionAddress("libcef.dll", "cef_urlrequest_create").hook((PVOID)cef_urlrequest_create_hook);
} cef_urlrequest_create_orig ? Log(L"BlockAds - patch success!", LogLevel::Info) : Log(L"BlockAds - patch failed!", LogLevel::Error);
else { return 0;
Log(L"sp://ads/v1/ads/ - patch failed!", LogLevel::Error); }
}
} DWORD WINAPI BlockBanner(LPVOID lpParam)
else { {
Log(L"sp://ads/v1/ads/ - failed not found!", LogLevel::Error); cef_zip_reader_create_orig = (_cef_zip_reader_create)MemoryScanner::GetFunctionAddress("libcef.dll", "cef_zip_reader_create").hook((PVOID)cef_zip_reader_create_hook);
} cef_zip_reader_create_orig ? Log(L"BlockBanner - patch success!", LogLevel::Info) : Log(L"BlockBanner - patch failed!", LogLevel::Error);
return 0;
const auto premium_free = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L"e.session?.productState?.catalogue?.toLowerCase()");
if (premium_free.is_valid()) {
//if (premium_free.offset(-1).write(std::string(48, ' ').append("\"\""))) {
if (premium_free.write("\"blockthespot-team-says-meow-meow-meow-meow-meow\"")) {
Log(L"premium patched!", LogLevel::Info);
}
else {
Log(L"premium - patch failed!", LogLevel::Error);
}
}
else {
Log(L"premium - failed not found!", LogLevel::Error);
}
}
return _retval;
}
#ifndef NDEBUG
cef_zip_reader_t* cef_zip_reader_create_hook(cef_stream_reader_t* stream)
#else
void* cef_zip_reader_create_hook(void* stream)
#endif
{
#ifndef NDEBUG
cef_zip_reader_t* zip_reader = (cef_zip_reader_t*)cef_zip_reader_create_orig(stream);
cef_zip_reader_t_read_file_orig = (_cef_zip_reader_t_read_file)zip_reader->read_file;
#else
auto zip_reader = cef_zip_reader_create_orig(stream);
cef_zip_reader_t_read_file_orig = *(_cef_zip_reader_t_read_file*)((uintptr_t)zip_reader + cef_zip_reader_t_read_file_offset);
#endif
if (!Hooking::HookFunction(&(PVOID&)cef_zip_reader_t_read_file_orig, (PVOID)cef_zip_reader_t_read_file_hook)) {
Log(L"zip_reader_read_file_hook - patch failed!", LogLevel::Error);
}
return zip_reader;
}
DWORD WINAPI EnableDeveloper(LPVOID lpParam)
{
#ifdef _WIN64
const auto app_developer = MemoryScanner::ScanFirst(L"app-developer").get_all_matching_codes({ 0x48, 0x8D, 0x15 });
const auto developer = app_developer.size() > 1 ? app_developer[1].scan_first(L"D1 EB").offset(2) : MemoryScanner::ScanResult();
if (developer.is_valid({ 0x80, 0xE3, 0x01 })) {
if (developer.write({ 0xB3, 0x01, 0x90 })) {
Log(L"Developer - patch success!", LogLevel::Info);
}
else {
Log(L"Developer - patch failed!", LogLevel::Error);
}
}
else {
Log(L"Developer - failed not found!", LogLevel::Error);
}
#else
//const auto app_developer = MemoryScanner::ScanFirst(L"app-developer").get_all_matching_codes({ 0x68 }, false);
const auto developer = MemoryScanner::ScanFirst(L"25 01 FF FF FF 89 ?? ?? ?? FF FF");
if (developer.is_valid()) {
if (developer.write({ 0xB8, 0x03, 0x00 })) {
Log(L"Developer - patch success!", LogLevel::Info);
}
else {
Log(L"Developer - patch failed!", LogLevel::Error);
}
}
else {
Log(L"Developer - failed not found!", LogLevel::Error);
}
#endif
return 0;
}
DWORD WINAPI BlockAds(LPVOID lpParam)
{
cef_string_userfree_utf16_free_orig = (_cef_string_userfree_utf16_free)MemoryScanner::GetFunctionAddress("libcef.dll", "cef_string_userfree_utf16_free").data();
if (!cef_string_userfree_utf16_free_orig) {
Log(L"BlockAds - patch failed!", LogLevel::Error);
return 0;
}
cef_urlrequest_create_orig = (_cef_urlrequest_create)MemoryScanner::GetFunctionAddress("libcef.dll", "cef_urlrequest_create").hook((PVOID)cef_urlrequest_create_hook);
cef_urlrequest_create_orig ? Log(L"BlockAds - patch success!", LogLevel::Info) : Log(L"BlockAds - patch failed!", LogLevel::Error);
return 0;
}
DWORD WINAPI BlockBanner(LPVOID lpParam)
{
cef_zip_reader_create_orig = (_cef_zip_reader_create)MemoryScanner::GetFunctionAddress("libcef.dll", "cef_zip_reader_create").hook((PVOID)cef_zip_reader_create_hook);
cef_zip_reader_create_orig ? Log(L"BlockBanner - patch success!", LogLevel::Info) : Log(L"BlockBanner - patch failed!", LogLevel::Error);
return 0;
} }

View file

@ -1,14 +1,4 @@
#pragma once #pragma once
DWORD WINAPI EnableDeveloper(LPVOID lpParam); DWORD WINAPI EnableDeveloper(LPVOID lpParam);
DWORD WINAPI BlockAds(LPVOID lpParam); DWORD WINAPI BlockAds(LPVOID lpParam);
DWORD WINAPI BlockBanner(LPVOID lpParam); DWORD WINAPI BlockBanner(LPVOID lpParam);
#ifdef _WIN64
static int cef_request_t_get_url_offset = 48;
static int cef_zip_reader_get_file_name_offset = 72;
static int cef_zip_reader_t_read_file_offset = 112;
#else
static int cef_request_t_get_url_offset = 24;
static int cef_zip_reader_get_file_name_offset = 36;
static int cef_zip_reader_t_read_file_offset = 56;
#endif

369
src/SettingsManager.cpp Normal file
View file

@ -0,0 +1,369 @@
#include "pch.h"
#include <chrono>
#include <thread>
void SettingsManager::Init()
{
SyncConfigFile();
Logger::Init(L"blockthespot.log", SettingsManager::m_config.at(L"Enable_Log"));
m_app_settings_file = L"blockthespot_settings.json";
if (!Load()) {
if (!Save()) {
Log(Utils::FormatString(L"Failed to open settings file: {}", m_app_settings_file), LogLevel::Error);
}
}
auto thread = CreateThread(NULL, 0, Update, NULL, 0, NULL);
if (thread != nullptr) {
CloseHandle(thread);
}
}
bool SettingsManager::Save()
{
m_block_list = { L"/ads/", L"/ad-logic/", L"/gabo-receiver-service/" };
m_zip_reader = {
{L"home-hpto.css", {
{L"hptocss", {
{L"Signature", L".WiPggcPDzbwGxoxwLWFf{display:-webkit-box;display:-ms-flexbox;display:flex;"},
{L"Value", L".WiPggcPDzbwGxoxwLWFf{display:-webkit-box;display:-ms-flexbox;display:none;"},
{L"Offset", 0},
{L"Fill", 0},
{L"Address", 0}
}}
}},
{L"xpui.js", {
{L"adsEnabled", {
{ L"Signature", L"adsEnabled:!0"},
{ L"Value", L"1"},
{ L"Offset", 12},
{ L"Fill", 0},
{ L"Address", 0}
}},
{L"sponsorship", {
{L"Signature", L".set(\"allSponsorships\",t.sponsorships)}}(e,t);" },
{L"Value", L"\""},
{L"Offset", 5},
{L"Fill", 15},
{L"Address", 0}
}},
{L"skipsentry", {
{L"Signature", L"sentry.io"},
{L"Value", L"localhost"},
{L"Offset", 0},
{L"Fill", 0},
{L"Address", 0}
}},
{L"hptoEnabled", {
{L"Signature", L"hptoEnabled:!0"},
{L"Value", L"1"},
{L"Offset", 13},
{L"Fill", 0},
{L"Address", 0}
}},
{L"ishptohidden", {
{L"Signature", L"isHptoHidden:!0"},
{L"Value", L"1"},
{L"Offset", 14},
{L"Fill", 0},
{L"Address", 0}
}},
{L"sp_localhost", {
{L"Signature", L"sp://ads/v1/ads/"},
{L"Value", L"sp://localhost//"},
{L"Offset", 0},
{L"Fill", 0},
{L"Address", 0}
}},
{L"premium_free", {
{ L"Signature", L"e.session?.productState?.catalogue?.toLowerCase()" },
{ L"Value", L"\"\""},
{ L"Offset", -1},
{ L"Fill", 48},
{ L"Address", 0}
}}
}}
};
m_developer = {
{L"x64", {
{L"Signature", L"80 E3 01 48 8B 95 ?? ?? ?? ?? 48 83 FA 10"},
{L"Value", L"B3 01 90"},
{L"Offset", 0},
{L"Address", 0}
}},
{L"x32", {
{L"Signature", L"25 01 FF FF FF 89 ?? ?? ?? FF FF"},
{L"Value", L"B8 03 00"},
{L"Offset", 0},
{L"Address", 0}
}}
};
m_cef_offsets = {
{L"x64", {
{L"cef_request_t_get_url", 48},
{L"cef_zip_reader_t_get_file_name", 72},
{L"cef_zip_reader_t_read_file", 112},
}},
{L"x32", {
{L"cef_request_t_get_url", 24},
{L"cef_zip_reader_t_get_file_name", 36},
{L"cef_zip_reader_t_read_file", 56},
}}
};
m_cef_offsets.at(m_architecture).at(L"cef_request_t_get_url").get_to(m_cef_request_t_get_url_offset);
m_cef_offsets.at(m_architecture).at(L"cef_zip_reader_t_get_file_name").get_to(m_cef_zip_reader_t_get_file_name_offset);
m_cef_offsets.at(m_architecture).at(L"cef_zip_reader_t_read_file").get_to(m_cef_zip_reader_t_read_file_offset);
m_app_settings = {
{L"Latest Release Date", m_latest_release_date},
{L"Block List", m_block_list},
{L"Zip Reader", m_zip_reader},
{L"Developer", m_developer},
{L"Cef Offsets", m_cef_offsets}
};
if (!Utils::WriteFile(m_app_settings_file, m_app_settings.dump(4))) {
Log(Utils::FormatString(L"Failed to open settings file: {}", m_app_settings_file), LogLevel::Error);
return false;
}
return true;
}
bool SettingsManager::Load()
{
std::wstring buffer;
if (!Utils::ReadFile(m_app_settings_file, buffer)) {
return false;
}
m_app_settings = Json::parse(buffer);
if (!ValidateSettings(m_app_settings)) {
return false;
}
m_app_settings.at(L"Latest Release Date").get_to(m_latest_release_date);
m_app_settings.at(L"Block List").get_to(m_block_list);
m_app_settings.at(L"Zip Reader").get_to(m_zip_reader);
m_app_settings.at(L"Developer").get_to(m_developer);
m_app_settings.at(L"Cef Offsets").get_to(m_cef_offsets);
m_app_settings.at(L"Cef Offsets").at(m_architecture).at(L"cef_request_t_get_url").get_to(m_cef_request_t_get_url_offset);
m_app_settings.at(L"Cef Offsets").at(m_architecture).at(L"cef_zip_reader_t_get_file_name").get_to(m_cef_zip_reader_t_get_file_name_offset);
m_app_settings.at(L"Cef Offsets").at(m_architecture).at(L"cef_zip_reader_t_read_file").get_to(m_cef_zip_reader_t_read_file_offset);
if (!m_cef_request_t_get_url_offset || !m_cef_zip_reader_t_get_file_name_offset || !m_cef_zip_reader_t_read_file_offset) {
Log(L"Failed to load cef offsets from settings file.", LogLevel::Error);
return false;
}
return true;
}
DWORD WINAPI SettingsManager::Update(LPVOID lpParam)
{
const auto end_time = std::chrono::steady_clock::now() + std::chrono::minutes(1);
while (std::chrono::steady_clock::now() < end_time) {
m_settings_changed = (
m_app_settings.at(L"Latest Release Date") != m_latest_release_date ||
m_app_settings.at(L"Block List") != m_block_list ||
m_app_settings.at(L"Zip Reader") != m_zip_reader ||
m_app_settings.at(L"Developer") != m_developer ||
m_app_settings.at(L"Cef Offsets") != m_cef_offsets
);
if (m_settings_changed) {
m_app_settings.at(L"Latest Release Date") = m_latest_release_date;
m_app_settings.at(L"Block List") = m_block_list;
m_app_settings.at(L"Zip Reader") = m_zip_reader;
m_app_settings.at(L"Developer") = m_developer;
m_app_settings.at(L"Cef Offsets") = m_cef_offsets;
if (!Utils::WriteFile(m_app_settings_file, m_app_settings.dump(4))) {
Log(Utils::FormatString(L"Failed to open settings file: {}", m_app_settings_file), LogLevel::Error);
}
}
if (m_config.at(L"Enable_Auto_Update") && Logger::HasError()) {
static Json release_info;
if (release_info.empty()) {
release_info = Json::parse(Utils::HttpGetRequest(L"https://api.github.com/repos/mrpond/BlockTheSpot/releases/latest"));
if (!release_info.contains(L"published_at") || !release_info.at(L"published_at").is_string()) {
Log(L"Release info is invalid or doesn't contain published_at field.", LogLevel::Error);
}
else if (release_info.at(L"published_at").get_string() != m_latest_release_date) {
Json remote_app_settings = Json::parse(Utils::HttpGetRequest(L"https://raw.githubusercontent.com/mrpond/BlockTheSpot/master/blockthespot_settings.json"));
if (ValidateSettings(remote_app_settings)) {
m_app_settings = remote_app_settings;
m_app_settings.at(L"Latest Release Date") = release_info.at(L"published_at").get_string();
if (!Utils::WriteFile(m_app_settings_file, m_app_settings.dump(4))) {
Log(Utils::FormatString(L"Failed to open settings file: {}", m_app_settings_file), LogLevel::Error);
}
//else if (MessageBoxW(NULL, L"A new version of BlockTheSpot is available! To apply the update, the program needs to be restarted. Would you like to restart now?", L"BlockTheSpot Update Available", MB_YESNO | MB_ICONQUESTION) == IDYES) {
// wchar_t exe_path[MAX_PATH];
// GetModuleFileNameW(NULL, exe_path, MAX_PATH);
// _wsystem(Utils::FormatString(L"powershell.exe -Command \"Stop-Process -Name Spotify; Start-Process -FilePath \"{}\"\"", exe_path).c_str());
//}
}
else {
Log(L"Failed to parse app settings from URL.", LogLevel::Error);
}
}
else {
Log(L"No new version of BlockTheSpot available.", LogLevel::Info);
}
}
}
std::this_thread::sleep_for(std::chrono::seconds(20));
}
return 0;
}
bool SettingsManager::ValidateSettings(const Json& settings)
{
// App Settings
if (settings.empty() || !settings.is_object()) {
Log(L"Invalid JSON format in settings file.", LogLevel::Error);
return false;
}
const std::vector<std::wstring> keys = { L"Latest Release Date", L"Block List", L"Zip Reader", L"Developer", L"Cef Offsets" };
for (const auto& key : keys) {
if (!settings.contains(key)) {
Log(L"Key '" + key + L"' is missing in settings file.", LogLevel::Error);
return false;
}
}
if (!settings.at(L"Latest Release Date").is_string() ||
!settings.at(L"Block List").is_array() ||
!settings.at(L"Zip Reader").is_object() ||
!settings.at(L"Developer").is_object() ||
!settings.at(L"Cef Offsets").is_object()) {
Log(L"Invalid data types in settings file.", LogLevel::Error);
return false;
}
// Block List
for (const auto& item : settings.at(L"Block List").get_array()) {
if (!item.is_string()) {
Log(L"Invalid data type in Block List.", LogLevel::Error);
return false;
}
}
// Cef Offsets
for (const auto& [arch, offset_data] : settings.at(L"Cef Offsets")) {
if (arch != L"x64" && arch != L"x32") {
Log(L"Invalid architecture in Cef Offsets settings.", LogLevel::Error);
return false;
}
if (!offset_data.contains(L"cef_request_t_get_url") || !offset_data.at(L"cef_request_t_get_url").is_integer() ||
!offset_data.contains(L"cef_zip_reader_t_get_file_name") || !offset_data.at(L"cef_zip_reader_t_get_file_name").is_integer() ||
!offset_data.contains(L"cef_zip_reader_t_read_file") || !offset_data.at(L"cef_zip_reader_t_read_file").is_integer()) {
Log(L"Invalid data for Cef Offsets in settings file.", LogLevel::Error);
return false;
}
}
// Developer
for (const auto& [arch, dev_data] : settings.at(L"Developer")) {
if (arch != L"x64" && arch != L"x32") {
Log(L"Invalid architecture in Developer settings.", LogLevel::Error);
return false;
}
if (!dev_data.contains(L"Signature") || !dev_data.at(L"Signature").is_string() ||
!dev_data.contains(L"Value") || !dev_data.at(L"Value").is_string() ||
!dev_data.contains(L"Offset") || !dev_data.at(L"Offset").is_integer() ||
!dev_data.contains(L"Address") || !dev_data.at(L"Address").is_integer()) {
Log(L"Invalid data for Developer settings in settings file.", LogLevel::Error);
return false;
}
}
// Zip Reader
for (const auto& [file_name, file_data] : settings.at(L"Zip Reader")) {
if (file_name.empty()) {
Log(L"File name is empty for a Zip Reader entry in settings file.", LogLevel::Error);
return false;
}
if (!file_data.is_object()) {
Log(L"Invalid data for Zip Reader entry '" + file_name + L"' in settings file.", LogLevel::Error);
return false;
}
for (const auto& [setting_name, setting_data] : file_data) {
if (setting_name.empty()) {
Log(L"Setting name is empty for a setting in Zip Reader entry '" + file_name + L"' in settings file.", LogLevel::Error);
return false;
}
if (!setting_data.contains(L"Signature") || !setting_data.at(L"Signature").is_string() ||
!setting_data.contains(L"Value") || !setting_data.at(L"Value").is_string() ||
!setting_data.contains(L"Offset") || !setting_data.at(L"Offset").is_integer() ||
!setting_data.contains(L"Fill") || !setting_data.at(L"Fill").is_integer() ||
!setting_data.contains(L"Address") || !setting_data.at(L"Address").is_integer()) {
Log(L"Invalid data for setting '" + setting_name + L"' in Zip Reader entry '" + file_name + L"' in settings file.", LogLevel::Error);
return false;
}
}
}
return true;
}
void SettingsManager::SyncConfigFile()
{
std::wstring ini_path = L".\\config.ini";
m_config = {
{L"Block_Ads", true},
{L"Block_Banner", true},
{L"Enable_Developer", true},
{L"Enable_Log", false},
{L"Enable_Auto_Update", true},
};
for (const auto& [key, value] : m_config) {
std::wstring current_value = Utils::ReadIniFile(ini_path, L"Config", key);
if (current_value.empty() || (current_value != L"1" && current_value != L"0")) {
Utils::WriteIniFile(ini_path, L"Config", key, value ? L"1" : L"0");
}
else {
m_config.at(key) = (current_value == L"1");
}
PrintStatus(m_config.at(key), key);
}
}
std::vector<std::wstring> SettingsManager::m_block_list;
Json SettingsManager::m_zip_reader;
Json SettingsManager::m_developer;
Json SettingsManager::m_cef_offsets;
Json SettingsManager::m_app_settings;
std::wstring SettingsManager::m_latest_release_date;
std::wstring SettingsManager::m_app_settings_file;
bool SettingsManager::m_settings_changed;
std::unordered_map<std::wstring, bool> SettingsManager::m_config;
int SettingsManager::m_cef_request_t_get_url_offset;
int SettingsManager::m_cef_zip_reader_t_get_file_name_offset;
int SettingsManager::m_cef_zip_reader_t_read_file_offset;
#ifdef _WIN64
std::wstring SettingsManager::m_architecture = L"x64";
#else
std::wstring SettingsManager::m_architecture = L"x32";
#endif

34
src/SettingsManager.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef SETTINGS_MANAGER_H
#define SETTINGS_MANAGER_H
class SettingsManager {
public:
static void Init();
static std::unordered_map<std::wstring, bool> m_config;
static std::vector<std::wstring> m_block_list;
static Json m_developer;
static Json m_zip_reader;
static Json m_cef_offsets;
static int m_cef_request_t_get_url_offset;
static int m_cef_zip_reader_t_get_file_name_offset;
static int m_cef_zip_reader_t_read_file_offset;
static std::wstring m_architecture;
private:
static bool Save();
static bool Load();
static DWORD WINAPI Update(LPVOID lpParam);
static bool ValidateSettings(const Json& settings);
static void SyncConfigFile();
static Json m_app_settings;
static std::wstring m_latest_release_date;
static std::wstring m_app_settings_file;
static bool m_settings_changed;
};
#endif // SETTINGS_MANAGER_H

View file

@ -1,35 +1,5 @@
#include "pch.h" #include "pch.h"
bool block_ads = true;
bool block_banner = true;
bool enable_developer = true;
bool enable_log = false;
void SyncConfigFile() {
std::wstring ini_path = L".\\config.ini";
std::map<std::wstring, bool*> config = {
{L"Block_Ads", &block_ads},
{L"Block_Banner", &block_banner},
{L"Enable_Developer", &enable_developer},
{L"Enable_Log", &enable_log},
};
for (const auto& [key, bool_ptr] : config) {
std::wstring current_value = Utils::ReadIniFile(ini_path, L"Config", key);
if (current_value.empty() || current_value != L"1" && current_value != L"0") {
Utils::WriteIniFile(ini_path, L"Config", key, *bool_ptr ? L"1" : L"0");
}
else {
*bool_ptr = (current_value == L"1");
}
}
PrintStatus(block_ads, L"Block ADS");
PrintStatus(block_banner, L"Block Banner");
PrintStatus(enable_developer, L"Enable Developer");
PrintStatus(enable_log, L"Enable Log");
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{ {
DisableThreadLibraryCalls(hModule); DisableThreadLibraryCalls(hModule);
@ -59,25 +29,23 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReser
CloseHandle(hThread); CloseHandle(hThread);
} }
#endif #endif
SettingsManager::Init();
SyncConfigFile(); if (SettingsManager::m_config.at(L"Block_Ads")) {
Logger::Init(L"blockthespot.log", enable_log);
if (block_ads) {
hThread = CreateThread(NULL, 0, BlockAds, NULL, 0, NULL); hThread = CreateThread(NULL, 0, BlockAds, NULL, 0, NULL);
if (hThread != nullptr) { if (hThread != nullptr) {
CloseHandle(hThread); CloseHandle(hThread);
} }
} }
if (block_banner) { if (SettingsManager::m_config.at(L"Block_Banner")) {
hThread = CreateThread(NULL, 0, BlockBanner, NULL, 0, NULL); hThread = CreateThread(NULL, 0, BlockBanner, NULL, 0, NULL);
if (hThread != nullptr) { if (hThread != nullptr) {
CloseHandle(hThread); CloseHandle(hThread);
} }
} }
if (enable_developer) { if (SettingsManager::m_config.at(L"Enable_Developer")) {
hThread = CreateThread(NULL, 0, EnableDeveloper, NULL, 0, NULL); hThread = CreateThread(NULL, 0, EnableDeveloper, NULL, 0, NULL);
if (hThread != nullptr) { if (hThread != nullptr) {
CloseHandle(hThread); CloseHandle(hThread);

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#define NOMINMAX
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <Windows.h> #include <Windows.h>
@ -12,6 +13,7 @@
#include "BasicUtils/MemoryScanner.h" #include "BasicUtils/MemoryScanner.h"
#include "BasicUtils/Memory.h" #include "BasicUtils/Memory.h"
#include "BasicUtils/Hooking.h" #include "BasicUtils/Hooking.h"
#include "BasicUtils/Json.h"
#ifndef NDEBUG #ifndef NDEBUG
#ifdef _WIN64 #ifdef _WIN64

View file

@ -9,6 +9,7 @@
// add headers that you want to pre-compile here // add headers that you want to pre-compile here
#include "framework.h" #include "framework.h"
#include "SettingsManager.h"
#include "Modify.h" #include "Modify.h"
#include "Debug.h" #include "Debug.h"