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>
<h5 align="center">Please support Spotify by purchasing premium</h5>
<p align="center">
<strong>Last updated:</strong> 14 February 2024<br>
<strong>Last tested version:</strong> Spotify for Windows (64 bit) 1.2.31.1205.g4d59ad7c
<strong>Last updated:</strong> 18 March 2024<br>
<strong>Last tested version:</strong> Spotify for Windows (64 bit) 1.2.33.1039.g8ddb5918
</p>
</center>
@ -61,6 +61,17 @@ rm -fo $env:APPDATA\spotify\dpapi.dll
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:
* 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_Banner=1
Enable_Developer=1
Enable_Auto_Update=1
;Log system
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"
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
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>
namespace Logger {
std::mutex mtx;
std::wofstream file;
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;
if (log_enabled) {
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) {
case LogLevel::Info:
return L"INFO";
@ -32,14 +34,16 @@ namespace Logger {
}
}
void Log(std::wstring_view message, LogLevel level) {
#ifndef NDEBUG
void Log(std::wstring_view message, LogLevel level)
{
if (level == LogLevel::Error) {
has_error = true;
PrintError(L"{}", message);
}
#endif
if (!log_enabled) return;
static std::mutex mtx;
std::lock_guard<std::mutex> lock(mtx);
if (file.is_open()) {
@ -50,4 +54,9 @@ namespace Logger {
file.flush();
}
}
bool HasError()
{
return has_error;
}
}

View file

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

View file

@ -24,13 +24,23 @@ namespace Memory {
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());
}
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());
}
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 <initializer_list>
#include <vector>
namespace Memory {
bool Read(void* address, void* buffer, 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, std::initializer_list<uint8_t>& data);
bool Write(void* address, const std::string_view& 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 "Hooking.h"
#include "Utils.h"
#include "Memory.h"
#include <sstream>
#include <Psapi.h>
#include <algorithm>
#include <Memory.h>
#include <unordered_map>
namespace MemoryScanner
{
ModuleInfo GetModuleInfo(std::wstring_view module_name)
{
static std::unordered_map<std::wstring_view, ModuleInfo> loaded_modules;
const auto module = loaded_modules.find(module_name);
if (module != loaded_modules.end()) {
return module->second;
}
HMODULE module_handle = GetModuleHandleW(module_name.empty() ? nullptr : module_name.data());
if (module_handle == nullptr) {
return ModuleInfo(module_name, 0, 0);
}
MODULEINFO module_info;
if (!GetModuleInformation(GetCurrentProcess(), module_handle, &module_info, sizeof(MODULEINFO))) {
return ModuleInfo(module_name, 0, 0);
}
const auto ret = ModuleInfo(module_name, reinterpret_cast<uintptr_t>(module_info.lpBaseOfDll), module_info.SizeOfImage);
loaded_modules.emplace(module_name, ret);
return ret;
}
ScanResult GetFunctionAddress(std::string_view module_name, std::string_view function_name)
{
HMODULE module_handle = GetModuleHandleA(module_name.data());
if (module_handle == nullptr) {
module_handle = LoadLibraryA(module_name.data());
if (module_handle == nullptr) {
return ScanResult(0, 0, 0);
}
}
FARPROC function_address = GetProcAddress(module_handle, function_name.data());
if (function_address == nullptr) {
return ScanResult(0, 0, 0);
}
MODULEINFO module_info;
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), reinterpret_cast<uintptr_t>(module_info.lpBaseOfDll), module_info.SizeOfImage);
}
std::vector<uint8_t> SignatureToByteArray(std::wstring_view signature)
{
std::vector<uint8_t> signature_bytes;
std::wstring word;
std::wistringstream iss(signature.data());
while (iss >> word) {
if (word.size() == 1 && word[0] == L'?') {
signature_bytes.push_back(0);
}
else if (word.size() == 2 && word[0] == L'?' && word[1] == L'?') {
signature_bytes.push_back(0);
}
else if (word.size() == 2 && std::isxdigit(word[0]) && std::isxdigit(word[1])) {
unsigned long value = std::stoul(word, nullptr, 16);
if (value > 255) {
return { 0 };
}
signature_bytes.push_back(static_cast<uint8_t>(value));
}
else {
for (wchar_t c : word) {
if (c > 255) {
return { 0 };
}
signature_bytes.push_back(static_cast<uint8_t>(c));
}
}
}
return signature_bytes;
}
std::vector<ScanResult> ScanAll(uintptr_t base_address, size_t image_size, const std::vector<uint8_t>& pattern_byte, bool only_first)
{
std::vector<ScanResult> matches;
size_t pattern_size = pattern_byte.size();
if (pattern_byte.empty()) {
return matches;
}
uint8_t* base_ptr = reinterpret_cast<uint8_t*>(base_address);
uintptr_t end_address = base_address + image_size - pattern_size + 1;
while (base_ptr < reinterpret_cast<uint8_t*>(end_address)) {
base_ptr = static_cast<uint8_t*>(memchr(base_ptr, pattern_byte[0], end_address - reinterpret_cast<uintptr_t>(base_ptr)));
if (!base_ptr) {
break;
}
bool found = true;
for (size_t i = 1; i < pattern_size; ++i) {
if (pattern_byte[i] != 0 && pattern_byte[i] != base_ptr[i]) {
found = false;
break;
}
}
if (found) {
matches.push_back(ScanResult(reinterpret_cast<uintptr_t>(base_ptr), base_address, image_size));
if (only_first) break;
}
++base_ptr;
}
return matches;
}
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)
{
const auto mod = GetModuleInfo(module_name);
return ScanAll(mod.base_address, mod.module_size, signature);
}
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);
return matches.empty() ? ScanResult(0, 0, 0) : matches.at(0);
}
ScanResult ScanFirst(uintptr_t base_address, size_t image_size, std::wstring_view signature)
{
return ScanFirst(base_address, image_size, SignatureToByteArray(signature));
}
ScanResult ScanFirst(std::wstring_view signature, std::wstring_view module_name)
{
const auto mod = GetModuleInfo(module_name);
return ScanFirst(mod.base_address, mod.module_size, signature);
}
ScanResult::ScanResult(uintptr_t address, uintptr_t base, size_t size) : m_address(address), m_base_address(base), m_image_size(size)
{
//...
}
ScanResult::operator uintptr_t() const
{
return m_address;
}
bool ScanResult::is_valid(const std::vector<uint8_t>& value) const
{
if (m_address == 0) {
return false;
}
for (size_t i = 0; i < value.size(); ++i) {
if (*(reinterpret_cast<uint8_t*>(m_address) + i) != value[i])
return false;
}
return true;
}
uint8_t* ScanResult::data() const
{
if (!is_valid()) {
return nullptr;
}
return reinterpret_cast<uint8_t*>(m_address);
}
ScanResult ScanResult::rva() const
{
if (!is_valid()) {
return ScanResult(0, m_base_address, m_image_size);
}
uintptr_t rva_address = m_address - m_base_address;
return ScanResult(rva_address, m_base_address, m_image_size);
}
ScanResult ScanResult::offset(std::ptrdiff_t offset_value) const
{
if (!is_valid()) {
return ScanResult(0, m_base_address, m_image_size);
}
uintptr_t new_address = m_address;
if (offset_value >= 0) {
new_address += static_cast<uintptr_t>(offset_value);
}
else {
new_address -= static_cast<uintptr_t>(-offset_value);
}
return ScanResult(new_address, m_base_address, m_image_size);
}
ScanResult ScanResult::scan_first(std::wstring_view value) const
{
return is_valid() ? ScanFirst(m_address, m_image_size - rva(), value) : ScanResult(0, m_base_address, m_image_size);
}
bool ScanResult::write(const void* data, size_t size) const
{
return Memory::Write(reinterpret_cast<void*>(m_address), data, size);
}
bool ScanResult::write(std::string_view data) const
{
return Memory::Write(reinterpret_cast<void*>(m_address), data);
}
bool ScanResult::write(std::initializer_list<uint8_t> data) const
{
return Memory::Write(reinterpret_cast<void*>(m_address), data);
}
PVOID* ScanResult::hook(PVOID hook_function) const
{
return (is_valid() && Hooking::HookFunction(&(PVOID&)m_address, hook_function)) ? reinterpret_cast<PVOID*>(m_address) : NULL;
}
bool ScanResult::unhook() const
{
return is_valid() ? Hooking::UnhookFunction(&(PVOID&)m_address) : false;
}
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;
if (image_size == 0) image_size = 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),
reinterpret_cast<const uint8_t*>(&m_address) + sizeof(m_address));
return ScanAll(base_address, image_size, new_pattern_byte, only_first);
}
std::vector<ScanResult> matches;
const auto all_matches = ScanAll(base_address, image_size, pattern_byte);
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);
if (*reinterpret_cast<const int32_t*>(offset_address) == relative_offset) {
matches.push_back(ScanResult(address, base_address, image_size));
if (only_first) break;
}
}
return matches;
}
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
{
const auto matches = get_all_matching_codes(pattern_byte, calculate_relative_offset, base_address, image_size, true);
return matches.empty() ? ScanResult(0, m_base_address, m_image_size) : matches.at(0);
}
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);
}
#include "MemoryScanner.h"
#include "Hooking.h"
#include "Utils.h"
#include "Memory.h"
#include <sstream>
#include <Psapi.h>
#include <algorithm>
#include <unordered_map>
#include <execution>
namespace MemoryScanner
{
ModuleInfo GetModuleInfo(std::wstring_view module_name)
{
static std::unordered_map<std::wstring_view, ModuleInfo> loaded_modules;
const auto module = loaded_modules.find(module_name);
if (module != loaded_modules.end()) {
return module->second;
}
HMODULE module_handle = GetModuleHandleW(module_name.empty() ? nullptr : module_name.data());
if (module_handle == nullptr) {
return ModuleInfo(module_name, 0, 0);
}
MODULEINFO module_info;
if (!GetModuleInformation(GetCurrentProcess(), module_handle, &module_info, sizeof(MODULEINFO))) {
return ModuleInfo(module_name, 0, 0);
}
const auto ret = ModuleInfo(module_name, reinterpret_cast<uintptr_t>(module_info.lpBaseOfDll), module_info.SizeOfImage);
loaded_modules.emplace(module_name, ret);
return ret;
}
ScanResult GetFunctionAddress(std::string_view module_name, std::string_view function_name)
{
HMODULE module_handle = GetModuleHandleA(module_name.data());
if (module_handle == nullptr) {
module_handle = LoadLibraryA(module_name.data());
if (module_handle == nullptr) {
return ScanResult(0, 0, 0);
}
}
FARPROC function_address = GetProcAddress(module_handle, function_name.data());
if (function_address == nullptr) {
return ScanResult(0, 0, 0);
}
MODULEINFO module_info;
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), reinterpret_cast<uintptr_t>(module_info.lpBaseOfDll), module_info.SizeOfImage);
}
std::vector<BytePattern> ParseBytePattern(std::wstring_view byte_pattern)
{
std::vector<BytePattern> parsed_pattern;
bool is_hex = byte_pattern.find_first_not_of(L"0123456789ABCDEFabcdef? ") == std::wstring::npos;
if (is_hex) {
std::wistringstream iss(byte_pattern.data());
std::wstring byte;
while (iss >> byte) {
BytePattern bp;
if (byte.size() == 1 && byte[0] == L'?') {
bp.half_byte[0].wildcard = true;
bp.half_byte[1].wildcard = true;
}
else {
if (byte[0] == L'?') {
bp.half_byte[0].wildcard = true;
}
else {
bp.half_byte[0].data = std::stoi(std::wstring(1, byte[0]), nullptr, 16);
}
if (byte[1] == L'?') {
bp.half_byte[1].wildcard = true;
}
else {
bp.half_byte[1].data = std::stoi(std::wstring(1, byte[1]), nullptr, 16);
}
}
parsed_pattern.push_back(bp);
}
}
else {
for (wchar_t ch : byte_pattern) {
BytePattern bp;
bp.half_byte[0].data = ch >> 4;
bp.half_byte[1].data = ch & 0xF;
parsed_pattern.push_back(bp);
}
}
return parsed_pattern;
}
std::vector<ScanResult> ScanAll(uintptr_t base_address, size_t image_size, const std::vector<BytePattern>& parsed_pattern, bool only_first)
{
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) {
result.push_back(ScanResult(reinterpret_cast<uintptr_t>(it), base_address, image_size));
if (only_first) {
break;
}
}
}
}
return result;
}
std::vector<ScanResult> ScanAll(uintptr_t base_address, size_t image_size, std::wstring_view pattern)
{
return ScanAll(base_address, image_size, ParseBytePattern(pattern));
}
std::vector<ScanResult> ScanAll(std::wstring_view pattern, std::wstring_view module_name)
{
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, const std::vector<BytePattern>& parsed_pattern)
{
const auto addresses = ScanAll(base_address, image_size, parsed_pattern, true);
return addresses.empty() ? ScanResult(0, 0, 0) : addresses.front();
}
ScanResult ScanFirst(uintptr_t base_address, size_t image_size, std::wstring_view pattern)
{
return ScanFirst(base_address, image_size, ParseBytePattern(pattern));
}
ScanResult ScanFirst(std::wstring_view pattern, std::wstring_view module_name)
{
const auto module_info = GetModuleInfo(module_name);
return ScanFirst(module_info.base_address, module_info.module_size, pattern);
}
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)
{
if (is_rva && address) {
m_address += m_base_address;
}
}
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)
{
if (is_rva && address) {
m_address += m_base_address;
}
}
ScanResult::operator uintptr_t() const
{
return m_address;
}
bool ScanResult::is_valid(const std::vector<BytePattern>& parsed_pattern) const
{
if (m_address == 0) {
return false;
}
for (size_t i = 0; i < parsed_pattern.size(); ++i) {
BytePattern pattern = parsed_pattern[i];
if (pattern.half_byte[0].wildcard && pattern.half_byte[1].wildcard) {
continue;
}
uint8_t byte = *(reinterpret_cast<uint8_t*>(m_address) + i);
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);
if (!(match_high_nibble && match_low_nibble)) {
return false;
}
}
return true;
}
bool ScanResult::is_valid(std::wstring_view pattern) const
{
return is_valid(ParseBytePattern(pattern));
}
uint8_t* ScanResult::data() const
{
if (!is_valid()) {
return nullptr;
}
return reinterpret_cast<uint8_t*>(m_address);
}
ScanResult ScanResult::rva() const
{
if (!is_valid()) {
return ScanResult(0, m_base_address, m_image_size);
}
return ScanResult(m_address - m_base_address, m_base_address, m_image_size);
}
ScanResult ScanResult::offset(std::ptrdiff_t offset_value) const
{
if (!is_valid()) {
return ScanResult(0, m_base_address, m_image_size);
}
uintptr_t new_address = m_address;
if (offset_value >= 0) {
new_address += static_cast<uintptr_t>(offset_value);
}
else {
new_address -= static_cast<uintptr_t>(-offset_value);
}
return ScanResult(new_address, m_base_address, m_image_size);
}
ScanResult ScanResult::scan_first(std::wstring_view value) const
{
return is_valid() ? ScanFirst(m_address, m_image_size - rva(), value) : ScanResult(0, m_base_address, m_image_size);
}
bool ScanResult::write(const std::string_view& data) const
{
return is_valid() ? Memory::Write(reinterpret_cast<void*>(m_address), data) : false;
}
bool ScanResult::write(const std::wstring_view& data) const
{
return is_valid() ? Memory::Write(reinterpret_cast<void*>(m_address), data) : false;
}
bool ScanResult::write(const std::initializer_list<uint8_t>& data) const
{
return is_valid() ? Memory::Write(reinterpret_cast<void*>(m_address), data) : false;
}
bool ScanResult::write(const std::vector<uint8_t>& data) const
{
return is_valid() ? Memory::Write(reinterpret_cast<void*>(m_address), data) : false;
}
PVOID* ScanResult::hook(PVOID hook_function) const
{
return (is_valid() && Hooking::HookFunction(&(PVOID&)m_address, hook_function)) ? reinterpret_cast<PVOID*>(m_address) : NULL;
}
bool ScanResult::unhook() const
{
return is_valid() ? Hooking::UnhookFunction(&(PVOID&)m_address) : false;
}
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
{
if (base_address == 0) base_address = m_base_address;
if (image_size == 0) image_size = m_image_size;
if (!calculate_relative_address) {
std::vector<BytePattern> new_parsed_pattern = parsed_pattern;
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&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
#define MEMORY_SCANNER_H
#include <Windows.h>
#include <string>
#include <vector>
namespace MemoryScanner
{
struct ModuleInfo {
std::wstring_view module_name;
uintptr_t base_address;
size_t module_size;
};
class ScanResult {
public:
ScanResult() : m_address(0), m_base_address(0), m_image_size(0) {}
ScanResult(uintptr_t address, uintptr_t base, size_t size);
operator uintptr_t() const;
bool is_valid(const std::vector<uint8_t>& value = {}) const;
uint8_t* data() const;
ScanResult rva() const;
ScanResult offset(std::ptrdiff_t offset_value) const;
ScanResult scan_first(std::wstring_view value) const;
bool write(const void* data, size_t size) const;
bool write(std::string_view data) const;
bool write(std::initializer_list<uint8_t> data) const;
PVOID* hook(PVOID hook_function) const;
bool unhook() 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 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;
uintptr_t get_base_address() const;
size_t get_image_size() const;
void print_address() const;
private:
uintptr_t m_address;
uintptr_t m_base_address;
size_t m_image_size;
};
ModuleInfo GetModuleInfo(std::wstring_view module_name = {});
ScanResult GetFunctionAddress(std::string_view module_name, std::string_view function_name);
std::vector<ScanResult> ScanAll(uintptr_t base_address, size_t image_size, const std::vector<uint8_t>& pattern_byte, bool only_first = false);
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 = {});
ScanResult ScanFirst(uintptr_t base_address, size_t image_size, const std::vector<uint8_t>& pattern_byte);
ScanResult ScanFirst(uintptr_t base_address, size_t image_size, std::wstring_view signature);
ScanResult ScanFirst(std::wstring_view signature, std::wstring_view module_name = {});
}
#endif // MEMORY_SCANNER_H
#ifndef MEMORY_SCANNER_H
#define MEMORY_SCANNER_H
#include <Windows.h>
#include <string>
#include <vector>
namespace MemoryScanner
{
struct ModuleInfo {
std::wstring_view module_name;
uintptr_t base_address;
size_t module_size;
};
struct BytePattern {
struct HalfByte {
uint8_t data{};
bool wildcard{};
} half_byte[2]{};
};
class ScanResult {
public:
ScanResult() : m_address(0), m_base_address(0), m_image_size(0) {}
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);
operator uintptr_t() const;
bool is_valid(const std::vector<BytePattern>& parsed_pattern = {}) const;
bool is_valid(std::wstring_view pattern) const;
uint8_t* data() const;
ScanResult rva() const;
ScanResult offset(std::ptrdiff_t offset_value) const;
ScanResult scan_first(std::wstring_view value) const;
bool write(const std::string_view& data) const;
bool write(const std::wstring_view& data) const;
bool write(const std::initializer_list<uint8_t>& data) const;
bool write(const std::vector<uint8_t>& data) const;
PVOID* hook(PVOID hook_function) const;
bool unhook() const;
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;
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;
ScanResult get_first_reference(std::wstring_view pattern, bool calculate_relative_address = true, uintptr_t base_address = 0, size_t image_size = 0) const;
uintptr_t get_base_address() const;
size_t get_image_size() const;
void print_address() const;
private:
uintptr_t m_address;
uintptr_t m_base_address;
size_t m_image_size;
};
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 <algorithm>
#include <chrono>
namespace Utils
{
std::string ToHexString(const std::vector<uint8_t>& byte_array, const bool insert_spaces)
{
std::ostringstream oss;
oss << std::hex << std::setfill('0');
for (size_t i = 0; i < byte_array.size(); ++i) {
if (i > 0 && insert_spaces) {
oss << ' ';
}
oss << std::setw(2) << static_cast<int>(byte_array[i]);
}
std::string hex_string = oss.str();
std::transform(hex_string.begin(), hex_string.end(), hex_string.begin(), ::toupper);
return hex_string;
}
std::string ToHexString(const uint8_t* data, size_t size, const bool insert_spaces)
{
if (data == nullptr) {
PrintError(L"ToHexString: The data pointer is null.");
return std::string();
}
if (size == 0)
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;
oss << std::hex << std::setfill(L'0');
for (size_t i = 0; i < byte_array.size(); ++i) {
if (i > 0 && insert_spaces) {
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);
return hex_string;
}
std::wstring ToHexWideString(const uint8_t* data, size_t size, const bool insert_spaces)
{
if (data == nullptr) {
PrintError(L"ToHexWideString: The data pointer is null.");
return std::wstring();
}
if (size == 0)
size = std::wcslen(reinterpret_cast<const wchar_t*>(data));
return ToHexWideString(std::vector<uint8_t>(data, data + size), insert_spaces);
}
std::string ConvertUInt8ArrayToString(uint8_t* data)
{
return std::string(reinterpret_cast<char*>(data), reinterpret_cast<char*>(data + std::strlen(reinterpret_cast<char*>(data))));
}
std::wstring ConvertUInt8ArrayToWideString(uint8_t* data)
{
return std::wstring(reinterpret_cast<wchar_t*>(data), reinterpret_cast<wchar_t*>(data + std::wcslen(reinterpret_cast<wchar_t*>(data))));
}
std::string IntegerToHexString(uintptr_t integer_value)
{
return std::format("{:x}", integer_value);
}
std::wstring IntegerToHexWideString(uintptr_t integer_value)
{
return std::format(L"{:x}", integer_value);
}
std::string ToString(std::wstring_view wide_string)
{
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);
return str_to;
}
std::wstring ToString(std::string_view narrow_string)
{
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &narrow_string[0], (int)narrow_string.size(), NULL, 0);
std::wstring wstr_to(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, &narrow_string[0], (int)narrow_string.size(), &wstr_to[0], size_needed);
return wstr_to;
}
std::wstring ToString(std::u16string_view utf16_string)
{
return std::wstring(utf16_string.begin(), utf16_string.end());
}
bool Contains(std::string_view str1, std::string_view str2, bool case_sensitive)
{
auto it = std::search(
str1.begin(), str1.end(),
str2.begin(), str2.end(),
[case_sensitive](char ch1, char ch2) {
return case_sensitive ? ch1 == ch2 : std::toupper(ch1) == std::toupper(ch2);
}
);
return (it != str1.end());
}
bool Contains(std::wstring_view str1, std::wstring_view str2, bool case_sensitive)
{
auto it = std::search(
str1.begin(), str1.end(),
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());
}
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](char ch1, char ch2) {
return case_sensitive ? ch1 == ch2 : std::toupper(ch1) == std::toupper(ch2);
});
}
bool Equals(std::wstring_view str1, std::wstring_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 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)
{
WritePrivateProfileStringW(section.data(), key.data(), value.data(), ini_path.data());
}
std::wstring ReadIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key)
{
wchar_t value[255];
GetPrivateProfileStringW(section.data(), key.data(), L"", value, 255, ini_path.data());
return std::wstring(value);
}
#ifndef NDEBUG
void MeasureExecutionTime(std::function<void()> func)
{
const auto start_time = std::chrono::high_resolution_clock::now();
func();
const auto end_time = std::chrono::high_resolution_clock::now();
const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
SetConsoleTitleW(FormatString(L"Execution time: {:d}ms", duration).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
#include "Utils.h"
#include <algorithm>
#include <chrono>
#include <cctype>
#include <cwctype>
#include <fstream>
#include <winhttp.h>
#pragma comment(lib, "winhttp.lib")
namespace Utils
{
std::string ToHexString(const std::vector<uint8_t>& byte_array, const bool insert_spaces)
{
std::ostringstream oss;
oss << std::hex << std::setfill('0');
for (size_t i = 0; i < byte_array.size(); ++i) {
if (i > 0 && insert_spaces) {
oss << ' ';
}
oss << std::setw(2) << static_cast<int>(byte_array[i]);
}
std::string hex_string = oss.str();
std::transform(hex_string.begin(), hex_string.end(), hex_string.begin(), ::toupper);
return hex_string;
}
std::string ToHexString(const uint8_t* data, size_t size, const bool insert_spaces)
{
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;
oss << std::hex << std::setfill(L'0');
for (size_t i = 0; i < byte_array.size(); ++i) {
if (i > 0 && insert_spaces) {
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);
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::vector<uint8_t> ToHexBytes(const std::string& hex_string)
{
std::vector<uint8_t> byte_array;
std::istringstream iss(hex_string);
std::string hex_byte;
while (iss >> std::setw(2) >> hex_byte) {
uint8_t byte_value = static_cast<uint8_t>(std::stoi(hex_byte, nullptr, 16));
byte_array.push_back(byte_value);
}
return byte_array;
}
std::vector<uint8_t> ToHexBytes(const std::wstring& hex_wstring)
{
std::vector<uint8_t> byte_array;
std::wistringstream iss(hex_wstring);
std::wstring hex_byte;
while (iss >> std::setw(2) >> hex_byte) {
uint8_t byte_value = static_cast<uint8_t>(std::stoi(hex_byte, nullptr, 16));
byte_array.push_back(byte_value);
}
return byte_array;
}
std::string IntegerToHexString(uintptr_t integer_value)
{
return std::format("{:x}", integer_value);
}
std::wstring IntegerToHexWideString(uintptr_t integer_value)
{
return std::format(L"{:x}", integer_value);
}
std::string ToString(std::wstring_view wide_string)
{
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);
return str_to;
}
std::wstring ToString(std::string_view narrow_string)
{
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &narrow_string[0], (int)narrow_string.size(), NULL, 0);
std::wstring wstr_to(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, &narrow_string[0], (int)narrow_string.size(), &wstr_to[0], size_needed);
return wstr_to;
}
std::wstring ToString(std::u16string_view utf16_string)
{
return std::wstring(utf16_string.begin(), utf16_string.end());
}
bool Contains(std::string_view str1, std::string_view str2, bool case_sensitive)
{
auto it = std::search(
str1.begin(), str1.end(),
str2.begin(), str2.end(),
[case_sensitive](char ch1, char ch2) {
return case_sensitive ? ch1 == ch2 : std::toupper(ch1) == std::toupper(ch2);
}
);
return (it != str1.end());
}
bool Contains(std::wstring_view str1, std::wstring_view str2, bool case_sensitive)
{
auto it = std::search(
str1.begin(), str1.end(),
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());
}
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](char ch1, char ch2) {
return case_sensitive ? ch1 == ch2 : std::toupper(ch1) == std::toupper(ch2);
});
}
bool Equals(std::wstring_view str1, std::wstring_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 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)
{
WritePrivateProfileStringW(section.data(), key.data(), value.data(), ini_path.data());
}
std::wstring ReadIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key)
{
wchar_t value[255];
GetPrivateProfileStringW(section.data(), key.data(), L"", value, 255, ini_path.data());
return std::wstring(value);
}
bool ReadFile(const std::wstring_view filename, std::wstring& out)
{
std::wifstream file(filename.data(), std::ios::binary | std::ios::ate);
if (!file.is_open()) return false;
out.resize(static_cast<std::wstring::size_type>(file.tellg()));
file.seekg(0, std::ios::beg);
file.read(&out[0], out.size());
return !file.fail();
}
bool WriteFile(const std::wstring_view filename, const std::wstring_view content)
{
std::wofstream file(filename.data(), std::ios::binary);
if (!file.is_open()) return false;
file.write(content.data(), content.size());
return !file.fail();
}
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
#define _UTILS_H
#include <Windows.h>
#include <iostream>
#include <string>
#include <format>
#include <functional>
namespace Utils
{
std::string ToHexString(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 std::vector<uint8_t>& byte_array, const bool insert_spaces);
std::wstring ToHexWideString(const uint8_t* data, size_t size, const bool insert_spaces);
std::string ConvertUInt8ArrayToString(uint8_t* data);
std::wstring ConvertUInt8ArrayToWideString(uint8_t* data);
std::string IntegerToHexString(uintptr_t integer_value);
std::wstring IntegerToHexWideString(uintptr_t integer_value);
std::string ToString(std::wstring_view wide_string);
std::wstring ToString(std::string_view narrow_string);
std::wstring ToString(std::u16string_view utf16_string);
bool Contains(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::string_view str1, std::string_view str2, bool case_sensitive);
bool Equals(std::wstring_view str1, std::wstring_view str2, bool case_sensitive);
void WriteIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key, std::wstring_view value);
std::wstring ReadIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key);
#ifndef NDEBUG
//Example: MeasureExecutionTime([&]() { Function(arg1, arg2); });
void MeasureExecutionTime(std::function<void()> func);
void PrintSymbols(std::wstring_view module_name);
#endif
template<typename T>
constexpr auto TypeConvert(const T& arg)
{
if constexpr (std::is_same_v<T, const wchar_t*>) {
return std::wstring_view(arg);
}
else if constexpr (std::is_same_v<T, const char*>) {
return ToString(arg);
}
else if constexpr (std::is_same_v < T, void*>) {
return reinterpret_cast<uintptr_t>(arg);
}
else if constexpr (std::is_pointer_v<T>) {
return *arg;
}
else {
return arg;
}
}
std::string FormatString(std::string_view fmt, const auto&... args)
{
return std::vformat(fmt, std::make_format_args(args...));
}
std::wstring FormatString(std::wstring_view fmt, const auto&... args)
{
return std::vformat(fmt, std::make_wformat_args(TypeConvert(args)...));
}
enum class Color : WORD
{
Red = FOREGROUND_RED,
Green = FOREGROUND_GREEN,
Blue = FOREGROUND_BLUE,
Yellow = FOREGROUND_RED | FOREGROUND_GREEN,
Cyan = FOREGROUND_GREEN | FOREGROUND_BLUE,
Magenta = FOREGROUND_RED | FOREGROUND_BLUE,
White = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
Black = 0,
Gray = FOREGROUND_INTENSITY,
DarkRed = FOREGROUND_RED | FOREGROUND_INTENSITY,
DarkGreen = FOREGROUND_GREEN | FOREGROUND_INTENSITY,
DarkBlue = FOREGROUND_BLUE | FOREGROUND_INTENSITY,
DarkYellow = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
DarkCyan = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
DarkMagenta = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY
};
#if defined(_DEBUG) || defined(_CONSOLE)
void _Print(std::string_view fmt, const auto&... args)
{
std::cout << FormatString(fmt, args...) << std::endl;
}
void _Print(std::wstring_view fmt, const auto&... args)
{
std::wcout << FormatString(fmt, args...) << std::endl;
}
void _Print(const std::vector<Color>& colors, std::wstring fmt, const auto&... args)
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsole == INVALID_HANDLE_VALUE) {
throw std::runtime_error("Failed to get console handle");
}
size_t start = 0;
size_t pos = fmt.find(L"{");
size_t color_index = 0;
auto print_arg = [&](const auto& arg) {
if (pos != std::wstring::npos) {
std::wcout << fmt.substr(start, pos - start);
if (color_index < colors.size()) {
if (!SetConsoleTextAttribute(hConsole, static_cast<WORD>(colors[color_index]))) {
throw std::runtime_error("Failed to set console text attribute");
}
++color_index;
}
size_t end = fmt.find(L"}", pos);
if (end != std::wstring::npos) {
std::wstring formatSpecifier = fmt.substr(pos, end - pos + 1);
std::wcout << Utils::FormatString(formatSpecifier, arg);
pos = fmt.find(L"{", end + 1);
}
else {
throw std::runtime_error("Invalid format string");
}
if (!SetConsoleTextAttribute(hConsole, static_cast<WORD>(Color::White))) {
throw std::runtime_error("Failed to set console text attribute");
}
start = end + 1;
}
else {
std::wcout << fmt.substr(start);
}
};
(print_arg(args), ...);
std::wcout << fmt.substr(start) << std::endl;
}
#endif
};
using Utils::Color;
#if defined(_DEBUG) || defined(_CONSOLE)
#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"{} " fmt, L" -", __VA_ARGS__)
#define PrintStatus(flag, label) Utils::_Print({ (flag) ? Color::Green : Color::Red }, L"{} " label, (flag) ? L" +" : L" -")
#else
#define Print(fmt, ...)
#define PrintColor(colors, fmt, ...)
#define PrintError(fmt, ...)
#define PrintStatus(flag, label)
#endif
#ifndef _UTILS_H
#define _UTILS_H
#include <Windows.h>
#include <iostream>
#include <string>
#include <vector>
#include <format>
#include <functional>
#include <mutex>
namespace Utils
{
std::string ToHexString(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 std::vector<uint8_t>& byte_array, const bool insert_spaces);
std::wstring ToHexWideString(const uint8_t* data, size_t size, const bool insert_spaces);
std::vector<uint8_t> ToHexBytes(const std::string& hex_string);
std::vector<uint8_t> ToHexBytes(const std::wstring& hex_wstring);
std::string IntegerToHexString(uintptr_t integer_value);
std::wstring IntegerToHexWideString(uintptr_t integer_value);
std::string ToString(std::wstring_view wide_string);
std::wstring ToString(std::string_view narrow_string);
std::wstring ToString(std::u16string_view utf16_string);
bool Contains(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::string_view str1, std::string_view str2, bool case_sensitive);
bool Equals(std::wstring_view str1, std::wstring_view str2, bool case_sensitive);
void WriteIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key, std::wstring_view value);
std::wstring ReadIniFile(std::wstring_view ini_path, std::wstring_view section, std::wstring_view key);
bool ReadFile(const std::wstring_view filename, std::wstring& out);
bool WriteFile(const std::wstring_view filename, const std::wstring_view content);
std::wstring HttpGetRequest(std::wstring_view url);
#ifndef NDEBUG
void MeasureExecutionTime(std::function<void()> func, bool total_duration = true);
void PrintSymbols(std::wstring_view module_name);
#endif
template<typename T>
constexpr auto TypeConvert(const T& arg)
{
if constexpr (std::is_same_v<T, const wchar_t*>) {
return std::wstring_view(arg);
}
else if constexpr (std::is_same_v<T, const char*>) {
return ToString(arg);
}
else if constexpr (std::is_same_v < T, void*>) {
return reinterpret_cast<uintptr_t>(arg);
}
else if constexpr (std::is_pointer_v<T>) {
return *arg;
}
else {
return arg;
}
}
std::string FormatString(std::string_view fmt, const auto&... args)
{
return std::vformat(fmt, std::make_format_args(args...));
}
std::wstring FormatString(std::wstring_view fmt, const auto&... args)
{
return std::vformat(fmt, std::make_wformat_args(TypeConvert(args)...));
}
enum class Color : WORD
{
Red = FOREGROUND_RED,
Green = FOREGROUND_GREEN,
Blue = FOREGROUND_BLUE,
Yellow = FOREGROUND_RED | FOREGROUND_GREEN,
Cyan = FOREGROUND_GREEN | FOREGROUND_BLUE,
Magenta = FOREGROUND_RED | FOREGROUND_BLUE,
White = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
Black = 0,
Gray = FOREGROUND_INTENSITY,
DarkRed = FOREGROUND_RED | FOREGROUND_INTENSITY,
DarkGreen = FOREGROUND_GREEN | FOREGROUND_INTENSITY,
DarkBlue = FOREGROUND_BLUE | FOREGROUND_INTENSITY,
DarkYellow = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
DarkCyan = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
DarkMagenta = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY
};
#if defined(_DEBUG) || defined(_CONSOLE)
static std::mutex console_mutex;
void _Print(std::string_view fmt, const auto&... args)
{
std::lock_guard<std::mutex> lock(console_mutex);
std::cout << FormatString(fmt, args...) << std::endl;
}
void _Print(std::wstring_view fmt, const auto&... args)
{
std::lock_guard<std::mutex> lock(console_mutex);
std::wcout << FormatString(fmt, args...) << std::endl;
}
void _Print(const std::vector<Color>& colors, std::wstring_view fmt, const auto&... args)
{
std::lock_guard<std::mutex> lock(console_mutex);
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsole == INVALID_HANDLE_VALUE) {
throw std::runtime_error("Failed to get console handle");
}
size_t start = 0;
size_t pos = fmt.find(L"{");
size_t color_index = 0;
auto print_arg = [&](const auto& arg) {
if (pos != std::wstring_view::npos) {
std::wcout << fmt.substr(start, pos - start);
if (color_index < colors.size()) {
if (!SetConsoleTextAttribute(hConsole, static_cast<WORD>(colors[color_index]))) {
throw std::runtime_error("Failed to set console text attribute");
}
++color_index;
}
size_t end = fmt.find(L"}", pos);
if (end != std::wstring_view::npos) {
std::wstring_view format_specifier = fmt.substr(pos, end - pos + 1);
std::wcout << FormatString(format_specifier, arg);
pos = fmt.find(L"{", end + 1);
}
else {
throw std::runtime_error("Invalid format string");
}
if (!SetConsoleTextAttribute(hConsole, static_cast<WORD>(Color::White))) {
throw std::runtime_error("Failed to set console text attribute");
}
start = end + 1;
}
else {
std::wcout << fmt.substr(start);
}
};
(print_arg(args), ...);
std::wcout << fmt.substr(start) << std::endl;
}
#endif
};
using Utils::Color;
#if defined(_DEBUG) || defined(_CONSOLE)
#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

