Windows 钩子

Windows钩子详解
本文深入介绍了Windows钩子机制,包括其概念、安装方法、钩子函数编写及卸载过程,并提供了一个具体的键盘消息钩子示例。
 
Windows钩子
Windows应用程序的运行模式是基于消息驱动的,任何线程只要注册了窗口类就会有一个消息队列来接收用户的输入消息和系统消息。为了取得特定线程接收或发送的消息,就要 Windows提供的钩子。
 
钩子的概念
 
钩子(Hook)是Windows消息处理机制中的一个监视点,应用程序可以在这里安装一个子程序(钩子函数)以监视指定窗口某种类型的消息,所监视的窗口可以是其他进程创建的。当消息到达后,在目标窗口处理函数处理之前,钩子机制允许应用程序截获它进行处理。
         钩子函数是一个处理消息的程序段,通过调用相关的API函数,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息。
         总之,关于Windows钩子要知道以下几点:
1.   钩子是用截获系统中的消息流。利用钩子,可以处理任何感兴趣的消息,包括其他进程的消息。
2.   截获消息后,用于处理消息的子程序叫做钩子函数,它是应用程序自定义的一个函数,在安装钩子时要把这个函数的地址告诉Windows
3.   系统中同一时间可能有多个进程安装了钩子,多个钩子函数在一起组成钩子链。所以在处理截获到的消息时,应该把消息事件传递下去,以便其他钩子也有机会处理这一消息。
 
钩子会使得系统变慢,因为它增加了系统对每个消息的处理量。仅应该在必要时才安装钩子,而且在不需要时应尽快移除。
 
钩子的安装
 
SetWindowsHookEx函数可以把应用程序定义的钩子函数安装到系统中。
HHOOK SetWindowsHookEx(
 Int idHook ;       // 指定钩子的类型
 HOOKPROC lpfn;   // 钩子函数的地址。如果使用的是远程钩子,钩子函数必须放在一个DLL中。
 HINSTANCE hMod; // 钩子函数所在DLL的实例句柄。如果是一个局部的钩子,该参数为NULL
 DWORD    dwThreadID; // 指定要为哪个线程安装钩子。若该值为0被解释成系统范围内的。
IdHook参数指定了要安装的钩子的类型,可以是下列取值之一:
WH_CALLWNDPROC       当目标线程调用SendMessage函数发送消息时,钩子函数被调用。
WH_CALLWNDPROCRET                   SendMessage发送的消息返回时,钩子函数被调用。
WH_GETMESSAGE           当目标线程调用GetMessage或者PeekMessage时。
WH_KEYBOARD               当从消息队列中查询WM_KEYUPWM_KEYDOWN消息时
WH_MOUSE                       当调用从消息队列中查询鼠标事件消息时
WH_MSGFILTER               当对话框,菜单或滚动条要处理一个消息时,钩子函数被调用。该钩子是局部的,它是为哪些有自己消息处理过程的控件对象设计的。
WH_SYSMSGFILTER        WH_MSGFILTER一样,只不过是系统范围的。
WH_JOURNALRECORD Windows从硬件队列中获取消息时。
WH_JOURNALPLAYBACK       当一个事件从系统的硬件输入队列中别请求时
WH_SHELL                         当关于Windows外壳事件发生时,比如任务条需要重画它的按钮
WH_CBT                             当基于计算机的训练(CBT)事件发生时。
WH_FOREGROUNDIDLE Windows自己使用,一般应用程序很少使用。
WH_DEBUG                       用来给钩子函数除错。
 
Lpfn参数是钩子函数的地址。钩子安装后如果有消息发生,Windows将调用此参数所指向的函数。
         如果dwThreadId参数是0,或者指定一个由其他进程创建的线程IDlpfn参数指向的钩子函数必须位于一个DLL中。这是因为进程的地址空间是相互隔离的,发生事件的进程不能调用其他进程地址空间的钩子函数。如果钩子函数的实现代码在DLL中,在相关事件发生时,系统会把这个DLL插入到发生事件的进程的地址空间,使它能够调用钩子函数。这种需要将钩子函数写入DLL以便挂钩其他进程事件的钩子称为远程钩子。
         如果dwThreadId参数指定一个由自身进程创建的线程IDlpfn参数指向的钩子函数只要在当前进程中即可,不必非要写入DLL。这种挂钩属于自身进程事件的钩子称为局部钩子。
 
hMod参数是钩子函数所在DLL的实例句柄,如果钩子函数不再DLL中,应将hMod设置为NULL
 
dwThreadId参数指定要与钩子函数相关联的线程ID号。如果设为0,那么钩子就是系统范围内的,即钩子函数将关联到系统内所有线程。
 
钩子函数
 
         钩子安装后如果有相应的消息发生,Windows将调用SetWindowsHookEx函数指定的钩子函数lpfn。钩子函数的一般形式如下:
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
         // 处理该消息的代码 …..
 
    Return ::CallNextHookEx(hHook,nCode,wParam,lParam);
}
HookProc是应用程序的名称。nCode参数是Hook代码,钩子函数使用这个参数来确定任务,它的值依赖于Hook的类型。wParamlParam参数的值依赖于Hook代码,但是它们典型的值是一些关于发送或者接收消息的信息。
         因为系统中可能会有多个钩子的存在,所以要调用那个CallNextHookEx函数把消息传到链中下一个钩子函数。hHook参数是安装钩子时得到的钩子句柄(SetWindowsHookEx的返回值)。
 
