1 // Copyright 2015 The Crashpad Authors. 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 #ifndef CRASHPAD_SNAPSHOT_WIN_PE_IMAGE_RESOURCE_READER_H_
16 #define CRASHPAD_SNAPSHOT_WIN_PE_IMAGE_RESOURCE_READER_H_
17 
18 #include <windows.h>
19 #include <stdint.h>
20 
21 #include <vector>
22 
23 #include "base/macros.h"
24 #include "snapshot/win/process_subrange_reader.h"
25 #include "util/misc/initialization_state_dcheck.h"
26 #include "util/win/address_types.h"
27 
28 namespace crashpad {
29 
30 //! \brief A reader for resources stored in PE images mapped into another
31 //!     process.
32 //!
33 //! \sa PEImageReader
34 class PEImageResourceReader {
35  public:
36   PEImageResourceReader();
37   ~PEImageResourceReader();
38 
39   //! \brief Initializes the resource reader.
40   //!
41   //! \param[in] module_subrange_reader The reader for the module.
42   //! \param[in] resources_directory_entry The module’s `IMAGE_DATA_DIRECTORY`
43   //!     for its resources area. This is taken from the module’s
44   //!     `IMAGE_OPTIONAL_HEADER::DataDirectory` at index
45   //!     `IMAGE_DIRECTORY_ENTRY_RESOURCE`.
46   //!
47   //! \return `true` on success, `false` on failure with a message logged.
48   bool Initialize(const ProcessSubrangeReader& module_subrange_reader,
49                   const IMAGE_DATA_DIRECTORY& resources_directory_entry);
50 
51   //! \brief Locates a resource in a module by its ID.
52   //!
53   //! This method is similar to `FindResourceEx()`, but it operates on modules
54   //! loaded in a remote process’ address space. It is not necessary to
55   //! `LoadLibrary()` a module into a process in order to use this method.
56   //!
57   //! No support is provided at present for locating resources by \a type or \a
58   //! name using strings as opposed to integer identifiers.
59   //!
60   //! Languages are scanned in the order determined by
61   //! GetEntryFromResourceDirectoryByLanguage().
62   //!
63   //! \param[in] type The integer identifier of the resource type, as in the
64   //!     `lpType` parameter of `FindResourceEx()`.
65   //! \param[in] name The integer identifier of the resource, as in the `lpName`
66   //!     parameter of `FindResourceEx()`.
67   //! \param[in] language The language of the resource, as in the `wLanguage`
68   //!     parameter of `FindResourceEx()`.
69   //! \param[out] address The address, in the remote process’ address space, of
70   //!     the resource data.
71   //! \param[out] size The size of the resource data.
72   //! \param[out] code_page The code page used to encode textual resource data.
73   //!     This parameter is optional.
74   //!
75   //! \return `true` on success, with the out parameters set appropriately.
76   //!     `false` if the resource was not found, without logging any messages.
77   //!     `false` on failure, with a message logged.
78   bool FindResourceByID(uint16_t type,
79                         uint16_t name,
80                         uint16_t language,
81                         WinVMAddress* address,
82                         WinVMSize* size,
83                         uint32_t* code_page) const;
84 
85  private:
86   //! \brief Locates a resource directory entry within a resource directory by
87   //!     integer ID.
88   //!
89   //! \param[in] resource_directory_offset The offset, in the module’s resources
90   //!     area, of the resource directory to search.
91   //! \param[in] id The integer identifier of the resource to search for.
92   //! \param[in] want_subdirectory `true` if the resource directory entry is
93   //!     expected to be a resource directory itself, `false` otherwise.
94   //!
95   //! \return The offset, in the module’s resources area, of the entry that was
96   //!     found. On failure, `0`. `0` is technically a valid offset, but it
97   //!     corresponds to the root resource directory, which should never be the
98   //!     offset of another resource directory entry. If \a id was not found,
99   //!     `0` will be returned without logging anything. For other failures, a
100   //!     message will be logged.
101   uint32_t GetEntryFromResourceDirectoryByID(uint32_t resource_directory_offset,
102                                              uint16_t id,
103                                              bool want_subdirectory) const;
104 
105   //! \brief Locates a resource directory entry within a resource directory by
106   //!     language.
107   //!
108   //! This method is similar to GetEntryFromResourceDirectoryByID() with \a
109   //! want_subdirectory set to `false`. Attempts are made to locate the resource
110   //! by using these languages:
111   //! <ul>
112   //!     <li>If \a language is `LANG_NEUTRAL`:</li>
113   //!     <ul>
114   //!         <li>Unless `SUBLANG_SYS_DEFAULT` is specified, the language of the
115   //!             thread’s locale, with its normal sublanguage and with
116   //!             `SUBLANG_NEUTRAL`.</li>
117   //!         <li>Unless `SUBLANG_SYS_DEFAULT` is specified, the language of the
118   //!             user’s default locale, with its normal sublanguage and with
119   //!             `SUBLANG_NEUTRAL`.</li>
120   //!         <li>Unless `SUBLANG_DEFAULT` is specified, the language of the
121   //!             system’s default locale, with its normal sublanguage and with
122   //!             `SUBLANG_NEUTRAL`.</li>
123   //!     </ul>
124   //!     <li>If \a language is not `LANG_NEUTRAL`:</li>
125   //!     <ul>
126   //!         <li>\a language</li>
127   //!         <li>\a language, with `SUBLANG_NEUTRAL`</li>
128   //!     </ul>
129   //!     <li>`LANG_NEUTRAL` with `SUBLANG_NEUTRAL`</li>
130   //!     <li>`LANG_ENGLISH` with `SUBLANG_DEFAULT`</li>
131   //!     <li>If none of the above match, the first language found</li>
132   //! </ul>
133   //!
134   //! If only a specific language is desired without any fallbacks, call
135   //! GetEntryFromResourceDirectoryByID() with the language directory’s offset
136   //! instead, passing the desired language in the \a id parameter, and `false`
137   //! for \a want_subdirectory.
138   //!
139   //! \param[in] language_directory_offset The offset, in the module’s resources
140   //!     area, of the resource directory to search.
141   //! \param[in] language The language of the resource to search for.
142   //!
143   //! \return The return value is as in GetEntryFromResourceDirectoryByID().
144   uint32_t GetEntryFromResourceDirectoryByLanguage(
145       uint32_t language_directory_offset,
146       uint16_t language) const;
147 
148   //! \brief Reads a resource directory.
149   //!
150   //! \param[in] resource_directory_offset The offset, in the module’s resources
151   //!     area, of the resource directory to read.
152   //! \param[out] resource_directory The `IMAGE_RESOURCE_DIRECTORY` structure.
153   //!     This parameter is optional.
154   //! \param[out] named_entries A vector of \a
155   //!     resource_directory->NumberOfNamedEntries
156   //!     `IMAGE_RESOURCE_DIRECTORY_ENTRY` items that follow the resource
157   //!     directory. This parameter is optional.
158   //! \param[out] id_entries A vector of \a
159   //!     resource_directory->NumberOfIdEntries `IMAGE_RESOURCE_DIRECTORY_ENTRY`
160   //!     items that follow the named entries. This parameter is optional.
161   //!
162   //! \return `true` on success, with the out parameters set appropriately.
163   //!     `false` on failure with a message logged.
164   bool ReadResourceDirectory(
165       uint32_t resource_directory_offset,
166       IMAGE_RESOURCE_DIRECTORY* resource_directory,
167       std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY>* named_entries,
168       std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY>* id_entries) const;
169 
170   ProcessSubrangeReader resources_subrange_reader_;
171   WinVMAddress module_base_;
172   InitializationStateDcheck initialized_;
173 
174   DISALLOW_COPY_AND_ASSIGN(PEImageResourceReader);
175 };
176 
177 }  // namespace crashpad
178 
179 #endif  // CRASHPAD_SNAPSHOT_WIN_PE_IMAGE_RESOURCE_READER_H_
180