7

In gcc this works fine. The code goes something like:

unsigned char b[50] = "\xda\xd1 ... \x0"; //some shellcode with terminating \x0
( (void(*)())b )(); //cast b to function pointer from void to void, then run it

But when this is put in Visual C++, it spits out this error message:

1>..\test.cpp(132): error C2440: 'type cast' : cannot convert from 'unsigned char [50]' to 'void (__cdecl *)(void)'
1>          There is no context in which this conversion is possible

Anyone know why this is so?

Ethan Heilman
  • 16,347
  • 11
  • 61
  • 88
jcai
  • 3,448
  • 3
  • 21
  • 36
  • 1
    Even if you get this to work somehow, it's a very bad idea. – Mark Ransom Mar 06 '12 at 23:04
  • Or: `reinterpret_cast(static_cast(b))()`. – Kerrek SB Mar 06 '12 at 23:04
  • @NiklasB. `(*(void(*)())&b[0])()` crashes at runtime. First, &b[0] is the same as b. Second, the extra * at the beginning dereferences the function pointer; I assume that it then tries to interpret the shellcode as an address. – jcai Mar 06 '12 at 23:24
  • The wonder isn't that it crashes in Visual C++, the wonder is that it works in gcc. And what exactly do you mean by "shellcode"? – Mark Ransom Mar 06 '12 at 23:35
  • @user49164 dereferencing a function pointer is harmless. It quickly decays back into a function pointer. That's where the classical `***********************************fun_ptr` example comes from. – R. Martinho Fernandes Mar 06 '12 at 23:37
  • @user: You're wrong, it's not the same. – Niklas B. Mar 06 '12 at 23:43
  • @Mark Ransom: It's the standard idiom for testing position-independent, self-contained machine code (shellcode). – Niklas B. Mar 06 '12 at 23:55

2 Answers2

13

A proper debugger will tell you what's going wrong. I can only guess that your code is causing an access violation because the buffer you want to jump to is not executable.

Probably you're on a default-DEP-enabled system like Vista or 7, so you have to make sure that your shellcode is executable. To do that, first use VirtualAlloc to allocate a new, executable buffer and copy your shellcode into it, then execute it:

void *exec = VirtualAlloc(0, sizeof b, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, b, sizeof b);
((void(*)())exec)();

By the way, you don't need to null-terminate the shellcode (C++ will terminate the string literal automatically for you, but this is not necessary). You also don't need to specify a size:

unsigned char b[] = "\xcc";
Niklas B.
  • 92,950
  • 18
  • 194
  • 224
  • Thank you - this works properly. Didn't know that there was a special allocation function for executing stuff. – jcai Mar 06 '12 at 23:53
  • 1
    @user49164: To increase the difficulty of exploiting stack- and heap-based buffer overflows, DEP enforces the obedience of execution permissions on memory pages. This prevents the immediate execution of data on the stack or heap. `VirtualAlloc` is not a special allocation function for executing stuff, it's the general allocation function (which happens to take as an argument the desired access permissions of the allocated memory). – Niklas B. Mar 07 '12 at 00:00
1

The typical way to reinterpret data as a different type is by copying the binary representation:

void (*fp)();
unsigned char buf[50];
char const * p = reinterpret_cast<char const *>(&buf);

std::copy(p, p + sizeof(char const *), reinterpret_cast<char*>(&fp));

// now fp contains the same value as &buf

fp();  // call

This avoids undefined behaviour caused by aliasing and alignment violations.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • The OP is trying to reinterpret a pointer to the buffer as a function pointer, in order to execute the contents as code. Your version overwrites the function pointer with some of the buffer contents - the result is certainly not a valid pointer. You'll need to define a pointer to `buf`, then copy the value of that. – Mike Seymour Mar 06 '12 at 23:17
  • confirmed. This crashes at runtime. – jcai Mar 06 '12 at 23:25
  • This seems like it should work but it crashes - perhaps it's the same DEP problem? – jcai Mar 06 '12 at 23:48
  • Even in the edited form, this will only copy `sizeof(void*)` bytes. – Niklas B. Mar 06 '12 at 23:52
  • @NiklasB.: Well, no, it'll copy `sizeof(char*)` bytes, which is precisely how many bytes there are at `&buf`. Nobody said this was guaranteed to make sense, and it's up to you to ensure that on your platform char pointers, void pointers and function pointers have the same size. You could add one (standard) conversion to void-pointer if you wanted to omit the first check (i.e. add a `void const * q = static_cast(p);` and copy that one). – Kerrek SB Mar 07 '12 at 06:16