Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reconstructing IAT many times can break PE files #523

Open
Catminusminus opened this issue Jan 15, 2021 · 0 comments · May be fixed by #528
Open

Reconstructing IAT many times can break PE files #523

Catminusminus opened this issue Jan 15, 2021 · 0 comments · May be fixed by #528
Assignees

Comments

@Catminusminus
Copy link

Describe the bug
Applying IAT reconstruction by patch_imports(true) and build_imports(true) many times can produce broken PE files.

To Reproduce

  1. Make a PE file by compiling the following code.
#include <stdio.h>

int main() {
	printf("Hello, World!");
	return 0;
}

(I used Microsoft Visual Studio Professional 2019 Version 16.3.9 to compile it.)
Assume that this produced "original.exe".

  1. Clone the LIEF repository and modify LIEF/examples/cpp/pe_builder.cpp to the following code.
#include <iostream>
#include <memory>
#include <fstream>
#include <algorithm>
#include <iterator>

#include <LIEF/PE.hpp>

using namespace LIEF::PE;
int main(int argc, char **argv) {
  std::cout << "PE Rebuilder" << std::endl;
  if (argc != 3) {
    std::cerr << "Usage: " << argv[0] << " <Input Binary> <Output Binary>" << std::endl;
    return -1;
  }

  std::unique_ptr<Binary> binary{Parser::parse(argv[1])};
  binary->optional_header().remove(DLL_CHARACTERISTICS::IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE);
  Builder builder{binary.get()};

  builder
    .build_imports(true)
    .patch_imports(true)
    .build_tls(false)
    .build_resources(false);

  builder.build();
  builder.write(argv[2]);
  std::cout << binary->name() << std::endl;

  return 0;
}
  1. Build LIEF and the example codes including the above modified LIEF/examples/cpp/pe_builder.cpp. This makes modified version of pe_builder.

  2. Applyfing IAT reconstruction by the modified pe_builder 9 times. For example,

./pe_builder original.exe 2.exe
./pe_builder 2.exe 3.exe
./pe_builder 3.exe 4.exe
...
./pe_builder 9.exe 10.exe
  1. Run the 10.exe and you will see that it exits abnormally.

Expected behavior
You will see "Hello, World!".

Environment (please complete the following information):

  • System and Version : Ubuntu 18.04 (Building LIEF and modifying original.exe) and Ubuntu 18.04 on WSL1 on Windows 10 1909 (running the 10.exe)
  • Target format (PE, ELF, Mach-O) : PE
  • LIEF commit version: 0.11.0-cd286e1

Additional context
This behavior seems to be due to the current implementation of finding the "original" import section logic.
Look at the LIEF/src/PE/Builder.tcc.

  // As add_section will change DATA_DIRECTORY::IMPORT_TABLE we have to save it before
  uint32_t offset_imports  = this->binary_->rva_to_offset(this->binary_->data_directory(DATA_DIRECTORY::IMPORT_TABLE).RVA());
  Section& import_section = this->binary_->add_section(new_import_section, PE_SECTION_TYPES::IMPORT);


  // Patch the original IAT with the address of the associated trampoline
  if (this->patch_imports_) {
    Section& original_import = this->binary_->section_from_offset(offset_imports);
    std::vector<uint8_t> import_content  = original_import.content();
    uint32_t roffset_import = offset_imports - original_import.offset();

In some cases, original_import is not corresponding to the "original" import section.
The IAT reconstruction makes an additional section so that an additional section header will be added, too.
This increase the header size and can move sections backward. In this case, original_import returns the previous section of the "original" import section.

I am creating a PR but some tests failed at commit d1ad5ab on Ubuntu 18.04 on EC2 without any modification, so I am investigating the issue.

This was referenced Jan 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants