Ghidra + MSDN Offline Library = ❤️



A while back I blawgd about how to 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, 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 - 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 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:

https://blag.nullteilerfrei.de/wp-content/uploads/2019/07/LaunchMSDN.In_.Script.Manager.png 1025w, https://blag.nullteilerfrei.de/wp-content/uploads/2019/07/LaunchMSDN.In_.Script.Manager-300x187.png 300w, https://blag.nullteilerfrei.de/wp-content/uploads/2019/07/LaunchMSDN.In_.Script.Manager-768x480.png 768w, https://blag.nullteilerfrei.de/wp-content/uploads/2019/07/LaunchMSDN.In_.Script.Manager-1024x639.png 1024w" sizes="(max-width: 1025px) 100vw, 1025px">

Using it is a painfully slow process, but it works. This is me testing it on a Phorpiex sample:

MSDN Lookup from Ghidra

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."

Tags: - - -

2 Replies to “Ghidra + MSDN Offline Library = ❤️

  1. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *