Skip to main content
GameDev.net gamedev.net
🔒 Locked

Force compiler/linker to use relative addressing

Started by XTAL256 Sep 22, 2010 at 8:08 PM 17 replies 4.9k views
Original Post
XTAL256
XTAL256
Background info: I'm using C++ and Visual Studio 2008.

My program (Window Detective) injects code into remote processes. This code works fine in debug but crashes in release mode. I think it is because the generated assembly uses absolute addresses for function calls, which will not work in a remote process.

// Code snippet from release build01C30013  push        edi  01C30014  push        43CFDCh 01C30019  call        dword ptr ds:[43B050h] 01C3001F  mov         edi,dword ptr [esp+20h] 01C30023  lea         ebp,[edi+54h] 01C30026  push        ebp  01C30027  mov         ebx,eax 01C30029  call        dword ptr ds:[43B148h] // Code snippet from debug build00411036  mov         eax,dword ptr [inj] 00411039  add         eax,0Ch 0041103C  push        eax  0041103D  mov         ecx,dword ptr [inj] 00411040  mov         edx,dword ptr [ecx] 00411042  call        edx  00411044  mov         dword ptr [dll],eax 00411047  cmp         dword ptr [dll],0 


Assuming that this is indeed the cause of the crashing, is there any way i can force the compiler to use relative addressing? More specifically, i want a #pragma switch rather than a compiler or linker option. That way i can use this option only for the function that will be injected into the remote thread.
[Window Detective] - Windows UI spy utility for programmers
XTAL256
XTAL256
I tried turning off all optimisations:
#pragma optimise("", off)static DWORD WINAPI RemoteFunction(...) {    ...}#pragma optimise("", on)


It seemed to work, there was no crash and the asm did not refer to absolute addresses. I cannot say for sure, though, as i am not very fluent in assembly.
[Window Detective] - Windows UI spy utility for programmers
Nypyren
Nypyren
I'm not sure you'd be able to trust that. For example if you use a switch statement it probably will still use an absolute-addressed jump table.

If I remember correctly, everything compiled into a DLL will use relative addressing. When I inject code, I get the most reliable results from the VirtualAllocEx -> WriteProcessMemory -> CreateRemoteThread -> LoadLibrary approach.
outRider
outRider
I haven't messed with Windows in a long time, but is your code in a DLL? If so, it should be relocated when it's loaded by other processes, which means all your absolute calls will be fixed up to jump to the right places. As far as I remember Windows doesn't do relative calls (PIC).
XTAL256
XTAL256
Quote:
Original post by Nypyren
I'm not sure you'd be able to trust that. For example if you use a switch statement it probably will still use an absolute-addressed jump table.

I know about the switch problem, it (and a few other caveats) are mentioned here.
My remote function does not use any switch statements, all it does it calls another function in an already loaded DLL.

And, no, that remote function is not in a DLL. I posted about it not long ago, here, if you want to know.

Ok, so assuming that i am not using any switch statements or anything else like that, can i trust the #pragma optimise?

Here is the code for the function to inject:
/*------------------------------------------------------------------+| This function is injected into a remote process and is            || responsible for calling the desired function in the hook dll.     || Assumes that the hook dll is already loaded in the remote process |+------------------------------------------------------------------*/#pragma check_stack(off)#pragma optimize("", off)static DWORD WINAPI RemoteFunctionDelegate(InjectionData* inj) {	HMODULE dll = inj->fnGetModuleHandle(inj->moduleName);    if (!dll) {        inj->result = inj->fnGetLastError();        // Not sure if the return value can be retrieved from the remote        // thread, so just store it in the struct and return 0 here        return 0;    }	    // Get the address of the function to call	RemoteProc func = (RemoteProc)inj->fnGetProcAddress(dll, inj->funcName);	if (!func) {        inj->result = inj->fnGetLastError();        return 0;    }	    // Call the function passing the data (which is at the end of the    // injection struct) and the size of the data    void* dataAddr = (void*)((char*)inj + sizeof(InjectionData));    inj->result = func(dataAddr, inj->dataSize);    return 0;}#pragma optimize("", on)#pragma check_stack(on)
[Window Detective] - Windows UI spy utility for programmers
cache_hit
cache_hit
Quote:
Original post by XTAL256
Background info: I'm using C++ and Visual Studio 2008.

My program (Window Detective) injects code into remote processes. This code works fine in debug but crashes in release mode. I think it is because the generated assembly uses absolute addresses for function calls, which will not work in a remote process.

*** Source Snippet Removed ***

Assuming that this is indeed the cause of the crashing, is there any way i can force the compiler to use relative addressing? More specifically, i want a #pragma switch rather than a compiler or linker option. That way i can use this option only for the function that will be injected into the remote thread.



