http://www.ollydbg.de/Loaddll.htm
refer to : http://bbs.pediy.com/showthread.php?s=&threadid=40211

调试DLL 
by oooooooo 
原创。02/28/2007 ver1.0
译者按: (In the debugging process, most of the time the crucial functions are resided in the DLL instead of an independent exe file. So the understand of the debugging DLL file is very important. In the article, the debugging procedure is updated to Windows XP SP2.  )

实例1: MessageBox函数 
实例 2: wsprintf  函数
详文及源码 

   ollydbg1.10可以调试独立的DLL. Windows 无法直接调用DLL,ollydbg 利用loaddll.exe间接调用 DLL.这个程序保存在压缩包里。如果你正尝试打开动态链接库文件, ollydbg会自动调用loaddll.exe 并且传递动态链接库文件名作为参数. 
   借助 loaddll,你可以调用由动态链接库输出的函数.我会通过在user32.dll 中的Windows' API wsprintf函数MessageBox函数来 演示这一功能. 
实例1: MessageBox函数 
    1象调用普通可执行文件一样调用DLL, OllyDbg 发出警告: 

   当然,我们在回答"Yes". Ollydbg 用loaddl调入动态链接库, 停在主程序窗口循环之前. 断点地址标示firstbp. 然后ollydbg分析和显示它的反汇编代码.注意当载入DLL内存时, Windows OS自动执行DLL的启动代码。
    2从主菜单,选择"Debug|Call DLL export"/ "调试|调用DLL出口". 出现的对话框非模态(non-modal) , 你们还可以调用OllyDbg 各种功能. 你可以浏览代码和数据,设置断点,修改内存等. 

    3.选择想调用的函数.我们将首先试MessageBox函数.  注意这个名字是通用的, 实际上有ASCII代码版本MessageBoxA和UNICODE版本MessageBoxW. 让我们试试UNICODE版本. 当我们选择它, 右侧长方形内容为: Number of arguments: 4参数数目: 4. Ollydbg 通过函数结尾代码RET 10正确识别参数个数. RET nnn是典型的PASCAL 函数调用规定 (参数入栈次序、第一个参数最后入栈, 被调用函数平衡堆栈). 大部分Windows' API 都是PASCAL 调用方式。

    4. 设置参数数目. 就这个例子而言,这是没有必要的,因为ollydbg已经知道MessageBoxW需要多少参数. 当然,你可以通过点击左边相应控件checkbox改写参数个数. 

    5. 填写各个参数. 这一dialog对话框支持多达10 个参数. 参数是任何不使用寄存器的有效表达式。如果操作数指向内存, 在参数右边的窗口会显示内存的内容。 loaddll.exe保存10个内存缓冲区, 每个1K 、从ARG1标记到Arg10 , 你可以自由使用. 另外,对话框 支持两个假名(pseudovariables): loaddll.exe生成的父窗口句柄<hwnd> 和loaddll 的实例句柄<hinst>. 为了方便,当你首次使用输出调用, ollydbg自动把他们添加到历史清单上. 
    MessageBoxW 需要4 个参数: 
handle of owner window .父窗口句柄. 在这里,我们只需选择<hwnd>; 
address of UNICODE text in message box .UNICODE的文本信息的地址. 选择Arg2. 右侧以十六进制展出内存内容. 缓冲区初始化为零. 右键选择点击"Text|UNICODE (32 chars)"。选择首字位,按Ctrl+E (或者选择"二进制|编辑""Binary|Edit"菜单). In the appearing window, type "Text in box" or any other text to display;在出现的窗口里输入"文本框"("Text in box")或任何其他文字; 
address of UNICODE title of message box .  UNICODE的消息框标题文本信息的地址.选Arg3,然后在内存写入UNICODE格式的消息框标题文本"Box title"; 
style of message box.消息框样式是一个组合mb_xxx常数. OllyDbg knows them, type here MB_OK|MB_ICONEXCLAMATION. OllyDbg 可以识别他们,这里输入MB_OK|MB_ICONEXCLAMATION . 
    6.设置寄存器变量. 在输出函数中很少使用寄存器变量. 不过,OllyDbg 同样支持寄存器变量。. 

    7.其他选项. Hide on call “对话框隐藏”意味着在执行函数时,对话框从屏幕上消失. 这个选项在执行需很长的时间,或如果你要设断点时很有用. 你也可以手动关闭对话框. 当被调用函数执行完比时, OllyDbg 会自动重启“Call export” 对话框. “Pause after call” 意味着当被调用函数执行完比后暂停执行应用程序. 
 如果一切正确的话会出现类似对话框: 

    8. “Call function”按下Call按钮 ,OllyDbg自动备份所有缓冲区,验证,计算参数和寄存器,隐藏对话框调用MessageBoxW。屏幕上就会出现的讯息框: 


     按OK. MessageBoxW 返回, Call export对话框显示调用成功. 注意返回寄存器EAX值为1. 这是常量IDOK的数值. 这很简单,不是吗? 
