1 // Copyright 2015 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <intrin.h>
16 #include <stdint.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <wchar.h>
20 #include <windows.h>
21 #include <winternl.h>
22
23 namespace {
24
UnicodeStringEndsWithCaseInsensitive(const UNICODE_STRING & us,const wchar_t * ends_with)25 bool UnicodeStringEndsWithCaseInsensitive(const UNICODE_STRING& us,
26 const wchar_t* ends_with) {
27 const size_t len = wcslen(ends_with);
28 // Recall that UNICODE_STRING.Length is in bytes, not characters.
29 const size_t us_len_in_chars = us.Length / sizeof(wchar_t);
30 if (us_len_in_chars < len)
31 return false;
32 return _wcsnicmp(&us.Buffer[us_len_in_chars - len], ends_with, len) == 0;
33 }
34
35 } // namespace
36
37 // A simple binary to be loaded and inspected by ProcessInfo.
wmain(int argc,wchar_t ** argv)38 int wmain(int argc, wchar_t** argv) {
39 if (argc != 2)
40 abort();
41
42 // Get a handle to the event we use to communicate with our parent.
43 HANDLE done_event = CreateEvent(nullptr, true, false, argv[1]);
44 if (!done_event)
45 abort();
46
47 // Load an unusual module (that we don't depend upon) so we can do an
48 // existence check. It's also important that these DLLs don't depend on
49 // any other DLLs, otherwise there'll be additional modules in the list, which
50 // the test expects not to be there.
51 if (!LoadLibrary(L"lz32.dll"))
52 abort();
53
54 // Load another unusual module so we can destroy its FullDllName field in the
55 // PEB to test corrupted name reads.
56 static constexpr wchar_t kCorruptableDll[] = L"kbdurdu.dll";
57 if (!LoadLibrary(kCorruptableDll))
58 abort();
59
60 // Find and corrupt the buffer pointer to the name in the PEB.
61 HINSTANCE ntdll = GetModuleHandle(L"ntdll.dll");
62 decltype(NtQueryInformationProcess)* nt_query_information_process =
63 reinterpret_cast<decltype(NtQueryInformationProcess)*>(
64 GetProcAddress(ntdll, "NtQueryInformationProcess"));
65 if (!nt_query_information_process)
66 abort();
67
68 PROCESS_BASIC_INFORMATION pbi;
69 if (nt_query_information_process(GetCurrentProcess(),
70 ProcessBasicInformation,
71 &pbi,
72 sizeof(pbi),
73 nullptr) < 0) {
74 abort();
75 }
76
77 PEB_LDR_DATA* ldr = pbi.PebBaseAddress->Ldr;
78 LIST_ENTRY* head = &ldr->InMemoryOrderModuleList;
79 LIST_ENTRY* next = head->Flink;
80 while (next != head) {
81 LDR_DATA_TABLE_ENTRY* entry =
82 CONTAINING_RECORD(next, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
83 if (UnicodeStringEndsWithCaseInsensitive(entry->FullDllName,
84 kCorruptableDll)) {
85 // Corrupt the pointer to the name.
86 entry->FullDllName.Buffer = 0;
87 }
88 next = next->Flink;
89 }
90
91 HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
92 if (out == INVALID_HANDLE_VALUE)
93 abort();
94 // We just want any valid address that's known to be code.
95 uint64_t code_address = reinterpret_cast<uint64_t>(_ReturnAddress());
96 DWORD bytes_written;
97 if (!WriteFile(
98 out, &code_address, sizeof(code_address), &bytes_written, nullptr) ||
99 bytes_written != sizeof(code_address)) {
100 abort();
101 }
102
103 if (WaitForSingleObject(done_event, INFINITE) != WAIT_OBJECT_0)
104 abort();
105
106 CloseHandle(done_event);
107
108 return EXIT_SUCCESS;
109 }
110