2

Would be grateful for your suggestion.Trying to run a 32/64bit on (Windows 10- 64 bit /Visual studio) program which tries to run an executable from memory.This is for my learning purpose.

#include <iostream> // Standard C++ library for console I/O
#include <string> // Standard C++ Library for string manip
#include <Windows.h> // WinAPI Header
#include <TlHelp32.h> //WinAPI Process API

#ifdef _WIN64
typedef IMAGE_NT_HEADERS64  IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS;
typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER;
#else
typedef IMAGE_NT_HEADERS32  IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS;
typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER;
#endif 


// use this if you want to read the executable from disk
HANDLE MapFileToMemory(LPCSTR filename)
{
  std::streampos size;
  std::fstream file(filename, std::ios::in | std::ios::binary 
 |std::ios::ate);
 if (file.is_open())
 {
    size = file.tellg();

    char* Memblock = new char[size]();

    file.seekg(0, std::ios::beg);
    file.read(Memblock, size);
    file.close();

    return Memblock;
    }
 return 0;
 }
 int RunPortableExecutable(void* Image)
  {
   IMAGE_DOS_HEADER* DOSHeader; // For Nt DOS Header symbols
   IMAGE_NT_HEADERS* NtHeader; // For Nt PE Header objects & symbols
   IMAGE_SECTION_HEADER* SectionHeader;

    PROCESS_INFORMATION PI; 
    STARTUPINFOA SI; 
    CONTEXT* CTX;


DWORD* ImageBase; //Base address of the image
void* pImageBase; // Pointer to the image base

int count;
char CurrentFilePath[1024];

DOSHeader = PIMAGE_DOS_HEADER(Image); // Initialize Variable
NtHeader = PIMAGE_NT_HEADERS(DWORD(Image) + DOSHeader->e_lfanew); // Initialize

GetModuleFileNameA(0, CurrentFilePath, 1024); // path to current executable

if (NtHeader->Signature == IMAGE_NT_SIGNATURE) // Check if image is a PE File.
{
    ZeroMemory(&PI, sizeof(PI)); // Null the memory
    ZeroMemory(&SI, sizeof(SI)); // Null the memory

    if (CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE,
        CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) // Create a new instance of current
        //process in suspended state, for the new image.
    {
        // Allocate memory for the context.
        CTX = LPCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE));
        CTX->ContextFlags = CONTEXT_FULL; // Context is allocated

        if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) //if context is in thread
        {
            // Read instructions
            ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Rbx + 8), LPVOID(&ImageBase), 4, 0);

            pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(NtHeader->OptionalHeader.ImageBase),
                NtHeader->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);

            // Write the image to the process
            WriteProcessMemory(PI.hProcess, pImageBase, Image, NtHeader->OptionalHeader.SizeOfHeaders, NULL);

            for (count = 0; count < NtHeader->FileHeader.NumberOfSections; count++)
            {
                SectionHeader = PIMAGE_SECTION_HEADER(DWORD(Image) + DOSHeader->e_lfanew + 248 + (count * 40));

                WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress),
                    LPVOID(DWORD(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0);
            }
            WriteProcessMemory(PI.hProcess, LPVOID(CTX->Rbx + 8),
                LPVOID(&NtHeader->OptionalHeader.ImageBase), 4, 0);

            // Move address of entry point to the eax register
            CTX->Rax = DWORD(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint;
            SetThreadContext(PI.hThread, LPCONTEXT(CTX)); // Set the context
            ResumeThread(PI.hThread); //´Start the process/call main()

            return 0; // Operation was successful.
        }
    }
}

      //enter valid bytes of a  *64 BIT* program here.
      //Sample code 
       unsigned char rawData[37376] = {
       0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00}; 

    int main()
 {
      RunPortableExecutable(rawData); // run executable from the array - 
                                 // 64bit program in hex -coverted from exe
       getchar();
 }

After successful compile on VS 2017 on x64 platform , getting exception.

 if(NtHeader->Signature == IMAGE_NT_SIGNATURE) // Check if image is a PE File  

Still clueless on how the 64bit PE format works on Windows 10. Is the issue on running code (hex format) or this program itself? Am i missing any points? Any suggestions useful.

