首页  编辑  

截获API函数

Tags: /超级猛料/Hook.钩子/   Date Created:
截获API函数
转载一篇文章,也许有用,但我在MSDN上没有查到IMAGE_IMPORT_DESCRIPTOR的结构,
Kingron:你把它转成Delphi代码后记得给我发一份哦
====================================
下面是GoodHope的翻译:
// 我只是照着翻译了一下,可以编译通过。代码本身不全,所以没有进行任何的调试。
// 如果在格式对齐上有问题,请把Tab设为2。
unit x;

// 如何截获API函数(转)
// 该程序是基于HOOK原理,主要是将自己的函数放到目标PROCESS的地址空间,这里是使用HOOK实现.
// 首先建立一个MOUSE的HOOK程序,然后在全局鼠标HOOK的DLL中做截获动作,
// 可以在PROCESS_ATTACH时做,也可以在鼠标的HOOK链函数中做.
// 建立全局HOOK就不说了,可以在网上很多地方看到.主要是截获动作.
// 通过PE格式(使用IMAGE)改变API函数在调用时的地址.DLL部分参考如下代码:
interface

const
  IMAGE_ORDINAL_FLAG64 = $8000000000000000;
  IMAGE_ORDINAL_FLAG32 = $80000000;
{$IFDEF _WIN64}
  IMAGE_ORDINAL_FLAG = IMAGE_ORDINAL_FLAG64;
{$ELSE}
  IMAGE_ORDINAL_FLAG = IMAGE_ORDINAL_FLAG32;
{$ENDIF}

