1 : // Copyright 2015 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/refinery/validators/vftable_ptr_validator.h"
16 :
17 : #include <string>
18 :
19 : #include "base/strings/stringprintf.h"
20 : #include "syzygy/refinery/process_state/process_state_util.h"
21 : #include "syzygy/refinery/process_state/refinery.pb.h"
22 : #include "syzygy/refinery/types/type.h"
23 :
24 m : namespace refinery {
25 :
26 m : namespace {
27 :
28 m : TypePtr RecoverType(ModuleLayerAccessor* accessor,
29 m : SymbolProvider* provider,
30 m : const TypedBlock& typedblock) {
31 m : DCHECK(accessor);
32 m : DCHECK(provider);
33 :
34 m : pe::PEFile::Signature signature;
35 m : if (!accessor->GetModuleSignature(typedblock.module_id(), &signature))
36 m : return nullptr;
37 :
38 m : scoped_refptr<TypeRepository> type_repository;
39 m : if (!provider->FindOrCreateTypeRepository(signature, &type_repository))
40 m : return nullptr;
41 :
42 m : return type_repository->GetType(typedblock.type_id());
43 m : }
44 :
45 m : void AddViolation(const TypedData& typed_data, ValidationReport* report) {
46 m : DCHECK(typed_data.IsValid());
47 m : DCHECK(report);
48 :
49 m : Violation* violation = report->add_error();
50 m : violation->set_type(VIOLATION_VFPTR);
51 :
52 m : std::string description = base::StringPrintf(
53 m : "Type %ls at address %08X has an incorrect vfptr.",
54 m : typed_data.type()->GetName().c_str(), typed_data.GetRange().start());
55 m : violation->set_description(description);
56 m : }
57 :
58 m : } // namespace
59 :
60 m : VftablePtrValidator::VftablePtrValidator(
61 m : scoped_refptr<SymbolProvider> symbol_provider)
62 m : : symbol_provider_(symbol_provider) {
63 m : DCHECK(symbol_provider);
64 m : }
65 :
66 m : Validator::ValidationResult VftablePtrValidator::Validate(
67 m : ProcessState* process_state,
68 m : ValidationReport* report) {
69 m : DCHECK(process_state);
70 m : DCHECK(report);
71 :
72 : // Analyzers that build content for the bytes and typed block layer must have
73 : // already run. We use the existence of a bytes layer and a typed block layer
74 : // as a proxy for this.
75 m : BytesLayerPtr bytes_layer;
76 m : if (!process_state->FindLayer(&bytes_layer)) {
77 m : LOG(ERROR) << "Missing bytes layer.";
78 m : return VALIDATION_ERROR;
79 m : }
80 m : TypedBlockLayerPtr typed_layer;
81 m : if (!process_state->FindLayer(&typed_layer)) {
82 m : LOG(ERROR) << "Missing typed block layer.";
83 m : return VALIDATION_ERROR;
84 m : }
85 :
86 : // Get the set of valid vftable ptrs.
87 : // Go through the typed block layer for validation.
88 m : base::hash_set<Address> vftable_vas;
89 m : if (!GetVFTableVAs(process_state, symbol_provider_.get(), &vftable_vas)) {
90 m : LOG(ERROR) << "Failed to get vfptr VAs.";
91 m : return VALIDATION_ERROR;
92 m : }
93 :
94 : // Validate each typed block.
95 m : ModuleLayerAccessor accessor(process_state);
96 m : for (TypedBlockRecordPtr rec : *typed_layer) {
97 m : TypePtr type = RecoverType(&accessor, symbol_provider_.get(), rec->data());
98 m : if (type == nullptr)
99 m : return VALIDATION_ERROR;
100 :
101 m : TypedData typed_data(process_state, type, rec->range().start());
102 m : ValidateTypedData(typed_data, vftable_vas, report);
103 m : }
104 :
105 m : return VALIDATION_COMPLETE;
106 m : }
107 :
108 m : bool VftablePtrValidator::GetVFTableVAs(
109 m : ProcessState* process_state,
110 m : SymbolProvider* symbol_provider,
111 m : base::hash_set<RelativeAddress>* vftable_vas) {
112 m : DCHECK(process_state);
113 m : DCHECK(symbol_provider);
114 m : DCHECK(vftable_vas);
115 :
116 m : ModuleLayerPtr layer;
117 m : if (!process_state->FindLayer(&layer))
118 m : return false; // We expect to find a module layer (though possibly empty).
119 m : ModuleLayerAccessor accessor(process_state);
120 :
121 : // Note: no optimisation for multiples instances of the same module.
122 m : for (ModuleRecordPtr record : *layer) {
123 m : pe::PEFile::Signature signature;
124 m : if (!accessor.GetModuleSignature(record->data().module_id(), &signature))
125 m : return false;
126 :
127 m : base::hash_set<Address> vftable_rvas;
128 m : if (!symbol_provider->GetVFTableRVAs(signature, &vftable_rvas))
129 m : return false;
130 :
131 m : Address module_base = record->range().start();
132 m : for (Address rva : vftable_rvas) {
133 m : base::CheckedNumeric<Address> virtual_address = module_base;
134 m : virtual_address += rva;
135 m : if (!virtual_address.IsValid())
136 m : return false;
137 :
138 m : vftable_vas->insert(virtual_address.ValueOrDie());
139 m : }
140 m : }
141 :
142 m : return true;
143 m : }
144 :
145 m : bool VftablePtrValidator::ValidateTypedData(
146 m : const TypedData& typed_data,
147 m : const base::hash_set<Address>& vftable_vas,
148 m : ValidationReport* report) {
149 m : DCHECK(typed_data.IsValid());
150 m : DCHECK(report);
151 :
152 : // Restrict to UDTs.
153 m : if (!typed_data.IsUserDefinedType())
154 m : return false;
155 :
156 m : size_t field_cnt;
157 m : if (!typed_data.GetFieldCount(&field_cnt))
158 m : return false;
159 :
160 m : for (size_t i = 0; i < field_cnt; ++i) {
161 m : FieldPtr field;
162 m : if (!typed_data.GetField(i, &field))
163 m : return false;
164 m : TypedData field_data;
165 m : if (!typed_data.GetField(i, &field_data))
166 m : return false;
167 :
168 m : switch (field->kind()) {
169 m : case UserDefinedType::Field::VFPTR_KIND: {
170 m : Address vfptr;
171 m : if (field_data.GetPointerValue(&vfptr) &&
172 m : vftable_vas.find(vfptr) == vftable_vas.end()) {
173 : // The value of the vfptr was retrieved but it's not in the allowed
174 : // set. Add a violation.
175 m : AddViolation(typed_data, report);
176 m : }
177 m : break;
178 m : }
179 m : case UserDefinedType::Field::BASE_CLASS_KIND:
180 m : case UserDefinedType::Field::MEMBER_KIND: {
181 : // Recurse on "nested" UDTs (base classes and members).
182 m : if (!ValidateTypedData(field_data, vftable_vas, report))
183 m : return false;
184 m : break;
185 m : }
186 m : }
187 m : }
188 :
189 m : return true;
190 m : }
191 :
192 m : } // namespace refinery
|