Petok Lorand
Petok Lorand

Reputation: 973

Casting char buffer to function pointer

I recently found out that you can inject machine code in a buffer, at run-time, cast it to a function pointer and then call it to execute the instructions in the buffer. It looks something like this:

int main(void)
{
    char buffer[] = "\xB8\x04\x00\x00\x00\xC3";
    auto func = (int(*)())buffer;
    func();

    return 0;
}

Now what if i don't want to pay for the function call at run-time, in other words i want to treat the buffer as an inline function.

My first naive attempt to achieve this was to declare both the buffer and the func as constexpr and replace the c-style cast with static_cast, although this doesn't seem to work, because it's an invalid cast according to gcc. Tried reinterpret_cast too, but that can't be evaluated at compile-time apparently

Any ideas would be welcome, if is possible to achieve this at all.

Upvotes: 0

Views: 494

Answers (1)

n. m. could be an AI
n. m. could be an AI

Reputation: 119877

Inline assembly code can be injected in a C++ function with an asm declaration. This construct is conditionally supported and implementation defined.

In most implementations, the asm declaration expects some form of symbolic assembly language rather than binary object code.

Here's an example of using the asm declaration construct with GCC on x86.

#include <iostream>

template <int nontype>
int add(int operand)
{
    int sum;

    asm ("movl %1, %0\n\t"
         "addl %2, %0"
         : "=r" (sum)
         : "r" (operand), "r" (nontype)
         : "0");

    return sum;
}

int main()
{
    std::cout << add<42>(6) << "\n";
}

This prints 48 as expected.

Note that gcc's version of asm is quite powerful, and its syntax has to go beyond what the standard specifies in order to support its many features. Other implementations may or may not offer such flexibility (or indeed offer anything at all — the construct is conditionally supported).

Casting between function pointers and data pointers is undefined behaviour in C++. Implementations may do whatever they want with it. I would guess that exploiting this particular form of UB to duplicate perfectly good asm declaration functionality would be rather low on most implementers' to-do lists.

Upvotes: 2

Related Questions