type
  // 我定义了一个结构
  tag_HOOKAPI = record
    szFunc: LPCSTR; // 待HOOK的API函数名
    pNewProc: FARPROC; // 新的函数指针
    pOldProc: FARPROC; // 老的函数指针
  end;

  HOOKAPI = tag_HOOKAPI;
  LPHOOKAPI = ^HOOKAPI;
  THookAPI = tag_HOOKAPI;
  LONG = Longint;
  ULONGLONG = Int64;
  PSTR = LPSTR;
  PVOID = Pointer;
  // WinNT.h Begin;
{$ALIGN OFF}
{$IFDEF _WIN64}
  ULONG_PTR = ULONGLONG;
  PULONG_PTR = ^ULONG_PTR;
{$ELSE}
  ULONG_PTR = LONG;
  PULONG_PTR = ^ULONG_PTR;
{$ENDIF}
  SIZE_T = ULONG_PTR;
  PSIZE_T = ^SIZE_T;

  tag_IMAGE_IMPORT_DESCRIPTOR = record
    case Boolean of
      False:
        (Characteristics: DWORD); // 0 for terminating null import descriptor
      True:
        (OriginalFirstThunk: DWORD;
          // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
          TimeDateStamp: DWORD; // 0 if not bound,
          // -1 if bound, and real date\time stamp
          // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
          // O.W. date/time stamp of DLL bound to (Old BIND)
          ForwarderChain: DWORD; // -1 if no forwarders
          Name: DWORD;
          FirstThunk: DWORD;
          // RVA to IAT (if bound this IAT has actual addresses)
        );
  end;

  IMAGE_IMPORT_DESCRIPTOR = tag_IMAGE_IMPORT_DESCRIPTOR;
  PIMAGE_IMPORT_DESCRIPTOR = ^IMAGE_IMPORT_DESCRIPTOR;

  tag_IMAGE_DOS_HEADER = record // DOS .EXE header
    e_magic: WORD; // Magic number
    e_cblp: WORD; // Bytes on last page of file
    e_cp: WORD; // Pages in file
    e_crlc: WORD; // Relocations
    e_cparhdr: WORD; // Size of header in paragraphs
    e_minalloc: WORD; // Minimum extra paragraphs needed
    e_maxalloc: WORD; // Maximum extra paragraphs needed
    e_ss: WORD; // Initial (relative) SS value
    e_sp: WORD; // Initial SP value
    e_csum: WORD; // Checksum
    e_ip: WORD; // Initial IP value
    e_cs: WORD; // Initial (relative) CS value
    e_lfarlc: WORD; // File address of relocation table
    e_ovno: WORD; // Overlay number
    e_res: array [0 .. 4 - 1] of WORD; // Reserved words
    e_oemid: WORD; // OEM identifier (for e_oeminfo)
    e_oeminfo: WORD; // OEM information; e_oemid specific
    e_res2: array [0 .. 10 - 1] of WORD; // Reserved words
    e_lfanew: LONG; // File address of new exe header
  end;

  IMAGE_DOS_HEADER = tag_IMAGE_DOS_HEADER;
  PIMAGE_DOS_HEADER = ^IMAGE_DOS_HEADER;

  tag_IMAGE_FILE_HEADER = record
    Machine: WORD;
    NumberOfSections: WORD;
    TimeDateStamp: DWORD;
    PointerToSymbolTable: DWORD;
    NumberOfSymbols: DWORD;
    SizeOfOptionalHeader: WORD;
    Characteristics: WORD;
  end;

  IMAGE_FILE_HEADER = tag_IMAGE_FILE_HEADER;
  PIMAGE_FILE_HEADER = ^IMAGE_FILE_HEADER;

  tag_IMAGE_DATA_DIRECTORY = record
    VirtualAddress: DWORD;
    Size: DWORD;
  end;

  IMAGE_DATA_DIRECTORY = tag_IMAGE_DATA_DIRECTORY;
  PIMAGE_DATA_DIRECTORY = ^IMAGE_DATA_DIRECTORY;

  tag_IMAGE_OPTIONAL_HEADER64 = record
    Magic: WORD;
    MajorLinkerVersion: BYTE;
    MinorLinkerVersion: BYTE;
    SizeOfCode: DWORD;
    SizeOfInitializedData: DWORD;
    SizeOfUninitializedData: DWORD;
    AddressOfEntryPoint: DWORD;
    BaseOfCode: DWORD;
    ImageBase: ULONGLONG;
    SectionAlignment: DWORD;
    FileAlignment: DWORD;
    MajorOperatingSystemVersion: WORD;
    MinorOperatingSystemVersion: WORD;
    MajorImageVersion: WORD;
    MinorImageVersion: WORD;
    MajorSubsystemVersion: WORD;
    MinorSubsystemVersion: WORD;
    Win32VersionValue: DWORD;
    SizeOfImage: DWORD;
    SizeOfHeaders: DWORD;
    CheckSum: DWORD;
    Subsystem: WORD;
    DllCharacteristics: WORD;
    SizeOfStackReserve: ULONGLONG;
    SizeOfStackCommit: ULONGLONG;
    SizeOfHeapReserve: ULONGLONG;
    SizeOfHeapCommit: ULONGLONG;
    LoaderFlags: DWORD;
    NumberOfRvaAndSizes: DWORD;
    DataDirectory: array [0 .. IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1]
      of IMAGE_DATA_DIRECTORY;
  end;

  IMAGE_OPTIONAL_HEADER64 = tag_IMAGE_OPTIONAL_HEADER64;
  PIMAGE_OPTIONAL_HEADER64 = ^IMAGE_OPTIONAL_HEADER64;

  tag_IMAGE_OPTIONAL_HEADER = record
    //
    // Standard fields.
    //
    Magic: WORD;
    MajorLinkerVersion: BYTE;
    MinorLinkerVersion: BYTE;
    SizeOfCode: DWORD;
    SizeOfInitializedData: DWORD;
    SizeOfUninitializedData: DWORD;
    AddressOfEntryPoint: DWORD;
    BaseOfCode: DWORD;
    BaseOfData: DWORD;
    //
    // NT additional fields.
    //
    ImageBase: DWORD;
    SectionAlignment: DWORD;
    FileAlignment: DWORD;
    MajorOperatingSystemVersion: WORD;
    MinorOperatingSystemVersion: WORD;
    MajorImageVersion: WORD;
    MinorImageVersion: WORD;
    MajorSubsystemVersion: WORD;
    MinorSubsystemVersion: WORD;
    Win32VersionValue: DWORD;
    SizeOfImage: DWORD;
    SizeOfHeaders: DWORD;
    CheckSum: DWORD;
    Subsystem: WORD;
    DllCharacteristics: WORD;
    SizeOfStackReserve: DWORD;
    SizeOfStackCommit: DWORD;
    SizeOfHeapReserve: DWORD;
    SizeOfHeapCommit: DWORD;
    LoaderFlags: DWORD;
    NumberOfRvaAndSizes: DWORD;
    DataDirectory: array [0 .. IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1]
      of IMAGE_DATA_DIRECTORY;
  end;

  IMAGE_OPTIONAL_HEADER32 = tag_IMAGE_OPTIONAL_HEADER;
  PIMAGE_OPTIONAL_HEADER32 = ^IMAGE_OPTIONAL_HEADER32;

  tag_IMAGE_NT_HEADERS64 = record
    Signature: DWORD;
    FileHeader: IMAGE_FILE_HEADER;
    OptionalHeader: IMAGE_OPTIONAL_HEADER64;
  end;

  IMAGE_NT_HEADERS64 = tag_IMAGE_NT_HEADERS64;
  PIMAGE_NT_HEADERS64 = IMAGE_NT_HEADERS64;

  tag_IMAGE_NT_HEADERS = record
    Signature: DWORD;
    FileHeader: IMAGE_FILE_HEADER;
    OptionalHeader: IMAGE_OPTIONAL_HEADER32;
  end;

  IMAGE_NT_HEADERS32 = tag_IMAGE_NT_HEADERS;
  PIMAGE_NT_HEADERS32 = ^IMAGE_NT_HEADERS32;
{$IFDEF _WIN64}
  IMAGE_NT_HEADERS = IMAGE_NT_HEADERS64;
  PIMAGE_NT_HEADERS = PIMAGE_NT_HEADERS64;
  // IMAGE_FIRST_SECTION64(ntheader) IMAGE_FIRST_SECTION(ntheader)
{$ELSE}
  IMAGE_NT_HEADERS = IMAGE_NT_HEADERS32;
  PIMAGE_NT_HEADERS = PIMAGE_NT_HEADERS32;
  // IMAGE_FIRST_SECTION32(ntheader) = IMAGE_FIRST_SECTION(ntheader);
{$ENDIF}

  tag_IMAGE_IMPORT_BY_NAME = record
    Hint: WORD;
    Name: array [0 .. 0] of BYTE;
  end;

  IMAGE_IMPORT_BY_NAME = tag_IMAGE_IMPORT_BY_NAME;
  PIMAGE_IMPORT_BY_NAME = ^IMAGE_IMPORT_BY_NAME;

  tag_U1_64 = record
    case BYTE of
      1:
        (ForwarderString: PBYTE;);
      2:
        (Function_: PDWORD;);
      3:
        (Ordinal: ULONGLONG;);
      4:
        (AddressOfData: PIMAGE_IMPORT_BY_NAME;);
  end;

  tag_IMAGE_THUNK_DATA64 = record
    u1: tag_U1_64;
  end;

  IMAGE_THUNK_DATA64 = tag_IMAGE_THUNK_DATA64;
  PIMAGE_THUNK_DATA64 = ^IMAGE_THUNK_DATA64;

  tag_U1_32 = record
    case BYTE of
      1:
        (ForwarderString: PBYTE;);
      2:
        (Function_: PDWORD);
      3:
        (Ordinal: DWORD);
      4:
        (AddressOfData: PIMAGE_IMPORT_BY_NAME);
  end;

  tag_IMAGE_THUNK_DATA32 = record
    u1: tag_U1_32;
  end;

  IMAGE_THUNK_DATA32 = tag_IMAGE_THUNK_DATA32;
  PIMAGE_THUNK_DATA32 = ^IMAGE_THUNK_DATA32;
{$IFDEF _WIN64}
  // IMAGE_ORDINAL64(Ordinal) = IMAGE_ORDINAL(Ordinal)
  IMAGE_THUNK_DATA = IMAGE_THUNK_DATA64;
  PIMAGE_THUNK_DATA = PIMAGE_THUNK_DATA64;
  // IMAGE_SNAP_BY_ORDINAL64(Ordinal)IMAGE_SNAP_BY_ORDINAL(Ordinal)
  // IMAGE_TLS_DIRECTORY = IMAGE_TLS_DIRECTORY64;
  // PIMAGE_TLS_DIRECTORY = PIMAGE_TLS_DIRECTORY64
{$ELSE}
  // IMAGE_ORDINAL32(Ordinal) =IMAGE_ORDINAL(Ordinal)
  IMAGE_THUNK_DATA = IMAGE_THUNK_DATA32;
  PIMAGE_THUNK_DATA = PIMAGE_THUNK_DATA32;
  // IMAGE_SNAP_BY_ORDINAL32(Ordinal) = IMAGE_SNAP_BY_ORDINAL(Ordinal)
  // IMAGE_TLS_DIRECTORY = IMAGE_TLS_DIRECTORY32
  // PIMAGE_TLS_DIRECTORY = PIMAGE_TLS_DIRECTORY32
{$ENDIF}
{$ALIGN ON}
function GetNamedImportDescriptor(hModule: hModule; szImportMod: LPCSTR)
  : PIMAGE_IMPORT_DESCRIPTOR; stdcall;
