动态连接库和钩子

动态连接库和钩子
需要解决的几个问题:
1. 了解动态连接库的性质
2. 如何编写动态连接库
3. 如何调用动态连接库
4. 什么是钩子以及钩子的类型
5. 远程钩子的安装和使用
6. 日志钩子
7. API钩子
一. 什么是动态连接库
动态连接库使用标准的PE文件格式,在动态连接库里可以定义资源并使用各种资源,并且可以导入并使用其它动态连接库里定义的函数(动态连接库嵌套)。它提供函数给其它程序在运行的时候调用。通常动态连接库文件的扩展名是.dll,但是系统中某些exe文件,字体文件.fon,一些驱动程序.drv,各种控件.ocx和输入法模块ime等都是动态连接库。
二. 动态连接库框架
;-------------------------------------------------------------------------------------- 
;                           DLLSkeleton.asm 
;-------------------------------------------------------------------------------------- 
.386 
.model flat,stdcall 
option casemap:none 
include /masm32/include/windows.inc 
include /masm32/include/user32.inc 
include /masm32/include/kernel32.inc 
includelib /masm32/lib/user32.lib 
includelib /masm32/lib/kernel32.lib 
.data 
.code 
DllEntry proc hInstDLL:HINSTANCE, reason WORD, reserved1 WORD 
        mov  eax,TRUE 
        ret 
DllEntry Endp 
;--------------------------------------------------------------------------------------------------- 
;下面是一个空函数,您可以象下面一样插入您的函数。 
;---------------------------------------------------------------------------------------------------- 
TestFunction proc 
    ret 
TestFunction endp 
End DllEntry 
;------------------------------------------------------------------------------------- 
;                              DLLSkeleton.def 
;------------------------------------------------------------------------------------- 
LIBRARY   DLLSkeleton 
EXPORTS   TestFunction 

1入口点和初始化代码
DllEntry proc hInstDLL:HINSTANCE, reason WORD, reserved1 WORD 
        mov  eax,TRUE 
        ret 
