0

When calling a C++ function, the RAX AND RCX registers are changed. How can I force the compiler to store the value of the registers? I could call push pop, but I plan to call more complex functions and it is important for me that the registers are not corrupted (even for floating point numbers).

Architecture: amd64 IDE: Visual Studio 19

.data
    extern TestCall: proto
.code

HookFunc proc
    mov rax, [rbp + 8h]
    
    call TestCall
    
    ret
HookFunc endp

end
extern "C" void TestCall()
{
    cout << "TestCall" << endl;
}

Disassembler

extern "C" __declspec(dllexport) void TestCall()
{
00007FFAA9C76FB0 40 55                push        rbp  
00007FFAA9C76FB2 57                   push        rdi  
00007FFAA9C76FB3 48 81 EC E8 00 00 00 sub         rsp,0E8h  
00007FFAA9C76FBA 48 8D 6C 24 20       lea         rbp,[rsp+20h]  
00007FFAA9C76FBF 48 8D 0D 70 B0 01 00 lea         rcx,[__ED185583_dllmain@cpp (07FFAA9C92036h)]  
00007FFAA9C76FC6 E8 DD A7 FF FF       call        __CheckForDebuggerJustMyCode (07FFAA9C717A8h)  
    cout << "TestCall" << endl;
00007FFAA9C76FCB 48 8D 15 EE EF 00 00 lea         rdx,[string "TestCall" (07FFAA9C85FC0h)]  
00007FFAA9C76FD2 48 8B 0D 7F 82 01 00 mov         rcx,qword ptr [__imp_std::cout (07FFAA9C8F258h)]  
00007FFAA9C76FD9 E8 FE A0 FF FF       call        std::operator<<<std::char_traits<char> > (07FFAA9C710DCh)  
00007FFAA9C76FDE 48 8D 15 66 A0 FF FF lea         rdx,[std::endl<char,std::char_traits<char> > (07FFAA9C7104Bh)]  
00007FFAA9C76FE5 48 8B C8             mov         rcx,rax  
00007FFAA9C76FE8 FF 15 92 82 01 00    call        qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FFAA9C8F280h)]  
}
00007FFAA9C76FEE 48 8D A5 C8 00 00 00 lea         rsp,[rbp+0C8h]  
00007FFAA9C76FF5 5F                   pop         rdi  
00007FFAA9C76FF6 5D                   pop         rbp  
00007FFAA9C76FF7 C3                   ret  
273K
  • 19,191
  • 8
  • 34
  • 47
Tim
  • 15
  • 2
  • 2
    [Caller/callee saved registers](https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-160#callercallee-saved-registers). You may not force the compiler to store the values of the registers. – 273K Aug 16 '21 at 14:46
  • 1
    Besides the call-clobbered registers, the callee also "owns" 32 bytes above its return address, and can assume 16-byte stack alignment before the `call`. You violate both of those things (so `TestCall` could overwrite your return address), and you're using whatever garbage your caller left in RBP as a pointer. If your caller was compiled with a debug build, that might be its return address, otherwise it might not be a valid pointer at all (if it uses RBP for something else.) – Peter Cordes Aug 16 '21 at 14:59

0 Answers0