Close program if another application is closed.

Pages: 12
Hello. I have a game made in C++ and I have also made AntiCheat application in C#. Now since I'm not really into C++ I need the following code:

I want my C++ app to check if AntiCheat.exe is in the same directory.
Should check file name, version, decription and size (if possible)

If AntiCheat.exe is in the same dir, run the game and run the AntiCheat.exe. If AntiCheat.exe is closed, close the game too.

If AntiCheat.exe doesn't exist, don't start the game.

Thank you!
Why don't you do it in C# ? It would be much easier.

If AntiCheat.exe is closed, close the game too.

This is quite a difficult task.
http://stackoverflow.com/questions/872364/win32-get-message-notification-of-other-applications-close-exit
I can't do it in C#, cause the original project is made in C++ by someone else and I am just modding it. Also, it uses mingw compiler cause the game is made to be run on both linux and windows os which confuses me even more. Now I don't care about linux, it can work on windows only. I understand closing the game when AntiCheat.exe is closed could be difficult, but how about others ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Something like this:
#include <iostream>
#include <string>
#include <experimental/filesystem> // microsoft has implemented filesystem TS
#include <windows.h>
#include <vector>

bool exists_and_is_of_size( std::string path, std::uintmax_t size )
{
    try { return std::experimental::filesystem::file_size(path) == size ; }
    catch( const std::experimental::filesystem::filesystem_error& ) { return false; }
}

HANDLE create_process( std::string path )
{
    ::STARTUPINFO si {} ;
    ::PROCESS_INFORMATION pi {} ;
    std::vector<char> vec( path.begin(), path.end() ) ;
    vec.resize( path.size() + 100 ) ;

    if( ::CreateProcessA( nullptr, vec.data(), nullptr, nullptr, false, 0, nullptr, nullptr,
                          std::addressof(si), std::addressof(pi) ) )
        ::CloseHandle( pi.hThread ) ;

    return pi.hProcess ;
}

int main()
{
    const std::string anti_cheat_path = "AntiCheat.exe" ;
    const std::uintmax_t anti_cheat_size = 12345 ;

    // if anti_cheat is in the current directory and has the expected size
    if( exists_and_is_of_size( anti_cheat_path, anti_cheat_size ) )
    {
        const auto anti_cheat = create_process( anti_cheat_path ) ;
        if( !anti_cheat ) return 1 ; // return if the anti_cheat process could not be launched

        while( WaitForSingleObject( anti_cheat, 0 ) == WAIT_TIMEOUT ) // if anti_cheat is still running
        {
            const unsigned int check_interval_millisecs = 5000 ; // check every five seconds
            // run game loop for check_interval_millisecs milliseconds
            // go back to while and check if anti_cheat is still running
        }
    }
}
Hi @JLborges, thanks for the code. I don't seem to find that <experimental/filesystem> file. Do I have to install some library ? If yes, which one ? In case you didn't read above, I am using GNU GCC Compiler with MinGW to compile the project. I have tried to install libstdc++, but it didn't worked.
Last edited on
The GNU C++ library does not have a filesystem TS implementation; use WinAPI:
1
2
3
4
5
6
7
8
9
bool exists_and_is_of_size( std::string path, unsigned long size )
{
    const auto file = ::CreateFileA( path.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, 0 ) ;
    if( file == INVALID_HANDLE_VALUE ) return false ;

    const auto sz = ::GetFileSize( file, nullptr ) ;
    ::CloseHandle(file) ;
    return sz == size ;
}
Last edited on
The GNU C++ library does not have a filesystem TS implementation;


VS 2013 also doesn't have it.
As I recall, <experimental/filesystem> is available from GCC 5.3 onwards. It requires an additional link at the command line: -lstdc++fs

I've used it myself and it was fine, although I can't speak for a MinGW version.
Last edited on
Hi @JLBorges. I tried to use the WinAPI code, but it gives me errors:

1
2
3
4
5
6
7
8
9
10
'file' does not name a type
'file' was not declared in this scope
'sz' does not name a type
'sz' was not declared in this scope
'nullptr' was not declared in this scope
'addressof' is not a member of 'std'
'uintmax_t' in namespace 'std' does not name a type
'anti_cheat_size' was not declared in this scope
'anti_cheat' does not name a type
'anti_cheat' was not declared in this scope


I have included:

