| OLD | NEW | 
 | (Empty) | 
|    1 // Copyright 2017 The Chromium Authors. All rights reserved. |  | 
|    2 // Use of this source code is governed by a BSD-style license that can be |  | 
|    3 // found in the LICENSE file. |  | 
|    4  |  | 
|    5 #include "chrome/browser/conflicts/module_event_sink_impl_win.h" |  | 
|    6  |  | 
|    7 #include <windows.h> |  | 
|    8 #include <psapi.h> |  | 
|    9  |  | 
|   10 #include <utility> |  | 
|   11  |  | 
|   12 #include "base/bind.h" |  | 
|   13 #include "base/callback.h" |  | 
|   14 #include "base/files/file_path.h" |  | 
|   15 #include "base/macros.h" |  | 
|   16 #include "base/memory/ptr_util.h" |  | 
|   17 #include "base/strings/string_piece.h" |  | 
|   18 #include "chrome/browser/conflicts/module_database_win.h" |  | 
|   19 #include "chrome/common/conflicts/module_watcher_win.h" |  | 
|   20 #include "content/public/browser/browser_thread.h" |  | 
|   21 #include "mojo/public/cpp/bindings/strong_binding.h" |  | 
|   22  |  | 
|   23 namespace { |  | 
|   24  |  | 
|   25 // Gets the process creation time associated with the given process. |  | 
|   26 bool GetProcessCreationTime(base::ProcessHandle process, |  | 
|   27                             uint64_t* creation_time) { |  | 
|   28   FILETIME creation_ft = {}; |  | 
|   29   FILETIME exit_ft = {}; |  | 
|   30   FILETIME kernel_ft = {}; |  | 
|   31   FILETIME user_ft = {}; |  | 
|   32   if (!::GetProcessTimes(process, &creation_ft, &exit_ft, &kernel_ft, |  | 
|   33                          &user_ft)) { |  | 
|   34     return false; |  | 
|   35   } |  | 
|   36   *creation_time = (static_cast<uint64_t>(creation_ft.dwHighDateTime) << 32) | |  | 
|   37                    static_cast<uint64_t>(creation_ft.dwLowDateTime); |  | 
|   38   return true; |  | 
|   39 } |  | 
|   40  |  | 
|   41 // Gets the path of the module in the provided remote process. Returns true on |  | 
|   42 // success, false otherwise. |  | 
|   43 bool GetModulePath(base::ProcessHandle process, |  | 
|   44                    HMODULE module, |  | 
|   45                    base::FilePath* path) { |  | 
|   46   std::vector<wchar_t> temp_path(MAX_PATH); |  | 
|   47   size_t length = 0; |  | 
|   48   while (true) { |  | 
|   49     length = ::GetModuleFileNameEx(process, module, temp_path.data(), |  | 
|   50                                    temp_path.size()); |  | 
|   51     if (length == 0) |  | 
|   52       return false; |  | 
|   53     if (length < temp_path.size()) |  | 
|   54       break; |  | 
|   55     // The entire buffer was consumed, so grow it to ensure the result wasn't |  | 
|   56     // actually truncated. |  | 
|   57     temp_path.resize(2 * temp_path.size()); |  | 
|   58   } |  | 
|   59  |  | 
|   60   *path = base::FilePath(base::StringPiece16(temp_path.data(), length)); |  | 
|   61   return true; |  | 
|   62 } |  | 
|   63  |  | 
|   64 // Gets the size of a module in a remote process. Returns true on success, false |  | 
|   65 // otherwise. |  | 
|   66 bool GetModuleSize(base::ProcessHandle process, |  | 
|   67                    HMODULE module, |  | 
|   68                    uint32_t* size) { |  | 
|   69   MODULEINFO info = {}; |  | 
|   70   if (!::GetModuleInformation(process, module, &info, sizeof(info))) |  | 
|   71     return false; |  | 
|   72   *size = info.SizeOfImage; |  | 
|   73   return true; |  | 
|   74 } |  | 
|   75  |  | 
|   76 // Reads the typed data from a remote process. Returns true on success, false |  | 
|   77 // otherwise. |  | 
|   78 template <typename T> |  | 
|   79 bool ReadRemoteData(base::ProcessHandle process, uint64_t address, T* data) { |  | 
|   80   const void* typed_address = |  | 
|   81       reinterpret_cast<const void*>(static_cast<uintptr_t>(address)); |  | 
|   82   SIZE_T bytes_read = 0; |  | 
|   83   if (!::ReadProcessMemory(process, typed_address, &data, sizeof(data), |  | 
|   84                            &bytes_read)) { |  | 
|   85     return false; |  | 
|   86   } |  | 
|   87   if (bytes_read != sizeof(data)) |  | 
|   88     return false; |  | 
|   89   return true; |  | 
|   90 } |  | 
|   91  |  | 
|   92 // Reads the time date stamp from the module loaded in the provided remote |  | 
|   93 // |process| at the provided remote |load_address|. |  | 
|   94 bool GetModuleTimeDateStamp(base::ProcessHandle process, |  | 
|   95                             uint64_t load_address, |  | 
|   96                             uint32_t* time_date_stamp) { |  | 
|   97   uint64_t address = load_address + offsetof(IMAGE_DOS_HEADER, e_lfanew); |  | 
|   98   LONG e_lfanew = 0; |  | 
|   99   if (!ReadRemoteData(process, address, &e_lfanew)) |  | 
|  100     return false; |  | 
|  101  |  | 
|  102   address = load_address + e_lfanew + offsetof(IMAGE_NT_HEADERS, FileHeader) + |  | 
|  103             offsetof(IMAGE_FILE_HEADER, TimeDateStamp); |  | 
|  104   DWORD temp = 0; |  | 
|  105   if (!ReadRemoteData(process, address, &temp)) |  | 
|  106     return false; |  | 
|  107  |  | 
|  108   *time_date_stamp = temp; |  | 
|  109   return true; |  | 
|  110 } |  | 
|  111  |  | 
|  112 }  // namespace |  | 
|  113  |  | 
|  114 ModuleEventSinkImpl::ModuleEventSinkImpl(base::ProcessHandle process, |  | 
|  115                                          content::ProcessType process_type, |  | 
|  116                                          ModuleDatabase* module_database) |  | 
|  117     : process_(process), |  | 
|  118       module_database_(module_database), |  | 
|  119       process_id_(0), |  | 
|  120       creation_time_(0), |  | 
|  121       in_error_(false) { |  | 
|  122   // Failing to get basic process information means this channel should not |  | 
|  123   // continue to forward data, thus it is marked as being in error. |  | 
|  124   process_id_ = ::GetProcessId(process_); |  | 
|  125   if (!GetProcessCreationTime(process_, &creation_time_)) { |  | 
|  126     in_error_ = true; |  | 
|  127     return; |  | 
|  128   } |  | 
|  129   module_database->OnProcessStarted(process_id_, creation_time_, process_type); |  | 
|  130 } |  | 
|  131  |  | 
|  132 ModuleEventSinkImpl::~ModuleEventSinkImpl() = default; |  | 
|  133  |  | 
|  134 // static |  | 
|  135 void ModuleEventSinkImpl::Create(base::ProcessHandle process, |  | 
|  136                                  content::ProcessType process_type, |  | 
|  137                                  ModuleDatabase* module_database, |  | 
|  138                                  mojom::ModuleEventSinkRequest request) { |  | 
|  139   DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |  | 
|  140   auto module_event_sink_impl = base::MakeUnique<ModuleEventSinkImpl>( |  | 
|  141       process, process_type, module_database); |  | 
|  142   base::Closure error_handler = base::Bind( |  | 
|  143       &ModuleDatabase::OnProcessEnded, base::Unretained(module_database), |  | 
|  144       module_event_sink_impl->process_id_, |  | 
|  145       module_event_sink_impl->creation_time_); |  | 
|  146   auto binding = mojo::MakeStrongBinding(std::move(module_event_sink_impl), |  | 
|  147                                          std::move(request)); |  | 
|  148   binding->set_connection_error_handler(error_handler); |  | 
|  149 } |  | 
|  150  |  | 
|  151 void ModuleEventSinkImpl::OnModuleEvent(mojom::ModuleEventType event_type, |  | 
|  152                                         uint64_t load_address) { |  | 
|  153   if (in_error_) |  | 
|  154     return; |  | 
|  155  |  | 
|  156   // Mojo takes care of validating |event_type|, so only |load_address| needs to |  | 
|  157   // be checked. Load addresses must be aligned with the allocation granularity |  | 
|  158   // which is at least 64KB on any supported Windows OS. |  | 
|  159   if (load_address == 0 || load_address % (64 * 1024) != 0) |  | 
|  160     return; |  | 
|  161  |  | 
|  162   switch (event_type) { |  | 
|  163     case mojom::ModuleEventType::MODULE_ALREADY_LOADED: |  | 
|  164     case mojom::ModuleEventType::MODULE_LOADED: |  | 
|  165       return OnModuleLoad(load_address); |  | 
|  166  |  | 
|  167     case mojom::ModuleEventType::MODULE_UNLOADED: |  | 
|  168       return OnModuleUnload(load_address); |  | 
|  169   } |  | 
|  170 } |  | 
|  171  |  | 
|  172 void ModuleEventSinkImpl::OnModuleLoad(uint64_t load_address) { |  | 
|  173   if (in_error_) |  | 
|  174     return; |  | 
|  175  |  | 
|  176   // The |load_address| is a unique key to a module in a remote process. If |  | 
|  177   // there is a valid module there then the following queries should all pass. |  | 
|  178   // If any of them fail then the load event is silently swallowed. The entire |  | 
|  179   // channel is not marked as being in an error mode, as later events may be |  | 
|  180   // well formed. |  | 
|  181  |  | 
|  182   // Convert the |load_address| to a module handle. |  | 
|  183   HMODULE module = |  | 
|  184       reinterpret_cast<HMODULE>(static_cast<uintptr_t>(load_address)); |  | 
|  185  |  | 
|  186   // Look up the various pieces of module metadata in the remote process. |  | 
|  187  |  | 
|  188   base::FilePath module_path; |  | 
|  189   if (!GetModulePath(process_, module, &module_path)) |  | 
|  190     return; |  | 
|  191  |  | 
|  192   uint32_t module_size = 0; |  | 
|  193   if (!GetModuleSize(process_, module, &module_size)) |  | 
|  194     return; |  | 
|  195  |  | 
|  196   uint32_t module_time_date_stamp = 0; |  | 
|  197   if (!GetModuleTimeDateStamp(process_, load_address, &module_time_date_stamp)) |  | 
|  198     return; |  | 
|  199  |  | 
|  200   // Forward this to the module database. |  | 
|  201   module_database_->OnModuleLoad(process_id_, creation_time_, module_path, |  | 
|  202                                  module_size, module_time_date_stamp, |  | 
|  203                                  load_address); |  | 
|  204 } |  | 
|  205  |  | 
|  206 void ModuleEventSinkImpl::OnModuleUnload(uint64_t load_address) { |  | 
|  207   // Forward this directly to the module database. |  | 
|  208   module_database_->OnModuleUnload(process_id_, creation_time_, |  | 
|  209                                    static_cast<uintptr_t>(load_address)); |  | 
|  210 } |  | 
| OLD | NEW |