My Project  + 80db3
offsets.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011-2019 Daniel Scharrer
3  *
4  * This software is provided 'as-is', without any express or implied
5  * warranty. In no event will the author(s) be held liable for any damages
6  * arising from the use of this software.
7  *
8  * Permission is granted to anyone to use this software for any purpose,
9  * including commercial applications, and to alter it and redistribute it
10  * freely, subject to the following restrictions:
11  *
12  * 1. The origin of this software must not be misrepresented; you must not
13  * claim that you wrote the original software. If you use this software
14  * in a product, an acknowledgment in the product documentation would be
15  * appreciated but is not required.
16  * 2. Altered source versions must be plainly marked as such, and must not be
17  * misrepresented as being the original software.
18  * 3. This notice may not be removed or altered from any source distribution.
19  */
20 
21 #include "loader/offsets.hpp"
22 
23 #include <cstring>
24 #include <limits>
25 
26 #include <boost/cstdint.hpp>
27 #include <boost/static_assert.hpp>
28 #include <boost/range/size.hpp>
29 
30 #include <stddef.h>
31 
32 #include "crypto/crc32.hpp"
33 #include "loader/exereader.hpp"
34 #include "setup/version.hpp"
35 #include "util/load.hpp"
36 #include "util/log.hpp"
37 #include "util/output.hpp"
38 
39 namespace loader {
40 
41 namespace {
42 
43 struct setup_loader_version {
44 
45  unsigned char magic[12];
46 
47  // Earliest known version with that ID
49 
50 };
51 
52 const setup_loader_version known_setup_loader_versions[] = {
53  { { 'r', 'D', 'l', 'P', 't', 'S', '0', '2', 0x87, 'e', 'V', 'x' }, INNO_VERSION(1, 2, 10) },
54  { { 'r', 'D', 'l', 'P', 't', 'S', '0', '4', 0x87, 'e', 'V', 'x' }, INNO_VERSION(4, 0, 0) },
55  { { 'r', 'D', 'l', 'P', 't', 'S', '0', '5', 0x87, 'e', 'V', 'x' }, INNO_VERSION(4, 0, 3) },
56  { { 'r', 'D', 'l', 'P', 't', 'S', '0', '6', 0x87, 'e', 'V', 'x' }, INNO_VERSION(4, 0, 10) },
57  { { 'r', 'D', 'l', 'P', 't', 'S', '0', '7', 0x87, 'e', 'V', 'x' }, INNO_VERSION(4, 1, 6) },
58  { { 'r', 'D', 'l', 'P', 't', 'S', 0xcd, 0xe6, 0xd7, '{', 0x0b, '*' }, INNO_VERSION(5, 1, 5) },
59  { { 'n', 'S', '5', 'W', '7', 'd', 'T', 0x83, 0xaa, 0x1b, 0x0f, 'j' }, INNO_VERSION(5, 1, 5) },
60 };
61 
62 const int ResourceNameInstaller = 11111;
63 
64 const boost::uint32_t SetupLoaderHeaderOffset = 0x30;
65 const boost::uint32_t SetupLoaderHeaderMagic = 0x6f6e6e49;
66 
67 } // anonymous namespace
68 
69 bool offsets::load_from_exe_file(std::istream & is) {
70 
71  is.seekg(SetupLoaderHeaderOffset);
72 
73  boost::uint32_t magic = util::load<boost::uint32_t>(is);
74  if(is.fail() || magic != SetupLoaderHeaderMagic) {
75  is.clear();
76  return false;
77  }
78 
79  boost::uint32_t offset_table_offset = util::load<boost::uint32_t>(is);
80  boost::uint32_t not_offset_table_offset = util::load<boost::uint32_t>(is);
81  if(is.fail() || offset_table_offset != ~not_offset_table_offset) {
82  is.clear();
83  return false;
84  }
85 
86  return load_offsets_at(is, offset_table_offset);
87 }
88 
89 bool offsets::load_from_exe_resource(std::istream & is) {
90 
91  exe_reader::resource resource = exe_reader::find_resource(is, ResourceNameInstaller);
92  if(!resource) {
93  is.clear();
94  return false;
95  }
96 
97  return load_offsets_at(is, resource.offset);
98 }
99 
100 bool offsets::load_offsets_at(std::istream & is, boost::uint32_t pos) {
101 
102  if(is.seekg(pos).fail()) {
103  is.clear();
104  return false;
105  }
106 
107  char magic[12];
108  if(is.read(magic, std::streamsize(sizeof(magic))).fail()) {
109  is.clear();
110  return false;
111  }
112 
114  for(size_t i = 0; i < size_t(boost::size(known_setup_loader_versions)); i++) {
115  BOOST_STATIC_ASSERT(sizeof(known_setup_loader_versions[i].magic) == sizeof(magic));
116  if(!memcmp(magic, known_setup_loader_versions[i].magic, sizeof(magic))) {
117  version = known_setup_loader_versions[i].version;
118  break;
119  }
120  }
121  if(!version) {
122  log_warning << "Unexpected setup loader magic: " << print_hex(magic);
123  version = std::numeric_limits<setup::version_constant>::max();
124  }
125 
126  crypto::crc32 checksum;
127  checksum.init();
128  checksum.update(magic, sizeof(magic));
129 
130  if(version >= INNO_VERSION(5, 1, 5)) {
131  boost::uint32_t revision = checksum.load<boost::uint32_t>(is);
132  if(is.fail()) {
133  is.clear();
134  return false;
135  } else if(revision != 1) {
136  log_warning << "Unexpected setup loader revision: " << revision;
137  }
138  }
139 
140  (void)checksum.load<boost::uint32_t>(is);
141  exe_offset = checksum.load<boost::uint32_t>(is);
142 
143  if(version >= INNO_VERSION(4, 1, 6)) {
145  } else {
146  exe_compressed_size = checksum.load<boost::uint32_t>(is);
147  }
148 
149  exe_uncompressed_size = checksum.load<boost::uint32_t>(is);
150 
151  if(version >= INNO_VERSION(4, 0, 3)) {
153  exe_checksum.crc32 = checksum.load<boost::uint32_t>(is);
154  } else {
156  exe_checksum.adler32 = checksum.load<boost::uint32_t>(is);
157  }
158 
159  if(version >= INNO_VERSION(4, 0, 0)) {
160  message_offset = 0;
161  } else {
162  message_offset = util::load<boost::uint32_t>(is);
163  }
164 
165  header_offset = checksum.load<boost::uint32_t>(is);
166  data_offset = checksum.load<boost::uint32_t>(is);
167 
168  if(is.fail()) {
169  is.clear();
170  return false;
171  }
172 
173  if(version >= INNO_VERSION(4, 0, 10)) {
174  boost::uint32_t expected = util::load<boost::uint32_t>(is);
175  if(is.fail()) {
176  is.clear();
177  return false;
178  }
179  if(checksum.finalize() != expected) {
180  log_warning << "Setup loader checksum mismatch!";
181  }
182  }
183 
184  return true;
185 }
186 
187 void offsets::load(std::istream & is) {
188 
189  /*
190  * Try to load the offset table by following a pointer at a constant offset.
191  * This method of storing the offset table is used in versions before 5.1.5
192  */
193  if(load_from_exe_file(is)) {
194  return;
195  }
196 
197  /*
198  * Try to load an offset table located in a PE/COFF (.exe) resource entry.
199  * This method of storing the offset table was introduced in version 5.1.5
200  */
201  if(load_from_exe_resource(is)) {
202  return;
203  }
204 
205  /*
206  * If no offset table has been found, this must be an external setup-0.bin file.
207  * In that case, the setup headers start at the beginning of the file.
208  */
209 
210  exe_compressed_size = exe_uncompressed_size = exe_offset = 0; // No embedded setup exe.
211 
212  message_offset = 0; // No embedded messages.
213 
214  header_offset = 0; // Whole file contains just the setup headers.
215 
216  data_offset = 0; // No embedded setup data.
217 }
218 
219 } // namespace loader
Output utility functions.
boost::uint32_t crc32
Definition: checksum.hpp:53
Utility function to load stored data while properly handling encodings and endianness.
boost::uint32_t data_offset
Offset of embedded setup-1.bin data.
Definition: offsets.hpp:107
boost::uint32_t exe_compressed_size
Size of setup.e32 after compression, in bytes.
Definition: offsets.hpp:65
#define log_warning
Definition: log.hpp:45
checksum_type type
Definition: checksum.hpp:58
boost::uint32_t version_constant
Definition: version.hpp:40
Functions to find resources in Windows executables.
boost::uint32_t exe_offset
Offset of compressed setup.e32 (the actual installer code)
Definition: offsets.hpp:58
void load(std::istream &is)
Find the setup loader offsets in a file.
Definition: offsets.cpp:187
detail::print_hex< T > print_hex(T value)
Definition: output.hpp:173
boost::uint32_t exe_uncompressed_size
Size of setup.e32 before compression, in bytes.
Definition: offsets.hpp:68
boost::uint32_t message_offset
Offset of embedded setup messages.
Definition: offsets.hpp:78
boost::uint32_t header_offset
Offset of embedded setup-0.bin data (the setup headers)
Definition: offsets.hpp:91
#define INNO_VERSION(a, b, c)
Definition: version.hpp:47
boost::uint32_t adler32
Definition: checksum.hpp:52
static resource find_resource(std::istream &is, boost::uint32_t name, boost::uint32_t type=TypeData, boost::uint32_t language=Default)
Find where a resource with a given ID is stored in a NE or PE binary.
Definition: exereader.cpp:481
boost::uint32_t finalize() const
Definition: crc32.hpp:42
unsigned char magic[12]
Definition: offsets.cpp:45
T load(std::istream &is)
Load the data and process it.
Definition: checksum.hpp:75
Functions to find Inno Setup data inside an executable.
void update(const char *data, size_t length)
Definition: crc32.cpp:94
CRC32 checksum routines.
crypto::checksum exe_checksum
Checksum of setup.e32 before compression.
Definition: offsets.hpp:75
CRC32 checksum calculation.
Definition: crc32.hpp:36
Logging functions.
Inno Setup version number utilities.
void init()
Definition: crc32.hpp:38
setup::version_constant version
Definition: offsets.cpp:48