DllEntry Endp 
每一个动态连接库必须有一个入口函数,以方便操作系统使用。(注意入口函数对调用的应用程序是透明的)函数的名称是什么没有特定的要求,但是格式是有规定的。看看什么情况下要用到入口函数:
■当动态链接库被加载时 
■当动态链接库卸载时 
■同一进程的线程生成时 
■同一进程的线程退出时 
hInstDLL是该动态链接库模块的句柄。它和进程的实例句柄不一样。如果您以后要用,可以保存它,因为以后再要获得它不容易。
根据不同的时机,reason传入的值可能是下面的四个值中的一个: 
DLL_PROCESS_ATTACH 动态链接库第一次插入进程的地址空间时。当传入的参数是该值时,可以做一些初始化的工作。 
DLL_PROCESS_DETACH 动态链接库从进程的地址空间卸出时。可以在此做一些清理的工作。譬如:释放内存等。 
DLL_THREAD_ATTACH 新线程生成。 
DLL_THREAD_DETACH 线程销毁。 
如果想要库中的代码继续执行,返回TRUE,否则返回FALSE,那样动态链接库就不会加载了。譬如:想分配一块内存,如果不成功的话就退出,这时就可以返回FALSE。那样动态链接库就不会加载了。可以加入的函数,它们的位置并不重要,把它们放在入口点函数的前面或后面都可以。只是如果您想要它们能被其它的程序调用的话,就必须把它们的名字放到模块定义文件(.def)中去。
动态链接库在它们自己的编译过程就需要,而不只是提供给其它要引用它的程序参考。它们如下:
LIBRARY   DLLSkeleton 
EXPORTS   TestFunction 
第一行是必须的。LIBRARY 定义了DLL的模块名称。它必须和动态链接库的名称相同。
EXPORTS关键字告诉链接器该DLL的引出函数,也就是其它程序可以调用的函数。举个例子:其它的程序想要调用函数TestFunction ,我们就把它放到EXPORTS中。
2 链接选项
链接器的选项中必须放入开关项:/DLL 和/DEF<DLL文件名>,就像下面这样: 
link /DLL /SUBSYSTEM:WINDOWS /DEF LLSkeleton.def /LIBPATH:c:/masm32/lib DLLSkeleton.obj 
编译器的开关选项是一样的,即:/c /coff /Cp。在链接好后,链接器会生成.lib 和.dll文件。前者是引入库,当其它的程序要调用自己的动态链接库中的函数时就需要该引入库,以便把必要的信息加入到其可执行文件中去。
三. 动态连接库的调用方法
1在include文件定义的时候包含动态连接库的.rc和.lib库文件,在程序中直接调用动态连接库里的函数
2动态加载所需的DLL。
那我们该如何解决这个问题呢?
在Windows中提供了两个函数LoadLibrary和GetProcAddress,LoadLibrary函数用来动态加载DLL,而GetProcAddress函数用来从某个DLL中获取指定函数的地址。这两个函数的用法如下:
HINSTANCE LoadLibrary(
LPCTSTR lpLibFileName   // address of filename of executable module
);
FARPROC GetProcAddress(
  HMODULE hModule,    // handle to DLL module
  LPCSTR lpProcName   // name of function
);
LoadLibarary函数用来加载一个DLL模块,如果成功,则返回该模块的句柄。这个句柄可以用于GetProcAddress函数。而GetProcAddress函数则从DLL模块中查找特定函数名的函数的地址。例如下面两句代码就是从kernel32.dll中取得CreateProcess函数的地址:
HMODULE hModule=LoadLibrary(“kernel32.dll”);
FARPROC *fn=GetProcAddress(hModule,”CreatePrcess”)
但现在又出现了一个问题,函数LoadLibrary和GetProcAddress的地址又从哪得到呢?这就像一个现有鸡还是先有蛋的问题一样。
在WinNT中,进程的环境块(PEB)地址总是在0x7FFDF000处。而在PEB中由该进程加载的每个DLL的地址,当然包括Kernel32.dll的地址。找到Kernel32.dll的地址之后,就可以通过Kernel32.dll的PE文件头找到其导出函数表,再查找该导出函数表就可以找到函数“GetProcAddress”的地址,之后就可以通过GetProcAddress函数得到“LoadLibrary”的地址了。
完成这个功能的Win32汇编代码给出。
;**************************************************************************
;*下面这部分汇编需要对PEB结构非常的了解
;**************************************************************************
mov eax,7FFDF00Ch
;7FFDF000的位置是PEB的位置,其偏移0x0C(即7FFDF00Ch)是PEB_LDR_DATA结构
mov eax,dword ptr [eax]
mov esi,dword ptr [eax+1Ch]
;在PEB_LDR_DATA+0x1c地方就是一些动态连接库的地址了,如第一个指向ntdll.dll 
;第二个就是我们需要的kernel32.dll的地址,第三个是msvcrt.dll,一个指针链表
lodsd
mov eax,dword ptr [eax+8]
;此时得到了Kernel32.dll的位置,eax等于77E60000
mov [ebx+hModule],eax
;此时hModule等于kernel32.dll的位置,即77E60000