1
2
3
4
#include <iostream>
#include <string>
#include <vector>
#include <windows.h> 
The GNU compiler, with its default settings, does not support C++11. Compile with
g++ -std=c++11 -Wall -Wextra -pedantic-errors

-std=c++11 - conform (to the extent possible) to the C++11 standard
-pedantic-errors - C++11: the International Standard for C++11 (not the home-grown dialect of C++11)

To set these from the IDE, see: http://www.cplusplus.com/doc/tutorial/introduction/codeblocks/
Okay I set these from the IDE following the tutorial. I started my game without anticheat.exe exist in the same dir and nothing happens. Game doesn't close and it should be closing if anticheat.exe is missing or not started.
Last edited on
It may help if you post the code for main() (and the two functions exists_and_is_of_size() and create_process() )
Hi. exist_and_is_of_size() and create_process() are in the code you gave me ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
bool exists_and_is_of_size( std::string path, unsigned long size )
{
    const auto file = ::CreateFileA( path.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, 0 ) ;
    if( file == INVALID_HANDLE_VALUE ) return false ;

    const auto sz = ::GetFileSize( file, nullptr ) ;
    ::CloseHandle(file) ;
    return sz == size ;
}

HANDLE create_process( std::string path )
{
    ::STARTUPINFO si {} ;
    ::PROCESS_INFORMATION pi {} ;
    std::vector<char> vec( path.begin(), path.end() ) ;
    vec.resize( path.size() + 100 ) ;

    if( ::CreateProcessA( nullptr, vec.data(), nullptr, nullptr, false, 0, nullptr, nullptr,
                          std::addressof(si), std::addressof(pi) ) )
        ::CloseHandle( pi.hThread ) ;

    return pi.hProcess ;
}


Here's my original main function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main(int argc, char *argv[])
{
	if (!init_sdl()) return 0;
	init_memory();
	init_audio();
	load_splash_screen();
	load_login();
	read_host_info();
	read_config_info();
	load_ignore();
	load_sos();
	//connect_to_hub();
	init_sockets();
	main_loop();
	return 0;
}


And here's how it looks when i add your code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int main(int argc, char *argv[])
{
    const std::string anti_cheat_path = "AntiCheat.exe" ;
    const std::uintmax_t anti_cheat_size = 40 ; //file is 40kb

    // if anti_cheat is in the current directory and has the expected size
    if( exists_and_is_of_size( anti_cheat_path, anti_cheat_size ) )
    {
        const auto anti_cheat = create_process( anti_cheat_path ) ;
        if( !anti_cheat ) return 1 ; // return if the anti_cheat process could not be launched

        while( WaitForSingleObject( anti_cheat, 0 ) == WAIT_TIMEOUT ) // if anti_cheat is still running
        {
            const unsigned int check_interval_millisecs = 5000 ; // check every five seconds
            // run game loop for check_interval_millisecs milliseconds
            // go back to while and check if anti_cheat is still running
        }
    }
	if (!init_sdl()) return 0;
	init_memory();
	init_audio();
	load_splash_screen();
	load_login();
	read_host_info();
	read_config_info();
	load_ignore();
	load_sos();
	//connect_to_hub();
	init_sockets();
	main_loop();
	return 0;
}
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int main()
{
    const std::string anti_cheat_path = "AntiCheat.exe" ;
    // const std::uintmax_t anti_cheat_size = 40 ; //file is 40kb
    const std::uintmax_t anti_cheat_size = 39386 ; // put the actual size here (39,386 bytes in this example)
    
    // if anti_cheat is in the current directory and has the expected size
    if( exists_and_is_of_size( anti_cheat_path, anti_cheat_size ) )
    {
        const auto anti_cheat = create_process( anti_cheat_path ) ;
        if( !anti_cheat ) return 1 ; // return if the anti_cheat process could not be launched

        if (!init_sdl()) return 0;
        init_memory();
        init_audio();
        load_splash_screen();
        load_login();
        read_host_info();
        read_config_info();
        load_ignore();
        load_sos();
        //connect_to_hub();
        init_sockets();
        
        // main_loop() should execute this while loop, once every 'check_interval_millisecs' milliseconds
        while( WaitForSingleObject( anti_cheat, 0 ) == WAIT_TIMEOUT ) // if anti_cheat is still running
        {
            const unsigned int check_interval_millisecs = 5000 ; // check every five seconds
            // run game loop for check_interval_millisecs milliseconds
            // go back to while and check if anti_cheat is still running
        }
    }
    
    else return 1 ; // anti cheat not found
}
Works like a charm @JLBorges, thank you very much! One more thing I would like to ask is if its possible to somehow hard code the AntiCheat.exe's MD5 hash into the C++ application and then scan the AntiCheat.exe for a match ? Thank you very much.
Last edited on
~bump

