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