View file

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

View file

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

View file

@ -1,36 +1,48 @@
#include "pch.h"
#ifndef NDEBUG
DWORD WINAPI Debug(LPVOID lpParam)
{
try {
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_read_file = offsetof(cef_zip_reader_t, read_file);
if (cef_request_t_get_url != cef_request_t_get_url_offset) {
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) {
PrintError(L"The offset of cef_zip_reader_t::get_file_name has changed: {}", cef_zip_reader_get_file_name);
}
if (cef_zip_reader_t_read_file != 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);
}
//Utils::PrintSymbols(L"chrome_elf.dll");
Utils::MeasureExecutionTime([&]() {
});
}
catch (const std::exception& e) {
Print(e.what());
}
return 0;
}
#include "pch.h"
#ifndef NDEBUG
DWORD WINAPI Debug(LPVOID lpParam)
{
try {
const auto cef_request_t_get_url = offsetof(cef_request_t, get_url);
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);
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);
}
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_t_get_file_name);
}
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);
}
// Utils::PrintSymbols(L"chrome_elf.dll");
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);
//}
//MemoryScanner::ScanFirst(L"app-developer").get_first_reference(L"48 8D 15").print_address();
//MemoryScanner::ScanFirst(L"app-developer").get_first_reference(L"4? ?D 1?").print_address();
//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

