Skip to content

Commit

Permalink
new hook system & some edits (#481)
Browse files Browse the repository at this point in the history
* new hook system

* ChangeWindowText property added

* ChangeWindowText property has been removed

* The GetMemberFunctionOffset function has been added

* some edits

* some edits

* new hook system & some edits

* Revert "new hook system & some edits"

This reverts commit bdbe5db.

* new hook system & some edits

* Update README.md

* Update README.md

* new hook system & some edits
  • Loading branch information
ejaxh authored Aug 14, 2023
1 parent aba6639 commit 2e3c193
Show file tree
Hide file tree
Showing 17 changed files with 350 additions and 123 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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> 24 July 2023<br>
<strong>Last tested version:</strong>1.2.16.947.gcfbaa410
<strong>Last updated:</strong> 6 August 2023<br>
<strong>Last tested version:</strong> 1.2.17.834.g26ee1129
</p>
</center>

Expand Down
7 changes: 6 additions & 1 deletion src/BasicUtils/Console.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,15 @@ namespace Console {
std::wcout << fmt.substr(start) << std::endl;
}
catch (const std::exception& e) {
throw std::runtime_error("Failed to format string: " + std::string(e.what()));
std::wcerr << L"Failed to format string: " << e.what() << std::endl;
}
#endif
}

void PrintError(std::wstring fmt, const auto&... args) {
Print({ Color::Red }, L"[{}] " + fmt, L"ERROR", args...);
}

// void Print(const std::vector<Color>& colors, std::wstring fmt, const auto&... args)
// {
//#if defined(_DEBUG) || defined(_CONSOLE)
Expand Down
64 changes: 36 additions & 28 deletions src/BasicUtils/Hooking.cpp
Original file line number Diff line number Diff line change
@@ -1,61 +1,67 @@
#include "Hooking.h"
#include <stdexcept>
#include <mutex>
#include <detours.h>

