LIEF: Library to Instrument Executable Formats Version 1.0.0
Loading...
Searching...
No Matches
BinaryStream.hpp
Go to the documentation of this file.
1/* Copyright 2017 - 2026 R. Thomas
2 * Copyright 2017 - 2026 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#include <utility>
25
27#include "LIEF/errors.hpp"
28#include "LIEF/visibility.h"
29
30namespace LIEF {
31class ASN1Reader;
32
35 public:
36 friend class ASN1Reader;
37
38 enum class STREAM_TYPE {
39 UNKNOWN = 0,
40 VECTOR,
41 MEMORY,
42 SPAN,
43 FILE,
44
45 ELF_DATA_HANDLER,
46 };
47
50 virtual ~BinaryStream() = default;
51 virtual uint64_t size() const = 0;
52
53 STREAM_TYPE type() const {
54 return stype_;
55 }
56
57 bool is_memory_stream() const {
58 return type() == STREAM_TYPE::MEMORY;
59 }
60
61 result<uint64_t> read_uleb128(size_t* size = nullptr) const;
62 result<uint64_t> read_sleb128(size_t* size = nullptr) const;
63
64 result<int64_t> read_dwarf_encoded(uint8_t encoding) const;
65
66 result<std::string> read_string(size_t maxsize = ~static_cast<size_t>(0)) const;
67 result<std::string> peek_string(size_t maxsize = ~static_cast<size_t>(0)) const;
69 peek_string_at(size_t offset,
70 size_t maxsize = ~static_cast<size_t>(0)) const;
71
74
75 result<std::string> read_mutf8(size_t maxsize = ~static_cast<size_t>(0)) const;
76
79 result<std::u16string> peek_u16string_at(size_t offset, size_t length) const;
80
81
82 virtual ok_error_t peek_data(std::vector<uint8_t>& container, uint64_t offset,
83 uint64_t size, uint64_t virtual_address = 0) {
84 if (size == 0) {
85 return ok();
86 }
87 // Even though offset + size < ... => offset < ...
88 // the addition could overflow so it's worth checking both
89 const bool read_ok = offset <= this->size() &&
90 (offset + size) <= this->size()
91 /* Check for an overflow */
92 && (static_cast<int64_t>(offset) >= 0 &&
93 static_cast<int64_t>(size) >= 0) &&
94 (static_cast<int64_t>(offset + size) >= 0);
95 if (!read_ok) {
97 }
98
99 if (container.size() < size) {
100 std::vector<uint8_t> buffer(size);
101 const ok_error_t res = peek_in(buffer.data(), offset, size, virtual_address);
102 container = std::move(buffer);
103 return res;
104 }
105
106 return peek_in(container.data(), offset, size, virtual_address);
107 }
108
109 virtual ok_error_t read_data(std::vector<uint8_t>& container, uint64_t size) {
110 if (!peek_data(container, pos(), size)) {
112 }
113
115 return ok();
116 }
117
118 ok_error_t read_data(std::vector<uint8_t>& container) {
119 const size_t size = this->size() - this->pos();
120 return read_data(container, size);
121 }
122
123 template<class T>
124 ok_error_t read_objects(std::vector<T>& container, uint64_t count) {
125 if (count == 0) {
126 return ok();
127 }
128 const size_t size = count * sizeof(T);
129 auto ret = peek_objects(container, count);
130 if (!ret) {
132 }
134 return ok();
135 }
136
137 template<class T>
138 ok_error_t peek_objects(std::vector<T>& container, uint64_t count) {
139 return peek_objects_at(pos(), container, count);
140 }
141
142 template<class T>
143 ok_error_t peek_objects_at(uint64_t offset, std::vector<T>& container,
144 uint64_t count) {
145 if (count == 0) {
146 return ok();
147 }
148 const auto current_p = pos();
149 setpos(offset);
150
151 const size_t size = count * sizeof(T);
152
153 if (!can_read(offset, size)) {
154 setpos(current_p);
156 }
157
159
160 if (container.size() < count) {
161 std::vector<T> buffer(count);
162 res = peek_in(buffer.data(), pos(), size);
163 container = std::move(buffer);
164 } else {
165 res = peek_in(container.data(), pos(), size);
166 }
167
168 setpos(current_p);
169 return res;
170 }
171
172 void setpos(size_t pos) const {
173 pos_ = pos;
174 }
175
176 const BinaryStream& increment_pos(size_t value) const LIEF_LIFETIMEBOUND {
177 pos_ += value;
178 return *this;
179 }
180
181 void decrement_pos(size_t value) const {
182 if (pos_ > value) {
183 pos_ -= value;
184 } else {
185 pos_ = 0;
186 }
187 }
188
189 size_t pos() const {
190 return pos_;
191 }
192
193 bool is_valid() const {
194 return pos_ < size();
195 }
196
197 operator bool() const {
198 return is_valid();
199 }
200
201 template<class T>
202 const T* read_array(size_t size) const;
203
204 template<class T, size_t N>
205 ok_error_t peek_array(std::array<T, N>& dst) const {
206 if /*constexpr*/ (N == 0) {
207 return ok();
208 }
209 // Even though offset + size < ... => offset < ...
210 // the addition could overflow so it's worth checking both
211 const bool read_ok =
212 pos_ <= size() &&
213 (pos_ + N) <= size()
214 /* Check for an overflow */
215 && (static_cast<int64_t>(pos_) >= 0 && static_cast<int64_t>(N) >= 0) &&
216 (static_cast<int64_t>(pos_ + N) >= 0);
217
218 if (!read_ok) {
220 }
221 if (peek_in(dst.data(), pos_, N)) {
222 return ok();
223 }
225 }
226
227 template<class T, size_t N>
228 ok_error_t read_array(std::array<T, N>& dst) const {
229 if (!peek_array<T, N>(dst)) {
231 }
232
233 increment_pos(N);
234 return ok();
235 }
236
237 template<class T>
238 result<T> peek() const;
239
240 template<class T>
241 result<T> peek(size_t offset) const;
242
243 template<class T>
244 const T* peek_array(size_t size) const;
245
246 template<class T>
247 const T* peek_array(size_t offset, size_t size) const;
248
249 template<class T>
250 result<T> read() const;
251
252 template<typename T>
253 bool can_read() const;
254
255 template<typename T>
256 bool can_read(size_t offset) const;
257
258 bool can_read(int64_t offset, int64_t size) const {
259 return offset < (int64_t)this->size() &&
260 (offset + size) < (int64_t)this->size();
261 }
262
263 size_t align(size_t align_on) const;
264
265 void set_endian_swap(bool swap) {
266 endian_swap_ = swap;
267 }
268
269 template<class T>
270 static bool is_all_zero(const T& buffer) {
271 const auto* ptr = reinterpret_cast<const uint8_t* const>(&buffer);
272 return std::all_of(ptr, ptr + sizeof(T), [](uint8_t x) { return x == 0; });
273 }
274
275 bool should_swap() const {
276 return endian_swap_;
277 }
278
279 virtual const uint8_t* p() const {
280 return nullptr;
281 }
282
283 virtual uint8_t* start() {
284 return const_cast<uint8_t*>(static_cast<const BinaryStream*>(this)->start());
285 }
286
287 virtual uint8_t* p() {
288 return const_cast<uint8_t*>(static_cast<const BinaryStream*>(this)->p());
289 }
290
291 virtual uint8_t* end() {
292 return const_cast<uint8_t*>(static_cast<const BinaryStream*>(this)->end());
293 }
294
295 virtual const uint8_t* start() const {
296 return nullptr;
297 }
298
299 virtual const uint8_t* end() const {
300 return nullptr;
301 }
302
303 virtual result<const void*> read_at(uint64_t offset, uint64_t size,
304 uint64_t virtual_address = 0) const = 0;
305 virtual ok_error_t peek_in(void* dst, uint64_t offset, uint64_t size,
306 uint64_t virtual_address = 0) const {
307 if (auto raw = read_at(offset, size, virtual_address)) {
308 if (dst == nullptr) {
310 }
311
312 const void* ptr = *raw;
313
314 if (ptr == nullptr) {
316 }
317
318 memcpy(dst, ptr, size);
319 return ok();
320 }
322 }
323
324 template<class T>
325 const T* cast() const {
326 static_assert(std::is_base_of<BinaryStream, T>::value,
327 "Require BinaryStream inheritance");
328 if (T::classof(*this)) {
329 return static_cast<const T*>(this);
330 }
331 return nullptr;
332 }
333
334 template<class T>
335 T* cast() {
336 return const_cast<T*>(static_cast<const BinaryStream*>(this)->cast<T>());
337 }
338
339 protected:
340 BinaryStream() = default;
341
342 mutable size_t pos_ = 0;
343 bool endian_swap_ = false;
344 STREAM_TYPE stype_ = STREAM_TYPE::UNKNOWN;
345};
346
348 public:
349 ScopedStream(const ScopedStream&) = delete;
351
354
355 explicit ScopedStream(BinaryStream& stream, uint64_t pos) :
356 pos_{stream.pos()},
357 stream_{stream} {
358 stream_.setpos(pos);
359 }
360
361 explicit ScopedStream(BinaryStream& stream) :
362 pos_{stream.pos()},
363 stream_{stream} {}
364
366 stream_.setpos(pos_);
367 }
368
370 return &stream_;
371 }
372
374 return stream_;
375 }
376
377 const BinaryStream& operator*() const {
378 return stream_;
379 }
380
381 private:
382 uint64_t pos_ = 0;
383 BinaryStream& stream_;
384};
385
387 public:
390
393
394 explicit ToggleEndianness(BinaryStream& stream, bool value) :
395 endian_swap_(stream.should_swap()),
396 stream_{stream} {
397 stream.set_endian_swap(value);
398 }
399
400 explicit ToggleEndianness(BinaryStream& stream) :
401 endian_swap_(stream.should_swap()),
402 stream_{stream} {
403 stream.set_endian_swap(!stream_.should_swap());
404 }
405
407 stream_.set_endian_swap(endian_swap_);
408 }
409
411 return &stream_;
412 }
413
415 return stream_;
416 }
417
418 const BinaryStream& operator*() const {
419 return stream_;
420 }
421
422 private:
423 bool endian_swap_ = false;
424 BinaryStream& stream_;
425};
426
427
428template<class T>
430 result<T> tmp = this->peek<T>();
431 if (!tmp) {
432 return tmp;
433 }
434 this->increment_pos(sizeof(T));
435 return tmp;
436}
437
438template<class T>
440 const auto current_p = pos();
441 T ret{};
442 if (auto res = peek_in(&ret, pos(), sizeof(T))) {
443 setpos(current_p);
444 if (endian_swap_) {
445 swap_endian(&ret);
446 }
447 return ret;
448 }
449
450 setpos(current_p);
452}
453
454template<class T>
455result<T> BinaryStream::peek(size_t offset) const {
456 const size_t saved_offset = this->pos();
457 this->setpos(offset);
458 result<T> r = this->peek<T>();
459 this->setpos(saved_offset);
460 return r;
461}
462
463
464template<class T>
465const T* BinaryStream::peek_array(size_t size) const {
466 result<const void*> raw = this->read_at(this->pos(), sizeof(T) * size);
467 if (!raw) {
468 return nullptr;
469 }
470 return reinterpret_cast<const T*>(raw.value());
471}
472
473template<class T>
474const T* BinaryStream::peek_array(size_t offset, size_t size) const {
475 const size_t saved_offset = this->pos();
476 this->setpos(offset);
477 const T* r = this->peek_array<T>(size);
478 this->setpos(saved_offset);
479 return r;
480}
481
482
483template<typename T>
485 // Even though pos_ + sizeof(T) < ... => pos_ < ...
486 // the addition could overflow so it's worth checking both
487 return pos_ < size() && (pos_ + sizeof(T)) < size();
488}
489
490
491template<typename T>
492bool BinaryStream::can_read(size_t offset) const {
493 // Even though offset + sizeof(T) < ... => offset < ...
494 // the addition could overflow so it's worth checking both
495 return offset < size() && (offset + sizeof(T)) < size();
496}
497
498
499template<class T>
500const T* BinaryStream::read_array(size_t size) const {
501 const T* tmp = this->peek_array<T>(size);
502 this->increment_pos(sizeof(T) * size);
503 return tmp;
504}
505
506}
507#endif
Definition ASN1Reader.hpp:32
Class that is used to a read stream of data from different sources.
Definition BinaryStream.hpp:34
size_t align(size_t align_on) const
ok_error_t peek_array(std::array< T, N > &dst) const
Definition BinaryStream.hpp:205
result< std::string > read_mutf8(size_t maxsize=~static_cast< size_t >(0)) const
STREAM_TYPE
Definition BinaryStream.hpp:38
@ MEMORY
Definition BinaryStream.hpp:41
result< T > peek() const
Definition BinaryStream.hpp:439
result< int64_t > read_dwarf_encoded(uint8_t encoding) const
virtual uint8_t * p()
Definition BinaryStream.hpp:287
result< std::string > peek_string(size_t maxsize=~static_cast< size_t >(0)) const
virtual const uint8_t * p() const
Definition BinaryStream.hpp:279
const T * read_array(size_t size) const
Definition BinaryStream.hpp:500
virtual uint64_t size() const =0
friend class ASN1Reader
Definition BinaryStream.hpp:36
result< std::u16string > peek_u16string_at(size_t offset, size_t length) const
bool can_read() const
Definition BinaryStream.hpp:484
ok_error_t read_objects(std::vector< T > &container, uint64_t count)
Definition BinaryStream.hpp:124
ok_error_t peek_objects_at(uint64_t offset, std::vector< T > &container, uint64_t count)
Definition BinaryStream.hpp:143
result< std::u16string > peek_u16string(size_t length) const
const T * cast() const
Definition BinaryStream.hpp:325
result< std::u16string > read_u16string() const
void set_endian_swap(bool swap)
Definition BinaryStream.hpp:265
bool is_memory_stream() const
Definition BinaryStream.hpp:57
const BinaryStream & increment_pos(size_t value) const
Definition BinaryStream.hpp:176
result< std::u16string > peek_u16string() const
bool should_swap() const
Definition BinaryStream.hpp:275
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:138
size_t pos() const
Definition BinaryStream.hpp:189
virtual uint8_t * start()
Definition BinaryStream.hpp:283
result< uint64_t > read_uleb128(size_t *size=nullptr) const
virtual result< const void * > read_at(uint64_t offset, uint64_t size, uint64_t virtual_address=0) const =0
void setpos(size_t pos) const
Definition BinaryStream.hpp:172
bool is_valid() const
Definition BinaryStream.hpp:193
virtual const uint8_t * end() const
Definition BinaryStream.hpp:299
static bool is_all_zero(const T &buffer)
Definition BinaryStream.hpp:270
result< std::string > read_string(size_t maxsize=~static_cast< size_t >(0)) const
T * cast()
Definition BinaryStream.hpp:335
virtual ok_error_t peek_in(void *dst, uint64_t offset, uint64_t size, uint64_t virtual_address=0) const
Definition BinaryStream.hpp:305
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:82
void decrement_pos(size_t value) const
Definition BinaryStream.hpp:181
result< T > read() const
Definition BinaryStream.hpp:429
BinaryStream(STREAM_TYPE type)
Definition BinaryStream.hpp:48
virtual const uint8_t * start() const
Definition BinaryStream.hpp:295
result< uint64_t > read_sleb128(size_t *size=nullptr) const
ok_error_t read_array(std::array< T, N > &dst) const
Definition BinaryStream.hpp:228
bool can_read(int64_t offset, int64_t size) const
Definition BinaryStream.hpp:258
ok_error_t read_data(std::vector< uint8_t > &container)
Definition BinaryStream.hpp:118
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:109
virtual uint8_t * end()
Definition BinaryStream.hpp:291
const BinaryStream & operator*() const
Definition BinaryStream.hpp:377
ScopedStream(BinaryStream &stream, uint64_t pos)
Definition BinaryStream.hpp:355
ScopedStream(BinaryStream &stream)
Definition BinaryStream.hpp:361
ScopedStream(const ScopedStream &)=delete
ScopedStream & operator=(const ScopedStream &)=delete
ScopedStream & operator=(ScopedStream &&)=delete
~ScopedStream()
Definition BinaryStream.hpp:365
BinaryStream & operator*()
Definition BinaryStream.hpp:373
ScopedStream(ScopedStream &&)=delete
BinaryStream * operator->()
Definition BinaryStream.hpp:369
ToggleEndianness(BinaryStream &stream, bool value)
Definition BinaryStream.hpp:394
ToggleEndianness(ToggleEndianness &&)=delete
ToggleEndianness & operator=(const ToggleEndianness &)=delete
ToggleEndianness & operator=(ToggleEndianness &&)=delete
BinaryStream & operator*()
Definition BinaryStream.hpp:414
BinaryStream * operator->()
Definition BinaryStream.hpp:410
ToggleEndianness(BinaryStream &stream)
Definition BinaryStream.hpp:400
~ToggleEndianness()
Definition BinaryStream.hpp:406
const BinaryStream & operator*() const
Definition BinaryStream.hpp:418
ToggleEndianness(const ToggleEndianness &)=delete
Opaque structure that is used by LIEF to avoid writing result<void> f(...). Instead,...
Definition errors.hpp:118
Wrapper that contains an Object (T) or an error.
Definition errors.hpp:78
#define LIEF_LIFETIMEBOUND
Definition compiler_attributes.hpp:72
@ read_error
Definition errors.hpp:25
@ inconsistent
Definition errors.hpp:43
tl::unexpected< lief_errors > make_error_code(lief_errors e)
Create a standard error code from lief_errors.
Definition errors.hpp:54
LIEF namespace.
Definition Abstract/Binary.hpp:40
ok_t ok()
Return success for function with return type ok_error_t.
Definition errors.hpp:102
void swap_endian(T *)
Definition endianness_support.hpp:117
#define LIEF_API
Definition visibility.h:45