卸载钩子
 
         要卸载钩子,可以调用UnhookWindowsHookEx函数。
 BOOL UnhookWindowsHookEx(HHOOK hhk); // hhk 为要卸载的钩子的句柄
 
注意:
1.   安装钩子的代码可以在DLL模块中,也可以在主模块中,但是一般在DLL里实现它,主要是为了使程序更加模块化。
 
 
例子(HOOK键盘消息)
1.dll库的生成(只是部分重要的文件,没有全部贴出)
None.gif
None.gif
//ke 
            //The following ifdef block is the standard way of creating macros which make exporting 
None.gif
// from a DLL simpler. All files within this DLL are compiled with the KEYHOOKLIB_EXPORTS
None.gif
// symbol defined on the command line. this symbol should not be defined on any project
None.gif
// that uses this DLL. This way any other project whose source files include this file see 
None.gif
// KEYHOOKLIB_API functions as being imported from a DLL, wheras this DLL sees symbols
None.gif
// defined with this macro as being exported.
None.gif
#ifdef KEYHOOKLIB_EXPORTS
None.gif
#define KEYHOOKLIB_API __declspec(dllexport)
None.gif
#else
None.gif
#define KEYHOOKLIB_API __declspec(dllimport)
None.gif
#endif
None.gif
None.gif
// 自定义与主程序通信的消息
None.gif
#define HM_KEY WM_USER+1
None.gif
None.gif
// 声明要导出的函数
None.gif
BOOL KEYHOOKLIB_API WINAPI SetKeyHook(BOOL bInstall, 
None.gif                               DWORD dwThreadId 
= 0
None.gif                               HWND hWndCaller 
= NULL
None.gif                               );
None.gif

None.gif// KeyHookLib.cpp : Defines the entry point for the DLL application.
None.gif
//
None.gif

