Results 1 to 15 of 15
  1. #1
    radnomguywfq3's Avatar
    Join Date
    Jan 2007
    Gender
    male
    Location
    J:\E\T\A\M\A\Y.exe
    Posts
    8,858
    Reputation
    381
    Thanks
    1,823
    My Mood
    Sad

    Custom PE Loader - Sample

    I have quickly whipped up a custom PE Loader. Honestly, I didn't spend that much time on it, so I haven't bothered to wrap it in an OOP design or clean it up, or anything of the sort. I'm in the process of doing that right now actually.

    MSDN doesn't document A LOT of relocation types, and I really had to dig around to find information on some PE structures. So if you can constribute to this with your knowledge of the windows PE Loader, I would appreciate that.

    I threw it all in one source file and threw in some comments. If you have any questions just ask (I will be posting a more revised version of it later, when I get more time.)

    Right now, it just loads the library in to the local process. Making it do otherwise, is a simple manner of replacing memcpy with writeprocessmemory, virtualalloc with VirtualAllocEx, and the call with CreateRemoteThread, etc...

    Also, sorry for all the reinterpret_casts... Its a side-effect of doing a lot of C pointer arithmatic in C++.

    This can easily be modified for stealing another process's address space. I.e, unload the executable in the remote address space, and setup your executable inside of the remote process from memory (popular with malware.)

    Code:
    // testttt.cpp : Defines the entry point for the console application.
    //Author : [MPGH] Jetamay (mpgh.net)
    
    #include "stdafx.h"
    #include <string>
    #include <Windows.h>
    #include <iostream>
    
    typedef BOOL (WINAPI* DllMain_t)(
        HINSTANCE hinstDLL,
        DWORD fdwReason,
        LPVOID lpReserved);
    
    class Exception
    {
    private:
    	std::string m_sReason;
    public:
    	Exception(const std::string& sReason)
    	{
    		m_sReason = sReason;
    	}
    
    	~Exception()
    	{
    	}
    
    	std::string getReason()
    	{
    		return m_sReason;
    	}
    };
    
    inline void calculateRelocation(const long difference, const unsigned long ulBase, const WORD wOffset)
    {
    	const unsigned long relocationType = wOffset>>12;
    	unsigned long ulDest = (wOffset & (0xFFF));
    
    	switch(relocationType)
    	{
    		//There are a lot of relocations that aren't documented (or I haven't found any sort of documentation for them.
    		//... however, not relocating them doesn't seem to cause much harm... Here are just some guesses as to what should be relocated (and how...)
    	case IMAGE_REL_BASED_MIPS_JMPADDR:
    	case IMAGE_REL_BASED_HIGH:
    	case IMAGE_REL_BASED_LOW:
    	case IMAGE_REL_BASED_HIGHLOW:
    		*reinterpret_cast<unsigned long*>(ulDest + ulBase) += difference;
    		break;
    	case IMAGE_REL_BASED_ABSOLUTE:
    	default:
    		break;
    	};
    }
    
    void setSectionPermissions(void* pAddress, unsigned long ulSize, unsigned long ulCharacteristics)
    {
    		//Correct section permissions.
    		unsigned long ulPermissions = 0;
    
    		if(ulCharacteristics & IMAGE_SCN_MEM_EXECUTE)
    			ulPermissions = PAGE_EXECUTE;
    			
    		if(ulCharacteristics & IMAGE_SCN_MEM_READ)
    			ulPermissions = PAGE_READONLY;
    			
    		if(ulCharacteristics & IMAGE_SCN_MEM_WRITE)
    			ulPermissions = PAGE_READWRITE;
    		
    		if((ulCharacteristics & IMAGE_SCN_MEM_EXECUTE) && ulPermissions == PAGE_READWRITE)
    			ulPermissions = PAGE_EXECUTE_READWRITE;
    
    		if((ulCharacteristics & IMAGE_SCN_MEM_EXECUTE) && ulPermissions == PAGE_READONLY)
    			ulPermissions = PAGE_EXECUTE_READ;
    
    		if(!VirtualProtect(pAddress, ulSize, ulPermissions, &ulPermissions))
    			throw Exception("Error applying page protection.");
    }
    
    void loadDll(const std::string& sLibrary)
    {
    	//Map the file in to memory for quick IO and easy read access.
    	HANDLE hFile = CreateFileA(sLibrary.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    
    	if(hFile == INVALID_HANDLE_VALUE)
    		throw Exception("Unable to open file.");
    
    	HANDLE hFileMap = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0);
    
    	if(!hFileMap)
    		throw Exception("Error create file mapping.");
    
    	void* pViewBase = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
    
    	if(!pViewBase)
    		throw Exception("Error mapping view of file in to memory.");
    
    	//Get the address of the NT header:
    	IMAGE_NT_HEADERS* pNtHeaders = reinterpret_cast<IMAGE_NT_HEADERS*>(reinterpret_cast<IMAGE_DOS_HEADER*>(pViewBase)->e_lfanew + reinterpret_cast<LONG>(pViewBase));
    
    	//Validate PE Image.
    	if(strcmp(reinterpret_cast<const char*>(&pNtHeaders->Signature), "PE\0\0") != 0)
    		throw Exception("Invalid PE Image.");
    
    	//Reserve enough memory to copy all the library's sections into. Not all of it will be needed, and thus it is more optimal to first reserve, then commit as needed.
    	void* pLibraryBase = VirtualAlloc(reinterpret_cast<void*>(pNtHeaders->OptionalHeader.ImageBase), pNtHeaders->OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);
    
    	if(!pLibraryBase)
    		throw Exception("Error allocating enough memory for library in process.");
    
    	IMAGE_SECTION_HEADER* pSectionHeaders = reinterpret_cast<IMAGE_SECTION_HEADER*>(reinterpret_cast<unsigned long>(pNtHeaders) + sizeof(IMAGE_NT_HEADERS));
    		
    	for(unsigned int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
    	{
    			
    		void* pFileSectionAddress = reinterpret_cast<void*>(pSectionHeaders[i].PointerToRawData + reinterpret_cast<unsigned long>(pViewBase));
    		void* pMemorySectionAddress = reinterpret_cast<void*>(pSectionHeaders[i].VirtualAddress + reinterpret_cast<unsigned long>(pLibraryBase));
    
    		unsigned long ulSectionSize = pSectionHeaders[i].SizeOfRawData;
    			
    		//If the section size is zero(i.e no data), the standard says to use the sizes defined in the optional headers...
    		if(!ulSectionSize)
    		{
    			if(pSectionHeaders[i].Characteristics & IMAGE_SCN_CNT_CODE)
    				ulSectionSize = pNtHeaders->OptionalHeader.SizeOfCode;
    			else if(pSectionHeaders[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
    				ulSectionSize = pNtHeaders->OptionalHeader.SizeOfInitializedData;
    			else if(pSectionHeaders[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
    				ulSectionSize = pNtHeaders->OptionalHeader.SizeOfUninitializedData;
    			
    		}
    		
    		//Commit the memory we previously reserved for this section.
    		if(VirtualAlloc(pMemorySectionAddress, max(pSectionHeaders[i].Misc.VirtualSize, ulSectionSize), MEM_COMMIT, PAGE_READWRITE) != pMemorySectionAddress)
    			throw Exception("Error commiting memory for section.");
    
    		if(ulSectionSize > 0)
    			memcpy_s(pMemorySectionAddress, ulSectionSize, pFileSectionAddress, ulSectionSize);
    	}
    
    	//Resolve image imports and setup the IAT.
    	IMAGE_IMPORT_DESCRIPTOR* pImportDescriptors = reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR*>(pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + reinterpret_cast<unsigned long>(pLibraryBase));
    	for(unsigned int i = 0; pImportDescriptors[i].FirstThunk; i++)
    	{
    		IMAGE_THUNK_DATA* pInts = reinterpret_cast<IMAGE_THUNK_DATA*>(reinterpret_cast<unsigned long>(pLibraryBase) + pImportDescriptors[i].OriginalFirstThunk);
    		IMAGE_THUNK_DATA* pIat = reinterpret_cast<IMAGE_THUNK_DATA*>(reinterpret_cast<unsigned long>(pLibraryBase) + pImportDescriptors[i].FirstThunk);
    
    		//Technically, I could just use a recursive call to our version of load library, but loading the library via the windows PE loader is a lot less error prone. If you
    		//are writing a packer or something, obviously you want to avoid calls to LoadLibraryA, in which case you should just call recusivley, otherwise just call LoadLibraryA
    		HMODULE hImportLib = LoadLibraryA(reinterpret_cast<const char*>(reinterpret_cast<unsigned long>(pLibraryBase) + pImportDescriptors[i].Name));
    			
    		if(!hImportLib)
    			throw Exception("Unable to find dependancy library.");
    
    		for(unsigned int x = 0; pInts[x].u1.Function != 0; x++)
    		{
    			unsigned long ulImportNameOrdinal = 0;
    
    			if(pInts[x].u1.Function & (1>>31))
    			{
    				//if MSB is set, it is an ordinal.
    				ulImportNameOrdinal = pInts[x].u1.Function & ~(1>>31);
    			}else
    			{
    				IMAGE_IMPORT_BY_NAME* pImport = reinterpret_cast<IMAGE_IMPORT_BY_NAME*>(reinterpret_cast<unsigned long>(pLibraryBase) + pInts[x].u1.Function);
    				ulImportNameOrdinal = reinterpret_cast<unsigned long>(pImport->Name);
    			}
    
    			if( !(pIat[x].u1.Function = reinterpret_cast<unsigned long>(GetProcAddress(hImportLib, reinterpret_cast<const char*>(ulImportNameOrdinal))) ))
    				throw Exception("Error finding import.");
    		}
    	}
    
    	//Do relocations described in the Relocations data directory
    	IMAGE_BASE_RELOCATION* pBaseRelocations = reinterpret_cast<IMAGE_BASE_RELOCATION*>(pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + reinterpret_cast<unsigned long>(pLibraryBase));
    	for(IMAGE_BASE_RELOCATION* pCurrentRelocation = pBaseRelocations; 
    		reinterpret_cast<unsigned long>(pCurrentRelocation) - reinterpret_cast<unsigned long>(pBaseRelocations) < pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
    		pCurrentRelocation = reinterpret_cast<IMAGE_BASE_RELOCATION*>(reinterpret_cast<unsigned long>(pCurrentRelocation) + pCurrentRelocation->SizeOfBlock))
    	{
    		long difference = reinterpret_cast<unsigned long>(pLibraryBase) - pNtHeaders->OptionalHeader.ImageBase;
    		unsigned long ulBase = reinterpret_cast<unsigned long>(pLibraryBase) + pCurrentRelocation->VirtualAddress;
    		
    		WORD* pRelocationOffsets = reinterpret_cast<WORD*>(reinterpret_cast<unsigned long>(pCurrentRelocation) + sizeof(IMAGE_BASE_RELOCATION));
    
    		for(unsigned int i = 0; i < pCurrentRelocation->SizeOfBlock / sizeof(WORD); i++)
    			calculateRelocation(difference, ulBase, pRelocationOffsets[i]);
    	}
    
    	//After code relocations, we can apply the proper page permissions.
    	for(unsigned int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
    	{
    		void* pMemorySectionAddress = reinterpret_cast<void*>(pSectionHeaders[i].VirtualAddress + reinterpret_cast<unsigned long>(pLibraryBase));
    		setSectionPermissions(pMemorySectionAddress, pSectionHeaders[i].Misc.VirtualSize, pSectionHeaders[i].Characteristics);
    	}
    
    	//And call the library's entrypoint.
    	DllMain_t pEntry = reinterpret_cast<DllMain_t>(reinterpret_cast<unsigned long>(pLibraryBase) + pNtHeaders->OptionalHeader.AddressOfEntryPoint);
    	pEntry(reinterpret_cast<HINSTANCE>(pLibraryBase), DLL_PROCESS_ATTACH, 0);
    
    	UnmapViewOfFile(hFileMap);
    	CloseHandle(hFile);
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	const char* const DLL_NAME = "testdll.dll";
    
    	try
    	{
    		loadDll(DLL_NAME);
    	}catch(Exception& e)
    	{
    		std::cout<<"Error occured: "<<e.getReason()<<std::endl;
    	}
    }
    Last edited by radnomguywfq3; 08-27-2012 at 08:51 PM.



    There are two types of tragedies in life. One is not getting what you want, the other is getting it.

    If you wake up at a different time in a different place, could you wake up as a different person?


  2. The Following 4 Users Say Thank You to radnomguywfq3 For This Useful Post:

    giniyat101 (08-28-2012),inmate (08-28-2012),Jabberwock (08-28-2012),ntKid (08-27-2012)

  3. #2
    Broderick's Avatar
    Join Date
    Apr 2011
    Gender
    male
    Location
    Basement.
    Posts
    100
    Reputation
    42
    Thanks
    30
    First off, all the documentation you really need can be found here; 96 pages of PE/COFF goodness.
    https://download.microsof*****m/downlo...pecoff_v8.docx

    Or by reading all of Matt Pietrek's articles in the MSDN magazine.

    One big thing is that I'm not sure, from scanning your code, that you've taken File/Memory alignment differences into account when using the Virtual Address fields in the various structures. Take a look at Matt Pietrek's GetPtrFromRVA function, it's pretty straightforward and will resolve RVAs into the file locations.

    There's a few ways you can clean this up. Firstly you can pretty much ignore most relocation types except for ABSOLUTE (padding so you don't need to do anything) and HIGHLOW.

    Quote from Matt Pietrek:
    Quote Originally Posted by "Matt Pietrek
    For PE files that run on Intel CPUs, you'll only see two types of relocations:

    0 IMAGE_REL_BASED_ABSOLUTE This relocation is meaningless and is only used as a place holder to round relocation blocks up to a DWORD multiple size.
    3 IMAGE_REL_BASED_HIGHLOW This relocation means add both the high and low 16 bits of the delta to the DWORD specified by the calculated RVA.
    Seeing as virtually all programs are compatible with Intel CPUs (and the ones that aren't can go fuck themselves), I just check for the HIGHLOW relocation.

    Next up, the you need to check whether sections actually need to be mapped into memory (for example, the .reloc section typically doesn't need to be brought into the process memory) This is checked by checking if the DISCARDABLE bit field is set in the section characteristics:



    So like
    Code:
    if (!(pSecHd->Characteristics & IMAGE_SCN_MEM_DISCARDABLE))
        // map the section into memory.
    From what I've heard you can also pull the page protection from the characteristics using the following bitmask:
    Code:
    pSecHd->Characteristics & 0x00FFFFFF
    I've been using this for a while with no dramas. It probably isn't overly correct (might give some sections more access than they need), but it gives at least the minimum required page protection.

    As for the section allocation, the SizeOfRawData field in the section header will always tell you the size of the section on-disk. The Misc.VirtualSize field will always be SizeOfRawData rounded up to the nearest page boundary, so there's no need to check the section characteristics and use the other SizeXXX fields. Allocate/Commit Misc.VirtualSize virtual memory (in fact you can just allocate SizeOfRawData bytes of memory, and the OS will automatically allocate Misc.VirtualSize for you as VirtualAlloc allocates on a per-page basis, not per-byte.

    Imports look fairly good, though there are much simpler ways to check for import by ordinal. Here's a snippet from some of my ManualMap code, you'll have to ignore the variable names and the aforementioned GetPtrFromRVA function:

    Code:
        if (pThunk->u1.Ordinal & IMAGE_ORDINAL_IMPORT) //import by ordinal
            lpProcName = (LPCSTR)(pThunk->u1.Ordinal & 0xFFFF);
        else //import by function name
    	lpProcName = (LPCSTR)(((IMAGE_IMPORT_BY_NAME*)GetPtrFromRVA(pThunk->u1.AddressOfData, pNtHd, pBase))->Name);
    And finally (for now, i need to go to work :P), have you tried using this on non-statically linked files that use different C++ runtime versions (MSVCR100.dll in the imports for example)? I think you'll find LoadLibraryA returns 0. Have a look at ActivateActCtx. You'll need to parse the internal/external manifest file to set the Activation Context and then be able to LoadLibrary side-by-side dlls.
    Last edited by Broderick; 08-27-2012 at 11:18 PM.
    The fish trap exists because of the fish.
    Once you've gotten the fish you can forget the trap.
    The rabbit snare exists because of the rabbit.
    Once you've gotten the rabbit, you can forget the snare.
    Words exist because of meaning.
    Once you've gotten the meaning, you can forget the words.
    Where can I find a man who has forgotten words so I can talk with him?

  4. The Following 2 Users Say Thank You to Broderick For This Useful Post:

    radnomguywfq3 (08-28-2012),Saltine (08-28-2012)

  5. #3
    radnomguywfq3's Avatar
    Join Date
    Jan 2007
    Gender
    male
    Location
    J:\E\T\A\M\A\Y.exe
    Posts
    8,858
    Reputation
    381
    Thanks
    1,823
    My Mood
    Sad
    I did not know there was an entire manual on the PE/COFF file-format, lol. That would've saved me tons of time and would've made writing this a million times easier. I wonder why it isn't on the MSDN websites. Is it offically supported by MS, or is it just something published in the name of one of their employers?

    Thanks for the tip on the IMAGE_SCN_MEM_DISCARDABLE, I'll be sure to add that to the loader's code.

    Also, I have simplified the manner in which I allocate sections by just using the SizeOfRawData as you had suggested. ALong with that, I have changed my relocations module to only relocate HIGHLOW relocations.

    I did not need to translate RVAs to file-offsets because, by mapping the relocations section in the process, I would simply read them as mapped in memory using the virtualaddress member. However, now that I am no longer mapping in the relocations section (because it has the IMAGE_SCN_MEM_DISCARDABLE flag set) I have to read the relocations directory from the file and thus now need to calculate file-offsets from their respective rvas. So I have done that appropriately (only one place where it was really required)

    And about loading older versions of the C++ runtime, no I haven't checked. However it probably will not work as you suggested. I will look in to fixing that.

    I will be wrapping this entire module inside of an OOP interface, so it will be much easier to interface with.

    About getting the page permissions, I'd rather just leave it the way it is, it works perfectly fine and gives the pages their respective permissions.

    Thanks for all the feed-back, tbh I didn't expect such a descriptive and informative response and I really appreciate it.

    *edit*
    o.o I am not going to write an XML parser or statically link an XML parser to this. There would simply be too much code, it would be too easy to pickup with a signature scanner. (Granted, I haven't really designed this with that in mind :S)

    Here is the latest revision:
    Code:
    // testttt.cpp : Defines the entry point for the console application.
    //Author : [MPGH] Jetamay (mpgh.net)
    
    #include "stdafx.h"
    #include <string>
    #include <Windows.h>
    #include <iostream>
    
    typedef BOOL (WINAPI* DllMain_t)(
        HINSTANCE hinstDLL,
        DWORD fdwReason,
        LPVOID lpReserved);
    
    class Exception
    {
    private:
    	std::string m_sReason;
    public:
    	Exception(const std::string& sReason)
    	{
    		m_sReason = sReason;
    	}
    
    	~Exception()
    	{
    	}
    
    	std::string getReason()
    	{
    		return m_sReason;
    	}
    };
    
    inline void calculateRelocation(const long difference, const unsigned long ulBase, const WORD wOffset)
    {
    	const unsigned long relocationType = wOffset>>12;
    	unsigned long ulDest = (wOffset & (0xFFF));
    
    	switch(relocationType)
    	{
    	case IMAGE_REL_BASED_HIGHLOW:
    		*reinterpret_cast<unsigned long*>(ulDest + ulBase) += difference;
    		break;
    	case IMAGE_REL_BASED_ABSOLUTE:
    	default:
    		break;
    	};
    }
    
    void setSectionPermissions(void* pAddress, unsigned long ulSize, unsigned long ulCharacteristics)
    {
    		//Correct section permissions.
    		unsigned long ulPermissions = 0;
    
    		if(ulCharacteristics & IMAGE_SCN_MEM_EXECUTE)
    			ulPermissions = PAGE_EXECUTE;
    			
    		if(ulCharacteristics & IMAGE_SCN_MEM_READ)
    			ulPermissions = PAGE_READONLY;
    			
    		if(ulCharacteristics & IMAGE_SCN_MEM_WRITE)
    			ulPermissions = PAGE_READWRITE;
    		
    		if((ulCharacteristics & IMAGE_SCN_MEM_EXECUTE) && ulPermissions == PAGE_READWRITE)
    			ulPermissions = PAGE_EXECUTE_READWRITE;
    
    		if((ulCharacteristics & IMAGE_SCN_MEM_EXECUTE) && ulPermissions == PAGE_READONLY)
    			ulPermissions = PAGE_EXECUTE_READ;
    
    		if(!VirtualProtect(pAddress, ulSize, ulPermissions, &ulPermissions))
    			throw Exception("Error applying page protection.");
    }
    
    const IMAGE_SECTION_HEADER* getRvaSection(const unsigned long ulRva, const IMAGE_NT_HEADERS* pNtHeaders)
    {
    	IMAGE_SECTION_HEADER* pSections = IMAGE_FIRST_SECTION(const_cast<IMAGE_NT_HEADERS*>(pNtHeaders));
    
    	for(unsigned int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
    	{
    		if(ulRva >= pSections[i].VirtualAddress &&
    			ulRva < pSections[i].VirtualAddress + pSections[i].Misc.VirtualSize)
    			return &pSections[i];
    	}
    	
    	throw Exception("Unable to resolve RVA to its parent section.");
    }
    
    long rvaToFileOffset(const unsigned long ulRva, const IMAGE_NT_HEADERS* pNtHeaders)
    {
    	const IMAGE_SECTION_HEADER* pSection = getRvaSection(ulRva, pNtHeaders);
    
    	//Calculate differene in base of section data and base of section when mounted in to memory.
    	long lDelta = pSection->PointerToRawData - pSection->VirtualAddress;
    
    	return ulRva + lDelta;
    }
    
    void loadDll(const std::string& sLibrary)
    {
    	//Map the file in to memory for quick IO and easy read access.
    	HANDLE hFile = CreateFileA(sLibrary.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    
    	if(hFile == INVALID_HANDLE_VALUE)
    		throw Exception("Unable to open file.");
    
    	HANDLE hFileMap = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0);
    
    	if(!hFileMap)
    		throw Exception("Error create file mapping.");
    
    	void* pViewBase = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
    
    	if(!pViewBase)
    		throw Exception("Error mapping view of file in to memory.");
    
    	//Get the address of the NT header:
    	IMAGE_NT_HEADERS* pNtHeaders = reinterpret_cast<IMAGE_NT_HEADERS*>(reinterpret_cast<IMAGE_DOS_HEADER*>(pViewBase)->e_lfanew + reinterpret_cast<LONG>(pViewBase));
    
    	//Validate PE Image.
    	if(strcmp(reinterpret_cast<const char*>(&pNtHeaders->Signature), "PE\0\0") != 0)
    		throw Exception("Invalid PE Image.");
    
    	//Reserve enough memory to copy all the library's sections into. Not all of it will be needed, and thus it is more optimal to first reserve, then commit as needed.
    	void* pLibraryBase = VirtualAlloc(reinterpret_cast<void*>(pNtHeaders->OptionalHeader.ImageBase), pNtHeaders->OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);
    
    	if(!pLibraryBase)
    		throw Exception("Error allocating enough memory for library in process.");
    
    	IMAGE_SECTION_HEADER* pSectionHeaders = IMAGE_FIRST_SECTION(pNtHeaders);
    		
    	for(unsigned int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
    	{
    		if(pSectionHeaders[i].Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
    			continue;
    
    		void* pFileSectionAddress = reinterpret_cast<void*>(pSectionHeaders[i].PointerToRawData + reinterpret_cast<unsigned long>(pViewBase));
    		void* pMemorySectionAddress = reinterpret_cast<void*>(pSectionHeaders[i].VirtualAddress + reinterpret_cast<unsigned long>(pLibraryBase));
    
    		unsigned long ulSectionSize = pSectionHeaders[i].SizeOfRawData;
    	
    		//Commit the memory we previously reserved for this section.
    		if(VirtualAlloc(pMemorySectionAddress, pSectionHeaders[i].Misc.VirtualSize, MEM_COMMIT, PAGE_READWRITE) != pMemorySectionAddress)
    			throw Exception("Error commiting memory for section.");
    
    		if(ulSectionSize > 0)
    			memcpy_s(pMemorySectionAddress, ulSectionSize, pFileSectionAddress, ulSectionSize);
    	}
    
    	//Resolve image imports and setup the IAT.
    	IMAGE_IMPORT_DESCRIPTOR* pImportDescriptors = reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR*>(pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + reinterpret_cast<unsigned long>(pLibraryBase));
    	for(unsigned int i = 0; pImportDescriptors[i].FirstThunk; i++)
    	{
    		IMAGE_THUNK_DATA* pInts = reinterpret_cast<IMAGE_THUNK_DATA*>(reinterpret_cast<unsigned long>(pLibraryBase) + pImportDescriptors[i].OriginalFirstThunk);
    		IMAGE_THUNK_DATA* pIat = reinterpret_cast<IMAGE_THUNK_DATA*>(reinterpret_cast<unsigned long>(pLibraryBase) + pImportDescriptors[i].FirstThunk);
    
    		//Technically, I could just use a recursive call to our version of load library, but loading the library via the windows PE loader is a lot less error prone. If you
    		//are writing a packer or something, obviously you want to avoid calls to LoadLibraryA, in which case you should just call recusivley, otherwise just call LoadLibraryA
    		HMODULE hImportLib = LoadLibraryA(reinterpret_cast<const char*>(reinterpret_cast<unsigned long>(pLibraryBase) + pImportDescriptors[i].Name));
    			
    		if(!hImportLib)
    			throw Exception("Unable to find dependancy library.");
    
    		for(unsigned int x = 0; pInts[x].u1.Function != 0; x++)
    		{
    			unsigned long ulImportNameOrdinal = 0;
    
    			if(pInts[x].u1.Function & (1>>31))
    			{
    				//if MSB is set, it is an ordinal.
    				ulImportNameOrdinal = pInts[x].u1.Function & ~(1>>31);
    			}else
    			{
    				IMAGE_IMPORT_BY_NAME* pImport = reinterpret_cast<IMAGE_IMPORT_BY_NAME*>(reinterpret_cast<unsigned long>(pLibraryBase) + pInts[x].u1.Function);
    				ulImportNameOrdinal = reinterpret_cast<unsigned long>(pImport->Name);
    			}
    
    			if( !(pIat[x].u1.Function = reinterpret_cast<unsigned long>(GetProcAddress(hImportLib, reinterpret_cast<const char*>(ulImportNameOrdinal))) ))
    				throw Exception("Error finding import.");
    		}
    	}
    
    	//Do relocations described in the Relocations data directory
    	IMAGE_BASE_RELOCATION* pBaseRelocations = reinterpret_cast<IMAGE_BASE_RELOCATION*>(rvaToFileOffset(pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, pNtHeaders) + reinterpret_cast<unsigned long>(pViewBase));
    	for(IMAGE_BASE_RELOCATION* pCurrentRelocation = pBaseRelocations; 
    		reinterpret_cast<unsigned long>(pCurrentRelocation) - reinterpret_cast<unsigned long>(pBaseRelocations) < pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
    		pCurrentRelocation = reinterpret_cast<IMAGE_BASE_RELOCATION*>(reinterpret_cast<unsigned long>(pCurrentRelocation) + pCurrentRelocation->SizeOfBlock))
    	{
    		long difference = reinterpret_cast<unsigned long>(pLibraryBase) - pNtHeaders->OptionalHeader.ImageBase;
    		unsigned long ulBase = reinterpret_cast<unsigned long>(pLibraryBase) + pCurrentRelocation->VirtualAddress;
    		
    		WORD* pRelocationOffsets = reinterpret_cast<WORD*>(reinterpret_cast<unsigned long>(pCurrentRelocation) + sizeof(IMAGE_BASE_RELOCATION));
    
    		for(unsigned int i = 0; i < pCurrentRelocation->SizeOfBlock / sizeof(WORD); i++)
    			calculateRelocation(difference, ulBase, pRelocationOffsets[i]);
    	}
    
    	//After code relocations, we can apply the proper page permissions.
    	for(unsigned int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
    	{
    		if(pSectionHeaders[i].Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
    			continue;
    
    		void* pMemorySectionAddress = reinterpret_cast<void*>(pSectionHeaders[i].VirtualAddress + reinterpret_cast<unsigned long>(pLibraryBase));
    		setSectionPermissions(pMemorySectionAddress, pSectionHeaders[i].Misc.VirtualSize, pSectionHeaders[i].Characteristics);
    	}
    
    	//And call the library's entrypoint.
    	DllMain_t pEntry = reinterpret_cast<DllMain_t>(reinterpret_cast<unsigned long>(pLibraryBase) + pNtHeaders->OptionalHeader.AddressOfEntryPoint);
    	pEntry(reinterpret_cast<HINSTANCE>(pLibraryBase), DLL_PROCESS_ATTACH, 0);
    
    	UnmapViewOfFile(hFileMap);
    	CloseHandle(hFile);
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	const char* const DLL_NAME = "testdll.dll";
    
    	try
    	{
    		loadDll(DLL_NAME);
    	}catch(Exception& e)
    	{
    		std::cout<<"Error occured: "<<e.getReason()<<std::endl;
    	}
    }
    Last edited by radnomguywfq3; 08-28-2012 at 01:13 AM.



    There are two types of tragedies in life. One is not getting what you want, the other is getting it.

    If you wake up at a different time in a different place, could you wake up as a different person?


  6. #4
    TF.Hacks's Avatar
    Join Date
    Aug 2012
    Gender
    male
    Posts
    18
    Reputation
    10
    Thanks
    4
    My Mood
    Breezy
    Quote Originally Posted by Jetamay View Post
    I did not know there was an entire manual on the PE/COFF file-format, lol. That would've saved me tons of time and would've made writing this a million times easier. I wonder why it isn't on the MSDN websites. Is it offically supported by MS, or is it just something published in the name of one of their employers?

    Thanks for the tip on the IMAGE_SCN_MEM_DISCARDABLE, I'll be sure to add that to the loader's code.

    Also, I have simplified the manner in which I allocate sections by just using the SizeOfRawData as you had suggested. ALong with that, I have changed my relocations module to only relocate HIGHLOW relocations.

    I did not need to translate RVAs to file-offsets because, by mapping the relocations section in the process, I would simply read them as mapped in memory using the virtualaddress member. However, now that I am no longer mapping in the relocations section (because it has the IMAGE_SCN_MEM_DISCARDABLE flag set) I have to read the relocations directory from the file and thus now need to calculate file-offsets from their respective rvas. So I have done that appropriately (only one place where it was really required)

    And about loading older versions of the C++ runtime, no I haven't checked. However it probably will not work as you suggested. I will look in to fixing that.

    I will be wrapping this entire module inside of an OOP interface, so it will be much easier to interface with.

    About getting the page permissions, I'd rather just leave it the way it is, it works perfectly fine and gives the pages their respective permissions.

    Thanks for all the feed-back, tbh I didn't expect such a descriptive and informative response and I really appreciate it.

    *edit*
    o.o I am not going to write an XML parser or statically link an XML parser to this. There would simply be too much code, it would be too easy to pickup with a signature scanner. (Granted, I haven't really designed this with that in mind :S)

    Here is the latest revision:
    Code:
    // testttt.cpp : Defines the entry point for the console application.
    //Author : [MPGH] Jetamay (mpgh.net)
    
    #include "stdafx.h"
    #include <string>
    #include <Windows.h>
    #include <iostream>
    
    typedef BOOL (WINAPI* DllMain_t)(
        HINSTANCE hinstDLL,
        DWORD fdwReason,
        LPVOID lpReserved);
    
    class Exception
    {
    private:
    	std::string m_sReason;
    public:
    	Exception(const std::string& sReason)
    	{
    		m_sReason = sReason;
    	}
    
    	~Exception()
    	{
    	}
    
    	std::string getReason()
    	{
    		return m_sReason;
    	}
    };
    
    inline void calculateRelocation(const long difference, const unsigned long ulBase, const WORD wOffset)
    {
    	const unsigned long relocationType = wOffset>>12;
    	unsigned long ulDest = (wOffset & (0xFFF));
    
    	switch(relocationType)
    	{
    	case IMAGE_REL_BASED_HIGHLOW:
    		*reinterpret_cast<unsigned long*>(ulDest + ulBase) += difference;
    		break;
    	case IMAGE_REL_BASED_ABSOLUTE:
    	default:
    		break;
    	};
    }
    
    void setSectionPermissions(void* pAddress, unsigned long ulSize, unsigned long ulCharacteristics)
    {
    		//Correct section permissions.
    		unsigned long ulPermissions = 0;
    
    		if(ulCharacteristics & IMAGE_SCN_MEM_EXECUTE)
    			ulPermissions = PAGE_EXECUTE;
    			
    		if(ulCharacteristics & IMAGE_SCN_MEM_READ)
    			ulPermissions = PAGE_READONLY;
    			
    		if(ulCharacteristics & IMAGE_SCN_MEM_WRITE)
    			ulPermissions = PAGE_READWRITE;
    		
    		if((ulCharacteristics & IMAGE_SCN_MEM_EXECUTE) && ulPermissions == PAGE_READWRITE)
    			ulPermissions = PAGE_EXECUTE_READWRITE;
    
    		if((ulCharacteristics & IMAGE_SCN_MEM_EXECUTE) && ulPermissions == PAGE_READONLY)
    			ulPermissions = PAGE_EXECUTE_READ;
    
    		if(!VirtualProtect(pAddress, ulSize, ulPermissions, &ulPermissions))
    			throw Exception("Error applying page protection.");
    }
    
    const IMAGE_SECTION_HEADER* getRvaSection(const unsigned long ulRva, const IMAGE_NT_HEADERS* pNtHeaders)
    {
    	IMAGE_SECTION_HEADER* pSections = IMAGE_FIRST_SECTION(const_cast<IMAGE_NT_HEADERS*>(pNtHeaders));
    
    	for(unsigned int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
    	{
    		if(ulRva >= pSections[i].VirtualAddress &&
    			ulRva < pSections[i].VirtualAddress + pSections[i].Misc.VirtualSize)
    			return &pSections[i];
    	}
    	
    	throw Exception("Unable to resolve RVA to its parent section.");
    }
    
    long rvaToFileOffset(const unsigned long ulRva, const IMAGE_NT_HEADERS* pNtHeaders)
    {
    	const IMAGE_SECTION_HEADER* pSection = getRvaSection(ulRva, pNtHeaders);
    
    	//Calculate differene in base of section data and base of section when mounted in to memory.
    	long lDelta = pSection->PointerToRawData - pSection->VirtualAddress;
    
    	return ulRva + lDelta;
    }
    
    void loadDll(const std::string& sLibrary)
    {
    	//Map the file in to memory for quick IO and easy read access.
    	HANDLE hFile = CreateFileA(sLibrary.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    
    	if(hFile == INVALID_HANDLE_VALUE)
    		throw Exception("Unable to open file.");
    
    	HANDLE hFileMap = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0);
    
    	if(!hFileMap)
    		throw Exception("Error create file mapping.");
    
    	void* pViewBase = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
    
    	if(!pViewBase)
    		throw Exception("Error mapping view of file in to memory.");
    
    	//Get the address of the NT header:
    	IMAGE_NT_HEADERS* pNtHeaders = reinterpret_cast<IMAGE_NT_HEADERS*>(reinterpret_cast<IMAGE_DOS_HEADER*>(pViewBase)->e_lfanew + reinterpret_cast<LONG>(pViewBase));
    
    	//Validate PE Image.
    	if(strcmp(reinterpret_cast<const char*>(&pNtHeaders->Signature), "PE\0\0") != 0)
    		throw Exception("Invalid PE Image.");
    
    	//Reserve enough memory to copy all the library's sections into. Not all of it will be needed, and thus it is more optimal to first reserve, then commit as needed.
    	void* pLibraryBase = VirtualAlloc(reinterpret_cast<void*>(pNtHeaders->OptionalHeader.ImageBase), pNtHeaders->OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);
    
    	if(!pLibraryBase)
    		throw Exception("Error allocating enough memory for library in process.");
    
    	IMAGE_SECTION_HEADER* pSectionHeaders = IMAGE_FIRST_SECTION(pNtHeaders);
    		
    	for(unsigned int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
    	{
    		if(pSectionHeaders[i].Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
    			continue;
    
    		void* pFileSectionAddress = reinterpret_cast<void*>(pSectionHeaders[i].PointerToRawData + reinterpret_cast<unsigned long>(pViewBase));
    		void* pMemorySectionAddress = reinterpret_cast<void*>(pSectionHeaders[i].VirtualAddress + reinterpret_cast<unsigned long>(pLibraryBase));
    
    		unsigned long ulSectionSize = pSectionHeaders[i].SizeOfRawData;
    	
    		//Commit the memory we previously reserved for this section.
    		if(VirtualAlloc(pMemorySectionAddress, pSectionHeaders[i].Misc.VirtualSize, MEM_COMMIT, PAGE_READWRITE) != pMemorySectionAddress)
    			throw Exception("Error commiting memory for section.");
    
    		if(ulSectionSize > 0)
    			memcpy_s(pMemorySectionAddress, ulSectionSize, pFileSectionAddress, ulSectionSize);
    	}
    
    	//Resolve image imports and setup the IAT.
    	IMAGE_IMPORT_DESCRIPTOR* pImportDescriptors = reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR*>(pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + reinterpret_cast<unsigned long>(pLibraryBase));
    	for(unsigned int i = 0; pImportDescriptors[i].FirstThunk; i++)
    	{
    		IMAGE_THUNK_DATA* pInts = reinterpret_cast<IMAGE_THUNK_DATA*>(reinterpret_cast<unsigned long>(pLibraryBase) + pImportDescriptors[i].OriginalFirstThunk);
    		IMAGE_THUNK_DATA* pIat = reinterpret_cast<IMAGE_THUNK_DATA*>(reinterpret_cast<unsigned long>(pLibraryBase) + pImportDescriptors[i].FirstThunk);
    
    		//Technically, I could just use a recursive call to our version of load library, but loading the library via the windows PE loader is a lot less error prone. If you
    		//are writing a packer or something, obviously you want to avoid calls to LoadLibraryA, in which case you should just call recusivley, otherwise just call LoadLibraryA
    		HMODULE hImportLib = LoadLibraryA(reinterpret_cast<const char*>(reinterpret_cast<unsigned long>(pLibraryBase) + pImportDescriptors[i].Name));
    			
    		if(!hImportLib)
    			throw Exception("Unable to find dependancy library.");
    
    		for(unsigned int x = 0; pInts[x].u1.Function != 0; x++)
    		{
    			unsigned long ulImportNameOrdinal = 0;
    
    			if(pInts[x].u1.Function & (1>>31))
    			{
    				//if MSB is set, it is an ordinal.
    				ulImportNameOrdinal = pInts[x].u1.Function & ~(1>>31);
    			}else
    			{
    				IMAGE_IMPORT_BY_NAME* pImport = reinterpret_cast<IMAGE_IMPORT_BY_NAME*>(reinterpret_cast<unsigned long>(pLibraryBase) + pInts[x].u1.Function);
    				ulImportNameOrdinal = reinterpret_cast<unsigned long>(pImport->Name);
    			}
    
    			if( !(pIat[x].u1.Function = reinterpret_cast<unsigned long>(GetProcAddress(hImportLib, reinterpret_cast<const char*>(ulImportNameOrdinal))) ))
    				throw Exception("Error finding import.");
    		}
    	}
    
    	//Do relocations described in the Relocations data directory
    	IMAGE_BASE_RELOCATION* pBaseRelocations = reinterpret_cast<IMAGE_BASE_RELOCATION*>(rvaToFileOffset(pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, pNtHeaders) + reinterpret_cast<unsigned long>(pViewBase));
    	for(IMAGE_BASE_RELOCATION* pCurrentRelocation = pBaseRelocations; 
    		reinterpret_cast<unsigned long>(pCurrentRelocation) - reinterpret_cast<unsigned long>(pBaseRelocations) < pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
    		pCurrentRelocation = reinterpret_cast<IMAGE_BASE_RELOCATION*>(reinterpret_cast<unsigned long>(pCurrentRelocation) + pCurrentRelocation->SizeOfBlock))
    	{
    		long difference = reinterpret_cast<unsigned long>(pLibraryBase) - pNtHeaders->OptionalHeader.ImageBase;
    		unsigned long ulBase = reinterpret_cast<unsigned long>(pLibraryBase) + pCurrentRelocation->VirtualAddress;
    		
    		WORD* pRelocationOffsets = reinterpret_cast<WORD*>(reinterpret_cast<unsigned long>(pCurrentRelocation) + sizeof(IMAGE_BASE_RELOCATION));
    
    		for(unsigned int i = 0; i < pCurrentRelocation->SizeOfBlock / sizeof(WORD); i++)
    			calculateRelocation(difference, ulBase, pRelocationOffsets[i]);
    	}
    
    	//After code relocations, we can apply the proper page permissions.
    	for(unsigned int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
    	{
    		if(pSectionHeaders[i].Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
    			continue;
    
    		void* pMemorySectionAddress = reinterpret_cast<void*>(pSectionHeaders[i].VirtualAddress + reinterpret_cast<unsigned long>(pLibraryBase));
    		setSectionPermissions(pMemorySectionAddress, pSectionHeaders[i].Misc.VirtualSize, pSectionHeaders[i].Characteristics);
    	}
    
    	//And call the library's entrypoint.
    	DllMain_t pEntry = reinterpret_cast<DllMain_t>(reinterpret_cast<unsigned long>(pLibraryBase) + pNtHeaders->OptionalHeader.AddressOfEntryPoint);
    	pEntry(reinterpret_cast<HINSTANCE>(pLibraryBase), DLL_PROCESS_ATTACH, 0);
    
    	UnmapViewOfFile(hFileMap);
    	CloseHandle(hFile);
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	const char* const DLL_NAME = "testdll.dll";
    
    	try
    	{
    		loadDll(DLL_NAME);
    	}catch(Exception& e)
    	{
    		std::cout<<"Error occured: "<<e.getReason()<<std::endl;
    	}
    }
    Could you make me a coustom Loader ? i sent u a request on MSN

  7. #5
    radnomguywfq3's Avatar
    Join Date
    Jan 2007
    Gender
    male
    Location
    J:\E\T\A\M\A\Y.exe
    Posts
    8,858
    Reputation
    381
    Thanks
    1,823
    My Mood
    Sad
    Quote Originally Posted by TF.Hacks View Post
    Could you make me a coustom Loader ? i sent u a request on MSN
    I don't write modules strictly for one particular person; if I publish anything it is for the entire MPGH community and done so publicly. Just make a request in the MPGH C++ section and explain some of the methods you've tried to work out. If you haven't tried anything the mods will probably just delete your request.



    There are two types of tragedies in life. One is not getting what you want, the other is getting it.

    If you wake up at a different time in a different place, could you wake up as a different person?


  8. #6
    Broderick's Avatar
    Join Date
    Apr 2011
    Gender
    male
    Location
    Basement.
    Posts
    100
    Reputation
    42
    Thanks
    30
    Quote Originally Posted by Jetamay View Post
    I did not know there was an entire manual on the PE/COFF file-format, lol. That would've saved me tons of time and would've made writing this a million times easier. I wonder why it isn't on the MSDN websites. Is it offically supported by MS, or is it just something published in the name of one of their employers?

    Thanks for the tip on the IMAGE_SCN_MEM_DISCARDABLE, I'll be sure to add that to the loader's code.

    Also, I have simplified the manner in which I allocate sections by just using the SizeOfRawData as you had suggested. ALong with that, I have changed my relocations module to only relocate HIGHLOW relocations.

    I did not need to translate RVAs to file-offsets because, by mapping the relocations section in the process, I would simply read them as mapped in memory using the virtualaddress member. However, now that I am no longer mapping in the relocations section (because it has the IMAGE_SCN_MEM_DISCARDABLE flag set) I have to read the relocations directory from the file and thus now need to calculate file-offsets from their respective rvas. So I have done that appropriately (only one place where it was really required)

    And about loading older versions of the C++ runtime, no I haven't checked. However it probably will not work as you suggested. I will look in to fixing that.

    I will be wrapping this entire module inside of an OOP interface, so it will be much easier to interface with.

    About getting the page permissions, I'd rather just leave it the way it is, it works perfectly fine and gives the pages their respective permissions.

    Thanks for all the feed-back, tbh I didn't expect such a descriptive and informative response and I really appreciate it.

    *edit*
    o.o I am not going to write an XML parser or statically link an XML parser to this. There would simply be too much code, it would be too easy to pickup with a signature scanner. (Granted, I haven't really designed this with that in mind :S)

    Here is the latest revision:
    Code:
    // testttt.cpp : Defines the entry point for the console application.
    //Author : [MPGH] Jetamay (mpgh.net)
    
    #include "stdafx.h"
    #include <string>
    #include <Windows.h>
    #include <iostream>
    
    typedef BOOL (WINAPI* DllMain_t)(
        HINSTANCE hinstDLL,
        DWORD fdwReason,
        LPVOID lpReserved);
    
    class Exception
    {
    private:
    	std::string m_sReason;
    public:
    	Exception(const std::string& sReason)
    	{
    		m_sReason = sReason;
    	}
    
    	~Exception()
    	{
    	}
    
    	std::string getReason()
    	{
    		return m_sReason;
    	}
    };
    
    inline void calculateRelocation(const long difference, const unsigned long ulBase, const WORD wOffset)
    {
    	const unsigned long relocationType = wOffset>>12;
    	unsigned long ulDest = (wOffset & (0xFFF));
    
    	switch(relocationType)
    	{
    	case IMAGE_REL_BASED_HIGHLOW:
    		*reinterpret_cast<unsigned long*>(ulDest + ulBase) += difference;
    		break;
    	case IMAGE_REL_BASED_ABSOLUTE:
    	default:
    		break;
    	};
    }
    
    void setSectionPermissions(void* pAddress, unsigned long ulSize, unsigned long ulCharacteristics)
    {
    		//Correct section permissions.
    		unsigned long ulPermissions = 0;
    
    		if(ulCharacteristics & IMAGE_SCN_MEM_EXECUTE)
    			ulPermissions = PAGE_EXECUTE;
    			
    		if(ulCharacteristics & IMAGE_SCN_MEM_READ)
    			ulPermissions = PAGE_READONLY;
    			
    		if(ulCharacteristics & IMAGE_SCN_MEM_WRITE)
    			ulPermissions = PAGE_READWRITE;
    		
    		if((ulCharacteristics & IMAGE_SCN_MEM_EXECUTE) && ulPermissions == PAGE_READWRITE)
    			ulPermissions = PAGE_EXECUTE_READWRITE;
    
    		if((ulCharacteristics & IMAGE_SCN_MEM_EXECUTE) && ulPermissions == PAGE_READONLY)
    			ulPermissions = PAGE_EXECUTE_READ;
    
    		if(!VirtualProtect(pAddress, ulSize, ulPermissions, &ulPermissions))
    			throw Exception("Error applying page protection.");
    }
    
    const IMAGE_SECTION_HEADER* getRvaSection(const unsigned long ulRva, const IMAGE_NT_HEADERS* pNtHeaders)
    {
    	IMAGE_SECTION_HEADER* pSections = IMAGE_FIRST_SECTION(const_cast<IMAGE_NT_HEADERS*>(pNtHeaders));
    
    	for(unsigned int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
    	{
    		if(ulRva >= pSections[i].VirtualAddress &&
    			ulRva < pSections[i].VirtualAddress + pSections[i].Misc.VirtualSize)
    			return &pSections[i];
    	}
    	
    	throw Exception("Unable to resolve RVA to its parent section.");
    }
    
    long rvaToFileOffset(const unsigned long ulRva, const IMAGE_NT_HEADERS* pNtHeaders)
    {
    	const IMAGE_SECTION_HEADER* pSection = getRvaSection(ulRva, pNtHeaders);
    
    	//Calculate differene in base of section data and base of section when mounted in to memory.
    	long lDelta = pSection->PointerToRawData - pSection->VirtualAddress;
    
    	return ulRva + lDelta;
    }
    
    void loadDll(const std::string& sLibrary)
    {
    	//Map the file in to memory for quick IO and easy read access.
    	HANDLE hFile = CreateFileA(sLibrary.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    
    	if(hFile == INVALID_HANDLE_VALUE)
    		throw Exception("Unable to open file.");
    
    	HANDLE hFileMap = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0);
    
    	if(!hFileMap)
    		throw Exception("Error create file mapping.");
    
    	void* pViewBase = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
    
    	if(!pViewBase)
    		throw Exception("Error mapping view of file in to memory.");
    
    	//Get the address of the NT header:
    	IMAGE_NT_HEADERS* pNtHeaders = reinterpret_cast<IMAGE_NT_HEADERS*>(reinterpret_cast<IMAGE_DOS_HEADER*>(pViewBase)->e_lfanew + reinterpret_cast<LONG>(pViewBase));
    
    	//Validate PE Image.
    	if(strcmp(reinterpret_cast<const char*>(&pNtHeaders->Signature), "PE\0\0") != 0)
    		throw Exception("Invalid PE Image.");
    
    	//Reserve enough memory to copy all the library's sections into. Not all of it will be needed, and thus it is more optimal to first reserve, then commit as needed.
    	void* pLibraryBase = VirtualAlloc(reinterpret_cast<void*>(pNtHeaders->OptionalHeader.ImageBase), pNtHeaders->OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);
    
    	if(!pLibraryBase)
    		throw Exception("Error allocating enough memory for library in process.");
    
    	IMAGE_SECTION_HEADER* pSectionHeaders = IMAGE_FIRST_SECTION(pNtHeaders);
    		
    	for(unsigned int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
    	{
    		if(pSectionHeaders[i].Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
    			continue;
    
    		void* pFileSectionAddress = reinterpret_cast<void*>(pSectionHeaders[i].PointerToRawData + reinterpret_cast<unsigned long>(pViewBase));
    		void* pMemorySectionAddress = reinterpret_cast<void*>(pSectionHeaders[i].VirtualAddress + reinterpret_cast<unsigned long>(pLibraryBase));
    
    		unsigned long ulSectionSize = pSectionHeaders[i].SizeOfRawData;
    	
    		//Commit the memory we previously reserved for this section.
    		if(VirtualAlloc(pMemorySectionAddress, pSectionHeaders[i].Misc.VirtualSize, MEM_COMMIT, PAGE_READWRITE) != pMemorySectionAddress)
    			throw Exception("Error commiting memory for section.");
    
    		if(ulSectionSize > 0)
    			memcpy_s(pMemorySectionAddress, ulSectionSize, pFileSectionAddress, ulSectionSize);
    	}
    
    	//Resolve image imports and setup the IAT.
    	IMAGE_IMPORT_DESCRIPTOR* pImportDescriptors = reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR*>(pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + reinterpret_cast<unsigned long>(pLibraryBase));
    	for(unsigned int i = 0; pImportDescriptors[i].FirstThunk; i++)
    	{
    		IMAGE_THUNK_DATA* pInts = reinterpret_cast<IMAGE_THUNK_DATA*>(reinterpret_cast<unsigned long>(pLibraryBase) + pImportDescriptors[i].OriginalFirstThunk);
    		IMAGE_THUNK_DATA* pIat = reinterpret_cast<IMAGE_THUNK_DATA*>(reinterpret_cast<unsigned long>(pLibraryBase) + pImportDescriptors[i].FirstThunk);
    
    		//Technically, I could just use a recursive call to our version of load library, but loading the library via the windows PE loader is a lot less error prone. If you
    		//are writing a packer or something, obviously you want to avoid calls to LoadLibraryA, in which case you should just call recusivley, otherwise just call LoadLibraryA
    		HMODULE hImportLib = LoadLibraryA(reinterpret_cast<const char*>(reinterpret_cast<unsigned long>(pLibraryBase) + pImportDescriptors[i].Name));
    			
    		if(!hImportLib)
    			throw Exception("Unable to find dependancy library.");
    
    		for(unsigned int x = 0; pInts[x].u1.Function != 0; x++)
    		{
    			unsigned long ulImportNameOrdinal = 0;
    
    			if(pInts[x].u1.Function & (1>>31))
    			{
    				//if MSB is set, it is an ordinal.
    				ulImportNameOrdinal = pInts[x].u1.Function & ~(1>>31);
    			}else
    			{
    				IMAGE_IMPORT_BY_NAME* pImport = reinterpret_cast<IMAGE_IMPORT_BY_NAME*>(reinterpret_cast<unsigned long>(pLibraryBase) + pInts[x].u1.Function);
    				ulImportNameOrdinal = reinterpret_cast<unsigned long>(pImport->Name);
    			}
    
    			if( !(pIat[x].u1.Function = reinterpret_cast<unsigned long>(GetProcAddress(hImportLib, reinterpret_cast<const char*>(ulImportNameOrdinal))) ))
    				throw Exception("Error finding import.");
    		}
    	}
    
    	//Do relocations described in the Relocations data directory
    	IMAGE_BASE_RELOCATION* pBaseRelocations = reinterpret_cast<IMAGE_BASE_RELOCATION*>(rvaToFileOffset(pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, pNtHeaders) + reinterpret_cast<unsigned long>(pViewBase));
    	for(IMAGE_BASE_RELOCATION* pCurrentRelocation = pBaseRelocations; 
    		reinterpret_cast<unsigned long>(pCurrentRelocation) - reinterpret_cast<unsigned long>(pBaseRelocations) < pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
    		pCurrentRelocation = reinterpret_cast<IMAGE_BASE_RELOCATION*>(reinterpret_cast<unsigned long>(pCurrentRelocation) + pCurrentRelocation->SizeOfBlock))
    	{
    		long difference = reinterpret_cast<unsigned long>(pLibraryBase) - pNtHeaders->OptionalHeader.ImageBase;
    		unsigned long ulBase = reinterpret_cast<unsigned long>(pLibraryBase) + pCurrentRelocation->VirtualAddress;
    		
    		WORD* pRelocationOffsets = reinterpret_cast<WORD*>(reinterpret_cast<unsigned long>(pCurrentRelocation) + sizeof(IMAGE_BASE_RELOCATION));
    
    		for(unsigned int i = 0; i < pCurrentRelocation->SizeOfBlock / sizeof(WORD); i++)
    			calculateRelocation(difference, ulBase, pRelocationOffsets[i]);
    	}
    
    	//After code relocations, we can apply the proper page permissions.
    	for(unsigned int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
    	{
    		if(pSectionHeaders[i].Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
    			continue;
    
    		void* pMemorySectionAddress = reinterpret_cast<void*>(pSectionHeaders[i].VirtualAddress + reinterpret_cast<unsigned long>(pLibraryBase));
    		setSectionPermissions(pMemorySectionAddress, pSectionHeaders[i].Misc.VirtualSize, pSectionHeaders[i].Characteristics);
    	}
    
    	//And call the library's entrypoint.
    	DllMain_t pEntry = reinterpret_cast<DllMain_t>(reinterpret_cast<unsigned long>(pLibraryBase) + pNtHeaders->OptionalHeader.AddressOfEntryPoint);
    	pEntry(reinterpret_cast<HINSTANCE>(pLibraryBase), DLL_PROCESS_ATTACH, 0);
    
    	UnmapViewOfFile(hFileMap);
    	CloseHandle(hFile);
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	const char* const DLL_NAME = "testdll.dll";
    
    	try
    	{
    		loadDll(DLL_NAME);
    	}catch(Exception& e)
    	{
    		std::cout<<"Error occured: "<<e.getReason()<<std::endl;
    	}
    }
    Luckily you don't actually have to parse the manifest file yourself. The Activation Context functions only require a file location of the manifest, so in the worst case you can simply extract the RT_MANIFEST resource from the PE onto disk, or in the best case the PE will have an external manifest already :3. I forgot you were using MapViewOfFile, so I was basing the code off of my own ManualMap function which is designed for injection into a remote process (I simply load the whole file into memory as an array of bytes and manipulate that data before mapping the file into the remote process).

    Your activation context code will probably be a lot more straightforward than mine. Because all of my code was designed for remote process injection it was a real bitch to write (there are no remote Activation Context functions, so I had to write an assembly stub to d oit, get the bytecode for the stub from Olly and then patch it all up to work with absolute addresses, not exactly fun when the stub is something like 280 bytes long) and of course C# isn't exactly the most assembly-friendly language haha.

    I really should get around to sharing my injection library, but I'm so lazy.
    The fish trap exists because of the fish.
    Once you've gotten the fish you can forget the trap.
    The rabbit snare exists because of the rabbit.
    Once you've gotten the rabbit, you can forget the snare.
    Words exist because of meaning.
    Once you've gotten the meaning, you can forget the words.
    Where can I find a man who has forgotten words so I can talk with him?

  9. #7
    radnomguywfq3's Avatar
    Join Date
    Jan 2007
    Gender
    male
    Location
    J:\E\T\A\M\A\Y.exe
    Posts
    8,858
    Reputation
    381
    Thanks
    1,823
    My Mood
    Sad
    Quote Originally Posted by Broderick View Post


    Luckily you don't actually have to parse the manifest file yourself. The Activation Context functions only require a file location of the manifest, so in the worst case you can simply extract the RT_MANIFEST resource from the PE onto disk, or in the best case the PE will have an external manifest already :3. I forgot you were using MapViewOfFile, so I was basing the code off of my own ManualMap function which is designed for injection into a remote process (I simply load the whole file into memory as an array of bytes and manipulate that data before mapping the file into the remote process).

    Your activation context code will probably be a lot more straightforward than mine. Because all of my code was designed for remote process injection it was a real bitch to write (there are no remote Activation Context functions, so I had to write an assembly stub to d oit, get the bytecode for the stub from Olly and then patch it all up to work with absolute addresses, not exactly fun when the stub is something like 280 bytes long) and of course C# isn't exactly the most assembly-friendly language haha.

    I really should get around to sharing my injection library, but I'm so lazy.
    /dayum, I'm building this PE loader for remote injection too D: I am about make the according changes to get it working like that.

    Ugh, I'll figure it out :X Thanks for the tips.

    On the bright side, the Common runtime libraries used by VS 2010 no longer use SXS, instead they just add the version in to the library name thus making the two runtime libraries (differing in version number) completely different libraries.
    Last edited by radnomguywfq3; 08-28-2012 at 02:37 AM.



    There are two types of tragedies in life. One is not getting what you want, the other is getting it.

    If you wake up at a different time in a different place, could you wake up as a different person?


  10. #8
    Broderick's Avatar
    Join Date
    Apr 2011
    Gender
    male
    Location
    Basement.
    Posts
    100
    Reputation
    42
    Thanks
    30
    Quote Originally Posted by Jetamay View Post
    On the bright side, the Common runtime libraries used by VS 2010 no longer use SXS, instead they just add the version in to the library name thus making the two runtime libraries (differing in version number) completely different libraries.
    What do you mean they no longer use SxS and "just add the version in to the library name"? MSVCR90.dll and MSVCR100.dll are obviously named differently, but they still need to go through the windows SxS assembly cache to retrieve the appropriate version of each.

    x64

    x86

    Obviously if you use static linkage instead of dynamic you won't need the sxs cache for those certain modules (and you'll have a bigger .dll/.exe to distribute). Also, if it's only VS2010 that does what you say (though I don't think even it does that as it'd make no sense), you'd still need to support sxs module resolution for legacy sake (some people are still using archaic versions of VS).

    Nevertheless, fun days ahead :3
    Last edited by Broderick; 08-28-2012 at 02:51 AM.
    The fish trap exists because of the fish.
    Once you've gotten the fish you can forget the trap.
    The rabbit snare exists because of the rabbit.
    Once you've gotten the rabbit, you can forget the snare.
    Words exist because of meaning.
    Once you've gotten the meaning, you can forget the words.
    Where can I find a man who has forgotten words so I can talk with him?

  11. #9
    radnomguywfq3's Avatar
    Join Date
    Jan 2007
    Gender
    male
    Location
    J:\E\T\A\M\A\Y.exe
    Posts
    8,858
    Reputation
    381
    Thanks
    1,823
    My Mood
    Sad
    Quote Originally Posted by Broderick View Post


    What do you mean they no longer use SxS and "just add the version in to the library name"? MSVCR90.dll and MSVCR100.dll are obviously named differently, but they still need to go through the windows SxS assembly cache to retrieve the appropriate version of each.

    x64

    x86

    Obviously if you use static linkage instead of dynamic you won't need the sxs cache for those certain modules (and you'll have a bigger .dll/.exe to distribute). Also, if it's only VS2010 that does what you say (though I don't think even it does that as it'd make no sense), you'd still need to support sxs module resolution for legacy sake (some people are still using archaic versions of VS).

    Nevertheless, fun days ahead :3
    I was just regurgitating what I found on wikipedia regarding side-by-side assemblys.

    Side-by-side assembly - Wikipedia, the free encyclopedia

    Microsoft Visual C++ 2005 and 2008 employ SxS with all C runtime libraries. However, runtime libraries in Visual C++ 2010 no longer use this technology; instead, they include the version number of a DLL in its file name, which means that different versions of one DLL will technically be completely different DLLs now.[1][2]
    And yeah, I know for legacy sake it will still be required for proper implementation. Just thought it would be worth pointing out.
    Last edited by radnomguywfq3; 08-28-2012 at 03:03 AM.



    There are two types of tragedies in life. One is not getting what you want, the other is getting it.

    If you wake up at a different time in a different place, could you wake up as a different person?


  12. #10
    Broderick's Avatar
    Join Date
    Apr 2011
    Gender
    male
    Location
    Basement.
    Posts
    100
    Reputation
    42
    Thanks
    30
    Quote Originally Posted by Jetamay View Post
    I was just regurgitating what I found on wikipedia regarding side-by-side assemblys.

    Side-by-side assembly - Wikipedia, the free encyclopedia



    And yeah, I know for legacy sake it will still be required for proper implementation. Just thought it would be worth pointing out.
    Read the "citations" that whoever wrote that bollocks provided.
    Deployment in Visual C++
    Breaking Changes in Visual C++

    Neither actually state anything about new linkage methods to replace SxS (The "Breaking Changes in Visual C++" doesn't mention side-by-side at all). The other article actually just reinforces what I've just been saying haha.
    Quote Originally Posted by MSDN
    Different library versions can exist side-by-side because the filenames contain the version number (for example, version 11 of the CRT DLL is msvcr110.dll).
    Place no trust in Wikipedia :3
    The fish trap exists because of the fish.
    Once you've gotten the fish you can forget the trap.
    The rabbit snare exists because of the rabbit.
    Once you've gotten the rabbit, you can forget the snare.
    Words exist because of meaning.
    Once you've gotten the meaning, you can forget the words.
    Where can I find a man who has forgotten words so I can talk with him?

  13. #11
    radnomguywfq3's Avatar
    Join Date
    Jan 2007
    Gender
    male
    Location
    J:\E\T\A\M\A\Y.exe
    Posts
    8,858
    Reputation
    381
    Thanks
    1,823
    My Mood
    Sad
    Quote Originally Posted by Broderick View Post


    Read the "citations" that whoever wrote that bollocks provided.
    Deployment in Visual C++
    Breaking Changes in Visual C++

    Neither actually state anything about new linkage methods to replace SxS (The "Breaking Changes in Visual C++" doesn't mention side-by-side at all). The other article actually just reinforces what I've just been saying haha.


    Place no trust in Wikipedia :3
    I have no idea :S I really haven't done such exhaustive research in to the PE file format; but I suppose it is something I really
    should read more in to.

    If you google around though, a lot of people seem to assume that it has been dropped in the Common runtime libraries shipped with MSVC++2010
    https://stackoverflow.com/questions/6...-with-manifest

    Anyway, thanks again.
    Last edited by radnomguywfq3; 08-28-2012 at 03:52 AM.



    There are two types of tragedies in life. One is not getting what you want, the other is getting it.

    If you wake up at a different time in a different place, could you wake up as a different person?


  14. #12
    Broderick's Avatar
    Join Date
    Apr 2011
    Gender
    male
    Location
    Basement.
    Posts
    100
    Reputation
    42
    Thanks
    30
    Quote Originally Posted by Jetamay View Post
    I have no idea :S I really haven't done such exhaustive research in to the PE file format; but I suppose it is something I really
    should read more in to.

    If you google around though, a lot of people seem to assume that it has been dropped in the Common runtime libraries shipped with MSVC++2010
    c++ cli - Visual C++ 2010: Changes to MSVC runtime deployment (no more SxS with manifest) - Stack Overflow

    Anyway, thanks again.
    Now that's a better reference. It appears that you're right and VS2010 no longer uses SxS for the runtime libraries. However writing a generalized loader would still require the Activation Context craps to be dealt with. It's not that big of a deal anyways. What my assembler stub essentially did was Create/Activate the actctx, mass LoadLibrary all the imported modules (regardless of their SxS status), then Deactivate/Release the actctx afterwards. The modules are now loaded into the remote process and you can use their handles to patch the IAT. Simple as a pimple.

    Code:
    BOOL success = TRUE;
    hActCtx = CreateActCtx(...);
    ActivateActCtx(hActCtx, ...);
    while (hasMoreImports && success)
    {
        if (!GetModuleHandle(hasMoreImports) && !LoadLibrary(hasMoreImports))
            success = FALSE;
        hasMoreImports++;
    }
    DeactivateActCtx(NULL, ...);
    ReleaseActCtx(hActCtx);
    return success;
    That's the essence of it.
    Last edited by Broderick; 08-28-2012 at 04:35 AM.
    The fish trap exists because of the fish.
    Once you've gotten the fish you can forget the trap.
    The rabbit snare exists because of the rabbit.
    Once you've gotten the rabbit, you can forget the snare.
    Words exist because of meaning.
    Once you've gotten the meaning, you can forget the words.
    Where can I find a man who has forgotten words so I can talk with him?

  15. #13
    Jabberwock's Avatar
    Join Date
    Jun 2012
    Gender
    male
    Posts
    1,735
    Reputation
    191
    Thanks
    15,701
    My Mood
    Relaxed
    Wow, so much code. It really shows you are a pro C++ user, seeing how complicated the code is...

    If I place a valid dll it seems to work without an error. But how do I actually write it to the process?
    Seems like without learning the code I can't even use it.

    Does it load the DLL to its own EXE? not to other or what? I fail to understand the code.

    Quote Originally Posted by Jetamay View Post
    This can easily be modified for stealing another process's address space. I.e, unload the executable in the remote address space, and setup your executable inside of the remote process from memory (popular with malware.)
    Just now noticed you wrote that.

    So basically I need to do other business with it. That's fine.

    But for that I need to understand the code you wrote.

    Seems like I hurried things, I'll read the post again sorry.
    Last edited by Jabberwock; 08-28-2012 at 08:04 AM.
    Even familiar landscapes will
    reveal a different kind of beauty
    if you change your viewpoint.
    Where these new encounters
    and new bonds will lead you...
    Such dazzling golden days.
    I, too, look forward to
    what I might behold.

  16. #14
    giniyat101's Avatar
    Join Date
    Sep 2011
    Gender
    male
    Location
    Not telling.
    Posts
    1,935
    Reputation
    130
    Thanks
    1,380
    My Mood
    Dead
    omg nice job


     



    [img]https://i43.photobucke*****m/albums/e367/DeteSting/Steam-update.gif[/img]

  17. #15
    radnomguywfq3's Avatar
    Join Date
    Jan 2007
    Gender
    male
    Location
    J:\E\T\A\M\A\Y.exe
    Posts
    8,858
    Reputation
    381
    Thanks
    1,823
    My Mood
    Sad
    Don't download this, refer to the later version: https://www.mpgh.net/forum/31-c-c-pro...ule-final.html



    There are two types of tragedies in life. One is not getting what you want, the other is getting it.

    If you wake up at a different time in a different place, could you wake up as a different person?


  18. The Following User Says Thank You to radnomguywfq3 For This Useful Post:

    giniyat101 (09-03-2012)

Similar Threads

  1. My Custome Loader :)
    By B-Hacker in forum Visual Basic Programming
    Replies: 10
    Last Post: 06-12-2010, 11:35 PM
  2. My Custom CA Loader
    By -CoNdEmNeD- in forum Combat Arms Hacks & Cheats
    Replies: 23
    Last Post: 10-17-2009, 05:18 PM
  3. CUSTOM LOADERS BY NCEXXX
    By ncexxx7214 in forum Combat Arms Hacks & Cheats
    Replies: 5
    Last Post: 08-04-2009, 08:03 PM
  4. Dont Sample The Boolean
    By kvmn8 in forum General
    Replies: 3
    Last Post: 06-15-2006, 08:48 AM
  5. Custom User Titles?
    By Dave84311 in forum News & Announcements
    Replies: 1
    Last Post: 05-02-2006, 10:33 AM