3

I'm trying to replace a static value:

MOV DWORD PTR SS:[EBP-30],4c

With a value from a specific address:

MOV DWORD PTR SS:[EBP-30],400400 // MOV DWORD PTR SS:[EBP-30],OFFSET 400400

But SS:[EBP-30] is not being set to the value from 0x400400.

I'm new to this but I was thinking this would work:

MOV DWORD PTR SS:[EBP-30],DWORD PTR DS:[400400]

But I guess it doesn't because ollydbg gives an error.

The value from 0x400400 is int 100 or 64 00 00 00. Why doesn't it work? And what are my options?

I was also thinking of doing something like:

MOV ECX,DWORD PTR DS:[400400]
MOV DWORD PTR SS:[EBP-30],ECX

But I don't know how to add a new line of instruction in ollydbg I was also afraid it would change all the addresses.

5

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,

  1. Assemble our shellcode, making note of correct x86 ASM and preserving program state.

  2. If not enough space to patch the instruction in-line, idenfity a code cave.

  3. 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.

  • does it matter that the value I'm trying to read is only 1-100? like the value is maxed at 100. so technically I can get away with reading it as a single byte. – majidarif Sep 27 '18 at 17:45
  • it won't matter unless the bytes around the value are changed. eg 0x400401, 0x400402, contain other values not part of the value. dword ptr [0x400400] will read 4 bytes (little-endian) starting at 0x400400. if you change it to byte ptr, it will only read the one byte. – Abigail Sep 27 '18 at 18:59
1

Memory-to-memory MOV does not exist. You could try the following:

    MOV eax, DWORD PTR DS : [400400]
    MOV DWORD PTR SS : [EBP - 30], eax

Please check also if the absolute numbers are interpreted as hex values in your assembler.

  • I was actually thinking of this but how do I do it in ollydbg? I'm not sure how to add a new line of instructions and it might change all the addresses? – majidarif Sep 27 '18 at 14:39
  • If your intent is to patch an existing code, and the patch needs more bytes than the replaced code, you must be sure that either the code in the additional space is not needed any more, or you could insert (i.e. patch) a jmp to a free memory location, re-insert the "destroyed" code and jmp back to the original code where it can continue like before the patch. With respect to Olly, I don't know the answer, because I usually work in Ida. – josh Sep 27 '18 at 15:01
  • Thank you. Unfortunately although I think I get what you meant. I'm really new to this to know how to do it. When you say JMP to an free memory location. Do I replace the current instructions with JMP then use that to do those instructions are return back? But, how do I do that exactly? And how do I find a free memory? – majidarif Sep 27 '18 at 15:09
  • I think you got it right. How you do it technically depends. Try to become proficient with your tools. One possibility would be to create the machine code (usually not by hand, but from an assembler), then patch it in the exe file and test it in your debugger. Often the tricky part is to find a free mem location, large enough, and to not introduce new errors, by e.g. relying on absolute mem addresses (try to understand what "ASLR" means) etc. No standard recipes exist. – josh Sep 27 '18 at 16:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.