Debugging undebuggable applications with PIX

by Nick September. 10, 12 0 Comment

Developers can ask DirectX 9 not to allow PIX to debug their application by calling D3DPERF_SetOptions(1). I knew that and encountered several commercial applications using it. One day, I was fooling around with Portal 2 and wanted to feed my curiosity on how some stuff is done but when I started PIX all I got was “Direct3D Analysis Disabled” and I knew it was the time to find a way to circumvent this little peculiarity. So, let’s see how can we convince DirectX to ignore the request of the said developers.

I started with a simple application:


Let’s check out the disassembly of the D3DPERF_SetOptions(1) call:


72EC7402 8B FF mov edi,edi
72EC7404 55 push ebp
72EC7405 8B EC mov ebp,esp
72EC7407 83 EC 18 sub esp,18h
72EC740A A1 50 92 FC 72 mov eax,dword ptr [___security_cookie (72FC9250h)]
72EC740F 33 C5 xor eax,ebp
72EC7411 89 45 FC mov dword ptr [ebp-4],eax
72EC7414 A1 54 74 EC 72 mov eax,dword ptr [string “DirectX Direct3D SO” (72EC7454h)]
72EC7419 89 45 E8 mov dword ptr [ebp-18h],eax
72EC741C 8B 0D 58 74 EC 72 mov ecx,dword ptr ds:[72EC7458h]
72EC7422 89 4D EC mov dword ptr [ebp-14h],ecx
72EC7425 8B 15 5C 74 EC 72 mov edx,dword ptr ds:[72EC745Ch]
72EC742B 89 55 F0 mov dword ptr [ebp-10h],edx
72EC742E A1 60 74 EC 72 mov eax,dword ptr ds:[72EC7460h]
72EC7433 89 45 F4 mov dword ptr [ebp-0Ch],eax
72EC7436 8B 0D 64 74 EC 72 mov ecx,dword ptr ds:[72EC7464h]
72EC743C 89 4D F8 mov dword ptr [ebp-8],ecx
72EC743F C6 45 ED 44 mov byte ptr [ebp-13h],44h
72EC7443 8B 4D FC mov ecx,dword ptr [ebp-4]
72EC7446 33 CD xor ecx,ebp
72EC7448 E8 D3 A1 F5 FF call @__security_check_cookie@4 (72E21620h)
72EC744D 8B E5 mov esp,ebp
72EC744F 5D pop ebp
72EC7450 C2 04 00 ret 4

Some movs, xors, runtime security check and that’s it, nothing with the actual value we passed to D3DPERF_SetOptions… well that was big nothing.

Ok, take two – let’s first start the application with PIX and then attach.
We’ll have to add some code to give us time to attach:


Use something like this, or just a Sleep() for enough time. Now what do we have with the new setup:

72EC7402 E9 46 77 AA E8    jmp      HookedD3DPERF_SetOptions (5B96EB4Dh)

All right, the sneaky PIX has modified d3d9.dll’s memory and now it has a jmp in the beginning! The function it now executes takes us inside PIXHelper.dll:


5BF6EB4D 8B FF mov edi,edi
5BF6EB4F 55 push ebp
5BF6EB50 8B EC mov ebp,esp
5BF6EB52 83 7D 08 01 cmp dword ptr [ebp+8],1
5BF6EB56 75 0B jne HookedD3DPERF_SetOptions+16h (5BF6EB63h)

We’ve only had one push so far (for the value we passed) and we push ebp, so that’s 2 pushes. After “mov ebp,esp” ebp is the same as the stack pointer, so dword ptr [ebp + 8] would be exactly the value we passed to D3DPERF_SetOptions. We compare that to 1 and if it’s equal some procedures are invoked that stop the execution. If it isn’t – we follow the jump specified by jne. What we have to do is make that jump unconditional – i.e. always execute the jump, regardless of the value passed. We don’t care about the code that pops the message for disabled analysis so we have plenty of bytes to play with; However, we don’t need them as we can see in “Intel® 64 and IA-32 Architectures Software Developer Manuals” – what we’re looking for is the EB cb variant of jmp, the exact same amount of bytes as the used jne instruction. Now all that’s left is open PIXHelper.dll with a hex editor (I used Notepad++ with hex-editor plugin), search for some of the bytes (try “8B EC 83 7D 08 01 75 0B” – I found it only once) and change the 75 to EB. Voila! Now you won’t see that annoying warning anymore.


Follow Nick on Twitter: @Nikxio

Social Shares

Related Articles

Leave a Comment