Skip to content

Commit 7cda922

Browse files
Merge pull request #510 from GameTechDev/injection-rainbow-side
Injection rainbow side
2 parents 3bf800a + 4fd92f6 commit 7cda922

File tree

20 files changed

+210
-135
lines changed

20 files changed

+210
-135
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,5 @@ PresentMon/ddETWExternalEventsTEMP.BIN
6060

6161
# Local runsettings files (user-specific test configurations)
6262
*.local.runsettings
63+
64+
Directory.Build.props

IntelPresentMon/AppCef/ipm-ui-vue/src/views/FlashConfigView.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ watch(
9797

9898
<v-row class="mt-8">
9999
<v-col cols="3">
100-
Rainbow Flash
101-
<p class="text-medium-emphasis text-caption mb-0">Cycle through a rainbow of colors instead of using above flash color.</p>
100+
Rainbow Strip
101+
<p class="text-medium-emphasis text-caption mb-0">Draw a strip on the left-hand side of the screen that cycles through colors every frame.</p>
102102
</v-col>
103103
<v-col cols="9">
104104
<v-switch v-model="prefs.preferences.flashInjectionUseRainbow" label="Enable"></v-switch>

IntelPresentMon/CommonUtilities/win/com/ProcessSpawnSink.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ namespace pmon::util::win::com
3131
std::function<void()> notificationFunction_;
3232
};
3333
// functions
34-
ProcessSpawnSink(EventQueue& queue, float delayToleranceSeconds = 0.4);
34+
ProcessSpawnSink(EventQueue& queue, float delayToleranceSeconds = 0.5);
3535
HRESULT STDMETHODCALLTYPE Indicate(LONG count,
3636
IWbemClassObject __RPC_FAR* __RPC_FAR* pObjArr) override;
3737
std::string GetQueryString() const override;

IntelPresentMon/Core/source/cli/CliOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace p2c::cli
2626
Flag traceExceptions{ this, "--trace-exceptions", "Add stack trace to all thrown exceptions (including SEH exceptions)" };
2727
Flag enableDiagnostic{ this, "--enable-diagnostic", "Enable debug diagnostic layer forwarding (duplicates exiisting log entries)" };
2828
Flag filesWorking{ this, "--files-working", "Use the working directory for file storage" };
29+
Flag waitForDebugger{ this, "--wait-for-debugger", "On entry wait for debugger to be attached, then break" };
2930

3031
private: Group gl_{ this, "Logging", "Customize logging for this tool"}; public:
3132
Option<log::Level> logLevel{ this, "--log-level", log::Level::Error, "Severity to log at", logLevelTf_ };

