Question: Given what you learned about CALL and RET, explain how you would read the value of EIP? Why can't you just do MOV EAX, EIP?
Answer: The easiest way I could think of to read the current value of EIP was to do the following:
CALL *instruction after this call instruction* <- 5 Bytes
POP EAX <- 1 Byte (the instruction that we will point to)
ADD EAX, 4 <- 3 bytes
Essentially we will do a CALL to the POP EAX instruction, at which point ESP will point to the address where "POP EAX" is located in memory (aka the return address for the CALL instruction). POP EAX will ensure EAX gets set to this value. Adding 4 to EAX will ensure we add 1 to this value to compensate for the "POP EAX" instruction, then we add another 3 for the bytes that formulate the "ADD EAX, 4" instruction.
Presto majestico, we have EIP :D
To answer the other question we can refer to page 82 of https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf or section 3.5 of volume 1 of the Intel Software Developer's Manual. On this page they mention that EIP can only be controlled by control transfer instructions like CALL, JMP, etc. It cannot be directly accessed by software in x86.
Question: Come up with at least two code sequences to set EIP to 0xAABBCCDD.
PUSH 0xAABBCCDD ; PUSH value onto the stack
RETN ; POP the value at the top of the stack into EIP and resume execution from this location.
JMP 0xAABBCCDD ; Just straight up redirect execution. Why not make it simple after all?
Question: In the example function, addme, what would happen if the stack pointer were not properly restored before executing RET?
Answer: Well considering the stack pointer would be the part where we do the PUSH EBP instruction, we would return execution to EBP, which would basically mean we would return execution to the stack. What happens from here depends on the data that is on the stack. If this results in invalid instructions we would crash. On modern systems the more likely scenario is that DEP would kick in and you would get an ACCESS VIOLATION as the stack would be marked as non-executable.
Question: In all of the calling conventions explained the return value is stored in a 32-bit register (EAX). What happens when the return value does not fit in a 32-bit register? Write a program to experiment and evaluate your answer. Does the mechanism change from compiler to compiler?
Answer: I honestly haven't played around with this much due to compilers deciding to fail over at the time of testing :( However the one I did get something to work on, Visual Studio 2017, appeared to give a warning that it was going to truncate the return address value down to a 32 bit value during compilation. I have heard other compilers may try use EDX:EAX as a way of returning the value as well, but yet to verify this further via my own experiments.