bool Hooking::HookFunction(std::vector<PVOID*> ppPointers, std::vector<PVOID> pDetours) {
if (Begin())
{
for (size_t i = 0; i < ppPointers.size(); i++) {
if (FindHookFunction(ppPointers[i]) != nullptr) {
std::mutex mtx;

bool Hooking::HookFunction(HookData data)
{
std::scoped_lock lock(mtx);
if (Begin()) {
for (auto& [ppPointer, pDetour] : data) {
if (FindHookFunction(ppPointer) != nullptr) {
throw std::runtime_error("DetourAttach failed");
}

if (DetourAttach(ppPointers[i], pDetours[i]) != NO_ERROR) {
if (DetourAttach(ppPointer, pDetour) != NO_ERROR) {
throw std::runtime_error("DetourAttach failed");
}

InsertHookFunction(ppPointers[i], pDetours[i]);
InsertHookFunction(ppPointer, pDetour);
}
return Commit();
}
return false;
}

bool Hooking::HookFunction(PVOID* ppPointers, PVOID pDetours) {
auto _ppPointers = { ppPointers };
auto _pDetours = { pDetours };
return HookFunction(_ppPointers, _pDetours);
bool Hooking::HookFunction(PVOID* ppPointers, PVOID pDetours)
{
HookData data = { {ppPointers, pDetours} };
return HookFunction(data);
}

bool Hooking::UnhookFunction(std::vector<PVOID*> ppPointers, std::vector<PVOID> pDetours) {
if (Begin())
{
for (size_t i = 0; i < ppPointers.size(); i++) {
if (pDetours[i] == nullptr) {
pDetours[i] = FindHookFunction(ppPointers[i]);
if (pDetours[i] == nullptr) {
bool Hooking::UnhookFunction(HookData data)
{
std::scoped_lock lock(mtx);
if (Begin()) {
for (auto& [ppPointer, pDetour] : data) {
if (pDetour == nullptr) {
pDetour = FindHookFunction(ppPointer);
if (pDetour == nullptr) {
throw std::runtime_error("DetourDetach failed");
}
}

if (DetourDetach(ppPointers[i], pDetours[i]) != NO_ERROR) {
if (DetourDetach(ppPointer, pDetour) != NO_ERROR) {
throw std::runtime_error("DetourDetach failed");
}

EraseHookFunction(ppPointers[i]);
EraseHookFunction(ppPointer);
}
return Commit();
}
return false;
}

bool Hooking::UnhookFunction(PVOID* ppPointers, PVOID pDetours) {
auto _ppPointers = { ppPointers };
auto _pDetours = { pDetours };
return UnhookFunction(_ppPointers, _pDetours);
bool Hooking::UnhookFunction(PVOID* ppPointers, PVOID pDetours)
{
HookData data = { {ppPointers, pDetours} };
return UnhookFunction(data);
}

bool Hooking::Begin() {
bool Hooking::Begin()
{
if (DetourIsHelperProcess()) {
throw std::runtime_error("DetourIsHelperProcess failed");
}
Expand All @@ -69,7 +75,8 @@ bool Hooking::Begin() {
return true;
}

bool Hooking::Commit() {
bool Hooking::Commit()
{
if (DetourTransactionCommit() != NO_ERROR) {
throw std::runtime_error("DetourTransactionCommit failed");
}
Expand All @@ -86,12 +93,13 @@ void Hooking::EraseHookFunction(PVOID* ppPointers)
HookFunctionList.erase(ppPointers);
}

PVOID Hooking::FindHookFunction(PVOID* ppPointers) {
PVOID Hooking::FindHookFunction(PVOID* ppPointers)
{
auto iter = HookFunctionList.find(ppPointers);
if (iter != HookFunctionList.end()) {
return iter->second;
}
return nullptr;
}

std::map<PVOID*, PVOID> Hooking::HookFunctionList;
Hooking::HookData Hooking::HookFunctionList;
7 changes: 4 additions & 3 deletions src/BasicUtils/Hooking.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@

class Hooking {
public:
static bool HookFunction(std::vector<PVOID*> ppPointers, std::vector<PVOID> pDetours);
using HookData = std::map<PVOID*, PVOID>;
static bool HookFunction(HookData data);
static bool HookFunction(PVOID* ppPointers, PVOID pDetours);
static bool UnhookFunction(std::vector<PVOID*> ppPointers, std::vector<PVOID> pDetours = {});
static bool UnhookFunction(HookData data);
static bool UnhookFunction(PVOID* ppPointers, PVOID pDetours = nullptr);


Expand All @@ -19,7 +20,7 @@ class Hooking {
static void InsertHookFunction(PVOID* ppPointers, PVOID pDetours);
static void EraseHookFunction(PVOID* ppPointers);
static PVOID FindHookFunction(PVOID* ppPointers);
static std::map<PVOID*, PVOID> HookFunctionList;
static HookData HookFunctionList;
};

#endif //_HOOKING_H
19 changes: 7 additions & 12 deletions src/BasicUtils/Logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,22 @@ namespace Logger

void Init(std::wstring_view log_file, bool log_enable)
{
if (log_enable)
{
if (log_enable) {
file.open(log_file.data(), std::ios::out | std::ios::trunc);

std::locale utf8_locale("en_US.UTF-8");
file.imbue(utf8_locale);
buffer.imbue(utf8_locale);

if (!file.is_open()) {
Print({ Color::Red }, L"[{}] Failed to open log file.", L"ERROR");
PrintError(L"Failed to open log file.");
}
}
}

void Flush()
{
if (file.is_open())
{
if (file.is_open()) {
file << buffer.str();
buffer.str(L"");
file.flush();
Expand All @@ -44,8 +42,7 @@ namespace Logger

void Close()
{
if (file.is_open())
{
if (file.is_open()) {
Flush();
file.close();
}
Expand All @@ -69,17 +66,15 @@ namespace Logger

#ifndef NDEBUG
if (level == LogLevel::Error) {
Print({ Color::Red }, L"[{}] {}", level_str, message);
PrintError(message.data());
}
#endif

if (file.is_open())
{
if (file.is_open()) {
auto now_time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::wostringstream ss;
ss << std::put_time(std::localtime(&now_time), L"%Y-%m-%d %H:%M:%S");
std::wstring time_str = ss.str();
buffer << time_str << L" | " << level_str << L" | " << message << std::endl;
buffer << ss.str() << L" | " << std::left << std::setw(5) << level_str << L" | " << message << std::endl;
Flush();
}
}
Expand Down
9 changes: 6 additions & 3 deletions src/BasicUtils/Memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
#include <cstddef>
#include <stdexcept>
#include <vector>
#include "Console.h"
using namespace Console;

namespace Memory {
template<typename T>
Expand All @@ -23,7 +21,7 @@ namespace Memory {
throw std::runtime_error("Failed to set memory protection for reading");

std::memcpy(static_cast<void*>(&buffer), address, bufferSize);

if (!VirtualProtect(address, bufferSize, oldProtect, &oldProtect))
throw std::runtime_error("Failed to restore memory protection after reading");
return true;
Expand Down Expand Up @@ -80,6 +78,11 @@ namespace Memory {

return true;
}

template <typename T, typename U>
std::size_t GetMemberFunctionOffset(U T::* member_ptr) {
return reinterpret_cast<std::size_t>(&(((T*)nullptr)->*member_ptr));
}
}

#endif //_MEMORY_H
38 changes: 21 additions & 17 deletions src/BasicUtils/PatternScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ PatternScanner::ModuleInfo PatternScanner::GetModuleInfo(std::wstring_view modul
{
const HMODULE module_handle = GetModuleHandleW(module_name.empty() ? nullptr : module_name.data());
if (!module_handle) {
const auto error_code = GetLastError();
throw std::runtime_error(Utils::ToString(Utils::FormatString(L"Could not get module handle for {}. Error code: {}",
module_name.empty() ? L"main module" : module_name, error_code)).c_str());
module_name.empty() ? L"main module" : module_name, GetLastError())).c_str());
}
MODULEINFO module_info;
if (!GetModuleInformation(GetCurrentProcess(), module_handle, &module_info, sizeof(module_info))) {
const auto error_code = GetLastError();
throw std::runtime_error(Utils::ToString(Utils::FormatString(L"Could not get module information for {}. Error code: {}",
module_name.empty() ? L"main module" : module_name, error_code)).c_str());
module_name.empty() ? L"main module" : module_name, GetLastError())).c_str());
}

return { reinterpret_cast<std::size_t>(module_info.lpBaseOfDll), static_cast<std::size_t>(module_info.SizeOfImage) };
Expand Down Expand Up @@ -115,11 +113,12 @@ bool PatternScanner::ScanMatch(const void* value, ScanTargets targets, ValueType
std::string_view val(reinterpret_cast<const char*>(value));
std::string_view first(reinterpret_cast<const char*>(targets.first.data()), targets.first.size());
std::string_view second(targets.second.empty() ? "" : reinterpret_cast<const char*>(targets.second.data()), targets.second.size());

//std::wstring_view val(reinterpret_cast<const wchar_t*>(value));
//std::wstring_view first(reinterpret_cast<const wchar_t*>(targets.first.data()), targets.first.size());
//std::wstring_view second(targets.second.empty() ? L"" : reinterpret_cast<const wchar_t*>(targets.second.data()), targets.second.size());

return ScanMatchNumeric(val, first, second, scan_type);
}
case ValueType::WString: {
std::wstring_view val(reinterpret_cast<const wchar_t*>(value));
std::wstring_view first(reinterpret_cast<const wchar_t*>(targets.first.data()), targets.first.size());
std::wstring_view second(targets.second.empty() ? L"" : reinterpret_cast<const wchar_t*>(targets.second.data()), targets.second.size());
return ScanMatchNumeric(val, first, second, scan_type);
}
default:
Expand Down Expand Up @@ -200,13 +199,13 @@ std::vector<std::uint8_t> PatternScanner::SignatureToByteArray(std::wstring_view
std::vector<Scan> PatternScanner::ScanAll(std::size_t base_address, std::size_t image_size, ScanTargets byte_pattern, ValueType value_type, ScanType scan_type, bool forward)
{
if (!base_address)
throw std::invalid_argument(Utils::FormatString("Invalid base address ({})", value_type == ValueType::String ? std::string(byte_pattern.first.begin(), byte_pattern.first.end()) : Utils::ToHexString(byte_pattern.first.data(), byte_pattern.first.size())));
throw std::invalid_argument(Utils::FormatString("Invalid base address ({})", value_type == ValueType::String || value_type == ValueType::WString ? std::string(byte_pattern.first.begin(), byte_pattern.first.end()) : Utils::ToHexString(byte_pattern.first.data(), byte_pattern.first.size())));

if (!image_size)
throw std::invalid_argument(Utils::FormatString("Invalid image size ({})", value_type == ValueType::String ? std::string(byte_pattern.first.begin(), byte_pattern.first.end()) : Utils::ToHexString(byte_pattern.first.data(), byte_pattern.first.size())));
throw std::invalid_argument(Utils::FormatString("Invalid image size ({})", value_type == ValueType::String || value_type == ValueType::WString ? std::string(byte_pattern.first.begin(), byte_pattern.first.end()) : Utils::ToHexString(byte_pattern.first.data(), byte_pattern.first.size())));

if (byte_pattern.first.empty() || byte_pattern.first.size() > image_size)
throw std::invalid_argument(Utils::FormatString("Invalid pattern size ({})", value_type == ValueType::String ? std::string(byte_pattern.first.begin(), byte_pattern.first.end()) : Utils::ToHexString(byte_pattern.first.data(), byte_pattern.first.size())));
throw std::invalid_argument(Utils::FormatString("Invalid pattern size ({})", value_type == ValueType::String || value_type == ValueType::WString ? std::string(byte_pattern.first.begin(), byte_pattern.first.end()) : Utils::ToHexString(byte_pattern.first.data(), byte_pattern.first.size())));

const auto pattern_size = byte_pattern.first.size();
const auto end_address = base_address + image_size - pattern_size;
Expand Down Expand Up @@ -246,7 +245,7 @@ std::vector<Scan> PatternScanner::ScanAll(std::size_t base_address, std::size_t

std::vector<Scan> PatternScanner::ScanAll(std::size_t base_address, std::size_t image_size, std::wstring_view value, ScanType scan_type, bool forward)
{
return ScanAll(base_address, image_size, { SignatureToByteArray(value) }, ValueType::String, scan_type, forward);
return ScanAll(base_address, image_size, { SignatureToByteArray(value) }, ValueType::WString, scan_type, forward);
}

std::vector<Scan> PatternScanner::ScanAll(std::wstring_view value, std::wstring_view module_name, ScanType scan_type, bool forward)
Expand All @@ -258,13 +257,13 @@ std::vector<Scan> PatternScanner::ScanAll(std::wstring_view value, std::wstring_
Scan PatternScanner::ScanFirst(std::size_t base_address, std::size_t image_size, ScanTargets byte_pattern, ValueType value_type, ScanType scan_type, bool forward)
{
if (!base_address)
throw std::invalid_argument(Utils::FormatString("Invalid base address ({})", value_type == ValueType::String ? std::string(byte_pattern.first.begin(), byte_pattern.first.end()) : Utils::ToHexString(byte_pattern.first.data(), byte_pattern.first.size())));
throw std::invalid_argument(Utils::FormatString("Invalid base address ({})", value_type == ValueType::String || value_type == ValueType::WString ? std::string(byte_pattern.first.begin(), byte_pattern.first.end()) : Utils::ToHexString(byte_pattern.first.data(), byte_pattern.first.size())));

if (!image_size)
throw std::invalid_argument(Utils::FormatString("Invalid image size ({})", value_type == ValueType::String ? std::string(byte_pattern.first.begin(), byte_pattern.first.end()) : Utils::ToHexString(byte_pattern.first.data(), byte_pattern.first.size())));
throw std::invalid_argument(Utils::FormatString("Invalid image size ({})", value_type == ValueType::String || value_type == ValueType::WString ? std::string(byte_pattern.first.begin(), byte_pattern.first.end()) : Utils::ToHexString(byte_pattern.first.data(), byte_pattern.first.size())));

if (byte_pattern.first.empty() || byte_pattern.first.size() > image_size)
throw std::invalid_argument(Utils::FormatString("Invalid pattern size ({})", value_type == ValueType::String ? std::string(byte_pattern.first.begin(), byte_pattern.first.end()) : Utils::ToHexString(byte_pattern.first.data(), byte_pattern.first.size())));
throw std::invalid_argument(Utils::FormatString("Invalid pattern size ({})", value_type == ValueType::String || value_type == ValueType::WString ? std::string(byte_pattern.first.begin(), byte_pattern.first.end()) : Utils::ToHexString(byte_pattern.first.data(), byte_pattern.first.size())));

const auto pattern_size = byte_pattern.first.size();
const auto end_address = base_address + image_size - pattern_size;
Expand Down Expand Up @@ -301,7 +300,7 @@ Scan PatternScanner::ScanFirst(std::size_t base_address, std::size_t image_size,

Scan PatternScanner::ScanFirst(std::size_t base_address, std::size_t image_size, std::wstring_view value, ScanType scan_type, bool forward)
{
return ScanFirst(base_address, image_size, { SignatureToByteArray(value) }, ValueType::String, scan_type, forward);
return ScanFirst(base_address, image_size, { SignatureToByteArray(value) }, ValueType::WString, scan_type, forward);
}

Scan PatternScanner::ScanFirst(std::wstring_view value, std::wstring_view module_name, ScanType scan_type, bool forward)
Expand Down Expand Up @@ -419,6 +418,11 @@ bool Scan::unhook() const
return is_found() ? Hooking::UnhookFunction(&(PVOID&)m_address) : false;
}

Scan Scan::scan_first(std::wstring_view value, ScanType scan_type, bool forward) const
{
return is_found() ? PatternScanner::ScanFirst(m_address, m_module_info.second, { PatternScanner::SignatureToByteArray(value) }, ValueType::WString, scan_type, forward) : Scan(NULL, m_module_info);
}

std::vector<Scan> Scan::get_all_matching_codes(AssemblyCode code, std::size_t base_address, std::size_t image_size) const
{
std::vector<uint8_t> pattern = { static_cast<std::uint8_t>(code) };
Expand Down
11 changes: 6 additions & 5 deletions src/BasicUtils/PatternScanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <vector>
#include <format>
#include <span>
#include "Memory.h"

enum class AssemblyCode {
PUSH_VALUE = 0x68,
Expand All @@ -31,6 +32,7 @@ enum class ValueType {
Float,
Double,
String,
WString,
};

class Scan {
Expand All @@ -50,6 +52,8 @@ class Scan {
bool hook(PVOID p_detours) const;
bool unhook() const;

Scan scan_first(std::wstring_view value, ScanType scan_type = ScanType::Unknown, bool forward = true) const;

std::vector<Scan> get_all_matching_codes(AssemblyCode code, std::size_t base_address = 0, std::size_t image_size = 0) const;
Scan get_first_matching_code(AssemblyCode code, std::size_t base_address = 0, std::size_t image_size = 0) const;

Expand All @@ -64,11 +68,8 @@ class Scan {
}

template <typename T>
bool write(const T& value) const {
if constexpr (std::is_pointer_v<T> || std::is_same_v<T, std::wstring> || std::is_same_v<T, std::wstring_view>)
return ::WriteProcessMemory(::GetCurrentProcess(), reinterpret_cast<LPVOID>(m_address), value, (std::char_traits<wchar_t>::length(reinterpret_cast<const wchar_t*>(value)) + 1) * sizeof(wchar_t), nullptr) != 0;
else
return ::WriteProcessMemory(::GetCurrentProcess(), reinterpret_cast<LPVOID>(m_address), std::addressof(value), sizeof(value), nullptr) != 0;
bool write(const T& buffer, std::size_t bufferSize = -1) const {
return is_found() ? Memory::Write(reinterpret_cast<LPVOID>(m_address), buffer, bufferSize) : false;
}

private:
Expand Down
Loading

0 comments on commit 2e3c193

Please sign in to comment.