Sorely need this feature to work as welljlnsrk wrote: ↑Fri Nov 08, 2019 5:08 pmHello Mirillis Team,
so I have been having an issue with Splash Player for quite some time now. The subtitles of some Anime would not be shown properly. To remedy this I made a plugin for your tool whose effect can be seen in the following attachments.
Before:
After:
I would like to make my tool available to other people in binary form, however I understand that Splash Player is 100% the property of Mirillis and hence I would like to ask your permission before I do this to prevent any kind of issue from occurring from me having done this work.
I am attaching this code in case you guys would like to review it.
Code: Select all
#include <Windows.h> #include <TlHelp32.h> #include <intrin.h> typedef int (__cdecl* Type_InitSubtitleFont)( wchar_t *Str, int, int, int, int, int, int, int, int ); Type_InitSubtitleFont pInitSubtitleFont; int __cdecl hkInitSubtitleFont( wchar_t *Str, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8 ) // D3D12 { int Len = wcslen( Str ); int SkipIndex = 0; for( size_t i = 0, j = 7; i < Len && j > 0; i++ ) { if( Str[i] == ',' ) { if( j < 2 ) { SkipIndex = i + 1; } j--; } } return pInitSubtitleFont( &Str[ SkipIndex ], a1, a2, a3, a4, a5, a6, a7, a8 ); } typedef int( __cdecl* Type_RenderSubtitleLine )( HDC hdc, wchar_t* Str, int a3, int a4, int a5, int a6, int a7, int a8 ); Type_RenderSubtitleLine pRenderSubtitleLine; int __cdecl hkRenderSubtitleLine( HDC hdc, wchar_t* Str, int a3, int a4, int a5, int a6, int a7, int a8 )// GDI { int Len = wcslen( Str ); int SkipIndex = 0; for( size_t i = 0, j = 7; i < Len && j > 0; i++ ) { if( Str[ i ] == ',' ) { if( j < 2 ) { SkipIndex = i + 1; } j--; } } return pRenderSubtitleLine( hdc, &Str[ SkipIndex ], a3, a4, a5, a6, a7, a8 ); } bool bDataCompare( const BYTE* pData, const BYTE* bMask, const char* szMask ) { for( ; *szMask; ++szMask, ++pData, ++bMask ) if( *szMask == 'x' && *pData != *bMask ) return false; return ( *szMask ) == NULL; } DWORD dwFindPattern( DWORD dwAddress, DWORD dwLen, BYTE *bMask, char * szMask ) { for( DWORD i = 0; i < dwLen; i++ ) if( bDataCompare( ( BYTE* ) ( dwAddress + i ), bMask, szMask ) ) return ( DWORD ) ( dwAddress + i ); return NULL; } void *DetourFunc( BYTE *src, const BYTE *dst, const int len ) { BYTE *jmp = ( BYTE* ) VirtualAlloc( nullptr, len + 5, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); DWORD dwback; VirtualProtect( src, len, PAGE_READWRITE, &dwback ); __movsb( jmp, src, len ); jmp += len; jmp[ 0 ] = 0xE9; *( DWORD* ) ( jmp + 1 ) = ( DWORD ) ( src + len - jmp ) - 5; src[ 0 ] = 0xE9; *( DWORD* ) ( src + 1 ) = ( DWORD ) ( dst - src ) - 5; VirtualProtect( src, len, dwback, &dwback ); return ( jmp - len ); } DWORD __stdcall dwThread( void* ) { HMODULE hmModule = GetModuleHandle( nullptr ); IMAGE_DOS_HEADER* pDosHeader = reinterpret_cast< IMAGE_DOS_HEADER* >( hmModule ); if( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE ) { MessageBoxA( 0, "Error 1", nullptr, 0 ); return 0; } IMAGE_NT_HEADERS* pImageNtHeader = reinterpret_cast< IMAGE_NT_HEADERS* >( ( ( DWORD_PTR ) hmModule + pDosHeader->e_lfanew ) ); if( pImageNtHeader->Signature != IMAGE_NT_SIGNATURE ) { MessageBoxA( 0, "Error 2", nullptr, 0 ); return 0; } DWORD dwSize = pImageNtHeader->OptionalHeader.SizeOfCode; DWORD dwStart = ( DWORD ) hmModule + pImageNtHeader->OptionalHeader.BaseOfCode; DWORD dwAddress = dwFindPattern( dwStart, dwSize, ( BYTE* ) "\x57\x56\x55\x53\x81\xEC\x00\x00\x00\x00\x8B\xB4\x24\x00\x00\x00\x00\xBB\x00\x00\x00\x00\x83\xFE\x00\x0F\x44\x9C\x24\x00\x00\x00\x00\x8D\x84\x24\x00\x00\x00\x00\x50", "xxxxxx????xxx????x????xxxxxxx????xxx????x" ); if( !dwAddress ) { MessageBoxA( 0, "Error 3", nullptr, 0 ); return 0; } pInitSubtitleFont = ( Type_InitSubtitleFont ) DetourFunc( ( BYTE* ) dwAddress, ( BYTE* ) hkInitSubtitleFont, 0xA ); if( !pInitSubtitleFont ) { MessageBoxA( 0, "Error 4", nullptr, 0 ); return 0; } // dwAddress = dwFindPattern( dwStart, dwSize, ( BYTE* ) "\x57\x56\x55\x53\x83\xEC\x4C\x8D\x04\x24\x50\xFF\x35\x00\x00\x00\x00", "xxxxxxxxxxxxx????" ); if( !dwAddress ) { MessageBoxA( 0, "Error 5", nullptr, 0 ); return 0; } pRenderSubtitleLine = ( Type_RenderSubtitleLine ) DetourFunc( ( BYTE* ) dwAddress, ( BYTE* ) hkRenderSubtitleLine, 0x7 ); if( !pRenderSubtitleLine ) { MessageBoxA( 0, "Error 6", nullptr, 0 ); return 0; } return 1; } extern "C" BOOL __declspec( dllexport ) __stdcall EnumProcesses( DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded ) { PROCESSENTRY32 pe32; HANDLE hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); if( hProcessSnap == INVALID_HANDLE_VALUE ) return FALSE; pe32.dwSize = sizeof( PROCESSENTRY32 ); DWORD dwNeeded; if( lpcbNeeded == nullptr ) { lpcbNeeded = &dwNeeded; } *lpcbNeeded = 0; if( Process32First( hProcessSnap, &pe32 ) ) { do { if( lpidProcess ) lpidProcess[ *lpcbNeeded ] = pe32.th32ProcessID; *lpcbNeeded++; } while( cb / sizeof( DWORD ) > *lpcbNeeded ); } return *lpcbNeeded > 0; } extern "C" DWORD __declspec( dllexport ) __stdcall GetModuleBaseNameW( HANDLE hProcess, HMODULE hModule, LPWSTR lpBaseName, DWORD nSize ) { MODULEENTRY32 me32; HANDLE hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, GetProcessId( hProcess ) ); if( hProcessSnap == INVALID_HANDLE_VALUE ) return 0; me32.dwSize = sizeof( MODULEENTRY32 ); if( Module32First( hProcessSnap, &me32 ) ) { do { if( me32.hModule == hModule || me32.modBaseAddr == ( BYTE* ) hModule ) { lstrcpyW( lpBaseName, me32.szModule ); } } while( Module32Next( hProcessSnap, &me32 ) ); } return 0; } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: CreateThread( nullptr, 0, reinterpret_cast< LPTHREAD_START_ROUTINE >( &dwThread ), hModule, 0, nullptr ); case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
Cheers.