Voice from the field

Tags: .Net WinDBG
Donwloads: Demo Project

Changing memory in live .Net process with Windbg

April 14 2016

Developers on the field ask me interesting question after my presentation of live Windbg debugging. They has doubts if the Windbg really the most powerful debugger even in compare with Visual Studio. I would say yes, not just, because I love Windbg but because Visual Studio is Developer's IDE for developing code in design time and Windbg is debugger for run time stage.

 

One of the option which is VS has is useful by developers and many of them ask if the windbg has the same option. This option is Live Debugging memory modification. In other words is assigning variables and values during the live debugging.

The goal of this modification first has you application alive and not fail with memory corruption exception, which is highly likely happened if you modify too much J

 

Let me show you quick example which you can execute during debugging you console project in "Immediate Window".

The same operation you can do with "Quick Watch" window.

 

So what about Windbg?  

You can download and run following example..

The code inside is for demo purpose and does not produce any values. Basically, we have demo1 and demo2 variables which will stay in the execution context during the working of while loop. Each cycle of the loop will print out parameters of the demo1 instance. Field ID is really for reference to identify instance if we going to change Message's values.  


C#

class Program

{

    static void Main(string[] args)

    {

            var demo1 = new Demo(){Message = "First"};

            var demo2 = new Demo(){Message = "Second"};

 

            while (true)

            {

                Console.WriteLine("{0}:Message={1}", demo1.ID, demo1.Message);

                Console.ReadKey();

            }

     }

}

 

public class Demo

{

        public string Message { get; set; }

        public long ID { get; set; }

 

        public Demo()

        {

            ID = DateTime.Now.Ticks;

        }

}

To simplify example lets execute it in Win32 configuration.

First, Please close Visual studio and  run  process "DebugDemo.exe".

  1. Lets attach to the process DebugDemo.exe. Now you are in the live process, so stay calm and breath normally, you are going to perform heart operation over you process.
  2. Switch to #0  thread  and run !CLRstack and !dso to make sure you are in correct thread.
  3. Dump both address of DebugDemo.Demo demonstrate that they have a different string objects ("First", "Second"). Now on console you see output of "First".
  4. Let us change string "First" to the "Third" directly to the memory. You can get an address of the first sting from output of the !dso command. Do not make new string longer then exited to avoid corruption J And, yes, you need some unmanaged debugging skills, just a little to read and modify memory.
  5. But before you run this command make sure you calculate adders_of_first_string+8 value. Windbg will help us to calculate it:  ? 02382fdc+8  will provide 02382fe4

    dd [adders_of_first_string+8] l1   - run to get the real memory address where you sting is located, because the address from !dso contains just reference. String is a referee's type if you forget.

    du [output_addess]   - to make sure what value you have. It should product you "First"

    eu [adders_of_first_string+8] "Third"   - run to modify memory

     

     

  6. "Go" you process and verify console by pressing any key.
  7. Now let's switch addresses of property Message of DebugDemo.Demo instances. So the firs message witch is "Third" right now is going to be "Second" and the "Second" message of the demo2 variable is going to be "Third"
  8. Before you run change for demo1 object let's find out the address  of the second string and address of the first demo object by output of !dso. Then calculate it.
  9. dq [adderss_of_first_demo+8] l1

    eq [adderss_of_first_demo+8] [adders_of_second_string]`[secodpart_as_is]

  10. The same for second object
  11. dq [adderss_of_second_demo+8] l1

    eq [adderss_of_second_demo+8] [adders_of_first_string]`[secodpart_as_is]

     

  12. "Go" you process and verify console by pressing any key.
  13.  

  14. Ok. We switch messages by changes address of strings. Relink the existed string to different object. Now let us do another trick. Let us change the local variables of the Program class. If you remember form code snippet about we have two variables "demo1" and "demo2". They referenced to the objects with different ID and then by listing ID in console we can verify the trick.
  15. Run command !CLRStack -a to find out address of LOCALS in DebugDemo.Program.Main. We need just two firs values.
  16. Then just switch address of the references. Change adders of first Demo with second and third with forth.
  17. ed [address_of_local_1] [value_of_local_2]

    ed [address_of_local_2] [value_of_local_1]

     

  18.    "Go" you process and verify console by pressing any key. Oh, that is s "Third" again!!
 

So as result, right now in the memory you have "demo1" object with ID = 635962409293142454 and Message = Third which is used to be referenced by demo2 local variable.

Then you have "demo2" object ID = 635962409293102457 and Message=Second which is used to be referenced by demo1 local variable.

Your application is still working!

Who is a need a design-time development now? You can simply change everything in run-time J