Don’t trust the return address

Date:January 1, 2004 / year-entry #1
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20040101-00/?p=41223
Comments:    17
Summary:Sometimes people ask, "So I know how to get my return address [use the _ReturnAddress() intrinsic]; how do I figure out what DLL that return address belongs to?" Beware. Even if you figure out which DLL the return address belongs to [use Get­Module­Handle­Ex(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)], that doesn't mean that that is actually the DLL that called you....

Sometimes people ask, "So I know how to get my return address [use the _ReturnAddress() intrinsic]; how do I figure out what DLL that return address belongs to?"

Beware.

Even if you figure out which DLL the return address belongs to [use Get­Module­Handle­Ex(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)], that doesn't mean that that is actually the DLL that called you.

A common trick is to search through a "trusted" DLL for some code bytes that coincidentally match ones you (the attacker) want to execute. This can be something as simple as a "retd" instruction, which are quite abundant. The attacker then builds a stack frame that looks like this, for, say, a function that takes two parameters.

trusted_retd
hacked parameter 1
hacked parameter 2
hacker_code_addr

After building this stack frame, the attacker then jumps to the start of the function being attacked.

The function being attacked looks at the return address and sees trusted_retd, which resides in a trusted DLL. It then foolishly trusts the caller and allows some unsafe operation to occur, using hacked parameters 1 and 2. The function being attacked then does a "retd 8" to return and clean the parameters. This transfers control to the trusted_retd, which performs a simple retd, which now gives control to the hacker_code_addr, and the hacker can use the result to continue his nefarious work.

This is why you should be concerned if somebody says, "This code verifies that its caller is trusted..." How do they know who the caller really is?


Comments (17)
  1. ep says:

    So is there a way to verify that my caller is trusted and allows some operations?

  2. Peter Torr says:

    Well, in .NET you have IPermission.Demand() to see if all your callers have the right permissions, or SecurityAction.LinkDemand if you just want to check your immediate caller (which is generally a really bad idea — avoid using LinkDemands to enforce security; they’re better suited to improving API usability).

  3. Phaeron says:

    There are other reasons why the return address shouldn’t be used to determine the caller: the source may be a dynamically generated code fragment, and the call to the DLL function may be a tail call (jmp dword ptr [__imp__DefWindowProc@16]).

    Incidentally, what is the "sanctioned" method of emulating GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) on pre-XP platforms? The only way I know of is to VirtualQuery() the address and case the AllocationBase to HMODULE.

  4. Raymond Chen says:

    zz: It looks like they focused on my phrase "You dummy". I didn’t mean it to be as insulting to the user as it turned out. I should have written "Psst" instead, but what’s done is done.

  5. Steve Sheppard says:

    No, you did the right thing. You wrote what you meant, they CHOSE to be insulted by it. Don’t play the PC game by trying to guess what they will insulted by because the answer is eveything. Anyone who reads your blog regularly knows what you mean and to hell with idiots like that guy.

    Keep up the good work!

  6. Peter Lund/firefly@diku.dk says:

    why would anyone try to get the return address?

  7. Raymond Chen says:

    Because they want to do things "only if their caller is trusted".

  8. Peter Lund/firefly@diku.dk says:

    But, but… that *really* makes no sense :)

    Reminds me of the Poly/Turbo/Borland Pascal programmers I’ve met who wanted an "exit2" pseudo procedure that would leave not just one but /two/ procedures.

    (exit is like return in C without an argument, Pascal can have nested functions unlike C (but like gcc))

    I thought at least *somebody* had had a real need for it?

  9. Recently on Raymond Chens blog he had a post about not trusting return addresses. Specifically to not use the _ReturnAddress() intrinsic and GetModuleHandleEx to figure out if the caller is trusted. I had to try and come up with a…

  10. Because there sometimes isn’t enough information to determine what the "right" order is.

  11. Counterintuitive results from the file search.

  12. Thanks to code injection.

  13. No really, you can’t.

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index