├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── examples ├── CMakeLists.txt └── main.cpp └── include └── pe-builder └── pe-builder.h /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .vscode/ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.9) 2 | 3 | project(pe-builder 4 | DESCRIPTION "" 5 | HOMEPAGE_URL "https://github.com/jonomango/pe-builder" 6 | LANGUAGES CXX C 7 | ) 8 | 9 | option(PE_BUILDER_BUILD_EXAMPLES "Build the pe-builder examples." OFF) 10 | 11 | # create pe_builder as an INTERFACE since it is header-only 12 | add_library(pe-builder INTERFACE) 13 | target_include_directories(pe-builder INTERFACE include) 14 | target_compile_features(pe-builder INTERFACE cxx_std_17 c_std_11) 15 | 16 | # hack to get files to show up in IDEs as a project 17 | add_custom_target(pe-builder-library SOURCES include/pe-builder/pe-builder.h) 18 | 19 | # build the examples 20 | if (PE_BUILDER_BUILD_EXAMPLES) 21 | add_subdirectory(examples) 22 | endif() -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 jono 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pe-builder 2 | 3 | Header-only C++ library for producing PE files. 4 | 5 | **Disclaimer:** Very bad code ahead, consider using another library. 6 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # include the main library 2 | link_libraries(pe-builder) 3 | 4 | # examples 5 | add_executable(pe-builder-ex-main main.cpp) 6 | -------------------------------------------------------------------------------- /examples/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | pb::pe_builder pe; 6 | 7 | pe.section_alignment(0x1000) 8 | .file_alignment(0x200) 9 | .image_base(0x140000000) 10 | .subsystem(IMAGE_SUBSYSTEM_WINDOWS_CUI) 11 | .file_characteristics(IMAGE_FILE_EXECUTABLE_IMAGE); 12 | 13 | printf("Remaining sections: %zX.\n", pe.sections_until_resize()); 14 | 15 | auto& text_sec = pe.section() 16 | .name(".text") 17 | .characteristics(IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE); 18 | 19 | text_sec.data().push_back(0xAA); 20 | text_sec.data().push_back(0xBB); 21 | 22 | auto& bss_sec = pe.section() 23 | .name(".bss") 24 | .characteristics(IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE) 25 | .padding(0x1999); 26 | 27 | auto& data_sec = pe.section() 28 | .name(".data") 29 | .characteristics(IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE); 30 | 31 | data_sec.data().push_back(0xCC); 32 | data_sec.data().push_back(0xDD); 33 | 34 | // Set the entrypoint to the start of the .text section. 35 | pe.entrypoint(pe.virtual_address(text_sec)); 36 | 37 | if (!pe.write("fish-frog.exe")) 38 | printf("Failed to write PE image.\n"); 39 | else 40 | printf("Wrote PE image to file.\n"); 41 | 42 | printf("VA of .text section: 0x%zX.\n", pe.virtual_address(text_sec)); 43 | printf("VA of .bss section: 0x%zX.\n", pe.virtual_address(bss_sec)); 44 | printf("VA of .data section: 0x%zX.\n", pe.virtual_address(data_sec)); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /include/pe-builder/pe-builder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace pb { 12 | 13 | class pe_section { 14 | public: 15 | // Set the name of this section (maximum of 8 characters). 16 | // This directly corresponds to IMAGE_SECTION_HEADER::Name. 17 | pe_section& name(char const* name); 18 | 19 | // Set the virtual padding to be added to the end of this section (all zeros). 20 | // This is pretty much VirtualSize - SizeOfRawData, if we ignore alignment. 21 | pe_section& padding(std::uint32_t value); 22 | 23 | // Set the characteristics of this section. 24 | // This directly corresponds to IMAGE_SECTION_HEADER::Characteristics. 25 | pe_section& characteristics(std::uint32_t value); 26 | 27 | // Get a reference to the raw data that makes up this section. 28 | std::vector& data(); 29 | 30 | private: 31 | friend class pe_builder; 32 | 33 | // The index of this section in the section vector. 34 | std::size_t section_idx_ = 0; 35 | 36 | // This is null-terminated but the real section name wont be (only 8 bytes). 37 | char name_[9] = { 0 }; 38 | 39 | // Raw data (not including padding). 40 | std::vector data_ = {}; 41 | 42 | std::uint32_t padding_ = 0; 43 | std::uint32_t characteristics_ = 0; 44 | }; 45 | 46 | class pe_builder { 47 | public: 48 | // Write the PE image to a file 49 | bool write(char const* path) const; 50 | 51 | // Write the PE image to a buffer. 52 | std::vector write() const; 53 | 54 | // Set the section alignment. 55 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::SectionAlignment. 56 | pe_builder& section_alignment(std::uint32_t alignment); 57 | 58 | // Get the section alignment. 59 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::SectionAlignment. 60 | std::uint32_t section_alignment() const; 61 | 62 | // Set the file alignment. 63 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::FileAlignment. 64 | pe_builder& file_alignment(std::uint32_t alignment); 65 | 66 | // Get the file alignment. 67 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::FileAlignment. 68 | std::uint32_t file_alignment() const; 69 | 70 | // Set the image base address. 71 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::ImageBase. 72 | pe_builder& image_base(std::uint64_t address); 73 | 74 | // Get the image base address. 75 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::ImageBase. 76 | std::uint64_t image_base() const; 77 | 78 | // Set the entrypoint address. 79 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::AddressOfEntryPoint. 80 | pe_builder& entrypoint(std::uint64_t address); 81 | 82 | // Get the entrypoint address. 83 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::AddressOfEntryPoint. 84 | std::uint64_t entrypoint() const; 85 | 86 | // Set the subsystem type. 87 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::Subsystem. 88 | pe_builder& subsystem(std::uint16_t value); 89 | 90 | // Get the subsystem type. 91 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::Subsystem. 92 | std::uint16_t subsystem() const; 93 | 94 | // Set the file characteristics. 95 | // This directly corresponds to IMAGE_NT_HEADERS::FileHeader::Characteristics. 96 | pe_builder& file_characteristics(std::uint16_t value); 97 | 98 | // Get the file characteristics. 99 | // This directly corresponds to IMAGE_NT_HEADERS::FileHeader::Characteristics. 100 | std::uint16_t file_characteristics() const; 101 | 102 | // Append a new section to the PE image. 103 | pe_section& section(); 104 | 105 | // Set the RVA and size of the specified data directory. 106 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::DataDirectory[idx]. 107 | pe_builder& data_directory(std::size_t idx, std::uint32_t rva, std::uint32_t size); 108 | 109 | // Compute the virtual address of a section. 110 | std::uint64_t virtual_address(pe_section const& section) const; 111 | 112 | // Compute the RVA of a section. 113 | std::uint32_t rvirtual_address(pe_section const& section) const; 114 | 115 | // Return the remaining number of sections that can be added until the 116 | // image header is resized (which will invalidate all previously computed 117 | // section virtual addresses. This value is usually way more than enough 118 | // unless you use a low section alignment. 119 | std::size_t sections_until_resize() const; 120 | 121 | private: 122 | std::uint32_t section_alignment_ = 0x1000; 123 | std::uint32_t file_alignment_ = 0x200; 124 | std::uint64_t image_base_ = 0x140000000; 125 | std::uint64_t entrypoint_ = 0x0; 126 | std::uint16_t subsystem_ = IMAGE_SUBSYSTEM_WINDOWS_CUI; 127 | std::uint16_t file_characteristics_ = IMAGE_FILE_EXECUTABLE_IMAGE; 128 | IMAGE_DATA_DIRECTORY data_directories_[16] = { 0 }; 129 | 130 | // We need to use a deque so we don't invalidate any iterators. 131 | std::deque sections_ = {}; 132 | 133 | private: 134 | // Fill in the DOS header. 135 | void write_dos_header(PIMAGE_DOS_HEADER dos_header) const; 136 | 137 | // Fill in the NT header. 138 | void write_nt_header(PIMAGE_NT_HEADERS64 nt_header, 139 | std::uint32_t image_size, std::uint32_t headers_size) const; 140 | 141 | // Compute the (unaligned) headers size. 142 | static std::size_t compute_headers_size(std::size_t num_sections); 143 | 144 | // Align an integer up to the specified alignment. 145 | static std::uint64_t align_integer(std::uint64_t value, std::uint64_t alignment); 146 | }; 147 | 148 | // Set the name of this section (maximum of 8 characters). 149 | inline pe_section& pe_section::name(char const* const name) { 150 | if (!name) { 151 | std::memset(&name_, 0, sizeof(name_)); 152 | return *this; 153 | } 154 | 155 | // This smells a little... 156 | strncpy_s(name_, name, 8); 157 | return *this; 158 | } 159 | 160 | // Set the virtual padding to be added to the end of this section (all zeros). 161 | // This is pretty much VirtualSize - SizeOfRawData, if we ignore alignment. 162 | inline pe_section& pe_section::padding(std::uint32_t const value) { 163 | padding_ = value; 164 | return *this; 165 | } 166 | 167 | // Set the characteristics of this section. 168 | // This directly corresponds to IMAGE_SECTION_HEADER::Characteristics. 169 | inline pe_section& pe_section::characteristics(std::uint32_t const value) { 170 | characteristics_ = value; 171 | return *this; 172 | } 173 | 174 | // Get a reference to the raw data that makes up this section. 175 | inline std::vector& pe_section::data() { 176 | return data_; 177 | } 178 | 179 | // Write the PE image to a file 180 | inline bool pe_builder::write(char const* const path) const { 181 | auto const contents = write(); 182 | if (contents.empty()) 183 | return false; 184 | 185 | std::ofstream file(path, std::ios::binary); 186 | if (!file) 187 | return false; 188 | 189 | file.write(reinterpret_cast(contents.data()), contents.size()); 190 | 191 | return true; 192 | } 193 | 194 | // Write the PE image to a buffer. 195 | inline std::vector pe_builder::write() const { 196 | // This is the initial file size of the image, before we start adding the 197 | // raw section data. This value is aligned to the file alignment. 198 | auto const headers_size = align_integer( 199 | compute_headers_size(sections_.size()), file_alignment_); 200 | 201 | // Allocate a vector with enough space for the MS-DOS header, the PE header, 202 | // and the section headers. 203 | std::vector contents(headers_size, 0); 204 | 205 | std::uint64_t current_rva = align_integer( 206 | static_cast(headers_size), section_alignment_); 207 | 208 | auto const section_hdrs = reinterpret_cast( 209 | &contents[sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS64)]); 210 | 211 | for (std::size_t i = 0; i < sections_.size(); ++i) { 212 | auto const& sec = sections_[i]; 213 | 214 | assert(rvirtual_address(sec) == current_rva); 215 | 216 | // This needs to be computed everytime since we're using a vector and it can resize. 217 | auto& hdr = reinterpret_cast( 218 | &contents[sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS64)])[i]; 219 | 220 | std::memset(&hdr, 0, sizeof(hdr)); 221 | std::memcpy(hdr.Name, sec.name_, 8); 222 | hdr.Characteristics = sec.characteristics_; 223 | hdr.VirtualAddress = static_cast(current_rva); 224 | hdr.Misc.VirtualSize = static_cast(sec.data_.size() + sec.padding_); 225 | hdr.SizeOfRawData = static_cast( 226 | align_integer(sec.data_.size(), file_alignment_)); 227 | hdr.PointerToRawData = static_cast(contents.size()); 228 | 229 | // This needs to be stored before we add to the buffer. 230 | auto const aligned_size = hdr.SizeOfRawData; 231 | 232 | // Append the section data to the buffer. 233 | contents.insert(end(contents), begin(sec.data_), end(sec.data_)); 234 | 235 | // We need to add padding so that we're aligned to the file alignment. 236 | if (aligned_size > sec.data_.size()) 237 | contents.insert(end(contents), aligned_size - sec.data_.size(), 0); 238 | 239 | // This is how much virtual padding we need (since we added some real 240 | // padding when aligning to file alignment). 241 | auto const virtual_padding = sec.padding_ - (aligned_size - sec.data_.size()); 242 | 243 | current_rva = align_integer(current_rva 244 | + aligned_size + virtual_padding, section_alignment_); 245 | } 246 | 247 | // Write the headers to the buffer. 248 | write_dos_header(reinterpret_cast(&contents[0])); 249 | write_nt_header(reinterpret_cast( 250 | &contents[sizeof(IMAGE_DOS_HEADER)]), 251 | static_cast(current_rva), 252 | static_cast(headers_size)); 253 | 254 | return contents; 255 | } 256 | 257 | // Set the section alignment. 258 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::SectionAlignment. 259 | inline pe_builder& pe_builder::section_alignment(std::uint32_t const alignment) { 260 | section_alignment_ = alignment; 261 | return *this; 262 | } 263 | 264 | // Get the section alignment. 265 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::SectionAlignment. 266 | inline std::uint32_t pe_builder::section_alignment() const { 267 | return section_alignment_; 268 | } 269 | 270 | // Set the file alignment. 271 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::FileAlignment. 272 | inline pe_builder& pe_builder::file_alignment(std::uint32_t const alignment) { 273 | file_alignment_ = alignment; 274 | return *this; 275 | } 276 | 277 | // Get the file alignment. 278 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::FileAlignment. 279 | inline std::uint32_t pe_builder::file_alignment() const { 280 | return file_alignment_; 281 | } 282 | 283 | // Set the image base address. 284 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::ImageBase. 285 | inline pe_builder& pe_builder::image_base(std::uint64_t const address) { 286 | image_base_ = address; 287 | return *this; 288 | } 289 | 290 | // Get the image base address. 291 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::ImageBase. 292 | inline std::uint64_t pe_builder::image_base() const { 293 | return image_base_; 294 | } 295 | 296 | // Set the entrypoint address. 297 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::AddressOfEntryPoint. 298 | inline pe_builder& pe_builder::entrypoint(std::uint64_t const address) { 299 | entrypoint_ = address; 300 | return *this; 301 | } 302 | 303 | // Get the entrypoint address. 304 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::AddressOfEntryPoint. 305 | inline std::uint64_t pe_builder::entrypoint() const { 306 | return entrypoint_; 307 | } 308 | 309 | // Set the subsystem type. 310 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::Subsystem. 311 | inline pe_builder& pe_builder::subsystem(std::uint16_t const value) { 312 | subsystem_ = value; 313 | return *this; 314 | } 315 | 316 | // Get the subsystem type. 317 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::Subsystem. 318 | inline std::uint16_t pe_builder::subsystem() const { 319 | return subsystem_; 320 | } 321 | 322 | // Set the file characteristics. 323 | // This directly corresponds to IMAGE_NT_HEADERS::FileHeader::Characteristics. 324 | inline pe_builder& pe_builder::file_characteristics(std::uint16_t const value) { 325 | file_characteristics_ = value; 326 | return *this; 327 | } 328 | 329 | // Get the file characteristics. 330 | // This directly corresponds to IMAGE_NT_HEADERS::FileHeader::Characteristics. 331 | inline std::uint16_t pe_builder::file_characteristics() const { 332 | return file_characteristics_; 333 | } 334 | 335 | // Append a new section to the PE image. 336 | inline pe_section& pe_builder::section() { 337 | auto& sec = sections_.emplace_back(); 338 | sec.section_idx_ = sections_.size() - 1; 339 | return sec; 340 | } 341 | 342 | // Set the RVA and size of the specified data directory. 343 | // This directly corresponds to IMAGE_NT_HEADERS::OptionalHeader::DataDirectory[idx]. 344 | inline pe_builder& pe_builder::data_directory(std::size_t const idx, 345 | std::uint32_t const rva, std::uint32_t const size) { 346 | assert(idx < 16); 347 | data_directories_[idx] = { rva, size }; 348 | return *this; 349 | } 350 | 351 | // Compute the virtual address of a section. 352 | inline std::uint64_t pe_builder::virtual_address(pe_section const& section) const { 353 | return rvirtual_address(section) + image_base_; 354 | } 355 | 356 | // Compute the RVA of a section. 357 | inline std::uint32_t pe_builder::rvirtual_address(pe_section const& section) const { 358 | // This is the initial file size of the image, before we start adding the 359 | // raw section data. This value is aligned to the file alignment. 360 | auto const headers_size = align_integer( 361 | compute_headers_size(sections_.size()), file_alignment_); 362 | 363 | std::uint32_t current_rva = static_cast(align_integer( 364 | static_cast(headers_size), section_alignment_)); 365 | 366 | for (std::size_t i = 0; i < sections_.size(); ++i) { 367 | if (i == section.section_idx_) 368 | return current_rva; 369 | 370 | auto const& sec = sections_[i]; 371 | 372 | auto const aligned_size = align_integer(sec.data_.size(), file_alignment_); 373 | auto const virtual_padding = sec.padding_ - (aligned_size - sec.data_.size()); 374 | 375 | current_rva = static_cast(align_integer(current_rva + 376 | aligned_size + virtual_padding, section_alignment_)); 377 | } 378 | 379 | return 0; 380 | } 381 | 382 | // Return the remaining number of sections that can be added until the 383 | // image header is resized (which will invalidate all previously computed 384 | // section virtual addresses. This value is usually way more than enough 385 | // unless you use a low section alignment. 386 | inline std::size_t pe_builder::sections_until_resize() const { 387 | auto const unaligned_hdr_size = compute_headers_size(sections_.size()); 388 | return (align_integer(unaligned_hdr_size, section_alignment_) 389 | - unaligned_hdr_size) / sizeof(IMAGE_SECTION_HEADER); 390 | } 391 | 392 | // Fill in the DOS header. 393 | inline void pe_builder::write_dos_header(PIMAGE_DOS_HEADER const dos_header) const { 394 | std::memset(dos_header, 0, sizeof(*dos_header)); 395 | dos_header->e_magic = IMAGE_DOS_SIGNATURE; 396 | dos_header->e_lfanew = sizeof(IMAGE_DOS_HEADER); 397 | // TODO: Mimic a real DOS header instead of this bare minimum code. 398 | } 399 | 400 | // Fill in the NT header. 401 | inline void pe_builder::write_nt_header(PIMAGE_NT_HEADERS64 const nt_header, 402 | std::uint32_t const image_size, std::uint32_t const headers_size) const { 403 | std::memset(nt_header, 0, sizeof(*nt_header)); 404 | nt_header->Signature = IMAGE_NT_SIGNATURE; 405 | nt_header->FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; 406 | nt_header->FileHeader.NumberOfSections = static_cast(sections_.size()); 407 | nt_header->FileHeader.SizeOfOptionalHeader = sizeof(nt_header->OptionalHeader); 408 | nt_header->FileHeader.Characteristics = file_characteristics_; 409 | nt_header->OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC; 410 | nt_header->OptionalHeader.AddressOfEntryPoint = static_cast(entrypoint_ - image_base_); 411 | nt_header->OptionalHeader.ImageBase = image_base_; 412 | nt_header->OptionalHeader.SectionAlignment = section_alignment_; 413 | nt_header->OptionalHeader.FileAlignment = file_alignment_; 414 | nt_header->OptionalHeader.MajorOperatingSystemVersion = 6; 415 | nt_header->OptionalHeader.MinorOperatingSystemVersion = 0; 416 | nt_header->OptionalHeader.MajorSubsystemVersion = 6; 417 | nt_header->OptionalHeader.MinorSubsystemVersion = 0; 418 | nt_header->OptionalHeader.Subsystem = subsystem_; 419 | nt_header->OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 420 | | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_NO_SEH; 421 | nt_header->OptionalHeader.SizeOfStackReserve = 0x10000; 422 | nt_header->OptionalHeader.SizeOfStackCommit = 0x1000; 423 | nt_header->OptionalHeader.SizeOfHeapReserve = 0x10000; 424 | nt_header->OptionalHeader.SizeOfHeapCommit = 0x1000; 425 | nt_header->OptionalHeader.NumberOfRvaAndSizes = 16; 426 | nt_header->OptionalHeader.SizeOfImage = image_size; 427 | nt_header->OptionalHeader.SizeOfHeaders = headers_size; 428 | 429 | // Copy the data directories over. 430 | std::memcpy(nt_header->OptionalHeader.DataDirectory, 431 | data_directories_, sizeof(data_directories_)); 432 | } 433 | 434 | // Compute the (unaligned) headers size. 435 | inline std::size_t pe_builder::compute_headers_size(std::size_t const num_sections) { 436 | // This value might get more complicated if we decide to include a proper 437 | // DOS header (and DOS stub). 438 | return sizeof(IMAGE_DOS_HEADER) + 439 | sizeof(IMAGE_NT_HEADERS64) + 440 | sizeof(IMAGE_SECTION_HEADER) * num_sections; 441 | } 442 | 443 | // Align an integer up to the specified alignment. 444 | inline std::uint64_t pe_builder::align_integer( 445 | std::uint64_t const value, std::uint64_t const alignment) { 446 | auto const r = value % alignment; 447 | 448 | // Already aligned. 449 | if (r == 0) 450 | return value; 451 | 452 | return value + (alignment - r); 453 | } 454 | 455 | } // namespace pb 456 | --------------------------------------------------------------------------------