5
  • You have to make sure that your compiler is compiling as the same "bitness" (don't know the correct word) as the payload you are trying to run. If you compile the injector as 64 bit, your payload also has to be 64 bit. Same goes for 32 bit applications Jan 4, 2018 at 14:58
  • what exception? Jan 4, 2018 at 15:20
  • @PawełŁukasik: Unhandled exception at 0x00007FF64224103C in PE_execute.exe: 0xC0000005: Access violation reading location 0x00000000422540E8
    – Chandra
    Jan 4, 2018 at 15:36
  • Have you debugged the program..? What's Signature pointing to? Doesn't really seem related to SRE
    – Peanut
    Jan 8, 2018 at 2:33
  • Clearly x64 - NT memory pointing something out of bound. Please x86 and x64 comparison (Debug mode). Pls refer the link x86 and x64.
    – Chandra
    Jan 8, 2018 at 7:19

5 Answers 5

2

I have managed to debug and find your problems, but it's really is out of scope since your "bytes" of a "64 bit " program does not have "IMAGE_NT_SIGNATURE" (PE00) but rather has "IMAGE_DOS_SIGNATURE" (MZ). https://i.stack.imgur.com/NdPCQ.png

If I were you, I would first find/prepare proper code for running it as SHELL CODE ( by the way, you know that exploits/shells/malware use the same method yes ? ).

Furthermore, your approach is wrong from the "valid bytes of a 64 BIT program here" to the end.

I shall not post a full solution/answer because that way you will learn nothing. Use the following snippet in addition to what I said, and you shall succeed in your "learning purpose":

IMAGE_DOS_HEADER* lpDosHeader = (IMAGE_DOS_HEADER*)lpBaseAddress;

if(lpDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
    return 0;
}

IMAGE_NT_HEADERS* lpNtHeader = (IMAGE_NT_HEADERS*)(lpBaseAddress+lpDosHeader->e_lfanew);

if(lpNtHeader->Signature != IMAGE_NT_SIGNATURE)
{
    return 0;
}

NOTE that "lpBaseAddress" is BYTE*.

More reference: https://stackoverflow.com/questions/38161809/generating-shellcode-from-an-exe

2
  • @Nobert: aware malware use the same method. This prof of concept. On the Windows 10 (64bit OS ) -my original 32 bit program has run time error though it compiled successfully. Will try your new code and update here. Thanks for your efforts..Cheers!
    – Chandra
    Feb 12, 2018 at 10:42
  • @Chandra No problem, happy to help!
    – Mecanik
    Feb 12, 2018 at 10:43
1

So, you've initialized several bytes:

unsigned char rawData[37376] = { 0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00};

But then, you're accessing DOSHeader->e_lfanew which is not initialized in rawData. Most likely data DOSHeader->e_lfanew contains some trash like 0xCCCCCCCC or 0xDDDDDDDD, so NtHeader points to some memory outside of rawData and you get exception trying to access non-existing memory address.

2
  • MSDN says, In a valid PE file, the Signature field is set to the value 0x00004550, which in ASCII is "PE00". A #define, IMAGE_NT_SIGNATURE, is defined for this value. This is applicable for 32bit files or 64bits as well. My image hex look like this.. [link] (1drv.ms/i/s!AgQa8i37A0sigoIZPkX6dAmx4bOJMA). I have to change to 64 bit instead of 32 on hex editor when i am copying.
    – Chandra
    Jan 4, 2018 at 16:09
  • Please note that the above rawData[ ] is NOT full hex value.
    – Chandra
    Jan 4, 2018 at 16:11
1

The canonical example (IMHO) was written in C by Joachim Bauch in his MemoryModule project.

There is an Object-Pascal port (both Lazarus and Delphi) called BTMemoryModule.

2
  • Just checked example MemoryModule seems work on 32bit version. Can not select X64 from visual studio to compile.So, it is 32 bit version only?
    – Chandra
    Jan 5, 2018 at 3:30
  • 1
    Comments in the codebase indicate it supports 64-bit. You'll have to add this as a build target yourself if you don't see it in Visual Studio.
    – Mick
    Jan 6, 2018 at 18:54
1

For anyone who sees this in the future. The problem was indeed the 64 vs 32 bit issue that the asker thought. The mistake is in this line NtHeader = PIMAGE_NT_HEADERS(DWORD(Image) + DOSHeader->e_lfanew);.

Here, you attempt to add two pointers as a hack to get an address and cast it as a pointer to IMAGE_NT_HEADERS structure. 64-bit pointers, as @dee_two mentioned are 64bits long and DWORD-ing them truncates them; you should get a warning from the vs compiler about this.

The solution is here: don't ever typecast pointers to DWORD, especially on 64-bit architecture. Instead typecast it to a ULONG_PTR or UINT_PTR, like this: NtHeader = PIMAGE_NT_HEADERS(ULONG_PTR(Image) + DOSHeader->e_lfanew);

I lost too much time to find this answer...

1
  • I use ULONG_PT instance of DWORD, but now, My Program will open self. (Not byte of exe).
    – VOLVO
    Aug 22, 2020 at 21:41
0

DWORD is typedefined as unsigned long which is 32bits but the address is 64bits long hence the access violation error. So, use size_t datatype which is typedefined as unsigned long long (64bits long).

As it is a 64 bit program, replace all DWORD's with size_t.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.