TestDll
// dllmain.cpp : 定义 DLL 应用程序的入口点。#include "stdafx.h"#include <windows.h>extern "C" __declspec(dllexport)void funA(){ MessageBox(0, L"funA", L"", 0);}extern "C" __declspec(dllexport)void funB(){ MessageBox(0, L"funB", L"", 0);}BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){ switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE;}
导入导出
// win原理Day002.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <windows.h>#define DLL "D:\\ProgramVS\\win原理Day002\\Debug\\TestDll.dll"//1 把文件读到内存中char* ReadFileToMemory(char* pFilePath){ //1 获取文件句柄 HANDLE hFile = CreateFileA(pFilePath, GENERIC_READ | GENERIC_WRITE, FALSE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf("文件打开失败\n"); return 0; } //2.获取文件大小 DWORD dwFileSize = GetFileSize(hFile, NULL); //3.申请内存空间 char* pBuf = new char[dwFileSize]{}; if (!pBuf) { CloseHandle(hFile); printf("内存申请失败\n"); return 0; } //4.读取文件内容到内存空间 DWORD dwRead; ReadFile(hFile, pBuf, dwFileSize, &dwRead, NULL); //5. 返回内存地址 return pBuf;}//2 是否是PE文件bool IsPeFile(char* pBuf){ PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf; if (pDos->e_magic != IMAGE_DOS_SIGNATURE) { printf("不是PE文件\n"); return false; } PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS) (pDos->e_lfanew + pBuf); if (pNt->Signature != IMAGE_NT_SIGNATURE) { printf("不是PE文件\n"); return false; } return true;}//3 解析PE(头部重要字段)void ShowImportantHead(char* pBuf){ PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf; PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf); //文件默认加载基址 printf("默认加载基址:0x%08X\n", pNt->OptionalHeader.ImageBase); //文件入口点 printf("文件入口点:0x%08X\n", pNt->OptionalHeader.AddressOfEntryPoint); //文件区段个数 printf("文件区段个数:%d\n", pNt->FileHeader.NumberOfSections); //。。。}//RVA to FOADWORD RVAtoFOA(DWORD dwRVA, char* pBuf){ PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf; PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf); //区段个数(文件头第二个字段) DWORD dwCount = pNt->FileHeader.NumberOfSections; //区段首地址(IMAGE_FIRST_SECTION) PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(pNt); for (DWORD i = 0; i < dwCount; i++) { //FOA = RVA - 内存中区段首地址 + 文件中区段首地址 if (dwRVA >= pSec->VirtualAddress && dwRVA < pSec->VirtualAddress + pSec->SizeOfRawData) { return dwRVA - pSec->VirtualAddress + pSec->PointerToRawData; } //下一个区段表 pSec++; } return 0;}//遍历导出表void ShowExportTable(char* pBuf){ PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf; PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf); //找到导出表(数据目录表第一项) PIMAGE_DATA_DIRECTORY pData = &pNt->OptionalHeader.DataDirectory[0]; //导出表RVA转FOA DWORD dwExportFOA = RVAtoFOA(pData->VirtualAddress, pBuf); //得到导出表在文件中的具体地址 = FOA + pBuf PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)(dwExportFOA + pBuf); //解析导出表 printf("模块名:%s\n", RVAtoFOA(pExport->Name, pBuf) + pBuf); //导出地址表中函数个数 //pExport->NumberOfFunctions //导出名称表中函数名称个数 //pExport->NumberOfNames; DWORD* pFuncAddr = (DWORD*)(RVAtoFOA(pExport->AddressOfFunctions,pBuf)+pBuf); DWORD* pFuncNameAddr = (DWORD*)(RVAtoFOA(pExport->AddressOfNames, pBuf) + pBuf); WORD* pFuncOrdinalAddr = (WORD*)(RVAtoFOA(pExport->AddressOfNameOrdinals, pBuf) + pBuf); for (int i = 0; i < pExport->NumberOfFunctions;i++) { if (pFuncAddr[i] == 0) { continue; } //检测是否存在函数名称,如果有就输出 //判断条件:序号表中存在的序号都是有名称的 bool bFlag = FALSE; for (int j = 0; j < pExport->NumberOfNames; j++) { if (i == pFuncOrdinalAddr[j]) { //有名称的函数 bFlag = TRUE; DWORD dwNameRVA = pFuncNameAddr[j]; printf("函数序号:%d 函数名称【%s】\n", i + pExport->Base, RVAtoFOA(dwNameRVA,pBuf)+pBuf); break; } } if (!bFlag) { //i+pExport->Base调用号 printf("函数序号:%d 函数名称【NULL】\n", i+pExport->Base); } }}//遍历导入表void ShowImportTable(char* pBuf){ PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf; PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf); //找到导入表(数据目录表的第二项) DWORD dwImportRVA = pNt->OptionalHeader.DataDirectory[1].VirtualAddress; PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)(RVAtoFOA(dwImportRVA, pBuf) + pBuf); //解析导入表(以全0结构为结尾) while (pImport->Name) { //导入模块名 printf("导入模块名称:%s\n", RVAtoFOA(pImport->Name, pBuf) + pBuf); //导入名称表(以0结构为结尾) PIMAGE_THUNK_DATA pThunkINT = (PIMAGE_THUNK_DATA) (RVAtoFOA(pImport->OriginalFirstThunk, pBuf) + pBuf); //导入地址表(以0结构为结尾) PIMAGE_THUNK_DATA pThunkIAT = (PIMAGE_THUNK_DATA) (RVAtoFOA(pImport->FirstThunk, pBuf) + pBuf); while (pThunkINT->u1.AddressOfData) { //判断导入函数的导入方式 if (IMAGE_SNAP_BY_ORDINAL32(pThunkINT->u1.AddressOfData)) { //序号导入 //LOWORD(pThunkINT->u1.AddressOfData) printf("\t函数序号:【%d】函数名称:【NULL】\n", pThunkINT->u1.AddressOfData & 0xFFFF); } else { //名称导入 DWORD dwNameFOA = RVAtoFOA(pThunkINT->u1.AddressOfData, pBuf); PIMAGE_IMPORT_BY_NAME pName = (PIMAGE_IMPORT_BY_NAME) (dwNameFOA + pBuf); printf("\t函数序号:【%d】函数名称:【%s】\n", pName->Hint,pName->Name); } //下一个导入函数 pThunkINT++; //pThunkIAT++;如果是加载到内存中再做遍历,在磁盘上时,与INT是一样的 } //下一个导入表(下一个导入模块) pImport++; }}int _tmain(int argc, _TCHAR* argv[]){// void(*pFun)();// HMODULE hMod = LoadLibraryA(DLL);// pFun = (void(*)())GetProcAddress(hMod, (char*)1);// pFun(); char* pBuf = ReadFileToMemory("TestDll.dll"); if (IsPeFile(pBuf)) { //ShowImportantHead(pBuf); //ShowExportTable(pBuf); ShowImportTable(pBuf); } //释放内存 delete pBuf; return 0;}
TLS
// TLS.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include<windows.h>#pragma comment(linker, "/INCLUDE:__tls_used")// TLS变量__declspec (thread) int g_nNum = 0x11111111;__declspec (thread) char g_szStr[] = "TLS g_nNum = 0x%p ...\r\n";// TLS回调函数Avoid NTAPI t_TlsCallBack_A(PVOID DllHandle, DWORD Reason, PVOID Red) { if (DLL_THREAD_DETACH == Reason) // 如果线程退出则打印信息 printf("t_TlsCallBack_A -> ThreadDetach!\r\n"); return;}// TLS回调函数Bvoid NTAPI t_TlsCallBack_B(PVOID DllHandle, DWORD Reason, PVOID Red) { if (DLL_THREAD_DETACH == Reason) // 如果线程退出则打印信息 printf("t_TlsCallBack_B -> ThreadDetach!\r\n"); return;}/** 注册TLS回调函数,".CRT$XLB"的含义是:* CRT表明使用C RunTime机制* X表示标识名随机* L表示TLS callback section* B其实也可以为B-Y的任意一个字母*/#pragma data_seg(".CRT$XLB")PIMAGE_TLS_CALLBACK p_thread_callback[] = { t_TlsCallBack_A, t_TlsCallBack_B, NULL };#pragma data_seg()DWORD WINAPI t_ThreadFun(PVOID pParam) { printf("t_Thread -> first printf:"); printf(g_szStr, g_nNum); g_nNum = 0x22222222; // 注意这里 printf("t_Thread -> second printf:"); printf(g_szStr, g_nNum); return 0;}int _tmain(int argc, _TCHAR* argv[]) { printf("_tmain -> TlsDemo.exe is runing...\r\n\r\n"); CreateThread(NULL, 0, t_ThreadFun, NULL, 0, 0); Sleep(100); // 睡眠100毫秒用于确保第一个线程执行完毕 printf("\r\n"); CreateThread(NULL, 0, t_ThreadFun, NULL, 0, 0); system("pause"); return 0;}
延迟加载
// 延迟加载.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <windows.h>//包含头文件和库文件#include <delayimp.h>#pragma comment(lib, "Delayimp.lib")//设置“连接器”>“输入”>“延迟加载的DLL”选项//中的值为我们需要延迟加载的DLL名称(大小写必须完全一致)int _tmain(int argc, _TCHAR* argv[]){ MessageBox(0, 0, 0, 0); return 0;}