0

I have an array with hexadecimal values representing assembly instructions.
I want to push the HelloWorld array as parameter for printf.

Is (int)&HelloWorld the right way to get the address of my array or is there a better solution?
And how can I call Code[] as a function?

I tried with a function pointer but the program jumps somewhere else in memory and ends up crashing at an invalid instruction.

Here is my code:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <errno.h>

int main()
{
    int HelloWorld[15] =
    {
        // Hello World
        0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x00
    };

    int Code[50] =
    {
        // PUSH [DWORD PTR] DS:<address of array HelloWorld>
        0xFF, 0x35, (int)&HelloWorld,
        // CALL <address of function printf>
        0xE8, (int)&printf,
        // ADD esp, 4
        0x83, 0xC4, 0x04,
        // RET
        0xC3
    };

    long unsigned int ProtectionCode = 0;

    // Change protection to read, write, execute
    int ChangeProtect = VirtualProtect(Code, 50, PAGE_EXECUTE_READWRITE,
                                       &ProtectionCode);

    if(ChangeProtect == 0)
    {
        printf("Error: %s\n", strerror(errno));
        return 1;
    }

    void (*CodePtr)() = &Code;
    (*CodePtr)();

    return 0;
}

Thanks for your help.

  • *"I have an array with hexadecimal values representing assembly instructions."* -- Assembly instructions shouldn't come as a bunch of ints. They should come as a string containing instructions such as `"mov eax, 3"`. This is then run by employing the `asm` keyword. Anything like that function pointer cast that you are trying would be undefined behavior and only reliably works if your compiler's documentation says that you can do that. – Blaze Feb 13 '20 at 12:11
  • Assuming that you use x86_32 or x86_64: the problem is, that indeed in memory "0xff,0x35" is stored as "ff 00 00 00 35 00 00 00 ...", while you want to have "ff 35 ...". You have to be more careful when you try to create a buffer with machine code. You could also try to write the buffer to a file and disassemble it with objdump to verify, that it is well-formed. Otherwise, the function call looks ok. – Ctx Feb 13 '20 at 12:18
  • This question duplicates others already on Stack Overflow; asking how to execute data that contains machine instructions is asked from time to time. First, the answer is platform dependent, so you must specify which operating system you are using. Second, you must get the machine code correct. An array of `int`, or preferably `unsigned int`, could be used for machines with a fixed instruction size, but, for Intel, an array of `unsigned char` is a better approach. Third, you will need to call operating system routines to change the page mapping and flush the instruction cache. – Eric Postpischil Feb 13 '20 at 12:34
  • This question does have more questions than those originals, so it could be reopened to address those. But they are elementary errors and probably should be covered separately. Using `(uintptr_t)&HelloWorld` is one way to get an address for use by dynamically prepared instructions, but there could be others. But, for the x86 architecture, the instruction stream must be written as a sequence of bytes, not `int`, and the address (or offset or whatever is used) will have to be copied into that sequence as bytes, not as a whole `int` or `uintptr_t`. – Eric Postpischil Feb 13 '20 at 12:44

1 Answers1

0

This version works fine on my windows:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <errno.h>


char HelloWorld[15] =
{
    // Hello World
    0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x00
};


void  __attribute__((used)) foo(void)
{
    int (*p)(const char *, ...) = printf;
    p(HelloWorld);
}


int main()
{

    unsigned char Code[] ={

        0x55,
        0x89, 0xe5,
        0x83, 0xec, 0x28,
        0xc7, 0x45,  0xf4,  0x78,  0x8c,  0x40, 0x00,
        0xc7, 0x04, 0x24, 0x04, 0xa0, 0x40, 0x00,
        0x8b, 0x45, 0xf4,
        0xff, 0xd0,
        0x90,
        0xc9,
        0xc3,
    };

    long unsigned int ProtectionCode = 0;

    // Change protection to read, write, execute
    int ChangeProtect = VirtualProtect(Code, 50, PAGE_EXECUTE_READWRITE,
                                       &ProtectionCode);

    if(ChangeProtect == 0)
    {
        printf("Error: %s\n", strerror(errno));
        return 1;
    }

    void (*CodePtr)() = &Code;
    (*CodePtr)();

    return 0;
}

the foo is just to take the code from :)

0___________
  • 60,014
  • 4
  • 34
  • 74