Kayaker

  1. OllyDbg 2.x Plugin Writing - Creating the OLLYDBG.LIB file

    While the current version of OllyDbg (2.01e as of writing) is still in development, it now has full plugin API support.
    Compiling a plugin requires linking with an ollydbg.lib file describing the imports defined in the plugin.h header file.
    For Borland compilers this is a straight forward procedure and the LIB file should be fully compatible with the plugin declarations.
    For MSVC compilers (Visual Studio, Visual C++) the situation is a bit more complicated.
    I will describe what worked for me and how to go about producing an MSVC compatible ollydbg.lib file.

    For MSVC you first need to create a DEF file in the proper format and then create the LIB file with the LIB /DEF: command. In OllyDbg 2.x the plugin exports are a mixture of _cdecl and _stdcall.

    Cdecl functions can be declared in the DEF file as FunctionName @Ordinal.

    Stdcall functions must be declared in the DEF file in the decorated format FunctionName@<number of parameter bytes> @Ordinal.

    The attachment contains an MSVC suitable ollydbg.lib file (tested in VC6++ and VS 2010), the DEF file, and the python script I wrote to extract the number of parameter bytes from each _stdcall function in plugin.h and create the required DEF file format. Since the plugin.h function declarations may change in future versions as OllyDbg 2.x is developed, the python script may come in useful to create an updated ollydbg.lib file.

    Stop reading now if you don't need the details.


    For Borland compilers one can simply use IMPLIB.exe to create a LIB file in the following manner, and you're ready to go.

    implib ollydbg.lib ollydbg.exe

    For MSVC, well, here's the MS definition of the steps:

    Given a .DLL (in our case OLLYDBG.EXE) with functions exported via a C interface, you can create an import library by following these steps:

    1. Use DUMPBIN /EXPORTS <.DLL file name> to obtain the list of exported symbols for the .DLL in question. The symbols appear in the "name" column of the table whose headings are "ordinal hint name."
    2. Create a .DEF file that contains an EXPORTS section with the names of the functions listed in the "name" column of the DUMPBIN output.
    3. For _cdecl functions, the symbol appears just as it would when used in the calling program. Just place this symbol in the EXPORTS section of the .DEF file.
    4. Use LIB /DEF:<.DEF file name> to generate the import library and exports file. The base name of the import library will be the base name of the .DEF file. Use /OUT: to control the output library name.


    http://msdn.microsoft.com/en-us/library/d91k01sh(v=vs.80).aspx
    http://support.microsoft.com/default.aspx?scid=kb;en-us;131313


    For OllyDbg 1.x all export functions were in _cdecl format and the above instructions were suitable. Modified PDK's and explanations were provided in the following links:

    http://www.ollydbg.de/whatsnew.htm
    http://nezumi-lab.org/blog/?p=151

    OllyDbg 2.x now has a mixture of _stdcall and _cdecl exported functions in plugin.h. If you try to link with an ollydbg.lib produced in the previous way you'll get compiler errors such as this when trying to compile the bookmark.c plugin example:

    error LNK2019: unresolved external symbol _Commentaddress@16 referenced in function _Bookmarkdraw

    I found that is was required to declare the stdcall function in the DEF file as follows:

    Commentaddress@16 @278

    Here is a useful article which sums up some of the differences in calling conventions for _stdcall and _cdecl for various compilers:

    http://wyw.dcweb.cn/stdcall.htm


    I guess the rest of the details are in the python script below. For those who are interested in that kind of thing you might read it easier from the zip file copy with syntax highlighting.

    There is one further modification of plugin.h for MSVC, two of the exported functions (Heapsort/Heapsortex) use the Borland _USERENTRY type in their parameter list which generates a compiler error. The solution is provided by the Borland defs.h file:

    _USERENTRY Specifies the calling convention the RTL expects user
    compiled functions to use (for callbacks)

    #define _USERENTRY __cdecl
    You simply need to add #define _USERENTRY __cdecl to the plugin.h file.


    All that's left is for the RE community to start updating old 1.x version plugins or creating new ones and adding them to the CRCETL here:

    http://www.woodmann.com/collaborative/tools/index.php/Category:OllyDbg_2.x_Extensions

    Cheers,
    Kayaker

    Code:
    # makedef.py
    
    # Generates a correct EXPORTS .DEF file for OllyDbg 2.x in MSVC format in order to
    # create the OLLYDBG.LIB file required for writing OllyDbg plugins
    
    
    # Instructions:
    
    # 1. Create a DUMPBIN.EXE /EXPORTS file for Ollydbg.exe, i.e.:
    #       C:\Program Files\Microsoft Visual Studio 10.0\VC>dumpbin /exports ollydbg.exe > olly_exports.txt
    
    # 2. Create a DEF file by running this python script on the file, 
    #    making sure the Ollydbg plugin.h file is in the same directory
    #       > python makedef.py olly_exports.txt
    
    # 3. Create a LIB file by running LIB.EXE /DEF on the output file from this script (ollydbg.def) 
    #       C:\Program Files\Microsoft Visual Studio 10.0\VC>lib /def:ollydbg.def /OUT:ollydbg.lib
    
    # 4. Compile your Ollydbg plugin linked to the lib file
    
    
    # In OllyDbg 2.x the plugin exports are a mixture of _cdecl and _stdcall. 
    
    # Cdecl functions can be declared in the DEF file as
    #       FunctionName @Ordinal
    
    # Stdcall functions must be declared in the DEF file in the decorated format
    #       FunctionName@<number of parameter bytes> @Ordinal
    
    
    
    # There is one further modification of plugin.h for MSVC, two of the exported functions (Heapsort/Heapsortex)
    # use the Borland _USERENTRY type in their parameter list which generates a compiler error.
    # The solution is provided by the Borland defs.h file:
    
    #   _USERENTRY      Specifies the calling convention the RTL expects user
    #                   compiled functions to use (for callbacks)
    
    #   #define _USERENTRY __cdecl
        
    # You simply need to add #define _USERENTRY __cdecl to the plugin.h file.
    
    ###################################################################################################
    
    
    import string, re, sys, os
    
    def main():    
        
        if len(sys.argv) < 2:
            sys.stderr.write("USAGE: %s <DUMPBIN /EXPORTS output filename>" % (sys.argv[0],))
            return 1
    
        if not os.path.exists(sys.argv[1]):
            sys.stderr.write("ERROR: File %r was not found!" % (sys.argv[1],))
            return 1        
        
        if not os.path.exists("plugin.h"):
            sys.stderr.write("ERROR: Ollydbg plugin.h file must be in same directory!")
            return 1 
            
    
    ###################################################################################################
      
        # PART 1: 
        # Extract all __stdcall ("stdapi") functions from plugin.h, determine the number of parameters for each,
        #   and create a list of them in the decorated format 
        #       FunctionName@<number of parameter bytes>, i.e. Absolutizepath@4
        #
        #   This list will be merged later with the rest of the undecorated __cdecl functions
        #   and exported variables to create a DEF file
        
    
        #########################################################
        #
        # Parse plugin.h to isolate STDAPI functions
        #
        #########################################################
        
    
        # List to hold original complete function declaration string
        
        list_fx = []
        
        # List to hold decorated 'function@parameters' export name string for __stdcall functions
        
        list_decorated = []    
            
        
        # Regex pattern to match Type portion of function string for removal, i.e. "stdapi (int)  "     
        
        # pattern_stdapi = re.compile(r"(?i)^stdapi.+?\)\s*")
        
        # RegexBuddy is my buddy ;)    
        # (?i)^stdapi.+?\)\s*
        # Options: case insensitive; ^ and $ match at line breaks
    
        pattern_stdapi = re.compile(r"""
            (?i)                    # Match the remainder of the regex with the options: case insensitive (i) <?i>
            ^                       # Assert position at the beginning of a line (at beginning of the string or after a line break character) <^>
            stdapi                  # Match the characters "stdapi" literally <stdapi>
            .+?                     # Match any single character that is not a line break character <.+?>
                                    #   Between one and unlimited times, as few times as possible, expanding as needed (lazy) <+?>
            \)                      # Match the character ")" literally <\)>
            \s*                     # Match a single character that is a "whitespace character" (spaces, tabs, line breaks, etc.) <\s*>
                                    #   Between zero
    ...
    Categories
    Uncategorized
    Attached Thumbnails Attached Files