LIEF: Library to Instrument Executable Formats Version 0.17.0
Loading...
Searching...
No Matches
BinaryStream.hpp
Go to the documentation of this file.
1/* Copyright 2017 - 2024 R. Thomas
2 * Copyright 2017 - 2024 Quarkslab
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#ifndef LIEF_BINARY_STREAM_H
17#define LIEF_BINARY_STREAM_H
18
19#include <cstdint>
20#include <vector>
21#include <cstring>
22#include <string>
23#include <algorithm>
24
26#include "LIEF/errors.hpp"
27#include "LIEF/visibility.h"
28
29namespace LIEF {
30class ASN1Reader;
34 public:
35 friend class ASN1Reader;
36
37 enum class STREAM_TYPE {
38 UNKNOWN = 0,
39 VECTOR,
40 MEMORY,
41 SPAN,
42 FILE,
43
44 ELF_DATA_HANDLER,
45 };
46
47 BinaryStream(STREAM_TYPE type) :
48 stype_(type)
49 {}
50 virtual ~BinaryStream() = default;
51 virtual uint64_t size() const = 0;
52
53 STREAM_TYPE type() const {
54 return stype_;
55 }
56
57 result<uint64_t> read_uleb128() const;
58 result<uint64_t> read_sleb128() const;
59
60 result<int64_t> read_dwarf_encoded(uint8_t encoding) const;
61
62 result<std::string> read_string(size_t maxsize = ~static_cast<size_t>(0)) const;
63 result<std::string> peek_string(size_t maxsize = ~static_cast<size_t>(0)) const;
64 result<std::string> peek_string_at(size_t offset, size_t maxsize = ~static_cast<size_t>(0)) const;
65
66 result<std::u16string> read_u16string() const;
67 result<std::u16string> peek_u16string() const;
68
69 result<std::string> read_mutf8(size_t maxsize = ~static_cast<size_t>(0)) const;
70
71 result<std::u16string> read_u16string(size_t length) const;
72 result<std::u16string> peek_u16string(size_t length) const;
73 result<std::u16string> peek_u16string_at(size_t offset, size_t length) const;
74
75
76 virtual ok_error_t peek_data(std::vector<uint8_t>& container,
77 uint64_t offset, uint64_t size,
78 uint64_t virtual_address = 0)
79 {
80
81 if (size == 0) {
82 return ok();
83 }
84 // Even though offset + size < ... => offset < ...
85 // the addition could overflow so it's worth checking both
86 const bool read_ok = offset <= this->size() && (offset + size) <= this->size()
87 /* Check for an overflow */
88 && (static_cast<int64_t>(offset) >= 0 && static_cast<int64_t>(size) >= 0)
89 && (static_cast<int64_t>(offset + size) >= 0);
90 if (!read_ok) {
92 }
93 container.resize(size);
94 if (peek_in(container.data(), offset, size, virtual_address)) {
95 return ok();
96 }
98 }
99
100 virtual ok_error_t read_data(std::vector<uint8_t>& container, uint64_t size) {
101 if (!peek_data(container, pos(), size)) {
103 }
104
105 increment_pos(size);
106 return ok();
107 }
108
109
110 template<class T>
111 ok_error_t read_objects(std::vector<T>& container, uint64_t count) {
112 const size_t size = count * sizeof(T);
113 auto ret = peek_objects(container, count);
114 if (!ret) {
116 }
117 increment_pos(size);
118 return ok();
119 }
120
121 template<class T>
122 ok_error_t peek_objects(std::vector<T>& container, uint64_t count) {
123 return peek_objects_at(pos(), container, count);
124 }
125
126 template<class T>
127 ok_error_t peek_objects_at(uint64_t offset, std::vector<T>& container, uint64_t count) {
128 const auto current_p = pos();
129 setpos(offset);
130
131 const size_t size = count * sizeof(T);
132
133 if (!can_read(offset, size)) {
134 setpos(current_p);
136 }
137
138 container.resize(count);
139
140 if (!peek_in(container.data(), pos(), size)) {
141 setpos(current_p);
143 }
144
145 setpos(current_p);
146 return ok();
147 }
148
149 void setpos(size_t pos) const {
150 pos_ = pos;
151 }
152
153 void increment_pos(size_t value) const {
154 pos_ += value;
155 }
156
157 void decrement_pos(size_t value) const {
158 if (pos_ > value) {
159 pos_ -= value;
160 } else {
161 pos_ = 0;
162 }
163 }
164
165 size_t pos() const {
166 return pos_;
167 }
168
169 operator bool() const {
170 return pos_ < size();
171 }
172
173 template<class T>
174 const T* read_array(size_t size) const;
175
176 template<class T>
177 result<T> peek() const;
178
179 template<class T>
180 result<T> peek(size_t offset) const;
181
182 template<class T>
183 const T* peek_array(size_t size) const;
184
185 template<class T>
186 const T* peek_array(size_t offset, size_t size) const;
187
188 template<class T>
189 result<T> read() const;
190
191 template<typename T>
192 bool can_read() const;
193
194 template<typename T>
195 bool can_read(size_t offset) const;
196
197 bool can_read(int64_t offset, int64_t size) const {
198 return offset < (int64_t)this->size() && (offset + size) < (int64_t)this->size();
199 }
200
201 size_t align(size_t align_on) const;
202
203 void set_endian_swap(bool swap) {
204 endian_swap_ = swap;
205 }
206
207 template<class T>
208 static bool is_all_zero(const T& buffer) {
209 const auto* ptr = reinterpret_cast<const uint8_t *const>(&buffer);
210 return std::all_of(ptr, ptr + sizeof(T),
211 [] (uint8_t x) { return x == 0; });
212 }
213
214 bool should_swap() const {
215 return endian_swap_;
216 }
217
218 virtual const uint8_t* p() const {
219 return nullptr;
220 }
221
222 virtual uint8_t* start() {
223 return const_cast<uint8_t*>(static_cast<const BinaryStream*>(this)->start());
224 }
225
226 virtual uint8_t* p() {
227 return const_cast<uint8_t*>(static_cast<const BinaryStream*>(this)->p());
228 }
229
230 virtual uint8_t* end() {
231 return const_cast<uint8_t*>(static_cast<const BinaryStream*>(this)->end());
232 }
233
234 virtual const uint8_t* start() const {
235 return nullptr;
236 }
237
238 virtual const uint8_t* end() const {
239 return nullptr;
240 }
241
242 protected:
243 BinaryStream() = default;
244 virtual result<const void*> read_at(uint64_t offset, uint64_t size,
245 uint64_t virtual_address = 0) const = 0;
246 virtual ok_error_t peek_in(void* dst, uint64_t offset, uint64_t size,
247 uint64_t virtual_address = 0) const {
248 if (auto raw = read_at(offset, size, virtual_address)) {
249 if (dst == nullptr) {
251 }
252
253 const void* ptr = *raw;
254
255 if (ptr == nullptr) {
257 }
258
259 memcpy(dst, ptr, size);
260 return ok();
261 }
263 }
264 mutable size_t pos_ = 0;
265 bool endian_swap_ = false;
266 STREAM_TYPE stype_ = STREAM_TYPE::UNKNOWN;
267};
268
270 public:
271 ScopedStream(const ScopedStream&) = delete;
273
276
277 explicit ScopedStream(BinaryStream& stream, uint64_t pos) :
278 pos_{stream.pos()},
279 stream_{stream}
280 {
281 stream_.setpos(pos);
282 }
283
284 explicit ScopedStream(BinaryStream& stream) :
285 pos_{stream.pos()},
286 stream_{stream}
287 {}
288
290 stream_.setpos(pos_);
291 }
292
293 BinaryStream* operator->() {
294 return &stream_;
295 }
296
297 BinaryStream& operator*() {
298 return stream_;
299 }
300
301 const BinaryStream& operator*() const {
302 return stream_;
303 }
304
305 private:
306 uint64_t pos_ = 0;
307 BinaryStream& stream_;
308};
309
311 public:
314
317
318 explicit ToggleEndianness(BinaryStream& stream, bool value) :
319 endian_swap_(stream.should_swap()),
320 stream_{stream}
321 {
322 stream.set_endian_swap(value);
323 }
324
325 explicit ToggleEndianness(BinaryStream& stream) :
326 endian_swap_(stream.should_swap()),
327 stream_{stream}
328 {
329 stream.set_endian_swap(!stream_.should_swap());
330 }
331
333 stream_.set_endian_swap(endian_swap_);
334 }
335
336 BinaryStream* operator->() {
337 return &stream_;
338 }
339
340 BinaryStream& operator*() {
341 return stream_;
342 }
343
344 const BinaryStream& operator*() const {
345 return stream_;
346 }
347
348 private:
349 bool endian_swap_ = false;
350 BinaryStream& stream_;
351};
352
353
354template<class T>
356 result<T> tmp = this->peek<T>();
357 if (!tmp) {
358 return tmp;
359 }
360 this->increment_pos(sizeof(T));
361 return tmp;
362}
363
364template<class T>
366 const auto current_p = pos();
367 T ret{};
368 if (auto res = peek_in(&ret, pos(), sizeof(T))) {
369 setpos(current_p);
370 if (endian_swap_) {
371 swap_endian(&ret);
372 }
373 return ret;
374 }
375
376 setpos(current_p);
378}
379
380template<class T>
381result<T> BinaryStream::peek(size_t offset) const {
382 const size_t saved_offset = this->pos();
383 this->setpos(offset);
384 result<T> r = this->peek<T>();
385 this->setpos(saved_offset);
386 return r;
387}
388
389
390template<class T>
391const T* BinaryStream::peek_array(size_t size) const {
392 result<const void*> raw = this->read_at(this->pos(), sizeof(T) * size);
393 if (!raw) {
394 return nullptr;
395 }
396 return reinterpret_cast<const T*>(raw.value());
397}
398
399template<class T>
400const T* BinaryStream::peek_array(size_t offset, size_t size) const {
401 const size_t saved_offset = this->pos();
402 this->setpos(offset);
403 const T* r = this->peek_array<T>(size);
404 this->setpos(saved_offset);
405 return r;
406}
407
408
409template<typename T>
411 // Even though pos_ + sizeof(T) < ... => pos_ < ...
412 // the addition could overflow so it's worth checking both
413 return pos_ < size() && (pos_ + sizeof(T)) < size();
414}
415
416
417template<typename T>
418bool BinaryStream::can_read(size_t offset) const {
419 // Even though offset + sizeof(T) < ... => offset < ...
420 // the addition could overflow so it's worth checking both
421 return offset < size() && (offset + sizeof(T)) < size();
422}
423
424
425template<class T>
426const T* BinaryStream::read_array(size_t size) const {
427 const T* tmp = this->peek_array<T>(size);
428 this->increment_pos(sizeof(T) * size);
429 return tmp;
430}
431
432}
433#endif
Definition ASN1Reader.hpp:32
Class that is used to a read stream of data from different sources.
Definition BinaryStream.hpp:33
size_t align(size_t align_on) const
void increment_pos(size_t value) const
Definition BinaryStream.hpp:153
result< std::string > read_mutf8(size_t maxsize=~static_cast< size_t >(0)) const
result< uint64_t > read_sleb128() const
result< T > peek() const
Definition BinaryStream.hpp:365
result< uint64_t > read_uleb128() const
result< int64_t > read_dwarf_encoded(uint8_t encoding) const
virtual uint8_t * p()
Definition BinaryStream.hpp:226
result< std::string > peek_string(size_t maxsize=~static_cast< size_t >(0)) const
virtual const uint8_t * p() const
Definition BinaryStream.hpp:218
const T * read_array(size_t size) const
Definition BinaryStream.hpp:426
virtual uint64_t size() const =0
result< std::u16string > peek_u16string_at(size_t offset, size_t length) const
bool can_read() const
Definition BinaryStream.hpp:410
ok_error_t read_objects(std::vector< T > &container, uint64_t count)
Definition BinaryStream.hpp:111
ok_error_t peek_objects_at(uint64_t offset, std::vector< T > &container, uint64_t count)
Definition BinaryStream.hpp:127
result< std::u16string > peek_u16string(size_t length) const
result< std::u16string > read_u16string() const
void set_endian_swap(bool swap)
Definition BinaryStream.hpp:203
result< std::u16string > peek_u16string() const
bool should_swap() const
Definition BinaryStream.hpp:214
result< std::string > peek_string_at(size_t offset, size_t maxsize=~static_cast< size_t >(0)) const
ok_error_t peek_objects(std::vector< T > &container, uint64_t count)
Definition BinaryStream.hpp:122
size_t pos() const
Definition BinaryStream.hpp:165
virtual uint8_t * start()
Definition BinaryStream.hpp:222
const T * peek_array(size_t size) const
Definition BinaryStream.hpp:391
void setpos(size_t pos) const
Definition BinaryStream.hpp:149
virtual const uint8_t * end() const
Definition BinaryStream.hpp:238
static bool is_all_zero(const T &buffer)
Definition BinaryStream.hpp:208
result< std::string > read_string(size_t maxsize=~static_cast< size_t >(0)) const
result< std::u16string > read_u16string(size_t length) const
virtual ok_error_t peek_data(std::vector< uint8_t > &container, uint64_t offset, uint64_t size, uint64_t virtual_address=0)
Definition BinaryStream.hpp:76
void decrement_pos(size_t value) const
Definition BinaryStream.hpp:157
result< T > read() const
Definition BinaryStream.hpp:355
BinaryStream(STREAM_TYPE type)
Definition BinaryStream.hpp:47
virtual const uint8_t * start() const
Definition BinaryStream.hpp:234
bool can_read(int64_t offset, int64_t size) const
Definition BinaryStream.hpp:197
virtual ~BinaryStream()=default
STREAM_TYPE type() const
Definition BinaryStream.hpp:53
virtual ok_error_t read_data(std::vector< uint8_t > &container, uint64_t size)
Definition BinaryStream.hpp:100
virtual uint8_t * end()
Definition BinaryStream.hpp:230
Definition BinaryStream.hpp:269
const BinaryStream & operator*() const
Definition BinaryStream.hpp:301
ScopedStream(BinaryStream &stream, uint64_t pos)
Definition BinaryStream.hpp:277
ScopedStream(BinaryStream &stream)
Definition BinaryStream.hpp:284
ScopedStream(const ScopedStream &)=delete
ScopedStream & operator=(const ScopedStream &)=delete
ScopedStream & operator=(ScopedStream &&)=delete
~ScopedStream()
Definition BinaryStream.hpp:289
BinaryStream & operator*()
Definition BinaryStream.hpp:297
ScopedStream(ScopedStream &&)=delete
BinaryStream * operator->()
Definition BinaryStream.hpp:293
Definition BinaryStream.hpp:310
ToggleEndianness(BinaryStream &stream, bool value)
Definition BinaryStream.hpp:318
ToggleEndianness(ToggleEndianness &&)=delete
ToggleEndianness & operator=(const ToggleEndianness &)=delete
ToggleEndianness & operator=(ToggleEndianness &&)=delete
BinaryStream & operator*()
Definition BinaryStream.hpp:340
BinaryStream * operator->()
Definition BinaryStream.hpp:336
ToggleEndianness(BinaryStream &stream)
Definition BinaryStream.hpp:325
~ToggleEndianness()
Definition BinaryStream.hpp:332
const BinaryStream & operator*() const
Definition BinaryStream.hpp:344
ToggleEndianness(const ToggleEndianness &)=delete
@ read_error
Definition errors.hpp:24
tl::unexpected< lief_errors > make_error_code(lief_errors e)
Create an standard error code from lief_errors.
Definition errors.hpp:52
LIEF namespace.
Definition Abstract/Binary.hpp:36
result< ok_t > ok_error_t
Opaque structure that is used by LIEF to avoid writing result<void> f(...). Instead,...
Definition errors.hpp:109
ok_t ok()
Return success for function with return type ok_error_t.
Definition errors.hpp:93
void swap_endian(T *)
Definition endianness_support.hpp:116
tl::expected< T, lief_errors > result
Wrapper that contains an Object (T) or an error.
Definition errors.hpp:75
#define LIEF_API
Definition visibility.h:41