IntelPresentMon/Core/source/kernel/InjectorComplex.cpp

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,22 +54,38 @@ namespace p2c::kern
5454
InjectorComplex::InjectorModule_::InjectorModule_(bool is32Bit)
5555
:
5656
pipeOut_{ ioctx_ },
57-
pipeIn_{ ioctx_ }
57+
pipeIn_{ ioctx_ },
58+
pipeErr_{ ioctx_ },
59+
is32Bit_{ is32Bit },
60+
injectorProcess_{ ioctx_ }
5861
{
5962
// Determine the correct injector executable
6063
auto exe = is32Bit
6164
? "FlashInjector-Win32.exe"
6265
: "FlashInjector-x64.exe";
63-
auto path = std::filesystem::current_path() / exe;
6466

65-
// Spawn the child with Asio pipes for stdin/stdout (stderr inherited)
66-
injectorProcess_.emplace(
67+
// Spawn the child with Asio pipes for stdin/stdout/stderr
68+
injectorProcess_ = bp2::process{
6769
ioctx_,
68-
path.string(),
70+
exe, // using relative path to injector here due to issue with boost.process (following up)
6971
/* no args = */ std::vector<std::string>{},
7072
bp2::windows::process_creation_flags<CREATE_NO_WINDOW>(),
71-
bp2::process_stdio{ pipeIn_, pipeOut_, nullptr }
72-
);
73+
bp2::process_stdio{ pipeIn_, pipeOut_, pipeErr_ }
74+
};
75+
76+
// if logging at debug level, pump stderr into pmlog
77+
namespace log = ::pmon::util::log;
78+
if (log::GlobalPolicy::Get().GetLogLevel() >= log::Level::Debug) {
79+
errListenerThread_ = std::jthread{ [this](std::stop_token st) {
80+
// when someone does listenerThread_.request_stop(),
81+
// this callback will fire and break ioctx_.run()
82+
std::stop_callback cb{ st, [this] { ioctx_.stop(); } };
83+
// kick off the first async read
84+
SpawnReadErrTask_();
85+
// enter Asio’s event loop
86+
ioctx_.run();
87+
} };
88+
}
7389

7490
// Start the listener thread; on stop request we'll call ioctx_.stop()
7591
listenerThread_ = std::jthread{ [this](std::stop_token st) {
@@ -149,6 +165,30 @@ namespace p2c::kern
149165
}
150166
});
151167
}
168+
void InjectorComplex::InjectorModule_::SpawnReadErrTask_()
169+
{
170+
as::async_read_until(pipeErr_, errBuffer_, '\n',
171+
[this](boost::system::error_code ec, std::size_t /*bytes*/) {
172+
if (!ec) {
173+
// read a line out from the asio buffer
174+
std::istream is(&errBuffer_);
175+
std::string stderrLine;
176+
std::getline(is, stderrLine);
177+
178+
try {
179+
pmlog_dbg("Stderr from injector").pmwatch(is32Bit_).pmwatch(stderrLine);
180+
}
181+
catch (...) {
182+
pmlog_error("Failed to read stderr from injector");
183+
}
184+
}
185+
186+
// queue the next read (unless we're shutting down)
187+
if (pipeErr_.is_open()) {
188+
SpawnReadErrTask_();
189+
}
190+
});
191+
}
152192
void InjectorComplex::InjectorModule_::PushConfig_()
153193
{
154194
std::lock_guard lk{ actionClientMutex_ };

IntelPresentMon/Core/source/kernel/InjectorComplex.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,21 @@ namespace p2c::kern
2525

2626
private:
2727
void SpawnReadPidTask_();
28+
void SpawnReadErrTask_();
2829
void PushConfig_();
29-
as::io_context ioctx_;
30+
bool is32Bit_;
31+
as::io_context ioctx_;
3032
as::writable_pipe pipeIn_; // us to child's stdin
3133
as::readable_pipe pipeOut_; // child's stdout to us
34+
as::readable_pipe pipeErr_; // child's stderr to us
3235
as::streambuf readBuffer_;
36+
as::streambuf errBuffer_;
3337
std::jthread listenerThread_;
38+
std::jthread errListenerThread_;
3439
std::mutex actionClientMutex_;
3540
std::optional<iact::ActionClient> injectionPointClient_;
3641
GfxLayer::Extension::OverlayConfig config_;
37-
std::optional<bp2::process> injectorProcess_;
42+
bp2::process injectorProcess_;
3843
};
3944
public:
4045
void SetActive(bool active);

IntelPresentMon/FlashInjector/LibraryInject.cpp

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,22 @@ namespace LibraryInject
1616
{
1717
auto hProcess = (win::Handle)OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
1818
if (!hProcess) {
19-
LOGI << "OpenProcess failed with [" << win::GetErrorDescription(GetLastError()) << "]; re-attemping with elevated privileges";
19+
LOGI << "OpenProcess failed with [" << win::GetErrorDescription(GetLastError()) << "]; re-attemping with elevated privileges" << std::endl;
2020

2121
// Increase privileges
2222
win::Handle hToken;
2323
{
2424
HANDLE tempHandle;
2525
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &tempHandle)) {
26-
LOGE << "OpenProcessToken failed for current process. Error: " << win::GetErrorDescription(GetLastError());
26+
LOGE << "OpenProcessToken failed for current process. Error: " << win::GetErrorDescription(GetLastError()) << std::endl;
2727
exit(1);
2828
}
2929
hToken = win::Handle(tempHandle);
3030
}
3131

3232
LUID debugPrivilegeId;
3333
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &debugPrivilegeId)) {
34-
LOGE << "LookupPrivilegeValue failed for current process. Error: " << win::GetErrorDescription(GetLastError());
34+
LOGE << "LookupPrivilegeValue failed for current process. Error: " << win::GetErrorDescription(GetLastError()) << std::endl;
3535
exit(1);
3636
}
3737