function HookAPIByName(hModule: hModule; // 被HOOK的目标进程MODULE
  szImportMod: LPCSTR; // 如GDI32.DLL
  pHookApi: LPHOOKAPI // 指定函数名,如'MessageBoxW'
  ): Boolean;
stdcall implementation
// 自己的MessageBoxW函数
  function MyMessageBoxW(hWnd: hWnd; lpText: LPCWSTR; lpCaption: LPCWSTR;
  uType: UINT): Integer;
stdcall;
begin
  Result := MessageBox(hWnd, 'TNT' { lpText } , 'TNT' { lpCaption } , uType);
end;
function GetNamedImportDescriptor(hModule: hModule; szImportMod: LPCSTR)
  : PIMAGE_IMPORT_DESCRIPTOR;

var
  pDOSHeader: PIMAGE_DOS_HEADER;
  pNTHeader: PIMAGE_NT_HEADERS;
  pImageDataDirectory: PIMAGE_DATA_DIRECTORY;
  pImportDesc: PIMAGE_IMPORT_DESCRIPTOR;
  szCurrMod: PSTR;
begin
  Result := nil;
  // 首先是DOS头
  pDOSHeader := PIMAGE_DOS_HEADER(hModule);
  if pDOSHeader.e_magic <> IMAGE_DOS_SIGNATURE then
    Exit;
  pNTHeader := PIMAGE_NT_HEADERS(DWORD(pDOSHeader) +
    DWORD(pDOSHeader.e_lfanew));
  if pNTHeader.Signature <> IMAGE_NT_SIGNATURE then
    Exit;
  // 如果没有Import部分,返回失败
  pImageDataDirectory := @pNTHeader.OptionalHeader.DataDirectory
    [IMAGE_DIRECTORY_ENTRY_IMPORT];
  if (pImageDataDirectory.VirtualAddress = 0) then
    Exit;
  // 取Import部分
  pImportDesc := PIMAGE_IMPORT_DESCRIPTOR(DWORD(pDOSHeader) +
    DWORD(pImageDataDirectory.VirtualAddress));
  // 寻找与szImportMod相配部分
  while pImportDesc.Name <> 0 do
  begin
    szCurrMod := PSTR(DWORD(pDOSHeader) + DWORD(pImportDesc.Name));
    if (CompareText(szCurrMod, szImportMod) = 0) then
      Break; // 找到
    Inc(pImportDesc);
  end;
  if pImportDesc.Name <> 0 then
    Result := pImportDesc;
