記憶體偏移(RVA)與檔案偏移(offset)相互轉換
寫此文源於前一陣寫一個PE修改工具,需要用到記憶體偏移向檔案偏移轉化。想著這種簡單的程式碼網上應該一大把,百度了一下,沒找到。又google,又沒找到,可能是自己搜尋的功力太不到家了。著急用,只好自己寫了一個函式用來轉換。相信很多人做PE開發的時候都會有這個需求,把這個函式貼出來供大家參考,大牛莫恥笑。
原理比較簡單:首先判斷這個地址是否在PE頭中,如果在,檔案偏移和記憶體偏移相等,如果存在於檔案的區段中,則利用以下公式:
記憶體偏移 - 該段起始的RVA(VirtualAddress) = 檔案偏移 - 該段的PointerToRawData
記憶體偏移 = 該段起始的RVA(VirtualAddress) + (檔案偏移 - 該段的PointerToRawData)
檔案偏移 = 該段的PointerToRawData + (記憶體偏移 - 該段起始的RVA(VirtualAddress))
程式碼如下:
原理比較簡單:首先判斷這個地址是否在PE頭中,如果在,檔案偏移和記憶體偏移相等,如果存在於檔案的區段中,則利用以下公式:
記憶體偏移 - 該段起始的RVA(VirtualAddress) = 檔案偏移 - 該段的PointerToRawData
記憶體偏移 = 該段起始的RVA(VirtualAddress) + (檔案偏移 - 該段的PointerToRawData)
檔案偏移 = 該段的PointerToRawData + (記憶體偏移 - 該段起始的RVA(VirtualAddress))
程式碼如下:
01.#include <stdio.h>
02./*
03.Purpose:PE檔案的記憶體偏移與檔案偏移相互轉換,不考慮系統為對齊填充偏移轉換
04.szFileName:檔名
05.dwAddr:需要轉換的偏移值
06.bFile2RVA:是否是檔案偏移到記憶體偏移的轉換,1 - dwAddr代表的是檔案偏移,此函式返回記憶體偏移
07. 0 - dwAddr代表的是記憶體偏移,此函式返回檔案偏移
08.返回值:相對應的偏移值,失敗返回-1
09.*/
10.
11.DWORD AddressConvert(char szFileName[], DWORD dwAddr, BOOL bFile2RVA)
12.{
13. char *lpBase = NULL;
14. DWORD dwRet = -1;
15. //1.首先將檔案讀入記憶體
16. if(szFileName[0] == 0)
17. {
18. return -1;
19. }
20.
21. FILE *fp = fopen(szFileName, "rb");
22. if(fp == 0)
23. {
24. return -1;
25. }
26.
27. fseek(fp, 0, SEEK_END);
28. DWORD dwFileSize = ftell(fp);
29. if(dwFileSize == 0)
30. {
31. return -1;
32. }
33.
34. lpBase = new char[dwFileSize];
35. memset(lpBase, 0, dwFileSize);
36. fseek(fp, 0, SEEK_SET);
37. fread(lpBase, 1, dwFileSize, fp);
38. fclose(fp);
39.
40. //2.讀取該檔案的資訊(檔案記憶體對齊方式以及區塊數量,並將區塊表指標指向區塊表第一個區塊頭)
41. PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpBase;
42. PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((unsigned long)lpBase + pDosHeader->e_lfanew);
43.
44. DWORD dwMemAlign = pNtHeader->OptionalHeader.SectionAlignment;
45. DWORD dwFileAlign = pNtHeader->OptionalHeader.FileAlignment;
46. int dwSecNum = pNtHeader->FileHeader.NumberOfSections;
47. PIMAGE_SECTION_HEADER pSecHeader = (PIMAGE_SECTION_HEADER)((char *)lpBase + pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS));
48. DWORD dwHeaderSize = 0;
49.
50. if(!bFile2RVA) // 記憶體偏移轉換為檔案偏移
51. {
52. //看需要轉移的偏移是否在PE頭內,如果在則兩個偏移相同
53. dwHeaderSize = pNtHeader->OptionalHeader.SizeOfHeaders;
54. if(dwAddr <= dwHeaderSize)
55. {
56. delete lpBase;
57. lpBase = NULL;
58. return dwAddr;
59. }
60. else //不再PE頭裡,檢視該地址在哪個區塊中
61. {
62. for(int i = 0; i < dwSecNum; i++)
63. {
64. DWORD dwSecSize = pSecHeader[i].Misc.VirtualSize;
65. if((dwAddr >= pSecHeader[i].VirtualAddress) && (dwAddr <= pSecHeader[i].VirtualAddress + dwSecSize))
66. {
67. //3.找到該該偏移,則檔案偏移 = 該區塊的檔案偏移 + (該偏移 - 該區塊的記憶體偏移)
68. dwRet = pSecHeader[i].PointerToRawData + dwAddr - pSecHeader[i].VirtualAddress;
69. }
70. }
71. }
72. }
73. else // 檔案偏移轉換為記憶體偏移
74. {
75. dwHeaderSize = pNtHeader->OptionalHeader.SizeOfHeaders;
76. //看需要轉移的偏移是否在PE頭內,如果在則兩個偏移相同
77. if(dwAddr <= dwHeaderSize)
78. {
79. delete lpBase;
80. lpBase = NULL;
81. return dwAddr;
82. }
83. else//不再PE頭裡,檢視該地址在哪個區塊中
84. {
85. for(int i = 0; i < dwSecNum; i++)
86. {
87. DWORD dwSecSize = pSecHeader[i].Misc.VirtualSize;
88. if((dwAddr >= pSecHeader[i].PointerToRawData) && (dwAddr <= pSecHeader[i].PointerToRawData + dwSecSize))
89. {
90. //3.找到該該偏移,則記憶體偏移 = 該區塊的記憶體偏移 + (該偏移 - 該區塊的檔案偏移)
91. dwRet = pSecHeader[i].VirtualAddress + dwAddr - pSecHeader[i].PointerToRawData;
92. }
93. }
94. }
95. }
96.
97. //5.釋放記憶體
98. delete lpBase;
99. lpBase = NULL;
100. return dwRet;
101.}
相關文章
- JavaScript--元素偏移量(offset)JavaScript
- rocketMq 訊息偏移量 OffsetMQ
- java 字串與檔案相互轉換Java字串
- JavaScript偏移量offset,可視區client,滾動scroll系列JavaScriptclient
- C#:檔案、byte[]、Stream相互轉換C#
- 元素偏移量
- UIImage與Iplimage相互轉換UI
- DataTable與List相互轉換
- SDOM與QDOM相互轉換
- kafka重置偏移量Kafka
- kafka的偏移量Kafka
- access偏移注入原理
- CAD如何批次偏移物件?物件
- cad偏移快捷鍵命令全稱 cad直線偏移命令怎麼用
- string與數字相互轉換
- JSON字串與HashMap相互轉換JSON字串HashMap
- java 物件與xml相互轉換Java物件XML
- [轉載] Java直接記憶體與堆記憶體Java記憶體
- 陣列與字串方法與相互轉換陣列字串
- string與char陣列相互轉換陣列
- pandas中dataframe與dict相互轉換
- [20230224]bbed設定偏移技巧.txt
- Torrent檔案的解析與轉換
- xml與陣列的相互轉換——phpXML陣列PHP
- jQuery 物件 與 原生 DOM 物件 相互轉換jQuery物件
- linux檔案存在記憶體裡Linux記憶體
- Java 檔案換行符識別與轉換Java
- 旋轉矩陣與尤拉角的相互轉換矩陣
- Spark Streaming 之 Kafka 偏移量管理SparkKafka
- 塊級元素與內聯元素相互轉換
- JavaScript陣列與字串相互轉換 join、splitJavaScript陣列字串
- mysql時間與字串之間相互轉換MySql字串
- Python字典格式與JSON格式的相互轉換PythonJSON
- Ubuntu 新增虛擬記憶體檔案Ubuntu記憶體
- 使用記憶體對映檔案(mmap)記憶體
- js時間戳與日期格式的相互轉換JS時間戳
- Permute for mac(媒體檔案格式轉換器)Mac
- TSC 243pro印表機偏移問題
- SWPUCTF_2019_login(格式字串偏移bss段)字串