1 : // Copyright 2012 Google Inc. 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 "syzygy/agent/common/process_utils.h"
16 :
17 : #include <psapi.h>
18 :
19 : #include "base/logging.h"
20 : #include "base/win/pe_image.h"
21 : #include "syzygy/common/com_utils.h"
22 : #include "syzygy/common/path_util.h"
23 : #include "syzygy/trace/client/rpc_session.h"
24 :
25 : namespace agent {
26 : namespace common {
27 :
28 : namespace {
29 :
30 : // Accessing a module acquired from process iteration calls is inherently racy,
31 : // as we don't hold any kind of reference to the module, and so the module
32 : // could be unloaded while we're accessing it.
33 : bool CaptureModuleInformation(const base::win::PEImage& image,
34 : size_t* module_base_size,
35 : uint32* module_checksum,
36 i : uint32* module_time_date_stamp) {
37 i : DCHECK(module_base_size != NULL);
38 i : DCHECK(module_checksum != NULL);
39 i : DCHECK(module_time_date_stamp != NULL);
40 :
41 i : __try {
42 i : const IMAGE_NT_HEADERS* nt_headers = image.GetNTHeaders();
43 i : *module_base_size = nt_headers->OptionalHeader.SizeOfImage;
44 i : *module_checksum = nt_headers->OptionalHeader.CheckSum;
45 i : *module_time_date_stamp = nt_headers->FileHeader.TimeDateStamp;
46 :
47 : // Make reasonably sure we're actually looking at a module.
48 i : if (!image.VerifyMagic())
49 i : return false;
50 i : } __except(EXCEPTION_EXECUTE_HANDLER) {
51 i : return false;
52 i : }
53 :
54 i : return true;
55 i : }
56 :
57 : } // namespace
58 :
59 : bool LogModule(HMODULE module,
60 : trace::client::RpcSession* session,
61 E : trace::client::TraceFileSegment* segment) {
62 E : DCHECK(module != NULL);
63 E : DCHECK(session != NULL);
64 E : DCHECK(segment != NULL);
65 :
66 : // See whether we can acquire the module data.
67 E : base::win::PEImage image(module);
68 E : size_t module_base_size = 0;
69 E : uint32 module_checksum = 0;
70 E : uint32 module_time_date_stamp = 0;
71 : if (!CaptureModuleInformation(image,
72 : &module_base_size,
73 : &module_checksum,
74 E : &module_time_date_stamp)) {
75 E : LOG(ERROR) << "Failed to capture module information.";
76 E : return false;
77 : }
78 :
79 : // Make sure the event we're about to write will fit.
80 : if (!segment->CanAllocate(sizeof(TraceModuleData)) &&
81 E : !session->ExchangeBuffer(segment)) {
82 : // Failed to allocate a new segment.
83 i : LOG(ERROR) << "Failed to exchange buffer.";
84 i : return false;
85 : }
86 E : DCHECK(segment->CanAllocate(sizeof(TraceModuleData)));
87 :
88 : // Allocate a record in the log.
89 : TraceModuleData* module_event = reinterpret_cast<TraceModuleData*>(
90 : segment->AllocateTraceRecordImpl(
91 E : TRACE_PROCESS_ATTACH_EVENT, sizeof(TraceModuleData)));
92 E : DCHECK(module_event != NULL);
93 :
94 E : module_event->module_base_addr = module;
95 E : module_event->module_base_size = module_base_size;
96 E : module_event->module_checksum = module_checksum;
97 E : module_event->module_time_date_stamp = module_time_date_stamp;
98 :
99 E : wchar_t module_name[MAX_PATH] = { 0 };
100 : if (::GetMappedFileName(::GetCurrentProcess(), module,
101 E : module_name, arraysize(module_name)) == 0) {
102 i : DWORD error = ::GetLastError();
103 i : LOG(ERROR) << "Failed to get module name: " << ::common::LogWe(error)
104 : << ".";
105 i : return false;
106 : }
107 E : base::FilePath device_path(module_name);
108 E : base::FilePath drive_path;
109 E : if (!::common::ConvertDevicePathToDrivePath(device_path, &drive_path)) {
110 i : LOG(ERROR) << "ConvertDevicePathToDrivePath failed.";
111 i : return false;
112 : }
113 : ::wcsncpy(module_event->module_name, drive_path.value().c_str(),
114 E : arraysize(module_event->module_name));
115 :
116 E : module_event->module_exe[0] = L'\0';
117 :
118 E : return true;
119 E : }
120 :
121 : } // namespace common
122 : } // namespace agent
|