相信很多人都知道Loaddll.exe这个程序,它为Ollydbg提供了调试DLL的功能
但是又有多少人知道Loaddll.exe是如何工作的?
在介绍Loaddll.exe如何工作前,先介绍一下它的来源吧.

从官网上下载的Ollydbg解压后,里面没有Loaddll.exe这个程序,
但是如果你尝试用Ollydbg载入DLL调试,那么Ollydbg目录下就会自动生成一下Loaddll.exe程序.
Loaddll.exe来源于Ollydbg的资源,参考Ollydbg资源中的KNOWNERSTYPE\RES_LOADDLL


知道了Loaddll.exe的来源后,再来思考一下,它是如何为Ollydbg提供调试DLL功能的

一般情况下使用DLL又两种手段,
1>在编译程序时,连接到程序里面
  [如果DLL丢失或升级等,程序易出错,导致不能运行]

2>动态调用DLL
  使用的函数有LoadLibrary与GetProcAddress

在这里就是采用LoadLibraryA载入DLL实现的动态分析
能介绍一下Ollydbg是如何利用Loaddll载入DLL,调试分析的吗?

==========================================================
DLL在载入时,会完成初始化的操作,一般DLL的入口形式如下:

DllEntry    proc    hInstance,dwReason,dwReaserved
                    .if      dwReason == DLL_PROCESS_ATTACH
                                    mov   eax,TRUE
                                   ;表示任何程序可以使用
                    .elseif  dwReason == DLL_PROCESS_DETACH

                    .elseif  dwReason == DLL_THREAD_ATTACH

                    .elseif  dwReason == DLL_THREAD_DETACH
                    
                    .endif
                    RET
DllEntry    endp
end         DllEntry

假设DLL_PROCESS_ATTACH[DLL初始化成功],会执行某个函数[假设函数名为 "Run"]的操作
==================================================
Ollydbg自带的LoadDLL载入DLL时,会自动执行这个函数Run
[有人肯定要说,使因为DLL初始化成功,符合执行条件]

那么请问:
某些前辈的开发的加强版Loaddll.exe,则不会执行DLL的内容,当DLL加载时,自动停在入口处
能解释一下,前辈们是如何做到的吗?

下面是我分析得出来的结论,希望大家喜欢!


================================================================================
Ollydbg载入程序,注意在菜单Debug>>Arguments,填入DLL的地址,例如:C:\1.dll,
这时弹出一个对话框,提示重新再如Loaddll.exe,输入的参数生效.
按下Ctrl+F2,重新运行程序.

00401075  |.  6A 24         push    24                                       ; /Style = MB_YESNO|MB_ICONQUESTION|MB_APPLMODAL
00401077  |.  68 4B304000   push    0040304B                                 ; |Title = "Question"
0040107C  |.  68 00304000   push    00403000                                 ; |Text = "Would you like to load the .dll on a base......
00401081  |.  6A 00         push    0                                        ; |hOwner = NULL
00401083  |.  E8 5E010000   call    <jmp.&user32.MessageBoxA>                ; \MessageBoxA
00401088  |.  83F8 06       cmp     eax, 6                                   ;  点击Yes返回值是6
0040108B  |.  75 16         jnz     short 004010A3
0040108D  |.  6A 00         push    0                                        ; /lParam = NULL
0040108F  |.  68 06114000   push    00401106                                 ; |DlgProc = LoadDll.00401106
00401094  |.  6A 00         push    0                                        ; |hOwner = NULL
00401096  |.  6A 66         push    66                                       ; |pTemplate = 66
00401098  |.  FF35 C0304000 push    dword ptr [4030C0]                       ; |hInst = 00400000
0040109E  |.  E8 31010000   call    <jmp.&user32.DialogBoxParamA>            ; \DialogBoxParamA


利用函数DialogBoxParamA创建一个窗口,窗口过程地址为:401106,具体过程如下:

00401106  /.  55            push    ebp
00401107  |.  8BEC          mov     ebp, esp
00401109  |.  817D 0C 11010>cmp     dword ptr [ebp+C], 111
00401110  |.  0F85 A8000000 jnz     004011BE
00401116  |.  817D 10 F1030>cmp     dword ptr [ebp+10], 3F1
0040111D  |.  0F85 AB000000 jnz     004011CE
00401123  |.  6A 64         push    64                                       ; /Count = 64 (100.)
00401125  |.  68 34334000   push    00403334                                 ; |Buffer = LoadDll.00403334
0040112A  |.  68 F0030000   push    3F0                                      ; |ControlID = 3F0 (1008.)
0040112F  |.  FF75 08       push    dword ptr [ebp+8]                        ; |hWnd
00401132  |.  E8 A9000000   call    <jmp.&user32.GetDlgItemTextA>            ; \GetDlgItemTextA
00401137  |.  83F8 08       cmp     eax, 8
0040113A  |.  77 05         ja      short 00401141

