v1.0.2
- Smart patterns - Code improvements - Crash handling
This commit is contained in:
parent
d9315980e7
commit
42211ffa48
@ -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 ) {
|
||||
|
21
spotify-reverse/hooks/hooked/create_track.cpp
Normal file
21
spotify-reverse/hooks/hooked/create_track.cpp
Normal file
@ -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( );
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user