/**
* oon2.cpp - Example program for the PeLib library.
* OON2 (The 2nd version of "Out of nowhere") creates a valid PE file
* from scratch. The creation of the header structures are automized
* as much as possible. The file produced by oon2 ("dummy.exe")
* shows a messagebox when you run it.
*
* Copyright (c) 2004 Sebastian Porst (webmaster@the-interweb.com)
* All rights reserved.
*
* This software is licensed under the zlib/libpng License.
* For more details see http://www.opensource.org/licenses/zlib-license.php
* or the license information file (license.htm) in the root directory 
* of PeLib.
**/

#include "PeLib.h"
#include <iostream>
#include <string>
#include <vector>

int main()
{
	std::string strFilename = "dummy.exe";
	
	PeLib::PeFile f(strFilename);

	unsigned int uiSizeMzHeader = f.mzHeader().size();

	// At first we need a valid MZ header.
	std::cout << "Building MZ header..." << std::endl;
	f.mzHeader().setAddressOfPeHeader(uiSizeMzHeader);
	f.mzHeader().makeValid();
	f.mzHeader().write(strFilename, 0);

	// Then we need a valid PE header.
	std::cout << "Building PE header..." << std::endl;
	f.peHeader().setAddressOfEntryPoint(0x1000);
	f.peHeader().makeValid(uiSizeMzHeader);

	// We need a section for the code.
	std::cout << "Building Sections..." << std::endl;

	f.peHeader().addSection("PELIB", 0x200);
	unsigned uiImpDir = f.peHeader().getVirtualAddress(0) + 0x100;

	// After the section was added the PE header needs to be updated.
	f.peHeader().setIdImportRva(uiImpDir);
	f.peHeader().setIdImportSize(f.impDir().size());
	f.peHeader().setImageBase(0x01000000);
	f.peHeader().setMajorSubsystemVersion(4);
	f.peHeader().setSubsystem(2);
	f.peHeader().makeValid(uiSizeMzHeader);

	f.peHeader().writeHeader(strFilename, uiSizeMzHeader);

	// Write the new section to the output file.
	f.writeSections();
	// Dummy.exe needs to import User32.dll's MessageBoxA to use it.
	std::cout << "Building Import Directory..." << std::endl;
	f.impDir().addFunction("User32.dll", "MessageBoxA");
	f.impDir().write(strFilename, f.peHeader().rvaToOffset(uiImpDir), uiImpDir);

	// Program code created with an assembler.
	char data[] = { 0x6A, 0x00,	// push	0
			0x68, 0x00, 0x00, 0x00, 0x00,	// push "PeLib"
			0x68, 0x00, 0x00, 0x00, 0x00,	// push "Built with PeLib"
			0x6A, 0x00,	// push 0
			0xFF, 0x15, 0x00, 0x00, 0x00, 0x00,	// call MessageBoxA
			0xC3,	// ret
			'B','u','i','l','t',' ',	// Data string
			'w','i','t','h',' ',
			'P','e','L','i','b',0x00};

	unsigned int uiOffset = f.peHeader().getPointerToRawData(0);

	// Update the program code with the necessary addresses for data and calls
	*(dword*)(&data[3]) = f.peHeader().offsetToVa(uiOffset + 32);
	*(dword*)(&data[8]) = f.peHeader().offsetToVa(uiOffset + 21);
	*(dword*)(&data[16]) = f.peHeader().rvaToVa(uiImpDir + 0x28);

	// Write program code to file.
	std::cout << "Writing data..." << std::endl;
	std::vector<byte> vData(data, data + sizeof(data)/sizeof(data[0]));
	f.writeSectionData(0, vData);
}
