TestDll

  1. // dllmain.cpp : 定义 DLL 应用程序的入口点。
  2. #include "stdafx.h"
  3. #include <windows.h>
  4. extern "C" __declspec(dllexport)
  5. void funA()
  6. {
  7. MessageBox(0, L"funA", L"", 0);
  8. }
  9. extern "C" __declspec(dllexport)
  10. void funB()
  11. {
  12. MessageBox(0, L"funB", L"", 0);
  13. }
  14. BOOL APIENTRY DllMain( HMODULE hModule,
  15. DWORD ul_reason_for_call,
  16. LPVOID lpReserved
  17. )
  18. {
  19. switch (ul_reason_for_call)
  20. {
  21. case DLL_PROCESS_ATTACH:
  22. case DLL_THREAD_ATTACH:
  23. case DLL_THREAD_DETACH:
  24. case DLL_PROCESS_DETACH:
  25. break;
  26. }
  27. return TRUE;
  28. }

导入导出

  1. // win原理Day002.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <windows.h>
  5. #define DLL "D:\\ProgramVS\\win原理Day002\\Debug\\TestDll.dll"
  6. //1 把文件读到内存中
  7. char* ReadFileToMemory(char* pFilePath)
  8. {
  9. //1 获取文件句柄
  10. HANDLE hFile = CreateFileA(pFilePath,
  11. GENERIC_READ | GENERIC_WRITE,
  12. FALSE,
  13. NULL,
  14. OPEN_EXISTING,
  15. FILE_ATTRIBUTE_NORMAL,
  16. NULL);
  17. if (hFile == INVALID_HANDLE_VALUE)
  18. {
  19. printf("文件打开失败\n");
  20. return 0;
  21. }
  22. //2.获取文件大小
  23. DWORD dwFileSize = GetFileSize(hFile, NULL);
  24. //3.申请内存空间
  25. char* pBuf = new char[dwFileSize]{};
  26. if (!pBuf)
  27. {
  28. CloseHandle(hFile);
  29. printf("内存申请失败\n");
  30. return 0;
  31. }
  32. //4.读取文件内容到内存空间
  33. DWORD dwRead;
  34. ReadFile(hFile, pBuf, dwFileSize, &dwRead, NULL);
  35. //5. 返回内存地址
  36. return pBuf;
  37. }
  38. //2 是否是PE文件
  39. bool IsPeFile(char* pBuf)
  40. {
  41. PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf;
  42. if (pDos->e_magic != IMAGE_DOS_SIGNATURE)
  43. {
  44. printf("不是PE文件\n");
  45. return false;
  46. }
  47. PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)
  48. (pDos->e_lfanew + pBuf);
  49. if (pNt->Signature != IMAGE_NT_SIGNATURE)
  50. {
  51. printf("不是PE文件\n");
  52. return false;
  53. }
  54. return true;
  55. }
  56. //3 解析PE(头部重要字段)
  57. void ShowImportantHead(char* pBuf)
  58. {
  59. PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf;
  60. PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf);
  61. //文件默认加载基址
  62. printf("默认加载基址:0x%08X\n", pNt->OptionalHeader.ImageBase);
  63. //文件入口点
  64. printf("文件入口点:0x%08X\n", pNt->OptionalHeader.AddressOfEntryPoint);
  65. //文件区段个数
  66. printf("文件区段个数:%d\n", pNt->FileHeader.NumberOfSections);
  67. //。。。
  68. }
  69. //RVA to FOA
  70. DWORD RVAtoFOA(DWORD dwRVA, char* pBuf)
  71. {
  72. PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf;
  73. PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf);
  74. //区段个数(文件头第二个字段)
  75. DWORD dwCount = pNt->FileHeader.NumberOfSections;
  76. //区段首地址(IMAGE_FIRST_SECTION)
  77. PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(pNt);
  78. for (DWORD i = 0; i < dwCount; i++)
  79. {
  80. //FOA = RVA - 内存中区段首地址 + 文件中区段首地址
  81. if (dwRVA >= pSec->VirtualAddress &&
  82. dwRVA < pSec->VirtualAddress + pSec->SizeOfRawData)
  83. {
  84. return dwRVA - pSec->VirtualAddress + pSec->PointerToRawData;
  85. }
  86. //下一个区段表
  87. pSec++;
  88. }
  89. return 0;
  90. }
  91. //遍历导出表
  92. void ShowExportTable(char* pBuf)
  93. {
  94. PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf;
  95. PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf);
  96. //找到导出表(数据目录表第一项)
  97. PIMAGE_DATA_DIRECTORY pData = &pNt->OptionalHeader.DataDirectory[0];
  98. //导出表RVA转FOA
  99. DWORD dwExportFOA = RVAtoFOA(pData->VirtualAddress, pBuf);
  100. //得到导出表在文件中的具体地址 = FOA + pBuf
  101. PIMAGE_EXPORT_DIRECTORY pExport =
  102. (PIMAGE_EXPORT_DIRECTORY)(dwExportFOA + pBuf);
  103. //解析导出表
  104. printf("模块名:%s\n", RVAtoFOA(pExport->Name, pBuf) + pBuf);
  105. //导出地址表中函数个数
  106. //pExport->NumberOfFunctions
  107. //导出名称表中函数名称个数
  108. //pExport->NumberOfNames;
  109. DWORD* pFuncAddr = (DWORD*)(RVAtoFOA(pExport->AddressOfFunctions,pBuf)+pBuf);
  110. DWORD* pFuncNameAddr = (DWORD*)(RVAtoFOA(pExport->AddressOfNames, pBuf) + pBuf);
  111. WORD* pFuncOrdinalAddr = (WORD*)(RVAtoFOA(pExport->AddressOfNameOrdinals, pBuf) + pBuf);
  112. for (int i = 0; i < pExport->NumberOfFunctions;i++)
  113. {
  114. if (pFuncAddr[i] == 0)
  115. {
  116. continue;
  117. }
  118. //检测是否存在函数名称,如果有就输出
  119. //判断条件:序号表中存在的序号都是有名称的
  120. bool bFlag = FALSE;
  121. for (int j = 0; j < pExport->NumberOfNames; j++)
  122. {
  123. if (i == pFuncOrdinalAddr[j])
  124. {
  125. //有名称的函数
  126. bFlag = TRUE;
  127. DWORD dwNameRVA = pFuncNameAddr[j];
  128. printf("函数序号:%d 函数名称【%s】\n",
  129. i + pExport->Base,
  130. RVAtoFOA(dwNameRVA,pBuf)+pBuf);
  131. break;
  132. }
  133. }
  134. if (!bFlag)
  135. {
  136. //i+pExport->Base调用号
  137. printf("函数序号:%d 函数名称【NULL】\n", i+pExport->Base);
  138. }
  139. }
  140. }
  141. //遍历导入表
  142. void ShowImportTable(char* pBuf)
  143. {
  144. PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf;
  145. PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf);
  146. //找到导入表(数据目录表的第二项)
  147. DWORD dwImportRVA = pNt->OptionalHeader.DataDirectory[1].VirtualAddress;
  148. PIMAGE_IMPORT_DESCRIPTOR pImport =
  149. (PIMAGE_IMPORT_DESCRIPTOR)(RVAtoFOA(dwImportRVA, pBuf) + pBuf);
  150. //解析导入表(以全0结构为结尾)
  151. while (pImport->Name)
  152. {
  153. //导入模块名
  154. printf("导入模块名称:%s\n", RVAtoFOA(pImport->Name, pBuf) + pBuf);
  155. //导入名称表(以0结构为结尾)
  156. PIMAGE_THUNK_DATA pThunkINT =
  157. (PIMAGE_THUNK_DATA)
  158. (RVAtoFOA(pImport->OriginalFirstThunk, pBuf) + pBuf);
  159. //导入地址表(以0结构为结尾)
  160. PIMAGE_THUNK_DATA pThunkIAT =
  161. (PIMAGE_THUNK_DATA)
  162. (RVAtoFOA(pImport->FirstThunk, pBuf) + pBuf);
  163. while (pThunkINT->u1.AddressOfData)
  164. {
  165. //判断导入函数的导入方式
  166. if (IMAGE_SNAP_BY_ORDINAL32(pThunkINT->u1.AddressOfData))
  167. {
  168. //序号导入
  169. //LOWORD(pThunkINT->u1.AddressOfData)
  170. printf("\t函数序号:【%d】函数名称:【NULL】\n",
  171. pThunkINT->u1.AddressOfData & 0xFFFF);
  172. }
  173. else
  174. {
  175. //名称导入
  176. DWORD dwNameFOA = RVAtoFOA(pThunkINT->u1.AddressOfData, pBuf);
  177. PIMAGE_IMPORT_BY_NAME pName =
  178. (PIMAGE_IMPORT_BY_NAME)
  179. (dwNameFOA + pBuf);
  180. printf("\t函数序号:【%d】函数名称:【%s】\n",
  181. pName->Hint,pName->Name);
  182. }
  183. //下一个导入函数
  184. pThunkINT++;
  185. //pThunkIAT++;如果是加载到内存中再做遍历,在磁盘上时,与INT是一样的
  186. }
  187. //下一个导入表(下一个导入模块)
  188. pImport++;
  189. }
  190. }
  191. int _tmain(int argc, _TCHAR* argv[])
  192. {
  193. // void(*pFun)();
  194. // HMODULE hMod = LoadLibraryA(DLL);
  195. // pFun = (void(*)())GetProcAddress(hMod, (char*)1);
  196. // pFun();
  197. char* pBuf = ReadFileToMemory("TestDll.dll");
  198. if (IsPeFile(pBuf))
  199. {
  200. //ShowImportantHead(pBuf);
  201. //ShowExportTable(pBuf);
  202. ShowImportTable(pBuf);
  203. }
  204. //释放内存
  205. delete pBuf;
  206. return 0;
  207. }