Using absolute addresses won't work in any process if you have a DLL, not just a remote process. There's another force at work here, and I don't think it has anything to do with a linker setting or relative / absolute addressing. From your point of view, it shouldn't matter that it's executing in a remote process. Either way you just end up with a DLL loaded in a process, same as any. In any case, NOTHING will work in a dll with absolute addressing, because the DLL can be loaded in memory anywhere. By definition, absolute addressing is totally incomaptible with DLLs.


Why is that function static? Is it a member of a class? If not, that could be your problem. Functions which are static at the file scope can have various types of compiler optimizations performed on them that are not possible otherwise.

Also, why do you have a pointer to the GetModuleHandle() function? Just call it directly, GetModuleHandle(inj->moduleName)

[Edited by - cache_hit on September 23, 2010 2:02:41 AM]
XTAL256
XTAL256
I don't think you understand what i am doing. Did you read the page i linked to? I am using the "CreateRemoteThread & WriteProcessMemory Technique"
[Window Detective] - Windows UI spy utility for programmers
outRider
outRider
Quote:
Original post by XTAL256
I don't think you understand what i am doing. Did you read the page i linked to? I am using the "CreateRemoteThread & WriteProcessMemory Technique"


You're actually copying instructions into the other process' memory? No wonder you have problems. Did you read the caveats mentioned by the page you linked to? You can't call arbitrary functions because the function you're injecting doesn't go through relocation, which I explained previously. The compiler will not generate relative calls because IIRC 32-bit Windows doesn't support position independent code (PIC), only relocations (however 64-bit does). If you want your code to be relocated make sure it's actually loaded by the process you're injecting into.
Yann L
Yann L
Quote:
Original post by XTAL256
Ok, so assuming that i am not using any switch statements or anything else like that, can i trust the #pragma optimise?

No, you can't.

You would be relying on a sideeffect of that pragma, an arbitrary artifact. The pragma controls optimization, not addressing mode. The fact that it seems to work for your case is pure luck. It could stop functioning with any VS service pack or new VS version.
Promit
Promit
Quote:
Original post by Yann L
Quote:
Original post by XTAL256
Ok, so assuming that i am not using any switch statements or anything else like that, can i trust the #pragma optimise?

No, you can't.

You would be relying on a sideeffect of that pragma, an arbitrary artifact. The pragma controls optimization, not addressing mode. The fact that it seems to work for your case is pure luck. It could stop functioning with any VS service pack or new VS version.
Or code change, or code rearrangement, or recompile.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
XTAL256
XTAL256
Quote:
Original post by outRider
Did you read the caveats mentioned by the page you linked to?

Did you read my post?
Quote:
Original post by XTAL256
I know about the switch problem, it (and a few other caveats) are mentioned here.


@Yann L and Promit: Ok, so is there any way i can do this? I did have it working at one stage (in both debug and release), in my previous release of Window Detective. You can download the source here, look at the file "inspector/RemoteFunctions.cpp".
I didn't see what assembly was generated by that release, but it didn't crash so i assume it was using relative addressing.

EDIT: Perhaps i could just write the function in assembly.
[Window Detective] - Windows UI spy utility for programmers
outRider
outRider
Quote:
Original post by XTAL256
Quote:
Original post by outRider
Did you read the caveats mentioned by the page you linked to?

Did you read my post?


I read your original post. My apologies. The fact that it worked before is irrelevent, you could have gotten lucky. If your injected function is calling functions from a particular DLL that DLL might be loaded at the same base in both your process and the target process, thereby making your absolute calls correct in both runtime contexts, but that can change at the drop of a hat.

Even if you write your function in assembly, you need to know the absolute address of the function you want to call in the process you're injecting your code into.
cache_hit
cache_hit
I feel like this is being way overcomplicated. Injecting code into running processes is not that hard, and considerations such as absolute / relative addressing are completely not a factor in the equation if done correctly. Once your DLL is loaded into the process's address space, you can just write code the same way you always would. Just like it's any other DLL running in your own process. Set up some IPC mechanism such as a mutex/shared memory, or a named pipe to communicate back and forth to your main Window Detective application.

Maybe there's some miscommunication / misunderstanding going on, but I really don't see why we're now talking about writing in assembly language to control the addressing mode of generated code. We need to take a step back and figure out how we got to this point because something has gone terribly wrong if you feel this is warranted just to get code injected into a remote process.
XTAL256
XTAL256
Firstly, I should apologise for my incorrect usage of the term "relative addressing".
What i mean was that the generated release assembly was using call instructions like this (where i assume 43B148h is a function address):
call dword ptr ds:[43B148h]

