We’ve been working on a series of x64 related crashes so that we can work up to analyzing a crash dump from a real world system. In this post I’m going to demonstrate the techniques you can use to find the actual parameters passed to a function when working with an x64 crash. As mentioned previously, this can be tricky due to the x64 compiler’s use of volatile registers for parameter passing. So we’re going to have to rely on the parameters being stored into other registers or on the execution stack.
Let’s use the dump that we’re eventually going to analyze and get the parameters to the faulting subroutine back. Here’s a shot of the faulting instruction in the faulting module:
The faulting intruction is the second arrow and the first arrow shows the bad pointer value being loaded from RDX into RBX. The analysis will later show that this bugcheck is a result of a bad pointer dereference via the RBX register. As we know from our discussion of calling conventions, RDX is the second parameter to this function thus presumably this function was passed a bad pointer value as the second parameter.
Googling the function name gives us the function prototype for RtlDeleteNoSplay:
IN PRTL_SPLAY_LINKS Links,
IN OUT PRTL_SPLAY_LINKS *Root
What I would like to do now is reconstruct the two parameters to the function so that I can perform further analysis. Because this can range from a simple task to something quite annoying, I’m going to demonstrate reconstructing the first parameter to this routine using three different levels of difficultly. This is always going to of course be very situation specific, but hopefully the three techniques shown here will come in handy.
In this routine I get lucky in finding the first parameter, as RCX is loaded into the R11 register before the crash:
Since R11 is a volatile register, I can trust the value of R11 in the trap frame that I have so I can inspect the first parameter by looking in R11:
But, what if RCX hadn’t been stored into R11 before the crash? Then we’d have to dig a little deeper and try to find the parameter in a previous frame. I like to do this as a practice exercise when I can, I already have the result that I know I have to get to so I can easily validate my result from going the hard way.
So, how do I find the first parameter to this function without using R11? Well, I know that the previous function in the stack must have loaded a value into RCX to set up for this frame. So, I’ll start by walking up the stack to the previous function, which in this case is TreeUnlinkNoBalance:
You’ll note here that RCX is stored in RBX before calling into RtlDeleteNoSplay. Now I know that upon entry to RtlDeleteNoSplay RCX was equal to RBX, so that gives me another register I can track inside RtlDeleteNoSplay in the hopes of recontructing the first parameter. So, let’s look at RtlDeleteNoSplay again:
Notice the first instruction of RtlDeleteNoSplay, it’s a push of RBX onto the stack! That means that the value of the first parameter to this routine was preserved on the execution stack. The RSP value in the trap frame will be that of the stack pointer at the time of the crash, thus in order to get the value on the stack back I will need to unwind any stack manipulations done after the save of the value on the stack. In this case, I simply have to add 0×20 to the stack pointer to undo the subtraction of 0×20 from RSP after the push:
But what if we had to go even further up in the stack to find a parameter? Would we be able to get a parameter to a function back? Let’s give it a shot!
For this one I’m doing to use a different routine with different parameters, since it’s further up in the stack and that will complicate our analysis.
Earlier in the stack PurgeStreamNameCache calls DeleteNameCacheNodes:
Note that the routine sets up RCX by loading it with the value of RSI. Thus, if I want the first parameter back when I’m inside DeleteNameCacheNodes I can look for either RCX or RSI being loaded into another register or, even better, saved on the stack:
Immediately at the beginning of the function we see DeleteNameCacheNodes storing RSI into the R9 home space on the stack. This is great news for us, as it means that we can get this parameter back by plucking it off of the stack location. But, how can we figure out what stack pointer value to use?
This is the key trick to reconstructing parameters on the x64. It’s quite simple actually, all we need to do is execute the k command and get the Child-SP value for the frame that we’re interested in:
That is the value the stack pointer will be upon return from the current call that subroutine is making. That’s a bit confusing, but what I mean is that in this case we see DeleteNameCacheNodes calling TreeUnlinkMulti. The Child-SP indicates what RSP will be when that call returns. This makes it very easy to find anything on the stack that we want in DeleteNameCacheNodes since all we need to do is start unwinding the stack changes that were made in the prolog until we hit the value that we want:
(Note: Picture above fixed on 1/15 based on comments from Anonymous. See comments section of the post.)
Now that we have the correct values, we can just dump out that memory location with the dq command:
As a final tip, in this can I could have quickly found this value by leveraging the fact that the Args to Child in the kv output shows the four home space values from the stack. Since RSI was put in the R9 home space (RSP+0×20), I could have just done a kv and pulled the fourth value from the resulting output in the DeleteNameCacheNodes entry.