dod-cyber-crime-center / pyhidra

Pyhidra is a Python library that provides direct access to the Ghidra API within a native CPython interpreter using jpype.
Other
176 stars 15 forks source link

Fails to start gui on macOS (version 1.2.0) #42

Open kyrre opened 3 months ago

kyrre commented 3 months ago

While version 1.1.0 works fine the newest version 1.2.0 fails to launch on macOS:

macOS 14.5 ghidra via homebrew (with rebuilt native binaries)

GHIDRA_INSTALL_DIR=/opt/homebrew/Caskroom/ghidra/11.1.1-20240614/ghidra_11.1.1_PUBLIC pyhidra -g
INFO  Class search complete (1814 ms) (ClassSearcher)
INFO  Initializing SSL Context (SSLContextInitializer)
INFO  Initializing Random Number Generator... (SecureRandomFactory)
INFO  Random Number Generator initialization complete: NativePRNGNonBlocking (SecureRandomFactory)
INFO  Trust manager disabled, cacerts have not been set (ApplicationTrustManagerFactory)
INFO  User kyrre.wahl.kongsgaard started Ghidra. (GhidraRun)
INFO  User settings directory: /Users/kyrre.wahl.kongsgaard/Library/ghidra/ghidra_11.1.1_PUBLIC (GhidraRun)
INFO  User temp directory: /var/folders/bn/dtsdn12n0b986drxdvnf4n1m0000gp/T/kyrre.wahl.kongsgaard-ghidra (GhidraRun)
INFO  User cache directory: /var/tmp/kyrre.wahl.kongsgaard-ghidra (GhidraRun)
INFO  Opening project: /Users/kyrre.wahl.kongsgaard/projects/do_or_die/Rewind (DefaultProject)
INFO  Ghidra startup complete (3682 ms) (GhidraRun)

This is where it gets stuck on 1.2.0. Not sure how to debug this further

dc3-tsd commented 3 months ago

Can you supply the print results of the ctypes.find_library calls in runmac_app at the end of launcher.py?

kyrre commented 2 months ago

Like this?

def _run_mac_app():
    # this runs the main event loop
    # it is required for the GUI to show up
    objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("libobjc"))
    ctypes.cdll.LoadLibrary(ctypes.util.find_library("AppKit")) # required

    print(ctypes.util.find_library("libobjc"))
    print(ctypes.util.find_library("AppKit"))

    ...

/usr/lib/libobjc.dylib /System/Library/Frameworks/AppKit.framework/AppKit

dc3-tsd commented 2 months ago

Thanks for providing the additional information. The values you shared seem to be correct, but we're still working to see if we can replicate this error.

dc3-tsd commented 2 months ago

Can you attempt to update _run_map_app with the following? It seems that there are some unusual behaviors when Java starts up so this tries to work around it. Please let us know if this works.

def _run_mac_app():
    # this runs the event loop
    # it is required for the GUI to show up
    import ctypes
    import ctypes.util
    from ctypes import c_void_p, c_double, c_uint64, c_int64, c_int32, c_bool, CFUNCTYPE

    CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library("CoreFoundation"))

    def get_function(name, restype, *argtypes):
        res = getattr(CoreFoundation, name)
        res.argtypes = [arg for arg in argtypes]
        res.restype = restype
        return res

    CFRunLoopTimerCallback = CFUNCTYPE(None, c_void_p, c_void_p)
    kCFRunLoopDefaultMode = c_void_p.in_dll(CoreFoundation, "kCFRunLoopDefaultMode")
    kCFRunLoopRunFinished = c_int32(1)
    NULL = c_void_p(0)
    INF_TIME = c_double(1.0e20)
    FIRE_ONCE = c_double(0)
    kCFAllocatorDefault = NULL

    CFRunLoopGetCurrent = get_function("CFRunLoopGetCurrent", c_void_p)
    CFRelease = get_function("CFRelease", None, c_void_p)

    CFRunLoopTimerCreate = get_function(
        "CFRunLoopTimerCreate",
        c_void_p,
        c_void_p,
        c_double,
        c_double,
        c_uint64,
        c_int64,
        CFRunLoopTimerCallback,
        c_void_p
    )

    CFRunLoopAddTimer = get_function("CFRunLoopAddTimer", None, c_void_p, c_void_p, c_void_p)
    CFRunLoopRunInMode = get_function("CFRunLoopRunInMode", c_int32, c_void_p, c_double, c_bool)

    @CFRunLoopTimerCallback
    def dummy_timer(timer, info):
        # this doesn't need to do anything
        # CFRunLoopTimerCreate just needs a valid callback
        return

    timer = CFRunLoopTimerCreate(kCFAllocatorDefault, INF_TIME, FIRE_ONCE, 0, 0, dummy_timer, NULL)
    CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode)
    CFRelease(timer)

    while CFRunLoopRunInMode(kCFRunLoopDefaultMode, INF_TIME, False) != kCFRunLoopRunFinished:
        pass
kyrre commented 1 month ago

Sorry for the late reply. Replacing the function with the one you provided fixes it.