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))
def searchAddress(address):
try:
search = getFunctionAt(address).getName()
except AttributeError:
raise Exception('No reference found for address {}'.format(address))
if search.startswith('FID_conflict:'):
search = search[13:]
return search
def getReferenceName(address, level=0):
assert level < 5
for reference in getReferencesFrom(address):
if reference.isExternalReference():
return reference.getLabel()
if reference.getReferenceType() == FlowType.UNCONDITIONAL_CALL:
try:
return searchAddress(reference.getToAddress())
except Exception:
pass
if reference.getReferenceType() == FlowType.INDIRECTION:
return getReferenceName(reference.getToAddress(), level + 1)
else:
return searchAddress(address)
try:
searchMSDN(getReferenceName(currentAddress))
except Exception as E:
print 'ERROR: Help lookup failed: {}'.format(E)
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."_
FlowType.INDIRECTION
.