xref: /aosp_15_r20/external/cronet/base/debug/handle_hooks_win.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2015 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/debug/handle_hooks_win.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <windows.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include <psapi.h>
10*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
11*6777b538SAndroid Build Coastguard Worker 
12*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/win/iat_patch_function.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/win/pe_image.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/win/scoped_handle.h"
18*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
19*6777b538SAndroid Build Coastguard Worker 
20*6777b538SAndroid Build Coastguard Worker namespace {
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker using CloseHandleType = decltype(&::CloseHandle);
23*6777b538SAndroid Build Coastguard Worker using DuplicateHandleType = decltype(&::DuplicateHandle);
24*6777b538SAndroid Build Coastguard Worker 
25*6777b538SAndroid Build Coastguard Worker CloseHandleType g_close_function = nullptr;
26*6777b538SAndroid Build Coastguard Worker DuplicateHandleType g_duplicate_function = nullptr;
27*6777b538SAndroid Build Coastguard Worker 
28*6777b538SAndroid Build Coastguard Worker // The entry point for CloseHandle interception. This function notifies the
29*6777b538SAndroid Build Coastguard Worker // verifier about the handle that is being closed, and calls the original
30*6777b538SAndroid Build Coastguard Worker // function.
CloseHandleHook(HANDLE handle)31*6777b538SAndroid Build Coastguard Worker BOOL WINAPI CloseHandleHook(HANDLE handle) {
32*6777b538SAndroid Build Coastguard Worker   base::win::OnHandleBeingClosed(handle,
33*6777b538SAndroid Build Coastguard Worker                                  base::win::HandleOperation::kCloseHandleHook);
34*6777b538SAndroid Build Coastguard Worker   return g_close_function(handle);
35*6777b538SAndroid Build Coastguard Worker }
36*6777b538SAndroid Build Coastguard Worker 
DuplicateHandleHook(HANDLE source_process,HANDLE source_handle,HANDLE target_process,HANDLE * target_handle,DWORD desired_access,BOOL inherit_handle,DWORD options)37*6777b538SAndroid Build Coastguard Worker BOOL WINAPI DuplicateHandleHook(HANDLE source_process,
38*6777b538SAndroid Build Coastguard Worker                                 HANDLE source_handle,
39*6777b538SAndroid Build Coastguard Worker                                 HANDLE target_process,
40*6777b538SAndroid Build Coastguard Worker                                 HANDLE* target_handle,
41*6777b538SAndroid Build Coastguard Worker                                 DWORD desired_access,
42*6777b538SAndroid Build Coastguard Worker                                 BOOL inherit_handle,
43*6777b538SAndroid Build Coastguard Worker                                 DWORD options) {
44*6777b538SAndroid Build Coastguard Worker   if ((options & DUPLICATE_CLOSE_SOURCE) &&
45*6777b538SAndroid Build Coastguard Worker       (GetProcessId(source_process) == ::GetCurrentProcessId())) {
46*6777b538SAndroid Build Coastguard Worker     base::win::OnHandleBeingClosed(
47*6777b538SAndroid Build Coastguard Worker         source_handle, base::win::HandleOperation::kDuplicateHandleHook);
48*6777b538SAndroid Build Coastguard Worker   }
49*6777b538SAndroid Build Coastguard Worker 
50*6777b538SAndroid Build Coastguard Worker   return g_duplicate_function(source_process, source_handle, target_process,
51*6777b538SAndroid Build Coastguard Worker                               target_handle, desired_access, inherit_handle,
52*6777b538SAndroid Build Coastguard Worker                               options);
53*6777b538SAndroid Build Coastguard Worker }
54*6777b538SAndroid Build Coastguard Worker 
55*6777b538SAndroid Build Coastguard Worker }  // namespace
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker namespace base {
58*6777b538SAndroid Build Coastguard Worker namespace debug {
59*6777b538SAndroid Build Coastguard Worker 
60*6777b538SAndroid Build Coastguard Worker namespace {
61*6777b538SAndroid Build Coastguard Worker 
62*6777b538SAndroid Build Coastguard Worker // Provides a simple way to temporarily change the protection of a memory page.
63*6777b538SAndroid Build Coastguard Worker class AutoProtectMemory {
64*6777b538SAndroid Build Coastguard Worker  public:
AutoProtectMemory()65*6777b538SAndroid Build Coastguard Worker   AutoProtectMemory()
66*6777b538SAndroid Build Coastguard Worker       : changed_(false), address_(nullptr), bytes_(0), old_protect_(0) {}
67*6777b538SAndroid Build Coastguard Worker 
68*6777b538SAndroid Build Coastguard Worker   AutoProtectMemory(const AutoProtectMemory&) = delete;
69*6777b538SAndroid Build Coastguard Worker   AutoProtectMemory& operator=(const AutoProtectMemory&) = delete;
70*6777b538SAndroid Build Coastguard Worker 
~AutoProtectMemory()71*6777b538SAndroid Build Coastguard Worker   ~AutoProtectMemory() { RevertProtection(); }
72*6777b538SAndroid Build Coastguard Worker 
73*6777b538SAndroid Build Coastguard Worker   // Grants write access to a given memory range.
74*6777b538SAndroid Build Coastguard Worker   bool ChangeProtection(void* address, size_t bytes);
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker   // Restores the original page protection.
77*6777b538SAndroid Build Coastguard Worker   void RevertProtection();
78*6777b538SAndroid Build Coastguard Worker 
79*6777b538SAndroid Build Coastguard Worker  private:
80*6777b538SAndroid Build Coastguard Worker   bool changed_;
81*6777b538SAndroid Build Coastguard Worker   raw_ptr<void> address_;
82*6777b538SAndroid Build Coastguard Worker   size_t bytes_;
83*6777b538SAndroid Build Coastguard Worker   DWORD old_protect_;
84*6777b538SAndroid Build Coastguard Worker };
85*6777b538SAndroid Build Coastguard Worker 
ChangeProtection(void * address,size_t bytes)86*6777b538SAndroid Build Coastguard Worker bool AutoProtectMemory::ChangeProtection(void* address, size_t bytes) {
87*6777b538SAndroid Build Coastguard Worker   DCHECK(!changed_);
88*6777b538SAndroid Build Coastguard Worker   DCHECK(address);
89*6777b538SAndroid Build Coastguard Worker 
90*6777b538SAndroid Build Coastguard Worker   // Change the page protection so that we can write.
91*6777b538SAndroid Build Coastguard Worker   MEMORY_BASIC_INFORMATION memory_info;
92*6777b538SAndroid Build Coastguard Worker   if (!VirtualQuery(address, &memory_info, sizeof(memory_info)))
93*6777b538SAndroid Build Coastguard Worker     return false;
94*6777b538SAndroid Build Coastguard Worker 
95*6777b538SAndroid Build Coastguard Worker   DWORD is_executable = (PAGE_EXECUTE | PAGE_EXECUTE_READ |
96*6777b538SAndroid Build Coastguard Worker                          PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) &
97*6777b538SAndroid Build Coastguard Worker                         memory_info.Protect;
98*6777b538SAndroid Build Coastguard Worker 
99*6777b538SAndroid Build Coastguard Worker   DWORD protect = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
100*6777b538SAndroid Build Coastguard Worker   if (!VirtualProtect(address, bytes, protect, &old_protect_))
101*6777b538SAndroid Build Coastguard Worker     return false;
102*6777b538SAndroid Build Coastguard Worker 
103*6777b538SAndroid Build Coastguard Worker   changed_ = true;
104*6777b538SAndroid Build Coastguard Worker   address_ = address;
105*6777b538SAndroid Build Coastguard Worker   bytes_ = bytes;
106*6777b538SAndroid Build Coastguard Worker   return true;
107*6777b538SAndroid Build Coastguard Worker }
108*6777b538SAndroid Build Coastguard Worker 
RevertProtection()109*6777b538SAndroid Build Coastguard Worker void AutoProtectMemory::RevertProtection() {
110*6777b538SAndroid Build Coastguard Worker   if (!changed_)
111*6777b538SAndroid Build Coastguard Worker     return;
112*6777b538SAndroid Build Coastguard Worker 
113*6777b538SAndroid Build Coastguard Worker   DCHECK(address_);
114*6777b538SAndroid Build Coastguard Worker   DCHECK(bytes_);
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker   VirtualProtect(address_, bytes_, old_protect_, &old_protect_);
117*6777b538SAndroid Build Coastguard Worker   changed_ = false;
118*6777b538SAndroid Build Coastguard Worker   address_ = nullptr;
119*6777b538SAndroid Build Coastguard Worker   bytes_ = 0;
120*6777b538SAndroid Build Coastguard Worker   old_protect_ = 0;
121*6777b538SAndroid Build Coastguard Worker }
122*6777b538SAndroid Build Coastguard Worker 
123*6777b538SAndroid Build Coastguard Worker #if defined(ARCH_CPU_32_BITS)
124*6777b538SAndroid Build Coastguard Worker // Performs an EAT interception. Only supported on 32-bit.
EATPatch(HMODULE module,const char * function_name,void * new_function,void ** old_function)125*6777b538SAndroid Build Coastguard Worker void EATPatch(HMODULE module,
126*6777b538SAndroid Build Coastguard Worker               const char* function_name,
127*6777b538SAndroid Build Coastguard Worker               void* new_function,
128*6777b538SAndroid Build Coastguard Worker               void** old_function) {
129*6777b538SAndroid Build Coastguard Worker   if (!module)
130*6777b538SAndroid Build Coastguard Worker     return;
131*6777b538SAndroid Build Coastguard Worker 
132*6777b538SAndroid Build Coastguard Worker   base::win::PEImage pe(module);
133*6777b538SAndroid Build Coastguard Worker   if (!pe.VerifyMagic())
134*6777b538SAndroid Build Coastguard Worker     return;
135*6777b538SAndroid Build Coastguard Worker 
136*6777b538SAndroid Build Coastguard Worker   DWORD* eat_entry = pe.GetExportEntry(function_name);
137*6777b538SAndroid Build Coastguard Worker   if (!eat_entry)
138*6777b538SAndroid Build Coastguard Worker     return;
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker   if (!(*old_function))
141*6777b538SAndroid Build Coastguard Worker     *old_function = pe.RVAToAddr(*eat_entry);
142*6777b538SAndroid Build Coastguard Worker 
143*6777b538SAndroid Build Coastguard Worker   AutoProtectMemory memory;
144*6777b538SAndroid Build Coastguard Worker   if (!memory.ChangeProtection(eat_entry, sizeof(DWORD)))
145*6777b538SAndroid Build Coastguard Worker     return;
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker   // Perform the patch.
148*6777b538SAndroid Build Coastguard Worker   *eat_entry =
149*6777b538SAndroid Build Coastguard Worker       base::checked_cast<DWORD>(reinterpret_cast<uintptr_t>(new_function) -
150*6777b538SAndroid Build Coastguard Worker                                 reinterpret_cast<uintptr_t>(module));
151*6777b538SAndroid Build Coastguard Worker }
152*6777b538SAndroid Build Coastguard Worker #endif  // defined(ARCH_CPU_32_BITS)
153*6777b538SAndroid Build Coastguard Worker 
154*6777b538SAndroid Build Coastguard Worker // Performs an IAT interception.
IATPatch(HMODULE module,const char * function_name,void * new_function,void ** old_function)155*6777b538SAndroid Build Coastguard Worker std::unique_ptr<base::win::IATPatchFunction> IATPatch(HMODULE module,
156*6777b538SAndroid Build Coastguard Worker                                                       const char* function_name,
157*6777b538SAndroid Build Coastguard Worker                                                       void* new_function,
158*6777b538SAndroid Build Coastguard Worker                                                       void** old_function) {
159*6777b538SAndroid Build Coastguard Worker   if (!module)
160*6777b538SAndroid Build Coastguard Worker     return nullptr;
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker   auto patch = std::make_unique<base::win::IATPatchFunction>();
163*6777b538SAndroid Build Coastguard Worker   __try {
164*6777b538SAndroid Build Coastguard Worker     // There is no guarantee that |module| is still loaded at this point.
165*6777b538SAndroid Build Coastguard Worker     if (patch->PatchFromModule(module, "kernel32.dll", function_name,
166*6777b538SAndroid Build Coastguard Worker                                new_function)) {
167*6777b538SAndroid Build Coastguard Worker       return nullptr;
168*6777b538SAndroid Build Coastguard Worker     }
169*6777b538SAndroid Build Coastguard Worker   } __except ((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ||
170*6777b538SAndroid Build Coastguard Worker                GetExceptionCode() == EXCEPTION_GUARD_PAGE ||
171*6777b538SAndroid Build Coastguard Worker                GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR)
172*6777b538SAndroid Build Coastguard Worker                   ? EXCEPTION_EXECUTE_HANDLER
173*6777b538SAndroid Build Coastguard Worker                   : EXCEPTION_CONTINUE_SEARCH) {
174*6777b538SAndroid Build Coastguard Worker     // Leak the patch.
175*6777b538SAndroid Build Coastguard Worker     std::ignore = patch.release();
176*6777b538SAndroid Build Coastguard Worker     return nullptr;
177*6777b538SAndroid Build Coastguard Worker   }
178*6777b538SAndroid Build Coastguard Worker 
179*6777b538SAndroid Build Coastguard Worker   if (!(*old_function)) {
180*6777b538SAndroid Build Coastguard Worker     // Things are probably messed up if each intercepted function points to
181*6777b538SAndroid Build Coastguard Worker     // a different place, but we need only one function to call.
182*6777b538SAndroid Build Coastguard Worker     *old_function = patch->original_function();
183*6777b538SAndroid Build Coastguard Worker   }
184*6777b538SAndroid Build Coastguard Worker   return patch;
185*6777b538SAndroid Build Coastguard Worker }
186*6777b538SAndroid Build Coastguard Worker 
187*6777b538SAndroid Build Coastguard Worker }  // namespace
188*6777b538SAndroid Build Coastguard Worker 
189*6777b538SAndroid Build Coastguard Worker // static
AddIATPatch(HMODULE module)190*6777b538SAndroid Build Coastguard Worker void HandleHooks::AddIATPatch(HMODULE module) {
191*6777b538SAndroid Build Coastguard Worker   if (!module)
192*6777b538SAndroid Build Coastguard Worker     return;
193*6777b538SAndroid Build Coastguard Worker 
194*6777b538SAndroid Build Coastguard Worker   auto close_handle_patch =
195*6777b538SAndroid Build Coastguard Worker       IATPatch(module, "CloseHandle", reinterpret_cast<void*>(&CloseHandleHook),
196*6777b538SAndroid Build Coastguard Worker                reinterpret_cast<void**>(&g_close_function));
197*6777b538SAndroid Build Coastguard Worker   if (!close_handle_patch)
198*6777b538SAndroid Build Coastguard Worker     return;
199*6777b538SAndroid Build Coastguard Worker   // This is intentionally leaked.
200*6777b538SAndroid Build Coastguard Worker   std::ignore = close_handle_patch.release();
201*6777b538SAndroid Build Coastguard Worker 
202*6777b538SAndroid Build Coastguard Worker   auto duplicate_handle_patch = IATPatch(
203*6777b538SAndroid Build Coastguard Worker       module, "DuplicateHandle", reinterpret_cast<void*>(&DuplicateHandleHook),
204*6777b538SAndroid Build Coastguard Worker       reinterpret_cast<void**>(&g_duplicate_function));
205*6777b538SAndroid Build Coastguard Worker   if (!duplicate_handle_patch)
206*6777b538SAndroid Build Coastguard Worker     return;
207*6777b538SAndroid Build Coastguard Worker   // This is intentionally leaked.
208*6777b538SAndroid Build Coastguard Worker   std::ignore = duplicate_handle_patch.release();
209*6777b538SAndroid Build Coastguard Worker }
210*6777b538SAndroid Build Coastguard Worker 
211*6777b538SAndroid Build Coastguard Worker #if defined(ARCH_CPU_32_BITS)
212*6777b538SAndroid Build Coastguard Worker // static
AddEATPatch()213*6777b538SAndroid Build Coastguard Worker void HandleHooks::AddEATPatch() {
214*6777b538SAndroid Build Coastguard Worker   // An attempt to restore the entry on the table at destruction is not safe.
215*6777b538SAndroid Build Coastguard Worker   EATPatch(GetModuleHandleA("kernel32.dll"), "CloseHandle",
216*6777b538SAndroid Build Coastguard Worker            reinterpret_cast<void*>(&CloseHandleHook),
217*6777b538SAndroid Build Coastguard Worker            reinterpret_cast<void**>(&g_close_function));
218*6777b538SAndroid Build Coastguard Worker   EATPatch(GetModuleHandleA("kernel32.dll"), "DuplicateHandle",
219*6777b538SAndroid Build Coastguard Worker            reinterpret_cast<void*>(&DuplicateHandleHook),
220*6777b538SAndroid Build Coastguard Worker            reinterpret_cast<void**>(&g_duplicate_function));
221*6777b538SAndroid Build Coastguard Worker }
222*6777b538SAndroid Build Coastguard Worker #endif  // defined(ARCH_CPU_32_BITS)
223*6777b538SAndroid Build Coastguard Worker 
224*6777b538SAndroid Build Coastguard Worker // static
PatchLoadedModules()225*6777b538SAndroid Build Coastguard Worker void HandleHooks::PatchLoadedModules() {
226*6777b538SAndroid Build Coastguard Worker   const DWORD kSize = 256;
227*6777b538SAndroid Build Coastguard Worker   DWORD returned;
228*6777b538SAndroid Build Coastguard Worker   auto modules = std::make_unique<HMODULE[]>(kSize);
229*6777b538SAndroid Build Coastguard Worker   if (!::EnumProcessModules(GetCurrentProcess(), modules.get(),
230*6777b538SAndroid Build Coastguard Worker                             kSize * sizeof(HMODULE), &returned)) {
231*6777b538SAndroid Build Coastguard Worker     return;
232*6777b538SAndroid Build Coastguard Worker   }
233*6777b538SAndroid Build Coastguard Worker   returned /= sizeof(HMODULE);
234*6777b538SAndroid Build Coastguard Worker   returned = std::min(kSize, returned);
235*6777b538SAndroid Build Coastguard Worker 
236*6777b538SAndroid Build Coastguard Worker   for (DWORD current = 0; current < returned; current++) {
237*6777b538SAndroid Build Coastguard Worker     AddIATPatch(modules[current]);
238*6777b538SAndroid Build Coastguard Worker   }
239*6777b538SAndroid Build Coastguard Worker }
240*6777b538SAndroid Build Coastguard Worker 
241*6777b538SAndroid Build Coastguard Worker }  // namespace debug
242*6777b538SAndroid Build Coastguard Worker }  // namespace base
243