mirror of
https://gitgud.io/yuv420p10le/plexmediaserver_crack
synced 2025-07-04 16:34:47 +00:00
v1.40.3.8555+ support and other quirks.
* Now works with v1.40.3.8555 (inlined) and older versions too. * Added a whitelist of features now rather than a global-enable. * Refactored some code to use std::optional. * Linux: Wrote proper hooking function. No unhooking support as it's unneeded. * Windows: Now uses SafetyHook as we need trampolines. * Windows: When building for debug, you can see queried features and their caller (return address offset from PMS base address); reverse on your own or query me.
This commit is contained in:
parent
7897276f16
commit
2a003b95ba
1
.gitignore
vendored
1
.gitignore
vendored
@ -236,3 +236,4 @@ install_manifest.txt
|
|||||||
compile_commands.json
|
compile_commands.json
|
||||||
CTestTestfile.cmake
|
CTestTestfile.cmake
|
||||||
_deps
|
_deps
|
||||||
|
*.clangd
|
@ -1,6 +1,6 @@
|
|||||||
# plexmediaserver_crack
|
# plexmediaserver_crack
|
||||||
|
|
||||||
Enables Godmode, unlocking *all features* on (hardware transcoding, intro/credit detection, HEVC transcoding, etc..) on Plex Media Server. Including Plex Pass features without a required subscription, and including early-access/development/Plex Ninja features.
|
Unlocking *most features* on (hardware transcoding, intro/credit detection, HEVC transcoding, etc..) on Plex Media Server. Including Plex Pass features without a required subscription, and including early-access/development/Plex Ninja features. Some features are exempt (check the Windows source code for reference).
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ Setup the above commands as a script for an easy installation, and optionally, s
|
|||||||
|
|
||||||
#### Windows
|
#### Windows
|
||||||
|
|
||||||
Build using Visual Studio 2022, C++20.
|
Build using Visual Studio 2022, C++20. You need [Zydis](https://github.com/zyantific/zydis).
|
||||||
|
|
||||||
#### Linux
|
#### Linux
|
||||||
|
|
||||||
|
@ -2,13 +2,13 @@ cmake_minimum_required(VERSION 3.18)
|
|||||||
project(plexmediaserver_crack)
|
project(plexmediaserver_crack)
|
||||||
SET(CMAKE_BUILD_RPATH_USE_ORIGIN TRUE)
|
SET(CMAKE_BUILD_RPATH_USE_ORIGIN TRUE)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
add_compile_options(-Wall -Wextra -Werror)
|
add_compile_options(-Wextra -Werror)
|
||||||
|
|
||||||
set(SOURCES main.cpp hook.cpp)
|
set(SOURCES main.cpp hook.cpp Zydis.c)
|
||||||
set(HEADERS hook.hpp)
|
set(HEADERS hook.hpp Zydis.h)
|
||||||
|
|
||||||
add_library(plexmediaserver_crack SHARED ${SOURCES} ${HEADERS})
|
add_library(plexmediaserver_crack SHARED ${SOURCES} ${HEADERS})
|
||||||
set_target_properties(plexmediaserver_crack PROPERTIES PREFIX "")
|
set_target_properties(plexmediaserver_crack PROPERTIES PREFIX "")
|
||||||
|
54990
linux/Zydis.c
Normal file
54990
linux/Zydis.c
Normal file
File diff suppressed because one or more lines are too long
12113
linux/Zydis.h
Normal file
12113
linux/Zydis.h
Normal file
File diff suppressed because it is too large
Load Diff
310
linux/hook.cpp
310
linux/hook.cpp
@ -5,9 +5,214 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unistd.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include "Zydis.h"
|
||||||
|
|
||||||
bool get_dottext_info(uintptr_t& start, uintptr_t& end)
|
std::unordered_map<std::string, std::string> g_features =
|
||||||
|
{
|
||||||
|
// Available with Plex Pass
|
||||||
|
{ "c9d9b7ee-fdd9-474e-b143-5039c04e9b9b", "guided-upgrade" },
|
||||||
|
{ "9e93f8a8-7ccd-4d15-99fa-76a158027660", "increase-password-complexity" },
|
||||||
|
{ "547514ab-3284-46e5-af77-bbaff247e3fc", "upgrade-3ds2" },
|
||||||
|
{ "3ae06d3a-a76b-435e-8cef-2d2008610ba2", "ad-countdown-timer" },
|
||||||
|
{ "abd37b14-706c-461f-8255-fa9563882af3", "adaptive_bitrate" },
|
||||||
|
{ "d1477307-4dac-4e57-9258-252e5b908693", "amazon-loop-debug" },
|
||||||
|
{ "b227c158-e062-4ff1-95d8-8ed11cecafb1", "Android - Dolby Vision" },
|
||||||
|
{ "86da2200-58db-4d78-ba46-f146ba25906b", "Android - PiP" },
|
||||||
|
{ "2797e341-b062-46ed-862f-0acbba5dd522", "artist-tv" },
|
||||||
|
{ "c987122a-a796-432f-af00-953821c127bb", "avod-ad-analysis" },
|
||||||
|
{ "e703655b-ee05-4e24-97e3-a138da62c425", "avod-new-media" },
|
||||||
|
{ "bec2ba97-4b25-472b-9cfc-674f5c68c2ae", "blacklist_get_signin" },
|
||||||
|
{ "b3b87f19-5ccd-4b14-bb62-b9d7b982392e", "blacklist-subnets" },
|
||||||
|
{ "6aaaf4fc-c55f-4042-92c8-b35f7886d249", "bypass-web-navbar-upsell-modal" },
|
||||||
|
{ "fb34e64d-cd89-47b8-8bae-a6d20c542bae", "camera_upload" },
|
||||||
|
{ "567033ef-ffee-44fb-8f90-f678077445f9", "CU Sunset" },
|
||||||
|
{ "58829fc9-26b8-41f4-a6c0-90ea7a11ae24", "chromecast-music-mp" },
|
||||||
|
{ "6ab6677b-ad9b-444f-9ca1-b8027d05b3e1", "client-non-destructive-comskip" },
|
||||||
|
{ "5b6190a9-77a4-477e-9fbc-c8118e35a4c1", "client-radio-stations" },
|
||||||
|
{ "65152b75-13a9-408a-bd30-dbd23a259183", "cloudsync" },
|
||||||
|
{ "c4704b28-4e26-460a-bf2e-2576d0c2cb77", "community-new-user-onboarding" },
|
||||||
|
{ "7bb1ed71-a0a3-4362-aa08-7c3fa7241578", "community-friendships-management" },
|
||||||
|
{ "fc3e8322-5e6e-4f4a-9d71-728c6d5656bd", "community-phase0" },
|
||||||
|
{ "a852775a-2b74-4624-aaa3-3d624471a537", "community-phase0-web" },
|
||||||
|
{ "6272ad55-9fc0-43c6-8e1a-3f0df7a3630e", "community-p1" },
|
||||||
|
{ "31fcbe1f-0459-42cb-a15f-5084f62374d9", "community-p2-r1" },
|
||||||
|
{ "06798ab7-4fa5-4416-9db3-f313c4292f01", "community-p2-r2" },
|
||||||
|
{ "626004b8-a8b8-4fb1-9adc-8a6277f98597", "community-p2-r3" },
|
||||||
|
{ "8f47a689-aa84-408f-bf6b-00015e9413e1", "community-p2-r4" },
|
||||||
|
{ "7f46bf17-fabf-4f96-99a2-cf374f6eed71", "comments_and_replies_push_notifications" },
|
||||||
|
{ "c36a6985-eee3-4400-a394-c5787fad15b5", "friend_request_push_notifications" },
|
||||||
|
{ "3f6baa76-7488-479a-9e4f-49ff2c0d3711", "community_access_plex_tv" },
|
||||||
|
{ "24b4cf36-b296-4002-86b7-f1adb657e76a", "companions_sonos" },
|
||||||
|
{ "32cc8bf5-b425-4582-a52d-71b4f1cf436b", "content_filter" },
|
||||||
|
{ "f6a0e423-1a83-418c-8448-a1c7105fd71a", "create_anonymous_users" },
|
||||||
|
{ "926bc176-58ca-47da-b8e3-080ed14ea6ba", "credits-markers" },
|
||||||
|
{ "849433b0-ef60-4a71-9dd9-939bc01f5362", "custom-home-removal" },
|
||||||
|
{ "7ee1495c-2798-4288-94e2-9cd98e67d441", "grandfather-sync" },
|
||||||
|
{ "d29f0ee0-3d3a-46c3-b582-4bc69bc17c29", "disable_home_user_friendships" },
|
||||||
|
{ "ce8f644e-87ce-4ba5-b165-fadd69778019", "disable_sharing_friendships" },
|
||||||
|
{ "6225c337-cd26-4ff0-b864-6c6dd84c9e0d", "disco-reported-issues" },
|
||||||
|
{ "d865f64a-ca06-472d-ae01-7a444aba6251", "disco-director-cast-crew-updates" },
|
||||||
|
{ "2131d3dc-56c8-45d0-acec-c4683fd9a027", "discover-genre-browsing" },
|
||||||
|
{ "cb0e4c75-b1cb-43e9-97ea-6b9bc66c717b", "discover-managed-related-vod" },
|
||||||
|
{ "807d9881-a846-40c3-8d54-84fc490b7ba9", "discover-managed-user-test" },
|
||||||
|
{ "ba7c4a4f-a13b-4ec0-8eb2-cd0ba2fe77f8", "discover-services-hub" },
|
||||||
|
{ "67c80530-eae3-4500-a9fa-9b6947d0f6d1", "Sync v3" },
|
||||||
|
{ "3bfd3ccf-8c63-4dbb-8f87-9b21b402c82b", "downloads-gating" },
|
||||||
|
{ "34e182bd-2f62-4678-a9e9-d13b3e25019d", "drm_support" },
|
||||||
|
{ "e8230c74-0940-4b91-9e20-6571eb068086", "dvr" },
|
||||||
|
{ "c92d4903-bc06-4715-8ce4-4a22674abac8", "dvr-block-unsupported-countries" },
|
||||||
|
{ "af291e9e-813f-4467-8779-5d215abc3b5f", "le_isrg_root_x1" },
|
||||||
|
{ "9c982beb-c676-4d6f-a777-ff5d37ec3081", "epg-recent-channels" },
|
||||||
|
{ "5d819d02-5d04-4116-8eec-f49def4e2d6f", "federated-auth" },
|
||||||
|
{ "4742780c-af9d-4b44-bf5b-7b27e3369aa8", "global-continue-watching" },
|
||||||
|
{ "84a754b0-d1ca-4433-af2d-c949bf4b4936", "hwtranscode" },
|
||||||
|
{ "bc8d1fca-deb0-4d0a-a6f4-12cfd681002d", "hardware_transcoding" },
|
||||||
|
{ "b2403ac6-4885-4971-8b96-59353fd87c72", "home" },
|
||||||
|
{ "f1ac7a53-c524-4311-9a27-713562fc24fa", "HRK_enable_EUR" },
|
||||||
|
{ "c6ce2260-a19d-4fea-9f74-a52231f03924", "hybrid-guide" },
|
||||||
|
{ "55b9f6ed-5d26-4d2d-a436-68882a9901b5", "imagga-v2" },
|
||||||
|
{ "b83c8dc9-5a01-4b7a-a7c9-5870c8a6e21b", "intro-markers" },
|
||||||
|
{ "39dbdd84-8339-4736-96a1-0eb105cc2e08", "ios14-privacy-banner" },
|
||||||
|
{ "b58d7f28-7b4a-49bb-97a7-152645505f28", "item_clusters" },
|
||||||
|
{ "81c8d5fa-8d90-4833-aa10-a31a51310e2f", "iterable-notification-tokens" },
|
||||||
|
{ "e4a9fd6f-4105-476b-bc57-adccd009323b", "keep-payment-method" },
|
||||||
|
{ "c7ae6f8f-05e6-48bb-9024-c05c1dc3c43e", "kevin-bacon" },
|
||||||
|
{ "cb151c05-1943-408a-b37c-06f7d409d6bb", "korea-consent" },
|
||||||
|
{ "8536058d-e1dd-4ae7-b30f-e8b059b7cc17", "lets_encrypt" },
|
||||||
|
{ "6b85840c-d79d-40c2-8d8f-dfc0b7d26776", "lightning-dvr-pivot" },
|
||||||
|
{ "65685ff8-4375-4e4c-a806-ec1f0b4a8b7f", "livetv" },
|
||||||
|
{ "de789b83-9c5e-4472-bccf-791c69e67500", "livetv-platform-specific" },
|
||||||
|
{ "d8810b38-ec9b-494c-8555-3df6e365dfbd", "allow_dvr" },
|
||||||
|
{ "9eaa5152-320b-48e6-9d47-9492ba5e5b54", "live-tv-channels-grid" },
|
||||||
|
{ "d1b1e233-a891-45e5-935c-6114e905dbe8", "live-tv-grid-pagination" },
|
||||||
|
{ "dab501df-5d99-48ef-afc2-3e839e4ddc9a", "live-tv-support-incomplete-segments" },
|
||||||
|
{ "4b522f91-ae89-4f62-af9c-76f44d8ef61c", "tuner-sharing" },
|
||||||
|
{ "0b8bf267-1acf-4f89-99eb-4afbb9d250e5", "live-tv-on-plex-subtitles" },
|
||||||
|
{ "002c9f1a-2fc0-4812-b85b-0e6140f21a0f", "lyrics" },
|
||||||
|
{ "7ab197ee-1bd6-4335-8f55-db827f0110ba", "media-access-split-2" },
|
||||||
|
{ "4a933f24-464d-4a6b-b372-9e4497abd361", "discover" },
|
||||||
|
{ "dbab9396-78ff-48f5-a5ce-c76539ed1b6e", "cloud-livetv" },
|
||||||
|
{ "22b27e12-472e-4383-92ea-2ec3976d8e72", "metadata_search" },
|
||||||
|
{ "f8ea4f37-c554-476a-8852-1cbd2912f3f6", "metadata" },
|
||||||
|
{ "8e8dd5c8-14a4-4208-97d4-623e09191774", "music_preview" },
|
||||||
|
{ "e7cea823-02e5-48c4-a501-d37b82bf132f", "music" },
|
||||||
|
{ "1841971c-6be5-40e6-a211-7e189d767a78", "podcasts" },
|
||||||
|
{ "68747f3a-ce13-46ce-9274-1e0544c9f500", "vod_cloudflare" },
|
||||||
|
{ "ed374ad1-1d36-4396-8794-f710011e4fed", "vod_subtitles" },
|
||||||
|
{ "50a1cfe9-dac1-4722-aee8-cc22e9758dd6", "tunefind-vod" },
|
||||||
|
{ "cc9bea3b-11ab-4402-a222-4958bb129cab", "vod" },
|
||||||
|
{ "55e1398c-930f-41c1-bead-f5c2e471bb25", "webshows" },
|
||||||
|
{ "1844737f-1a87-45c3-ab20-01435959e63c", "music_videos" },
|
||||||
|
{ "de65add8-2782-4bb8-b156-e0b57a844479", "new_plex_pass_prices" },
|
||||||
|
{ "b77e6744-c18d-415a-8e7c-7aac5d7a7750", "news-provider-sunset-modal" },
|
||||||
|
{ "0de6151c-e0dd-47c8-a81e-1acb977c7f0f", "nominatim" },
|
||||||
|
{ "3dd35df0-3e4a-4e74-9ba8-2baeda83a733", "nonAnonymousAccount" },
|
||||||
|
{ "5dc82bc9-6038-4c21-b752-bc3454773eda", "onboarding-community" },
|
||||||
|
{ "73d0bba4-a6ba-4114-bac3-3039c12e08fb", "parental-controls" },
|
||||||
|
{ "82999dd3-a2be-482e-9f44-357879b4f603", "pass" },
|
||||||
|
{ "f4fe27db-7292-4e13-98b6-f3ff9b5ed5fe", "people-pages" },
|
||||||
|
{ "652968f4-d474-4e04-a1cf-2dd1eaeb488a", "people-pages-pms" },
|
||||||
|
{ "96cac76e-c5bc-4596-87eb-4fdfef9aaa11", "photos-favorites" },
|
||||||
|
{ "2ea0e464-ea4f-4be2-97c1-ce6ed4b377dd", "photos-metadata-edition" },
|
||||||
|
{ "850f3d1e-3f38-44c1-9c0c-e3c9127b8b5a", "photosV6-edit" },
|
||||||
|
{ "3a2b0cb6-1519-4431-98e2-823c248c70eb", "photosV6-tv-albums" },
|
||||||
|
{ "02da2909-ddfd-46be-9e42-65008a79fc05", "played_badges" },
|
||||||
|
{ "9aea4ca5-2095-4619-9339-88c1e662fde6", "pms_health" },
|
||||||
|
{ "222020fb-1504-492d-af33-a0b80a49558a", "premium-dashboard" },
|
||||||
|
{ "d413fb56-de7b-40e4-acd0-f3dbb7c9e104", "premium_music_metadata" },
|
||||||
|
{ "a0a78867-6b26-446f-9c3f-df4edf831259", "promoted-grid-channel-filters" },
|
||||||
|
{ "3eb2789b-200c-4a15-91d2-dedfe560953c", "rate-limit-client-token" },
|
||||||
|
{ "64adaa4e-aa7e-457d-b385-51438216d7fe", "shared_server_notification" },
|
||||||
|
{ "6c4d66d9-729d-49dc-b70d-ab2652abf15a", "shared_source_notification" },
|
||||||
|
{ "0cce52a7-0778-4781-9a07-712370fb6b8a", "require-plex-nonce" },
|
||||||
|
{ "644c4466-05fa-45e0-a478-c594cf81778f", "save-to-library" },
|
||||||
|
{ "ccef9d3a-537a-43d9-8161-4c7113c6e2bb", "scrobbling-service" },
|
||||||
|
{ "7b392594-6949-4736-9894-e57a9dfe4037", "scrobbling-service-plex-tv" },
|
||||||
|
{ "1df3cd16-faf2-4d37-8349-1fcf3713bf1d", "album-types" },
|
||||||
|
{ "1417df52-986e-4e4b-8dcd-3997fbc5c976", "collections" },
|
||||||
|
{ "8fd37970-6e4e-4f00-a64a-e70b52f18e94", "music-analysis" },
|
||||||
|
{ "300231e0-69aa-4dce-97f4-52d8c00e3e8c", "radio" },
|
||||||
|
{ "05690239-443e-43fb-bc1a-95b5d916ca63", "session_bandwidth_restrictions" },
|
||||||
|
{ "4ca03b04-54c1-4f9f-aea2-f813ae48f317", "session_kick" },
|
||||||
|
{ "6d7be725-9a96-42c7-8af4-01e735138822", "exclude restrictions" },
|
||||||
|
{ "1b3a63e4-c2f4-4011-a181-2343d3a97ef7", "signin_notification" },
|
||||||
|
{ "b5874ecb-6610-47b2-8906-1b5a897acb02", "signin_with_apple" },
|
||||||
|
{ "62b1e357-5450-41d8-9b60-c7705f750849", "singleitemsharing" },
|
||||||
|
{ "c5adf9dc-af13-4a85-a24b-98de6fa2f595", "sleep-timer" },
|
||||||
|
{ "8a9471c4-13bd-435a-b5b8-4ca6e423f355", "sonos-client-feature" },
|
||||||
|
{ "579156cf-0664-45b4-8b7b-dda400ac3e26", "spotlight-style-hub" },
|
||||||
|
{ "fec722a0-a6d4-4fbd-96dc-4ffb02b072c5", "spring_serve_ad_provider" },
|
||||||
|
{ "bb50c92f-b412-44fe-8d8a-b1684f212a44", "Subtitles on Demand" },
|
||||||
|
{ "9dc1df45-fb45-4be1-9ab2-eb23eb57f082", "sync" },
|
||||||
|
{ "6380e085-02fe-43b5-8bff-380fa4f2423c", "trailers" },
|
||||||
|
{ "a3d2d5c4-46a0-436e-a2d6-80d26f32b369", "transcoder_cache" },
|
||||||
|
{ "c2409baa-d044-45c7-b1f4-e9e7ccd2d128", "boost-voices" },
|
||||||
|
{ "85ebfb7b-77fb-4afd-bb1a-2fe2fefdddbe", "TREBLE-show-features" },
|
||||||
|
{ "a6e0a154-4735-4cbb-a6ec-7a0a146c8216", "silence-removal" },
|
||||||
|
{ "95149521-f64b-46ea-825c-9114e56afd2c", "sweet-fades" },
|
||||||
|
{ "1dd846ed-7cde-4dc5-8ef6-53d3ce8c4e9d", "visualizers" },
|
||||||
|
{ "bbf73498-4912-4d80-9560-47c4fe212cec", "volume-leveling" },
|
||||||
|
{ "07f804e6-28e6-4beb-b5c3-f2aefc88b938", "tunefind-clients" },
|
||||||
|
{ "5d80b92d-4ecf-4b0b-935f-5efc907bb2c1", "tvod_playback" },
|
||||||
|
{ "06d14b9e-2af8-4c2b-a4a1-ea9d5c515824", "two-factor-authentication" },
|
||||||
|
{ "20824f5c-6dd9-4655-9970-e7701a73c02a", "two-factor-authentication-clients" },
|
||||||
|
{ "d14556be-ae6d-4407-89d0-b83953f4789a", "type-first" },
|
||||||
|
{ "cec2152f-321a-4c24-8c6d-c2b35a624389", "ultrablur" },
|
||||||
|
{ "8b46de05-1f96-4278-87b3-010ba5b1e386", "universal-search" },
|
||||||
|
{ "cce9af5d-7b44-4119-a6b1-108fd0db725c", "universal-search-live-tv" },
|
||||||
|
{ "b6b68f84-5127-4dc9-8a7e-3a04419b5cd4", "universal-search-new-quick-search" },
|
||||||
|
{ "d9528436-ee7c-42e3-ab7b-814f85ef74b4", "universal-watchlist" },
|
||||||
|
{ "b46d16ae-cbd6-4226-8ee9-ab2b27e5dd42", "unsupportedtuners" },
|
||||||
|
{ "096ab4b8-04d2-41f4-9602-f1d5b9e8c7cc", "users-and-sharing" },
|
||||||
|
{ "1b870b8e-f1a7-497c-80b2-857d45f3123f", "vod-schema" },
|
||||||
|
{ "65faa2d0-f57e-4c63-a6b6-f1baa48951b1", "watch-together-20200520" },
|
||||||
|
{ "f83450e2-759a-4de4-8b31-e4a163896d43", "watch-together-invite" },
|
||||||
|
{ "f0c452ce-11e7-465f-be04-5fb0bf4bec48", "watchlist" },
|
||||||
|
{ "edd6039a-137c-4ace-b5d5-4e111ce9690b", "watchlist-source" },
|
||||||
|
{ "f0f40559-a43a-4b8f-85ef-bdb1de1a912a", "watchlist-rss" },
|
||||||
|
{ "b737075d-a6c5-4e8a-8ee9-7dc72d984062", "web-desktop-live-tv-chromecast-remote-player" },
|
||||||
|
{ "f8484f94-92a8-4ca4-9f43-e83ab3f586c7", "web-desktop-v4-dvr-setup" },
|
||||||
|
{ "29bca3b8-e40b-4c69-b71c-f88047240f9b", "web-desktop-v4-home" },
|
||||||
|
{ "591895c1-8c60-4eab-8096-3594bb190257", "web-desktop-v4-pre-plays" },
|
||||||
|
{ "740a75d2-6dba-4317-ba68-ed3d619d4c7a", "web-log-viewer" },
|
||||||
|
{ "5e2a89ec-fb26-4234-b66e-14d37f35dff2", "web_server_dashboard" },
|
||||||
|
{ "73c73f05-7131-41cd-86d7-b91301684bfe", "web-share-v2" },
|
||||||
|
{ "6f82ca43-6117-4e55-ae0e-5ea3b3e99a96", "webhooks" },
|
||||||
|
{ "e4f02866-841f-4ceb-a30c-0a0e68fb874d", "where-to-watch-clients" },
|
||||||
|
|
||||||
|
// Dev/Ninja features
|
||||||
|
{ "044a1fac-6b55-47d0-9933-25a035709432", "transcode-offline" },
|
||||||
|
{ "0e2acda2-d70d-4df6-96e0-f63cf264d217", "transcode-hevc" },
|
||||||
|
{ "fd6683b9-1426-4b00-840f-cd5fb0904a6a", "transcode-tonemapping" },
|
||||||
|
{ "fef9b829-af7e-430c-a757-d80de818f211", "music-analysis" },
|
||||||
|
{ "ea442c16-044a-4fa7-8461-62643f313c62", "thetvdb_v4_plugin" },
|
||||||
|
{ "0eee866d-782b-4dfd-b42b-3bbe8eb0af16", "server-manager" },
|
||||||
|
{ "0a348865-4f87-46dc-8bb2-f37637975724", "photos-v5" },
|
||||||
|
{ "59127bcf-acc8-4e97-ad88-8ba6380880b9", "pro_install" },
|
||||||
|
{ "c55d5900-b546-416d-a8c5-45b24a13e9bc", "download_certificates" },
|
||||||
|
{ "3d572099-e243-49bb-9f94-17de7703f9f9", "advanced-playback-settings" },
|
||||||
|
{ "99d17487-7106-4d42-a3b1-c92f68b73165", "news" },
|
||||||
|
{ "e4532fb1-b2e8-4269-9225-b804657cb3ba", "roku-dogfood" },
|
||||||
|
{ "a19d495a-1cef-4f7c-ab77-5186e63e17f7", "loudness" },
|
||||||
|
{ "4866e9e9-ad14-4c2b-bd92-49576f320fd7", "ump-matching-pref" },
|
||||||
|
{ "d20f9af2-fdb1-4927-99eb-a2eb8fbff799", "shared-radio" },
|
||||||
|
{ "c43d8d0f-7aa3-4fef-b9ad-4902580c90ce", "incremental-epg" },
|
||||||
|
{ "075954ad-56ef-4f5e-9519-9cfb0ed05827", "categories" },
|
||||||
|
{ "88aba3a3-bd62-42a5-91bb-0558a4c1db57", "collections-custom-sorting" },
|
||||||
|
{ "e954ef21-08b4-411e-a1f0-7551f1e57b11", "push-notification" },
|
||||||
|
{ "cd0ef747-af8a-414b-9d3a-dd02b6454db9", "voice-activity-generation" },
|
||||||
|
{ "ba8459cd-81fe-4799-93e2-84358717bfb4", "augmentation-provider-environment" },
|
||||||
|
{ "16abced2-1e64-4f01-b64f-f8ef41b1ea6c", "plex-online-environment" },
|
||||||
|
{ "a6f3f9b3-c10c-4b94-ad59-755e30ac6c90", "detect-commercials" },
|
||||||
|
};
|
||||||
|
|
||||||
|
auto _is_feature_available = reinterpret_cast<decltype(&hook_is_feature_available)>(0);
|
||||||
|
auto _map_find = reinterpret_cast<decltype(&hook_map_find)>(0);
|
||||||
|
|
||||||
|
std::optional<std::tuple<uintptr_t, uintptr_t>> get_dottext_info()
|
||||||
{
|
{
|
||||||
std::ifstream file("/proc/self/maps");
|
std::ifstream file("/proc/self/maps");
|
||||||
std::string line;
|
std::string line;
|
||||||
@ -18,32 +223,62 @@ bool get_dottext_info(uintptr_t& start, uintptr_t& end)
|
|||||||
// Only .text should have `r-xp`. This works I guess..
|
// Only .text should have `r-xp`. This works I guess..
|
||||||
if(line.find("Plex Media Server") != std::string::npos && line.find("r-xp") != std::string::npos)
|
if(line.find("Plex Media Server") != std::string::npos && line.find("r-xp") != std::string::npos)
|
||||||
{
|
{
|
||||||
start = std::stoull(line.substr(0, line.find('-')), nullptr, 16);
|
const uintptr_t start = std::stoull(line.substr(0, line.find('-')), nullptr, 16);
|
||||||
end = std::stoull(line.substr(line.find('-') + 1), nullptr, 16);
|
const uintptr_t end = std::stoull(line.substr(line.find('-') + 1), nullptr, 16);
|
||||||
|
|
||||||
return true;
|
return std::make_tuple(start, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_jmp(const uintptr_t from, const uintptr_t to)
|
std::optional<uintptr_t> create_hook(uintptr_t from, uintptr_t to)
|
||||||
{
|
{
|
||||||
|
ZydisDecoder decoder;
|
||||||
|
ZydisDecodedInstruction instruction;
|
||||||
|
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
|
||||||
|
|
||||||
|
auto trampoline_mem = reinterpret_cast<uint8_t*>(mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_SHARED, -1, 0));
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
while(offset < 14)
|
||||||
|
{
|
||||||
|
if(ZYAN_SUCCESS(ZydisDecoderDecodeInstruction(&decoder, nullptr, reinterpret_cast<void*>(from + offset), ZYDIS_MAX_INSTRUCTION_LENGTH, &instruction)))
|
||||||
|
{
|
||||||
|
std::memcpy(trampoline_mem + offset, reinterpret_cast<uintptr_t*>(from + offset), instruction.length);
|
||||||
|
offset += instruction.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete[] trampoline_mem;
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t shellcode[] =
|
uint8_t shellcode[] =
|
||||||
{
|
{
|
||||||
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp [rip+0x06]
|
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp [rip+0x06]
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ?
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ?
|
||||||
};
|
};
|
||||||
|
|
||||||
*reinterpret_cast<uintptr_t*>(&shellcode[6]) = to;
|
// Jump to original code in trampoline and make trampoline executable
|
||||||
|
*reinterpret_cast<uintptr_t*>(&shellcode[6]) = from + offset;
|
||||||
|
std::memcpy(trampoline_mem + offset, shellcode, sizeof(shellcode));
|
||||||
|
mprotect(reinterpret_cast<void*>(trampoline_mem), 64, PROT_READ|PROT_EXEC);
|
||||||
|
|
||||||
|
// Jump to target code
|
||||||
|
*reinterpret_cast<uintptr_t*>(&shellcode[6]) = to;
|
||||||
mprotect(reinterpret_cast<void*>(from), sizeof(shellcode), PROT_READ|PROT_WRITE|PROT_EXEC);
|
mprotect(reinterpret_cast<void*>(from), sizeof(shellcode), PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||||
memcpy(reinterpret_cast<void*>(from), shellcode, sizeof(shellcode));
|
memcpy(reinterpret_cast<void*>(from), shellcode, sizeof(shellcode));
|
||||||
mprotect(reinterpret_cast<void*>(from), sizeof(shellcode), PROT_READ|PROT_EXEC);
|
mprotect(reinterpret_cast<void*>(from), sizeof(shellcode), PROT_READ|PROT_EXEC);
|
||||||
|
|
||||||
|
return reinterpret_cast<uintptr_t>(trampoline_mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t sig_scan(const uintptr_t start, const uintptr_t end, std::string_view pattern)
|
std::optional<uintptr_t> sig_scan(const uintptr_t start, const uintptr_t end, std::string_view pattern)
|
||||||
{
|
{
|
||||||
constexpr const uint16_t WILDCARD = 0xFFFF;
|
constexpr const uint16_t WILDCARD = 0xFFFF;
|
||||||
std::vector<uint16_t> pattern_vec;
|
std::vector<uint16_t> pattern_vec;
|
||||||
@ -95,7 +330,7 @@ uintptr_t sig_scan(const uintptr_t start, const uintptr_t end, std::string_view
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t follow_call_rel32(const uintptr_t address)
|
uintptr_t follow_call_rel32(const uintptr_t address)
|
||||||
@ -103,30 +338,65 @@ uintptr_t follow_call_rel32(const uintptr_t address)
|
|||||||
return address + 5 + *reinterpret_cast<uint32_t*>(address + 1);
|
return address + 5 + *reinterpret_cast<uint32_t*>(address + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t hook_is_feature_available([[maybe_unused]] uintptr_t user, [[maybe_unused]] const char* feature)
|
bool process_feature(const char* guid)
|
||||||
{
|
{
|
||||||
// `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?
|
if(g_features.contains(guid))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t hook_is_feature_available(uintptr_t user, const char* feature)
|
||||||
|
{
|
||||||
|
if(process_feature(feature))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _is_feature_available(user, feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t* hook_map_find(uintptr_t* rcx, const char** str)
|
||||||
|
{
|
||||||
|
if(str != nullptr && process_feature(*str))
|
||||||
|
{
|
||||||
|
static uint64_t FAKE_PTR = 0;
|
||||||
|
|
||||||
|
return &FAKE_PTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _map_find(rcx, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hook()
|
void hook()
|
||||||
{
|
{
|
||||||
uintptr_t dottext_start;
|
auto info = get_dottext_info();
|
||||||
uintptr_t dottext_end;
|
|
||||||
|
|
||||||
if(!get_dottext_info(dottext_start, dottext_end))
|
if(!info)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto _is_feature_available_ref = sig_scan(dottext_start, dottext_end, "E8 ? ? ? ? 86 43");
|
const auto start = std::get<0>(info.value());
|
||||||
|
const auto end = std::get<1>(info.value());
|
||||||
|
|
||||||
if(_is_feature_available_ref == 0)
|
if(const auto is_feature_available_ref = sig_scan(start, end, "E8 ? ? ? ? 86 43"); is_feature_available_ref)
|
||||||
{
|
{
|
||||||
return;
|
const auto is_feature_available = follow_call_rel32(is_feature_available_ref.value());
|
||||||
|
|
||||||
|
if(auto trampoline = create_hook(is_feature_available, reinterpret_cast<uintptr_t>(hook_is_feature_available)); trampoline)
|
||||||
|
{
|
||||||
|
_is_feature_available = reinterpret_cast<decltype(_is_feature_available)>(trampoline.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto _is_feature_available = follow_call_rel32(_is_feature_available_ref);
|
if(const auto map_find = sig_scan(start, end, "55 48 89 E5 41 57 41 56 53 48 83 EC ? 49 89 F7 4C 8D 77"); map_find)
|
||||||
write_jmp(_is_feature_available, reinterpret_cast<uintptr_t>(&hook_is_feature_available));
|
{
|
||||||
|
if(auto trampoline = create_hook(map_find.value(), reinterpret_cast<uintptr_t>(hook_map_find)); trampoline)
|
||||||
|
{
|
||||||
|
_map_find = reinterpret_cast<decltype(_map_find)>(trampoline.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
bool get_dottext_info(uintptr_t& start, uintptr_t& end);
|
std::optional<std::tuple<uintptr_t, uintptr_t>> get_dottext_info();
|
||||||
void write_jmp(const uintptr_t from, const uintptr_t to);
|
std::optional<uintptr_t> create_hook(uintptr_t from, uintptr_t to);
|
||||||
uintptr_t sig_scan(const uintptr_t start, const uintptr_t end, std::string_view pattern);
|
std::optional<uintptr_t> sig_scan(const uintptr_t start, const uintptr_t end, std::string_view pattern);
|
||||||
uintptr_t follow_call_rel32(const uintptr_t address);
|
uintptr_t follow_call_rel32(const uintptr_t address);
|
||||||
uint64_t hook_is_feature_available(uintptr_t user, const char* feature);
|
uint64_t hook_is_feature_available(uintptr_t rcx, const char* guid);
|
||||||
|
uint64_t* hook_map_find(uintptr_t* rcx, const char** str);
|
||||||
void hook();
|
void hook();
|
||||||
|
@ -3,4 +3,4 @@
|
|||||||
__attribute__((constructor)) void init_so()
|
__attribute__((constructor)) void init_so()
|
||||||
{
|
{
|
||||||
hook();
|
hook();
|
||||||
}
|
}
|
||||||
|
377
windows/hook.cpp
377
windows/hook.cpp
@ -7,57 +7,278 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <intrin.h>
|
||||||
|
#include "safetyhook.hpp"
|
||||||
|
|
||||||
uintptr_t _is_feature_available;
|
#if _DEBUG
|
||||||
|
#include <regex>
|
||||||
|
#include <print>
|
||||||
|
#endif
|
||||||
|
|
||||||
bool get_section_info(std::string_view name, uintptr_t& start, uintptr_t& end)
|
std::unordered_map<std::string, std::string> g_features =
|
||||||
|
{
|
||||||
|
// Available with Plex Pass
|
||||||
|
{ "c9d9b7ee-fdd9-474e-b143-5039c04e9b9b", "guided-upgrade" },
|
||||||
|
{ "9e93f8a8-7ccd-4d15-99fa-76a158027660", "increase-password-complexity" },
|
||||||
|
{ "547514ab-3284-46e5-af77-bbaff247e3fc", "upgrade-3ds2" },
|
||||||
|
{ "3ae06d3a-a76b-435e-8cef-2d2008610ba2", "ad-countdown-timer" },
|
||||||
|
{ "abd37b14-706c-461f-8255-fa9563882af3", "adaptive_bitrate" },
|
||||||
|
{ "d1477307-4dac-4e57-9258-252e5b908693", "amazon-loop-debug" },
|
||||||
|
{ "b227c158-e062-4ff1-95d8-8ed11cecafb1", "Android - Dolby Vision" },
|
||||||
|
{ "86da2200-58db-4d78-ba46-f146ba25906b", "Android - PiP" },
|
||||||
|
{ "2797e341-b062-46ed-862f-0acbba5dd522", "artist-tv" },
|
||||||
|
{ "c987122a-a796-432f-af00-953821c127bb", "avod-ad-analysis" },
|
||||||
|
{ "e703655b-ee05-4e24-97e3-a138da62c425", "avod-new-media" },
|
||||||
|
{ "bec2ba97-4b25-472b-9cfc-674f5c68c2ae", "blacklist_get_signin" },
|
||||||
|
{ "b3b87f19-5ccd-4b14-bb62-b9d7b982392e", "blacklist-subnets" },
|
||||||
|
{ "6aaaf4fc-c55f-4042-92c8-b35f7886d249", "bypass-web-navbar-upsell-modal" },
|
||||||
|
{ "fb34e64d-cd89-47b8-8bae-a6d20c542bae", "camera_upload" },
|
||||||
|
{ "567033ef-ffee-44fb-8f90-f678077445f9", "CU Sunset" },
|
||||||
|
{ "58829fc9-26b8-41f4-a6c0-90ea7a11ae24", "chromecast-music-mp" },
|
||||||
|
{ "6ab6677b-ad9b-444f-9ca1-b8027d05b3e1", "client-non-destructive-comskip" },
|
||||||
|
{ "5b6190a9-77a4-477e-9fbc-c8118e35a4c1", "client-radio-stations" },
|
||||||
|
{ "65152b75-13a9-408a-bd30-dbd23a259183", "cloudsync" },
|
||||||
|
{ "c4704b28-4e26-460a-bf2e-2576d0c2cb77", "community-new-user-onboarding" },
|
||||||
|
{ "7bb1ed71-a0a3-4362-aa08-7c3fa7241578", "community-friendships-management" },
|
||||||
|
{ "fc3e8322-5e6e-4f4a-9d71-728c6d5656bd", "community-phase0" },
|
||||||
|
{ "a852775a-2b74-4624-aaa3-3d624471a537", "community-phase0-web" },
|
||||||
|
{ "6272ad55-9fc0-43c6-8e1a-3f0df7a3630e", "community-p1" },
|
||||||
|
{ "31fcbe1f-0459-42cb-a15f-5084f62374d9", "community-p2-r1" },
|
||||||
|
{ "06798ab7-4fa5-4416-9db3-f313c4292f01", "community-p2-r2" },
|
||||||
|
{ "626004b8-a8b8-4fb1-9adc-8a6277f98597", "community-p2-r3" },
|
||||||
|
{ "8f47a689-aa84-408f-bf6b-00015e9413e1", "community-p2-r4" },
|
||||||
|
{ "7f46bf17-fabf-4f96-99a2-cf374f6eed71", "comments_and_replies_push_notifications" },
|
||||||
|
{ "c36a6985-eee3-4400-a394-c5787fad15b5", "friend_request_push_notifications" },
|
||||||
|
{ "3f6baa76-7488-479a-9e4f-49ff2c0d3711", "community_access_plex_tv" },
|
||||||
|
{ "24b4cf36-b296-4002-86b7-f1adb657e76a", "companions_sonos" },
|
||||||
|
{ "32cc8bf5-b425-4582-a52d-71b4f1cf436b", "content_filter" },
|
||||||
|
{ "f6a0e423-1a83-418c-8448-a1c7105fd71a", "create_anonymous_users" },
|
||||||
|
{ "926bc176-58ca-47da-b8e3-080ed14ea6ba", "credits-markers" },
|
||||||
|
{ "849433b0-ef60-4a71-9dd9-939bc01f5362", "custom-home-removal" },
|
||||||
|
{ "7ee1495c-2798-4288-94e2-9cd98e67d441", "grandfather-sync" },
|
||||||
|
{ "d29f0ee0-3d3a-46c3-b582-4bc69bc17c29", "disable_home_user_friendships" },
|
||||||
|
{ "ce8f644e-87ce-4ba5-b165-fadd69778019", "disable_sharing_friendships" },
|
||||||
|
{ "6225c337-cd26-4ff0-b864-6c6dd84c9e0d", "disco-reported-issues" },
|
||||||
|
{ "d865f64a-ca06-472d-ae01-7a444aba6251", "disco-director-cast-crew-updates" },
|
||||||
|
{ "2131d3dc-56c8-45d0-acec-c4683fd9a027", "discover-genre-browsing" },
|
||||||
|
{ "cb0e4c75-b1cb-43e9-97ea-6b9bc66c717b", "discover-managed-related-vod" },
|
||||||
|
{ "807d9881-a846-40c3-8d54-84fc490b7ba9", "discover-managed-user-test" },
|
||||||
|
{ "ba7c4a4f-a13b-4ec0-8eb2-cd0ba2fe77f8", "discover-services-hub" },
|
||||||
|
{ "67c80530-eae3-4500-a9fa-9b6947d0f6d1", "Sync v3" },
|
||||||
|
{ "3bfd3ccf-8c63-4dbb-8f87-9b21b402c82b", "downloads-gating" },
|
||||||
|
{ "34e182bd-2f62-4678-a9e9-d13b3e25019d", "drm_support" },
|
||||||
|
{ "e8230c74-0940-4b91-9e20-6571eb068086", "dvr" },
|
||||||
|
{ "c92d4903-bc06-4715-8ce4-4a22674abac8", "dvr-block-unsupported-countries" },
|
||||||
|
{ "af291e9e-813f-4467-8779-5d215abc3b5f", "le_isrg_root_x1" },
|
||||||
|
{ "9c982beb-c676-4d6f-a777-ff5d37ec3081", "epg-recent-channels" },
|
||||||
|
{ "5d819d02-5d04-4116-8eec-f49def4e2d6f", "federated-auth" },
|
||||||
|
{ "4742780c-af9d-4b44-bf5b-7b27e3369aa8", "global-continue-watching" },
|
||||||
|
{ "84a754b0-d1ca-4433-af2d-c949bf4b4936", "hwtranscode" },
|
||||||
|
{ "bc8d1fca-deb0-4d0a-a6f4-12cfd681002d", "hardware_transcoding" },
|
||||||
|
{ "b2403ac6-4885-4971-8b96-59353fd87c72", "home" },
|
||||||
|
{ "f1ac7a53-c524-4311-9a27-713562fc24fa", "HRK_enable_EUR" },
|
||||||
|
{ "c6ce2260-a19d-4fea-9f74-a52231f03924", "hybrid-guide" },
|
||||||
|
{ "55b9f6ed-5d26-4d2d-a436-68882a9901b5", "imagga-v2" },
|
||||||
|
{ "b83c8dc9-5a01-4b7a-a7c9-5870c8a6e21b", "intro-markers" },
|
||||||
|
{ "39dbdd84-8339-4736-96a1-0eb105cc2e08", "ios14-privacy-banner" },
|
||||||
|
{ "b58d7f28-7b4a-49bb-97a7-152645505f28", "item_clusters" },
|
||||||
|
{ "81c8d5fa-8d90-4833-aa10-a31a51310e2f", "iterable-notification-tokens" },
|
||||||
|
{ "e4a9fd6f-4105-476b-bc57-adccd009323b", "keep-payment-method" },
|
||||||
|
{ "c7ae6f8f-05e6-48bb-9024-c05c1dc3c43e", "kevin-bacon" },
|
||||||
|
{ "cb151c05-1943-408a-b37c-06f7d409d6bb", "korea-consent" },
|
||||||
|
{ "8536058d-e1dd-4ae7-b30f-e8b059b7cc17", "lets_encrypt" },
|
||||||
|
{ "6b85840c-d79d-40c2-8d8f-dfc0b7d26776", "lightning-dvr-pivot" },
|
||||||
|
{ "65685ff8-4375-4e4c-a806-ec1f0b4a8b7f", "livetv" },
|
||||||
|
{ "de789b83-9c5e-4472-bccf-791c69e67500", "livetv-platform-specific" },
|
||||||
|
{ "d8810b38-ec9b-494c-8555-3df6e365dfbd", "allow_dvr" },
|
||||||
|
{ "9eaa5152-320b-48e6-9d47-9492ba5e5b54", "live-tv-channels-grid" },
|
||||||
|
{ "d1b1e233-a891-45e5-935c-6114e905dbe8", "live-tv-grid-pagination" },
|
||||||
|
{ "dab501df-5d99-48ef-afc2-3e839e4ddc9a", "live-tv-support-incomplete-segments" },
|
||||||
|
{ "4b522f91-ae89-4f62-af9c-76f44d8ef61c", "tuner-sharing" },
|
||||||
|
{ "0b8bf267-1acf-4f89-99eb-4afbb9d250e5", "live-tv-on-plex-subtitles" },
|
||||||
|
{ "002c9f1a-2fc0-4812-b85b-0e6140f21a0f", "lyrics" },
|
||||||
|
{ "7ab197ee-1bd6-4335-8f55-db827f0110ba", "media-access-split-2" },
|
||||||
|
{ "4a933f24-464d-4a6b-b372-9e4497abd361", "discover" },
|
||||||
|
{ "dbab9396-78ff-48f5-a5ce-c76539ed1b6e", "cloud-livetv" },
|
||||||
|
{ "22b27e12-472e-4383-92ea-2ec3976d8e72", "metadata_search" },
|
||||||
|
{ "f8ea4f37-c554-476a-8852-1cbd2912f3f6", "metadata" },
|
||||||
|
{ "8e8dd5c8-14a4-4208-97d4-623e09191774", "music_preview" },
|
||||||
|
{ "e7cea823-02e5-48c4-a501-d37b82bf132f", "music" },
|
||||||
|
{ "1841971c-6be5-40e6-a211-7e189d767a78", "podcasts" },
|
||||||
|
{ "68747f3a-ce13-46ce-9274-1e0544c9f500", "vod_cloudflare" },
|
||||||
|
{ "ed374ad1-1d36-4396-8794-f710011e4fed", "vod_subtitles" },
|
||||||
|
{ "50a1cfe9-dac1-4722-aee8-cc22e9758dd6", "tunefind-vod" },
|
||||||
|
{ "cc9bea3b-11ab-4402-a222-4958bb129cab", "vod" },
|
||||||
|
{ "55e1398c-930f-41c1-bead-f5c2e471bb25", "webshows" },
|
||||||
|
{ "1844737f-1a87-45c3-ab20-01435959e63c", "music_videos" },
|
||||||
|
{ "de65add8-2782-4bb8-b156-e0b57a844479", "new_plex_pass_prices" },
|
||||||
|
{ "b77e6744-c18d-415a-8e7c-7aac5d7a7750", "news-provider-sunset-modal" },
|
||||||
|
{ "0de6151c-e0dd-47c8-a81e-1acb977c7f0f", "nominatim" },
|
||||||
|
{ "3dd35df0-3e4a-4e74-9ba8-2baeda83a733", "nonAnonymousAccount" },
|
||||||
|
{ "5dc82bc9-6038-4c21-b752-bc3454773eda", "onboarding-community" },
|
||||||
|
{ "73d0bba4-a6ba-4114-bac3-3039c12e08fb", "parental-controls" },
|
||||||
|
{ "82999dd3-a2be-482e-9f44-357879b4f603", "pass" },
|
||||||
|
{ "f4fe27db-7292-4e13-98b6-f3ff9b5ed5fe", "people-pages" },
|
||||||
|
{ "652968f4-d474-4e04-a1cf-2dd1eaeb488a", "people-pages-pms" },
|
||||||
|
{ "96cac76e-c5bc-4596-87eb-4fdfef9aaa11", "photos-favorites" },
|
||||||
|
{ "2ea0e464-ea4f-4be2-97c1-ce6ed4b377dd", "photos-metadata-edition" },
|
||||||
|
{ "850f3d1e-3f38-44c1-9c0c-e3c9127b8b5a", "photosV6-edit" },
|
||||||
|
{ "3a2b0cb6-1519-4431-98e2-823c248c70eb", "photosV6-tv-albums" },
|
||||||
|
{ "02da2909-ddfd-46be-9e42-65008a79fc05", "played_badges" },
|
||||||
|
{ "9aea4ca5-2095-4619-9339-88c1e662fde6", "pms_health" },
|
||||||
|
{ "222020fb-1504-492d-af33-a0b80a49558a", "premium-dashboard" },
|
||||||
|
{ "d413fb56-de7b-40e4-acd0-f3dbb7c9e104", "premium_music_metadata" },
|
||||||
|
{ "a0a78867-6b26-446f-9c3f-df4edf831259", "promoted-grid-channel-filters" },
|
||||||
|
{ "3eb2789b-200c-4a15-91d2-dedfe560953c", "rate-limit-client-token" },
|
||||||
|
{ "64adaa4e-aa7e-457d-b385-51438216d7fe", "shared_server_notification" },
|
||||||
|
{ "6c4d66d9-729d-49dc-b70d-ab2652abf15a", "shared_source_notification" },
|
||||||
|
{ "0cce52a7-0778-4781-9a07-712370fb6b8a", "require-plex-nonce" },
|
||||||
|
{ "644c4466-05fa-45e0-a478-c594cf81778f", "save-to-library" },
|
||||||
|
{ "ccef9d3a-537a-43d9-8161-4c7113c6e2bb", "scrobbling-service" },
|
||||||
|
{ "7b392594-6949-4736-9894-e57a9dfe4037", "scrobbling-service-plex-tv" },
|
||||||
|
{ "1df3cd16-faf2-4d37-8349-1fcf3713bf1d", "album-types" },
|
||||||
|
{ "1417df52-986e-4e4b-8dcd-3997fbc5c976", "collections" },
|
||||||
|
{ "8fd37970-6e4e-4f00-a64a-e70b52f18e94", "music-analysis" },
|
||||||
|
{ "300231e0-69aa-4dce-97f4-52d8c00e3e8c", "radio" },
|
||||||
|
{ "05690239-443e-43fb-bc1a-95b5d916ca63", "session_bandwidth_restrictions" },
|
||||||
|
{ "4ca03b04-54c1-4f9f-aea2-f813ae48f317", "session_kick" },
|
||||||
|
{ "6d7be725-9a96-42c7-8af4-01e735138822", "exclude restrictions" },
|
||||||
|
{ "1b3a63e4-c2f4-4011-a181-2343d3a97ef7", "signin_notification" },
|
||||||
|
{ "b5874ecb-6610-47b2-8906-1b5a897acb02", "signin_with_apple" },
|
||||||
|
{ "62b1e357-5450-41d8-9b60-c7705f750849", "singleitemsharing" },
|
||||||
|
{ "c5adf9dc-af13-4a85-a24b-98de6fa2f595", "sleep-timer" },
|
||||||
|
{ "8a9471c4-13bd-435a-b5b8-4ca6e423f355", "sonos-client-feature" },
|
||||||
|
{ "579156cf-0664-45b4-8b7b-dda400ac3e26", "spotlight-style-hub" },
|
||||||
|
{ "fec722a0-a6d4-4fbd-96dc-4ffb02b072c5", "spring_serve_ad_provider" },
|
||||||
|
{ "bb50c92f-b412-44fe-8d8a-b1684f212a44", "Subtitles on Demand" },
|
||||||
|
{ "9dc1df45-fb45-4be1-9ab2-eb23eb57f082", "sync" },
|
||||||
|
{ "6380e085-02fe-43b5-8bff-380fa4f2423c", "trailers" },
|
||||||
|
{ "a3d2d5c4-46a0-436e-a2d6-80d26f32b369", "transcoder_cache" },
|
||||||
|
{ "c2409baa-d044-45c7-b1f4-e9e7ccd2d128", "boost-voices" },
|
||||||
|
{ "85ebfb7b-77fb-4afd-bb1a-2fe2fefdddbe", "TREBLE-show-features" },
|
||||||
|
{ "a6e0a154-4735-4cbb-a6ec-7a0a146c8216", "silence-removal" },
|
||||||
|
{ "95149521-f64b-46ea-825c-9114e56afd2c", "sweet-fades" },
|
||||||
|
{ "1dd846ed-7cde-4dc5-8ef6-53d3ce8c4e9d", "visualizers" },
|
||||||
|
{ "bbf73498-4912-4d80-9560-47c4fe212cec", "volume-leveling" },
|
||||||
|
{ "07f804e6-28e6-4beb-b5c3-f2aefc88b938", "tunefind-clients" },
|
||||||
|
{ "5d80b92d-4ecf-4b0b-935f-5efc907bb2c1", "tvod_playback" },
|
||||||
|
{ "06d14b9e-2af8-4c2b-a4a1-ea9d5c515824", "two-factor-authentication" },
|
||||||
|
{ "20824f5c-6dd9-4655-9970-e7701a73c02a", "two-factor-authentication-clients" },
|
||||||
|
{ "d14556be-ae6d-4407-89d0-b83953f4789a", "type-first" },
|
||||||
|
{ "cec2152f-321a-4c24-8c6d-c2b35a624389", "ultrablur" },
|
||||||
|
{ "8b46de05-1f96-4278-87b3-010ba5b1e386", "universal-search" },
|
||||||
|
{ "cce9af5d-7b44-4119-a6b1-108fd0db725c", "universal-search-live-tv" },
|
||||||
|
{ "b6b68f84-5127-4dc9-8a7e-3a04419b5cd4", "universal-search-new-quick-search" },
|
||||||
|
{ "d9528436-ee7c-42e3-ab7b-814f85ef74b4", "universal-watchlist" },
|
||||||
|
{ "b46d16ae-cbd6-4226-8ee9-ab2b27e5dd42", "unsupportedtuners" },
|
||||||
|
{ "096ab4b8-04d2-41f4-9602-f1d5b9e8c7cc", "users-and-sharing" },
|
||||||
|
{ "1b870b8e-f1a7-497c-80b2-857d45f3123f", "vod-schema" },
|
||||||
|
{ "65faa2d0-f57e-4c63-a6b6-f1baa48951b1", "watch-together-20200520" },
|
||||||
|
{ "f83450e2-759a-4de4-8b31-e4a163896d43", "watch-together-invite" },
|
||||||
|
{ "f0c452ce-11e7-465f-be04-5fb0bf4bec48", "watchlist" },
|
||||||
|
{ "edd6039a-137c-4ace-b5d5-4e111ce9690b", "watchlist-source" },
|
||||||
|
{ "f0f40559-a43a-4b8f-85ef-bdb1de1a912a", "watchlist-rss" },
|
||||||
|
{ "b737075d-a6c5-4e8a-8ee9-7dc72d984062", "web-desktop-live-tv-chromecast-remote-player" },
|
||||||
|
{ "f8484f94-92a8-4ca4-9f43-e83ab3f586c7", "web-desktop-v4-dvr-setup" },
|
||||||
|
{ "29bca3b8-e40b-4c69-b71c-f88047240f9b", "web-desktop-v4-home" },
|
||||||
|
{ "591895c1-8c60-4eab-8096-3594bb190257", "web-desktop-v4-pre-plays" },
|
||||||
|
{ "740a75d2-6dba-4317-ba68-ed3d619d4c7a", "web-log-viewer" },
|
||||||
|
{ "5e2a89ec-fb26-4234-b66e-14d37f35dff2", "web_server_dashboard" },
|
||||||
|
{ "73c73f05-7131-41cd-86d7-b91301684bfe", "web-share-v2" },
|
||||||
|
{ "6f82ca43-6117-4e55-ae0e-5ea3b3e99a96", "webhooks" },
|
||||||
|
{ "e4f02866-841f-4ceb-a30c-0a0e68fb874d", "where-to-watch-clients" },
|
||||||
|
|
||||||
|
// Dev/Ninja features
|
||||||
|
{ "044a1fac-6b55-47d0-9933-25a035709432", "transcode-offline" },
|
||||||
|
{ "0e2acda2-d70d-4df6-96e0-f63cf264d217", "transcode-hevc" },
|
||||||
|
{ "fd6683b9-1426-4b00-840f-cd5fb0904a6a", "transcode-tonemapping" },
|
||||||
|
{ "fef9b829-af7e-430c-a757-d80de818f211", "music-analysis" },
|
||||||
|
{ "ea442c16-044a-4fa7-8461-62643f313c62", "thetvdb_v4_plugin" },
|
||||||
|
{ "0eee866d-782b-4dfd-b42b-3bbe8eb0af16", "server-manager" },
|
||||||
|
{ "0a348865-4f87-46dc-8bb2-f37637975724", "photos-v5" },
|
||||||
|
{ "59127bcf-acc8-4e97-ad88-8ba6380880b9", "pro_install" },
|
||||||
|
{ "c55d5900-b546-416d-a8c5-45b24a13e9bc", "download_certificates" },
|
||||||
|
{ "3d572099-e243-49bb-9f94-17de7703f9f9", "advanced-playback-settings" },
|
||||||
|
{ "99d17487-7106-4d42-a3b1-c92f68b73165", "news" },
|
||||||
|
{ "e4532fb1-b2e8-4269-9225-b804657cb3ba", "roku-dogfood" },
|
||||||
|
{ "a19d495a-1cef-4f7c-ab77-5186e63e17f7", "loudness" },
|
||||||
|
{ "4866e9e9-ad14-4c2b-bd92-49576f320fd7", "ump-matching-pref" },
|
||||||
|
{ "d20f9af2-fdb1-4927-99eb-a2eb8fbff799", "shared-radio" },
|
||||||
|
{ "c43d8d0f-7aa3-4fef-b9ad-4902580c90ce", "incremental-epg" },
|
||||||
|
{ "075954ad-56ef-4f5e-9519-9cfb0ed05827", "categories" },
|
||||||
|
{ "88aba3a3-bd62-42a5-91bb-0558a4c1db57", "collections-custom-sorting" },
|
||||||
|
{ "e954ef21-08b4-411e-a1f0-7551f1e57b11", "push-notification" },
|
||||||
|
{ "cd0ef747-af8a-414b-9d3a-dd02b6454db9", "voice-activity-generation" },
|
||||||
|
{ "ba8459cd-81fe-4799-93e2-84358717bfb4", "augmentation-provider-environment" },
|
||||||
|
{ "16abced2-1e64-4f01-b64f-f8ef41b1ea6c", "plex-online-environment" },
|
||||||
|
{ "a6f3f9b3-c10c-4b94-ad59-755e30ac6c90", "detect-commercials" },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add above if you want to test :-)
|
||||||
|
std::unordered_set<std::string> g_ignored_guids
|
||||||
|
{
|
||||||
|
"a0220fbb-3a79-4041-8642-add6abf70eb5", // Unknown
|
||||||
|
"d0e6c27c-e25a-4d5f-a7cb-5c1d230c9e9e", // Unknown
|
||||||
|
"ed551997-3bf2-4132-a4fb-eb793a3cf032", // Unknown
|
||||||
|
"a6576713-876c-4e96-9de7-59e9c95563be", // Unknown
|
||||||
|
"2de092ec-e019-421a-97ec-537c7312708e", // Activity related
|
||||||
|
"6fde31f9-f70f-468c-b16c-4e20d7798213", // Activity related
|
||||||
|
"5fead2a7-48b1-41a7-89bd-f95187220266", // Activity related
|
||||||
|
"48703e43-7959-46e3-8c7f-109ba7064f2f", // Activity related
|
||||||
|
"a76ae470-6f57-4ca4-abc1-9cbc28f85368", // Activity related
|
||||||
|
"7ea6d1f4-b55b-466f-8a11-49fb79599d92", // Activity related
|
||||||
|
"818630cb-f618-4285-a83b-d3645065b7e2", // Activity related
|
||||||
|
"a070229b-2aa9-409c-9e97-1e1731b4440e", // Activity related
|
||||||
|
"c8849883-6d7b-4f02-b791-23b8f189ff36", // Activity related
|
||||||
|
"61a68306-7838-468e-97e3-2a8e0a602477", // Activity related
|
||||||
|
"04d7d794-b76c-49ef-9184-52f8f1f501ee", // indirectMedia
|
||||||
|
"93bf35b9-3b62-4a8a-b09b-5c85437fa67b", // "Curated hubs"
|
||||||
|
"e6eda780-8db7-4114-8179-2f581207d58f", // "ButlerTaskUpgradeDatabase"
|
||||||
|
"a548af72-b804-4d05-8569-52785952d31d", // Unknown, used in LibraryRequestHandler
|
||||||
|
};
|
||||||
|
|
||||||
|
SafetyHookInline _is_feature_available{};
|
||||||
|
SafetyHookInline _map_find{};
|
||||||
|
SafetyHookInline _feature_manager_init{};
|
||||||
|
auto _feature_manager = reinterpret_cast<FeatureManager*>(0);
|
||||||
|
|
||||||
|
uintptr_t get_current_process_handle()
|
||||||
{
|
{
|
||||||
char filename[MAX_PATH];
|
char filename[MAX_PATH];
|
||||||
GetModuleFileNameA(NULL, filename, sizeof(filename));
|
GetModuleFileNameA(NULL, filename, sizeof(filename));
|
||||||
|
|
||||||
const auto cur_handle = GetModuleHandleA(filename);
|
return reinterpret_cast<uintptr_t>(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);
|
|
||||||
|
|
||||||
|
std::optional<std::tuple<uintptr_t, uintptr_t>> get_section_info(std::string_view name)
|
||||||
|
{
|
||||||
|
const auto cur_handle = get_current_process_handle();
|
||||||
|
IMAGE_NT_HEADERS* nt_hdr = ImageNtHeader(reinterpret_cast<void*>(cur_handle));
|
||||||
|
IMAGE_SECTION_HEADER* section_hdr = reinterpret_cast<IMAGE_SECTION_HEADER*>(nt_hdr + 1);
|
||||||
|
|
||||||
for(int i = 0; i < nt_hdr->FileHeader.NumberOfSections; i++, section_hdr++)
|
for(int i = 0; i < nt_hdr->FileHeader.NumberOfSections; i++, section_hdr++)
|
||||||
{
|
{
|
||||||
const auto section_header_name = reinterpret_cast<char*>(section_hdr->Name);
|
const auto section_header_name = reinterpret_cast<char*>(section_hdr->Name);
|
||||||
|
|
||||||
if(name == section_header_name)
|
if(name == section_header_name)
|
||||||
{
|
{
|
||||||
const uintptr_t base_module = image_base + section_hdr->VirtualAddress;
|
const auto base_module = cur_handle + section_hdr->VirtualAddress;
|
||||||
start = base_module;
|
const auto end = base_module + section_hdr->Misc.VirtualSize - 1;
|
||||||
end = base_module + section_hdr->Misc.VirtualSize - 1;
|
|
||||||
|
return std::make_tuple(base_module, end);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_jmp(const uintptr_t from, const uintptr_t to)
|
std::optional<uintptr_t> sig_scan(const uintptr_t start, const uintptr_t end, std::string_view pattern)
|
||||||
{
|
|
||||||
uint8_t shellcode[] =
|
|
||||||
{
|
|
||||||
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp [rip+0x06]
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ?
|
|
||||||
};
|
|
||||||
|
|
||||||
*reinterpret_cast<uintptr_t*>(&shellcode[6]) = to;
|
|
||||||
|
|
||||||
DWORD old_prot;
|
|
||||||
VirtualProtect(reinterpret_cast<void*>(from), sizeof(shellcode), PAGE_EXECUTE_READWRITE, &old_prot);
|
|
||||||
memcpy(reinterpret_cast<void*>(from), shellcode, sizeof(shellcode));
|
|
||||||
VirtualProtect(reinterpret_cast<void*>(from), sizeof(shellcode), old_prot, &old_prot);
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t sig_scan(const uintptr_t start, const uintptr_t end, std::string_view pattern)
|
|
||||||
{
|
{
|
||||||
constexpr const uint16_t WILDCARD = 0xFFFF;
|
constexpr const uint16_t WILDCARD = 0xFFFF;
|
||||||
std::vector<uint16_t> pattern_vec;
|
std::vector<uint16_t> pattern_vec;
|
||||||
|
|
||||||
for(uintptr_t i = 0; i < pattern.length(); i++)
|
for(uintptr_t i = 0; i < pattern.length(); i++)
|
||||||
{
|
{
|
||||||
if(pattern[i] == ' ')
|
if(pattern[i] == ' ')
|
||||||
@ -83,7 +304,7 @@ uintptr_t sig_scan(const uintptr_t start, const uintptr_t end, std::string_view
|
|||||||
|
|
||||||
uintptr_t end_address = start;
|
uintptr_t end_address = start;
|
||||||
MEMORY_BASIC_INFORMATION mbi{};
|
MEMORY_BASIC_INFORMATION mbi{};
|
||||||
|
|
||||||
while(end_address < end && VirtualQuery(reinterpret_cast<void*>(end_address), &mbi, sizeof(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 ||
|
if((mbi.Protect & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) == 0 ||
|
||||||
@ -119,36 +340,106 @@ uintptr_t sig_scan(const uintptr_t start, const uintptr_t end, std::string_view
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t hook_is_feature_available([[maybe_unused]] uintptr_t user, [[maybe_unused]] const char* feature)
|
bool process_feature(const char* guid, [[maybe_unused]] uintptr_t caller)
|
||||||
{
|
{
|
||||||
// `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?
|
if(g_features.contains(guid))
|
||||||
|
{
|
||||||
|
#if _DEBUG
|
||||||
|
std::println("[plexmediaserver_crack] Spoofing feature: {} ({})", g_features[guid], guid);
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if _DEBUG
|
||||||
|
static const std::regex guid_regex(R"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})");
|
||||||
|
|
||||||
|
if(std::regex_match(guid, guid_regex) && !g_ignored_guids.contains(guid))
|
||||||
|
{
|
||||||
|
std::println("[plexmediaserver_crack] Unknown GUID found: {} | Caller: {:08X}", guid, caller);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t hook_is_feature_available(uintptr_t user, const char* feature)
|
||||||
|
{
|
||||||
|
if(process_feature(feature, reinterpret_cast<uintptr_t>(_ReturnAddress()) - get_current_process_handle()))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _is_feature_available.call<uint64_t>(user, feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t* hook_map_find(uintptr_t* rcx, uintptr_t rdx, const char** str)
|
||||||
|
{
|
||||||
|
if(_feature_manager != nullptr && rcx == &_feature_manager->m_feature_map() &&
|
||||||
|
process_feature(*str, reinterpret_cast<uintptr_t>(_ReturnAddress()) - get_current_process_handle()))
|
||||||
|
{
|
||||||
|
static uint64_t FAKE_PTR = 0;
|
||||||
|
|
||||||
|
return &FAKE_PTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _map_find.call<uint64_t*>(rcx, rdx, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
FeatureManager* hook_feature_manager_init(FeatureManager* rcx)
|
||||||
|
{
|
||||||
|
return _feature_manager = _feature_manager_init.call<FeatureManager*>(rcx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hook()
|
void hook()
|
||||||
{
|
{
|
||||||
uintptr_t dottext_start;
|
#if _DEBUG
|
||||||
uintptr_t dottext_end;
|
AllocConsole();
|
||||||
|
freopen_s(reinterpret_cast<FILE**>(stdout), "CONOUT$", "w", stdout);
|
||||||
|
#endif
|
||||||
|
|
||||||
if(!get_section_info(".text", dottext_start, dottext_end))
|
const auto info = get_section_info(".text");
|
||||||
|
|
||||||
|
if(!info)
|
||||||
{
|
{
|
||||||
std::cerr << "[ERR] [plexmediaserver_crack] .text section not found; aborting.\n";
|
#if _DEBUG
|
||||||
|
std::println("[ERR] [plexmediaserver_crack] .text section not found; aborting.");
|
||||||
|
#endif
|
||||||
|
|
||||||
return;
|
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");
|
const auto start = std::get<0>(info.value());
|
||||||
|
const auto end = std::get<1>(info.value());
|
||||||
|
const auto is_feature_available = sig_scan(start, end, "41 54 41 56 41 57 48 83 EC 20 4C 8B F9 4C 8B F2");
|
||||||
|
const auto map_find = sig_scan(start, end, "48 8B C4 55 41 55");
|
||||||
|
const auto feature_manager_init = sig_scan(start, end, "48 89 5C 24 10 48 89 74 24 18 48 89 7C 24 20 55 41 54 41 55 41 56 41 57 48 8D AC 24 B0 EB");
|
||||||
|
const auto feature_map_offset = sig_scan(start, end, "48 8D 5E ? 48 89 5C 24 20 ? ? ? 4C");
|
||||||
|
|
||||||
if(_is_feature_available == 0)
|
if((!map_find && !is_feature_available) || !feature_manager_init || !feature_map_offset)
|
||||||
{
|
{
|
||||||
std::cerr << "[ERR] [plexmediaserver_crack] Couldn't find is_feature_available; aborting.\n";
|
#if _DEBUG
|
||||||
|
std::println("[ERR] [plexmediaserver_crack] Couldn't find either is_feature_enabled or std::map<std::string, std::vector<float>>::find, FeatureManaget::Init, or the feature map offset; aborting.");
|
||||||
|
#endif
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_jmp(_is_feature_available, reinterpret_cast<uintptr_t>(&hook_is_feature_available));
|
// Pre-patch
|
||||||
|
if(is_feature_available)
|
||||||
|
{
|
||||||
|
_is_feature_available = safetyhook::create_inline(reinterpret_cast<void*>(is_feature_available.value()), reinterpret_cast<void*>(hook_is_feature_available));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post-patch (is_feature_available got inlined); v1.40.3.8555 and newer
|
||||||
|
if(map_find)
|
||||||
|
{
|
||||||
|
_map_find = safetyhook::create_inline(reinterpret_cast<void*>(map_find.value()), reinterpret_cast<void*>(hook_map_find));
|
||||||
|
}
|
||||||
|
|
||||||
|
_feature_manager_init = safetyhook::create_inline(reinterpret_cast<void*>(feature_manager_init.value()), reinterpret_cast<void*>(hook_feature_manager_init));
|
||||||
|
FeatureManager::m_map_offset = *reinterpret_cast<uint8_t*>(feature_map_offset.value() + 3);
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,32 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
bool get_section_info(std::string_view name, uintptr_t& start, uintptr_t& end);
|
#ifndef member_at
|
||||||
void write_jmp(const uintptr_t from, const uintptr_t to);
|
#define member_at(T, offset, name) \
|
||||||
uintptr_t sig_scan(const uintptr_t start, const uintptr_t end, std::string_view pattern);
|
__forceinline auto &name() \
|
||||||
uint64_t hook_is_feature_available(uintptr_t user, const char* feature);
|
{ \
|
||||||
|
return *reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(this) + offset); \
|
||||||
|
} \
|
||||||
|
__forceinline auto &name() const \
|
||||||
|
{ \
|
||||||
|
return *reinterpret_cast<const T *>(reinterpret_cast<uintptr_t>(this) + offset); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class FeatureManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static inline size_t m_map_offset{};
|
||||||
|
member_at(uintptr_t, m_map_offset, m_feature_map);
|
||||||
|
};
|
||||||
|
|
||||||
|
uintptr_t get_current_process_handle();
|
||||||
|
std::optional<std::tuple<uintptr_t, uintptr_t>> get_section_info(std::string_view name);
|
||||||
|
std::optional<uintptr_t> sig_scan(const uintptr_t start, const uintptr_t end, std::string_view pattern);
|
||||||
|
uint64_t hook_is_feature_available(uintptr_t rcx, const char* guid);
|
||||||
|
uint64_t* hook_map_find(uintptr_t* rcx, uintptr_t rdx, const char** str);
|
||||||
|
FeatureManager* hook_feature_manager_init(FeatureManager* rcx);
|
||||||
void hook();
|
void hook();
|
||||||
|
1664
windows/safetyhook.cpp
Normal file
1664
windows/safetyhook.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1062
windows/safetyhook.hpp
Normal file
1062
windows/safetyhook.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -178,10 +178,12 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="dllmain.cpp" />
|
<ClCompile Include="dllmain.cpp" />
|
||||||
<ClCompile Include="hook.cpp" />
|
<ClCompile Include="hook.cpp" />
|
||||||
|
<ClCompile Include="safetyhook.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="hook.hpp" />
|
<ClInclude Include="hook.hpp" />
|
||||||
<ClInclude Include="proxy.hpp" />
|
<ClInclude Include="proxy.hpp" />
|
||||||
|
<ClInclude Include="safetyhook.hpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
@ -21,6 +21,9 @@
|
|||||||
<ClCompile Include="hook.cpp">
|
<ClCompile Include="hook.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="safetyhook.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="hook.hpp">
|
<ClInclude Include="hook.hpp">
|
||||||
@ -29,5 +32,8 @@
|
|||||||
<ClInclude Include="proxy.hpp">
|
<ClInclude Include="proxy.hpp">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="safetyhook.hpp">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
Loading…
x
Reference in New Issue
Block a user