查询函数地址--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]
这个成员是数据目录表 放着下图数据
我们取出第一号元素 也就是导出表 来找我们的函数地址
那首先我们得知道导出表结构体中的成员
在这个结构体中我们首先取出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就是我们最后要的目标函数地址。
上一篇: 运动物体检测以及追踪