;********************************************************************
; 从 PE 文件头的数据目录获取导出表地址
;********************************************************************
mov esi,[ebx+hModule]
add esi,[esi + 3ch]
assume esi tr IMAGE_NT_HEADERS
mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
add esi,[ebx+hModule]
assume esi tr IMAGE_EXPORT_DIRECTORY
;esi指向kernel。dll的导出表
;********************************************************************
; 查找符合名称的导出函数名
;********************************************************************
mov eax,[esi].AddressOfNames
add eax,[ebx+hModule]
xor edx,edx
.repeat
push esi
mov edi,[eax]
add edi,[ebx+hModule]
lea esi,[ebx+offset _szGetProcAddress]
mov ecx,14
repz cmpsb
.if ZERO?
pop esi
jmp @F
.endif
pop esi
add eax,4
inc edx
.until edx >= [esi].NumberOfNames
jmp return
@@:
;********************************************************************
; API名称索引 --> 序号索引 --> 地址索引
;********************************************************************
sub eax,[esi].AddressOfNames
sub eax,[ebx+hModule]
shr eax,1
add eax,[esi].AddressOfNameOrdinals
add eax,[ebx+hModule]
movzx edx,word ptr [eax]
shl edx,2
add edx,[esi].AddressOfFunctions
add edx,[ebx+hModule]
;********************************************************************
; 从地址表得到导出函数地址
;********************************************************************
mov eax,[edx]
add eax,[ebx+hModule]
;取得GetProcAddress函数的地址
mov [ebx+_lpGetProcAddress],eax
;取得LoadLibrary函数的地址
lea esi,[ebx+ offset _szLoadLibrary]
_invoke [ebx+_lpGetProcAddress],[ebx+hModule],esi
mov [ebx+ _lpLoadLibrary],eax
assume esi:nothing
上面的代码是大嘴提供的,有一些地方还不懂~学吧:)PE文件格式看过一遍可是怎么就过眼云烟了啊?看来我的IQ是被范伟那厮抢去了,哈哈~
★ 钩子
太郁闷了!!!一个下午的辛苦全没有了。关机的时候忘记了保存这一部分了,只好重新写一遍了~~~~~~~~~~~我要大声地喊:“为什么?”
▲ 钩子的定义:A hook is a point in the Microsoft?Windows?message-handling mechanism where an application can install a subroutine to monitor the message traffic in the system and process certain types of messages before they reach the target window procedure.这是API手册对钩子的定义。看不明白的查查金山词霸吧。
▲钩子的分类:两种类型的钩子:局部的和远程的。 
局部钩子仅钩挂自己进程的事件。 
远程的钩子还可以将钩挂其它进程发生的事件。远程的钩子又有两种: 
基于线程的 它将捕获其它进程中某一特定线程的事件。简言之,就是可以用来观察其它进程中的某一特定线程将发生的事件。 
系统范围的 将捕捉系统中所有进程将发生的事件消息。
&#8226; WH_CALLWNDPROC 当调用SendMessage时 
&#8226; WH_CALLWNDPROCRET 当SendMessage的调用返回时 
&#8226; WH_GETMESSAGE 当调用GetMessage 或 PeekMessage时 
&#8226; WH_KEYBOARD 当调用GetMessage 或 PeekMessage 来从消息队列中查询WM_KEYUP 或 WM_KEYDOWN 消息时 
&#8226; WH_MOUSE 当调用GetMessage 或 PeekMessage 来从消息队列中查询鼠标事件消息时 
&#8226; WH_HARDWARE 当调用GetMessage 或 PeekMessage 来从消息队列种查询非鼠标、键盘消息时 
&#8226; WH_MSGFILTER 当对话框、菜单或滚动条要处理一个消息时。该钩子是局部的。它时为那些有自己的消息处理过程的控件对象设计的。 
&#8226; WH_SYSMSGFILTER 和WH_MSGFILTER一样,只不过是系统范围的 
&#8226; WH_JOURNALRECORD 当WINDOWS从硬件队列中获得消息时 
&#8226; WH_JOURNALPLAYBACK 当一个事件从系统的硬件输入队列中被请求时 
&#8226; WH_SHELL 当关于WINDOWS外壳事件发生时,譬如任务条需要重画它的按钮. 
&#8226; WH_CBT 当基于计算机的训练(CBT)事件发生时 
&#8226; WH_FOREGROUNDIDLE 由WINDOWS自己使用,一般的应用程序很少使用 
&#8226; WH_DEBUG 用来给钩子函数除错 