例二:wsprintf 
    1. 选择函数. 我希望 Call export 对话框仍然打开? 就像 MessageBox , wsprintf 也有两种形式: ASCII wsprintfA 和 UNICODE wsprintfW. 我们试一下ASCII 形式. 因为 wsprintf 接受可变数目变量, 它使用C 调用规定。与PASCAL 调用规定的主要区别在于调用代码在调用完毕负责清栈. C函数以RET(或RETN)结尾,所以OllyDbg 分析器无法确定有多少变量。 

    2.设置堆栈变量数目. wsprintfA 可以接受可变数目变量; 多少取决于格式字符串。让我们尝试了以下调用: 
wsprintf(Arg1,"arg3=%i, arg4=%08X",100,0x12345678);
你看,该函数有4个变量,点击控件checkbox "4". 

    3.填写变量列表. 
第一变量是一个缓冲区. 选择 <Arg1> 并且改变内存格式为 ASCII (32 chars); 
第二变量是格式串. 选择 <Arg2> 并且改变内存格式为 ASCII (32 chars);  Select first character, press Ctrl+E (binary edit) and type format string in ASCII field;选择首字,按Ctrl+E(二进制编辑),在ASCII 区输入格式串类代码; 
第三变量是一个十进制常数100. OllyDbg 通常假定十六格式. Decimal point at the end of the constant forces decimal;结尾小数点强制十进制数; 
第四变量是十六常数.OllyDbg 接受任何形式:0x12345678,12345678h 或者干脆12345678; 
    4.按下Call按钮 调用函数. 如果一切正确,结果如下: 

    在Arg1内存区的加亮字符显示被程序修改的部分。 在寄存器EAX, wsprintf 输出一串字符:0x17(十进制23). 
详文及源码  
    loaddll .exe 是一个用汇编编写的紧凑Win32程序。来看看它的源代码。程序从START开始执行. loaddll 接受命令行, 跳过可执行名字(必须双引号!)、提取DLL的路径, 传递给LoadLibrary 。若出现错误, 该函数传递错误信息指针到固定位置并设置退出代码0x1001.  若成功,它生成一个主窗口并停在Firstbp. 这断点是由OllyDbg 启动时设置的断点. 
    所有与OllyDbg 的参数传递都是透过128字节内存. 这块区域必须从地址0x420020开始紧接关键词(keyphrase). 几个开始字含有loaddll.exe 地址,被 OllyDbg 用来设置断点和参数,紧接着是被调用函数地址,寄存器内容,调用参数数目及调用参数本身。调用参数数目低于10. 如果调用参数是指向内存指针,你可以使用10个数据缓冲区、每个1 Kbyte ,名称为 Arg1 , Arg2 , ..., Arg10.  OllyDbg知道这些和其他被输出的名字. 
    当loaddll循环主窗口( WINLOOP ), 他会不断检查输出函数地址(PROCADR)是否是0. 如果0, loaddll备份寄存器ESP 和 EBP 的内容,并把16个零进栈. 这是必要的,用来避免如果用户指定无效调用参数数目而导致崩溃. 然后它把调用参数进栈并设置寄存器。在地址Prepatch 处有16个NOP 可以用来打小补丁. 如果你需要更多的空间,你可以跳转到patcharea 的2kBytes空间.  注意ollydbg不提取loaddll.exe若这个文件已经存在. 
   在 CallDLL 中,输出函数被调用,紧跟着16个 NOP .程序接着保存修改过的寄存器和 ESP的偏移量. 如果你向PASCAL 类函数提供无效调用参数数目,ollydbg能向你报告这个错误. 最后,loaddll恢复寄存器ESP和 EBP,清零 PROCADR ,在地址Finished 处调用INT3 中断. 当达到这一布, OllyDbg 执行完毕. 
 把LOADDLL.ASM 当作免费软件. 我不会抗义,如果你全部或部分使用这一程序(无版权说明)在自己的软件中.但不要把绿虫图标(loaddll.rc)用与无关ollydbg项目!