从上面的过程我们可以看出,输入的数据被保存在00403334处.单步向下调试

0040113F  |. /73 13         jnb     short 00401154
00401141  |> |6A 10         push    10                                       ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
00401143  |. |6A 00         push    0                                        ; |Title = NULL
00401145  |. |68 84304000   push    00403084                                 ; |Text = "Invalid input or imagebase already allocated!"
0040114A  |. |FF75 08       push    dword ptr [ebp+8]                        ; |hOwner
0040114D  |. |E8 94000000   call    <jmp.&user32.MessageBoxA>                ; \MessageBoxA
00401152  |. |EB 68         jmp     short 004011BC
00401154  |> \68 34334000   push    00403334                                 ;  ASCII "10000000"
00401159  |.  E8 AE000000   call    0040120C                                 ;  关键过程

00401159处的过程为关键过程,过程的具体信息如下:

0040120C  /$  55            push    ebp                          ;  关键过程
0040120D  |.  8BEC          mov     ebp, esp                     ;  调试到此处的堆栈显示如下
0040120F  |.  53            push    ebx
00401210  |.  56            push    esi
00401211  |.  57            push    edi
00401212  |.  8B7D 08       mov     edi, dword ptr [ebp+8]       ;  DLL载入的基地址 edi=403334  [403334]=10000000
00401215  |.  8B75 08       mov     esi, dword ptr [ebp+8]       ;  DLL载入的基地址
00401218  |>  8A07          /mov     al, byte ptr [edi]
0040121A  |.  47            |inc     edi                         ;  运算后的EDI=ESI +基地址的长度
0040121B  |.  0AC0          |or      al, al
0040121D  |.^ 75 F9         \jnz     short 00401218
0040121F  |.  2BF7          sub     esi, edi                     ;  ESI = ESI-EDI
00401221  |.  33DB          xor     ebx, ebx
00401223  |.  03FE          add     edi, esi                     ;  经过运算,现在的EDI就是401215处的ESI
00401225  |.  33D2          xor     edx, edx
00401227  |.  F7D6          not     esi                          ;  运算后的ESI,表示基地址的长度
00401229  |.  EB 23         jmp     short 0040124E
0040122B  |>  8A07          /mov     al, byte ptr [edi]          ;  基地址10000000的又一个运算
0040122D  |.  3C 41         |cmp     al, 41
0040122F  |.  72 0C         |jb      short 0040123D              ;  al < 41 满足条件
00401231  |.  2C 57         |sub     al, 57
00401233  |.  80D2 00       |adc     dl, 0
00401236  |.  C0E2 05       |shl     dl, 5
00401239  |.  02C2          |add     al, dl
0040123B  |.  EB 02         |jmp     short 0040123F
0040123D  |>  2C 30         |sub     al, 30
0040123F  |>  8D4E FF       |lea     ecx, dword ptr [esi-1]      ;  mov ecx,esi  [注意]
00401242  |.  83E0 0F       |and     eax, 0F                     ;  运算后eax=1
00401245  |.  C1E1 02       |shl     ecx, 2                      ;  ecx=7[111]     shl后    得到[11100]1C
00401248  |.  D3E0          |shl     eax, cl                     ;  EAX=1   CL=1C    运算后EAX=10000000   1后面的7个0,就是Shl来的
0040124A  |.  03D8          |add     ebx, eax                    ;  将DLL的有效基地址放在EBX中
0040124C  |.  47            |inc     edi
0040124D  |.  4E            |dec     esi                         ;  字符长度 - 1
0040124E  |>  0BF6           or      esi, esi
00401250  |.^ 75 D9         \jnz     short 0040122B
00401252  |.  8BC3          mov     eax, ebx                     ;  将有效地址传入EAX中
00401254  |.  5F            pop     edi
00401255  |.  5E            pop     esi
00401256  |.  5B            pop     ebx
00401257  |.  C9            leave
00401258  \.  C2 0400       retn    4


