Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(255)

Unified Diff: snapshot/win/pe_image_resource_reader.cc

Issue 1475023004: Get module versions and types from in-memory images (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Address review feedback (2) Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « snapshot/win/pe_image_resource_reader.h ('k') | snapshot/win/process_subrange_reader.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: snapshot/win/pe_image_resource_reader.cc
diff --git a/snapshot/win/pe_image_resource_reader.cc b/snapshot/win/pe_image_resource_reader.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3a754a9757596a63aa4153b8b6f8914e3db34511
--- /dev/null
+++ b/snapshot/win/pe_image_resource_reader.cc
@@ -0,0 +1,279 @@
+// Copyright 2015 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "snapshot/win/pe_image_resource_reader.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace {
+
+void AddLanguageAndNeutralSublanguage(std::vector<uint16_t>* languages,
+ uint16_t language) {
+ languages->push_back(language);
+ if (SUBLANGID(language) != SUBLANG_NEUTRAL) {
+ languages->push_back(MAKELANGID(PRIMARYLANGID(language), SUBLANG_NEUTRAL));
+ }
+}
+
+} // namespace
+
+namespace crashpad {
+
+PEImageResourceReader::PEImageResourceReader()
+ : resources_subrange_reader_(),
+ module_base_(0),
+ initialized_() {
+}
+
+PEImageResourceReader::~PEImageResourceReader() {}
+
+bool PEImageResourceReader::Initialize(
+ const ProcessSubrangeReader& module_subrange_reader,
+ const IMAGE_DATA_DIRECTORY& resources_directory_entry) {
+ INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
+
+ module_base_ = module_subrange_reader.Base();
+
+ if (!resources_subrange_reader_.InitializeSubrange(
+ module_subrange_reader,
+ module_base_ + resources_directory_entry.VirtualAddress,
+ resources_directory_entry.Size,
+ "resources")) {
+ return false;
+ }
+
+ INITIALIZATION_STATE_SET_VALID(initialized_);
+ return true;
+}
+
+bool PEImageResourceReader::FindResourceByID(uint16_t type,
+ uint16_t name,
+ uint16_t language,
+ WinVMAddress* address,
+ WinVMSize* size,
+ uint32_t* code_page) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+
+ // The root resource directory is at the beginning of the resources area
+ // within the module.
+ const uint32_t name_directory_offset =
+ GetEntryFromResourceDirectoryByID(0, type, true);
+ if (!name_directory_offset) {
+ return false;
+ }
+
+ const uint32_t language_directory_offset =
+ GetEntryFromResourceDirectoryByID(name_directory_offset, name, true);
+ if (!language_directory_offset) {
+ return false;
+ }
+
+ // The definition of IMAGE_RESOURCE_DIRECTORY_ENTRY in <winnt.h> has a comment
+ // saying that its offsets are relative to “the resource directory of the data
+ // associated with this directory entry”. That could be interpreted to mean
+ // that language_directory_offset is relative to name_directory_offset, since
+ // the language directory entry is found within the name directory. This is
+ // not correct. All resource offsets are relative to the resources area within
+ // the module.
+ const uint32_t data_offset = GetEntryFromResourceDirectoryByLanguage(
+ language_directory_offset, language);
+ if (!data_offset) {
+ return false;
+ }
+
+ IMAGE_RESOURCE_DATA_ENTRY data_entry;
+ if (!resources_subrange_reader_.ReadMemory(
+ resources_subrange_reader_.Base() + data_offset,
+ sizeof(data_entry),
+ &data_entry)) {
+ LOG(WARNING) << "could not read resource data entry from "
+ << resources_subrange_reader_.name();
+ return false;
+ }
+
+ // The definition of IMAGE_RESOURCE_DATA_ENTRY in <winnt.h> has a comment
+ // saying that OffsetToData is relative to the beginning of the resource data.
+ // This is not correct. It’s module-relative.
+ *address = module_base_ + data_entry.OffsetToData;
+ *size = data_entry.Size;
+ if (code_page) {
+ *code_page = data_entry.CodePage;
+ }
+
+ return true;
+}
+
+uint32_t PEImageResourceReader::GetEntryFromResourceDirectoryByID(
+ uint32_t language_directory_offset,
+ uint16_t id,
+ bool want_subdirectory) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+
+ std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY> entries_by_id;
+ if (!ReadResourceDirectory(
+ language_directory_offset, nullptr, nullptr, &entries_by_id)) {
+ return 0;
+ }
+
+ const auto entry_it =
+ std::find_if(entries_by_id.begin(),
+ entries_by_id.end(),
+ [id](const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry) {
+ return !entry.NameIsString && entry.Id == id;
+ });
+ if (entry_it != entries_by_id.end()) {
+ if ((entry_it->DataIsDirectory != 0) != want_subdirectory) {
+ LOG(WARNING) << "expected " << (want_subdirectory ? "" : "non-")
+ << "directory for entry id " << id << " in "
+ << resources_subrange_reader_.name();
+ return 0;
+ }
+
+ return entry_it->DataIsDirectory ? entry_it->OffsetToDirectory
+ : entry_it->OffsetToData;
+ }
+
+ return 0;
+}
+
+uint32_t PEImageResourceReader::GetEntryFromResourceDirectoryByLanguage(
+ uint32_t resource_directory_offset,
+ uint16_t language) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+
+ std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY> entries_by_language;
+ if (!ReadResourceDirectory(
+ resource_directory_offset, nullptr, nullptr, &entries_by_language)) {
+ return 0;
+ }
+
+ if (entries_by_language.empty()) {
+ return 0;
+ }
+
+ // https://msdn.microsoft.com/en-us/library/cc194810.aspx
+ //
+ // TODO(mark): It seems like FindResourceEx() might do something more complex.
+ // It would be best to mimic its behavior.
+ std::vector<uint16_t> try_languages;
+ if (PRIMARYLANGID(language) != LANG_NEUTRAL) {
+ AddLanguageAndNeutralSublanguage(&try_languages, language);
+ } else {
+ if (SUBLANGID(language) != SUBLANG_SYS_DEFAULT) {
+ AddLanguageAndNeutralSublanguage(&try_languages,
+ LANGIDFROMLCID(GetThreadLocale()));
+ AddLanguageAndNeutralSublanguage(&try_languages,
+ LANGIDFROMLCID(GetUserDefaultLCID()));
+ }
+ if (SUBLANGID(language) != SUBLANG_DEFAULT) {
+ AddLanguageAndNeutralSublanguage(&try_languages,
+ LANGIDFROMLCID(GetSystemDefaultLCID()));
+ }
+ }
+
+ try_languages.push_back(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
+ try_languages.push_back(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT));
+
+ for (const auto try_language : try_languages) {
+ const auto entry_it = std::find_if(
+ entries_by_language.begin(),
+ entries_by_language.end(),
+ [try_language](const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry) {
+ return !entry.NameIsString && entry.Id == try_language;
+ });
+ if (entry_it != entries_by_language.end()) {
+ if (entry_it->DataIsDirectory) {
+ LOG(WARNING) << "expected non-directory for entry language "
+ << try_language << " in "
+ << resources_subrange_reader_.name();
+ return 0;
+ }
+
+ return entry_it->OffsetToData;
+ }
+ }
+
+ // Fall back to the first entry in the list.
+ const auto& entry = entries_by_language.front();
+ if (entry.DataIsDirectory) {
+ LOG(WARNING) << "expected non-directory for entry in "
+ << resources_subrange_reader_.name();
+ return 0;
+ }
+
+ return entry.OffsetToData;
+}
+
+bool PEImageResourceReader::ReadResourceDirectory(
+ uint32_t resource_directory_offset,
+ IMAGE_RESOURCE_DIRECTORY* resource_directory,
+ std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY>* named_entries,
+ std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY>* id_entries) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+
+ // resource_directory is optional, but it’s still needed locally even if the
+ // caller isn’t interested in it.
+ scoped_ptr<IMAGE_RESOURCE_DIRECTORY> local_resource_directory;
+ if (!resource_directory) {
+ local_resource_directory.reset(new IMAGE_RESOURCE_DIRECTORY);
+ resource_directory = local_resource_directory.get();
+ }
+
+ const WinVMAddress address =
+ resources_subrange_reader_.Base() + resource_directory_offset;
+
+ if (!resources_subrange_reader_.ReadMemory(
+ address, sizeof(*resource_directory), resource_directory)) {
+ LOG(WARNING) << "could not read resource directory from "
+ << resources_subrange_reader_.name();
+ return false;
+ }
+
+ if (named_entries) {
+ named_entries->clear();
+ named_entries->resize(resource_directory->NumberOfNamedEntries);
+ if (!named_entries->empty() &&
+ !resources_subrange_reader_.ReadMemory(
+ address + sizeof(*resource_directory),
+ named_entries->size() * sizeof((*named_entries)[0]),
+ &(*named_entries)[0])) {
+ LOG(WARNING) << "could not read resource directory named entries from "
+ << resources_subrange_reader_.name();
+ return false;
+ }
+ }
+
+ if (id_entries) {
+ id_entries->clear();
+ id_entries->resize(resource_directory->NumberOfIdEntries);
+ if (!id_entries->empty() &&
+ !resources_subrange_reader_.ReadMemory(
+ address + sizeof(*resource_directory) +
+ resource_directory->NumberOfNamedEntries *
+ sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY),
+ id_entries->size() * sizeof((*id_entries)[0]),
+ &(*id_entries)[0])) {
+ LOG(WARNING) << "could not read resource directory ID entries from "
+ << resources_subrange_reader_.name();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace crashpad
« no previous file with comments | « snapshot/win/pe_image_resource_reader.h ('k') | snapshot/win/process_subrange_reader.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698