依星源码资源网,依星资源网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 383|回复: 0

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

[复制链接] 主动推送

5449

主题

5496

帖子

6838

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
6838
发表于 2023-8-15 17:25:51 | 显示全部楼层 |阅读模式
VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)
附件中为本例中的示例工程下载:
文件名称:提取码下载.txt 
下载次数:6  文件大小:17 Bytes  售价:15金钱 [记录]
下载权限: 不限 [购买VIP]   [充值]   [在线充值]   【VIP会员5折;永久VIP免费】
安全检测,请放心下载


一、VC++6.0生成示例DLL项目

1.新建项目,这里选择Win32 Dynamic-link Library,如下图:

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

2.选择“A simple DLL project”,然后点击完成,如下:

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

3.生成示例项目后,如下图:

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

4.添加自己的示例函数,这里以简单的求和函数为例:
  1. /*
  2. 程序功能:DLL生成项目,生成测试的DLL文件,
  3. 作者:依星
  4. QQ:34596561,312337667
  5. 日期:2023/8/15
  6. */
  7. #include "stdafx.h"

  8. extern "C" __declspec(dllexport) int sum(int a,int b);

  9. BOOL APIENTRY DllMain( HANDLE hModule,
  10.                        DWORD  ul_reason_for_call,
  11.                        LPVOID lpReserved
  12.                                          )
  13. {
  14.     return TRUE;
  15. }

  16. extern "C" __declspec(dllexport) int sum(int a,int b)
  17. {
  18.         return a+b;
  19. }
复制代码
5.设置项目为release,开始编译构建DLL文件,按“F7”。
二、用WinHex复制取得DLL文件的全部数据

这里使用WinHex来取得DLL的全部数据,具体使用流程如下:

1.打开WinHex,然后将DLL文件拖入到主界面中,如下图:

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

2.选择“编辑”---“复制所有”---“C源码”,这里实际是复制了所有的数据,如下图:

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

3.新建一个记事本,命名为“dll.h” ,将上面复制的数据粘贴到记事本中,然后将此文件复制到VC2015项目中。

三、建立VC2015示例工程,调用CMemLoadDll类源码

1. 这里先用VC2015建立一个标准的MFC工程项目,新建---项目,如下:

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

2. 选择MFC--MFC应用程序,然后选择保存的目录,并命名项目名称,如下图:

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

3.下一步,然后再选择“基于对话框”,点击“在静态库中使用MFC”,如下图:

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

4.至此没有特别要设置的了,点击下一步,直到完成。

5.项目创建后,默认为Unicode字符集,这里改为多字节;(PS:其实改不改都行,主要是项目中都是使用的多字节,习惯了)如下图:

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

6.将上一步生成的Dll.h文件添加到解决方案的头文件中,然后再新建一个头文件和源文件,用于把网上的CMemLoadDll类源码复制过来,源码将在后面贴出来,咱们先说流程。添加好之后,如下图工程目录:

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

7.在主对话框中,加一个按钮,用于调用示例:

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

8.双击按钮,显示点击方法(MemRunDllDlg.cpp):

  1. /*
  2. 调用CMemLoadDll,
  3. 加载内存中的DLL,
  4. 并运行DLL中的函数
  5. //
  6. dllData:为生成的测试DLL数据文件dll.h;(注:此处也可以把这个DLL文件加到资源中加载,或者以文件形式读取到内存中,都是可以的)
  7. 为安全起见,可以把DLL的数据加密存储到DLL.H中,本例不再展示。
  8. */
  9. void CMemRunDllDlg::OnBnClickedButton1()
  10. {
  11.         // TODO: 在此添加控件通知处理程序代码
  12.         CMemLoadDll *pMemLoadDll = new CMemLoadDll();
  13.         if (!pMemLoadDll->MemLoadLibrary(&dllData, sizeof(dllData))) //加载dll到当前进程的地址空间
  14.         {
  15.                 AfxMessageBox("Load DLL error!");
  16.                 return ;
  17.         }

  18.         addNumberProc addNumber = (addNumberProc)pMemLoadDll->MemGetProcAddress("sum");
  19.         if (addNumber == NULL)
  20.         {
  21.                 AfxMessageBox("Find Add function failed!");
  22.                 return ;
  23.         }
  24.         int c = addNumber(1, 2);

  25.         char itc[10];
  26.         sprintf(itc, "%d", c);
  27.         AfxMessageBox(itc);

  28. }
