/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru                                */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person           */
/* obtaining a copy of this software and associated documentation        */
/* files (the "Software"), to deal in the Software without               */
/* restriction, including without limitation the rights to use,          */
/* copy, modify, merge, publish, distribute, sublicense, and/or          */
/* sell copies of the Software, and to permit persons to whom the        */
/* Software is furnished to do so, subject to the following conditions:  */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#pragma once
#include <vector>
#include <string>
#include "pe_structures.h"
#include "pe_directory.h"
#include "pe_base.h"

namespace pe_bliss
{
//Class representing imported function
class imported_function
{
public:
	//Default constructor
	imported_function();

	//Returns true if imported function has name (and hint)
	bool has_name() const;
	//Returns name of function
	const std::string& get_name() const;
	//Returns hint
	uint16_t get_hint() const;
	//Returns ordinal of function
	uint16_t get_ordinal() const;

	//Returns IAT entry VA (usable if image has both IAT and original IAT and is bound)
	uint64_t get_iat_va() const;

public: //Setters do not change everything inside image, they are used by PE class
	//You also can use them to rebuild image imports
	//Sets name of function
	void set_name(const std::string& name);
	//Sets hint
	void set_hint(uint16_t hint);
	//Sets ordinal
	void set_ordinal(uint16_t ordinal);

	//Sets IAT entry VA (usable if image has both IAT and original IAT and is bound)
	void set_iat_va(uint64_t rva);

private:
	std::string name_; //Function name
	uint16_t hint_; //Hint
	uint16_t ordinal_; //Ordinal
	uint64_t iat_va_;
};

//Class representing imported library information
class import_library
{
public:
	typedef std::vector<imported_function> imported_list;

public:
	//Default constructor
	import_library();

	//Returns name of library
	const std::string& get_name() const;
	//Returns RVA to Import Address Table (IAT)
	uint32_t get_rva_to_iat() const;
	//Returns RVA to Original Import Address Table (Original IAT)
	uint32_t get_rva_to_original_iat() const;
	//Returns timestamp
	uint32_t get_timestamp() const;

	//Returns imported functions list
	const imported_list& get_imported_functions() const;

public: //Setters do not change everything inside image, they are used by PE class
	//You also can use them to rebuild image imports
	//Sets name of library
	void set_name(const std::string& name);
	//Sets RVA to Import Address Table (IAT)
	void set_rva_to_iat(uint32_t rva_to_iat);
	//Sets RVA to Original Import Address Table (Original IAT)
	void set_rva_to_original_iat(uint32_t rva_to_original_iat);
	//Sets timestamp
	void set_timestamp(uint32_t timestamp);

	//Adds imported function
	void add_import(const imported_function& func);
	//Clears imported functions list
	void clear_imports();

private:
	std::string name_; //Library name
	uint32_t rva_to_iat_; //RVA to IAT
	uint32_t rva_to_original_iat_; //RVA to original IAT
	uint32_t timestamp_; //DLL TimeStamp

	imported_list imports_;
};

//Simple import directory rebuilder
//Class representing import rebuilder advanced settings
class import_rebuilder_settings
{
public:
	//Default constructor
	//Default constructor
	//If set_to_pe_headers = true, IMAGE_DIRECTORY_ENTRY_IMPORT entry will be reset
	//to new value after import rebuilding
	//If auto_zero_directory_entry_iat = true, IMAGE_DIRECTORY_ENTRY_IAT will be set to zero
	//IMAGE_DIRECTORY_ENTRY_IAT is used by loader to temporarily make section, where IMAGE_DIRECTORY_ENTRY_IAT RVA points, writeable
	//to be able to modify IAT thunks
	explicit import_rebuilder_settings(bool set_to_pe_headers = true, bool auto_zero_directory_entry_iat = false);

	//Returns offset from section start where import directory data will be placed
	uint32_t get_offset_from_section_start() const;
	//Returns true if Original import address table (IAT) will be rebuilt
	bool build_original_iat() const;

	//Returns true if Original import address and import address tables will not be rebuilt,
	//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
	bool save_iat_and_original_iat_rvas() const;
	//Returns true if Original import address and import address tables contents will be rewritten
	//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
	//and save_iat_and_original_iat_rvas is true
	bool rewrite_iat_and_original_iat_contents() const;

	//Returns true if original missing IATs will be rebuilt
	//(only if IATs are saved)
	bool fill_missing_original_iats() const;
	//Returns true if PE headers should be updated automatically after rebuilding of imports
	bool auto_set_to_pe_headers() const;
	//Returns true if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true
	bool zero_directory_entry_iat() const;

	//Returns true if the last section should be stripped automatically, if imports are inside it
	bool auto_strip_last_section_enabled() const;

public: //Setters
	//Sets offset from section start where import directory data will be placed
	void set_offset_from_section_start(uint32_t offset);
	//Sets if Original import address table (IAT) will be rebuilt
	void build_original_iat(bool enable);
	//Sets if Original import address and import address tables will not be rebuilt,
	//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
	//enable_rewrite_iat_and_original_iat_contents sets if Original import address and import address tables contents will be rewritten
	//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
	//and save_iat_and_original_iat_rvas is true
	void save_iat_and_original_iat_rvas(bool enable, bool enable_rewrite_iat_and_original_iat_contents = false);
	//Sets if original missing IATs will be rebuilt
	//(only if IATs are saved)
	void fill_missing_original_iats(bool enable);
	//Sets if PE headers should be updated automatically after rebuilding of imports
	void auto_set_to_pe_headers(bool enable);
	//Sets if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true
	void zero_directory_entry_iat(bool enable);

	//Sets if the last section should be stripped automatically, if imports are inside it, default true
	void enable_auto_strip_last_section(bool enable);

private:
	uint32_t offset_from_section_start_;
	bool build_original_iat_;
	bool save_iat_and_original_iat_rvas_;
	bool fill_missing_original_iats_;
	bool set_to_pe_headers_;
	bool zero_directory_entry_iat_;
	bool rewrite_iat_and_original_iat_contents_;
	bool auto_strip_last_section_;
};

typedef std::vector<import_library> imported_functions_list;


//Returns imported functions list with related libraries info
const imported_functions_list get_imported_functions(const pe_base& pe);

template<typename PEClassType>
const imported_functions_list get_imported_functions_base(const pe_base& pe);


//You can get all image imports with get_imported_functions() function
//You can use returned value to, for example, add new imported library with some functions
//to the end of list of imported libraries
//To keep PE file working, rebuild its imports with save_iat_and_original_iat_rvas = true (default)
//Don't add new imported functions to existing imported library entries, because this can cause
//rewriting of some used memory (or other IAT/orig.IAT fields) by system loader
//The safest way is just adding import libraries with functions to the end of imported_functions_list array
const image_directory rebuild_imports(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings = import_rebuilder_settings());

template<typename PEClassType>
const image_directory rebuild_imports_base(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings = import_rebuilder_settings());
}
