PDA

View Full Version : OllyDbg 2.x Plugin Writing - Creating the OLLYDBG.LIB file


Kayaker
August 25th, 2012, 21:41
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:


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."
Create a .DEF file that contains an EXPORTS section with the names of the functions listed in the "name" column of the DUMPBIN output.
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.
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:

Quote:
_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 /defllydbg.def /OUTllydbg.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 and unlimited times, as many times as possible, giving back as needed (greedy) <*>
""", re.VERBOSE)


# Regex pattern to split function into separate Name and (Parameters) strings

pattern_fx = re.compile(r"(?i)^(.*)(\(.*\))"

# (?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) <^>
# Match the regular expression below and capture its match into backreference number 1 <(.*)>
# Match any single character that is not a line break character <.*>
# Between zero and unlimited times, as many times as possible, giving back as needed (greedy) <*>
# Match the regular expression below and capture its match into backreference number 2 <(\(.*\))>
# Match the character "(" literally <\(>
# Match any single character that is not a line break character <.*>
# Between zero and unlimited times, as many times as possible, giving back as needed (greedy) <*>
# Match the character "" literally <\)>



# Open plugin.h for reading

f = open("plugin.h", "r"

# Read each line

for line in f:

# Remove any leading/trailing whitespace characters

fx = line.strip()

if fx.startswith('stdapi'):

while True:

# Some functions are split over 2 or more lines, find ending ";"

if not fx.endswith(';'):

# Concatenate with next line until complete function is found

fx = fx + f.next().strip()

if fx.endswith(';'):

# Found complete function

break


# Confirm string begins with "stdapi (type)"

m = pattern_stdapi.match(fx)

if m:

# Pattern match found

# print 'Match found: ', m.group() ### Match found: stdapi (int)

# Remove "stdapi (type)" pattern from function, leaving raw function definition

fx = pattern_stdapi.sub("", fx)

# Store remaining portion of function string in a List

list_fx.append(fx)

else:

print 'No match'


# We have the complete functions, cleaned up and temporarily stored, close plugin.h

f.close()



#########################################################
#
# Determine number of parameters for each function
#
#########################################################


# Sort list alphabetically

list_fx.sort()

num_params = 0
num_param_bytes = 0
num_doubles = 0

for item in list_fx:

# print item ### Absolutizepath(wchar_t *path);

m = pattern_fx.match(item)

if m:

# print 'Match found: ', m.group(0) ## Absolutizepath(wchar_t *path)
# print 'Match found: ', m.group(1) ## Absolutizepath
# print 'Match found: ', m.group(2) ## (wchar_t *path)

# Copy capturing group to regular string

fxname = m.group(1)


# Add function name + @parameter count to List

if m.group(2) == "(void)":

# print m.group(0) + " has " + str(num_params) + " parameters"
### Checkfordebugevent(void) has 0 parameters

num_params = 0


# There are two special situations where our regex pattern doesn't match,
# Heapsort and Heapsortex both have non-standard parameter strings
# Rather than trying to come up with a protocol to deal with it, just handle it manually
#
# Note that these two functions also require the following to be added to the plugin.h file (from Borland defs.h):
# #define _USERENTRY __cdecl

elif fxname.startswith("Heapsort(":

# Heapsort(void *data,const int count,const int size,int (_USERENTRY *compare)(const void *,const void *));

# borked match
# print m.group(1) ### Heapsort(void *data,const int count,const int size,int (_USERENTRY *compare)

fxname = "Heapsort"

num_params = 4

elif fxname.startswith("Heapsortex(":

# Heapsortex(void *data,const int count,const int size,int (_USERENTRY *compareex)(const void *,const void *,ulong),ulong lp);

fxname = "Heapsortex"

num_params = 5

else:

# Number of DWORD size parameters can be determined by counting the number of commas and adding 1

num_params = m.group(2).count("," + 1

# print m.group(0) + " has " + str(num_params) + " parameters"
### Absolutizepath(wchar_t *path) has 1 parameters

# For DOUBLEWORD size parameters we need to add 4 bytes

num_doubles = m.group(2).count("double"

if num_doubles:

num_params = num_params + num_doubles

# print m.group(0) + " has " + str(num_doubles) + " DOUBLEWORD parameters"
### Printfloat10(wchar_t *s,long double ext) has 1 DOUBLEWORD parameters


# Convert number of parameters to bytes

num_param_bytes = num_params * 4

# Write function name + parameter bytes decoration to List

list_decorated.append(string.ljust(fxname + "@" + str(num_param_bytes), 40))

else:

print 'No match'



# We should now have a list of the __stdcall function definitions (327 of them!)
# ready for merging with the rest of the exports

# for idx, item in enumerate(list_decorated):

# print idx, item ### 0 Absolutizepath@4
### 1 Activatetablewindow@4


###################################################################################################


# PART 2:
# Extract list of all export functions from DUMPBIN /EXPORTS output file that we haven't already dealt with,
# in preparation for producing a properly formatted DEF file


#########################################################
#
# Extract export functions from DUMPBIN /EXPORTS output
#
#########################################################


# List to hold undecorated export strings (__cdecl functions and exported variables)

list_undecorated = []


# Regex pattern to find "header" for list of EXPORTS in dumpbin output in order to find starting line for further processing
# ordinal hint RVA name
#
# 34 0 00005D0C Absolutizepath

pattern = re.compile(r"(?i)\bordinal.*\bhint.*\bRVA.*name"

# pattern = re.compile(r"""
# (?i) # Match the remainder of the regex with the options: case insensitive (i) <?i>
# \bordinal # Assert position at a word boundary <\b>
# # Match the characters "ordinal" literally <ordinal>
# .* # Match any single character that is not a line break character <.>
# # Between zero and unlimited times, as many times as possible, giving back as needed (greedy) <*>
# \bhint.*\bRVA.*name # repeat
# """, re.VERBOSE)


