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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
|
/* Copyright (C) 2011-2013, Benjamin Jemlich <pcgod@users.sourceforge.net>
Copyright (C) 2013-2015, Mikkel Krautz <mikkel@krautz.dk>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of the Mumble Developers nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <windows.h>
#include <shlwapi.h>
#include <stdio.h>
#include <shellapi.h>
#include <string>
#include <vector>
#include "../overlay.h"
#include "overlay_exe.h"
#define UNUSED(x) ((void)x)
typedef int (*OverlayHelperProcessMain)(unsigned int magic, HANDLE parent);
// Signal to the overlay DLL that it should not inject
// into this process.
extern "C" __declspec(dllexport) void mumbleSelfDetection() {};
// Alert shows a fatal error dialog and waits for the user to click OK.
static void Alert(LPCWSTR title, LPCWSTR msg) {
MessageBox(NULL, msg, title, MB_OK|MB_ICONERROR);
}
// GetExecutableDirPath returns the directory that
// mumble_ol.exe resides in.
static std::wstring GetExecutableDirPath() {
wchar_t path[MAX_PATH];
if (GetModuleFileNameW(NULL, path, MAX_PATH) == 0)
return std::wstring();
if (!PathRemoveFileSpecW(path))
return std::wstring();
std::wstring exePath(path);
return exePath.append(L"\\");
}
// ConfigureEnvironment prepares mumble_ol.exe's environment to
// run mumble_ol.dll's OverlayHelperProcessMain() function.
static bool ConfigureEnvironment() {
std::wstring exePath = GetExecutableDirPath();
// Remove the current directory from the DLL search path.
if (!SetDllDirectoryW(L""))
return false;
// Set mumble_ol.exe's directory as the current working directory.
if (!SetCurrentDirectoryW(exePath.c_str()))
return false;
return true;
}
// GetAbsoluteMumbleOverlayDllPath returns the absolute path to
// mumble_ol.dll - the DLL containing the Mumble overlay code.
static std::wstring GetAbsoluteMumbleOverlayDllPath() {
std::wstring exePath = GetExecutableDirPath();
if (exePath.empty())
return std::wstring();
std::wstring absDLLPath(exePath);
absDLLPath.append(L"\\");
absDLLPath.append(MUMBLE_OVERLAY_DLL_NAME);
return absDLLPath;
}
// GetCommandLineArgs returns the command line arguments
// passed to the process.
// If the returned vector has a length of 0, an unknown
// error occurred.
static std::vector<std::wstring> GetCommandLineArgs() {
std::vector<std::wstring> args;
LPWSTR cmdLine = GetCommandLine();
if (cmdLine == NULL) {
return args;
}
int argc = 0;
LPWSTR *argv = CommandLineToArgvW(cmdLine, &argc);
if (argv == NULL) {
return args;
}
for (int i = 0; i < argc; i++) {
args.push_back(std::wstring(argv[i]));
}
return args;
}
int main(int argc, char **argv) {
UNUSED(argc);
UNUSED(argv);
// Mumble passes the OVERLAY_MAGIC_NUMBER it was built
// with the first argument to this helper process.
//
// This is done for two reasons.
//
// The first reason is that we need to ensure
// compatibility between Mumble, the overlay helper,
// and the overlay itself.
//
// The second reason is that it is an easy way to catch
// users accidentally double-clicking on the overlay
// helper's EXE file. We can detect these non-Mumble
// initiated launches by checking if we were passed any
// arguments at all. If no parameters are passed, we
// display a nice alert dialog directing users to
// 'mumble.exe' instead.
unsigned int magic = 0;
HANDLE parent = 0;
{
std::vector<std::wstring> args = GetCommandLineArgs();
// If there is only a single argument, it's the program name.
// That probably means that a user has double-clicked
// the executable. Tell them to run 'mumble.exe' instead.
//
// This also handles the case where GetCommandLineArgs returns
// an empty vector (the error case).
if (args.size() <= 1) {
Alert(L"Mumble Overlay", L"This program is not meant to be run by itself. Run 'mumble.exe' instead.");
return OVERLAY_HELPER_ERROR_EXE_NO_ARGUMENTS;
}
// The Mumble process passes the overlay magic number,
// and a HANDLE in numeric form as its only two arguments.
// We must have both of them to continue.
if (args.size() < 3) {
return OVERLAY_HELPER_ERROR_TOO_FEW_ARGUMENTS;
}
std::wstring magicNumberStr = args[1];
std::wstring handleStr = args[2];
try {
unsigned long passedInMagic = std::stoul(magicNumberStr);
magic = static_cast<unsigned int>(passedInMagic);
} catch (std::exception &) {
return OVERLAY_HELPER_ERROR_EXE_INVALID_MAGIC_ARGUMENT;
}
try {
unsigned long passedInHandle = std::stoul(handleStr);
parent = reinterpret_cast<HANDLE>(passedInHandle & 0xFFFFFFFFUL);
} catch(std::exception &) {
return OVERLAY_HELPER_ERROR_EXE_INVALID_HANDLE_ARGUMENT;
}
}
if (magic != OVERLAY_MAGIC_NUMBER) {
return OVERLAY_HELPER_ERROR_EXE_MAGIC_MISMATCH;
}
if (!ConfigureEnvironment()) {
return OVERLAY_HELPER_ERROR_EXE_CONFIGURE_ENVIRONMENT;
}
std::wstring absDLLPath = GetAbsoluteMumbleOverlayDllPath();
if (absDLLPath.empty()) {
return OVERLAY_HELPER_ERROR_EXE_GET_DLL_PATH;
}
HMODULE dll = LoadLibraryExW(absDLLPath.c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (!dll) {
return OVERLAY_HELPER_ERROR_EXE_LOAD_DLL;
}
OverlayHelperProcessMain entryPoint = reinterpret_cast<OverlayHelperProcessMain>(GetProcAddress(dll, "OverlayHelperProcessMain"));
if (!entryPoint) {
return OVERLAY_HELPER_ERROR_EXE_LOOKUP_ENTRY_POINT;
}
return entryPoint(magic, parent);
}
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, wchar_t *cmdArg, int cmdShow) {
UNUSED(instance);
UNUSED(prevInstance);
UNUSED(cmdArg);
UNUSED(cmdShow);
return main(0, NULL);
}
|