查詢函數地址--LookupApi(Application Programming Interface,應用程序編程接口)

Peb(Process Environment Block)

獲取Peb,也就是進程環境塊的一種方法
一句彙編指令

代碼

mov eax,fs:[30h]

獲得當前peb
peb是個結構體。

{
BYTE bInheritedAddressSpace;
BYTE bReadImageFileExecOptions;
BYTE bBeingDebugged;
BYTE bSpareBool;
LPVOID lpMutant;
LPVOID lpImageBaseAddress;
PPEB_LDR_DATA pLdr;                 <------------ 0C字節
········· 目前只需要這些
} _PEB, * _PPEB; ```

獲得PPEB_LDR_DATA pLdr 的指針 所指向的地址是一個PEB_LDR_DATA數據類型的結構體。

typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes
{
   DWORD dwLength;
   DWORD dwInitialized;
   LPVOID lpSsHandle;
   LIST_ENTRY InLoadOrderModuleList;    <-------0C字節
   LIST_ENTRY InMemoryOrderModuleList;
   LIST_ENTRY InInitializationOrderModuleList;
   LPVOID lpEntryInProgress;
} PEB_LDR_DATA, * PPEB_LDR_DATA;

取出LIST_ENTRY類型的結構體InLoadPrderModuleList(按照加載順序排列的模塊表)

typedef struct _LIST_ENTRY {
   struct _LIST_ENTRY *Flink;
   struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;

LIST_ENTRY是個雙向鏈表,其中Flink指向下一個模塊中的地址
在這個時候我們就不得不介紹一下其他的結構體了LDR_DATA_TABLE_ENTRY

typedef struct _LDR_DATA_TABLE_ENTRY
{
    //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry.
    LIST_ENTRY InMemoryOrderModuleList;
    LIST_ENTRY InInitializationOrderModuleList;
    PVOID DllBase;
    PVOID EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STR FullDllName;
    UNICODE_STR BaseDllName; <----------2C字節
    ULONG Flags;
    SHORT LoadCount;
    SHORT TlsIndex;
    LIST_ENTRY HashTableEntry;
    ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

這個結構體和PEB_LDR_DATA結構體的地址關係是如下圖一樣的關係

這裏寫圖片描述

這裏寫圖片描述

而在LDR_DATA_TABLE_ENTRY這個結構體中有我們想要的成員UNICODE_STR類型的BASEDLLNAME
UNICODE_STR也是一個結構體

typedef struct _UNICODE_STRING_
    {
        UINT16 Length;
        UINT16 MaximumLength;
        WCHAR* Buffer;
    }UNICODE_STRING, *PUNICODE_STRING;

BASEDLLNAME 中的 WCHAR* Buffer 是我們想要的存有模塊名稱的數據。

因此

我們要把LIST_ENTRY類型的Flink中的數據,也就是Flink指向的地址強轉成LDR_DATA_TABLE_ENTRY來獲取我們想要的Buffer。

找到想要找的庫則取LDR_DATA_TABLE_ENTRY的 DLLBASE (當前模塊Dos頭)


typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number<---MZ
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

在DOS頭中最重要的兩個成員就是 WORD e_magic(存放dos的標誌MZ)和 LONG e_lfanew(指向pe文件 NT頭的偏移)

IMAGE_NT_HEADERS =(PIMAGE_NT_HEADERS)( IMAGE_DOS_HEADER -> e_lfanew +(ULONG_PTR) IMAGE_DOS_HEADER)

#define IMAGE_NT_SIGNATURE 0x00004550 // PE00


typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;   //Signature字段被設置爲00004550h, ASCI|| 字符碼是:PE00
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

NT頭裏有兩個重要的成員 一個FileHeader (文件頭)和Optional Header(選項頭)

FileHeader

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;




IMAGE_FILE_HEADER STRUCT  

+04h    WORD          Machine;   // 運行平臺  

+06h      WORD          NumberOfSections; // 文件的區塊數目  

+08h    DWORD         TimeDateStamp;  // 文件創建日期和時間  

+0Ch      DWORD         PointerToSymbolTable; // 指向符號表(主要用於調試)  

+10h     DWORD         NumberOfSymbols;  // 符號表中符號個數(同上)  

+14h      WORD          SizeOfOptionalHeader;  // IMAGE_OPTIONAL_HEADER32 結構大小  

+16h      WORD          Characteristics;  // 文件屬性  

IMAGE_FILE_HEADER ENDS 

Optional Header




typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    //
    // NT additional fields.
    //

    DWORD   ImageBase;
    DWORD   SectionAlignment;
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;



IMAGE_OPTIONAL_HEADER32 STRUCT  

+18h    WORD    Magic;         // 標誌字, ROM 映像(0107h),普通可執行文件(010Bh)  

+1Ah    BYTE      MajorLinkerVersion;     // 鏈接程序的主版本號  

+1Bh    BYTE      MinorLinkerVersion;     // 鏈接程序的次版本號  

+1Ch    DWORD   SizeOfCode;     // 所有含代碼的節的總大小  

+20h    DWORD   SizeOfInitializedData;    // 所有含已初始化數據的節的總大小  

+24h    DWORD   SizeOfUninitializedData; // 所有含未初始化數據的節的大小  

+28h    DWORD   AddressOfEntryPoint;    // 程序執行入口RVA  

+2Ch    DWORD   BaseOfCode;      // 代碼的區塊的起始RVA  

+30h    DWORD   BaseOfData;      // 數據的區塊的起始RVA  

+34h    DWORD   ImageBase;      // 程序的首選裝載地址  

+38h    DWORD   SectionAlignment;      // 內存中的區塊的對齊大小  

+3Ch    DWORD   FileAlignment;      // 文件中的區塊的對齊大小  

+40h    WORD    MajorOperatingSystemVersion;  // 要求操作系統最低版本號的主版本號  

+42h    WORD    MinorOperatingSystemVersion;  // 要求操作系統最低版本號的副版本號  

+44h    WORD    MajorImageVersion;       // 可運行於操作系統的主版本號  

+46h    WORD    MinorImageVersion;       // 可運行於操作系統的次版本號  

+48h    WORD    MajorSubsystemVersion;  // 要求最低子系統版本的主版本號  

+4Ah    WORD    MinorSubsystemVersion;  // 要求最低子系統版本的次版本號  

+4Ch    DWORD   Win32VersionValue;       // 莫須有字段,不被病毒利用的話一般爲0  

+50h    DWORD   SizeOfImage;       // 映像裝入內存後的總尺寸  

+54h    DWORD   SizeOfHeaders;       // 所有頭 + 區塊表的尺寸大小  

+58h    DWORD   CheckSum;       // 映像的校檢和  

+5Ch    WORD    Subsystem;       // 可執行文件期望的子系統  

+5Eh    WORD    DllCharacteristics;       // DllMain()函數何時被調用,默認爲 0  

+60h    DWORD   SizeOfStackReserve;       // 初始化時的棧大小  

+64h    DWORD   SizeOfStackCommit;       // 初始化時實際提交的棧大小  

+68h    DWORD   SizeOfHeapReserve;        // 初始化時保留的堆大小  

+6Ch    DWORD   SizeOfHeapCommit;        // 初始化時實際提交的堆大小  

+70h    DWORD   LoaderFlags;        // 與調試有關,默認爲 0  

+74h    DWORD   NumberOfRvaAndSizes;  // 下邊數據目錄的項數,這個字段自Windows NT 發佈以來一直是16  

+78h    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];  // 數據目錄表  

IMAGE_OPTIONAL_HEADER32 ENDS 

對我們找出導出表有用的就是Optional Header中的最後一個成員 [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]
這個成員是數據目錄表 放着下圖數據

IMAGE_DATA_DIRECTORY DataDirectory
我們取出第一號元素 也就是導出表 來找我們的函數地址
那首先我們得知道導出表結構體中的成員
這裏寫圖片描述
在這個結構體中我們首先取出NumberOfNames成員(存有以函數名導出的函數個數),然後取出AddressOfNames(函數名地址表RVA)

AddressOfNames +  IMAGE_DOS_HEADER = TrueAddressOfNames 
//存有函數名字的數組首地址

TrueAddressOfNames[1,2,3,4····]就是dll中以函數名字導出的函數名字,

若找到函數名字

則記錄下來對應的TrueAddressOfNames[i]中的 i

然後取出AddressOfNameOrdinals(函數序號地址表,它本身是個RVA)

AddressOfNameOrdinals  + IMAGE_DOS_HEADER  = TrueAddressOfNameOrdinals 
//存有目標函數序號的數組首地址

TrueAddressOfNameOrdinals[i] = OrdinalsOfFunctionRva 可以得出存有函數地址RVA的數組中的序號

AddressOfFunctions + IMAGE_DOS_HEADER = RvaAddressOfFunctions
//存有函數地址RVA的數組首地址


TrueAddressOfFunctions =
 RvaAddressOfFunctions[OrdinalsOfFunctionRva] + IMAGE_DOS_HEADER 
 //目標函數在進程的地址

這樣子TrueAddressOfFunctions就是我們最後要的目標函數地址。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章