To sfx1999.
There is no need to store them in globals; it is slower than simply pushing/popping them, and more cumbersome.
If you store to globals, you have to use each global name (don't use array indexes or speed will be compromised) individually; a specific global set aside for a specific register.
Then you would have to code the assembly:
mov g_rEAX, EAX
mov g_rECX, ECX
mov g_rEDX, EDX
etc.
Then before you execute your translated code, you have to put the registers back:
mov EAX, g_rEAX
mov ECX, g_rECX
mov EDX, g_rEDX
etc.
It’s easier to just do:
PUSH EAX
PUSH ECX
PUSH EDX
…
POP EDX
POP ECX
POP EAX
This is all in regards to storing them to ensure they don’t get overwritten while you are waiting for new code to process.
To answer your question…
Aren't the registers stored when a function is called?
Generally EBP (the function’s local stack pointer) and ESP (the stack pointer) are stored at the start of a function, changed in some way, then restored at the end of the function, back to whatever they were originally.
Meanwhile, other registers will be changing, and those changes last even after the function returns.
Especially functions that return values, in which case EAX will contain the return value (and possibly EDX).
Well, normally you wouldn’t need to worry about this, since it should (in theory) only be the code you are emulating that will change registers, and of course whatever changes it makes, you don’t want to get in the way.
The problem is actually trying to stay out of the way.
You have one thread that sits in a loop and waits for new code to be written.
It checks a simple flag to determine if there is new code.
When the flag is changed, it goes immediately to the location where the new code was written, executes it, and comes back to the loop.
The new code may have stored a value in EAX that is intended for the next instruction (which has yet to be parsed/executed).
There is no second copy of EAX unless you specifically make one (with a global or by PUSH’ing).
So you go back to your loop.
It checks the global. Maybe the code looks like this:
MOV EAX, g_bCodeWritten
TEST EAX, EAX
Well now your loop has changed the same EAX that the emitted code is supposed to be using.
This is why you will definitely be required to write your loop in ASM yourself, so you know exactly what it is changing.
As I mentioned before, you don’t actually have to store backups of the registers at all, if you just write an ASM loop that uses “CMP g_bCodeWritten, 0†directly.
This will avoid changing any registers, so you don’t need to have globals or PUSH/POP.
However, it will change the EFlags, and this will cause a problem.
Registers are not actually the problem.
The thread flags used for conditional jumps now become the problem.
If you don’t understand why, read up on how CMP works in conjunction with JE, JNZ, or whatever conditional jump you like.
Luckily, there is a method for you to get around this problem.
Basically you’re going to have your own EIP pointer which keeps track of where you are in the code, so you know what instruction to translate next.
You load the instruction, translate it, write it in x86, set a flag, your second thread executes it, goes back to its loop, and you continue.
Well, you’re always saving the code to a specific location.
That means you actually can’t write CALL or JMP instructions (or conditional jumps).
Actually, these instructions would be parsed directly, and rather than translating them and executing them, you make the call or jump with your original EIP pointer, then continue from there.
To do this correctly, your original interpreter (with the EIP pointer) will be required to correctly interpret TEST and CMP instructions, and any others that modify EFlags. It will keep its own EFlags value for storing these results (I mean it will have a DWORD m_dwEFlags member; I am not suggesting it uses its real EFlags value in its thread context).
Then when it encounters a JNZ or whatever, it will check its m_dwEFlags to determine if the jump is taken.
If it is, it will need to correctly go to the location where it jumps and continue from there.
Remember that all of this is done without the steps of translating/executing the code.
This part is all interpreted.
I know this seems confusing.
You may want to really read up on ASM and thread context members.
You are going to need to code in ASM and set up a working system (partially in ASM) that allows two threads to communicate frequently and stay synchronized perfectly.
Your EIP thread can’t extract an instruction and write it to be executed while the executing thread is still executing the last bit if code it was passed.
You are also going to have to set up your own storage method to hold the values that the emulated code will be using.
The emulated code may try to access 0x003800EC, which quite likely won’t be a valid address in your program.
So you are going to create a method of mapping memory back and forth from the real location in your program to the respective location in the emulated code.
This part SHOULD be nothing more than a simple offset. Depends on what you are emulating.
L. Spiro