Function references stack address outside its context

Тема в разделе "WASM.ASSEMBLER", создана пользователем Eleanor, 17 сен 2017.

  1. Eleanor

    Eleanor New Member

    Публикаций:
    0
    Регистрация:
    17 сен 2017
    Сообщения:
    3
    I'm trying to understand what calling convention the following function uses:

    [​IMG]
    [​IMG]

    I realize it says fastcall, but that is not actually the case, since the ECX register contains an integer (the first parameter) like 0x2190. However, the weird issue is the following instruction:

    lea rcx, [rsp + 48h]

    The instruction references an address outside of the current stack frame. The current stack frame uses only 8 bytes (RIP stored on stack on account to call), 8 bytes (for push RBX), 30 bytes (for sub rsp, 30h) - however 0x48 is out of these bounds.

    Basically I would like to hook this callback function, since the function is called when an event occurs, but easyhook (and I guess a lot of other libraries) have a hard time dealing with this , which is not under control of the current function.

    Any ideas how the [rsp + 48h] is actually passed to the function, since the fastcall calling convention is used by the function, where only an integer is passed in rcx parameter?
     
    yashechka нравится это.
  2. comrade

    comrade Константин Ёпрст

    Публикаций:
    0
    Регистрация:
    16 сен 2002
    Сообщения:
    232
    Адрес:
    Russian Federation
    This is a good question.

    Win64 fastcall mandates that the caller allocate space for four arguments (32 bytes) prior to invoking a function. That means, in your context, routine invoke_callback, at its very first instruction (push rbx) can consider [rsp, rsp+20h) a valid range. It then allocates an additional 30h bytes from the stack, making the total valid range [rsp, rsp+50h). Thus, "lea ecx, rsp+48h" is valid since it spans [rsp+48h, rsp+4Fh].

    If you read more about this on the Internet, you will read that other OSes have a 128-byte pre-allocated redzone that routines may consider valid. Apparently, Win64 does not abide by this rule..

    References:
    1. https://stackoverflow.com/questions...calling-convention-from-all-other-oses-on-x86
    2. http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/
     
    yashechka нравится это.
  3. Eleanor

    Eleanor New Member

    Публикаций:
    0
    Регистрация:
    17 сен 2017
    Сообщения:
    3
    This is actually not true, the caller (when calling a __fastcall calling convention) doesn't allocate space for 4 arguments, but instead sends them in the following registers:

    - RCX
    - RDX
    - R8
    - R9

    Therefore, if there are at most 4 parameters, no additional space is allocated on the stack. In our case there is only a single parameter, which is sent in ECX! This does NOT
    explain the "lea ecx, rsp+48h" instruction, since the function's valid range spans [rsp, rsp+0x38] (the next on the stack is RIP at 0x40). Also the function is invoked as follows:

    loc_180175426:
    mov rax, [rdi+38h]
    mov ecx, [rax] ; int
    call ?invoke_callback@@YA_NH@Z ; invoke_callback(int)
    nop

    Only the integer is read into RCX register, which is passed to the function, nothing else is going on before the function call.
     
    yashechka нравится это.
  4. comrade

    comrade Константин Ёпрст

    Публикаций:
    0
    Регистрация:
    16 сен 2002
    Сообщения:
    232
    Адрес:
    Russian Federation
    rsp+48 is used as an output parameter, not input.

    If there are at most 4 parameters, or less, still, 32 bytes are allocated on the stack - read the ABI specification.
     
    yashechka нравится это.
  5. Eleanor

    Eleanor New Member

    Публикаций:
    0
    Регистрация:
    17 сен 2017
    Сообщения:
    3
    Sorry, but this isn't true. Do you see any stack allocation prior to the function being called, there isn't. However, it's possible that your ABI specification states that, but the program doesn't use/follow it.
     
  6. njeen

    njeen Active Member

    Публикаций:
    0
    Регистрация:
    26 мар 2017
    Сообщения:
    138
    Адрес:
    Ташлинск
    in MS x64 calling convention any unused space from 32 bit 'Shadow area' can be used by callee function for it's own purposes, like in your code
     
  7. comrade

    comrade Константин Ёпрст

    Публикаций:
    0
    Регистрация:
    16 сен 2002
    Сообщения:
    232
    Адрес:
    Russian Federation
    Correct, you will not see it because it is the burden of the caller (whoever calls invoke_callback) to maintain the scratch space. You do see a stack allocation of 30h bytes, which, with the addition of the 20h bytes already implicitly allocated by the caller, gives the invoke_callback routine a total of 50h bytes of usable stack space.

    You will need to scan back further - it is possible (and completely valid) that the caller you referenced is simply reusing the 20h bytes of scratch space that were allocated for it prior (caller of caller, caller of caller of caller, etc).

    I cited the ABI specification from Microsoft and AMD. It is not my own opinion or interpretation.

    The region [rsp+48h, rsp+4Fh] likely backs a stack-local instance of the MyClass::UString object. It is easy to imagine that this requires exactly 16 bytes: 8 bytes for the pointer to the base of the dynamically allocated string, and another 8 bytes to encode its length.

    You are welcome to entertain other explanations or interpretations of what you see. However, I see no other responses on this forum thread, or any wildly divergent out on the web.

    Модераторы: закройте топик при дальнейшей дегенерации обсуждения.