View file

@ -1,244 +1,153 @@
#include "pch.h"
using _cef_urlrequest_create = void* (*)(void* request, void* client, void* request_context);
static _cef_urlrequest_create cef_urlrequest_create_orig = nullptr;
using _cef_string_userfree_utf16_free = void (*)(void* str);
static _cef_string_userfree_utf16_free cef_string_userfree_utf16_free_orig = nullptr;
using _cef_zip_reader_create = void* (*)(void* stream);
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);
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)
#else
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);
std::wstring url = Utils::ToString(url_utf16->str);
#else
const auto get_url = *(void* (__stdcall**)(void*))((uintptr_t)request + cef_request_t_get_url_offset);
auto url_utf16 = get_url(request);
std::wstring url = *reinterpret_cast<wchar_t**>(url_utf16);
#endif
for (const auto& blockurl : block_list) {
if (std::wstring_view::npos != url.find (blockurl)) {
Log(L"blocked - " + url, LogLevel::Info);
cef_string_userfree_utf16_free_orig((void*)url_utf16);
return nullptr;
}
}
cef_string_userfree_utf16_free_orig((void*)url_utf16);
Log(L"allow - " + url, LogLevel::Info);
return cef_urlrequest_create_orig (request, client, request_context);
}
#ifndef NDEBUG
int cef_zip_reader_t_read_file_hook(struct _cef_zip_reader_t* self, void* buffer, size_t bufferSize)
#else
int cef_zip_reader_t_read_file_hook(void* self, void* buffer, size_t bufferSize)
#endif
{
int _retval = cef_zip_reader_t_read_file_orig(self, buffer, bufferSize);
#ifndef NDEBUG
std::wstring file_name = Utils::ToString(self->get_file_name(self)->str);
#else
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));
#endif
if (file_name == L"home-hpto.css") {
const auto hpto = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L".WiPggcPDzbwGxoxwLWFf{display:-webkit-box;display:-ms-flexbox;display:flex;");
if (hpto.is_valid()) {
if (hpto.write(".WiPggcPDzbwGxoxwLWFf{display:-webkit-box;display:-ms-flexbox;display:none;")) {
Log(L"hptocss patched!", LogLevel::Info);
}
else {
Log(L"hptocss patch failed!", LogLevel::Error);
}
}
else {
Log(L"hptocss - failed not found!", LogLevel::Error);
}
}
if (file_name == L"xpui.js") {
const auto skipads = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L"adsEnabled:!0");
if (skipads.is_valid()) {
if (skipads.offset(12).write("1")) {
Log(L"adsEnabled patched!", LogLevel::Info);
}
else {
Log(L"adsEnabled - patch failed!", LogLevel::Error);
}
}
else {
Log(L"adsEnabled - failed not found!", LogLevel::Error);
}
const auto sponsorship = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L".set(\"allSponsorships\",t.sponsorships)}}(e,t);");
if (sponsorship.is_valid()) {
if (sponsorship.offset(5).write(std::string(15, ' ').append("\"").c_str())) {
Log(L"sponsorship patched!", LogLevel::Info);
}
else {
Log(L"sponsorship patch failed!", LogLevel::Error);
}
}
else {
Log(L"sponsorship - failed not found!", LogLevel::Error);
}
const auto skipsentry = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L"sentry.io");
if (skipsentry.is_valid()) {
if (skipsentry.write("localhost")) {
Log(L"sentry.io -> localhost patched!", LogLevel::Info);
}
else {
Log(L"sentry.io -> localhost - patch failed!", LogLevel::Error);
}
}
else {
Log(L"sentry.io -> localhost - failed not found!", LogLevel::Error);
}
const auto ishptoenable = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L"hptoEnabled:!0");
if (ishptoenable.is_valid())
{
if (ishptoenable.offset(13).write("1")) {
Log(L"hptoEnabled patched!", LogLevel::Info);
}
else {
Log(L"hptoEnabled - patch failed!", LogLevel::Error);
}
}
else {
Log(L"hptoEnabled - failed not found!", LogLevel::Error);
}
const auto ishptohidden = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L"isHptoHidden:!0");
if (ishptohidden.is_valid()) {
if (ishptohidden.offset(14).write("1")) {
Log(L"isHptoHidden patched!", LogLevel::Info);
}
else {
Log(L"isHptoHidden - patch failed!", LogLevel::Error);
}
}
else {
Log(L"isHptoHidden - failed not found!", LogLevel::Error);
}
const auto sp_localhost = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, L"sp://ads/v1/ads/");
if (sp_localhost.is_valid()) {
if (sp_localhost.write("sp://localhost//")) {
Log(L"sp://ads/v1/ads/ patched!", LogLevel::Info);
}
else {
Log(L"sp://ads/v1/ads/ - patch failed!", LogLevel::Error);
}
}
else {
Log(L"sp://ads/v1/ads/ - failed not found!", LogLevel::Error);
}
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;
#include "pch.h"
using _cef_urlrequest_create = void* (*)(void* request, void* client, void* request_context);
static _cef_urlrequest_create cef_urlrequest_create_orig = nullptr;
using _cef_string_userfree_utf16_free = void (*)(void* str);
static _cef_string_userfree_utf16_free cef_string_userfree_utf16_free_orig = nullptr;
using _cef_zip_reader_create = void* (*)(void* stream);
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);
static _cef_zip_reader_t_read_file cef_zip_reader_t_read_file_orig = nullptr;
#ifndef NDEBUG
void* cef_urlrequest_create_hook(struct _cef_request_t* request, void* client, void* request_context)
#else
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);
std::wstring url = Utils::ToString(url_utf16->str);
#else
const auto get_url = *(void* (__stdcall**)(void*))((uintptr_t)request + SettingsManager::m_cef_request_t_get_url_offset);
auto url_utf16 = get_url(request);
std::wstring url = *reinterpret_cast<wchar_t**>(url_utf16);
#endif
for (const auto& block_url : SettingsManager::m_block_list) {
if (std::wstring_view::npos != url.find(block_url)) {
Log(L"blocked - " + url, LogLevel::Info);
cef_string_userfree_utf16_free_orig((void*)url_utf16);
return nullptr;
}
}
cef_string_userfree_utf16_free_orig((void*)url_utf16);
Log(L"allow - " + url, LogLevel::Info);
return cef_urlrequest_create_orig(request, client, request_context);
}
#ifndef NDEBUG
int cef_zip_reader_t_read_file_hook(struct _cef_zip_reader_t* self, void* buffer, size_t bufferSize)
#else
int cef_zip_reader_t_read_file_hook(void* self, void* buffer, size_t bufferSize)
#endif
{
int _retval = cef_zip_reader_t_read_file_orig(self, buffer, bufferSize);
#ifndef NDEBUG
std::wstring file_name = Utils::ToString(self->get_file_name(self)->str);
#else
const auto get_file_name = (*(void* (__stdcall**)(void*))((uintptr_t)self + SettingsManager::m_cef_zip_reader_t_get_file_name_offset));
std::wstring file_name = *reinterpret_cast<wchar_t**>(get_file_name(self));
#endif
if (SettingsManager::m_zip_reader.contains(file_name)) {
for (auto& [name, data] : SettingsManager::m_zip_reader.at(file_name)) {
const auto& sig = data.at(L"Signature").get_string();
auto scan = MemoryScanner::ScanResult(data.at(L"Address").get_integer(), reinterpret_cast<uintptr_t>(buffer), bufferSize, true);
if (!scan.is_valid(sig)) {
scan = MemoryScanner::ScanFirst(reinterpret_cast<uintptr_t>(buffer), bufferSize, sig);
data.at(L"Address") = static_cast<int>(scan.rva());
}
if (scan.is_valid()) {
const auto& value = data.at(L"Value").get_string();
const auto& offset = data.at(L"Offset").get_integer();
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);
}
else {
scan.offset(offset).write(Utils::ToString(value)) ? Log(name + L" - patch success!", LogLevel::Info) : Log(name + L" - patch failed!", LogLevel::Error);
}
}
else {
Log(name + L" - unable to find signature in memory!", 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 + SettingsManager::m_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"Failed to hook cef_zip_reader::read_file function!", LogLevel::Error);
}
else {
Hooking::UnhookFunction(&(PVOID&)cef_zip_reader_create_orig);
}
return zip_reader;
}
DWORD WINAPI EnableDeveloper(LPVOID lpParam)
{
auto& dev_data = SettingsManager::m_developer.at(SettingsManager::m_architecture);
const auto& sig = dev_data.at(L"Signature").get_string();
auto scan = MemoryScanner::ScanResult(dev_data.at(L"Address").get_integer(), L"", true);
if (!scan.is_valid(sig)) {
scan = MemoryScanner::ScanFirst(sig);
dev_data.at(L"Address") = static_cast<int>(scan.rva());
}
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"Developer - failed to patch!", LogLevel::Error);
}
}
else {
Log(L"Developer - unable to find signature in memory!", LogLevel::Error);
}
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
DWORD WINAPI EnableDeveloper(LPVOID lpParam);
DWORD WINAPI BlockAds(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
DWORD WINAPI BlockBanner(LPVOID lpParam);

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"
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)
{
DisableThreadLibraryCalls(hModule);
@ -59,25 +29,23 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReser
CloseHandle(hThread);
}
#endif
SettingsManager::Init();
SyncConfigFile();
Logger::Init(L"blockthespot.log", enable_log);
if (block_ads) {
if (SettingsManager::m_config.at(L"Block_Ads")) {
hThread = CreateThread(NULL, 0, BlockAds, NULL, 0, NULL);
if (hThread != nullptr) {
CloseHandle(hThread);
}
}
if (block_banner) {
if (SettingsManager::m_config.at(L"Block_Banner")) {
hThread = CreateThread(NULL, 0, BlockBanner, NULL, 0, NULL);
if (hThread != nullptr) {
CloseHandle(hThread);
}
}
if (enable_developer) {
if (SettingsManager::m_config.at(L"Enable_Developer")) {
hThread = CreateThread(NULL, 0, EnableDeveloper, NULL, 0, NULL);
if (hThread != nullptr) {
CloseHandle(hThread);

View file

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

View file

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