1

I wrote a shellcode in C that pops a messagebox. I have compiled two variations of it. One says "Hello World!" (shellcodeA) and the other one says "Goodbye World!" (shellcodeB).

#define WIN32_LEAN_AND_MEAN

#pragma warning( disable : 4201 ) // Disable warning about 'nameless struct/union'

#include "GetProcAddressWithHash.h"

#include <Windows.h>

/** NOTE: module hashes are computed using all-caps unicode strings */
#define LDRLOADDLL_HASH                 0xbdbf9c13
#define LDRGETPROCADDRESS_HASH          0x5ed941b5

typedef int (WINAPI* MESSAGEBOXW)(HWND, LPCWSTR, LPCWSTR, UINT);
typedef NTSTATUS(WINAPI* LDRLOADDLL)(PWCHAR, ULONG, PUNICODE_STRING, PHANDLE);
typedef NTSTATUS(WINAPI* LDRGETPROCADDRESS)(HMODULE, PANSI_STRING, WORD, PVOID*);

#define FILL_STRING_WITH_BUF(string, buffer) \
    string.Length = sizeof(buffer); \
    string.MaximumLength = string.Length; \
    string.Buffer = (PCHAR)buffer

VOID Run()
{
#pragma warning( push )
#pragma warning( disable : 4055 ) // Ignore cast warnings

    // Function pointers
    LDRLOADDLL pLdrLoadDll = NULL;
    LDRGETPROCADDRESS pLdrGetProcAddress = NULL;
    MESSAGEBOXW pMessageBoxW = NULL;

    // General
    HANDLE hUser32;

    // String
    UNICODE_STRING uString = { 0 };
    STRING aString = { 0 };

    WCHAR sUser32[] = { 'u', 's', 'e', 'r', '3', '2', '.', 'd', 'l', 'l' };

    BYTE sMessageBoxW[] = { 'M', 'e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'W', 0 };

    WCHAR sMsgContent[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 };
    WCHAR sMsgTitle[] = { 'D', 'e', 'm', 'o', '!', 0 };

    ///
    // STEP 1: locate all the required functions
    ///

    pLdrLoadDll = (LDRLOADDLL)GetProcAddressWithHash(LDRLOADDLL_HASH);
    pLdrGetProcAddress = (LDRGETPROCADDRESS)GetProcAddressWithHash(LDRGETPROCADDRESS_HASH);

    uString.Buffer = sUser32;
    uString.MaximumLength = sizeof(sUser32);
    uString.Length = sizeof(sUser32);

    pLdrLoadDll(NULL, 0, &uString, &hUser32);

    FILL_STRING_WITH_BUF(aString, sMessageBoxW);
    pLdrGetProcAddress(hUser32, &aString, 0, (PVOID*)&pMessageBoxW);

    ///
    // STEP 2: pop messagebox
    ///

    pMessageBoxW(NULL, sMsgContent, sMsgTitle, 0x00000000L);
}

Now i am trying to write a c++ program that generates a third piece of shellcode that is glueing shellcode A and B together. The way im doing this is having a piece of bootstrap asm that makes a call to shellcodeA and then to shellcodeB. So it will look like this in memory:

    // Bootstrap shellcode
    // shellCodeA
    // shellCodeB

Here is the program:

#include <cstdio>
#include <fstream>

#include "Windows.h"

BOOL ConvertToShellcode(LPSTR& outBytes, DWORD& outLength)
{
    //MARKER:S
    LPSTR shellCodeA32 = const_cast<LPSTR>("\x83\xEC\x60\x53\x55\x56\x57\x6A\x75\x58\x6A\x73\x59\x6A\x65\x5B\x6A\x72\x5F\x6A\x33\x66\x89\x44\x24\x44\x58\x6A\x32\x66\x89\x44\x24\x4C\x58\x6A\x2E\x66\x89\x44\x24\x4E\x58\x6A\x64\x5E\x6A\x6C\x5A\x6A\x6F\x83\x64\x24\x14\x00\x66\x89\x5C\x24\x48\x88\x5C\x24\x2D\x88\x5C\x24\x32\x5B\x6A\x57\x66\x89\x4C\x24\x46\x66\x89\x44\x24\x50\x88\x4C\x24\x2E\x88\x4C\x24\x2F\x59\x6A\x48\x58\x6A\x65\x5D\x6A\x20\x66\x89\x44\x24\x58\x58\x6A\x21\x66\x89\x44\x24\x62\x33\xC0\x88\x4C\x24\x36\x66\x89\x4C\x24\x64\x59\x6A\x44\x66\x89\x44\x24\x70\x58\x66\x89\x44\x24\x34\x6A\x6D\x58\x66\x89\x44\x24\x38\x33\xC0\x66\x89\x7C\x24\x46\x66\x89\x74\x24\x4E\x66\x89\x54\x24\x50\x66\x89\x54\x24\x52\xC6\x44\x24\x28\x4D\x66\xC7\x44\x24\x2C\x61\x67\xC6\x44\x24\x2F\x42\x88\x5C\x24\x30\xC6\x44\x24\x31\x78\xC6\x44\x24\x33\x00\x66\x89\x6C\x24\x56\x66\x89\x54\x24\x58\x66\x89\x54\x24\x5A\x66\x89\x5C\x24\x5C\x66\x89\x5C\x24\x62\x66\x89\x7C\x24\x64\x66\x89\x54\x24\x66\x66\x89\x74\x24\x68\x66\x89\x4C\x24\x6A\x66\x89\x6C\x24\x36\x66\x89\x5C\x24\x3A\x66\x89\x4C\x24\x3C\x66\x89\x44\x24\x3E\xB9\x13\x9C\xBF\xBD\xE8\x71\x00\x00\x00\xB9\xB5\x41\xD9\x5E\x8B\xF0\xE8\x65\x00\x00\x00\x8B\xF8\x33\xDB\x6A\x14\x8D\x44\x24\x44\x89\x44\x24\x20\x58\x66\x89\x44\x24\x1A\x66\x89\x44\x24\x18\x8D\x44\x24\x14\x50\x8D\x44\x24\x1C\x50\x53\x53\xFF\xD6\x6A\x0C\x58\x66\x89\x44\x24\x20\x66\x89\x44\x24\x22\x8D\x44\x24\x28\x89\x44\x24\x24\x8D\x44\x24\x10\x50\x53\x8D\x44\x24\x28\x50\xFF\x74\x24\x20\xFF\xD7\x53\x8D\x44\x24\x38\x50\x8D\x44\x24\x5C\x50\x53\xFF\x54\x24\x20\x5F\x5E\x5D\x5B\x83\xC4\x60\xC3\x83\xEC\x14\x64\xA1\x30\x00\x00\x00\x53\x55\x56\x8B\x40\x0C\x57\x89\x4C\x24\x1C\x8B\x78\x0C\xE9\xA5\x00\x00\x00\x8B\x47\x30\x33\xF6\x8B\x5F\x2C\x8B\x3F\x89\x44\x24\x10\x8B\x42\x3C\x89\x7C\x24\x14\x8B\x6C\x10\x78\x89\x6C\x24\x18\x85\xED\x0F\x84\x80\x00\x00\x00\xC1\xEB\x10\x33\xC9\x85\xDB\x74\x2F\x8B\x7C\x24\x10\x0F\xBE\x2C\x0F\xC1\xCE\x0D\x80\x3C\x0F\x61\x89\x6C\x24\x10\x7C\x09\x8B\xC5\x83\xC0\xE0\x03\xF0\xEB\x04\x03\x74\x24\x10\x41\x3B\xCB\x72\xDD\x8B\x7C\x24\x14\x8B\x6C\x24\x18\x8B\x44\x2A\x20\x33\xDB\x8B\x4C\x2A\x18\x03\xC2\x89\x4C\x24\x10\x85\xC9\x74\x34\x8B\x38\x33\xED\x03\xFA\x83\xC0\x04\x89\x44\x24\x20\x8A\x0F\xC1\xCD\x0D\x0F\xBE\xC1\x03\xE8\x47\x84\xC9\x75\xF1\x8B\x7C\x24\x14\x8D\x04\x2E\x3B\x44\x24\x1C\x74\x20\x8B\x44\x24\x20\x43\x3B\x5C\x24\x10\x72\xCC\x8B\x57\x18\x85\xD2\x0F\x85\x50\xFF\xFF\xFF\x33\xC0\x5F\x5E\x5D\x5B\x83\xC4\x14\xC3\x8B\x74\x24\x18\x8B\x44\x16\x24\x8D\x04\x58\x0F\xB7\x0C\x10\x8B\x44\x16\x1C\x8D\x04\x88\x8B\x04\x10\x03\xC2\xEB\xDB");
    LPSTR shellCodeA64 = const_cast<LPSTR>("\x48\x89\x5C\x24\x18\x48\x89\x7C\x24\x20\x55\x48\x8D\x6C\x24\xA9\x48\x81\xEC\xA0\x00\x00\x00\x33\xDB\xC7\x45\x17\x75\x00\x73\x00\xB9\x13\x9C\xBF\xBD\x48\x89\x5D\x67\x89\x5D\xFB\x89\x5D\x0B\x66\x89\x5D\x47\xC7\x45\x1B\x65\x00\x72\x00\xC7\x45\x1F\x33\x00\x32\x00\xC7\x45\x23\x2E\x00\x64\x00\xC7\x45\x27\x6C\x00\x6C\x00\xC7\x45\xD7\x4D\x65\x73\x73\xC7\x45\xDB\x61\x67\x65\x42\xC7\x45\xDF\x6F\x78\x57\x00\xC7\x45\x2F\x48\x00\x65\x00\xC7\x45\x33\x6C\x00\x6C\x00\xC7\x45\x37\x6F\x00\x20\x00\xC7\x45\x3B\x57\x00\x6F\x00\xC7\x45\x3F\x72\x00\x6C\x00\xC7\x45\x43\x64\x00\x21\x00\xC7\x45\xE7\x44\x00\x65\x00\xC7\x45\xEB\x6D\x00\x6F\x00\xC7\x45\xEF\x21\x00\x00\x00\xE8\x74\x00\x00\x00\xB9\xB5\x41\xD9\x5E\x48\x8B\xD8\xE8\x67\x00\x00\x00\x48\x8B\xF8\xC7\x45\xF7\x14\x00\x14\x00\x48\x8D\x45\x17\x33\xD2\x4C\x8D\x4D\x6F\x48\x89\x45\xFF\x4C\x8D\x45\xF7\x33\xC9\xFF\xD3\x48\x8B\x4D\x6F\x48\x8D\x45\xD7\x45\x33\xC0\x48\x89\x45\x0F\x4C\x8D\x4D\x67\xC7\x45\x07\x0C\x00\x0C\x00\x48\x8D\x55\x07\xFF\xD7\x45\x33\xC9\x4C\x8D\x45\xE7\x48\x8D\x55\x2F\x33\xC9\xFF\x55\x67\x4C\x8D\x9C\x24\xA0\x00\x00\x00\x49\x8B\x5B\x20\x49\x8B\x7B\x28\x49\x8B\xE3\x5D\xC3\xCC\xCC\x48\x8B\xC4\x48\x89\x58\x08\x48\x89\x68\x10\x48\x89\x70\x18\x48\x89\x78\x20\x41\x56\x48\x83\xEC\x10\x65\x48\x8B\x04\x25\x60\x00\x00\x00\x8B\xE9\x45\x33\xF6\x48\x8B\x50\x18\x4C\x8B\x4A\x10\x4D\x8B\x41\x30\x4D\x85\xC0\x0F\x84\xB3\x00\x00\x00\x41\x0F\x10\x41\x58\x49\x63\x40\x3C\x41\x8B\xD6\x4D\x8B\x09\xF3\x0F\x7F\x04\x24\x46\x8B\x9C\x00\x88\x00\x00\x00\x45\x85\xDB\x74\xD2\x48\x8B\x04\x24\x48\xC1\xE8\x10\x66\x44\x3B\xF0\x73\x22\x48\x8B\x4C\x24\x08\x44\x0F\xB7\xD0\x0F\xBE\x01\xC1\xCA\x0D\x80\x39\x61\x7C\x03\x83\xC2\xE0\x03\xD0\x48\xFF\xC1\x49\x83\xEA\x01\x75\xE7\x4F\x8D\x14\x18\x45\x8B\xDE\x41\x8B\x7A\x20\x49\x03\xF8\x45\x39\x72\x18\x76\x8E\x8B\x37\x41\x8B\xDE\x49\x03\xF0\x48\x8D\x7F\x04\x0F\xBE\x0E\x48\xFF\xC6\xC1\xCB\x0D\x03\xD9\x84\xC9\x75\xF1\x8D\x04\x13\x3B\xC5\x74\x0E\x41\xFF\xC3\x45\x3B\x5A\x18\x72\xD5\xE9\x5E\xFF\xFF\xFF\x41\x8B\x42\x24\x43\x8D\x0C\x1B\x49\x03\xC0\x0F\xB7\x14\x01\x41\x8B\x4A\x1C\x49\x03\xC8\x8B\x04\x91\x49\x03\xC0\xEB\x02\x33\xC0\x48\x8B\x5C\x24\x20\x48\x8B\x6C\x24\x28\x48\x8B\x74\x24\x30\x48\x8B\x7C\x24\x38\x48\x83\xC4\x10\x41\x5E\xC3");
    LPSTR shellCodeB32 = const_cast<LPSTR>("\x83\xEC\x64\x53\x55\x56\x57\x6A\x75\x58\x6A\x73\x59\x6A\x65\x5B\x6A\x72\x5F\x6A\x33\x66\x89\x44\x24\x44\x58\x6A\x32\x66\x89\x44\x24\x4C\x58\x6A\x2E\x66\x89\x44\x24\x4E\x58\x6A\x64\x5E\x6A\x6C\x5A\x6A\x6F\x83\x64\x24\x14\x00\x66\x89\x5C\x24\x48\x88\x5C\x24\x2D\x88\x5C\x24\x32\x5B\x6A\x57\x66\x89\x4C\x24\x46\x66\x89\x44\x24\x50\x88\x4C\x24\x2E\x88\x4C\x24\x2F\x59\x6A\x47\x58\x6A\x62\x66\x89\x44\x24\x58\x58\x6A\x79\x66\x89\x44\x24\x60\x58\x6A\x65\x5D\x6A\x20\x66\x89\x44\x24\x62\x58\x6A\x21\x88\x4C\x24\x36\x66\x89\x44\x24\x66\x33\xC0\x66\x89\x4C\x24\x68\x59\x6A\x44\x66\x89\x44\x24\x74\x58\x66\x89\x7C\x24\x46\x66\x89\x74\x24\x4E\x66\x89\x54\x24\x50\x66\x89\x54\x24\x52\xC6\x44\x24\x28\x4D\x66\xC7\x44\x24\x2C\x61\x67\xC6\x44\x24\x2F\x42\x88\x5C\x24\x30\xC6\x44\x24\x31\x78\xC6\x44\x24\x33\x00\x66\x89\x5C\x24\x56\x66\x89\x5C\x24\x58\x66\x89\x74\x24\x5A\x66\x89\x6C\x24\x60\x66\x89\x5C\x24\x66\x66\x89\x7C\x24\x68\x66\x89\x54\x24\x6A\x66\x89\x74\x24\x6C\x66\x89\x4C\x24\x6E\x66\x89\x44\x24\x34\x66\x89\x6C\x24\x36\x6A\x6D\x58\x66\x89\x44\x24\x38\x33\xC0\x66\x89\x4C\x24\x3C\xB9\x13\x9C\xBF\xBD\x66\x89\x5C\x24\x3A\x66\x89\x44\x24\x3E\xE8\x71\x00\x00\x00\xB9\xB5\x41\xD9\x5E\x8B\xF0\xE8\x65\x00\x00\x00\x8B\xF8\x33\xDB\x6A\x14\x8D\x44\x24\x44\x89\x44\x24\x20\x58\x66\x89\x44\x24\x1A\x66\x89\x44\x24\x18\x8D\x44\x24\x14\x50\x8D\x44\x24\x1C\x50\x53\x53\xFF\xD6\x6A\x0C\x58\x66\x89\x44\x24\x20\x66\x89\x44\x24\x22\x8D\x44\x24\x28\x89\x44\x24\x24\x8D\x44\x24\x10\x50\x53\x8D\x44\x24\x28\x50\xFF\x74\x24\x20\xFF\xD7\x53\x8D\x44\x24\x38\x50\x8D\x44\x24\x5C\x50\x53\xFF\x54\x24\x20\x5F\x5E\x5D\x5B\x83\xC4\x64\xC3\x83\xEC\x14\x64\xA1\x30\x00\x00\x00\x53\x55\x56\x8B\x40\x0C\x57\x89\x4C\x24\x1C\x8B\x78\x0C\xE9\xA5\x00\x00\x00\x8B\x47\x30\x33\xF6\x8B\x5F\x2C\x8B\x3F\x89\x44\x24\x10\x8B\x42\x3C\x89\x7C\x24\x14\x8B\x6C\x10\x78\x89\x6C\x24\x18\x85\xED\x0F\x84\x80\x00\x00\x00\xC1\xEB\x10\x33\xC9\x85\xDB\x74\x2F\x8B\x7C\x24\x10\x0F\xBE\x2C\x0F\xC1\xCE\x0D\x80\x3C\x0F\x61\x89\x6C\x24\x10\x7C\x09\x8B\xC5\x83\xC0\xE0\x03\xF0\xEB\x04\x03\x74\x24\x10\x41\x3B\xCB\x72\xDD\x8B\x7C\x24\x14\x8B\x6C\x24\x18\x8B\x44\x2A\x20\x33\xDB\x8B\x4C\x2A\x18\x03\xC2\x89\x4C\x24\x10\x85\xC9\x74\x34\x8B\x38\x33\xED\x03\xFA\x83\xC0\x04\x89\x44\x24\x20\x8A\x0F\xC1\xCD\x0D\x0F\xBE\xC1\x03\xE8\x47\x84\xC9\x75\xF1\x8B\x7C\x24\x14\x8D\x04\x2E\x3B\x44\x24\x1C\x74\x20\x8B\x44\x24\x20\x43\x3B\x5C\x24\x10\x72\xCC\x8B\x57\x18\x85\xD2\x0F\x85\x50\xFF\xFF\xFF\x33\xC0\x5F\x5E\x5D\x5B\x83\xC4\x14\xC3\x8B\x74\x24\x18\x8B\x44\x16\x24\x8D\x04\x58\x0F\xB7\x0C\x10\x8B\x44\x16\x1C\x8D\x04\x88\x8B\x04\x10\x03\xC2\xEB\xDB");
    LPSTR shellCodeB64 = const_cast<LPSTR>("\x48\x89\x5C\x24\x18\x48\x89\x7C\x24\x20\x55\x48\x8D\x6C\x24\xA9\x48\x81\xEC\xA0\x00\x00\x00\x33\xDB\xC7\x45\x17\x75\x00\x73\x00\xB9\x13\x9C\xBF\xBD\x48\x89\x5D\x67\x89\x5D\xFB\x89\x5D\x0B\x66\x89\x5D\x4B\xC7\x45\x1B\x65\x00\x72\x00\xC7\x45\x1F\x33\x00\x32\x00\xC7\x45\x23\x2E\x00\x64\x00\xC7\x45\x27\x6C\x00\x6C\x00\xC7\x45\xD7\x4D\x65\x73\x73\xC7\x45\xDB\x61\x67\x65\x42\xC7\x45\xDF\x6F\x78\x57\x00\xC7\x45\x2F\x47\x00\x6F\x00\xC7\x45\x33\x6F\x00\x64\x00\xC7\x45\x37\x62\x00\x79\x00\xC7\x45\x3B\x65\x00\x20\x00\xC7\x45\x3F\x57\x00\x6F\x00\xC7\x45\x43\x72\x00\x6C\x00\xC7\x45\x47\x64\x00\x21\x00\xC7\x45\xE7\x44\x00\x65\x00\xC7\x45\xEB\x6D\x00\x6F\x00\xC7\x45\xEF\x21\x00\x00\x00\xE8\x75\x00\x00\x00\xB9\xB5\x41\xD9\x5E\x48\x8B\xD8\xE8\x68\x00\x00\x00\x48\x8B\xF8\xC7\x45\xF7\x14\x00\x14\x00\x48\x8D\x45\x17\x33\xD2\x4C\x8D\x4D\x6F\x48\x89\x45\xFF\x4C\x8D\x45\xF7\x33\xC9\xFF\xD3\x48\x8B\x4D\x6F\x48\x8D\x45\xD7\x45\x33\xC0\x48\x89\x45\x0F\x4C\x8D\x4D\x67\xC7\x45\x07\x0C\x00\x0C\x00\x48\x8D\x55\x07\xFF\xD7\x45\x33\xC9\x4C\x8D\x45\xE7\x48\x8D\x55\x2F\x33\xC9\xFF\x55\x67\x4C\x8D\x9C\x24\xA0\x00\x00\x00\x49\x8B\x5B\x20\x49\x8B\x7B\x28\x49\x8B\xE3\x5D\xC3\xCC\xCC\xCC\x48\x8B\xC4\x48\x89\x58\x08\x48\x89\x68\x10\x48\x89\x70\x18\x48\x89\x78\x20\x41\x56\x48\x83\xEC\x10\x65\x48\x8B\x04\x25\x60\x00\x00\x00\x8B\xE9\x45\x33\xF6\x48\x8B\x50\x18\x4C\x8B\x4A\x10\x4D\x8B\x41\x30\x4D\x85\xC0\x0F\x84\xB3\x00\x00\x00\x41\x0F\x10\x41\x58\x49\x63\x40\x3C\x41\x8B\xD6\x4D\x8B\x09\xF3\x0F\x7F\x04\x24\x46\x8B\x9C\x00\x88\x00\x00\x00\x45\x85\xDB\x74\xD2\x48\x8B\x04\x24\x48\xC1\xE8\x10\x66\x44\x3B\xF0\x73\x22\x48\x8B\x4C\x24\x08\x44\x0F\xB7\xD0\x0F\xBE\x01\xC1\xCA\x0D\x80\x39\x61\x7C\x03\x83\xC2\xE0\x03\xD0\x48\xFF\xC1\x49\x83\xEA\x01\x75\xE7\x4F\x8D\x14\x18\x45\x8B\xDE\x41\x8B\x7A\x20\x49\x03\xF8\x45\x39\x72\x18\x76\x8E\x8B\x37\x41\x8B\xDE\x49\x03\xF0\x48\x8D\x7F\x04\x0F\xBE\x0E\x48\xFF\xC6\xC1\xCB\x0D\x03\xD9\x84\xC9\x75\xF1\x8D\x04\x13\x3B\xC5\x74\x0E\x41\xFF\xC3\x45\x3B\x5A\x18\x72\xD5\xE9\x5E\xFF\xFF\xFF\x41\x8B\x42\x24\x43\x8D\x0C\x1B\x49\x03\xC0\x0F\xB7\x14\x01\x41\x8B\x4A\x1C\x49\x03\xC8\x8B\x04\x91\x49\x03\xC0\xEB\x02\x33\xC0\x48\x8B\x5C\x24\x20\x48\x8B\x6C\x24\x28\x48\x8B\x74\x24\x30\x48\x8B\x7C\x24\x38\x48\x83\xC4\x10\x41\x5E\xC3");
    DWORD shellCodeA32Length = 629, shellCodeA64Length = 552;
    DWORD shellCodeB32Length = 645, shellCodeB64Length = 560;
    //MARKER:E

    LPSTR shellcodeA = shellCodeA32;
    LPSTR shellcodeB = shellCodeB32;
    DWORD shellcodeALength = shellCodeA32Length;
    DWORD shellcodeBLength = shellCodeB32Length;
    
    if (shellcodeA == NULL || shellcodeALength == 0) return FALSE;

    BYTE bootstrap[12] = { 0 };
    DWORD i = 0;

    // call - Transfer execution to shellCodeA
    bootstrap[i++] = 0xe8;
    bootstrap[i++] = sizeof(bootstrap) - i - 4; // Skip the remainder of instructions
    bootstrap[i++] = 0x00;
    bootstrap[i++] = 0x00;
    bootstrap[i++] = 0x00;
    
    // leave
    //bootstrap[i++] = 0xc9;

    // ret - return to caller
    //bootstrap[i++] = 0xc3;
    
    // call - Transfer execution to shellCodeB
    bootstrap[i++] = 0xe8;
    bootstrap[i++] = sizeof(bootstrap) + shellcodeALength - i - 4; // Skip the remainder of instructions
    bootstrap[i++] = 0x00;
    bootstrap[i++] = 0x00;
    bootstrap[i++] = 0x00;

    // leave
    bootstrap[i++] = 0xc9;

    // ret - return to caller
    bootstrap[i++] = 0xc3;

    // Ends up looking like this in memory:
    // Bootstrap shellcode
    // shellCodeA
    // shellCodeB
    outLength = sizeof(bootstrap) + shellcodeALength + shellcodeBLength;
    outBytes = (LPSTR)malloc(outLength);
    MoveMemory(outBytes, bootstrap, sizeof(bootstrap));
    MoveMemory(outBytes + sizeof(bootstrap), shellcodeA, shellcodeALength);
    MoveMemory(outBytes + sizeof(bootstrap) + shellcodeALength, shellcodeB, shellcodeBLength);

    return TRUE;
}

typedef UINT_PTR(WINAPI* SHC)();

int main()
{
    LPSTR           finalShellcode = NULL;
    DWORD           finalSize;
    DWORD           dwOldProtect1 = 0;
    SYSTEM_INFO     sysInfo;
    BOOL            status;
    std::fstream    outFile;
    DWORD           dLastError;
    
    status = ConvertToShellcode(finalShellcode, finalSize);
    if (!status) {
        printf("[!] Failed to convert shellcode\n");
        goto Cleanup;
    }

    outFile = std::fstream(R"(../bin/FinalShellcode_x86.bin)",
        std::ios::out | std::ios::binary);
    outFile.write(finalShellcode, finalSize);
    outFile.close();

    GetNativeSystemInfo(&sysInfo);

    status = VirtualProtect(finalShellcode, sysInfo.dwPageSize, PAGE_EXECUTE_READWRITE, &dwOldProtect1);
    if (status) {
        SHC shc = (SHC)(finalShellcode);

        printf("[+] Executing shell code\n");
        HMODULE hLoadedShc = (HMODULE)shc(); // Excute shellcode

        status = 1;
        goto Cleanup;
    }

    dLastError = GetLastError();

Cleanup:
    if (finalShellcode)
        free(finalShellcode);

    return !status;
}

So when i run the shellcode the ConvertToShellcode function produces shellcodeA gets called and i see a messagebox with "Hello world!". But when its time to call shellcodeB i get an access violation error. When i checked the buffer where the shellcode got allocated in IDA using blobrunner i found this: Bootstrap

I can see that the first call points to a valid function. But the second call points somewhere within the first shellcode and not to the second one. I saw the subroutine for shellcodeA started at 0x6A000C. ShellcodeA is 629 bytes long so shellcodeB should start at 0x6A0281. And not at 0x6A007E. 0x6A0281 looks about right. I can see the user32.dll array. shellcodeB If we now take a look again at the cpp program. If i debug it using msvc: deboooog I can see that the value for sizeof(bootstrap) + shellcodeALength - i - 4 equals 0x119 which is 281 This cant be true since ShellcodeA is around 600 bytes long. If i manually calculate sizeof(bootstrap) + shellcodeALength - i - 4 i get 631 which is 0x277 in hex. I have a feeling im confusing hex and ints at this point but the outcomes are totally different. Could anyone here please point me in the right direction since i have no idea what to do anymore. I have also already tried manually setting the call to the right offset but i didnt get different results.

EDIT: here is a link to the github project so you can compile the program and shellcodes if you want. https://github.com/11philip22/asmGlue/

0___________
  • 60,014
  • 4
  • 34
  • 74
woldgrep
  • 97
  • 2
  • 12
  • `bootstrap[i++] = sizeof(bootstrap) + shellcodeALength - i - 4;` looks like [undefined behaviour](https://stackoverflow.com/questions/949433/why-are-these-constructs-using-pre-and-post-increment-undefined-behavior). – YSC May 19 '21 at 13:11

1 Answers1

3

I don't know where you see the value 0x119, but BYTE bootstrap[12] is a BYTE array.

So assigning bootstrap[i++] = sizeof(bootstrap) + shellcodeALength - i - 4; will store the lowest byte of the expression in bootstrap[i++] and ignore the rest, hence can never go above 255.

You probably want something like this instead:

DWORD offset = sizeof(bootstrap) + shellcodeALength - i - 4;
bootstrap[i++] = (BYTE)offset;
bootstrap[i++] = (BYTE)(offset >> 8);
bootstrap[i++] = (BYTE)(offset >> 16);
bootstrap[i++] = (BYTE)(offset >> 24);

Also as mentioned in the comments, avoid i++ and i in the same statement - see What are “sequence points” and how do they affect undefined behavior? for more details.

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • 1
    Well turns out it was just enough to to make it work:) thanks a lot you made my day – woldgrep May 19 '21 at 13:42
  • @woldgrep: since you're running this on x86, you could jalso ust `memcpy` a dword into those 4 bytes, instead of doing it manually one byte at a time. (Although good modern compilers will see through that and compile it to a dword store). x86 machine code uses native endianness for immediates / displacements. – Peter Cordes May 19 '21 at 15:51
  • @PeterCordes Thanks for the tip! :) – woldgrep May 19 '21 at 18:59