Win32 application MOV to memory address does not work correctly

402 views Asked by At

I am playing with some test application to try to patch its code.

here is original code from IDA pro

movzx   eax, byte ptr word_F3BB4A
and     eax, 2
jz      short loc_62300F

here is my patch

push    ax
xor     ax, ax
mov     byte ptr word_F3BB4A, al
nop
pop     ax
jmp     short loc_62300F

The problem is that after launching application, address in my code does not change base. I am getting the exception accessing F3BB4A.

1

There are 1 answers

1
Margaret Bloom On

In the code you are patching, namely

movzx   eax, byte ptr word_F3BB4A
and     eax, 2
jz      short loc_62300F

there are two instructions that reference memory: the movzx and the jz.
Of the twos only the latter is position independent (it's destination is encoded as a relative offset), the former use an absolute address.
Absolute addresses are fixed up (relocated) by the loader based on the metadata the linker have generated. These metadata works by instruction address.

For example if we patch this program

012C1000 | A1 00 20 2C 01           | mov eax,dword ptr ds:[12C2000]          |
012C1005 | 90                       | nop                                     |
012C1006 | 90                       | nop                                     |
012C1007 | 90                       | nop                                     |
012C1008 | 90                       | nop                                     |
012C1009 | 90                       | nop                                     |
012C100A | 90                       | nop                                     |
012C100B | 90                       | nop                                     |
012C100C | 90                       | nop                                     |
012C100D | 90                       | nop                                     |
012C100E | C3                       | ret                                     |

by moving the move down 8 bytes (that's the reason of all the nop I used) and step again through the executable we have:

010C1000 | 90                       | nop                                     |
010C1001 | 90                       | nop                                     |
010C1002 | 90                       | nop                                     |
010C1003 | 5C                       | pop esp                                 |
010C1004 | 91                       | xchg eax,ecx                            |
010C1005 | 90                       | nop                                     |
010C1006 | 90                       | nop                                     |
010C1007 | 90                       | nop                                     |
010C1008 | A1 00 20 40 00           | mov eax,dword ptr ds:[402000]           |
010C100D | 90                       | nop                                     |
010C100E | C3                       | ret                                     |

where we see:

  1. The move instruction use the address 402000h and so it will eventually fail at runtime. It has not been relocated, as expected.
  2. The nop in place of the original move has been changed by the loader when performing the relocation of the, now non existent, original move.

If you want to patch the original code so that it overwrites the location of the move with a zero before doing its original work, then replace

0F B6 05 XX XX XX XX     | movzx eax,byte ptr ds:[XXXXXXXXh]
83 E0 02                 | and eax,2 

with

90                       | nop
C6 05 XX XX XX XX 00     | mov byte ptr ds:[XXXXXXXXh], 0
31 C0                    | xor eax,eax

Note how the immediates of both moves have the same address and how at the end eax is zero as expected.