# Open DUMPBIN /EXPORTS output file

f = open(sys.argv[1], "r"

# Read the whole file into memory

lines = f.readlines()

f.close()


# Find starting line of exports listing

for i, line in enumerate(lines):

if pattern.search(line):

startpos = i + 2



for i in xrange(startpos, len(lines)):

# Read line

line = lines[I]

# Check for empty line and stop

if not line.strip():

break

else:

x = line.split()

# print x ### ['34', '0', '00005D0C', 'Absolutizepath']
# print x[0] ### 34
# print x[1] ### 0
# print x[2] ### 00005D0C
# print x[3] ### Absolutizepath

# Check if this function has already been handled above
# i.e. it's a __stdcall function we've already decorated with the @parameter qualifier and stored in List list_decorated[]


NEWFUNCTION = True

# Iterate both the index and the item

for idx, entry in enumerate(list_decorated):

# Test if this string exists

if x[3] in entry:

# print "Function exists at index " + str(idx) + " as " + list_decorated[idx]
### Function exists at index 0 as Absolutizepath@4

# Add the ordinal value to the function@parameters string we already have

list_decorated[idx] = list_decorated[idx] + "@" + x[0]

NEWFUNCTION = False

break


if NEWFUNCTION == True:

# print x[3] + " is a new export" ### Addtolist is a new export

# Ollydbg exported variables preceded by an underscore ("oddata" also generate an MSVC compiler error
# Remove underscores on these functions - they begin with small caps

# This "slice" of string x[3] will return true for underscored small cap functions

if str.islower(x[3][:2]):

# print x[3] ### _aqueue

# Remove underscore

x[3] = x[3].lstrip("_"


# Add function and ordinal value to a new list

list_undecorated.append(string.ljust(x[3], 40) + "@" + x[0])



# Now merge the 2 unique lists together and we should have the full list in proper DEF format

li_def = list_decorated + list_undecorated

li_def.sort()

for item in li_def:

print item


###################################################################################################


# PART 3: Create the DEF file

# Open output file for writing

output = open("ollydbg.def", "w"
print >> output, "NAME OllyDbg"
print >> output, "EXPORTS"

for item in li_def:

print >> output, " " + item

# Close ollydbg.def

output.close()


###################################################################################################

if __name__ == '__main__':
main()
OllyDbg2.x_MSVC_PDK.zip (93.9 KB)

blabberer
August 26th, 2012, 08:16
i have neither read the entire post nor downloaded the zip

but i have to congratualte you on beating me by a big felines whisker



Code:


set DBGSDK_INC_PATH=F:\windbg\sdk\inc
set DBGSDK_LIB_PATH=F:\windbg\sdk\lib
set DBGLIB_LIB_PATH=F:\windbg\sdk\lib

@CALL "C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" x86
REM echo ollydbg | set /p progname=" enter name of exe / dll / etc for which you want to make import library ?progname:\>"
set progname=ollydbg
echo EXPORTS > %progname%.def
echo. >> %progname%.def
pause
dumpbin /exports %progname%.exe | sed 1,19d | sed /Summary/,$d | sed /./!d | sed s/.*\x20// >> %progname%.def
pause
lib /DEF:%progname%.def /MACHINE:x86 /OUTllydbg201dvc8.lib
pause
pause
nmake -I -f bookmark.mak
pause




i was trying to make out the reason for undeclared function name shit but it seems you won


Code:



D:\odbg_201b2_18_8_12_lib>dir /b
bookmark.MAK
dbghelp.dll
makeimplib.bat
MyBookmark.c
ollydbg.exe
ollydbg.ini
orig
plugin.h

D:\odbg_201b2_18_8_12_lib>makeimplib.bat

D:\odbg_201b2_18_8_12_lib>set DBGSDK_INC_PATH=F:\windbg\sdk\inc

D:\odbg_201b2_18_8_12_lib>set DBGSDK_LIB_PATH=F:\windbg\sdk\lib

D:\odbg_201b2_18_8_12_lib>set DBGLIB_LIB_PATH=F:\windbg\sdk\lib
Setting environment for using Microsoft Visual Studio 2008 x86 tools.
C:\Program Files\Microsoft SDKs\Windows\v7.1\lib;C:\Program Files\Microsoft Visu
al Studio 9.0\VC\LIB;C:\Program Files\Microsoft SDKs\Windows\v7.1\lib;
Press any key to continue . . .
Press any key to continue . . .
Microsoft (R) Library Manager Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.

Creating library ollydbg201dvc8.lib and object ollydbg201dvc8.exp
Press any key to continue . . .
Press any key to continue . . .

Microsoft (R) Program Maintenance Utility Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.

cl.exe @C:\DOCUME~1\Admin\LOCALS~1\Temp\nm4.tmp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

cl /Zp1 /EHsc /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp".\MyBookMark.pc
h" /I"C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE;C:\Program Files\M
icrosoft SDKs\Windows\v7.1\include;C:\Program Files\Microsoft Visual Studio 9.0\
VC\INCLUDE;C:\Program Files\Microsoft SDKs\Windows\v7.1\include;;F:\windbg\sdk\inc" /J /FD /c "MyBookMark.c"

MyBookMark.c
MyBookMark.c(495) : warning C4047: 'return' : 'DWORD' differs in levels of indir
ection from 't_menu [4]'
MyBookMark.c(498) : warning C4047: 'return' : 'DWORD' differs in levels of indir
ection from 't_menu [31]'
MyBookMark.c(499) : warning C4047: 'return' : 'DWORD' differs in levels of indir
ection from 'void *'
link.exe @C:\DOCUME~1\Admin\LOCALS~1\Temp\nm5.tmp
Creating library .\MyBookMark.lib and object .\MyBookMark.exp
MyBookMark.obj : error LNK2019: unresolved external symbol _Commentaddress@16 re
ferenced in function _Bookmarkdraw
MyBookMark.obj : error LNK2019: unresolved external symbol _Getanalysercomment@1
6 referenced in function _Bookmarkdraw
MyBookMark.obj : error LNK2019: unresolved external symbol _FindnameW@16 referen
ced in function _Bookmarkdraw
MyBookMark.obj : error LNK2019: unresolved external symbol _Simpleaddress@16 ref
erenced in function _Bookmarkdraw
MyBookMark.obj : error LNK2019: unresolved external symbol _Disasm@32 referenced
in function _Bookmarkdraw
MyBookMark.obj : error LNK2019: unresolved external symbol _Finddecode@8 referen
ced in function _Bookmarkdraw
MyBookMark.obj : error LNK2019: unresolved external symbol _Readmemory@16 refere
nced in function _Bookmarkdraw
MyBookMark.obj : error LNK2019: unresolved external symbol _Setcpu@24 referenced
in function _Bookmarkfunc
MyBookMark.obj : error LNK2019: unresolved external symbol _Getsortedbyselection
@8 referenced in function _Bookmarkfunc
MyBookMark.obj : error LNK2019: unresolved external symbol _Activatetablewindow@
4 referenced in function _Mopenbookmarks
MyBookMark.obj : error LNK2019: unresolved external symbol _Createtablewindow@24
referenced in function _Mopenbookmarks
MyBookMark.obj : error LNK2019: unresolved external symbol _Suspendallthreads@0
referenced in function _Mabout
MyBookMark.obj : error LNK2019: unresolved external symbol __imp__hwollymain ref
erenced in function _Mabout
MyBookMark.obj : error LNK2019: unresolved external symbol _Resumeallthreads@0 r
eferenced in function _Mabout
MyBookMark.obj : error LNK2019: unresolved external symbol _Pluginmodulechanged@
4 referenced in function _Msetmark
MyBookMark.obj : error LNK2019: unresolved external symbol _Addsorteddata@8 refe
renced in function _Msetmark
MyBookMark.obj : error LNK2019: unresolved external symbol _Findsorteddata@12 re
ferenced in function _Msetmark
MyBookMark.obj : error LNK2019: unresolved external symbol _Deletesorteddata@12
referenced in function _Mdeletemark
MyBookMark.obj : error LNK2019: unresolved external symbol _Getsortedbyindex@8 r
eferenced in function _ODBG2_Plugindump
MyBookMark.obj : error LNK2019: unresolved external symbol __imp__restorewinpos
referenced in function _ODBG2_Plugininit
MyBookMark.obj : error LNK2019: unresolved external symbol _Createsorteddata@24
referenced in function _ODBG2_Plugininit
MyBookMark.obj : error LNK2019: unresolved external symbol _Deletesorteddatarang
e@12 referenced in function _ODBG2_Pluginreset
MyBookMark.obj : error LNK2019: unresolved external symbol _Destroysorteddata@4
referenced in function _ODBG2_Plugindestroy
MyBookMark.obj : error LNK2019: unresolved external symbol _Deletenonconfirmedso
rteddata@4 referenced in function _ODBG2_Pluginnotify
MyBookMark.obj : error LNK2019: unresolved external symbol _Confirmsorteddata@8
referenced in function _ODBG2_Pluginnotify
MyBookMark.obj : error LNK2019: unresolved external symbol _Pluginsaverecord@16
referenced in function _ODBG2_Pluginsaveudd
.\MyBookMark.dll : fatal error LNK1120: 26 unresolved externals
Press any key to continue . . .

D:\odbg_201b2_18_8_12_lib>dir /b
bookmark.MAK
dbghelp.dll
makeimplib.bat
MyBookmark.c
MyBookMark.exp
MyBookMark.lib
MyBookMark.obj
MyBookMark.pdb
ollydbg.def
ollydbg.exe
ollydbg.ini
ollydbg201dvc8.exp
ollydbg201dvc8.lib
orig
plugin.h
vc90.idb

D:\odbg_201b2_18_8_12_lib>



let me download it and see


Quote:
[Originally Posted by Kayaker;93169]While the current version of OllyDbg (2.01e as of writing) is still in development, it now has full plugin API support.



edit

btw just using the lib wont seem to compile the bookmark,c / plugin.h that comes along

there seems to be some other problems as well

the function pentry( type ) seems to take int blah blah etc but doesnt seem to take * to int / blah * / t_menu * with msvc

also all the swprintf needs a count parameter in bookmark.c which is missing either we need to add the count param or we need to define the _no_deprecat_whatever

to reach to the stage i posted above

Kayaker
August 26th, 2012, 13:24
That's good blabberer, it just goes to show there's more than one way to skin a large feline

I was going to get into the t_menu and swprintf thing, but didn't want to complicate things at first and I figured it would come out.

For t_menu it seems to have to do with the structure declaration. In the original it's like this:

Code:
typedef struct t_menu {
...

} t_menu;


I changed it to the more standard C++ declaration I'm used to:

Code:
typedef struct _t_menu {
...

} t_menu, *pt_menu;


The erroring definition is then changed to this:

Code:
// pentry (t_menu *) ODBG2_Pluginmenu(wchar_t *type);

pentry (pt_menu) ODBG2_Pluginmenu(wchar_t *type);


And used like this:

Code:
// extc t_menu * _export cdecl ODBG2_Pluginmenu(wchar_t *type) {

extc pt_menu _export cdecl ODBG2_Pluginmenu(wchar_t *type) {
...
return NULL;
};


If you change to a .cpp main file rather than a .c one, this doesn't quite work as described, an additional redefinition error comes up, so you also need to change the submenu struct def within the main def from t_menu to _t_menu, for the way I redefined it at least.

Code:

typedef struct _t_menu {
wchar_t *name;
wchar_t *help;
int shortcutid;
MENUFUNC *menufunc;
struct _t_menu *submenu;
union {
ulong index;
HMENU hsubmenu;
};
} t_menu, *pt_menu;



For swprintf, it's as you mentioned. The problem seems to be that there are 2 definitions of the function, one which explicitly uses a 'size' parameter and one which doesn't.

Code:
int swprintf(
wchar_t *buffer,
const wchar_t *format [,
argument] ...
);

swprintf(
wchar_t *buffer,
size_t count,
const wchar_t *format [,
argument]...
);


http://msdn.microsoft.com/en-us/library/ybk95axf(v=vs.71).aspx


I don't really quite understand their different uses, but Olly seems to use the first type, where the string size can actually be added to the buffer parameter, yet still preventing buffer overruns.

Take a look at this sequence. Assuming 'n' returns the StrcopyW string length, it's then added to the first parameter in the next instruction. This didn't work, so I separated them, changing from a 3 parameter to 4 parameter swprintf function.

Code:
n=StrcopyW(s,TEXTLEN,L"Alt+";

// m=swprintf(s+n,L"%i",pmark->index);
m=swprintf(s,n,L"%i",pmark->index);


Where it wasn't clear what the second parameter should be I just used TEXTLEN for simplicity

Code:

// swprintf(name,L"Set bookmark %i",index);
swprintf(name,TEXTLEN,L"Set bookmark %i",index);



Oh, there are other errors as well if using a *.cpp file. The definition uchar data[0] gives this error which I haven't found a solution to yet:

plugin.h(3256): warning C4200: nonstandard extension used : zero-sized array in struct/union
Cannot generate copy-ctor or copy-assignment operator when UDT contains a zero-sized array


Code:
typedef struct t_rawdata {
...
#ifdef __cplusplus
uchar data[0];
#endif
} t_rawdata;



There must be a simpler way to deal with all this than having to make piece by piece plugin.h changes. Well, yeah, just code the damn plugins in the environment they were developed under, Borland But that's not really what we're going for here.

Kayaker
August 26th, 2012, 21:07
Quote:
Oh, there are other errors as well if using a *.cpp file. The definition uchar data[0] gives this error which I haven't found a solution to yet:

plugin.h(3256): warning C4200: nonstandard extension used : zero-sized array in struct/union
Cannot generate copy-ctor or copy-assignment operator when UDT contains a zero-sized array


Code:
typedef struct t_rawdata {
...
#ifdef __cplusplus
uchar data[0];
#endif
} t_rawdata;


When in doubt, play ostrich, bury your head in the sand so you don't see it

Code:
typedef struct t_rawdata {
...
#ifdef __cplusplus

#pragma warning( push )
#pragma warning( disable : 4200 )

uchar data[0];

#pragma warning( pop )

#endif
} t_rawdata;

aqrit
August 27th, 2012, 11:06
(t_menu *) error
move "_export" to in front of the type in "pentry" and at the function

Kayaker
August 27th, 2012, 12:58
Thanks agrit, that works.

Borland is obviously a lot more forgiving, it seems to accept either syntax.

#define pentry(type) extern type _export cdecl
#define pentry(type) extern _export type cdecl

blabberer
August 28th, 2012, 17:10
did anyone download the attachemnt ? i cant seem to download it

anyway the five lines below will create the functionnames with argbytes appended for stdapi



you would need the gnuwin32 ports of sed / grep / awk / wc /paste for windows in path

Code:


sed -e :a -e N -e $!ba -e s/,\n/,/g plugin.h | grep "stdapi (" | sed "s/.*api (//g" | sed s/.*)\x20//g > plugfunc1.txt | wc -l plugfunc1.txt & grep -c ; plugfunc1.txt
awk "BEGIN { FS = \"(\" };{ print $1\"@\" }" plugfunc1.txt > funcname.txt
awk "BEGIN { FS = \",\" };{ print NF*4 }" plugfunc1.txt > args.txt
paste funcname.txt args.txt > funcwitharg.txt
wc -l funcname.txt args.txt funcwitharg.txt
sed "s/ *//" funcwitharg.txt | sed "s/$ *//g" |sed "s/\t//g" > ollydbg.def
del *.txt



result as follows

Code:



D:\odbg_201b2_18_8_12_lib\sedex>dir /b
plugin.h
scriptstdapi.bat

D:\odbg_201b2_18_8_12_lib\sedex>scriptstdapi.bat

D:\odbg_201b2_18_8_12_lib\sedex>sed -e :a -e N -e $!ba -e s/,\n/,/g plugin.h |
grep "stdapi (" | sed "s/.*api (//g" | sed s/.*)\x20//g 1>plugfunc1.txt
| wc -l plugfunc1.txt & grep -c ; plugfunc1.txt
327 plugfunc1.txt 327 lines available
327 all 327 lines end with semicolon so must be ok i think

D:\odbg_201b2_18_8_12_lib\sedex>awk "BEGIN { FS = \"(\" };{ print $1\"@\" }" plu
gfunc1.txt 1>funcname.txt

D:\odbg_201b2_18_8_12_lib\sedex>awk "BEGIN { FS = \",\" };{ print NF*4 }" plugfu
nc1.txt 1>args.txt

D:\odbg_201b2_18_8_12_lib\sedex>paste funcname.txt args.txt 1>funcwitharg.txt

D:\odbg_201b2_18_8_12_lib\sedex>wc -l funcname.txt args.txt funcwitharg.txt
327 funcname.txt
327 args.txt
327 funcwitharg.txt so the pasted file also contain 327 lines should it be ok ? i think so
981 total

D:\odbg_201b2_18_8_12_lib\sedex>sed "s/ *//" funcwitharg.txt | sed "s/$ *//g"
| sed "s/\t//g" 1>ollydbg.def

D:\odbg_201b2_18_8_12_lib\sedex>del *.txt

D:\odbg_201b2_18_8_12_lib\sedex>type ollydbg.def | more
Stringfromini@16
Filefromini@12
Filetoini@8
Deleteinisection@8
Getfromsettings@8
Addtosettings@8
Replacegraphs@20
Unicodetoascii@16
Asciitounicode@16
Unicodetoutf@16
Utftounicode@16
Unicodebuffertoascii@4
Iszero@8
Guidtotext@8
Memalloc@8
Memfree@4
Mempurge@16
Memdouble@20
Virtalloc@8
Virtfree@4
Broadcast@12
Browsefilename@28
Browsedirectory@12
Relativizepath@4
^C
D:\odbg_201b2_18_8_12_lib\sedex>



edit this really seems to work i can concentrate on adding varapis too it seems

well down to 7 unresolved from 26 unresolved

Code:



D:\odbg_201b2_18_8_12_lib>dir /b
bookmark.MAK
dbghelp.dll
makeimplib.bat
MyBookmark.c
ollydbg.exe
ollydbg.ini
orig
plugin.h
sedex

D:\odbg_201b2_18_8_12_lib>makeimplib.bat

D:\odbg_201b2_18_8_12_lib>set DBGSDK_INC_PATH=F:\windbg\sdk\inc

D:\odbg_201b2_18_8_12_lib>set DBGSDK_LIB_PATH=F:\windbg\sdk\lib

D:\odbg_201b2_18_8_12_lib>set DBGLIB_LIB_PATH=F:\windbg\\sdk\lib
Setting environment for using Microsoft Visual Studio 2008 x86 tools.
C:\Program Files\Microsoft SDKs\Windows\v7.1\lib;
Press any key to continue . . .
327 plugfunc1.txt
327
327 funcname.txt
327 args.txt
327 funcwitharg.txt
981 total
Press any key to continue . . .
Microsoft (R) Library Manager Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.

Creating library ollydbg201dvc8.lib and object ollydbg201dvc8.exp
Press any key to continue . . .
Press any key to continue . . .

Microsoft (R) Program Maintenance Utility Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.

cl.exe @C:\DOCUME~1\Admin\LOCALS~1\Temp\nm14D.tmp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

cl /Zp1 /EHsc /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp".\MyBookMark.pc
h" /I"C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE;C:\Program Files\M
icrosoft SDKs\Windows\v7.1\include;;F:\windbg\sdk\inc" /J /FD /c "MyB
ookMark.c"

MyBookMark.c
MyBookMark.c(495) : warning C4047: 'return' : 'DWORD' differs in levels of indir
ection from 't_menu [4]'
MyBookMark.c(498) : warning C4047: 'return' : 'DWORD' differs in levels of indir
ection from 't_menu [31]'
MyBookMark.c(499) : warning C4047: 'return' : 'DWORD' differs in levels of indir
ection from 'void *'
link.exe @C:\DOCUME~1\Admin\LOCALS~1\Temp\nm14E.tmp
Creating library .\MyBookMark.lib and object .\MyBookMark.exp
MyBookMark.obj : error LNK2019: unresolved external symbol _StrcopyW referenced
in function _Bookmarkdraw
MyBookMark.obj : error LNK2019: unresolved external symbol _Writetoini reference
d in function _Mshowbookmarks
MyBookMark.obj : error LNK2019: unresolved external symbol _Suspendallthreads@0
referenced in function _Mabout
MyBookMark.obj : error LNK2019: unresolved external symbol __imp__hwollymain ref
erenced in function _Mabout
MyBookMark.obj : error LNK2019: unresolved external symbol _Resumeallthreads@0 r
eferenced in function _Mabout
MyBookMark.obj : error LNK2019: unresolved external symbol __imp__restorewinpos
referenced in function _ODBG2_Plugininit
MyBookMark.obj : error LNK2019: unresolved external symbol _Getfromini reference
d in function _ODBG2_Plugininit
.\MyBookMark.dll : fatal error LNK1120: 7 unresolved externals
Press any key to continue . . .

D:\odbg_201b2_18_8_12_lib>


Kayaker
August 28th, 2012, 18:37
Quote:
[Originally Posted by blabberer;93203]did anyone download the attachemnt ? i cant seem to download it


My bad. After I wrote the original Blog post and then it got imported to this forum, I updated the zip attachment in the Blog with a minor edit, but this thread had the old attachment Id, which is really only a link back to the original in the Blog. Fixed. Thanks for mentioning it.

I'm glad you're coming up with an alternative solution Blabs. So what you're saying then is - "who needs stinking Python when you've got Sed". Is that it?

blabberer
August 28th, 2012, 22:09
Quote:
So what you're saying then is - "who needs stinking Python when you've got Sed". Is that it?


wrong absolutely wrong you got it WRONG WRONG WRONG

sed stinks

Pythorn PRICKS

Kayaker
August 30th, 2012, 12:27
Thank you Oleh!

Well, the latest version of OllyDbg (2.01f) just came out, complete with compiler specific ollydbg.lib files, which addresses every issue raised here.

Stdapi functions are now declared as __cdecl instead of __stdcall, removing the <@parameter bytes> requirement, the pentry definition has been fixed, #define _CRT_SECURE_NO_DEPRECATE is used against the swprintf/wscpy warnings, and even the t_rawdata structure has been redefined to remove that error.

The bookmark plugin compiles perfectly in VisualStudio2010 as either a .c or .cpp file.

You can't ask for better response than that. We love you

Regards,
Kayaker

blabberer
August 31st, 2012, 18:58
now that oleh has provided a perfectly fine lib file i cooked up a template source
the compiles in vs 2010 express with /w4 / WX

it contains the bare minimum code that is required
though only PluginQuery() is indicated as mandatory function
PluginMenu() too seeem to be mandatory else the
Plugin tab remains grey
(the log window has an entry that the plugin was active dont know why plugin tab
remains grayed out)

if a pluginmenu function is implemented with a t_menu and MENUFUNC
the plugin tab gets alive and the plugin seem to work properly

here is the code for the template and the package is attached to the post as well

Code:


#define _CRT_SECURE_NO_DEPRECATE
#include <windows.h>
#include <string.h>
#include "plugin.h"
HINSTANCE hdllinst;
wchar_t TempString[] = {L"Plugin Template For ODBG 2.00.01"};
BOOL WINAPI DllEntryPoint( HINSTANCE hi, DWORD reason, LPVOID reserved ) {
UNREFERENCED_PARAMETER( reserved );
if (reason==DLL_PROCESS_ATTACH)
hdllinst=hi;
return 1;
};
static int Mabout( t_table *pt, wchar_t *name, ulong index, int mode ) {
UNREFERENCED_PARAMETER( pt );
UNREFERENCED_PARAMETER( name );
UNREFERENCED_PARAMETER( index );
if (mode==MENU_VERIFY)
return MENU_NORMAL;
else if (mode==MENU_EXECUTE) {
Resumeallthreads();
MessageBox( hwollymain, TempString, TempString, MB_OK|MB_ICONINFORMATION );
Suspendallthreads();
return MENU_NOREDRAW;
};
return MENU_ABSENT;
};
static t_menu mainmenu[] = {

{ L"|Template",
TempString,
K_NONE, Mabout, NULL, 0 },
{ NULL, NULL, K_NONE, NULL, NULL, 0 }
};
extc int __cdecl ODBG2_Pluginquery( int ollydbgversion, ulong *features,
wchar_t pluginname[SHORTNAME], wchar_t pluginversion[SHORTNAME] ) {
UNREFERENCED_PARAMETER( features );
if (ollydbgversion<201)
return 0;
wcscpy( pluginname, L"Template" );
wcscpy( pluginversion, L"2.00.01" );
return PLUGIN_VERSION;
};
extc t_menu * __cdecl ODBG2_Pluginmenu( wchar_t *type ) {
if (wcscmp(type,PWM_MAIN)==0)
return mainmenu;
else if (wcscmp(type,PWM_DISASM)==0)
return mainmenu;
return NULL;
};



the sln and vcxproj files are modified to be built in release mode
with /W4 /WX enabled

and a small bat file used to BUILD the project wit msbuild and test the plugin loading

Code:


del *.dll
@call "C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86
dir /b
msbuild
copy release\template.dll . /y
rm -rd release
copy Template.dll ..\..\..\odbg201f\. /y
..\..\..\odbg201f\ollydbg.exe
dir /b
pause



here is the output

Code:

ODBG2PLUGIN:\>BuildPlugin.bat

ODBG2PLUGIN:\>del *.dll
Setting environment for using Microsoft Visual Studio 2010 x86 tools.
BuildPlugin.bat
ODBGG2PluginTemplate.cpp
ODBGG2PluginTemplate.sln
ODBGG2PluginTemplate.vcxproj
ollydbg.lib
plugin.h
Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.1]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 01/09/2012 04:46:22.
Project "C:\Documents and Settings\Admin\My Documents\ollydbg2beta\plug201f\vc2
010\Plugin_Template_For_ODBG_20001\ODBGG2PluginTemplate.sln" on node 1 (default
targets).
ValidateSolutionConfiguration:
Building solution configuration "Debug|Win32".
Project "C:\Documents and Settings\Admin\My Documents\ollydbg2beta\plug201f\vc2
010\Plugin_Template_For_ODBG_20001\ODBGG2PluginTemplate.sln" (1) is building "C
:\Documents and Settings\Admin\My Documents\ollydbg2beta\plug201f\vc2010\Plugin
_Template_For_ODBG_20001\ODBGG2PluginTemplate.vcxproj" (2) on node 1 (default t
argets).
PrepareForBuild:
Creating directory "Release\".
InitializeBuildStatus:
Creating "Release\Template.unsuccessfulbuild" because "AlwaysCreate" was spec
ified.
ClCompile:
C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\CL.exe /c /Zi /nologo /W
4 /WX /O2 /Oy- /D WIN32 /D NDEBUG /D _WINDOWS /D _USRDLL /D _WINDLL /D _UNICO
DE /D UNICODE /Gm- /EHsc /MT /Zp1 /GS /fprecise /Zc:wchar_t /Zc:forScope /F
o"Release\\" /Fd"Release\vc100.pdb" /Gd /TP /analyze- /errorReport:queue ODBG
G2PluginTemplate.cpp /J
ODBGG2PluginTemplate.cpp
Link:
C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\link.exe /ERRORREPORT:QU
EUE /OUT:"Release\Template.dll" /INCREMENTAL:NO /NOLOGO kernel32.lib user32.l
ib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib ole
aut32.lib uuid.lib odbc32.lib odbccp32.lib /MANIFEST /ManifestFile:"Release\T
emplate.dll.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='
false'" /DEBUG /PDB:"C:\Documents and Settings\Admin\My Documents\ollydbg2bet
a\plug201f\vc2010\Plugin_Template_For_ODBG_20001\Release\Template.pdb" /SUBSY
STEM:WINDOWS /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"Relea
se\Template.lib" /MACHINE:X86 /DLL Release\ODBGG2PluginTemplate.obj
ollydbg.lib user32.lib

