# Ghidra + MSDN Offline Library = ❤️

A while back [I blawgd about how to get the MSDN library for offline use](https://blag.nullteilerfrei.de/2017/12/21/get-the-msdn-library-for-offline-use/). However, the Help Viewer has its problems. I won't list all of its problems, but it was certainly a bad candidate to integrate Win32 API documentation support to Ghidra. There is [a pretty neat project by Laurence Jackson](http://laurencejackson.com/win32/), but I think I just found something a little better even: Microsoft provides [a download of the MSDN Library for Visual Studio 2008 SP1, stand-alone, offline, as an ISO](https://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=20955) - smell this, Help Viewer: So this is nice, but the main point of this exercise was to integrate this into Ghidra. If that's something you care about, read on. ## Integrating this into Ghidra After installing the MSDN for VS2008 to the default location, I took a [neat script](https://github.com/0x6d696368/ghidra_scripts/blob/master/GoogleSearch.py) by _mich_ (I take him for a big Endian kinda guy) and modified it as follows:
# Attempt to look up currently higlighted Windows API calls in the MSDN Library.
#@category Search
#@keybinding F2

import shlex
import os
import subprocess

from ghidra.program.model.symbol import FlowType

def searchMSDN(topic):
def getViewerPath(*commonFilesPathCandidates):
for baseDir in commonFilesPathCandidates:
path = os.path.join(baseDir, 'microsoft shared', 'Help 9', 'dexplore.exe')
if os.path.exists(path):
return path
viewer = getViewerPath(
os.environ.get('CommonProgramFiles(x86)', ''),
os.environ.get('CommonProgramFiles', ''),
R'C:\Program Files (x86)\Common Files',
R'C:\Program Files\Common Files'
)
command = '"{}" /helpcol ms-help://MS.MSDNQTR.v90.en /LaunchFKeywordTopic {}'.format(viewer, topic)
return subprocess.call(shlex.split(command))

try:
except AttributeError:
if search.startswith('FID_conflict:'):
search = search[13:]
return search

assert level < 5
if reference.isExternalReference():
return reference.getLabel()
if reference.getReferenceType() == FlowType.UNCONDITIONAL_CALL:
try:
except Exception:
pass
if reference.getReferenceType() == FlowType.INDIRECTION:
else:

try:

I put this into %USERPROFILE%\ghidra_scripts, and sure enough, I could bind this to the F2 key: Using it is a painfully slow process, but it works. This is me testing it on a [Phorpiex](https://malpedia.caad.fkie.fraunhofer.de/details/win.phorpiex) sample: ### Conclusion I can't believe I am going to say this, but here it goes: > _"Maybe I should rewrite this in Java for better performance."_
2. Oh nice, very glad to hear it! I only checked comments just now to say that I updated the script slightly to accommodate FlowType.INDIRECTION.