None.gif#include 
"stdafx.h"
None.gif#include 
"KeyHookLib.h"
None.gif
None.gif
// 共享数据段
None.gif
#pragma data_seg("YCIShared")
None.gifHWND g_hWndCaller 
= NULL;
None.gifHHOOK g_hHook 
= NULL;
None.gif
#pragma data_seg()
None.gif
None.gifLRESULT CALLBACK KeyHookProc(
int nCode, WPARAM wParam, LPARAM lParam);
None.gif
None.gif
None.gif
None.gif
// 一个通过内存地址取得模块句柄的帮助函数。
None.gif
HMODULE    WINAPI ModuleFromAddress(PVOID pv)
ExpandedBlockStart.gifContractedBlock.gif
...{
InBlock.gif    MEMORY_BASIC_INFORMATION mbi;
InBlock.gif    
if(VirtualQuery(pv,&mbi,sizeof(mbi)) != 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
...{
InBlock.gif        
return (HMODULE)mbi.AllocationBase;
ExpandedSubBlockEnd.gif    }
else 
ExpandedSubBlockStart.gifContractedSubBlock.gif    
...{
InBlock.gif        
return NULL;
ExpandedSubBlockEnd.gif    }

InBlock.gif
ExpandedBlockEnd.gif}

None.gif
None.gif
None.gif
// 安装钩子,卸载钩子的函数
None.gif
BOOL WINAPI SetKeyHook(
None.gif            BOOL bInstall,         
// 安装还是卸载已安装的钩子
None.gif
            DWORD dwThreadId,      // 目标线程的ID
None.gif
            HWND  hWndCaller)      // 指定主窗口的句柄,钩子函数会向这个窗口发送通知信息。
ExpandedBlockStart.gifContractedBlock.gif
...{
InBlock.gif    BOOL bOk;
InBlock.gif    g_hWndCaller 
= hWndCaller;
InBlock.gif    
if(bInstall)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
...{
InBlock.gif        g_hHook 
= SetWindowsHookEx(
InBlock.gif            WH_KEYBOARD,
InBlock.gif            KeyHookProc,
InBlock.gif            ModuleFromAddress(KeyHookProc),
InBlock.gif            dwThreadId);
InBlock.gif        bOk 
= (g_hHook != NULL);
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
...{
InBlock.gif        bOk 
= UnhookWindowsHookEx(g_hHook);
InBlock.gif        g_hHook 
= NULL;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
InBlock.gif    
return bOk;
ExpandedBlockEnd.gif}

None.gif
None.gif
// 键盘钩子函数
None.gif
LRESULT CALLBACK KeyHookProc(int nCode, WPARAM wParam, LPARAM lParam)
ExpandedBlockStart.gifContractedBlock.gif
...{
InBlock.gif    
if(nCode<0 || nCode == HC_NOREMOVE )
InBlock.gif        
return CallNextHookEx(g_hHook,nCode,wParam,lParam);
InBlock.gif    
if(lParam & 0x40000000// 消息重复就交给下一个HOOK链
InBlock.gif
        return CallNextHookEx(g_hHook,nCode,wParam,lParam);
InBlock.gif
InBlock.gif    
// 通知主窗口。wParam参数为虚拟键码,lParam包含了此键的信息
InBlock.gif
    ::PostMessage(g_hWndCaller,HM_KEY,wParam,lParam);
InBlock.gif    
return CallNextHookEx(g_hHook,nCode,wParam,lParam);
ExpandedBlockEnd.gif}
None.gif// keyhooklib.def
None.gif
EXPORTS
None.gif    SetKeyHook
None.gifSECTIONS
None.gif    YCIShared    Read Write Shared


2.应用
以对话框为基础建立工程(keyhookapp),改动的文件如下:

None.gif// KeyHookAppDlg.cpp : implementation file
None.gif
//
None.gif

None.gif#include 
"stdafx.h"
None.gif#include 
"KeyHookApp.h"
None.gif#include 
"KeyHookAppDlg.h"
None.gif#include 
"KeyHookLib.h"
None.gif
#pragma comment(lib,"KeyHookLib")
None.gif
None.gif#ifdef _DEBUG
None.gif
#define new DEBUG_NEW
None.gif
#undef THIS_FILE
None.gif
static char THIS_FILE[] = __FILE__;
None.gif
#endif

None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**//////////////////////////////////////////////////////////////////////////////
None.gif// CAboutDlg dialog used for App About

None.gif

None.gif
class CAboutDlg : public CDialog
ExpandedBlockStart.gifContractedBlock.gif
...
{
InBlock.gif
public
:
InBlock.gif    CAboutDlg();
InBlock.gif
InBlock.gif
//
 Dialog Data
InBlock.gif    
//{{AFX_DATA(CAboutDlg)

ExpandedSubBlockStart.gifContractedSubBlock.gif
    enum ...{ IDD = IDD_ABOUTBOX };
InBlock.gif    
//
}}AFX_DATA
InBlock.gif
InBlock.gif    
//
 ClassWizard generated virtual function overrides
InBlock.gif    
//{{AFX_VIRTUAL(CAboutDlg)

InBlock.gif
    protected:
InBlock.gif    
virtual void DoDataExchange(CDataExchange* pDX);    //
 DDX/DDV support
InBlock.gif    
//
}}AFX_VIRTUAL
InBlock.gif
InBlock.gif
// Implementation

InBlock.gif
protected:
InBlock.gif    
//
{{AFX_MSG(CAboutDlg)
InBlock.gif    
//}}AFX_MSG

InBlock.gif
    DECLARE_MESSAGE_MAP()
ExpandedBlockEnd.gif}
;
None.gif
None.gifCAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
ExpandedBlockStart.gifContractedBlock.gif
...
{
InBlock.gif    
//
{{AFX_DATA_INIT(CAboutDlg)
InBlock.gif    
//}}AFX_DATA_INIT

ExpandedBlockEnd.gif
}

None.gif
None.gif
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
ExpandedBlockStart.gifContractedBlock.gif
...
{
InBlock.gif    CDialog::DoDataExchange(pDX);
InBlock.gif    
//
{{AFX_DATA_MAP(CAboutDlg)
InBlock.gif    
//}}AFX_DATA_MAP

ExpandedBlockEnd.gif
}

None.gif
None.gifBEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
None.gif    
//{{AFX_MSG_MAP(CAboutDlg)
None.gif        
//
 No message handlers
None.gif    
//}}AFX_MSG_MAP

None.gif
END_MESSAGE_MAP()
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**//////////////////////////////////////////////////////////////////////////////
None.gif// CKeyHookAppDlg dialog

None.gif

ExpandedBlockStart.gifContractedBlock.gifCKeyHookAppDlg::CKeyHookAppDlg(CWnd
* pParent /**//*=NULL*/)
None.gif    : CDialog(CKeyHookAppDlg::IDD, pParent)
ExpandedBlockStart.gifContractedBlock.gif
...
{
InBlock.gif    
//
{{AFX_DATA_INIT(CKeyHookAppDlg)
InBlock.gif        
//
 NOTE: the ClassWizard will add member initialization here
InBlock.gif    
//
}}AFX_DATA_INIT
InBlock.gif    
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32

InBlock.gif
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
ExpandedBlockEnd.gif}

None.gif
None.gif
void CKeyHookAppDlg::DoDataExchange(CDataExchange* pDX)
ExpandedBlockStart.gifContractedBlock.gif
...
{
InBlock.gif    CDialog::DoDataExchange(pDX);
InBlock.gif    
//
{{AFX_DATA_MAP(CKeyHookAppDlg)
InBlock.gif        
//
 NOTE: the ClassWizard will add DDX and DDV calls here
InBlock.gif    
//}}AFX_DATA_MAP

ExpandedBlockEnd.gif
}

None.gif
None.gifBEGIN_MESSAGE_MAP(CKeyHookAppDlg, CDialog)
None.gif    
//{{AFX_MSG_MAP(CKeyHookAppDlg)
None.gif
    ON_WM_SYSCOMMAND()
None.gif    ON_WM_PAINT()
None.gif    ON_WM_QUERYDRAGICON()
None.gif    ON_MESSAGE(HM_KEY,OnHookKey)
None.gif    
//}}AFX_MSG_MAP

None.gif
END_MESSAGE_MAP()
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**//////////////////////////////////////////////////////////////////////////////
None.gif// CKeyHookAppDlg message handlers

None.gif

None.gifBOOL CKeyHookAppDlg::OnInitDialog()
ExpandedBlockStart.gifContractedBlock.gif
...{
InBlock.gif    CDialog::OnInitDialog();
InBlock.gif
InBlock.gif    
//
 Add "About..." menu item to system menu.
InBlock.gif
InBlock.gif    
// IDM_ABOUTBOX must be in the system command range.

InBlock.gif
    ASSERT((IDM_ABOUTBOX & 0xFFF0== IDM_ABOUTBOX);
InBlock.gif    ASSERT(IDM_ABOUTBOX 
< 0xF000
);
InBlock.gif
InBlock.gif    CMenu
* pSysMenu =
 GetSystemMenu(FALSE);
InBlock.gif    
if (pSysMenu !=
 NULL)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
...
{
InBlock.gif        CString strAboutMenu;
InBlock.gif        strAboutMenu.LoadString(IDS_ABOUTBOX);
InBlock.gif        
if (!
strAboutMenu.IsEmpty())
ExpandedSubBlockStart.gifContractedSubBlock.gif        
...
{
InBlock.gif            pSysMenu
->
AppendMenu(MF_SEPARATOR);
InBlock.gif            pSysMenu
->
AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
// Set the icon for this dialog.  The framework does this automatically
InBlock.gif    
//  when the application's main window is not a dialog

InBlock.gif
    SetIcon(m_hIcon, TRUE);            // Set big icon
InBlock.gif
    SetIcon(m_hIcon, FALSE);        // Set small icon
InBlock.gif    
InBlock.gif    
//
 TODO: Add extra initialization here
InBlock.gif
InBlock.gif    
// 安装钩子

InBlock.gif
    if(!SetKeyHook(TRUE,0,m_hWnd))
InBlock.gif        MessageBox(
"安装钩子失败"
);
InBlock.gif
InBlock.gif    
InBlock.gif    
return TRUE;  // return TRUE  unless you set the focus to a control

ExpandedBlockEnd.gif
}

None.gif
None.gif
void CKeyHookAppDlg::OnSysCommand(UINT nID, LPARAM lParam)
ExpandedBlockStart.gifContractedBlock.gif
...
{
InBlock.gif    
if ((nID & 0xFFF0==
 IDM_ABOUTBOX)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
...
{
InBlock.gif        CAboutDlg dlgAbout;
InBlock.gif        dlgAbout.DoModal();
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
...{
InBlock.gif        CDialog::OnSysCommand(nID, lParam);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
None.gif
// If you add a minimize button to your dialog, you will need the code below
None.gif
//
  to draw the icon.  For MFC applications using the document/view model,
None.gif
//  this is automatically done for you by the framework.

None.gif

None.gif
void CKeyHookAppDlg::OnPaint() 
ExpandedBlockStart.gifContractedBlock.gif
...
{
InBlock.gif    
if
 (IsIconic())
ExpandedSubBlockStart.gifContractedSubBlock.gif    
...
{
InBlock.gif        CPaintDC dc(
this); // device context for painting

InBlock.gif

InBlock.gif        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 
0);
InBlock.gif
InBlock.gif        
// Center icon in client rectangle

InBlock.gif
        int cxIcon = GetSystemMetrics(SM_CXICON);
InBlock.gif        
int cyIcon =
 GetSystemMetrics(SM_CYICON);
InBlock.gif        CRect rect;
InBlock.gif        GetClientRect(
&
rect);
InBlock.gif        
int x = (rect.Width() - cxIcon + 1/ 2
;
InBlock.gif        
int y = (rect.Height() - cyIcon + 1/ 2
;
InBlock.gif
InBlock.gif        
// Draw the icon

InBlock.gif
        dc.DrawIcon(x, y, m_hIcon);
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
...{
InBlock.gif        CDialog::OnPaint();
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
None.gif
// The system calls this to obtain the cursor to display while the user drags
None.gif
//  the minimized window.

None.gif
HCURSOR CKeyHookAppDlg::OnQueryDragIcon()
ExpandedBlockStart.gifContractedBlock.gif
...
{
InBlock.gif    
return
 (HCURSOR) m_hIcon;
ExpandedBlockEnd.gif}

None.gif
None.gif
void CKeyHookAppDlg::OnCancel() 
ExpandedBlockStart.gifContractedBlock.gif
...
{
InBlock.gif    
//
 TODO: Add extra cleanup here
InBlock.gif    
// 卸载钩子

InBlock.gif
    SetKeyHook(FALSE);
InBlock.gif    CDialog::OnCancel();
ExpandedBlockEnd.gif}

None.gif
None.gif
void CKeyHookAppDlg::OnOK() 
ExpandedBlockStart.gifContractedBlock.gif
...
{
InBlock.gif    
//
 TODO: Add extra validation here
InBlock.gif    
// 卸载钩子

InBlock.gif
    SetKeyHook(FALSE);
InBlock.gif    CDialog::OnOK();
ExpandedBlockEnd.gif}

None.gif
None.gif
// 钩子消息处理函数
None.gif
long CKeyHookAppDlg::OnHookKey(WPARAM wParam,LPARAM lParam)
ExpandedBlockStart.gifContractedBlock.gif
...
{
InBlock.gif    
//
 此时wParam为用户按键的虚拟键码
InBlock.gif    
//
 lParam包含按键的重复次数,扫描码,前一个按键状态等信息
InBlock.gif    
// 取得按键名称。lParam是键盘消息的第二个参数

InBlock.gif
    char szKey[80];
InBlock.gif    ::GetKeyNameText(lParam,szKey,
80
);
InBlock.gif    CString strItem;
InBlock.gif    strItem.Format(
"用户按键:%s "
,szKey);
InBlock.gif
InBlock.gif    
// 添加到编辑框

InBlock.gif
    CString strEdit;
InBlock.gif    GetDlgItem(IDC_KEY)
->
GetWindowText(strEdit);
InBlock.gif    GetDlgItem(IDC_KEY)
->SetWindowText(strItem+
strEdit);
InBlock.gif    ::MessageBeep(MB_OK);
InBlock.gif    
return 0
;
ExpandedBlockEnd.gif}

None.gif
None.gif

3。运行结果
一个对话框,检测当前键盘的状态。若有按键按下,则在对话框的EDIT控件中显示按下键的名字。

转载于:https://www.cnblogs.com/mywolrd/archive/2008/02/28/1930741.html

二、API Hook的原理 这里的API既包括传统的Win32 APIs,也包括任何Module输出的函数调用。熟悉PE文件格 式的朋友都知道,PE文件将对外部Module输出函数的调用信息保存在输入表中,即.idata段。 下面首先介绍本段的结构。 输入表首先以一个IMAGE_IMPORT_DESCRIPTOR(简称IID)数组开始。每个被PE文件隐式链接 进来的DLL都有一个IID.在这个数组中的最后一个单元是NULL,可以由此计算出该数组的项数。 例如,某个PE文件从两个DLL中引入函数,就存在两个IID结构来描述这些DLL文件,并在两个 IID结构的最后由一个内容全为0的IID结构作为结束。几个结构定义如下: IMAGE_IMPORT_DESCRIPTOR struct union{ DWORD Characteristics; ;00h DWORD OriginalFirstThunk; }; TimeDateStamp DWORD ;04h ForwarderChain DWORD ;08h Name DWORD ;0Ch FirstThunk DWORD ;10h IMAGE_IMPROT_DESCRIPTOR ends typedef struct _IMAGE_THUNK_DATA{ union{ PBYTE ForwarderString; PDWORD Functions; DWORD Ordinal; PIMAGE_IMPORT_BY_NAME AddressOfData; }u1; } IMAGE_IMPORT_BY_NAME结构保存一个输入函数的相关信息: IMAGE_IMPORT_BY_NAME struct Hint WORD ? ;本函数在其所驻留DLL的输出表中的序号 Name BYTE ? ;输入函数的函数名,以NULL结尾的ASCII字符串 IMAGE_IMPORT_BY_NAME ends OriginalFirstThunk(Characteristics):这是一个IMAGE_THUNK_DATA数组的RVA(相对于PE文件 起始处)。其中每个指针都指向IMAGE_IMPORT_BY_NAME结构。 TimeDateStamp:一个32位的时间标志,可以忽略。 ForwarderChain:正向链接索引,一般为0。当程序引用一个DLL中的API,而这个API又引用别的 DLL的API时使用。 NameLL名字的指针。是个以00结尾的ASCII字符的RVA地址,如"KERNEL32.DLL"。 FirstThunk:通常也是一个IMAGE_THUNK_DATA数组的RVA。如果不是一个指针,它就是该功能在 DLL中的序号。 OriginalFirstThunk与FirstThunk指向两个本质相同的数组IMAGE_THUNK_DATA,但名称不同, 分别是输入名称表(Import Name Table,INT)和输入地址表(Import Address Table,IAT)。 IMAGE_THUNK_DATA结构是个双字,在不同时刻有不同的含义,当双字最高位为1时,表示函数以 序号输入,低位就是函数序号。当双字最高位为0时,表示函数以字符串类型的函数名 方式输入,这时它是指向IMAGE_IMPORT_BY_NAME结构的RVA。 三个结构关系如下图: IMAGE_IMPORT_DESCRIPTOR INT IMAGE_IMPORT_BY_NAME IAT -------------------- /-->---------------- ---------- ---------------- |01| 函数1 ||02| 函数2 || n| ... |"USER32.dll" | |--------------------| | | FirstThunk |---------------------------------------------------------------/ -------------------- 在PE文件中对DLL输出函数的调用,主要以这种形式出现: call dword ptr[xxxxxxxx] 或 jmp [xxxxxxxx] 其中地址xxxxxxxx就是IAT中一个IMAGE_THUNK_DATA结构的地址,[xxxxxxxx]取为IMAGE_THUNK_DATA 的,即IMAGE_IMPORT_BY_NAME的地址。在操作系统加载PE文件的过程中,通过IID中的Name加载相应 的DLL,然后根据INT或IAT所指向的IMAGE_IMPORT_BY_NAME中的输入函数信息,在DLL中确定函数地址, 然后将函数地址写到IAT中,此时IAT将不再指向IMAGE_IMPORT_BY_NAME数组。这样[xxxxxxxx]取到的 就是真正的API地址。 从以上分析可以看出,要拦截API的调用,可以通过改写IAT来实现,将自己函数的地址写到IAT中, 达到拦截目的。 另外一种方法的原理更简单,也更直接。我们不是要拦截吗,先在内存中定位要拦截的API的地址, 然后改写代码的前几个字节为 jmp xxxxxxxx,其中xxxxxxxx为我们的API的地址。这样对欲拦截API的 调用实际上就跳转到了咱们的API调用去了,完成了拦截。不拦截时,再改写回来就是了。 这都是自己从网上辛辛苦苦找来的,真的很好啊
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值