mirror of
https://gitgud.io/yuv420p10le/plexmediaserver_crack
synced 2025-07-04 16:34:47 +00:00

* `rax` is no longer overwritten on Linux. * Absolute jumps are now used on both platforms, rather than MinHook. * The Windows code now performs page access checks. * The signature scanner now works as intended up to the last byte.
152 lines
3.7 KiB
C++
152 lines
3.7 KiB
C++
#include "hook.hpp"
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#define NOMINMAX
|
|
#include <Windows.h>
|
|
|
|
#include <format>
|
|
#include <vector>
|
|
#include <dbghelp.h>
|
|
#include <iostream>
|
|
|
|
uintptr_t _is_feature_available;
|
|
|
|
bool get_section_info(std::string_view name, uintptr_t& start, uintptr_t& end)
|
|
{
|
|
char filename[MAX_PATH];
|
|
GetModuleFileNameA(NULL, filename, sizeof(filename));
|
|
|
|
const auto cur_handle = GetModuleHandleA(filename);
|
|
IMAGE_NT_HEADERS* nt_hdr = ImageNtHeader(cur_handle);
|
|
IMAGE_SECTION_HEADER* section_hdr = reinterpret_cast<IMAGE_SECTION_HEADER*>(nt_hdr + 1);
|
|
const uintptr_t image_base = reinterpret_cast<uintptr_t>(cur_handle);
|
|
|
|
for(int i = 0; i < nt_hdr->FileHeader.NumberOfSections; i++, section_hdr++)
|
|
{
|
|
const auto section_header_name = reinterpret_cast<char*>(section_hdr->Name);
|
|
|
|
if(name == section_header_name)
|
|
{
|
|
const uintptr_t base_module = image_base + section_hdr->VirtualAddress;
|
|
start = base_module;
|
|
end = base_module + section_hdr->Misc.VirtualSize - 1;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
uintptr_t sig_scan(const uintptr_t start, const uintptr_t end, std::string_view pattern)
|
|
{
|
|
constexpr const uint16_t WILDCARD = 0xFFFF;
|
|
std::vector<uint16_t> pattern_vec;
|
|
|
|
for(uintptr_t i = 0; i < pattern.length(); i++)
|
|
{
|
|
if(pattern[i] == ' ')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(pattern[i] == '?')
|
|
{
|
|
if(pattern[i + 1] == '?')
|
|
{
|
|
i++;
|
|
}
|
|
|
|
pattern_vec.push_back(WILDCARD);
|
|
|
|
continue;
|
|
}
|
|
|
|
pattern_vec.push_back(static_cast<uint16_t>(std::strtol(&pattern[i], nullptr, 16)));
|
|
i++;
|
|
}
|
|
|
|
uintptr_t end_address = start;
|
|
MEMORY_BASIC_INFORMATION mbi{};
|
|
|
|
while(end_address < end && VirtualQuery(reinterpret_cast<void*>(end_address), &mbi, sizeof(mbi)))
|
|
{
|
|
if((mbi.Protect & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) == 0 ||
|
|
(mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) > 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
end_address = std::min(end, reinterpret_cast<uintptr_t>(mbi.BaseAddress) + mbi.RegionSize);
|
|
}
|
|
|
|
const auto vec_length = pattern_vec.size();
|
|
|
|
for(uintptr_t i = start; i <= end_address - vec_length; i++)
|
|
{
|
|
bool mismatch = false;
|
|
|
|
for(uintptr_t x = 0; x < vec_length; x++)
|
|
{
|
|
const auto mem = *reinterpret_cast<uint8_t*>(i + x);
|
|
|
|
if(pattern_vec[x] != WILDCARD && mem != pattern_vec[x])
|
|
{
|
|
mismatch = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!mismatch)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint64_t hook_is_feature_available([[maybe_unused]] uintptr_t user, [[maybe_unused]] const char* feature)
|
|
{
|
|
// `feature` is a GUID. You can use it to enable certain features rather than Godmode (everything); but there's no reason to limit ourselves.. is there?
|
|
|
|
return true;
|
|
}
|
|
|
|
void hook()
|
|
{
|
|
uintptr_t dottext_start;
|
|
uintptr_t dottext_end;
|
|
|
|
if(!get_section_info(".text", dottext_start, dottext_end))
|
|
{
|
|
std::cerr << "[ERR] [plexmediaserver_crack] .text section not found; aborting.\n";
|
|
|
|
return;
|
|
}
|
|
|
|
_is_feature_available = sig_scan(dottext_start, dottext_end, "41 54 41 56 41 57 48 83 EC 20 4C 8B F9 4C 8B F2");
|
|
|
|
if(_is_feature_available == 0)
|
|
{
|
|
std::cerr << "[ERR] [plexmediaserver_crack] Couldn't find is_feature_available; aborting.\n";
|
|
|
|
return;
|
|
}
|
|
|
|
// Jumps to specified address
|
|
uint8_t shellcode[] =
|
|
{
|
|
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp [rip+0x06]
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ?
|
|
};
|
|
|
|
*reinterpret_cast<decltype(&hook_is_feature_available)*>(&shellcode[6]) = &hook_is_feature_available;
|
|
|
|
DWORD old_prot;
|
|
VirtualProtect(reinterpret_cast<void*>(_is_feature_available), sizeof(shellcode), PAGE_EXECUTE_READWRITE, &old_prot);
|
|
memcpy(reinterpret_cast<void*>(_is_feature_available), shellcode, sizeof(shellcode));
|
|
VirtualProtect(reinterpret_cast<void*>(_is_feature_available), sizeof(shellcode), old_prot, &old_prot);
|
|
}
|