But the debug assembly was correctly using the function address that is either loaded or passed into the remote function:
call edx

This is not relative addressing but it is not absolute addressing, i should have been more clear about that. My bad.

Now...

@adeyblue: Thanks for the tip. According to MSDN, the function to get WNDCLASSEX can only be called from the process that owns the window. It looks like GetClassLongPtr can be called from any process, so i might use that instead.
I will still need the code injection to get other window data that can only be retrieved by that window's process (things like GDI objects).
[Window Detective] - Windows UI spy utility for programmers
elFarto
elFarto
Quote:
Original post by XTAL256
Firstly, I should apologise for my incorrect usage of the term "relative addressing".
What i mean was that the generated release assembly was using call instructions like this (where i assume 43B148h is a function address):
call dword ptr ds:[43B148h]

But the debug assembly was correctly using the function address that is either loaded or passed into the remote function:
call edx

This is not relative addressing but it is not absolute addressing, i should have been more clear about that. My bad.

I believe it is referred to as an indirect call (the call edx version) and direct call (the call dword version).

Regards
elFarto
outRider
outRider
Quote:
Original post by cache_hit
I feel like this is being way overcomplicated. Injecting code into running processes is not that hard, and considerations such as absolute / relative addressing are completely not a factor in the equation if done correctly. Once your DLL is loaded into the process's address space, you can just write code the same way you always would. Just like it's any other DLL running in your own process. Set up some IPC mechanism such as a mutex/shared memory, or a named pipe to communicate back and forth to your main Window Detective application.

Maybe there's some miscommunication / misunderstanding going on, but I really don't see why we're now talking about writing in assembly language to control the addressing mode of generated code. We need to take a step back and figure out how we got to this point because something has gone terribly wrong if you feel this is warranted just to get code injected into a remote process.


It's simple, his DLL is not being loaded into the target process' address space, instead he's allocating memory in the target address space and copying a function into that memory. Said function has only been loaded in and patched for his process, not the target.
outRider
outRider
Quote:
Original post by XTAL256
Firstly, I should apologise for my incorrect usage of the term "relative addressing".
What i mean was that the generated release assembly was using call instructions like this (where i assume 43B148h is a function address):
call dword ptr ds:[43B148h]

But the debug assembly was correctly using the function address that is either loaded or passed into the remote function:
call edx

This is not relative addressing but it is not absolute addressing, i should have been more clear about that. My bad.


You have a much simpler problem then. I guess I should have looked closely at your disassembly too. Define the function that's being injected in a seperate compilation unit than the code setting up the inj struct and disable whole-program optimization. That will prevent the compiler from optimizing the indirect call to into a direct one.

Although, you still have to make sure that at runtime the inj struct contains the address of the function you want to call as it is in the target process. Presumably you're filling this struct in your process and writing it into the other process' address space, so the address of the function you want to call from your injected function is really only correct in your process, if the other process loads the same DLL at a different base the address will still be incorrect. If this is one of the Windows DLLs then you're relying on it being loaded into the same place in every process you want to spy on for this whole scheme to work. I have no idea how strong a guarantee that is in theory or practice. Maybe there's a way to get the address of a function in an arbitrary method that you should dig around for?
cache_hit
cache_hit
Quote:
Original post by outRider
Quote:
Original post by cache_hit
I feel like this is being way overcomplicated. Injecting code into running processes is not that hard, and considerations such as absolute / relative addressing are completely not a factor in the equation if done correctly. Once your DLL is loaded into the process's address space, you can just write code the same way you always would. Just like it's any other DLL running in your own process. Set up some IPC mechanism such as a mutex/shared memory, or a named pipe to communicate back and forth to your main Window Detective application.

Maybe there's some miscommunication / misunderstanding going on, but I really don't see why we're now talking about writing in assembly language to control the addressing mode of generated code. We need to take a step back and figure out how we got to this point because something has gone terribly wrong if you feel this is warranted just to get code injected into a remote process.


It's simple, his DLL is not being loaded into the target process' address space, instead he's allocating memory in the target address space and copying a function into that memory. Said function has only been loaded in and patched for his process, not the target.


No I know, my point is why not just inject a DLL into the process? All of this business just disappears then, and aside from it maybe being slightly easier to detect the presence of an external tool spying on the application, I don't see any downsides. Just much simpler code, much clearer method.


BTW your other suggestion about moving into a separate compilation is related to my original suggestion much earlier about removing the static keyword, as they give the compiler the ability to perform almost the same optimization. I never got an answer about that, but either way I still think the static keyword needs to be gone.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.