==============================================0040120D处的堆栈数据====================================================
0040120D  |.  8BEC          mov     ebp, esp                                 ;  [调试到此处是的堆栈显示如下]

0012FBBC  /0012FBC8  塞.
0012FBC0  |0040115E  ^@.  RETURN to LoadDll.0040115E from LoadDll.0040120C
0012FBC4  |00403334  43@.  ASCII "10000000"
0012FBC8  ]0012FBF4  酐.

这说明[EBP+8]是存放输入的基地址的地方
===============================================================================================================

从DLL关键过程出来后,

00401152  |. /EB 68         jmp     short 004011BC
00401154  |> |68 34334000   push    00403334                     ;  ASCII "10000000"
00401159  |. |E8 AE000000   call    0040120C                     ;  关键过程
0040115E  |. |8BC8          mov     ecx, eax
00401160  |. |81E1 FF0F0000 and     ecx, 0FFF
00401166  |. |66:83F9 00    cmp     cx, 0
0040116A  |. |76 13         jbe     short 0040117F
0040116C  |. |6A 10         push    10                           ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
0040116E  |. |6A 00         push    0                            ; |Title = NULL
00401170  |. |68 84304000   push    00403084                     ; |Text = "Invalid input or imagebase already allocated!"
00401175  |. |FF75 08       push    dword ptr [ebp+8]            ; |hOwner
00401178  |. |E8 69000000   call    <jmp.&user32.MessageBoxA>    ; \MessageBoxA
0040117D  |. |EB 3D         jmp     short 004011BC
0040117F  |> |A3 30334000   mov     dword ptr [403330], eax      ;  输入的基地址被保存在这里
00401184  |. |6A 04         push    4                            ; /Protect = PAGE_READWRITE    此处的属性值需要注意[没有可执行属性]    这就是断点的原因
00401186  |. |68 00200000   push    2000                         ; |AllocationType = MEM_RESERVE
0040118B  |. |68 00000100   push    10000                        ; |Size = 10000 (65536.)
00401190  |. |FF35 30334000 push    dword ptr [403330]           ; |Address = 10000000
00401196  |. |E8 69000000   call    <jmp.&kernel32.VirtualAlloc> ; \VirtualAlloc
0040119B  |. |0BC0          or      eax, eax                     ;  利用VirtualAlloc指定DLL初始化的地址
0040119D  |. |75 13         jnz     short 004011B2


注意00401184处,关键就在这个VirtualAlloc函数上,他设置的属性中不包括执行属性
上面的分析是为了找出VirtualAlloc处的Address是从何而来


当VirtualAlloc未设置可执行属性时,程序用LoadLibraryA载入DLL时就会产生异常,也就被中断在DLL的入口.

  • 标 题:答复
  • 作 者:Gall
  • 时 间:2010-09-21 11:00:29

如果大家想要打造自己的Loaddll.exe,只需要将原版Loaddll.exe修改一下就可以了!

原版Loaddll.exe

[未修改第一处]
004100AE  |> \56            push    esi                              ; /FileName
004100AF  |.  E8 FC090000   call    <jmp.&KERNEL32.LoadLibraryA>     ; \LoadLibraryA

[未修改第二处]
00410298 >    90            nop
00410299      90            nop
0041029A      90            nop
0041029B      90            nop
0041029C      90            nop
0041029D      90            nop
0041029E      90            nop
0041029F      90            nop
004102A0      90            nop
004102A1      90            nop


修改后的Loaddll.exe
========================================================
[修改第一处]
004100AE  |> \90            nop
004100AF  |.  E9 E4010000   jmp     Patcharea
004100B4  |>  0BC0          or      eax, eax
004100B6  |.  75 0F         jnz     short 004100C7


[修改第二处]
00410298 >|$  6A 04         push    4                                ; /Protect = PAGE_READWRITE
0041029A  |.  68 00200000   push    2000                             ; |AllocationType = MEM_RESERVE
0041029F  |.  68 00000100   push    10000                            ; |Size = 10000 (65536.)
004102A4  |.  68 00000010   push    10000000                         ; |Address = 10000000 [此处地址自行指定]
004102A9  |.  E8 43983F7C   call    kernel32.VirtualAlloc            ; \VirtualAlloc
004102AE  |.  56            push    esi                              ; /FileName
004102AF  |.  E8 FC070000   call    <jmp.&KERNEL32.LoadLibraryA>     ; \LoadLibraryA
004102B4  \.^ E9 FBFDFFFF   jmp     004100B4