▲ 钩子函数的工作原理。
当创建一个钩子时,WINDOWS会先在内存中创建一个数据结构,该数据结构包含了钩子的相关信息,然后把该结构体加到已经存在的钩子链表中去。新的钩子将加到老的前面。当一个事件发生时,如果安装的是一个局部钩子,进程中的钩子函数将被调用。如果是一个远程钩子,系统就必须把钩子函数插入到其它进程的地址空间,要做到这一点要求钩子函数必须在一个动态链接库中,所以如果想要使用远程钩子,就必须把该钩子函数放到动态链接库中去。当然有两个例外:工作日志钩子和工作日志回放钩子。这两个钩子的钩子函数必须在安装钩子的线程中。原因是:这两个钩子是用来监控比较底层的硬件事件的,既然是记录和回放,所有的事件就当然都是有先后次序的。所以如果把回调函数放在DLL中,输入的事件被放在几个线程中记录,所以我们无法保证得到正确的次序。故解决的办法是:把钩子函数放到单个的线程中,譬如安装钩子的线程。

▲ 安装一个钩子 
SetWindowsHookEx proto HookType WORD, pHookProc WORD, hInstance WORD, ThreadID WORD 
HookType 是我们上面列出的值之一,譬如: WH_MOUSE, WH_KEYBOARD 
pHookProc 是钩子函数的地址。如果使用的是远程的钩子,就必须放在一个DLL中,否则放在本身代码中 
hInstance 钩子函数所在DLL的实例句柄。如果是一个局部的钩子,该值为NULL 
ThreadID 是安装该钩子函数后想监控的线程的ID号。该参数可以决定该钩子是局部的还是系统范围的。如果该值为NULL,那么该钩子将被解释成系统范围内的,那它就可以监控所有的进程及它们的线程。如果指定了自己进程中的某个线程ID 号,那该钩子是一个局部的钩子。如果该线程ID是另一个进程中某个线程的ID,那该钩子是一个全局的远程钩子。这里有两个特殊情况:WH_JOURNALRECORD 和 WH_JOURNALPLAYBACK总是代表局部的系统范围的钩子,之所以说是局部,是因为它们没有必要放到一个DLL中。WH_SYSMSGFILTER 总是一个系统范围内的远程钩子。其实它和WH_MSGFILTER钩子类似,如果把参数ThreadID设成0的话,它们就完全一样了。 
如果该函数调用成功的话,将在eax中返回钩子的句柄,否则返回NULL。必须保存该句柄,因为后面还要它来卸载钩子。

▲ 卸载钩子
invoke UnhookWindowsHookEx,hHook
该函数只有一个参数,就是要卸载的钩子句柄。如果调用成功的话,在eax中返回非0值,否则返回NULL。

▲ 钩子函数
HookProc proto nCode WORD, wParam WORD, lParam WORD 
     nCode 指定是否需要处理该消息 
wParam 和 lParam 包含该消息的附加消息 
任何钩子函数的原形都是这样,你可以更改钩子函数的名字,而且在具体用钩子函数的时候,函数的参数要视具体情况而定。可以参考API参考手册。

