Calling a Function Through Its Address in Memory in C/C++

Calling a function through its address in memory in c / c++

On modern operating systems, each process has its own address space and addresses are only valid within a process. If you want to execute code in some other process, you either have to inject a shared library or attach your program as a debugger.

Once you are in the other program's address space, this code invokes a function at an arbitrary address:

typedef int func(void);
func* f = (func*)0xdeadbeef;
int i = f();

Calling a function via its address C

Given the code (extracted from your code):

typedef void* memchr(const void *, int, size_t);

void shell_code(void)
{
memchr* memchr = (memchr*)0xdeadbeef;
// ^1 ^2 ^3

The ^1 mention of memchr is to the function type in the typedef; the ^2 mention is the name of a local variable. This local variable now hides the type; you can no longer access the type in the function. The ^3 mention of memchr is a reference to the local pointer-to-function variable, not to the type. You have a multiplication operator after the variable, but no RHS for the multiplication — so the compiler complains about the ) because it expected an expression there as the RHS of the multiplication.

Don't play so hard with the same name. You'll confuse people reading your code. Use different names for the type and the function pointer. For example (not necessarily good naming style, but sufficient — and avoiding functions in favour of function pointers):

typedef void *(*MemChr)(const void *, int, size_t);

void shell_code(void)
{
MemChr p_memchr = (MemChr)0xdeadbeef;

The code now stands a chance of compiling, but will simply crash when you run it and call p_memchr because the code at 0xDEADBEEF is unlikely to be a function like memchr, assuming it is mapped as executable code at all.

Note that this notation allows you to #include <string.h> (where memchr() is declared) without interfering with it, or interference from it.

Call function by known address? C++

If you’re sure that there’s a function there, you could call it by casting the address to a function pointer of the appropriate type, then calling it. Here’s C code to do this:

typedef int (*FunctionType)(uint32_t*);

FunctionType function = (FunctionType)0x11111111;
function(arg);

This can easily be modified to support any number of function arguments and any return type you’d like. Just tweak the argument types list of the FunctionType typedef.

Or, in one line (gulp):

(((int (*)(uint32_t *)) 0x11111111)(arg);

C# calling a function from it's memory address

I have to mention it first that CallingConvention.FastCall is not supported, please take a look here.

Here's the hook class:

// Author: Moien007
public unsafe class Hook
{
const string KERNEL32 = "kernel32.dll";

[DllImport(KERNEL32)]
static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, VirtualProtectionType flNewProtect, out VirtualProtectionType lpflOldProtect);

private enum VirtualProtectionType : uint
{
Execute = 0x10,
ExecuteRead = 0x20,
ExecuteReadWrite = 0x40,
ExecuteWriteCopy = 0x80,
NoAccess = 0x01,
Readonly = 0x02,
ReadWrite = 0x04,
WriteCopy = 0x08,
GuardModifierflag = 0x100,
NoCacheModifierflag = 0x200,
WriteCombineModifierflag = 0x400
}

private byte[] m_OriginalBytes;

public IntPtr TargetAddress { get; }
public IntPtr HookAddress { get; }

public Hook(IntPtr target, IntPtr hook)
{
if (Environment.Is64BitProcess)
throw new NotSupportedException("X64 not supported, TODO");

TargetAddress = target;
HookAddress = hook;

m_OriginalBytes = new byte[5];
fixed (byte* p = m_OriginalBytes)
{
ProtectionSafeMemoryCopy(new IntPtr(p), target, m_OriginalBytes.Length);
}
}

public void Install()
{
var jmp = CreateJMP(TargetAddress, HookAddress);
fixed (byte* p = jmp)
{
ProtectionSafeMemoryCopy(TargetAddress, new IntPtr(p), jmp.Length);
}
}

public void Unistall()
{
fixed (byte* p = m_OriginalBytes)
{
ProtectionSafeMemoryCopy(TargetAddress, new IntPtr(p), m_OriginalBytes.Length);
}
}

static void ProtectionSafeMemoryCopy(IntPtr dest, IntPtr source, int count)
{
// UIntPtr = size_t
var bufferSize = new UIntPtr((uint)count);
VirtualProtectionType oldProtection, temp;

// unprotect memory to copy buffer
if (!VirtualProtect(dest, bufferSize, VirtualProtectionType.ExecuteReadWrite, out oldProtection))
throw new Exception("Failed to unprotect memory.");

byte* pDest = (byte*)dest;
byte* pSrc = (byte*)source;

// copy buffer to address
for (int i = 0; i < count; i++)
{
*(pDest + i) = *(pSrc + i);
}

// protect back
if (!VirtualProtect(dest, bufferSize, oldProtection, out temp))
throw new Exception("Failed to protect memory.");
}

static byte[] CreateJMP(IntPtr from, IntPtr to)
{
return CreateJMP(new IntPtr(to.ToInt32() - from.ToInt32() - 5));
}

static byte[] CreateJMP(IntPtr relAddr)
{
var list = new List<byte>();
// get bytes of function address
var funcAddr32 = BitConverter.GetBytes(relAddr.ToInt32());

// jmp [relative addr] (http://ref.x86asm.net/coder32.html#xE9)
list.Add(0xE9); // jmp
list.AddRange(funcAddr32); // func addr

return list.ToArray();
}
}
  • Find target function address (for example using GetProcAddress)
  • Define a delegate for that function
  • Use Marshal.GetDelegateForFunctionPointer and get delegate for target function so you call it inside your hook function
  • Define your hook function (I mean the function that will called instead of target)
  • Use Marshal.GetFunctionPointerForDelegate and get function pointer for your hook function
    (Note: assign the delegate to a static field or use GCHandle.Alloc to prevent GC from collecting it which leads to crash)
  • Now use Hook class

This technique isn't thread safe (more info on it), I recommend you to use EasyHook.

Call a function in C++ by its address without knowing the return type

If the returning type is really unknown or it doesn't matter, you can use void in your function definition, or if it is any pointer you can use void *, but if the function is in a C coded DLL, and you'll use it in a C++ code, then you can utilize and share almost every type defined in your C code, because C++ it's a superset of C.

That said, I prepared a small example with a structure called PyObject shared in C and C++ codes.

To do this, is better creating a header with the shared types/definitions:

#ifndef PYOBJECT_DLL_H
#define PYOBJECT_DLL_H

#ifdef __cplusplus
extern "C" {
#endif

// Common structure definition
typedef struct PyObject{
int field1;
char *field2;
} PyObject;

// Public function pointer type declaration
typedef PyObject *(*__stdcall getPyObject_t)(int arg1, const char *arg2);

#ifdef __cplusplus
}
#endif

#endif // PYOBJECT_DLL_H

Let's suppose that the C code with the exported function is something like:

#include "pyobject.h"
#include <stdlib.h>

#ifdef __cplusplus
extern "C"
#endif
__declspec(dllexport) PyObject * getPyObject(int arg1, char *arg2);

PyObject *getPyObject(int arg1, char *arg2){
PyObject *obj = (PyObject *)malloc(sizeof(PyObject));
obj->field1 = arg1;
obj->field2 = arg2;
return obj;
}

Finally the C++ code using the function and data created in the library would be:

#include "pyobject.h"
#include <iostream>
#include <windows.h>

int main() {
HINSTANCE dll = LoadLibrary("pyobject.dll");
if (dll == NULL) {
std::cerr << "Cannot open pyobject.dll. Error: " << GetLastError() << "\n";
return 1;
}

getPyObject_t getPyObject = (getPyObject_t) GetProcAddress(dll, "getPyObject");
if (getPyObject == NULL) {
std::cerr << "Cannot locate 'getPyObject' function in dll. Error: " << GetLastError() << "\n";
FreeLibrary(dll);
return 2;
}

PyObject *obj = getPyObject(3, "test");
std::cout << "PyObject == { field1: " << obj->field1 << ", field2: \"" << obj->field2 << "\"}\n";

FreeLibrary(dll);
return 0;
}

Edit

As @raymondchen pointed in his comment, ignoring the return type when the C function returns a large aggregate (e.g. struct) it's not a good idea, because the C function expects that the caller already has had reserved stack space to store the returned aggregate, but if the caller treats the function as void or anything else, then compiler will not reserve that space, causing unpredictable effects (probably ending with Segmentation fault error).

To avoid it, it's always better to define the correct type in both C and C++ codes (or in the common header), especially when the C function returns an aggregate.

Is it possible within a function to get the memory address of the variable initialized by the return value?

NO. int is returned in a register, and the callee has no involvement in what the caller does with that register after it returns. It might never be stored in memory.

If the return-type wasn't int, but instead something large enough that the calling convention returned it by value, then hypothetical_func would have an address for an output. (Or a hypothetical (terrible) calling convention might return even int via hidden pointer instead of a register. Assuming the machine is a register machine like all real CPUs.)

But that might just be a return-value temporary, not the actual LHS of an assignment. (Or initialization, which is close enough to the same thing in C, if not C++). Especially if the assignment is to a global or something. See What prevents the usage of a function argument as hidden pointer? for the case of *out = foo(); where T *out is a function arg. It's highly non-trivial to prove if/when it's safe to pass that function arg along as the return-value object for foo().

And some compilers don't even try to optimize, and just make space on the stack for the return-value temporary and copy from there into the final object.

And as @prl points out, the return-value might not even be the initializer for a variable. e.g. printf("%d\n", foo()); just passes on the return value to a function arg. Or foo(); discards the return value, not assigning it anywhere. (But if the calling convention specifies that the function returns by hidden pointer, the caller must pass a pointer to enough scratch space. The callee is still going to write its return value and needs to not segfault from a bad pointer or overwrite something else. That's an asm / calling-convention detail separate from the operation of the C abstract machine. Or I guess you could say the return-value object still exists, it's just not assigned anywhere.)


Plus with inline assembly, you don't even have access to that. Unless you count writing a __attribute__((naked)) function where you still write the whole function inside an asm statement, and the compiler doesn't handle anything except the name-mangling of the function name. No prologue or epilogue, or abstracting away the calling convention with C variables for args and one that you return. (/grumble that C compilers can't create functions that return multiple separate values in multiple registers like you can in hand-written asm.)

But even with hand-written asm, there's no way to do this for normal calling conventions on normal ISAs like x86 and ARM. The return-value object for int is just a register.

How does one call a function from it's memory address in AVR C?

The common way to do this is to give the argument the correct type. Then you can call it right away:

void callFunctionAt(void (*address)()) {
address();
}

However, since you wrote "Without changing the header of this function [...]", you need to cast the unsigned integer to a function pointer:

void callFunctionAt(uint32_t address) {
void (*f)() = reinterpret_cast<void (*f)()>(address);
f();
}

But this is not safe and not portabel because it assumes that the uint32_t can be casted into a function pointer. And this needs not to be true: "[...] system-agnostic for all micro controllers [...]". Function pointers can have other widths than 32 bits. Pointers in general might consist of more than the pure address, for example include a selector for memory spaces, depending on the system's architecture.


If you got the address from a linker script, you might have declared it like this:

extern const uint32_t ext_func;

And like to use it so:

callFunctionAt(ext_func);

But you can change the declaration into:

extern void ext_func();

And call it directly or indirectly:

ext_func();

callFunctionAt(&ext_func);

The definition in the linker can stay as it is, because the linker knows nothing about types.

Declare function with memory address

The address 0x22feac looks like any address in normal code address space. But this depends on your environment. It is generally a bad idea to use an address specified by a number literal in your source code.

But there might be an address that you got from outside, such as from the Windows function GetProcAddress. If you are sure you really know what you are doing, then you can assign such a value to a function pointer:

intptr_t functionAddress = 0x22feac;
auto GetVal = reinterpret_cast<int(*)(int)>(functionAddress);

The auto allows you to follow the "Don't repeat yourself" pattern.



Related Topics



Leave a reply



Submit