diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8a9d35c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.user diff --git a/NativeLauncher.cpp b/NativeLauncher.cpp new file mode 100644 index 0000000..c120ed5 --- /dev/null +++ b/NativeLauncher.cpp @@ -0,0 +1,188 @@ +#define WIN32_LEAN_AND_MEAN 1 + +#include +#include +#include +#include +#include +#include + +using namespace std; + +bool disable_debug_privilege() +{ + HANDLE hToken = NULL; + LUID luidDebugPrivilege; + PRIVILEGE_SET RequiredPrivileges; + BOOL bResult; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken)) + { + std::cout << "OpenProcessToken failed: " << GetLastError() << std::endl; + return false; + } + + + if (!LookupPrivilegeValue(NULL, L"SeDebugPrivilege", &luidDebugPrivilege)) + { + std::cout << "LookupPrivilegeValue failed: " << GetLastError() << std::endl; + return false; + } + + + RequiredPrivileges.PrivilegeCount = 1; + RequiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY; + + RequiredPrivileges.Privilege[0].Luid = luidDebugPrivilege; + RequiredPrivileges.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED; + + PrivilegeCheck(hToken, &RequiredPrivileges, &bResult); + + if (bResult) // SeDebugPrivilege is enabled; try disabling it + { + TOKEN_PRIVILEGES TokenPrivileges; + TokenPrivileges.PrivilegeCount = 1; + TokenPrivileges.Privileges[0].Luid = luidDebugPrivilege; + TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED; + + if (!AdjustTokenPrivileges(hToken, FALSE, &TokenPrivileges, 0, NULL, 0)) { + std::cout << "AdjustTokenPrivileges failed: " << GetLastError() << std::endl; + return false; + } + } + + return true; +} + +struct handle_data { + unsigned long process_id; + HWND window_handle; +}; + +BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam) +{ + handle_data& data = *(handle_data*)lParam; + unsigned long process_id = 0; + GetWindowThreadProcessId(handle, &process_id); + if (data.process_id != process_id) + return TRUE; + data.window_handle = handle; + return FALSE; +} + +bool has_window(unsigned long process_id) +{ + handle_data data; + data.process_id = process_id; + data.window_handle = 0; + EnumWindows(enum_windows_callback, (LPARAM)&data); + return data.window_handle != nullptr; +} + +int launch_game(char* appC, char* argC) +{ + std::string app(appC); + std::string arg(argC); + + //Prepare CreateProcess args + std::wstring app_w(app.length(), L' '); // Make room for characters + std::copy(app.begin(), app.end(), app_w.begin()); // Copy string to wstring. + + std::wstring arg_w(arg.length(), L' '); // Make room for characters + std::copy(arg.begin(), arg.end(), arg_w.begin()); // Copy string to wstring. + + std::wstring input = app_w + L" " + arg_w; + wchar_t* arg_concat = const_cast(input.c_str()); + const wchar_t* app_const = app_w.c_str(); + + TCHAR username[256]; + DWORD size = 256; + if (!GetUserName((TCHAR*)username, &size)) + { + std::cout << "GetUserName failed: " << GetLastError() << std::endl; + return -1; + } + + EXPLICIT_ACCESS pExplicitAccess; + ZeroMemory(&pExplicitAccess, sizeof(pExplicitAccess)); + BuildExplicitAccessWithName(&pExplicitAccess, username, 0x001fffdf, GRANT_ACCESS, 0); + + PACL NewAcl; + SetEntriesInAcl(1u, &pExplicitAccess, nullptr, &NewAcl); + + SECURITY_DESCRIPTOR secDes; + ZeroMemory(&secDes, sizeof(secDes)); + if (!InitializeSecurityDescriptor(&secDes, 1u)) + { + std::cout << "InitializeSecurityDescriptor failed: " << GetLastError() << std::endl; + return -1; + } + + if (!SetSecurityDescriptorDacl(&secDes, true, NewAcl, false)) + { + std::cout << "SetSecurityDescriptorDacl failed: " << GetLastError() << std::endl; + return -1; + } + + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + + SECURITY_ATTRIBUTES pSec; + ZeroMemory(&pSec, sizeof(pSec)); + pSec.nLength = sizeof(pSec); + pSec.lpSecurityDescriptor = &secDes; + pSec.bInheritHandle = false; + + if (!CreateProcess(nullptr, arg_concat, &pSec, nullptr, false, 0x20, nullptr, nullptr, &si, &pi)) + { + std::cout << "CreateProcess failed: " << GetLastError() << std::endl; + return -1; + } + + + while (!has_window(pi.dwProcessId)) + { + Sleep(10); + } + + PACL myAcl; + auto gsi = GetSecurityInfo(GetCurrentProcess(), SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, nullptr, nullptr, &myAcl, nullptr, nullptr); + if (gsi != ERROR_SUCCESS) + { + std::cout << "GetSecurityInfo failed: " << gsi << std::endl; + return -1; + } + + auto ssi = SetSecurityInfo(pi.hProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION, nullptr, nullptr, myAcl, nullptr); + if (ssi != ERROR_SUCCESS) + { + std::cout << "SetSecurityInfo failed: " << ssi << std::endl; + return -1; + } + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + return pi.dwProcessId; +} + +int main(int argc, char* argv[]) +{ + if (argc < 3) + { + std::cout << "needs game and arguments"; + return -1; + } + + disable_debug_privilege(); + + auto pid = launch_game(argv[1], argv[2]); + + std::cout << pid; + + return pid; +} \ No newline at end of file diff --git a/NativeLauncher.vcxproj b/NativeLauncher.vcxproj new file mode 100644 index 0000000..14ad35b --- /dev/null +++ b/NativeLauncher.vcxproj @@ -0,0 +1,157 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {F1EAA424-8DEC-4963-872B-6CFAC77811BA} + Win32Proj + NativeLauncher + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)XIVLauncher\bin\$(Configuration)\ + + + true + + + false + $(SolutionDir)XIVLauncher\bin\$(Configuration)\ + + + false + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + \ No newline at end of file diff --git a/NativeLauncher.vcxproj.filters b/NativeLauncher.vcxproj.filters new file mode 100644 index 0000000..88f0e1a --- /dev/null +++ b/NativeLauncher.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file