Let's split this up a bit. I'll skip over some stuff that you might already understand, but we may need to expand this if some stuff is not clear.
MOV DWORD PTR SS:[EBP-30],400400
MOV DWORD PTR SS:[EBP-30],DWORD PTR DS:[400400]
The syntax is a bit wonky but we can understand that you want to encode a MOV
with two memory operands.
Let's take a look at some documentation
Ref: https://www.felixcloutier.com/x86/MOV.html
There is no possible encoding for MOV
that accepts m32,m32
. With m32
understood to be a 32 bit pointer.
It's not obvious this is the case, but unfortunately it is.
Ref: https://stackoverflow.com/a/33799523/10279341
This is a good answer if you care about why, but it is supplemental reading only, not critical to this situation.
So, if we want to copy memory to memory with x86:
Ref: https://stackoverflow.com/a/1299094/10279341
A commonly accepted solution is to use a register as a temporary value store.
Take note that we need to save the state of the register we are using else we might accidentally alter the program state.
MOV ECX,DWORD PTR DS:[400400]
MOV DWORD PTR SS:[EBP-30],ECX
So this is on the right track. But we need to save ECX
beforehand in case something else is using it.
0x00000000: 51 push ecx
0x00000001: 8b 0d 00 04 40 00 mov ecx, dword ptr [0x400400]
0x00000007: 89 4d e2 mov dword ptr [ebp - 0x1e], ecx
0x0000000a: 59 pop ecx
This should do that you want. We save ECX
by pushing it onto the stack. Load the value at address 0x400400
into ECX
. Then write the value of ECX
into the memory at [EBP-0x1E]
, then restore ECX
to it's previous value.
So how do we patch this into the binary image?
The above assembly is 11 bytes in length and our goal is to alter the instruction
0: c7 45 e2 4c 00 00 00 mov DWORD PTR [ebp-0x1e],0x4c
Which we can see is 7 bytes long.
We can get these extra 4 bytes by use of a "code cave". We will redirect execution into an unused bit of memory, execute our code, then jump back.
Ref: https://www.codeproject.com/Articles/20240/The-Beginners-Guide-to-Codecaves
In short, we're looking "empty space" that is allocated/mapped within the exe image, preferably in the .text section, but are not used by the program under any circumstances. This will occur in nearly every executable image due to SectionAlignment in Windows PE being 4096 by default.
The easiest way to implement this is to find unused bytes in the same region of memory that we are trying to modify.
A rudimentary way of finding/applying a code cave with ollydbg is shown here:
https://medium.com/@vysec.private/backdoor-101-f318110e1fcb
After finding suitable memory for our cave, patch in the shellcode:
0x00000000: 51 push ecx
0x00000001: 8b 0d 00 04 40 00 mov ecx, dword ptr [0x400400]
0x00000007: 89 4d e2 mov dword ptr [ebp - 0x1e], ecx
0x0000000a: 59 pop ecx
using ollydbg's assembler.
Then change the original instruction of mov DWORD PTR [ebp-0x1e],0x4c
to JMP x
where x
is your shellcode address, in the same module/image.
Overwrite the rest of the instruction bytes with 0x90 (NOP) if you want. So that we end up with:
c7 45 e2 4c 00 00 00
- Original instruction
e9 xx xx xx xx 90 90
- JMP rel32 plus 2 NOPs
Ref for x86 JMP: https://c9x.me/x86/html/file_module_x86_id_147.html
after pop ecx
back in our code cave assemble: JMP y
where y
is the address of the instruction directly after mov DWORD PTR [ebp-0x1e],0x4c
. You should end up skipping over the NOP instructions when jumping out of the code cave, which is why I said they were optional.
Summary,
Assemble our shellcode, making note of correct x86 ASM and preserving program state.
If not enough space to patch the instruction in-line, idenfity a code cave.
Apply the code-cave and assemble the two JMP
instructions to redirect execution (1) to the code-cave, (2) back to the next instruction from the original code.