Getting The Size of a C++ Function

2019-01-15 12:32发布

I was reading this question because I'm trying to find the size of a function in a C++ program, It is hinted at that there may be a way that is platform specific. My targeted platform is windows

The method I currently have in my head is the following:
1. Obtain a pointer to the function
2. Increment the Pointer (& counter) until I reach the machine code value for ret
3. The counter will be the size of the function?

Edit1: To clarify what I mean by 'size' I mean the number of bytes (machine code) that make up the function.
Edit2: There have been a few comments asking why or what do I plan to do with this. The honest answer is I have no intention, and I can't really see the benefits of knowing a functions length pre-compile time. (although I'm sure there are some)

This seems like a valid method to me, will this work?

15条回答
Explosion°爆炸
2楼-- · 2019-01-15 12:48

Using GCC, not so hard at all.

void do_something(void) { 
   printf("%s!", "Hello your name is Cemetech"); 
   do_something_END: 
} 

... 

   printf("size of function do_something: %i", (int)(&&do_something_END - (int)do_something));
查看更多
混吃等死
3楼-- · 2019-01-15 12:49

This can work in very limited scenarios. I use it in part of a code injection utility I wrote. I don't remember where I found the information, but I have the following (C++ in VS2005):

#pragma runtime_checks("", off)

static DWORD WINAPI InjectionProc(LPVOID lpvParameter)
{
    // do something
    return 0;
}

static DWORD WINAPI InjectionProcEnd()
{
    return 0;
}

#pragma runtime_checks("", on)

And then in some other function I have:

size_t cbInjectionProc = (size_t)InjectionProcEnd - (size_t)InjectionProc;

You have to turn off some optimizations and declare the functions as static to get this to work; I don't recall the specifics. I don't know if this is an exact byte count, but it is close enough. The size is only that of the immediate function; it doesn't include any other functions that may be called by that function. Aside from extreme edge cases like this, "the size of a function" is meaningless and useless.

查看更多
来,给爷笑一个
4楼-- · 2019-01-15 12:53

I think it will work on windows programs created with msvc, as for branches the 'ret' seems to always come at the end (even if there are branches that return early it does a jne to go the end). However you will need some kind of disassembler library to figure the current opcode length as they are variable length for x86. If you don't do this you'll run into false positives.

I would not be surprised if there are cases this doesn't catch.

查看更多
你好瞎i
5楼-- · 2019-01-15 12:55

This won't work... what if there's a jump, a dummy ret, and then the target of the jump? Your code will be fooled.

In general, it's impossible to do this with 100% accuracy because you have to predict all code paths, which is like solving the halting problem. You can get "pretty good" accuracy if you implement your own disassembler, but no solution will be nearly as easy as you imagine.

A "trick" would be to find out which function's code is after the function that you're looking for, which would give pretty good results assuming certain (dangerous) assumptions. But then you'd have to know what function comes after your function, which, after optimizations, is pretty hard to figure out.


Edit 1:

What if the function doesn't even end with a ret instruction at all? It could very well just jmp back to its caller (though it's unlikely).


Edit 2:

Don't forget that x86, at least, has variable-length instructions...


Update:

For those saying that flow analysis isn't the same as solving the halting problem:

Consider what happens when you have code like:

foo:
    ....
    jmp foo

You will have to follow the jump each time to figure out the end of the function, and you cannot ignore it past the first time because you don't know whether or not you're dealing with self-modifying code. (You could have inline assembly in your C++ code that modifies itself, for instance.) It could very well extend to some other place of memory, so your analyzer will (or should) end in an infinite loop, unless you tolerate false negatives.

Isn't that like the halting problem?

查看更多
Luminary・发光体
6楼-- · 2019-01-15 12:55

Just set PAGE_EXECUTE_READWRITE at the address where you got your function. Then read every byte. When you got byte "0xCC" it means that the end of function is actual_reading_address - 1.

查看更多
混吃等死
7楼-- · 2019-01-15 12:55

below code the get the accurate function block size, it works fine with my test runtime_checks disable _RTC_CheckEsp in debug mode

    #pragma runtime_checks("", off)
DWORD __stdcall loadDll(char* pDllFullPath)
{  
    OutputDebugStringA(pDllFullPath);
    //OutputDebugStringA("loadDll...................\r\n");
    return 0;
    //return test(pDllFullPath);
}
#pragma runtime_checks("", restore)

DWORD __stdcall getFuncSize_loadDll()
{
    DWORD maxSize=(PBYTE)getFuncSize_loadDll-(PBYTE)loadDll;
    PBYTE pTail=(PBYTE)getFuncSize_loadDll-1;
    while(*pTail != 0xC2 && *pTail != 0xC3) --pTail;
    if (*pTail==0xC2)
    {   //0xC3          : ret
        //0xC2 04 00    : ret 4
        pTail +=3;
    }

    return pTail-(PBYTE)loadDll;
};
查看更多
登录 后发表回答