7

I'm trying to get the function address to copy its content into a buffer using memcpy.

The problem I'm having is with getting function address. Here is my code:

__declspec(noinline) int gio()
{
    const char yle[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
    return 7;
}

int main(int argc, TCHAR* argv[])
{
    int(*funcptr)() = gio;
    unsigned char *p = (unsigned char *)&funcptr;
    size_t ik;

    for (ik = 0; ik < sizeof funcptr; ik++)
    {
        printf("%02x ", p[ik]);
    }
    putchar('\n');

    printf("gio x -> %x\n", gio);
    printf("gio p -> %p\n", gio);
}

I created a little test program where I try to print function address with different ways.

I'm using Visual Studio and had turn off the optimization and inline function expansion(but used noinline anyway). all the print statements print same output(0x00d213ca screenshot) but when I put my cursor(inside VS) on gio function it shows totally different address(0x00d218c0 screenshot).

When I right click on gio function and Go To Dissasembler I jump to the address which was shown when I put my cursor on it(0x00d218c0 screenshot). Which clearly shows where this function really is.

I got little confused here, seems like I don't understand something.

Why do print statements show incorrect value? What is the way to get the "real" function address?

Ojs
  • 924
  • 1
  • 12
  • 26
  • 2
    I think the question like this appeared just recently. Without optimizations function is invoked through dispatch table which jumps into function body. Function pointers store dispatch table entry addresses while debugger may show function body address. – user7860670 Feb 24 '18 at 20:09
  • 3
    @IInspectable And this address is used to print function address bytes. *"I try to print function address with different ways"* – user7860670 Feb 24 '18 at 20:12
  • so how do I get actual address? – Ojs Feb 24 '18 at 20:15
  • @IInspectable printf("gio p -> %p\n", gio); << but where is a variable here? – Zhani Baramidze Feb 24 '18 at 20:16
  • The difference isn’t that many bytes. Could it be headers or preamble? – Pam Feb 24 '18 at 20:17
  • 1
    @ZhaniBaramidze: A function pointer is not required to be the same size as a data pointer. `printf` format specifier `%p` is for data pointers only. – Ben Voigt Feb 24 '18 at 20:18
  • Probably you should inspect dispatch table entry to figure out where it jumps. All the table entries seems to contain just a single `jmp` instruction. – user7860670 Feb 24 '18 at 20:19
  • 1
    Could you please provide some information where I can read about dispatch tables? – Ojs Feb 24 '18 at 20:30
  • Which version of visual studio are you using? I CND with VS2017 (all 3 address displays match). – 1201ProgramAlarm Feb 24 '18 at 21:26
  • task not have general solution. `gio` can containing real pointer to function bytes. but can containing pointer to `jmp gio` instruction. also function code, with some optimization can be not continuous in memory – RbMm Feb 24 '18 at 23:48
  • also *to copy its content into a buffer* - function code must be base in depended. but `const char yle[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";` already base depended instruction in *x64* - you can not copy such function – RbMm Feb 24 '18 at 23:52

1 Answers1

5

Visual Studio "lies" to you here. When you print either funcptr or gio you see the actual address, that is the address you jump to when writing

gio() // or funcptr()

With Incremental Linking enabled this value is different from what Visual Studio tells you when you hover over gio because of thunking, see /INCREMENTAL.

May contain jump thunks to handle relocation of functions to new addresses.

To figure out the address of your code you can either disable Incremental Linking or
use the DIA SDK:

// initialize DIA SDK, etc.

void (*fp)() = &foo;
printf("foo(): %p\n\n", foo);

HMODULE hModule = GetModuleHandle(NULL);
DWORD rva = (DWORD)((size_t)fp - (size_t)hModule);

IDiaSymbol *pDiaSymbol;
hr = pDiaSession->findSymbolByRVA(rva, SymTagPublicSymbol, &pDiaSymbol);
if(FAILED(hr) || !pDiaSymbol)
    return hr;

ULONGLONG targetVA;
hr = pDiaSymbol->get_targetVirtualAddress(&targetVA);
pDiaSymbol->Release();

if(FAILED(hr))
    return hr;

if(hr == S_OK)
    printf("foo is a thunk, actual address: %p\n\n", (LPVOID)((size_t)hModule + targetVA));

But there might be a simpler way that I'm not aware of.

Axalo
  • 2,953
  • 4
  • 25
  • 39