I'm pretty new to assembly, I'm trying to understand things better.
My goal is to change the default text colour of controls in a win32 x86 application, these are stored as RGB values for different states of elements (like normal, hovered, disabled).
For most things this is pretty simple as I can just change the RGB value directly to a new RGB value. But for elements that use the colour #000000, the assembly seems to use some optimization whereby it's not stored as '000000', it's stored as '00'. So I can't just change this to a different RGB value as there's no room for it.
Below is an example of what I'm working with, this is the color of checkbox controls. puVar4
is the color of the text for a checkbox, local_14c
is an X position of an image sprite for multiple states of a checkbox (0 is the normal state, 0xe is active, 0x1c is disabled).
The disabled text color is 0xc0c0c0, the active state is 0x5645be, the normal state is 0x000000 but represented as 0x0 using what I assume is an optimization XOR EDI, EDI
which assigns 0.
So I know I need to change XOR EDI, EDI
but I need room for the change, and presumably the only way I can do this is to JMP
to an empty area in memory to perform the change, and then JMP
back to the next instruction? My process of attempting this is as follows:
I move the TEST
instruction up to where the XOR
was, and NOP
the 2 bytes excess along with the MOV
instruction. Then at the first NOP position I insert a JMP
, this leaves me with 3 excess NOP
.
I JMP
to 0x4002a9
which is near the start of the assembly and seems to be a large area of nothing so I think it's okay to use. I need to re-add those instructions I NOP'd, where I can assign a RGB value to EDI
, I assign the color red with 0xff0000. For some reason, Ghidra doesn't allow me to add instructions with the label local_14c
in these new instructions, so I change it to 0xfffffeb8
(the instruction info of the original MOV
shows this is what local_14c
refers to so I assume it's correct). I then JMP
back to the next instruction proceeding which was the JZ
The decompiled code seems to show my changes are without error.
And here is the instruction that the JMP
leads back to, which is after the area I NOP'd
When I export these changes and attempt to run the patched application, it crashes on startup. Is there something I'm missing? Any guidance on where to go from here would be most appreciated!
Update:
From what Luke mentioned, I now understand that I can only insert instructions into areas of memory that are executable.
From the below with this in mind, it seems I'd only be able to add new instructions within the .text block. (Though I assume I could also create new executable blocks if desired?)
I started over without the changes done above, I see that there's some space below the function that I'm making changes in.
I think the db 6h
lines are related to switch statements in the function, so I'm not touching those. A varying number of ?? CCh
lines are present at the end of every function so I assume these are free to use.
There are only 14 of these for the function I'm working with which isn't enough to make all the patches I did above, so I'll only change the local_14c variable for testing.
So basically, all I've done here is replace where local_14c was assigned with a JMP to the end of the function where it is then assigned instead, and then JMP back to the next instruction.. which should work fine?
But nope, it's the same issue
Here is the error output from WinDbg
(70f8.4604): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=02ea7470 ebx=00b90c52 ecx=eb080000 edx=00000000 esi=02e60450 edi=00000000 eip=0000d302 esp=00afecc0 ebp=00afee6c iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00210246 0000d302 ?? ??? 0:000> g
And when I resume, it's the same thing:
(70f8.4604): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=4dff1590 ebx=007e08ba ecx=eb080000 edx=00000000 esi=02e60450 edi=00000000 eip=0000d302 esp=00afecc0 ebp=00afee6c iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00210246 0000d302 ?? ??? 0:000> g
I think this is because the application is actually handling the error, as there is an error prompt that shows, but it does not show any text, I assume the application is in a hanged state before the text can show.