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 E : void GetProcessModules(ModuleVector* modules) {
60 E : DCHECK(modules != NULL);
61 :
62 E : modules->resize(128);
63 E : while (true) {
64 E : DWORD bytes = sizeof(modules->at(0)) * modules->size();
65 E : DWORD needed_bytes = 0;
66 : BOOL success = ::EnumProcessModules(::GetCurrentProcess(),
67 : &modules->at(0),
68 : bytes,
69 E : &needed_bytes);
70 E : if (success && bytes >= needed_bytes) {
71 : // Success - break out of the loop.
72 : // Resize our module vector to the returned size.
73 E : modules->resize(needed_bytes / sizeof(modules->at(0)));
74 E : return;
75 : }
76 :
77 : // Resize our module vector with the needed size and little slop.
78 i : modules->resize(needed_bytes / sizeof(modules->at(0)) + 4);
79 i : }
80 E : }
81 :
82 : bool LogModule(HMODULE module,
83 : trace::client::RpcSession* session,
84 E : trace::client::TraceFileSegment* segment) {
85 E : DCHECK(module != NULL);
86 E : DCHECK(session != NULL);
87 E : DCHECK(segment != NULL);
88 :
89 : // See whether we can acquire the module data.
90 E : base::win::PEImage image(module);
91 E : size_t module_base_size = 0;
92 E : uint32 module_checksum = 0;
93 E : uint32 module_time_date_stamp = 0;
94 : if (!CaptureModuleInformation(image,
95 : &module_base_size,
96 : &module_checksum,
97 E : &module_time_date_stamp)) {
98 E : LOG(ERROR) << "Failed to capture module information.";
99 E : return false;
100 : }
101 :
102 : // Make sure the event we're about to write will fit.
103 : if (!segment->CanAllocate(sizeof(TraceModuleData)) ||
104 E : !session->ExchangeBuffer(segment)) {
105 : // Failed to allocate a new segment.
106 i : LOG(ERROR) << "Failed to exchange buffer.";
107 i : return false;
108 : }
109 :
110 E : DCHECK(segment->CanAllocate(sizeof(TraceModuleData)));
111 :
112 : // Allocate a record in the log.
113 : TraceModuleData* module_event = reinterpret_cast<TraceModuleData*>(
114 : segment->AllocateTraceRecordImpl(
115 E : TRACE_PROCESS_ATTACH_EVENT, sizeof(TraceModuleData)));
116 E : DCHECK(module_event != NULL);
117 :
118 E : module_event->module_base_addr = module;
119 E : module_event->module_base_size = module_base_size;
120 E : module_event->module_checksum = module_checksum;
121 E : module_event->module_time_date_stamp = module_time_date_stamp;
122 :
123 E : wchar_t module_name[MAX_PATH] = { 0 };
124 : if (::GetMappedFileName(::GetCurrentProcess(), module,
125 E : module_name, arraysize(module_name)) == 0) {
126 i : DWORD error = ::GetLastError();
127 i : LOG(ERROR) << "Failed to get module name: " << ::common::LogWe(error)
128 : << ".";
129 i : return false;
130 : }
131 E : base::FilePath device_path(module_name);
132 E : base::FilePath drive_path;
133 E : if (!::common::ConvertDevicePathToDrivePath(device_path, &drive_path)) {
134 i : LOG(ERROR) << "ConvertDevicePathToDrivePath failed.";
135 i : return false;
136 : }
137 : ::wcsncpy(module_event->module_name, drive_path.value().c_str(),
138 E : arraysize(module_event->module_name));
139 :
140 E : module_event->module_exe[0] = L'\0';
141 :
142 E : return true;
143 E : }
144 :
145 : } // namespace common
146 : } // namespace agent
|