Who crashed?

Last week I was investigating a crash originating somewhere in a code that looked like this (GPF in this C++ line):

obj->GetFoo()->GetBar().Call(player->GetCat(), this, &MyType::SomeFunc, moreArgs

We could discuss the number of indirections or the fact that if this code had been split into multiple lines it’d be obvious, but that’s not the main point here. I didn’t have this luxury, I had to find out which pointer exactly was NULL here.

Let’s take a look at the assembly first, this should give us more info:

 1 lea         rdx,[rsp+58h]  
 2 mov         rcx,qword ptr [rax]  
 3 mov         rax,qword ptr [r14+0B20h]  
 4 mov         rdi,qword ptr [rcx]  
 5 mov         rcx,qword ptr [rax]  
 6 call        Object::GetFoo (07FF7A08AA2C0h)  
 7 mov         rcx,rdi  
 8 mov         rdx,qword ptr [rax]  
 9 mov         rax,qword ptr [rdi]  
10 mov         rbx,qword ptr [rdx]  
11 call        qword ptr [rax+0E8h]  *** crash here
12 mov         rdx,qword ptr [rbx]  
13 mov         rcx,rbx  
14 mov         rdi,rax  
15 call        qword ptr [rdx+1E0h]  
16 mov         dword ptr [rsp+38h],3  
17 lea         r9,[MyType::SomeFunc (07FF7A0DE7C6)]  
18 mov         byte ptr [rsp+30h],0  
19 mov         rcx,rax  
20 mov         dword ptr [rsp+28h],3  
21 mov         r8,r14  
22 mov         rdx,rdi  
23 mov         qword ptr [rsp+20h],r15  
24 call        Mgr::Call(07FF7A0DD87C0h)  

At the first glance, it might seem like the result of Object::GetFoo is null, as GPF occurs almost immediately after the call. Looking closer at the assembly, it doesn’t look like the result (RAX) is being used there, though. Is it possible it’s actually player pointer that’s invalid? We could analyze the assembly in more depth, but another way would be to determine the types of our pointers. We seem to be calling a bunch of virtual functions here, so if we know what method resides under [rax+0xE8], we’d be able to tell the type. If it’s GetBar() then it’s indeed result of GetFoo causing issues, if it’s GetCat -> it’s player.

How do we find the vtable for a given type, though? I’m not sure how to do it in Visual Studio, to be honest (my best bet would be to search memory for an address of one of the virtual methods, but the search memory command seems to be removed/well hidden in 2015), but it’s trivial in my old friend WinDbg:

0:000> x *!Foo*`vftable'
00007ff7`a1c70f78 App_x64!Foo::`vftable' = <no type information>
x = examine symbols, it display symbols that match the specified patterns. Now we know the vtable for the Foo type resides at 0x00007ff7a1c70f78.

All we have to do is to check what’s at 0xE8:

:000> dqs (00007ff7a1c70f78 + 0xE8) L1
00007ff7`a1c71060  00007ff7`a0e90b60 App_x64!Foo::GetAnimationMgr
dqs = display qwords (8b) at given address (L1 = we only want 1 entry)

Hmm, OK, doesn’t seem like it’s Foo that’s null then, if it was we’d see GetBar at offset 0xE8. Let’s try Player class now:

0:000> x *!Player*`vftable'
00007ff7`a1bd2870 App_x64!Player::`vftable' = <no type information>
0:000> dqs 00007ff7a1bd2870+0x0E8 L1
00007ff7`a1bd2958  00007ff7`a0909310 App_x64!Player::GetCat

Boom, that’s what we wanted to see. Application has crashed while trying to jump to GetCat using Player’s vtable, so it was the player pointer that was null. Now to find wht it’s the case, but that’s another story…

More Reading