- Smart patterns
- Code improvements
- Crash handling
This commit is contained in:
og 2021-11-28 14:26:47 +10:00
parent d9315980e7
commit 42211ffa48
16 changed files with 159 additions and 61 deletions

@ -4,6 +4,7 @@
#include <Windows.h>
#include <functional>
#define L_ERROR(...) util::logger::error(__FUNCTION__ "(): " __VA_ARGS__);
#define TRACE_FN util::logger::debug( "%s()", __FUNCTION__ );
@ -64,7 +65,9 @@ namespace util {
CREATE_LOGGER_METHOD( error );
inline void fatal( const char* fmt, ... ) {
LOGGER_PARSE_FMT;
MessageBoxA( NULL, buf, "Unspotify", MB_OK );
error( "Fatal error: %s", buf );
MessageBoxA( NULL, buf, "Unspotify fatal error", MB_OK );
ExitProcess( -1 );
}
__forceinline void startup( ) {
@ -76,7 +79,7 @@ namespace util {
__forceinline void detach( ) {
::ShowWindow( ::GetConsoleWindow( ), SW_HIDE );
::FreeConsole( );
::FreeConsole( );
}
}
}

@ -4,25 +4,25 @@
#include "../hooks/hooks.h"
#include "shared/logo.h"
#include <string>
#include <iostream>
#include <thread>
namespace bootstrap {
DWORD __stdcall _initial_routine( HANDLE ) {
util::logo::create_console_and_draw_logo( );
spotify::init( );
hooks::init( );
#ifdef _DEBUG
while ( !GetAsyncKeyState( VK_DELETE ) ) {
#else
util::logger::warn( "press any key to close this console" );
_getwch( );
util::logger::detach( );
#ifndef _DEBUG
for ( ;;) {
#else
while ( !GetAsyncKeyState( VK_DELETE ) ) {
#endif
while ( true ) {
#endif
std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
}

@ -1,5 +1,4 @@
#pragma once
#include <condition_variable>
#include <Windows.h>

@ -1,4 +1,5 @@
#include "bootstrap/bootstrap.h"
#include <cstdint>
BOOL __stdcall DllMain( std::uintptr_t hinstDll, std::uint32_t fdwReason, std::uintptr_t ) {

@ -0,0 +1,21 @@
#include "../hooks.h"
namespace hooks {
namespace hooked {
/*
@xref: " Creating track player for track (playback_id %s)"
*/
void __fastcall create_track(
void* pthis, void* pedx,
spotify::structs::player_meta_t* player_meta,
spotify::structs::player_track_meta_t* track_meta,
int a4, int a5, int a6, int a7, int a8, int a9, int a10
) {
player_meta->m_should_skip = static_cast< std::uint32_t >( static_cast< bool >( strstr( track_meta->m_track_uri, "spotify:ad:" ) ) );
util::logger::info( "Playing %s | should_skip: %s", track_meta->m_track_uri, player_meta->m_should_skip ? "true" : "false" );
original::create_track( pthis, pedx, player_meta, track_meta, a4, a5, 8, a7, a8, a9, a10 );
}
}
}

@ -3,17 +3,17 @@
namespace hooks {
namespace hooked {
#ifdef _DEBUG
std::uintptr_t __cdecl debug_msg( std::uint32_t, std::uint32_t, const char* win, const char* flag, std::uint32_t size, std::uint32_t, const char* fmt, ... ) { // @xref: "Path provided in --%s '%s' (resolved to '%s') does not exist."
#ifdef _DEBUG
LOGGER_PARSE_FMT;
for ( int i = 0; i < strlen( buf ); i++ )
buf[ i ] = buf[ i ] == '\n' ? ' ' : buf[ i ];
printf( "[spotify::debug_msg] %s\n", buf );
#endif
return 0;
}
#endif
}
}

@ -1,16 +1,24 @@
#include "hooks.h"
#include <algorithm>
#define CREATE_HOOK(n) if ( !util::hooking::detour::create(spotify::addr:: ##n, hooked:: ##n, reinterpret_cast< void** > ( &original:: ##n ) ) ) util::logger::fatal("Unable to hook %s", #n);
namespace hooks {
void init( ) {
util::hooking::detour::init( );
util::hooking::detour::create( spotify::addr::debug_msg, hooked::debug_msg, reinterpret_cast< void** >( &original::debug_msg ) );
util::hooking::detour::create( spotify::addr::get_ad, hooked::get_ad, reinterpret_cast< void** >( &original::get_ad ) );
util::hooking::detour::create( spotify::addr::play_track, hooked::play_track, reinterpret_cast< void** >( &original::play_track ) );
if ( !util::hooking::detour::init( ) )
util::logger::fatal( "Unable to init minhook" );
#ifdef _DEBUG
CREATE_HOOK( debug_msg );
#endif
CREATE_HOOK( get_ad );
CREATE_HOOK( create_track );
}
void shutdown( ) {
util::hooking::detour::remove( );
}
}
}
#undef CREATE_HOOK

@ -5,14 +5,18 @@
namespace hooks {
namespace hooked {
#ifdef _DEBUG
std::uintptr_t __cdecl debug_msg( std::uint32_t, std::uint32_t, const char* win, const char* flag, std::uint32_t size, std::uint32_t, const char* fmt, ... );
#endif
std::uintptr_t __cdecl get_ad( int a1, int a2 );
std::uintptr_t __fastcall play_track( std::uintptr_t pthis, std::uintptr_t pEDX, spotify::structs::player_meta_t* player_meta, spotify::structs::player_track_meta_t* track_meta, char a4, int a5, char a6, int a7, int a8, char a9, char a10, int a11, char a12, int a13 );
void __fastcall create_track( void* pthis, void* pedx, spotify::structs::player_meta_t* player_meta, spotify::structs::player_track_meta_t* track_meta, int a4, int a5, int a6, int a7, int a8, int a9, int a10 );
}
namespace original {
#ifdef _DEBUG
inline decltype( &hooked::debug_msg ) debug_msg;
#endif
inline decltype( &hooked::get_ad ) get_ad;
inline decltype( &hooked::play_track ) play_track;
inline decltype( &hooked::create_track ) create_track;
}
void init( );

@ -179,7 +179,7 @@
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="hooks\hooked\debug_msg.cpp" />
<ClCompile Include="hooks\hooked\get_ad.cpp" />
<ClCompile Include="hooks\hooked\play_track.cpp" />
<ClCompile Include="hooks\hooked\create_track.cpp" />
<ClCompile Include="hooks\hooks.cpp" />
<ClCompile Include="spotify\spotify.cpp" />
<ClCompile Include="util\hooking\detours\detours.cpp" />

@ -57,7 +57,7 @@
<ClCompile Include="hooks\hooked\debug_msg.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hooks\hooked\play_track.cpp">
<ClCompile Include="hooks\hooked\create_track.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>

@ -1,6 +1,10 @@
#include "spotify.h"
#define ASSERT_PATTERN(s) if ( !addr:: ##s .valid( ) ) util::logger::fatal( "Pattern %s not found. Please update your Unspotify version", #s);
#define ASSERT_PATTERN_STEP(s) if ( !s ) util::logger::fatal( "Unable to find %s at %d", #s, __LINE__ )
namespace spotify {
void init( ) {
TRACE_FN;
@ -8,22 +12,65 @@ namespace spotify {
modules::spotify = util::mem::module_t( nullptr );
util::logger::debug( "module::spotify = 0x%p", modules::spotify );
uint32_t str;
util::mem::addr_t sig;
std::vector<int> pattern = {};
#ifdef _DEBUG
// "Could not create stream reader for file: %s"
str = modules::spotify.sig( "43 6F 75 6C 64 20 6E 6F 74 20 63 72 65 61 74 65 20 73 74 72 65 61 6D 20 72 65 61 64 65 72 20 66 6F 72 20 66 69 6C 65 3A 20 25 73" );
ASSERT_PATTERN_STEP( str );
pattern.clear( );
pattern.emplace_back( 0x68 /* push offset */ );
for ( int i = 0; i < 4; i++ )
pattern.emplace_back( ( int )( ( ( uint8_t* )( &str ) )[ i ] ) );
sig = modules::spotify.sig( pattern );
ASSERT_PATTERN_STEP( sig );
addr::debug_msg =
modules::spotify.sig( "6A 24 B8 ? ? ? ? E8 ? ? ? ? 8B 7D 10 33 C0 8B 75 14 89 45 D8 89 45 E8 C7 45 ? ? ? ? ? 88 45 D8 89 45 FC 8D 45 24" );
sig.walk_until( 0x6A /* push 02 */ ).walk_until( 0xE8 /* call */ ).rel( 1 );
util::logger::debug( "addr::debug_msg = 0x%p", addr::debug_msg );
ASSERT_PATTERN( debug_msg );
#endif
addr::get_ad =
modules::spotify.sig( "68 ? ? ? ? B8 ? ? ? ? E8 ? ? ? ? 8B 5D 08 8D 8D ? ? ? ? 8B 7D 0C 53 89 9D ? ? ? ? 89 BD ? ? ? ? E8 ? ? ? ? 83 65 FC 00 8D 47 04 89 85 ? ? ? ?" );
// "ad_type"
str = modules::spotify.sig( "61 64 5F 74 79 70 65 00" );
ASSERT_PATTERN_STEP( str );
pattern.clear( );
for ( int i = 0; i < 4; i++ )
pattern.emplace_back( ( int )( ( ( uint8_t* )( &str ) )[ i ] ) );
sig = modules::spotify.sig( pattern );
ASSERT_PATTERN_STEP( sig );
do {
sig = sig.walk_back_until( 0xC3 /* retn */ );
} while ( sig.offset( -5 ).read<uint8_t>( ) != 0xE8 );
addr::get_ad = sig.add( 1 ).read<uint8_t>( ) == 0x68 /* push */ ? sig.add( 1 ) : sig.walk_until( 0x55 /* push ebp */ );
util::logger::debug( "addr::get_ad = 0x%p", addr::get_ad );
ASSERT_PATTERN( get_ad );
addr::play_track_table_mov =
modules::spotify.sig( "C7 03 ? ? ? ? 89 43 08 89 55 FC 89 11 89 51 04 E8 ? ? ? ? 8B 75 14 8D 7B 14 8B 45 18 8D 4B 28 FF 75 1C " );
util::logger::debug( "addr::play_track_table_mov = 0x%p", addr::play_track_table_mov );
addr::play_track_table = addr::play_track_table_mov.add( 2 ).self_get( );
util::logger::debug( "addr::play_track_table = 0x%p", addr::play_track_table );
addr::play_track_fn_addr = addr::play_track_table.add( 4 );
util::logger::debug( "addr::play_track_fn_addr = 0x%p", addr::play_track_fn_addr );
addr::play_track = addr::play_track_fn_addr.self_get( );
util::logger::debug( "addr::play_track = 0x%p", addr::play_track );
// " Creating track player for track (playback_id %s)"
str = modules::spotify.sig( "20 20 20 20 43 72 65 61 74 69 6E 67 20 74 72 61 63 6B 20 70 6C 61 79 65 72 20 66 6F 72 20 74 72 61 63 6B 20 28 70 6C 61 79 62 61 63 6B 5F 69 64 20 25 73 29" );
ASSERT_PATTERN_STEP( sig );
pattern.clear( );
pattern.emplace_back( 0x68 /* push offset */ );
for ( int i = 0; i < 4; i++ )
pattern.emplace_back( ( int )( ( ( uint8_t* )( &str ) )[ i ] ) );
sig = modules::spotify.sig( pattern );
ASSERT_PATTERN_STEP( sig );
addr::create_track = sig.walk_back_until( 0xC2 /* retn */ ).offset( 3 /* C2 04 00 */ );
while ( addr::create_track.read<uint8_t>( ) == 0xE8 /* call */ )
addr::create_track = addr::create_track.add( 5 ); // E8 + 4 bytes addr
//if ( addr::create_track.read<uint8_t>( ) == 0xCC /* align */ )
// addr::create_track = addr::create_track.walk_until( 0x55 /* push ebp */ );
while ( addr::create_track.read<uint8_t>( ) == 0xCC )
addr::create_track = addr::create_track.add( 1 ); // skip aligns
util::logger::debug( "addr::create_track = 0x%p", addr::create_track );
ASSERT_PATTERN( create_track );
}
}
}
#undef ASSERT_PATTERN
#undef ASSERT_PATTERN_STEP

@ -1,7 +1,7 @@
#pragma once
#include "../util/util.h"
namespace spotify {
namespace structs {
struct player_meta_t {
@ -20,13 +20,11 @@ namespace spotify {
}
namespace addr {
#ifdef _DEBUG
inline util::mem::addr_t debug_msg;
#endif
inline util::mem::addr_t get_ad;
inline util::mem::addr_t play_track;
inline util::mem::addr_t play_track_table_mov;
inline util::mem::addr_t play_track_table;
inline util::mem::addr_t play_track_fn_addr;
inline util::mem::addr_t create_track;
}
void init( );

@ -2,20 +2,16 @@
namespace util::hooking::detour {
void init( ) {
MH_Initialize( );
bool init( ) {
return MH_Initialize( ) == MH_OK;
}
void create( mem::addr_t& target, void* detour, void** orig ) {
return create( target.cast<void*>( ), detour, orig );
bool create( void* target, void* detour, void** orig ) {
return MH_CreateHook( target, detour, orig ) == MH_OK &&
MH_EnableHook( target ) == MH_OK;
}
void create( void* target, void* detour, void** orig ) {
if ( MH_CreateHook( target, detour, orig ) != MH_OK ) __debugbreak( );
if ( MH_EnableHook( target ) != MH_OK ) __debugbreak( );
}
void remove( void* target ) {
if ( MH_DisableHook( target ) != MH_OK ) __debugbreak( );
bool remove( void* target ) {
return MH_DisableHook( target ) == MH_OK;
}
}

@ -5,8 +5,7 @@
namespace util::hooking::detour {
void init( );
void create( mem::addr_t& target, void* detour, void** orig );
void create( void* target, void* detour, void** orig );
void remove( void* target = nullptr /* nullptr = MH_ALL_HOOKS */ );
bool init( );
bool create( void* target, void* detour, void** orig );
bool remove( void* target = nullptr /* nullptr = MH_ALL_HOOKS */ );
}

@ -63,8 +63,8 @@ namespace util::mem {
}
template <typename t = uint32_t>
inline memory_address_t relative_asm_address( ptr_type offset ) {
return this->add( this->add( offset ).read<t>( ) ).add( offset + sizeof( t ) );
inline memory_address_t rel( ptr_type offset ) {
return this->add( this->add( offset ).template read<t>( ) ).add( offset + sizeof( t ) );
}
//
@ -92,7 +92,27 @@ namespace util::mem {
return *this;
}
inline bool valid( ) { return static_cast< bool >( m_ptr ); }
memory_address_t<ptr_type> walk_until( uint8_t byte ) {
constexpr int max_iterations = 1000;
for ( int i = 0; i < max_iterations; i++ ) {
if ( offset( i ).template read<uint8_t>( ) != byte )
continue;
return offset( i );
}
return memory_address_t<ptr_type>( );
}
memory_address_t<ptr_type> walk_back_until( uint8_t byte ) {
constexpr int max_iterations = 1000;
for ( int i = 1; i < max_iterations; i++ ) {
if ( offset( -i ).template read<uint8_t>( ) != byte )
continue;
return offset( -i );
}
return memory_address_t<ptr_type>( );
}
inline bool valid( ) { return static_cast< bool >( m_ptr ) && m_ptr > 15; }
ptr_type raw( ) { return m_ptr; }

@ -26,9 +26,11 @@ namespace util::mem {
// pattern scan related
public:
mem::addr_t sig( std::string_view pattern ) {
unsigned long image_size = get_nt_headers( )->OptionalHeader.SizeOfImage;
return sig( pattern_to_byte( pattern ) );
}
std::vector<int> pattern_bytes = pattern_to_byte( pattern );
mem::addr_t sig( std::vector<int> pattern_bytes ) {
unsigned long image_size = get_nt_headers( )->OptionalHeader.SizeOfImage;
int* pattern_data = pattern_bytes.data( );
size_t pattern_size = pattern_bytes.size( );