Debugging Third-Party Applications – Part 2
19 January 2012, by Rupert Wood
This is a short series of posts about a problem I had with Microsoft Exchange’s Outlook Web Access (OWA): reading the Old New Thing blog through OWA suddenly stopped working with this error:
In the first part I tracked down this error message to a static page UrlBlockedError.aspx in the OWA files on the Exchange server.
Digging into the code responsible
So my next step was to identify the code that was redirecting me to the error page by searching for the “UrlBlockedError.aspx” in the script and binary files, and I got a hit for that as a Unicode string in Microsoft.Exchange.Clients.Owa.dll. Given the DLL filename looks like a .NET namespace, and that we have an .aspx file, this is almost certainly .NET code and this is much easier to dig into than equivalent native (i.e. compiled C or C++, etc.) code.
Now since this is Microsoft code, regardless of whether it’s native or .NET, it’s worth checking their public debugging symbol servers to see if debug information – or perhaps even the source code – is available. You can configure Visual Studio to check the Microsoft Symbol Servers for code that you are debugging into, but you would need to mock up a quick program to load the assembly / DLL / component to trick it into downloading symbols. The easiest way to query for symbols is to use the SymChk tool from the Debugging Tools for Windows package (the install that includes WinDbg), now packaged in the Windows SDK. Running
symchk /v Microsoft.Exchange.Clients.Owa.dll
will attempt to download symbolic debugging information for that DLL from Microsoft as a PDB (Program Debug Database) file. In this case, unfortunately, no symbols were available – they are usually only available for core OS components and not server or application code.
This isn’t a significant problem for .NET code, though: .NET assemblies will already contain class names and function and parameter names that you can use to understand the code you’re reading, and the PDB files often only add internal function variable names (plus line numbers from the original source). Debugging native code without PDBs, however, you will have only have information on any exported functions from the DLL plus the entry point and will have to figure everything else out yourself!
One of the best tools to look into a .NET assembly is Red Gate’s Reflector (or one of the recent clones). This will allow you to navigate through the assembly classes and namespaces and view a reverse-engineered version of any class or function – obviously extremely useful! The code generated is not a perfect match to the source but is far more readable than picking through a disassembler listing.
Unfortunately Reflector doesn’t support string searches through the source for strings in the code – as above I need to find “UrlBlockedError.aspx”. Instead I used Red Gate’s Reflector Pro plug-in to dump out source code for all classes in the assembly and then searched through those generated files for that string.
There’s only a single place in the code that generates UrlBlockedError links: a class OwaSafeHtmlCallbackBase. Reading the code in this class, and in its subclasses, I discovered that UrlBlockedError links are generated for any of the following reasons, whether they are hyperlinks, form submission targets or image sources:
- for message attachments where the message is suspected as junk or phishing, or attachments with a blocked file extension or content type
- any relative or incomplete URLs – any URL which does not parse correctly using Uri.TryCreate(uriKind: UriKind.Absolute)
- any URL with an invalid URL scheme identifier or an identifier not in a configured set of safe scheme names (http, https, ftp, mailto, etc.)
This was enough for me to realise what my own problem was: that the URLs OWA was trying to display were being passed as relative URLs and so blocked by the second rule.
Where were these relative URLs coming from and what had changed to cause me this problem in the first place? Answers on a post-card, or read-on in the final part of my story!