5

I really hope this hasn't been asked before, but my googling came up with nothing so I figured I would ask.

I have a small script I am working on where I inject a DLL into a game and edit a particular string that gets displayed when a particular event happens. I have found where this string resides in memory, and wrote a basic sigscanning function to find it when at runtime. My question now is, given the starting address, how/can I replace this string with a particular string of my own?

Say for example the string was "I love pancakes", and I wanted to replace it with "Pancakes are terrible, waffles are best!". How would one go about doing that?

Thanks!

Oh yeah, if it matters, the string in the source is a const char. I'm pretty sure it doesn't, but doesn't hurt to add that info!

Matt
  • 22,721
  • 17
  • 71
  • 112
haze
  • 239
  • 2
  • 11
  • 1
    Is there a reason `strcpy()` doesn't do what you want? – Kylotan Nov 14 '12 at 03:40
  • 1
    look into `memcpy`, that might help, also, you can't input a string longer than the const char due to overrun (unless you want funky happenings). – Serdalis Nov 14 '12 at 03:42
  • Darn, there's no way to increase the space? Is there any way I could just replace the string with a pointer to a string at a different address? Forgive me if that sounds stupid, but I am not to skilled in this particular area. – haze Nov 14 '12 at 04:02
  • Short answer: No, there isn't. Slightly longer, more complex answer: with a lot of insight into the program you're injecting, you could potentially achieve this, but it would be extremely involved and for all intents and purposes completely impractical. – Nik Bougalis Nov 14 '12 at 05:18
  • Wait a sec, this is what it looks like in memory... `push offset aString ; "I love pancakes"` Does that mean I could just redirect it to something different? – haze Nov 14 '12 at 05:18
  • @user1822632: Yes, you can do such a redirection. See my answer. – Mike Kwan Dec 27 '12 at 21:38

2 Answers2

2

If the string you want to replace it is at least as long as its replacement it's trivial: replace it in place. Otherwise, you can't reliably declare your hate of pancakes and love of waffles.

Nik Bougalis
  • 10,495
  • 1
  • 21
  • 37
1

As you noted, the assembly instructions referencing the string typically look like this:

push offset aString

After assembling and linking this is resolved to an actual address say:

push 0x00ABCDEF

This gives you two options:

  • Write data: modify the contents of aString (ie. memory pointed to by 0x00ABCDEF)
  • Write code: modify references to aString

Write Data

When source code is compiled involving standard C string literals (immutable array of characters in memory), at runtime the string is typically mapped to some read-only page with all the other read-only data. This data is generally packed contiguously to reduce the memory footprint of the program. This is the problem that you are hitting by trying to write a larger string. You will overwrite the next piece of data and any references to this overwritten data will now point to the middle of your large string.

Writing a longer string by changing the data is non-trivial because in order to not lose the original functional behaviour, you must shift all data after your string forward. After that you must update all the references to the shifted data (some of which may be calculated dynamically with pointer arithmetic). As I say, this process is non-trivial - you are trying to reproduce the task of the linker in terms of relocation without full (if any) symbolic information.

Write Code

The easy way out is to write your new string at some arbitrary location. This might be unused but reserved memory in the process already (commonly referred to as 'code caves') or it might be a string literal which you map in when you inject your DLL. Alternatively, you could allocate this dynamically at runtime after your injection.

The next step is to find all references to aString and replace them to reference your new string instead.

Bonus Method :)

Since you are delving with reverse engineering at this level, likely you have come across the concept of detours/interception/instrumentation. A similar approach can be applied here to intercept all references and redirect them at runtime. This will cause a heavier hit on performance than the 'Write Code' method outlined above, but will guarantee that all accesses are caught and redirected.

A hardware breakpoint on access is set to the data pointed at by the string. When the breakpoint is triggered, some register will hold the address of the string. In assembly, this might look something like this:

mov esi, 0x00ABCDEF
...

If the first character is accessed, the code might do this:

mov al, byte ptr ds:[esi]

When your breakpoint is hit, you can set the thread context (SetThreadContext on Windows) to modify the value of esi to point to your new string.

Mike Kwan
  • 24,123
  • 12
  • 63
  • 96
  • I apologize that at the time I asked this question I did not accept an answer. Yours is clearly the best, and with my present knowledge I definitely think it is the best. – haze Apr 13 '15 at 16:19