another quick 'n dirty post before leaving for a sequence of security conferences around the Globe... One of the most interesting things to understand on ROP is how to make conditional jumps. We have already seen how to make comparisons (here), very useful for making conditional changes on the stack (ESP). Now let's see the main strategy behind the conditional jumps is the following:
- Move flags to general-purpose registers. Flags are important because they are the result of comparison (here)
- "Do something" if flag is set up or do nothing if flag is not set up (or vice-versa)
- Modify ESP in the "do something" function
Since we know how to make comparisons lets see how we can use the 1 or 0 (the flag) saved into the memory. Let's assume we used the CF (carry flag) from a sub or a neg command. We need something that puts the flags into general-purposes registers: lahf is our instruction ! ;). It stores the five arithmetic flags (SF, ZF, AF, PF, CF) into %ah. Unfortunately lahf function is not very common (I'll post something on probability of gadgets later on this blog). Another great way to move flags to registers is by using pushf much more common. It pushes a word containing %eflags into the stack. Another good way is to use a function which keeps as input a CF like for example the "rotate with carry functions" ( rcl, rcr) and add with carry too, adc. A pretty common gadget is the following one:
adc %cl, %cl // ret
The above gadget computes the sum of its two operands and the carry flag, which is useful in multiword addition algorithms. If we take the two operands to be zero, the result is 1 or 0 depending on whether the carry flag is set ... it's exactly what we need. (NOTE: it should be pretty clear that we can evaluate complicated boolean expressions by collecting CF values of multiple tests and combining them with logical operands.)
Ok now comes the most complicated part: the ESP modification. Right now we have a word containing 1 or 0 depending of the CF, we want to transform it to ESP_delta or 0. Where the ESP_delta is the offset to give to ESP if the above condition is true. One way to obtain the ESP_delta is by using the two's complemet. negl of 1 is all-1 pattern and the negl of 0 is all-0 pattern. Then taking bitwise and of the result and ESP_delta gives a word containing ESP_delta or 0 (for more details on that please read this paper titled "The Geometry of Innocent Flesh on the Bon: Return-to-libc without Function Calls"). Now we need to modify ESP. The following gadget is what we need (or what we need to build).
addl (%eax), %esp addb %al, (%eax) addb %cl, 0(%eax) addb %al, (%eax) //ret
%eax is pointing to the ESP_delta. The follow instructions destroy it, but it has already been used, so no problem at all. The following picture sums up what we said till here.
Here we go! We've just been Jumping conditionally ;)