TLS

  1. // TLS.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include<windows.h>
  5. #pragma comment(linker, "/INCLUDE:__tls_used")
  6. // TLS变量
  7. __declspec (thread) int g_nNum = 0x11111111;
  8. __declspec (thread) char g_szStr[] = "TLS g_nNum = 0x%p ...\r\n";
  9. // TLS回调函数A
  10. void NTAPI t_TlsCallBack_A(PVOID DllHandle, DWORD Reason, PVOID Red) {
  11. if (DLL_THREAD_DETACH == Reason) // 如果线程退出则打印信息
  12. printf("t_TlsCallBack_A -> ThreadDetach!\r\n");
  13. return;
  14. }
  15. // TLS回调函数B
  16. void NTAPI t_TlsCallBack_B(PVOID DllHandle, DWORD Reason, PVOID Red) {
  17. if (DLL_THREAD_DETACH == Reason) // 如果线程退出则打印信息
  18. printf("t_TlsCallBack_B -> ThreadDetach!\r\n");
  19. return;
  20. }
  21. /*
  22. * 注册TLS回调函数,".CRT$XLB"的含义是:
  23. * CRT表明使用C RunTime机制
  24. * X表示标识名随机
  25. * L表示TLS callback section
  26. * B其实也可以为B-Y的任意一个字母
  27. */
  28. #pragma data_seg(".CRT$XLB")
  29. PIMAGE_TLS_CALLBACK p_thread_callback[] = {
  30. t_TlsCallBack_A,
  31. t_TlsCallBack_B,
  32. NULL };
  33. #pragma data_seg()
  34. DWORD WINAPI t_ThreadFun(PVOID pParam) {
  35. printf("t_Thread -> first printf:");
  36. printf(g_szStr, g_nNum);
  37. g_nNum = 0x22222222; // 注意这里
  38. printf("t_Thread -> second printf:");
  39. printf(g_szStr, g_nNum);
  40. return 0;
  41. }
  42. int _tmain(int argc, _TCHAR* argv[]) {
  43. printf("_tmain -> TlsDemo.exe is runing...\r\n\r\n");
  44. CreateThread(NULL, 0, t_ThreadFun, NULL, 0, 0);
  45. Sleep(100); // 睡眠100毫秒用于确保第一个线程执行完毕
  46. printf("\r\n");
  47. CreateThread(NULL, 0, t_ThreadFun, NULL, 0, 0);
  48. system("pause");
  49. return 0;
  50. }

延迟加载

  1. // 延迟加载.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <windows.h>
  5. //包含头文件和库文件
  6. #include <delayimp.h>
  7. #pragma comment(lib, "Delayimp.lib")
  8. //设置“连接器”>“输入”>“延迟加载的DLL”选项
  9. //中的值为我们需要延迟加载的DLL名称(大小写必须完全一致)
  10. int _tmain(int argc, _TCHAR* argv[])
  11. {
  12. MessageBox(0, 0, 0, 0);
  13. return 0;
  14. }