Creating library Release\Template.lib and object Release\Template.exp
ODBGG2PluginTemplate.vcxproj -> C:\Documents and Settings\Admin\My Documents\
ollydbg2beta\plug201f\vc2010\Plugin_Template_For_ODBG_20001\Release\Template.
dll
Manifest:
C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\mt.exe /nologo /verbose /ou
tputresource:"Release\Template.dll;#2" /manifest Release\Template.dll.interme
diate.manifest
FinalizeBuildStatus:
Deleting file "Release\Template.unsuccessfulbuild".
Touching "Release\Template.lastbuildstate".
Done Building Project "C:\Documents and Settings\Admin\My Documents\ollydbg2bet
a\plug201f\vc2010\Plugin_Template_For_ODBG_20001\ODBGG2PluginTemplate.vcxproj"
(default targets).

Done Building Project "C:\Documents and Settings\Admin\My Documents\ollydbg2bet
a\plug201f\vc2010\Plugin_Template_For_ODBG_20001\ODBGG2PluginTemplate.sln" (def
ault targets).


Build succeeded.
0 Warning(s)
0 Error(s)

Time Elapsed 00:00:01.43
1 file(s) copied.
1 file(s) copied.
BuildPlugin.bat
ODBGG2PluginTemplate.cpp
ODBGG2PluginTemplate.sln
ODBGG2PluginTemplate.vcxproj
ollydbg.lib
plugin.h
Template.dll
Press any key to continue . . .
ODBG2PLUGIN:\>


here is the package