anyone ?
Using Wincrypt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <fstream>
#include <iterator>
#include <windows.h>
#include <wincrypt.h>

constexpr std::size_t MD5_SIZE = 16 ;
using md5_digest = std::array< BYTE, MD5_SIZE > ;

std::vector<BYTE> get_bytes( std::string path )
{
    std::ifstream file( path, std::ios_base::binary ) ;
    return { std::istream_iterator<BYTE>{file}, std::istream_iterator<BYTE>{} } ;
}

md5_digest md5( std::string path ) // MinGW: link with libadvapi32.a
{
    md5_digest digest {} ;

    const auto bytes = get_bytes(path) ;
    if( !bytes.empty() )
    {
        HCRYPTPROV provider = 0 ;
        if( ::CryptAcquireContext( std::addressof(provider), nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) )
        {
            HCRYPTHASH hash = 0 ;
            if( ::CryptCreateHash( provider, CALG_MD5, 0, 0, std::addressof(hash) ) )
            {
                ::CryptHashData( hash, bytes.data(), bytes.size(), 0 ) ;
                DWORD nbytes = bytes.size() ;
                ::CryptGetHashParam( hash, HP_HASHVAL, digest.data(), std::addressof(nbytes), 0 ) ;
                ::CryptDestroyHash(hash) ;
            }
            ::CryptReleaseContext( provider, 0 ) ;
        }
    }

    return digest ;
}

int main()
{
    const std::string anti_cheat_path = "AntiCheat.exe" ;

    // initialise with the actual md5 digest for anti_cheat.exe
    const md5_digest expected_anti_cheat_md5 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } ;

    if( md5(anti_cheat_path) == expected_anti_cheat_md5 ) // if the md5 digest matches
    {
        // proceed with the game
    }
}
Last edited on
Thanks for the answer again @JLBorges, but my compiler doesn't seem to find <array> ? Do I have to install 3rd party library ? I am using the TDM-GCC compiler:


Bundle installer for the TDM32 MinGW edition. Includes C, C++, and OpenMP support, SJLJ exception handling, other GNU toolchain programs (binutils), Windows API libraries (MinGW WSL), GNU make (mingw32-make), and the GNU debugger (GDB).


I assume I need that libstdc++, but I don't know how to install it on windows.
Last edited on
> my compiler doesn't seem to find <array> ?

See: http://www.cplusplus.com/forum/general/188138/#msg914244
Thanks @JLBorges, array was magically found today when I started Code::Blocks, lol ..
But a couple of problems popped up. First, to be sure that I fully understand this line:

1
2
    // initialise with the actual md5 digest for anti_cheat.exe
const md5_digest expected_anti_cheat_md5 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } ;


This is the actual MD5 code of the AntiCheat.exe converted to Hex, right ? So in this case the MD5 string is "75a82fafa3b892a349f80ce45c7e7a15" which equals to: 3735613832666166613362383932613334396638306365343563376537613135 in hex, so the line becomes:

1
2
    // initialise with the actual md5 digest for anti_cheat.exe
const md5_digest expected_anti_cheat_md5 = { 3735, 6138, 3266, 6166, 6133, 6238, 3932, 6133, 3439, 6638, 3063, 6534, 3563, 3765, 3761, 3135 } ;


Is that right ? Cause it output errors for every one of the 16 fields saying:


error: narrowing conversion of '3439' from 'int' to 'unsigned char' inside { }


Also, it shows another error in this lile:

::CryptHashData( hash, bytes.data(), bytes.size(), 0 ) ;

saying:


error: invalid conversion from 'const unsigned char*' to 'PBYTE {aka unsigned char*}' [-fpermissive]


And a note in wincrypt.h line 1211:

::CryptHashData( hash, bytes.data(), bytes.size(), 0 ) ;

saying:

C:\TDM-GCC-32\include\wincrypt.h|1211|note: initializing argument 2 of 'BOOL CryptHashData(HCRYPTHASH, PBYTE, DWORD, DWORD)'|


This is getting harder than I though, lol. What is happening ??
Last edited on
Pages: 12