mirror of
https://github.com/Detanup01/gbe_fork.git
synced 2024-11-23 11:15:34 +08:00
allow specifying a load order via a file called load_order.txt inside the root of the dlls to inject folder + updated readmes
This commit is contained in:
parent
d881806644
commit
e2cb2e0f38
@ -1,8 +1,11 @@
|
|||||||
* a new experimental library to patch Stub drm v3.1 in memory, check the readme of the cold client loader
|
* a new experimental library to patch Stub drm v3.1 in memory, check the readme of the cold client loader
|
||||||
* cold client loader can now inject dlls, also it can force inject the `steamclient(64).dll` library
|
* cold client loader can now inject dlls, also it can force inject the `steamclient(64).dll` library
|
||||||
|
* cold client loader can inject the dlls according to a user sepcified order, check the readme and the provided example
|
||||||
* cold client loader will now treat relative paths as relative to its own path
|
* cold client loader will now treat relative paths as relative to its own path
|
||||||
* cold client loader now doesn't need an explicit setting for the `ExeRunDir`, by default it would be the folder of the exe
|
* cold client loader now doesn't need an explicit setting for the `ExeRunDir`, by default it would be the folder of the exe
|
||||||
* in cold client loader, the option `ResumeByDebugger` is now available in the release build
|
* in cold client loader, the option `ResumeByDebugger` is now available in the release build
|
||||||
|
* cold client loader will display a nag about architecture difference if for example the app was 32-bit and the loader was 64-bit,
|
||||||
|
this could be disabled via the setting `IgnoreLoaderArchDifference=1`
|
||||||
* the cold client loader will output useful debug info when the debug build is used
|
* the cold client loader will output useful debug info when the debug build is used
|
||||||
* fixed a problem in the overlay which would cause a crash for the guest player when an invitation was sent
|
* fixed a problem in the overlay which would cause a crash for the guest player when an invitation was sent
|
||||||
* imitate how the DOS Stub is manipulated during/after the build
|
* imitate how the DOS Stub is manipulated during/after the build
|
||||||
|
@ -478,7 +478,8 @@ echo: & echo:
|
|||||||
:: copy configs + examples
|
:: copy configs + examples
|
||||||
if %last_code% equ 0 (
|
if %last_code% equ 0 (
|
||||||
echo // copying readmes + files examples
|
echo // copying readmes + files examples
|
||||||
xcopy /y /s "post_build\steam_settings.EXAMPLE\" "%build_root_dir%\steam_settings.EXAMPLE\"
|
xcopy /y /s /e /r "post_build\steam_settings.EXAMPLE\" "%build_root_dir%\steam_settings.EXAMPLE\"
|
||||||
|
xcopy /y /s /e /r "post_build\win\ColdClientLoader.EXAMPLE\" "%steamclient_dir%\EXAMPLE\"
|
||||||
copy /y "%tools_src_dir%\steamclient_loader\win\ColdClientLoader.ini" "%steamclient_dir%\"
|
copy /y "%tools_src_dir%\steamclient_loader\win\ColdClientLoader.ini" "%steamclient_dir%\"
|
||||||
copy /y "post_build\README.release.md" "%build_root_dir%\"
|
copy /y "post_build\README.release.md" "%build_root_dir%\"
|
||||||
copy /y "CHANGELOG.md" "%build_root_dir%\"
|
copy /y "CHANGELOG.md" "%build_root_dir%\"
|
||||||
|
@ -106,6 +106,34 @@ bool common_helpers::ends_with_i(const std::wstring &target, const std::wstring
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string common_helpers::to_lower(std::string str)
|
||||||
|
{
|
||||||
|
std::string _str(str.size(), '\0');
|
||||||
|
std::transform(str.begin(), str.end(), _str.begin(), [](char c) { return std::tolower(c); });
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring common_helpers::to_lower(std::wstring wstr)
|
||||||
|
{
|
||||||
|
std::wstring _wstr(wstr.size(), '\0');
|
||||||
|
std::transform(wstr.begin(), wstr.end(), _wstr.begin(), [](wchar_t c) { return std::tolower(c); });
|
||||||
|
return _wstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string common_helpers::to_upper(std::string str)
|
||||||
|
{
|
||||||
|
std::string _str(str.size(), '\0');
|
||||||
|
std::transform(str.begin(), str.end(), _str.begin(), [](char c) { return std::toupper(c); });
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring common_helpers::to_upper(std::wstring wstr)
|
||||||
|
{
|
||||||
|
std::wstring _wstr(wstr.size(), '\0');
|
||||||
|
std::transform(wstr.begin(), wstr.end(), _wstr.begin(), [](wchar_t c) { return std::toupper(c); });
|
||||||
|
return _wstr;
|
||||||
|
}
|
||||||
|
|
||||||
std::filesystem::path to_absolute_impl(const std::filesystem::path &path, const std::filesystem::path &base)
|
std::filesystem::path to_absolute_impl(const std::filesystem::path &path, const std::filesystem::path &base)
|
||||||
{
|
{
|
||||||
if (path.is_absolute()) {
|
if (path.is_absolute()) {
|
||||||
|
@ -24,6 +24,14 @@ bool ends_with_i(const std::string &target, const std::string &query);
|
|||||||
|
|
||||||
bool ends_with_i(const std::wstring &target, const std::wstring &query);
|
bool ends_with_i(const std::wstring &target, const std::wstring &query);
|
||||||
|
|
||||||
|
std::string to_lower(std::string str);
|
||||||
|
|
||||||
|
std::wstring to_lower(std::wstring wstr);
|
||||||
|
|
||||||
|
std::string to_upper(std::string str);
|
||||||
|
|
||||||
|
std::wstring to_upper(std::wstring wstr);
|
||||||
|
|
||||||
std::string to_absolute(const std::string &path, const std::string &base = std::string());
|
std::string to_absolute(const std::string &path, const std::string &base = std::string());
|
||||||
|
|
||||||
std::wstring to_absolute(const std::wstring &path, const std::wstring &base = std::wstring());
|
std::wstring to_absolute(const std::wstring &path, const std::wstring &base = std::wstring());
|
||||||
|
@ -30,7 +30,10 @@ You do not need to create a `steam_interfaces.txt` file for the `steamclient` ve
|
|||||||
Note that you have to resume the main thread from the debugger after attaching, also the entry breakpoint may not be set automatically, but you can do that manually.
|
Note that you have to resume the main thread from the debugger after attaching, also the entry breakpoint may not be set automatically, but you can do that manually.
|
||||||
* `DllsToInjectFolder`: path to a folder containing dlls to force inject into the app upon start,
|
* `DllsToInjectFolder`: path to a folder containing dlls to force inject into the app upon start,
|
||||||
the loader will attempt to detect the dll architecture (32 or 64 bit), if it didn't match the architecture of the exe, then it will ignored
|
the loader will attempt to detect the dll architecture (32 or 64 bit), if it didn't match the architecture of the exe, then it will ignored
|
||||||
* `IgnoreInjectionError`: setting this to `1` or `y` or `true` will prevent the loader from displaying an error message when a dll injection fails
|
* `IgnoreInjectionError`: setting this to `1` or `y` or `true` will prevent the loader from displaying an error message when a dll injection fails
|
||||||
|
* `IgnoreLoaderArchDifference`: don't display an error message if the architecture of the loader is different from the app.
|
||||||
|
this will result in a silent failure if a dll injection didn't succeed.
|
||||||
|
both the loader and the app must have the same arch for the injection to work
|
||||||
|
|
||||||
|
|
||||||
**Note** that any arguments passed to `steamclient_loader.exe` via command line will be passed to the target `.exe`.
|
**Note** that any arguments passed to `steamclient_loader.exe` via command line will be passed to the target `.exe`.
|
||||||
@ -38,6 +41,14 @@ Example: `steamclient_loader.exe` `-dx11`
|
|||||||
If the additional exe arguments were both: passed via command line and set in the `.ini` file, then both will be cocatenated and passed to the exe.
|
If the additional exe arguments were both: passed via command line and set in the `.ini` file, then both will be cocatenated and passed to the exe.
|
||||||
This allows the loader to be used/called from other external apps which set additional args.
|
This allows the loader to be used/called from other external apps which set additional args.
|
||||||
|
|
||||||
|
### `DllsToInjectFolder`
|
||||||
|
The folder specified by this identifier should contain the .dll files you'd like to inject in the app earlier during its creation.
|
||||||
|
All the subfolders inside this folder will be traversed recursively, and the .dll files inside these subfolders will be loaded/injected.
|
||||||
|
|
||||||
|
Additionaly, you can create a file called `load_order.txt` inside your folder (root level, not inside any subdir), mentioning on each line the .dll files to inject, the order of the lines will instruct the loader which .dll to inject first, the .dll mentioned on the first line will be injected first and so on.
|
||||||
|
Each line inside this file has to be the relative path to the target .dll, and it should be relative to your folder. Check the example.
|
||||||
|
Any .dll file not mentioned in this file will be loaded later, but in random order.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `extra_dlls`
|
## `extra_dlls`
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
# modified version of ColdClientLoader originally by Rat431
|
||||||
|
[SteamClient]
|
||||||
|
# path to game exe, absolute or relative to the loader
|
||||||
|
Exe=my_app.exe
|
||||||
|
# empty means the folder of the exe
|
||||||
|
ExeRunDir=
|
||||||
|
# any additional args to pass, ex: -dx11, also any args passed to the loader will be passed to the app
|
||||||
|
ExeCommandLine=
|
||||||
|
# IMPORTANT
|
||||||
|
AppId=123
|
||||||
|
|
||||||
|
# path to the steamclient dlls, both must be set,
|
||||||
|
# absolute paths or relative to the loader
|
||||||
|
SteamClientDll=steamclient.dll
|
||||||
|
SteamClient64Dll=steamclient64.dll
|
||||||
|
|
||||||
|
# force inject steamclient dll instead of waiting for the app to load it
|
||||||
|
ForceInjectSteamClient=0
|
||||||
|
|
||||||
|
[Debug]
|
||||||
|
# don't call `ResumeThread()` on the main thread after spawning the .exe
|
||||||
|
ResumeByDebugger=0
|
||||||
|
|
||||||
|
[Extra]
|
||||||
|
# path to a folder containing some dlls to inject into the app upon start
|
||||||
|
# this folder will be traversed recursively
|
||||||
|
# additionally, inside this folder you can create a file called `load_order.txt` and
|
||||||
|
# inside it, specify line by line the order of the dlls that have to be injected
|
||||||
|
# each line should be a relative path of the dll, relative to the injection folder
|
||||||
|
DllsToInjectFolder=extra_dlls.EXAMPLE
|
||||||
|
# don't display an error message when a dll injection fails
|
||||||
|
IgnoreInjectionError=0
|
||||||
|
# don't display an error message if the architecture of the loader is different from the app
|
||||||
|
# this will result in a silent failure if a dll injection didn't succeed
|
||||||
|
# both the loader and the app must have the same arch for the injection to work
|
||||||
|
IgnoreLoaderArchDifference=0
|
@ -0,0 +1,3 @@
|
|||||||
|
dlls_subdir\3_my_third_dll.dll
|
||||||
|
2_my_second_dll.dll
|
||||||
|
|
@ -12,6 +12,7 @@
|
|||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
|
||||||
static const std::wstring IniFile = pe_helpers::get_current_exe_path_w() + L"ColdClientLoader.ini";
|
static const std::wstring IniFile = pe_helpers::get_current_exe_path_w() + L"ColdClientLoader.ini";
|
||||||
@ -59,6 +60,90 @@ static std::vector<uint8_t> get_pe_header(const std::wstring &filepath)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<std::wstring> collect_dlls_to_inject(
|
||||||
|
const std::wstring &extra_dlls_folder,
|
||||||
|
bool is_exe_32,
|
||||||
|
std::wstring &failed_dlls = std::wstring{})
|
||||||
|
{
|
||||||
|
const auto load_order_file = std::filesystem::path(extra_dlls_folder) / "load_order.txt";
|
||||||
|
std::vector<std::wstring> dlls_to_inject{};
|
||||||
|
for (auto const& dir_entry :
|
||||||
|
std::filesystem::recursive_directory_iterator(extra_dlls_folder, std::filesystem::directory_options::follow_directory_symlink)) {
|
||||||
|
if (std::filesystem::is_directory(dir_entry.path())) continue;
|
||||||
|
|
||||||
|
auto dll_path = dir_entry.path().wstring();
|
||||||
|
// ignore this file if it is the load order file
|
||||||
|
if (common_helpers::to_upper(dll_path) == common_helpers::to_upper(load_order_file.wstring())) continue;
|
||||||
|
|
||||||
|
auto dll_header = get_pe_header(dll_path);
|
||||||
|
if (dll_header.empty()) {
|
||||||
|
dbg_log::write(L"Failed to get PE header of dll: " + dll_path);
|
||||||
|
failed_dlls += dll_path + L"\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_dll_32 = pe_helpers::is_module_32((HMODULE)&dll_header[0]);
|
||||||
|
bool is_dll_64 = pe_helpers::is_module_64((HMODULE)&dll_header[0]);
|
||||||
|
if ((!is_dll_32 && !is_dll_64) || (is_dll_32 && is_dll_64)) { // ARM, or just a regular file
|
||||||
|
dbg_log::write(L"Dll " + dll_path + L" is neither 32 nor 64 bit and will be ignored");
|
||||||
|
failed_dlls += dll_path + L"\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_dll_32 == is_exe_32) { // same arch
|
||||||
|
dlls_to_inject.push_back(dll_path);
|
||||||
|
dbg_log::write(L"Dll " + dll_path + L" will be injected");
|
||||||
|
} else {
|
||||||
|
dbg_log::write(L"Dll " + dll_path + L" has a different arch than the exe and will be ignored");
|
||||||
|
failed_dlls += dll_path + L"\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::wstring> ordered_dlls_to_inject{};
|
||||||
|
{
|
||||||
|
dbg_log::write(L"Searching for load order file: " + load_order_file.wstring());
|
||||||
|
auto f_order = std::wifstream(load_order_file, std::ios::in);
|
||||||
|
if (f_order.is_open()) {
|
||||||
|
dbg_log::write(L"Reading load order file: " + load_order_file.wstring());
|
||||||
|
std::wstring line{};
|
||||||
|
while (std::getline(f_order, line)) {
|
||||||
|
auto abs = common_helpers::to_absolute(line, extra_dlls_folder);
|
||||||
|
auto abs_upper = common_helpers::to_upper(abs);
|
||||||
|
dbg_log::write(L"Load order line: " + abs_upper);
|
||||||
|
auto it = std::find_if(dlls_to_inject.begin(), dlls_to_inject.end(), [&abs_upper](const std::wstring &dll_to_inject) {
|
||||||
|
return common_helpers::to_upper(dll_to_inject) == abs_upper;
|
||||||
|
});
|
||||||
|
if (it != dlls_to_inject.end()) {
|
||||||
|
dbg_log::write("Found the dll specified by the load order line");
|
||||||
|
ordered_dlls_to_inject.push_back(*it);
|
||||||
|
// mark for deletion
|
||||||
|
it->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f_order.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the remaining dlls
|
||||||
|
for (auto &dll : dlls_to_inject) {
|
||||||
|
if (dll.size()) {
|
||||||
|
ordered_dlls_to_inject.push_back(dll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ordered_dlls_to_inject;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void to_bool_ini_val(std::wstring &val)
|
||||||
|
{
|
||||||
|
for (auto &c : val) {
|
||||||
|
c = (wchar_t)std::tolower((int)c);
|
||||||
|
}
|
||||||
|
if (val != L"1" && val != L"y" && val != L"yes" && val != L"true") {
|
||||||
|
val.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
|
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
|
||||||
{
|
{
|
||||||
dbg_log::init(dbg_file.c_str());
|
dbg_log::init(dbg_file.c_str());
|
||||||
@ -89,16 +174,22 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
|||||||
);
|
);
|
||||||
std::wstring ExeCommandLine = get_ini_value(L"SteamClient", L"ExeCommandLine");
|
std::wstring ExeCommandLine = get_ini_value(L"SteamClient", L"ExeCommandLine");
|
||||||
std::wstring AppId = get_ini_value(L"SteamClient", L"AppId");
|
std::wstring AppId = get_ini_value(L"SteamClient", L"AppId");
|
||||||
std::wstring InjectClient = get_ini_value(L"SteamClient", L"ForceInjectSteamClient");
|
std::wstring ForceInjectSteamClient = get_ini_value(L"SteamClient", L"ForceInjectSteamClient");
|
||||||
|
|
||||||
std::wstring resume_by_dbg = get_ini_value(L"Debug", L"ResumeByDebugger");
|
std::wstring ResumeByDebugger = get_ini_value(L"Debug", L"ResumeByDebugger");
|
||||||
|
|
||||||
// dlls to inject
|
// dlls to inject
|
||||||
std::wstring extra_dlls_folder = common_helpers::to_absolute(
|
std::wstring DllsToInjectFolder = common_helpers::to_absolute(
|
||||||
get_ini_value(L"Extra", L"DllsToInjectFolder"),
|
get_ini_value(L"Extra", L"DllsToInjectFolder"),
|
||||||
pe_helpers::get_current_exe_path_w()
|
pe_helpers::get_current_exe_path_w()
|
||||||
);
|
);
|
||||||
std::wstring IgnoreInjectionError = get_ini_value(L"Extra", L"IgnoreInjectionError", L"1");
|
std::wstring IgnoreInjectionError = get_ini_value(L"Extra", L"IgnoreInjectionError", L"1");
|
||||||
|
std::wstring IgnoreLoaderArchDifference = get_ini_value(L"Extra", L"IgnoreLoaderArchDifference", L"0");
|
||||||
|
|
||||||
|
to_bool_ini_val(ResumeByDebugger);
|
||||||
|
to_bool_ini_val(ForceInjectSteamClient);
|
||||||
|
to_bool_ini_val(IgnoreInjectionError);
|
||||||
|
to_bool_ini_val(IgnoreLoaderArchDifference);
|
||||||
|
|
||||||
// log everything
|
// log everything
|
||||||
dbg_log::write(L"SteamClient::Exe: " + ExeFile);
|
dbg_log::write(L"SteamClient::Exe: " + ExeFile);
|
||||||
@ -107,10 +198,11 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
|||||||
dbg_log::write(L"SteamClient::AppId: " + AppId);
|
dbg_log::write(L"SteamClient::AppId: " + AppId);
|
||||||
dbg_log::write(L"SteamClient::SteamClient: " + ClientPath);
|
dbg_log::write(L"SteamClient::SteamClient: " + ClientPath);
|
||||||
dbg_log::write(L"SteamClient::SteamClient64Dll: " + Client64Path);
|
dbg_log::write(L"SteamClient::SteamClient64Dll: " + Client64Path);
|
||||||
dbg_log::write(L"SteamClient::ForceInjectSteamClient: " + InjectClient);
|
dbg_log::write(L"SteamClient::ForceInjectSteamClient: " + ForceInjectSteamClient);
|
||||||
dbg_log::write(L"Debug::ResumeByDebugger: " + resume_by_dbg);
|
dbg_log::write(L"Debug::ResumeByDebugger: " + ResumeByDebugger);
|
||||||
dbg_log::write(L"Extra::DllsToInjectFolder: " + extra_dlls_folder);
|
dbg_log::write(L"Extra::DllsToInjectFolder: " + DllsToInjectFolder);
|
||||||
dbg_log::write(L"Extra::IgnoreInjectionError: " + IgnoreInjectionError);
|
dbg_log::write(L"Extra::IgnoreInjectionError: " + IgnoreInjectionError);
|
||||||
|
dbg_log::write(L"Extra::IgnoreLoaderArchDifference: " + IgnoreLoaderArchDifference);
|
||||||
|
|
||||||
if (AppId.size() && AppId[0]) {
|
if (AppId.size() && AppId[0]) {
|
||||||
SetEnvironmentVariableW(L"SteamAppId", AppId.c_str());
|
SetEnvironmentVariableW(L"SteamAppId", AppId.c_str());
|
||||||
@ -131,7 +223,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
|||||||
|
|
||||||
if (ExeRunDir.empty()) {
|
if (ExeRunDir.empty()) {
|
||||||
ExeRunDir = std::filesystem::path(ExeFile).parent_path().wstring();
|
ExeRunDir = std::filesystem::path(ExeFile).parent_path().wstring();
|
||||||
dbg_log::write(L"Setting exe run dir to: " + ExeRunDir);
|
dbg_log::write(L"Setting ExeRunDir to: " + ExeRunDir);
|
||||||
}
|
}
|
||||||
if (!common_helpers::dir_exist(ExeRunDir)) {
|
if (!common_helpers::dir_exist(ExeRunDir)) {
|
||||||
dbg_log::write("Couldn't find the requested Exe run dir");
|
dbg_log::write("Couldn't find the requested Exe run dir");
|
||||||
@ -154,29 +246,8 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &c : resume_by_dbg) {
|
if (DllsToInjectFolder.size()) {
|
||||||
c = (wchar_t)std::tolower((int)c);
|
if (!common_helpers::dir_exist(DllsToInjectFolder)) {
|
||||||
}
|
|
||||||
if (resume_by_dbg != L"1" && resume_by_dbg != L"y" && resume_by_dbg != L"yes" && resume_by_dbg != L"true") {
|
|
||||||
resume_by_dbg.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &c : IgnoreInjectionError) {
|
|
||||||
c = (wchar_t)std::tolower((int)c);
|
|
||||||
}
|
|
||||||
if (IgnoreInjectionError != L"1" && IgnoreInjectionError != L"y" && IgnoreInjectionError != L"yes" && IgnoreInjectionError != L"true") {
|
|
||||||
IgnoreInjectionError.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &c : InjectClient) {
|
|
||||||
c = (wchar_t)std::tolower((int)c);
|
|
||||||
}
|
|
||||||
if (InjectClient != L"1" && InjectClient != L"y" && InjectClient != L"yes" && InjectClient != L"true") {
|
|
||||||
InjectClient.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extra_dlls_folder.size()) {
|
|
||||||
if (!common_helpers::dir_exist(extra_dlls_folder)) {
|
|
||||||
dbg_log::write("Couldn't find the requested folder of dlls to inject");
|
dbg_log::write("Couldn't find the requested folder of dlls to inject");
|
||||||
MessageBoxA(NULL, "Couldn't find the requested folder of dlls to inject.", "ColdClientLoader", MB_ICONERROR);
|
MessageBoxA(NULL, "Couldn't find the requested folder of dlls to inject.", "ColdClientLoader", MB_ICONERROR);
|
||||||
dbg_log::close();
|
dbg_log::close();
|
||||||
@ -215,42 +286,15 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
|||||||
|
|
||||||
if (loader_is_32 != is_exe_32) {
|
if (loader_is_32 != is_exe_32) {
|
||||||
dbg_log::write("Arch of loader and requested exe are different, it is advised to use the appropriate one");
|
dbg_log::write("Arch of loader and requested exe are different, it is advised to use the appropriate one");
|
||||||
MessageBoxA(NULL, "Arch of loader and requested exe are different,\nit is advised to use the appropriate one.", "ColdClientLoader", MB_OK);
|
if (IgnoreLoaderArchDifference.empty()) {
|
||||||
|
MessageBoxA(NULL, "Arch of loader and requested exe are different,\nit is advised to use the appropriate one.", "ColdClientLoader", MB_OK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::wstring> dlls_to_inject{};
|
std::vector<std::wstring> dlls_to_inject{};
|
||||||
if (extra_dlls_folder.size()) {
|
if (DllsToInjectFolder.size()) {
|
||||||
std::wstring failed_dlls = std::wstring{};
|
std::wstring failed_dlls{};
|
||||||
|
dlls_to_inject = collect_dlls_to_inject(DllsToInjectFolder, is_exe_32, failed_dlls);
|
||||||
for (auto const& dir_entry :
|
|
||||||
std::filesystem::recursive_directory_iterator(extra_dlls_folder, std::filesystem::directory_options::follow_directory_symlink)) {
|
|
||||||
if (std::filesystem::is_directory(dir_entry.path())) continue;
|
|
||||||
|
|
||||||
auto dll_path = dir_entry.path().wstring();
|
|
||||||
auto dll_header = get_pe_header(dll_path);
|
|
||||||
if (dll_header.empty()) {
|
|
||||||
dbg_log::write(L"Failed to get PE header of dll: " + dll_path);
|
|
||||||
failed_dlls += dll_path + L"\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_dll_32 = pe_helpers::is_module_32((HMODULE)&dll_header[0]);
|
|
||||||
bool is_dll_64 = pe_helpers::is_module_64((HMODULE)&dll_header[0]);
|
|
||||||
if ((!is_dll_32 && !is_dll_64) || (is_dll_32 && is_dll_64)) { // ARM, or just a regular file
|
|
||||||
dbg_log::write(L"Dll " + dll_path + L" is neither 32 nor 64 bit and will be ignored");
|
|
||||||
failed_dlls += dll_path + L"\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((is_dll_32 && is_exe_32) || (is_dll_64 && is_exe_64)) {
|
|
||||||
dlls_to_inject.push_back(dll_path);
|
|
||||||
dbg_log::write(L"Dll " + dll_path + L" will be injected");
|
|
||||||
} else {
|
|
||||||
dbg_log::write(L"Dll " + dll_path + L" has a different arch than the exe and will be ignored");
|
|
||||||
failed_dlls += dll_path + L"\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failed_dlls.size() && IgnoreInjectionError.empty()) {
|
if (failed_dlls.size() && IgnoreInjectionError.empty()) {
|
||||||
int choice = MessageBoxW(
|
int choice = MessageBoxW(
|
||||||
NULL,
|
NULL,
|
||||||
@ -320,19 +364,20 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (InjectClient.size()) {
|
if (ForceInjectSteamClient.size()) {
|
||||||
if (is_exe_32) {
|
if (is_exe_32) {
|
||||||
dlls_to_inject.insert(dlls_to_inject.begin(), ClientPath);
|
dlls_to_inject.insert(dlls_to_inject.begin(), ClientPath);
|
||||||
} else {
|
} else {
|
||||||
dlls_to_inject.insert(dlls_to_inject.begin(), Client64Path);
|
dlls_to_inject.insert(dlls_to_inject.begin(), Client64Path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto &dll_path : dlls_to_inject) {
|
for (const auto &dll : dlls_to_inject) {
|
||||||
|
dbg_log::write(L"Injecting dll: '" + dll + L"' ...");
|
||||||
const char *err_inject = nullptr;
|
const char *err_inject = nullptr;
|
||||||
DWORD code = pe_helpers::loadlib_remote(processInfo.hProcess, dll_path, &err_inject);
|
DWORD code = pe_helpers::loadlib_remote(processInfo.hProcess, dll, &err_inject);
|
||||||
if (code != ERROR_SUCCESS) {
|
if (code != ERROR_SUCCESS) {
|
||||||
std::wstring err_full =
|
std::wstring err_full =
|
||||||
L"Failed to inject the dll: " + dll_path + L"\n" +
|
L"Failed to inject the dll: " + dll + L"\n" +
|
||||||
common_helpers::str_to_w(err_inject) + L"\n" +
|
common_helpers::str_to_w(err_inject) + L"\n" +
|
||||||
common_helpers::str_to_w(pe_helpers::get_err_string(code)) + L"\n" +
|
common_helpers::str_to_w(pe_helpers::get_err_string(code)) + L"\n" +
|
||||||
L"Error code = " + std::to_wstring(code) + L"\n";
|
L"Error code = " + std::to_wstring(code) + L"\n";
|
||||||
@ -346,12 +391,12 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
dbg_log::write("Injected!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// run
|
// run
|
||||||
if (resume_by_dbg.empty()) {
|
if (ResumeByDebugger.empty()) {
|
||||||
ResumeThread(processInfo.hThread);
|
ResumeThread(processInfo.hThread);
|
||||||
} else {
|
} else {
|
||||||
std::string msg = "Attach a debugger now to PID " + std::to_string(processInfo.dwProcessId) + " and resume its main thread";
|
std::string msg = "Attach a debugger now to PID " + std::to_string(processInfo.dwProcessId) + " and resume its main thread";
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
# modified version of ColdClientLoader originally by Rat431
|
# modified version of ColdClientLoader originally by Rat431
|
||||||
[SteamClient]
|
[SteamClient]
|
||||||
|
# path to game exe, absolute or relative to the loader
|
||||||
Exe=game.exe
|
Exe=game.exe
|
||||||
|
# empty means the folder of the exe
|
||||||
ExeRunDir=
|
ExeRunDir=
|
||||||
|
# any additional args to pass, ex: -dx11, also any args passed to the loader will be passed to the app
|
||||||
ExeCommandLine=
|
ExeCommandLine=
|
||||||
#IMPORTANT:
|
# IMPORTANT
|
||||||
AppId=
|
AppId=
|
||||||
|
|
||||||
|
# path to the steamclient dlls, both must be set,
|
||||||
|
# absolute paths or relative to the loader
|
||||||
SteamClientDll=steamclient.dll
|
SteamClientDll=steamclient.dll
|
||||||
SteamClient64Dll=steamclient64.dll
|
SteamClient64Dll=steamclient64.dll
|
||||||
|
|
||||||
# inject `steamclient(64).dll`
|
# force inject steamclient dll instead of waiting for the app to load it
|
||||||
ForceInjectSteamClient=0
|
ForceInjectSteamClient=0
|
||||||
|
|
||||||
[Debug]
|
[Debug]
|
||||||
@ -17,8 +22,17 @@ ForceInjectSteamClient=0
|
|||||||
ResumeByDebugger=0
|
ResumeByDebugger=0
|
||||||
|
|
||||||
[Extra]
|
[Extra]
|
||||||
; path to a folder containing dlls to force inject into the app upon start
|
# path to a folder containing some dlls to inject into the app upon start
|
||||||
; extra_dlls
|
# this folder will be traversed recursively
|
||||||
|
# additionally, inside this folder you can create a file called `load_order.txt` and
|
||||||
|
# inside it, specify line by line the order of the dlls that have to be injected
|
||||||
|
# each line should be a relative path of the dll, relative to the injection folder
|
||||||
|
# example:
|
||||||
|
#DllsToInjectFolder=extra_dlls
|
||||||
DllsToInjectFolder=
|
DllsToInjectFolder=
|
||||||
; don't display an error message when a dll injection fails
|
# don't display an error message when a dll injection fails
|
||||||
IgnoreInjectionError=1
|
IgnoreInjectionError=1
|
||||||
|
# don't display an error message if the architecture of the loader is different from the app
|
||||||
|
# this will result in a silent failure if a dll injection didn't succeed
|
||||||
|
# both the loader and the app must have the same arch for the injection to work
|
||||||
|
IgnoreLoaderArchDifference=0
|
||||||
|
Loading…
Reference in New Issue
Block a user