end;
function HookAPIByName(hModule: hModule; szImportMod: LPCSTR;
  pHookApi: LPHOOKAPI): Boolean;

var
  pImportDesc: PIMAGE_IMPORT_DESCRIPTOR;
  pOrigThunk: PIMAGE_THUNK_DATA;
  pRealThunk: PIMAGE_THUNK_DATA;
  pByName: PIMAGE_IMPORT_BY_NAME;
  mbi_thunk: TMemoryBasicInformation;
  dwOldProtect: DWORD;
begin
  Result := False;
  pImportDesc := GetNamedImportDescriptor(hModule, szImportMod);
  // 需要改换的API不能取到正确描
  pOrigThunk := PIMAGE_THUNK_DATA(DWORD(hModule) +
    DWORD(pImportDesc.OriginalFirstThunk));
  if pImportDesc = nil then
    Exit;
  pRealThunk := PIMAGE_THUNK_DATA(DWORD(hModule) +
    DWORD(pImportDesc.FirstThunk));
  while pOrigThunk.u1.Function_ <> nil do
  begin
    if (pOrigThunk.u1.Ordinal and IMAGE_ORDINAL_FLAG) <> IMAGE_ORDINAL_FLAG then
    begin
      pByName := PIMAGE_IMPORT_BY_NAME(DWORD(hModule) +
        DWORD(pOrigThunk.u1.AddressOfData));
      if pByName.Name[0] = 0 then
        Exit; // 失败
      if CompareText(pHookApi.szFunc, PChar(@pByName.Name[0])) = 0 then
      begin
        // 改变thunk保护属性
        VirtualQuery(pRealThunk, mbi_thunk, SizeOf(MEMORY_BASIC_INFORMATION));
        VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,
          PAGE_READWRITE, @mbi_thunk.Protect);
        // 保存原来的API函数指针
        if pHookApi.pOldProc = nil then
          pHookApi.pOldProc := FARPROC(pRealThunk.u1.Function_);
        // 改变API函数指针
        pRealThunk.u1.Function_ := PDWORD(pHookApi.pNewProc);
        // 将thunk保护属性改回来
        VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,
          mbi_thunk.Protect, @dwOldProtect);
      end;
    end;
    Inc(pOrigThunk);
    Inc(pRealThunk);
  end;
  SetLastError(ERROR_SUCCESS);
  Result := True;