@@ -42,12 +42,12 @@ namespace LibraryInject
4242
}
4343
};
4444
if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, sizeof(tokenPrivileges), NULL, NULL)) {
45-
LOGE << "AdjustTokenPrivileges failed for current process. Error: " << win::GetErrorDescription(GetLastError());
45+
LOGE << "AdjustTokenPrivileges failed for current process. Error: " << win::GetErrorDescription(GetLastError()) << std::endl;
4646
exit(1);
4747
}
4848

4949
if (!(hProcess = (win::Handle)OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId))) {
50-
LOGE << "Could not open process to attach with elevated privileges. Error: " << win::GetErrorDescription(GetLastError());
50+
LOGE << "Could not open process to attach with elevated privileges. Error: " << win::GetErrorDescription(GetLastError()) << std::endl;
5151
exit(1);
5252
}
5353
}
@@ -64,14 +64,14 @@ namespace LibraryInject
6464
if (pRemoteMem == NULL)
6565
{
6666
auto error = GetLastError();
67-
LOGE << "Could not allocate memory in target process. Error: " << win::GetErrorDescription(error);
67+
LOGE << "Could not allocate memory in target process. Error: " << win::GetErrorDescription(error) << std::endl;
6868
exit(1);
6969
}
7070

7171
if (!WriteProcessMemory(hProcess, pRemoteMem, absDllPath.c_str(), remoteMemSize, NULL))
7272
{
7373
auto error = GetLastError();
74-
LOGE << "WriteProcessMemory failed. Error: " << win::GetErrorDescription(error);
74+
LOGE << "WriteProcessMemory failed. Error: " << win::GetErrorDescription(error) << std::endl;
7575
exit(1);
7676
}
7777
FlushInstructionCache(hProcess, pRemoteMem, remoteMemSize);
@@ -91,7 +91,7 @@ namespace LibraryInject
9191
{
9292
auto error = GetLastError();
9393
LOGE << "Could not create remote thread in target process. Error: " << win::GetErrorDescription(error);
94-
LOGE << "Tip: Check bit-ness of the application and DXGIOverlay.exe.";
94+
LOGE << "Tip: Check bit-ness of the application and DXGIOverlay.exe." << std::endl;
9595
VirtualFreeEx(hProcess, pRemoteMem, 0, MEM_RELEASE);
9696
exit(1);
9797
}
@@ -107,4 +107,38 @@ namespace LibraryInject
107107
auto hTargetProcess = LibraryInject::OpenProcessAndMaybeElevate_(processId);
108108
LibraryInject::InjectDll(hTargetProcess, dllPath);
109109
}
110+
111+
ProcessMap GetProcessNames()
112+
{
113+
ProcessMap processMap;
114+
115+
DWORD processIds[1024];
116+
DWORD processIdsSize;
117+
EnumProcesses(processIds, sizeof(processIds), &processIdsSize);
118+
119+
auto processIdsFound = processIdsSize / sizeof(DWORD);
120+
for (unsigned idx = 0; idx < processIdsFound; idx++)
121+
{
122+
auto processId = processIds[idx];
123+
if (processId == 0)
124+
{
125+
continue;
126+
}
127+
128+
auto hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, processId);
129+
if (!hProcess)
130+
{
131+
continue;
132+
}
133+
134+
CHAR pProcessName[MAX_PATH] = "NOT_FOUND";
135+
GetModuleBaseName(hProcess, 0, pProcessName, sizeof(pProcessName) / sizeof(CHAR));
136+
137+
CloseHandle(hProcess);
138+
139+
processMap[processId] = pProcessName;
140+
}
141+
142+
return processMap;
143+
}
110144
}

IntelPresentMon/FlashInjector/LibraryInject.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@
77

88
namespace LibraryInject
99
{
10+
using ProcessMap = std::unordered_map<uint32_t, std::string>;
1011
void Attach(uint32_t processId, const std::filesystem::path& dllPath);
12+
ProcessMap GetProcessNames();
1113
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#pragma once
22
#include <iostream>
33

4-
#define LOGE std::cerr << "\n"
5-
#define LOGI std::cerr << "\n"
4+
#define LOGE std::cerr
5+
#define LOGI std::cerr

0 commit comments

Comments
 (0)