We will now find out how to store a small register into a wider register or a wide memory location. For instance, let's say the register AH holds the hex number 27. I want to store 27 into EDX, so that EDX holds 00000027. Now, normally the way to store a register into another register is to use a single MOV command. But this won't work: MOV EDX,AH ;Not accepted by OllyDbg. When using MOV, both operands must be the same data size.
You can MOV a DWORD-sized register into another DWORD-sized register. You can also MOV a BYTE-sized register into a BYTE-sized memory location. However, if you want to MOV a BYTE-sized register into a DWORD-sized register, it won't work at all. This is the meaning of "both operands must be the same data size".
Small Data Sizes to Large Data Sizes If you're clever enough, you probably already figured out how to store AH into EDX. You need two MOV instructions: MOV EDX,0 MOV DL,AHInteresting. We assume that AH already holds 27. So we first stored 0 to EDX, which made it hold 00000000. Next we stored AH into DL, where DL represents the rightmost 2 hex digits of EDX. Then EDX now contains 00000027, and we're done. Although this looks like a good solution, it doesn't work if AH holds a negative number, such as -44. We need a smarter solution. Sign Extension Enter sign-extension. Sign extension automatically "extends" a number found in a small data size to a larger data size. This works with both positives and negatives. For example, you can sign-extend a WORD into a DWORD, a BYTE into a DWORD, a BYTE into a WORD, and so on. To do this, we need the command MOVSX, which stands for "MOV with sign extend". MOVSX A,B = Stores B into A, where B is a smaller data size than A. A must be a register. B can be a register or memory location. Treats A and B as signed numbers. Now we can do what we want. MOVSX EDX,CL ADD CL,70 MOVSX AX,CL MOV WORD [49E6CC],AXLet's assume that CL initially held -3B. Using MOVSX, we store CL into EDX, so that EDX also holds -3B. After that, we add 70 to -3B, which is 35 in hex. We store 35 to AX, and then store AX to the player's current health. Now Quote's health is 35 in hex, which is 53 in decimal. We are not allowed to do MOVSX WORD [49E6CC],CL directly because the first operand of MOVSX must be a register, not a memory location.Zero Extension MOVSX works with signed numbers only. What if you want to use unsigned numbers? We need to switch to zero-extension. MOVZX means "MOV with zero extend", and it does the same thing as MOVSX except that it treats its operands as unsigned. MOVZX A,B = Stores B into A, where B is a smaller data size than A. A must be a register. B can be a register or memory location. Treats A and B as unsigned numbers. When You Shouldn't Use Sign-Extension and Zero-Extension MOV EAX,20Look at the above line of code. You may start to think, "I need to use MOVSX EAX,20 because 20 is the size of a byte and EAX is a DWORD."Wrong. We have been using instructions similar to MOV EAX,20 all the time. They've been working fine. In this case, the hex number 20 is automatically interpreted as DWORD size (written as 00000020). When you are storing regular old hex numbers into registers or memory locations, just use MOV, not MOVSX / MOVZX.
Previous Lesson: Redefining Jumps Next Lesson: Redefining IMUL and IDIV Table of Contents |