Does ‘return’ come back?

We all know that call invokes a function and ret returns to the caller. Alas, nothing is certain in the binary world. The ret instruction is quite often used for short jumps within a function. Among many other improvements in IDA v5.1 there will be a special logic to recognize and mark such pseudo-returns. I was surprised to see this graph and post it here for your amusement:

Please note the underlined ret and be prepared for unusual cross-references in your scripts :)

12 thoughts on “Does ‘return’ come back?”

  1. This example is flow-sensitive, though: what does IDA do if the path leading to the node consisting of a single jump pushes a different return-to address onto the stack? Does it aggregate them into multiple outgoing edges from the “returning” block?
    Anyway, keep up the good work.

  2. No, currently it does not aggregate them. If this becomes an issue in the future, we will add multiple xrefs…

  3. In fact, there are some Binary code obsfucators have been using this kind of trick to fool IDA and prevent manual analysis:
    .text:00010EB5 mov [esp+8], eax
    .text:00010EB9 push ecx
    .text:00010EBA mov eax, [esp]
    .text:00010EBD mov [esp+8], eax ; DATA XREF: .text:00010AF2o
    .text:00010EE8 retn
    So I think maybe multi code xref or data xref should be added to ret.Additionaly I think IDA could try to backtrace the stack top to automatic resolve some these tricks.
    There aren’t any GUI command to add data xref or code xref in IDA now.Maybe it’s better to expose them to the user than SDK/script only.When I use the SDK function to add code xref IDA wouldn’t add automatic comments to some indirect jump or call such as call [edx], I had to add the comment manually, would IDA support automatic comments to manual added xrefs in 5.1?
    Additionaly more and more obsfucators using unconditonal jump such as:
    .text:00011276 push eax
    .text:00011277 push [esp+0Ch+var_C]
    .text:0001127A mov eax, [esp+0]
    .text:0001127D mov [esp+10h+var_C], eax
    .text:00011281 jmp loc_11332
    loc_11332: ; CODE XREF: sub_11276+Bo
    .text:00011208 push edi
    .text:00011209 mov eax, esp
    .text:0001120B jmp loc_113FB
    to split one node into mutiple nodes, maybe IDA graph could reassemble them together when the jump target is one-indegree node.
    I think these kind of trick would be used in more and more software to protect themselves from being analyzed within one or two years.

  4. I assume people only use ret in this way to obfuscate their code?
    This trick wreaks havoc with the CPU’s call stack predictor and make all subsequent rets stall the pipeline!

  5. Alas, this is a standard trick. Borland’s Delphi routinely uses it in all applications.
    To tell the truth we do not try to fight against code obfuscation in IDA. There are unlimited number of potential obfuscation methods. Implementing something limited but practical would mean that a slightly new method would render the existing defenses useless and require constant modification and improvement of the analysis methods. Antivirus companies address this by creating virus signatures and updating them real time. We have to note that their task is simpler in a sense: given a new obfuscation method, flag the executable as suspicious and inform the user. IDA can not do that, you guys always want to have more information 😉
    A much better approach is to write small plugins to handle obfuscated code. Be it random jumps, useless computations, or something else, it is much easier to attack one particular obfuscation method than try to write a generic plugin.

  6. hume,
    You can add xrefs from the user interface, no need to write a plugin or script. For that, open the xrefs window and press Ins.
    Writing a script is really easy. Here is an oneliner:
    AddCodeXref(here, there, fl_CF|XREF_USER);
    would add an xref from here to there.
    If you want IDA to support a new feature, please send your suggestions to Datarescue (with your key file). I don’t promise that we will implement everything you ask but will consider your suggestions. Thanks.

  7. Thanks for your quick reply.Sorry for missing xrefs window from the manual,
    what I mean is:
    AddCodeXref(here, 0x00766FC0, fl_CN | XREF_USER);
    007F9BB5 mov eax, 7BEAB0h
    007F9BBA sub eax, 540h
    007F9BBF mov edx, 7852F52Ah
    007F9BC4 mov ecx, [ebp+keya]
    007F9BC7 call eax ; calc_keya00_2 ; CODE XREF: 007BE570 -> calc_keya00_2
    007F9BC9 neg eax
    007F9BCB add eax, 5A64E6B6h
    007F9BD0 mov edx, 91960538h
    007F9BD5 mov ecx, [ebp+keya]
    007F9BD8 call eax ; CODE XREF: 007497B0 -> calc_keya19_0
    007F9BDA neg eax
    007F9BDC add eax, 1480AA14h
    007F9BE1 mov dword ptr [ebp+var_24+4], eax
    007F9BE4 mov edx, [esi+20h]
    007F9BE7 mov ecx, esi
    007F9BE9 here:
    007F9BE9 call dword ptr [ebp+var_24+4]
    while the callee function at 0x00766FC0 will display xref relations correctly:
    00766FC0 ; Attributes: bp-based frame
    00766FC0 scramble_seed2_0x01_0x03 proc near ; CODE XREF: scramble_seed2_0x03_0:here>p
    although I added the xref to 00766FC0, but from the caller position I can’t see any xrefs in GUI, it’s rather boring sometimes:
    007F9BE9 here:
    007F9BE9 call dword ptr [ebp+var_24+4]
    if automatic comments is added by default, I know there is a xref there and I can jump to callee, it would be convinience most times, example is:
    0076706E 03C FF D0 call eax ; calc_keya00_6
    of course the repeatable comment work perfectly, so It would not be a big question for me. now I write a small plugin to do the dirty work to add comment such as:
    007F9BD8 call eax ; CODE XREF: 007497B0 -> calc_keya19_0
    hope to see 5.1 coming soon.

  8. While you’re in there messing with exit paths…
    I’d love to see IDA recognize other function terminators. On Windows, for example:
    I frequently see these preventing IDA from being able to tag a chunk of code as a function.
    Might be nice if I could tag a called function as “will never come back, terminates this function”.

  9. It is automatic, no need to activate anything. Take a function ending with ExitProcess and you will see that IDA sets the ‘noreturn’ attribute for it. The attribute is visible in the function header like this:

    ; Attributes: library function noreturn bp-based frame
    ; int __cdecl _terminate(UINT uExitCode)
    __terminate     proc near
    uExitCode       = dword ptr  8
    push    ebp
    mov     ebp, esp
    mov     eax, [ebp+uExitCode]
    push    eax
    call    ExitProcess
    __terminate     endp

    You yourself can change this attribute for any function using the “Edit function” command.

Comments are closed.