▲钩子链
当一个事件发生时,WINDOWS将按照从链表头到链表尾调用的顺序。所以您的钩子函数有责任把消息传到下一个链中的钩子函数。当然可以不这样做,但是最好明白这时这么做的原因。在大多数的情况下,最好把消息事件传递下去以便其它的钩子都有机会获得处理这一消息的机会。调用下一个钩子函数可以调用函数CallNextHookEx。该函数的原型如下: 
CallNextHookEx proto hHook WORD, nCode WORD, wParam WORD, lParam WORD 
hHook 是自己的钩子函数的句柄。利用该句柄可以遍历钩子链。 
nCode, wParam and lParam 只要把传入的参数简单传给CallNextHookEx即可。 
请注意:对于远程钩子,钩子函数必须放到DLL中,它们将从DLL中映射到其它的进程空间中去。当WINDOWS映射DLL到其它的进程空间中去时,不会把数据段也进行映射。简言之,所有的进程仅共享DLL的代码,至于数据段,每一个进程都将有其单独的拷贝。这是一个很容易被忽视的问题。不要想当然的以为,在DLL中保存的值可以在所有映射该DLL的进程之间共享。在通常情况下,由于每一个映射该DLL的进程都有自己的数据段,所以在大多数的情况下程序运行得都不错。但是钩子函数却不是如此。对于钩子函数来说,要求DLL的数据段对所有的进程也必须相同。这样就必须把数据段设成共享的,这可以通过在链接开关中指定段的属性来实现。在MASM中可以这么做: 
/SECTION:<section name>, S
已初期化的段名是.data,未初始化的段名是.bss。`加入想要写一个包含钩子函数的DLL,而且想使它的未初始化的数据段在所有进程间共享,必须这么做: 
link /section:.bss,S  /DLL  /SUBSYSTEM:WINDOWS ..........
附罗云彬的一个键盘钩子源代码:
Hook.dll源代码
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming >
; by 罗云彬,  ::URL:: http://asm.yeah.net
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Hookdll.asm
; 键盘钩子使用的 dll 程序
; 用来方置钩子过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff Hookdll.asm
; Link  /subsystem:windows /section:.bss,S /Def:Hookdll.def /Dll Hookdll.obj
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat, stdcall
option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
hInstance dd ?

.data?
hWnd dd ?
hHook dd ?
dwMessage dd ?
szAscii db 4 dup (?)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; dll 的入口函数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DllEntry proc _hInstance,_dwReason,_dwReserved

push _hInstance
pop hInstance
mov eax,TRUE
ret

DllEntry Endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 键盘钩子回调函数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
HookProc proc _dwCode,_wParam,_lParam
local @szKeyState[256]:byte

invoke CallNextHookEx,hHook,_dwCode,_wParam,_lParam
invoke GetKeyboardState,addr @szKeyState
invoke GetKeyState,VK_SHIFT
mov @szKeyState + VK_SHIFT,al
mov ecx,_lParam
shr ecx,16
invoke ToAscii,_wParam,ecx,addr @szKeyState,addr szAscii,0
mov byte ptr szAscii [eax],0
invoke SendMessage,hWnd,dwMessage,dword ptr szAscii,NULL
xor eax,eax
ret

HookProc endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 安装钩子
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
InstallHook proc _hWnd,_dwMessage

push _hWnd
pop hWnd
push _dwMessage
pop dwMessage
invoke SetWindowsHookEx,WH_KEYBOARD,addr HookProc,hInstance,NULL
mov hHook,eax
ret

InstallHook endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 卸载钩子
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
UninstallHook proc

invoke UnhookWindowsHookEx,hHook
ret

UninstallHook endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
End DllEntry


Hookdll的def
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
EXPORTS HookProc
InstallHook
UninstallHook
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


Hookdll的inc
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
HookProc proto :dword,:dword,:dword
InstallHook proto :dword,:dword
UninstallHook proto
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Main源代码
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming >
; by 罗云彬,  ::URL:: http://asm.yeah.net
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Main.asm
; 键盘钩子演示程序的主程序,调用 dll 装载键盘钩子
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff Main.asm
; rc Main.rc
; Link  /subsystem:windows Main.obj Main.res
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat, stdcall
option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include Hookdll.inc
includelib Hookdll.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equ 等值定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN equ 1000
DLG_MAIN equ 1000
IDC_TEXT equ 1001
WM_HOOK equ WM_USER + 100h
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam
local @dwTemp

mov eax,wMsg
;********************************************************************
.if eax == WM_CLOSE
invoke UninstallHook
invoke EndDialog,hWnd,NULL
;********************************************************************
.elseif eax == WM_INITDIALOG
invoke InstallHook,hWnd,WM_HOOK
.if ! eax
invoke EndDialog,hWnd,NULL
.endif
;********************************************************************
.elseif eax == WM_HOOK
mov eax,wParam
.if al == 0dh
mov eax,0a0dh
.endif
mov @dwTemp,eax
invoke SendDlgItemMessage,hWnd,IDC_TEXT,EM_REPLACESEL,0,addr @dwTemp
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret

_ProcDlgMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
invoke GetModuleHandle,NULL
invoke DialogBoxParam,eax,DLG_MAIN,NULL,offset _ProcDlgMain,NULL
invoke ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start


makefile
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
NAME = Main
DLL = Hookdll

ML_FLAG = /c /coff
LINK_FLAG = /subsystem:windows
DLL_LINK_FLAG = /subsystem:windows /section:.bss,S

(DLL).dll (NAME).exe:

(DLL).dll: (DLL).obj (DLL).def
Link  (DLL_LINK_FLAG) /Def DLL).def /Dll (DLL).obj
(NAME).exe: (NAME).obj (NAME).res
Link  (LINK_FLAG) (NAME).obj (NAME).res

.asm.obj:
ml (ML_FLAG) <
.rc.res:
rc <

clean:
del *.obj
del *.res
del *.exp
del *.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


资源源代码
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include <resource.h>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define ICO_MAIN 1000
#define DLG_MAIN 1000
#define IDC_TEXT 1001
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN ICON "Main.ico"
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DLG_MAIN DIALOG 208, 130, 234, 167
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "键盘钩子"
FONT 9, "宋体"
{
 EDITTEXT IDC_TEXT, 5, 5, 224, 158, ES_MULTILINE | ES_AUTOVSCROLL 
| WS_BORDER | WS_VSCROLL | WS_TABSTOP | ES_READONLY
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=308376

<script src="http://writeblog.csdn.net/PromoteIcon.aspx?Id=308376" type="text/javascript"></script> [ 点击此处收藏本文]   发表于 2005年03月02日 8:57 PM
href="http://blog.csdn.net/ToBeroOTer/Services/Pingback.aspx" rel="pingback" /> <script type="text/javascript">function hide(){showComment();}</script>
<script type="text/javascript">document.write(" ");</script>

 

 
梦飞翔 发表于2005-07-08 9:41 PM  IP: 61.186.252.*
看到"*下面这部分汇编需要对PEB结构非常的了解 " 的时候, 我太吃惊了. 我以为驴和小迷的思维居然能碰到一起, 太厉害了.
呵呵, 还好, 看到后面说是引的小迷的, 心中的大石头才落到肚子里去了.

动态链接库那里说的相对简单了些. 特别是很多地方是asm32说明举例的. 下面我就我的经验简单的补充一点点. 算是和驴过过招, 交流一下下:
1. 从何说起呢. 从c代码说起吧. c的dll代码:
dll的形式入口:

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hDll = hModule;
break;
case DLL_THREAD_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_DETACH:
break;
default:
break;
}

return TRUE;
}
四个case就不说了吧. 驴说的很清楚了. 一般来说, 除了DLL_PROCESS_ATTACH,以外, 其他的,我们很少用到. 因为我们写dll, 大多数时候是做坏事的, 也就是将之加入其他进程中去运行. 所以, 一般工作都在attach进程的时候完成了. 所以. 后面几个都可以省掉. 没用.
2. dll的引用.
dll的引用方式其实不多. 自己写exe程序调用. 或者说自己为了方便在其他地方使用. 写成dll, 日后使用. (这样的话, 其实还是写成函数方便一些.)不过既然是自己写的dll. 那么自然能生成lib文件. 所以加载lib文件, 直接使用函数就行了. 代码:
#pragma comment(lib, "ljj.lib")
还有就是远程线程插入. 这个代码就不在这里举例了. 有时间我贴出来, 去我的blog看吧.
包括后面的hook也算是一种吧. .
不过这些引用中, 其实都是不需要自己去寻找LoadLibrary(), GetProcAddress()的地址的, 因为对于一个进程来说, 这两个函数的地址都是固定的. 驴所说的鸡和蛋的问题, 其实是在写shellcode时候才需要注意的.

dll 的引用我再多说一点, 看起来似乎是多余的. 其实不然, 对于我们养成良好的编程习惯大有好处.
驴的文章中举了一个例子来说明对dll的引用(也就是引用dll中export的函数哈. ):
HMODULE hModule=LoadLibrary(“kernel32.dll”);
FARPROC *fn=GetProcAddress(hModule,”CreatePrcess”)
这个地方, 细细推敲是不对的. 得到的 fn是指针. 指针是不会告诉我们任何细节的, 最大的细节就是,传递参数的问题. 我们知道, 在调用api的时候, 参数的传递使用的是 WINAPI 类型, 或者 __stdcall, 都说的一回事. 但指针是不会告诉我们这些的. 也就是说, 我们需要自己定义指针参数传递的方向和多少.
假设我们的dll中提供一个这样的函数:
DWORD WINAPI drGetLove(char *pName, char *pLove, int iTime);那我们必须先定义drGetLove的参数传递方向.:也就是函数调用类型:
typedef DWORD (__stdcall *GL) (char *pName, char *pLove, int iTime);
说的直白一些就是, 我们定义一个具有三个参数,参数压栈顺序为 __stdcall的指针类型 GL. 然后用这个类型去修饰我们的GetProcAddress的返回值. 这样, 我们就可以像使用普通函数那样使用指针. 代码:
typedef DWORD (__stdcall *GL) (char *pName, char *pLove, int iTime);

GL lpdrGetLove;
//定义一个 GL型的指针 lpdrGetLove;

//使用代码:
HINSTANCE hDll = LoadLibrary("ljj.dll");
lpdrGetLove = (GL)GetProcAddress(hDll, "drGetLove");
DWORD dwRet = lpdrGetLove("draren", "very much", 1000year);

这样的代码才是正确调用dll(中函数的方法). 希望对别人有所帮助.
3. dll 与 Rundll32 (Rundll)
Rundll32 和Rundll都是windows提供的调用加载dll的自带程序. Rundll32加载32为的dll, Rundll加载16位的dll. 这两个程序都可以加载dll . (在符合调用规则的情况下. ) 具体资料我就不引述了. 我这里有一些它的调用实例, 以及英文的资料. 有兴趣的拿了去翻译一下.
这里简单的讲一下它的调用规则. 其实就是给dll编写满足这个"样式"的函数而已.:
void CALLBACK FunctionName(
HWND hwnd, // handle to owner window
HINSTANCE hinst, // instance handle for the DLL
LPTSTR lpCmdLine, // string the DLL will parse
int nCmdShow // show state
);
你可以构造两个这样样子的函数. 里面再调用你自己的函数就可以了. 值得一提的是. lpCmdLine 是传递给Rundll32 的参数. 假设我编写了一个这样的函数:
void CALLBACK drInstall(
HWND hwnd, // handle to owner window
HINSTANCE hinst, // instance handle for the DLL
LPTSTR lpCmdLine, // string the DLL will parse
int nCmdShow // show state
)
{
// do my things
}
这样你就可以这样来调用 drInstall(在命令行下):
Rundll32 ljj.dll,drInstall draren
注意调用格式, 首先 drInstall 是区分大小写的. I 必须大写. 否则, ....自己去看结果吧. 另外 ljj.dll后面是逗号",". draren前面是空格.

关于动态链接库就补充到这里, 其他的驴说的也差不多了. 不多说了.
都是经验之谈, 不对或者不准确的地方, 请指正, 便于交流进步.
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值