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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
|
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome_elf/blacklist/blacklist.h"
#include <string.h>
#include "base/basictypes.h"
#include "chrome_elf/blacklist/blacklist_interceptions.h"
#include "sandbox/win/src/interception_internal.h"
#include "sandbox/win/src/internal_types.h"
#include "sandbox/win/src/sandbox_utils.h"
#include "sandbox/win/src/service_resolver.h"
// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
extern "C" IMAGE_DOS_HEADER __ImageBase;
namespace blacklist{
const wchar_t* g_troublesome_dlls[kTroublesomeDllsMaxCount] = {};
int g_troublesome_dlls_cur_index = 0;
const wchar_t kRegistryBeaconPath[] = L"SOFTWARE\\Google\\Chrome\\BLBeacon";
} // namespace blacklist
// Allocate storage for thunks in a RWX page of this module to save on doing
// an extra allocation at run time.
#if !defined(_WIN64)
// 64-bit images appear to not support writeable and executable pages.
// This would yield compile warning C4330.
// TODO(robertshield): Add 64 bit support.
#pragma section(".crthunk",read,write,execute)
__declspec(allocate(".crthunk")) sandbox::ThunkData g_thunk_storage;
#endif
namespace {
enum Version {
VERSION_PRE_XP_SP2 = 0, // Not supported.
VERSION_XP_SP2,
VERSION_SERVER_2003, // Also includes XP Pro x64 and Server 2003 R2.
VERSION_VISTA, // Also includes Windows Server 2008.
VERSION_WIN7, // Also includes Windows Server 2008 R2.
VERSION_WIN8, // Also includes Windows Server 2012.
VERSION_WIN8_1,
VERSION_WIN_LAST, // Indicates error condition.
};
// Whether a process is running under WOW64 (the wrapper that allows 32-bit
// processes to run on 64-bit versions of Windows). This will return
// WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit
// Chrome on 64-bit Windows". WOW64_UNKNOWN means "an error occurred", e.g.
// the process does not have sufficient access rights to determine this.
enum WOW64Status {
WOW64_DISABLED,
WOW64_ENABLED,
WOW64_UNKNOWN,
};
WOW64Status GetWOW64StatusForCurrentProcess() {
typedef BOOL (WINAPI* IsWow64ProcessFunc)(HANDLE, PBOOL);
IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>(
GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process"));
if (!is_wow64_process)
return WOW64_DISABLED;
BOOL is_wow64 = FALSE;
if (!(*is_wow64_process)(GetCurrentProcess(), &is_wow64))
return WOW64_UNKNOWN;
return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED;
}
class OSInfo {
public:
struct VersionNumber {
int major;
int minor;
int build;
};
struct ServicePack {
int major;
int minor;
};
OSInfo() {
OSVERSIONINFOEX version_info = { sizeof(version_info) };
GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info));
version_number_.major = version_info.dwMajorVersion;
version_number_.minor = version_info.dwMinorVersion;
version_number_.build = version_info.dwBuildNumber;
if ((version_number_.major == 5) && (version_number_.minor > 0)) {
// Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003.
version_ = (version_number_.minor == 1) ? VERSION_XP_SP2 :
VERSION_SERVER_2003;
if (version_ == VERSION_XP_SP2 && version_info.wServicePackMajor < 2)
version_ = VERSION_PRE_XP_SP2;
} else if (version_number_.major == 6) {
switch (version_number_.minor) {
case 0:
// Treat Windows Server 2008 the same as Windows Vista.
version_ = VERSION_VISTA;
break;
case 1:
// Treat Windows Server 2008 R2 the same as Windows 7.
version_ = VERSION_WIN7;
break;
case 2:
// Treat Windows Server 2012 the same as Windows 8.
version_ = VERSION_WIN8;
break;
default:
version_ = VERSION_WIN8_1;
break;
}
} else if (version_number_.major > 6) {
version_ = VERSION_WIN_LAST;
} else {
version_ = VERSION_PRE_XP_SP2;
}
service_pack_.major = version_info.wServicePackMajor;
service_pack_.minor = version_info.wServicePackMinor;
}
Version version() const { return version_; }
VersionNumber version_number() const { return version_number_; }
ServicePack service_pack() const { return service_pack_; }
private:
Version version_;
VersionNumber version_number_;
ServicePack service_pack_;
DISALLOW_COPY_AND_ASSIGN(OSInfo);
};
bool IsNonBrowserProcess() {
wchar_t* command_line = GetCommandLine();
return (command_line && wcsstr(command_line, L"--type"));
}
} // namespace
namespace blacklist {
bool CreateBeacon() {
HKEY beacon_key = NULL;
DWORD disposition = 0;
LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER,
kRegistryBeaconPath,
0,
NULL,
0,
KEY_WRITE,
NULL,
&beacon_key,
&disposition);
bool success = (result == ERROR_SUCCESS &&
disposition != REG_OPENED_EXISTING_KEY);
if (result == ERROR_SUCCESS)
::RegCloseKey(beacon_key);
return success;
}
bool ClearBeacon() {
LONG result = ::RegDeleteKey(HKEY_CURRENT_USER, kRegistryBeaconPath);
return (result == ERROR_SUCCESS);
}
bool AddDllToBlacklist(const wchar_t* dll_name) {
if (g_troublesome_dlls_cur_index >= kTroublesomeDllsMaxCount)
return false;
for (int i = 0; i < g_troublesome_dlls_cur_index; ++i) {
if (!wcscmp(g_troublesome_dlls[i], dll_name))
return true;
}
// Copy string to blacklist.
wchar_t* str_buffer = new wchar_t[wcslen(dll_name) + 1];
wcscpy(str_buffer, dll_name);
g_troublesome_dlls[g_troublesome_dlls_cur_index] = str_buffer;
g_troublesome_dlls_cur_index++;
return true;
}
bool RemoveDllFromBlacklist(const wchar_t* dll_name) {
for (int i = 0; i < g_troublesome_dlls_cur_index; ++i) {
if (!wcscmp(g_troublesome_dlls[i], dll_name)) {
// Found the thing to remove. Delete it then replace it with the last
// element.
g_troublesome_dlls_cur_index--;
delete[] g_troublesome_dlls[i];
g_troublesome_dlls[i] = g_troublesome_dlls[g_troublesome_dlls_cur_index];
g_troublesome_dlls[g_troublesome_dlls_cur_index] = NULL;
return true;
}
}
return false;
}
bool Initialize(bool force) {
#if defined(_WIN64)
// TODO(robertshield): Implement 64-bit support by providing 64-bit
// interceptors.
return false;
#endif
// Check to see that we found the functions we need in ntdll.
if (!InitializeInterceptImports())
return false;
// Check to see if this is a non-browser process, abort if so.
if (IsNonBrowserProcess())
return false;
// Check to see if a beacon is present, abort if so.
if (!force && !CreateBeacon())
return false;
// Don't try blacklisting on unsupported OS versions.
OSInfo os_info;
if (os_info.version() <= VERSION_PRE_XP_SP2)
return false;
// Pseudo-handle, no need to close.
HANDLE current_process = ::GetCurrentProcess();
// Tells the resolver to patch already patched functions.
const bool kRelaxed = true;
// Create a thunk via the appropriate ServiceResolver instance.
sandbox::ServiceResolverThunk* thunk;
#if defined(_WIN64)
// TODO(robertshield): Use the appropriate thunk for 64-bit support
// when said support is implemented.
#else
if (GetWOW64StatusForCurrentProcess() == WOW64_ENABLED) {
if (os_info.version() >= VERSION_WIN8)
thunk = new sandbox::Wow64W8ResolverThunk(current_process, kRelaxed);
else
thunk = new sandbox::Wow64ResolverThunk(current_process, kRelaxed);
} else if (os_info.version() >= VERSION_WIN8) {
thunk = new sandbox::Win8ResolverThunk(current_process, kRelaxed);
} else {
thunk = new sandbox::ServiceResolverThunk(current_process, kRelaxed);
}
#endif
#if defined(_WIN64)
BYTE* thunk_storage = new BYTE[sizeof(sandbox::ThunkData)];
#else
BYTE* thunk_storage = reinterpret_cast<BYTE*>(&g_thunk_storage);
#endif
thunk->AllowLocalPatches();
// Get ntdll base, target name, interceptor address,
NTSTATUS ret = thunk->Setup(::GetModuleHandle(sandbox::kNtdllName),
reinterpret_cast<void*>(&__ImageBase),
"NtMapViewOfSection",
NULL,
&blacklist::BlNtMapViewOfSection,
thunk_storage,
sizeof(sandbox::ThunkData),
NULL);
delete thunk;
return NT_SUCCESS(ret);
}
} // namespace blacklist
|