复制代码

9 .在此文件头部(MemRunDllDlg.cpp),加入文件引用及DLL函数声明,如下:

  1. #include "dll.h"
  2. #include "MemLoadDll.h"

  3. typedef int(*addNumberProc)(int, int);
复制代码

10.生成EXE并运行,正常运行,如下:

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)

四、CMemLoadDll类源码,网上搜索的,作者不详

1.MemLoadDll.h头文件

  1. #pragma once  

  2. typedef   BOOL(__stdcall *ProcDllMain)(HINSTANCE, DWORD, LPVOID);

  3. class CMemLoadDll
  4. {
  5. public:
  6.         CMemLoadDll();
  7.         ~CMemLoadDll();
  8.         BOOL    MemLoadLibrary(void *lpFileData, int DataLength);  // Dll file data buffer  
  9.         FARPROC MemGetProcAddress(LPCSTR lpProcName);
  10. private:
  11.         BOOL isLoadOk;
  12.         BOOL CheckDataValide(void *lpFileData, int DataLength);
  13.         int  CalcTotalImageSize();
  14.         void CopyDllDatas(void *pDest, void *pSrc);
  15.         BOOL FillRavAddress(void *pBase);
  16.         void DoRelocation(void *pNewBase);
  17.         int  GetAlignedSize(int Origin, int Alignment);
  18. private:
  19.         ProcDllMain pDllMain;

  20. private:
  21.         DWORD  pImageBase;
  22.         PIMAGE_DOS_HEADER pDosHeader;
  23.         PIMAGE_NT_HEADERS pNTHeader;
  24.         PIMAGE_SECTION_HEADER pSectionHeader;

  25. };
复制代码