end;
====================================
如何截获API函数(转)
该程序是基于HOOK原理,主要是将自己的函数放到目标PROCESS的地址空间,这里是使用HOOK实现.首先建立一个MOUSE的HOOK程序,然后在全局鼠标HOOK的DLL中做截获动作,可以在PROCESS_ATTACH时做,也可以在鼠标的HOOK链函数中做.
建立全局HOOK就不说了,可以在网上很多地方看到.主要是截获动作.通过PE格式(使用IMAGE)改变API函数在调用时的地址.DLL部分参考如下代码:

static int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) // 自己的MessageBoxW函数
{
    return MessageBox(hWnd, "TNT" /*lpText*/, "TNT" /*lpCaption*/, uType);
}
我定义了一个结构
typedef struct tag_HOOKAPI
{
    LPCSTR szFunc; // 待HOOK的API函数名
    PROC pNewProc; // 新的函数指针
    PROC pOldProc; // 老的函数指针
} HOOKAPI, *LPHOOKAPI;

extern "C" __declspec(dllexport) PIMAGE_IMPORT_DESCRIPTOR GetNamedImportDescriptor(HMODULE hModule, LPCSTR szImportMod)
{ // 首先是DOS头
    PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER)hModule;
    if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
        return NULL;
    PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDOSHeader + (DWORD)(pDOSHeader->e_lfanew));
    if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
        return NULL;
    // 如果没有Import部分,返回失败
    if (pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)
        return NULL;
    // 取Import部分
    PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pDOSHeader + (DWORD)(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
    // 寻找与szImportMod相配部分
    while (pImportDesc->Name)
    {
        PSTR szCurrMod = (PSTR)((DWORD)pDOSHeader + (DWORD)(pImportDesc->Name));
        if (stricmp(szCurrMod, szImportMod) == 0)
            break; // 找到
        pImportDesc++;
    }
    if (pImportDesc->Name == NULL)
        return NULL;
    return pImportDesc;
}

extern "C" __declspec(dllexport) HookAPIByName(HMODULE hModule /*被HOOK的目标进程MODULE*/, LPCSTR szImportMod /*如GDI32.DLL*/, LPHOOKAPI pHookApi /*指定函数名,如"MessageBoxW"*/)
{
    PIMAGE_IMPORT_DESCRIPTOR pImportDesc =
        GetNamedImportDescriptor(hModule, szImportMod);
    if (pImportDesc == NULL)
        return FALSE; // 需要改换的API不能取到正确描PIMAGE_THUNK_DATA pOrigThunk = (PIMAGE_THUNK_DATA)((DWORD)hModule + (DWORD)(pImportDesc->OriginalFirstThunk));
    PIMAGE_THUNK_DATA pRealThunk =
        (PIMAGE_THUNK_DATA)((DWORD)hModule + (DWORD)(pImportDesc->FirstThunk));
    while (pOrigThunk->u1.Function)
    {
        if ((pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG)
        {
            PIMAGE_IMPORT_BY_NAME pByName = (PIMAGE_IMPORT_BY_NAME)((DWORD)hModule + (DWORD)(pOrigThunk->u1.AddressOfData));
            if (pByName->Name[0] == '\0')
                return FALSE; // 失败
            if (strcmpi(pHookApi->szFunc, (char *)pByName->Name) == 0)
            {
                // 改变thunk保护属性
                MEMORY_BASIC_INFORMATION mbi_thunk;
                VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION));
                VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect);
                // 保存原来的API函数指针
                if (pHookApi->pOldProc == NULL)
                    pHookApi->pOldProc = (PROC)pRealThunk->u1.Function;
                // 改变API函数指针
                pRealThunk->u1.Function = (PDWORD)pHookApi->pNewProc;
                // 将thunk保护属性改回来
                DWORD dwOldProtect;
                VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,
                               mbi_thunk.Protect, &dwOldProtect);
            }
        }
        pOrigThunk++;
        pRealThunk++;
    }
    SetLastError(ERROR_SUCCESS);
    return TRUE;
}