| 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 |