Modifying EIP in WinDbg on fly in order to test different branches of code

Sometimes during debugging it happens that you just got some function failed and you want to re-try it again. After this function fails you might have a BSOD, for example,

ntRetVal = FileOpen(&hFile, szPath);

if (!NT_SUCCESS(ntRetVal))
{
#ifdef DBG
     KeBugCheckEx(0x0, 0, 0, 0, id_of_the_problem);
#endif
}

Now, as you can see in above code it is gonna bsod (in debug) if FileOpen fails. In assembler it looks like this (approximatly):

b2cefae1 8b4dec          mov     ecx,dword ptr [ebp-14h]
b2cefae4 83c114          add     ecx,14h
b2cefae7 51              push    ecx
b2cefae8 8b55ec          mov     edx,dword ptr [ebp-14h]
b2cefaeb 81c224170000    add     edx,1724h
b2cefaf1 52              push    edx
b2cefaf2 e809850200      call    mydrv!FileOpen (b2d18000)
b2cefaf7 8945f0          mov     dword ptr [ebp-10h],eax
b2cefafa 837df000        cmp     dword ptr [ebp-10h],0
b2cefafe 0f8d82000000    jge     mydrv!MyRoutine2+0x656 (b2cefb86)
b2cefb04 6a6b            push    6Bh
b2cefb06 6a00            push    0
b2cefb08 6a00            push    0
b2cefb0a 6a00            push    0
b2cefb0c 6a00            push    0
b2cefb0e ff15c841d0b2    call    dword ptr [mydrv!_imp__KeBugCheckEx (b2d041c8)]

What if you don’t want now to BSOD and loose this test-case scenario? Of course, you can repeat debugging by modifying your code and remove call to KeBugCheckEx or even add more logging. But this is waste of time. You just need to retry call to FileOpen and step further inside to see why it fails.

So, you can modify EIP on fly and set it to a call to FileOpen function. The easiest way is to open registers window (Alt + 4) or you can use r command in windbg:

0: kd> r
eax=c0000120 ebx=00000007 ecx=00000008 edx=80500021 esi=e1448598 edi=805639e4
eip=b2cefb04 esp=b25f1b68 ebp=b25f1be8 iopl=0         nv up ei ng nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000282

Now, in order to call FileOpen I have to make sure I set the EIP in proper place, exactly before it pushes params into stack, look here:

b2cefae1 8b4dec          mov     ecx,dword ptr [ebp-14h]
b2cefae4 83c114          add     ecx,14h
b2cefae7 51              push    ecx
b2cefae8 8b55ec          mov     edx,dword ptr [ebp-14h]
b2cefaeb 81c224170000    add     edx,1724h
b2cefaf1 52              push    edx
b2cefaf2 e809850200      call    mydrv!FileOpen (b2d18000)

So, we have to set EIP to point to b2cefae1. You can modify EIP value in Registers window or you can set it via command line:

0: kd> r EIP=b2cefae1

Press F10 and you will see that the flow of execution will change. You can basically use this technique even in user mode debugging in Visual Studio (registers window), just make sure you don’t wack the stack, i.e., change EIP before your code pushes some params into stack, otherwise your stack will be bogus. In order to achieve this, switch to disassembly view from source view so that you would not miss any commands by pressing F10.

You can say: “what about Edit -> Set Current Instruction menu item in Windbg? Isn’t modifying registers more complex?” Indeed, it is. However, it gives you more control.

Imagine that you decided to change EIP by choosing “Set Current Instruction” menu item in Windbg, but before you chooose this item, you were in the middle of pushing to stack params to some function, i.e.,

b2cefb21 6a6b            push    6Bh <------- you are executing this instruction
b2cefb23 6a00            push    0
b2cefb25 6a00            push    0
b2cefb27 6a00            push    0
b2cefb29 6a00            push    0
b2cefb2b ff15c841d0b2    call    dword ptr [mydrv!_imp__KeBugCheckEx (b2d041c8)]

At this situation if you change EIP you will have in stack 1 dword: 6bh (4 bytes). Now, suppose you change EIP and execution flow goes somewhere, after you desired function worked out, these 4 bytes in stack are not going to be pop-ped out and you have to do something with them, as they eventually will cause problems.

In these situations you will have to adjust stack by … modifying ESP register! In this particular case in order to remove 4 bytes from stack you can do the following:

r ESP=@esp + 4

As you can see, even if you use “Set Current Instruction” you still may need to care about modifying registers, so why just not take this approach from the begining and consider accuratly all modifications you perfom? 🙂

4,502 views

Leave a Reply

Your email address will not be published. Required fields are marked *

Identify yourself * Time limit is exhausted. Please reload CAPTCHA.