2.MemLoadDll.cpp源文件

  1. #include "stdafx.h"
  2. #include <windows.h>  
  3. #include <assert.h>  
  4. #include "MemLoadDll.h"  


  5. CMemLoadDll::CMemLoadDll()
  6. {
  7.         isLoadOk = FALSE;
  8.         pImageBase = NULL;
  9.         pDllMain = NULL;
  10. }

  11. CMemLoadDll::~CMemLoadDll()
  12. {
  13.         if (isLoadOk)
  14.         {
  15.                 assert(pImageBase != NULL);
  16.                 assert(pDllMain != NULL);
  17.                 //脱钩,准备卸载dll  
  18.                 pDllMain((HINSTANCE)pImageBase, DLL_PROCESS_DETACH, 0);
  19.                 VirtualFree((LPVOID)pImageBase, 0, MEM_RELEASE);
  20.         }
  21. }

  22. //MemLoadLibrary函数从内存缓冲区数据中加载一个dll到当前进程的地址空间,缺省位置0x10000000  
  23. //返回值: 成功返回TRUE , 失败返回FALSE  
  24. //lpFileData: 存放dll文件数据的缓冲区  
  25. //DataLength: 缓冲区中数据的总长度  
  26. BOOL CMemLoadDll::MemLoadLibrary(void *lpFileData, int DataLength)
  27. {
  28.         if (pImageBase != NULL)
  29.         {
  30.                 return FALSE;  //已经加载一个dll,还没有释放,不能加载新的dll  
  31.         }

  32.         //检查数据有效性,并初始化  
  33.         if (!CheckDataValide(lpFileData, DataLength))
  34.         {
  35.                 return FALSE;
  36.         }

  37.         //计算所需的加载空间  
  38.         int ImageSize = CalcTotalImageSize();
  39.         if (ImageSize == 0)
  40.         {
  41.                 return FALSE;
  42.         }

  43.         // 分配虚拟内存  
  44.         void *pMemoryAddress = VirtualAlloc((LPVOID)NULL, ImageSize,
  45.                 MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  46.         if (pMemoryAddress == NULL)
  47.         {
  48.                 return FALSE;
  49.         }
  50.         else
  51.         {
  52.                 CopyDllDatas(pMemoryAddress, lpFileData); //复制dll数据,并对齐每个段  

  53.                                                                                                   //重定位信息  
  54.                 if (pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress > 0
  55.                         && pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > 0)
  56.                 {
  57.                         DoRelocation(pMemoryAddress);
  58.                 }

  59.                 //填充引入地址表  
  60.                 if (!FillRavAddress(pMemoryAddress))  //修正引入地址表失败  
  61.                 {
  62.                         VirtualFree(pMemoryAddress, 0, MEM_RELEASE);
  63.                         return FALSE;
  64.                 }

  65.                 //修改页属性。应该根据每个页的属性单独设置其对应内存页的属性。这里简化一下。  
  66.                 //统一设置成一个属性PAGE_EXECUTE_READWRITE  
  67.                 unsigned long old;
  68.                 VirtualProtect(pMemoryAddress, ImageSize, PAGE_EXECUTE_READWRITE, &old);
  69.         }

  70.         //修正基地址  
  71.         pNTHeader->OptionalHeader.ImageBase = (DWORD)pMemoryAddress;

  72.         //接下来要调用一下dll的入口函数,做初始化工作。  
  73.         pDllMain = (ProcDllMain)(pNTHeader->OptionalHeader.AddressOfEntryPoint + (DWORD)pMemoryAddress);

  74.         BOOL InitResult = pDllMain((HINSTANCE)pMemoryAddress, DLL_PROCESS_ATTACH, 0);
  75.         if (!InitResult)  //初始化失败  
  76.         {
  77.                 pDllMain((HINSTANCE)pMemoryAddress, DLL_PROCESS_DETACH, 0);
  78.                 VirtualFree(pMemoryAddress, 0, MEM_RELEASE);
  79.                 pDllMain = NULL;
  80.                 return FALSE;
  81.         }

  82.         isLoadOk = TRUE;
  83.         pImageBase = (DWORD)pMemoryAddress;
  84.         return TRUE;
  85. }

  86. //MemGetProcAddress函数从dll中获取指定函数的地址  
  87. //返回值: 成功返回函数地址 , 失败返回NULL  
  88. //lpProcName: 要查找函数的名字或者序号  
  89. FARPROC  CMemLoadDll::MemGetProcAddress(LPCSTR lpProcName)
  90. {
  91.         if (pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0 ||
  92.                 pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size == 0)
  93.         {
  94.                 return NULL;
  95.         }

  96.         if (!isLoadOk)
  97.         {
  98.                 return NULL;
  99.         }

  100.         DWORD OffsetStart = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
  101.         DWORD Size = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;

  102.         PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pImageBase + pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
  103.         int iBase = pExport->Base;
  104.         int iNumberOfFunctions = pExport->NumberOfFunctions;
  105.         int iNumberOfNames = pExport->NumberOfNames; //<= iNumberOfFunctions  
  106.         LPDWORD pAddressOfFunctions = (LPDWORD)(pExport->AddressOfFunctions + pImageBase);
  107.         LPWORD  pAddressOfOrdinals = (LPWORD)(pExport->AddressOfNameOrdinals + pImageBase);
  108.         LPDWORD pAddressOfNames = (LPDWORD)(pExport->AddressOfNames + pImageBase);

  109.         int iOrdinal = -1;

  110.         if (((DWORD)lpProcName & 0xFFFF0000) == 0)  //IT IS A ORDINAL!  
  111.         {
  112.                 iOrdinal = (DWORD)lpProcName & 0x0000FFFF - iBase;
  113.         }
  114.         else     //use name  
  115.         {
  116.                 int iFound = -1;

  117.                 for (int i = 0; i < iNumberOfNames; i++)
  118.                 {
  119.                         char *pName = (char *)(pAddressOfNames[i] + pImageBase);
  120.                         if (strcmp(pName, lpProcName) == 0)
  121.                         {
  122.                                 iFound = i;
  123.                                 break;
  124.                         }
  125.                 }
  126.                 if (iFound >= 0)
  127.                 {
  128.                         iOrdinal = (int)(pAddressOfOrdinals[iFound]);
  129.                 }
  130.         }

  131.         if (iOrdinal < 0 || iOrdinal >= iNumberOfFunctions)
  132.         {
  133.                 return NULL;
  134.         }
  135.         else
  136.         {
  137.                 DWORD pFunctionOffset = pAddressOfFunctions[iOrdinal];
  138.                 if (pFunctionOffset > OffsetStart && pFunctionOffset < (OffsetStart + Size)) //maybe Export Forwarding  
  139.                 {
  140.                         return NULL;
  141.                 }
  142.                 else
  143.                 {
  144.                         return (FARPROC)(pFunctionOffset + pImageBase);
  145.                 }
  146.         }

  147. }

  148. // 重定向PE用到的地址  
  149. void CMemLoadDll::DoRelocation(void *NewBase)
  150. {
  151.         /* 重定位表的结构:
  152.         // DWORD sectionAddress, DWORD size (包括本节需要重定位的数据)
  153.         // 例如 1000节需要修正5个重定位数据的话,重定位表的数据是
  154.         // 00 10 00 00   14 00 00 00      xxxx xxxx xxxx xxxx xxxx 0000
  155.         // -----------   -----------      ----
  156.         // 给出节的偏移  总尺寸=8+6*2     需要修正的地址           用于对齐4字节
  157.         // 重定位表是若干个相连,如果address 和 size都是0 表示结束
  158.         // 需要修正的地址是12位的,高4位是形态字,intel cpu下是3
  159.         */
  160.         //假设NewBase是0x600000,而文件中设置的缺省ImageBase是0x400000,则修正偏移量就是0x200000  
  161.         DWORD Delta = (DWORD)NewBase - pNTHeader->OptionalHeader.ImageBase;

  162.         //注意重定位表的位置可能和硬盘文件中的偏移地址不同,应该使用加载后的地址  
  163.         PIMAGE_BASE_RELOCATION pLoc = (PIMAGE_BASE_RELOCATION)((unsigned long)NewBase
  164.                 + pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
  165.         while ((pLoc->VirtualAddress + pLoc->SizeOfBlock) != 0)  //开始扫描重定位表  
  166.         {
  167.                 WORD *pLocData = (WORD *)((int)pLoc + sizeof(IMAGE_BASE_RELOCATION));
  168.                 //计算本节需要修正的重定位项(地址)的数目  
  169.                 int NumberOfReloc = (pLoc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
  170.                 for (int i = 0; i < NumberOfReloc; i++)
  171.                 {
  172.                         if ((DWORD)(pLocData[i] & 0xF000) == 0x00003000)  //这是一个需要修正的地址  
  173.                         {
  174.                                 // 举例:  
  175.                                 // pLoc->VirtualAddress = 0x1000;  
  176.                                 // pLocData[i] = 0x313E; 表示本节偏移地址0x13E处需要修正  
  177.                                 // 因此 pAddress = 基地址 + 0x113E  
  178.                                 // 里面的内容是 A1 ( 0c d4 02 10)  汇编代码是: mov eax , [1002d40c]  
  179.                                 // 需要修正1002d40c这个地址  
  180.                                 DWORD *pAddress = (DWORD *)((unsigned long)NewBase + pLoc->VirtualAddress + (pLocData[i] & 0x0FFF));
  181.                                 *pAddress += Delta;
  182.                         }
  183.                 }
  184.                 //转移到下一个节进行处理  
  185.                 pLoc = (PIMAGE_BASE_RELOCATION)((DWORD)pLoc + pLoc->SizeOfBlock);
  186.         }
  187. }

  188. //填充引入地址表  
  189. BOOL CMemLoadDll::FillRavAddress(void *pImageBase)
  190. {
  191.         // 引入表实际上是一个 IMAGE_IMPORT_DESCRIPTOR 结构数组,全部是0表示结束  
  192.         // 数组定义如下:  
  193.         //  
  194.         // DWORD   OriginalFirstThunk;         // 0表示结束,否则指向未绑定的IAT结构数组  
  195.         // DWORD   TimeDateStamp;  
  196.         // DWORD   ForwarderChain;             // -1 if no forwarders  
  197.         // DWORD   Name;                       // 给出dll的名字  
  198.         // DWORD   FirstThunk;                 // 指向IAT结构数组的地址(绑定后,这些IAT里面就是实际的函数地址)  

  199.         int i;

  200.         unsigned long Offset = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
  201.         if (Offset == 0)
  202.         {
  203.                 return TRUE;    //No Import Table  
  204.         }
  205.         PIMAGE_IMPORT_DESCRIPTOR pID = (PIMAGE_IMPORT_DESCRIPTOR)((unsigned long)pImageBase + Offset);
  206.         while (pID->Characteristics != 0)
  207.         {
  208.                 PIMAGE_THUNK_DATA pRealIAT = (PIMAGE_THUNK_DATA)((unsigned long)pImageBase + pID->FirstThunk);
  209.                 PIMAGE_THUNK_DATA pOriginalIAT = (PIMAGE_THUNK_DATA)((unsigned long)pImageBase + pID->OriginalFirstThunk);
  210.                 //获取dll的名字  
  211.                 TCHAR buf[256]; //dll name;  
  212.                 BYTE *pName = (BYTE *)((unsigned long)pImageBase + pID->Name);
  213.                 for (i = 0; i < 256; i++)
  214.                 {
  215.                         if (pName[i] == 0)
  216.                         {
  217.                                 break;
  218.                         }
  219.                         buf[i] = pName[i];
  220.                 }
  221.                 if (i >= 256)
  222.                 {
  223.                         return FALSE;    // bad dll name  
  224.                 }
  225.                 else
  226.                 {
  227.                         buf[i] = 0;
  228.                 }
  229.                 HMODULE hDll = GetModuleHandle(buf);
  230.                 if (hDll == NULL)
  231.                 {
  232.                         hDll = LoadLibrary(buf);
  233.                 }
  234.                 if (hDll == NULL)
  235.                 {
  236.                         return FALSE;    //NOT FOUND DLL  
  237.                 }
  238.                 //获取DLL中每个导出函数的地址,填入IAT  
  239.                 //每个IAT结构是 :  
  240.                 // union { PBYTE  ForwarderString;  
  241.                 //   PDWORD Function;  
  242.                 //   DWORD Ordinal;  
  243.                 //   PIMAGE_IMPORT_BY_NAME  AddressOfData;  
  244.                 // } u1;  
  245.                 // 长度是一个DWORD ,正好容纳一个地址。  
  246.                 for (i = 0; ; i++)
  247.                 {
  248.                         if (pOriginalIAT[i].u1.Function == 0)
  249.                         {
  250.                                 break;
  251.                         }
  252.                         FARPROC lpFunction = NULL;
  253.                         if (pOriginalIAT[i].u1.Ordinal & IMAGE_ORDINAL_FLAG)  //这里的值给出的是导出序号  
  254.                         {
  255.                                 lpFunction = GetProcAddress(hDll, (LPCSTR)(pOriginalIAT[i].u1.Ordinal & 0x0000FFFF));
  256.                         }
  257.                         else     //按照名字导入  
  258.                         {
  259.                                 //获取此IAT项所描述的函数名称  
  260.                                 PIMAGE_IMPORT_BY_NAME pByName = (PIMAGE_IMPORT_BY_NAME)
  261.                                         ((DWORD)pImageBase + (DWORD)(pOriginalIAT[i].u1.AddressOfData));
  262.                                 //    if(pByName->Hint !=0)  
  263.                                 //     lpFunction = GetProcAddress(hDll, (LPCSTR)pByName->Hint);  
  264.                                 //    else  
  265.                                 lpFunction = GetProcAddress(hDll, (char *)pByName->Name);
  266.                         }

  267.                         if (lpFunction != NULL)  //找到了!  
  268.                         {
  269.                                 pRealIAT[i].u1.Function = (DWORD)lpFunction;//(PDWORD) lpFunction;  
  270.                         }
  271.                         else
  272.                         {
  273.                                 return FALSE;
  274.                         }
  275.                 }

  276.                 //move to next  
  277.                 pID = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pID + sizeof(IMAGE_IMPORT_DESCRIPTOR));
  278.         }

  279.         return TRUE;
  280. }

  281. //CheckDataValide函数用于检查缓冲区中的数据是否有效的dll文件  
  282. //返回值: 是一个可执行的dll则返回TRUE,否则返回FALSE。  
  283. //lpFileData: 存放dll数据的内存缓冲区  
  284. //DataLength: dll文件的长度  
  285. BOOL CMemLoadDll::CheckDataValide(void *lpFileData, int DataLength)
  286. {
  287.         //检查长度  
  288.         if (DataLength < sizeof(IMAGE_DOS_HEADER))
  289.         {
  290.                 return FALSE;
  291.         }
  292.         pDosHeader = (PIMAGE_DOS_HEADER)lpFileData;  // DOS头  
  293.                                                                                                  //检查dos头的标记  
  294.         if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
  295.         {
  296.                 return FALSE;    //0x5A4D : MZ  
  297.         }

  298.         //检查长度  
  299.         if ((DWORD)DataLength < (pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)))
  300.         {
  301.                 return FALSE;
  302.         }
  303.         //取得pe头  
  304.         pNTHeader = (PIMAGE_NT_HEADERS)((unsigned long)lpFileData + pDosHeader->e_lfanew); // PE头  
  305.                                                                                                                                                                            //检查pe头的合法性  
  306.         if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
  307.         {
  308.                 return FALSE;    //0x00004550 : PE00  
  309.         }
  310.         if ((pNTHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) //0x2000  : File is a DLL  
  311.         {
  312.                 return FALSE;
  313.         }
  314.         if ((pNTHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0) //0x0002 : 指出文件可以运行  
  315.         {
  316.                 return FALSE;
  317.         }
  318.         if (pNTHeader->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))
  319.         {
  320.                 return FALSE;
  321.         }

  322.         //取得节表(段表)  
  323.         pSectionHeader = (PIMAGE_SECTION_HEADER)((int)pNTHeader + sizeof(IMAGE_NT_HEADERS));
  324.         //验证每个节表的空间  
  325.         for (int i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++)
  326.         {
  327.                 if ((pSectionHeader[i].PointerToRawData + pSectionHeader[i].SizeOfRawData) >(DWORD)DataLength)
  328.                 {
  329.                         return FALSE;
  330.                 }
  331.         }
  332.         return TRUE;
  333. }

  334. //计算对齐边界  
  335. int CMemLoadDll::GetAlignedSize(int Origin, int Alignment)
  336. {
  337.         return (Origin + Alignment - 1) / Alignment * Alignment;
  338. }

  339. //计算整个dll映像文件的尺寸  
  340. int CMemLoadDll::CalcTotalImageSize()
  341. {
  342.         int Size;
  343.         if (pNTHeader == NULL)
  344.         {
  345.                 return 0;
  346.         }
  347.         int nAlign = pNTHeader->OptionalHeader.SectionAlignment; //段对齐字节数  

  348.                                                                                                                          // 计算所有头的尺寸。包括dos, coff, pe头 和 段表的大小  
  349.         Size = GetAlignedSize(pNTHeader->OptionalHeader.SizeOfHeaders, nAlign);
  350.         // 计算所有节的大小  
  351.         for (int i = 0; i < pNTHeader->FileHeader.NumberOfSections; ++i)
  352.         {
  353.                 //得到该节的大小  
  354.                 int CodeSize = pSectionHeader[i].Misc.VirtualSize;
  355.                 int LoadSize = pSectionHeader[i].SizeOfRawData;
  356.                 int MaxSize = (LoadSize > CodeSize) ? (LoadSize) : (CodeSize);

  357.                 int SectionSize = GetAlignedSize(pSectionHeader[i].VirtualAddress + MaxSize, nAlign);
  358.                 if (Size < SectionSize)
  359.                 {
  360.                         Size = SectionSize;    //Use the Max;  
  361.                 }
  362.         }
  363.         return Size;
  364. }
  365. //CopyDllDatas函数将dll数据复制到指定内存区域,并对齐所有节  
  366. //pSrc: 存放dll数据的原始缓冲区  
  367. //pDest:目标内存地址  
  368. void CMemLoadDll::CopyDllDatas(void *pDest, void *pSrc)
  369. {
  370.         // 计算需要复制的PE头+段表字节数  
  371.         int  HeaderSize = pNTHeader->OptionalHeader.SizeOfHeaders;
  372.         int  SectionSize = pNTHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
  373.         int  MoveSize = HeaderSize + SectionSize;
  374.         //复制头和段信息  
  375.         memmove(pDest, pSrc, MoveSize);

  376.         //复制每个节  
  377.         for (int i = 0; i < pNTHeader->FileHeader.NumberOfSections; ++i)
  378.         {
  379.                 if (pSectionHeader[i].VirtualAddress == 0 || pSectionHeader[i].SizeOfRawData == 0)
  380.                 {
  381.                         continue;
  382.                 }
  383.                 // 定位该节在内存中的位置  
  384.                 void *pSectionAddress = (void *)((unsigned long)pDest + pSectionHeader[i].VirtualAddress);
  385.                 // 复制段数据到虚拟内存  
  386.                 memmove((void *)pSectionAddress,
  387.                         (void *)((DWORD)pSrc + pSectionHeader[i].PointerToRawData),
  388.                         pSectionHeader[i].SizeOfRawData);
  389.         }

  390.         //修正指针,指向新分配的内存  
  391.         //新的dos头  
  392.         pDosHeader = (PIMAGE_DOS_HEADER)pDest;
  393.         //新的pe头地址  
  394.         pNTHeader = (PIMAGE_NT_HEADERS)((int)pDest + (pDosHeader->e_lfanew));
  395.         //新的节表地址  
  396.         pSectionHeader = (PIMAGE_SECTION_HEADER)((int)pNTHeader + sizeof(IMAGE_NT_HEADERS));
  397.         return;
  398. }
复制代码
链接:https://pan.baidu.com/s/1OUK8VxrJZZ-Cwc5t3uJLBA

附件中为本例中的示例工程下载:
文件名称:提取码下载.txt 
下载次数:6  文件大小:17 Bytes  售价:15金钱 [记录]
下载权限: 不限 [购买VIP]   [充值]   [在线充值]   【VIP会员5折;永久VIP免费】
安全检测,请放心下载






相关帖子

扫码关注微信公众号,及时获取最新资源信息!下载附件优惠VIP会员5折;永久VIP免费
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

免责声明:
1、本站提供的所有资源仅供参考学习使用,版权归原著所有,禁止下载本站资源参与商业和非法行为,请在24小时之内自行删除!
2、本站所有内容均由互联网收集整理、网友上传,并且以计算机技术研究交流为目的,仅供大家参考、学习,请勿任何商业目的与商业用途。
3、若您需要商业运营或用于其他商业活动,请您购买正版授权并合法使用。
4、论坛的所有内容都不保证其准确性,完整性,有效性。阅读本站内容因误导等因素而造成的损失本站不承担连带责任。
5、用户使用本网站必须遵守适用的法律法规,对于用户违法使用本站非法运营而引起的一切责任,由用户自行承担
6、本站所有资源来自互联网转载,版权归原著所有,用户访问和使用本站的条件是必须接受本站“免责声明”,如果不遵守,请勿访问或使用本网站
7、本站使用者因为违反本声明的规定而触犯中华人民共和国法律的,一切后果自己负责,本站不承担任何责任。
8、凡以任何方式登陆本网站或直接、间接使用本网站资料者,视为自愿接受本网站声明的约束。
9、本站以《2013 中华人民共和国计算机软件保护条例》第二章 “软件著作权” 第十七条为原则:为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。若有学员需要商用本站资源,请务必联系版权方购买正版授权!
10、本网站如无意中侵犯了某个企业或个人的知识产权,请来信【站长信箱312337667@qq.com】告之,本站将立即删除。
郑重声明:
本站所有资源仅供用户本地电脑学习源代码的内含设计思想和原理,禁止任何其他用途!
本站所有资源、教程来自互联网转载,仅供学习交流,不得商业运营资源,不确保资源完整性,图片和资源仅供参考,不提供任何技术服务。
本站资源仅供本地编辑研究学习参考,禁止未经资源商正版授权参与任何商业行为,违法行为!如需商业请购买各资源商正版授权
本站仅收集资源,提供用户自学研究使用,本站不存在私自接受协助用户架设游戏或资源,非法运营资源行为。
 
在线客服
点击这里给我发消息 点击这里给我发消息 点击这里给我发消息
售前咨询热线
312337667

微信扫一扫,私享最新原创实用干货

QQ|免责声明|依星源码资源网 ( 鲁ICP备2021043233号-3 )|网站地图

GMT+8, 2024-4-28 14:56

Powered by Net188.com X3.4

邮箱:312337667@qq.com 客服QQ:312337667(工作时间:9:00~21:00)

快速回复 返回顶部 返回列表