在this文章,定义是
DWORD 虚拟地址
In EXEs, this field holds the RVA to where the loader should map the section. To calculate the real starting address of a given section in memory, add the base address of the image to the section's VirtualAddress stored in this field.
DWORD PointerToRawData
This is the file-based offset of where the raw data emitted by the compiler or assembler can be found. If your program memory maps a PE or COFF file itself (rather than letting the operating system load it), this field is more important than the VirtualAddress field. You'll have a completely linear file mapping in this situation, so you'll find the data for the sections at this offset, rather than at the RVA specified in the VirtualAddress field
同时 RVA 定义为
Many fields in PE files are specified in terms of RVAs. An RVA is simply the offset of some item, relative to where the file is memory-mapped
和
To convert an RVA into a usable pointer, simply add the RVA to the base address of the module. The base address is the starting address of a memory-mapped EXE or DLL
手头的问题是到达 PE 文件的 import section。
hFile = CreateFile(..);
hFileMapping = CreateFileMapping(..);
lpFileBase = MapViewOfFile(..);
ImageBase = (PIMAGE_DOS_HEADER)lpFileBase;
PEHeader = (ImageBase + ImageBase->e_lfanew);
现在获取导入表
PIMAGE_OPTIONAL_HEADER PEImageOptionalHeader = &(PEHeader->OptionalHeader);
IMAGE_DATA_DIRECTORY importTable = PEImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
因为 importTable.VirtualAddress 是一个 RVA,为了获得可用的指针,我可以添加图像文件的基地址。
所以 ImageBase + importTable.virtualAddress 应该让我导入部分。但它没有。为什么?
然后,如果我到达正确的部分标题(通常是 .idata)并执行此操作。
ImageBase + pointerToSection->PointerToRawData;
上面正确地将我带到了 IMAGE_IMPORT_DESCRIPTORS 数组。我知道使用 pointerToSection->virtualAddress 而不是上面的 PointerToRawData 是行不通的因为我自己映射 PE 文件。
现在要获取项目的 name,加载的模块依赖于,我可以使用指向 IMAGE_IMPORT_DESCRIPTORS 的指针,使用字段 name这又是一个RVA。要转换一个RVA,我只需添加ImageBase..
LPSTR libname = (PCHAR)((DWORD)ImageBase+ImageimportDescriptor->Name);
但它不起作用。为什么?要转换RVA,我们只需添加图像的基地址。下面的工作
ImageBase+ImageimportDescriptor->Name + pointerToSection->PointerToRawData - pointerToSection->virtualAddress
每次我需要一个部分中的一些信息时,我都需要进行此调整
pointerToSection->PointerToRawData - pointerToSection->virtualAddress
为什么需要进行此调整?
最佳答案
首先,这一行:
PEHeader = (ImageBase + ImageBase->e_lfanew);
不正确。 ImageBase 是 PIMAGE_DOS_HEADERS 类型,所以当你向它添加 ImageBase->e_lfanew 时,这是一个 DWORD 你是做 pointer arithmetic ,也就是说,您向 ImageBase 添加了与 (ImageBase->e_lfanew)*sizeof(IMAGE_DOS_HEADERS) 一样多的字节,这不是您想要的。你想要的是从 ImageBase 指向的地方推进 ImageBase->e_lfanew 字节。您可以通过执行以下操作实现此目的:
PIMAGE_NT_HEADERS PEheader = (PIMAGE_NT_HEADERS) ((PBYTE)(ImageBase) + dosHeader->e_lfanew);
注意转换为 PBYTE,这使得操作逐字节推进。
这在处理 PE 文件时很常见,因为很多时候你想从指针前进 n 个字节,而不是指针指向的 n 个数据结构。 在article you refered to它甚至在评论中说:
// Ignoring typecasts and pointer conversion issues for clarity...
pNTHeader = dosHeader + dosHeader->e_lfanew;
现在回答关于 VirtualAddress 和 PointerToRawData 的你的问题:
ImageBase + importTable.virtualAddress 行也不正确,原因如下:
PE Loader 不会像您在文件映射中那样将所有可执行文件连续映射到内存中,它会将每个部分映射到其相应的 VirtualAddress。在后一种情况下,要从 RVA 获取 VA,只需将 ImageBase 添加到 RVA 即可,因为磁盘上的文件代表PE 加载程序在内存中映射的内容。但是,由于您没有将每个部分映射到 PE 加载程序将映射它们的位置,因此将 ImageBase 添加到 RVA 就像您所做的那样不起作用。
您需要一个给定 RVA 的函数,为您提供磁盘上文件中与该 RVA 相对应的文件偏移量。要获得 VA,您只需将此文件偏移量添加到指向映射文件的字节指针。
只要你有一个 RVA(比如导入部分的 RVA,或者一个名称字符串等等),为了访问它,你必须执行以下操作。
PBYTE actualAddress = (PBYTE) (lpFileBase + RVAtoFileOffset(pNTHeader, RVA))
函数如下:I posted it on pastebin因为我无法在此处正确设置格式。
它是这样工作的:当你有一个 RVA 时,该 RVA 必须位于一个部分内,因此你遍历所有部分标题(紧接在可选标题之后),当你找到 RVA 所在的部分时,您计算该 RVA 在该部分 RVA - VirtualAddress 中的偏移量,并将其添加到该部分的 PointerToRawData,现在您有了 RVA 的文件偏移量。
如果 RVA 无效(它不在任何部分内),该函数返回 0。
您需要这样做才能访问导入目录或每个导入描述符的名称,因为您拥有的是 RVA。
希望对您有所帮助。
关于c++ - IMAGE_SECTION_HEADER的VirtualAddress和PointerToRawData的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45212489/
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是
我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行
我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
转自:spring.profiles.active和spring.profiles.include的使用及区别说明下文笔者讲述spring.profiles.active和spring.profiles.include的区别简介说明,如下所示我们都知道,在日常开发中,开发|测试|生产环境都拥有不同的配置信息如:jdbc地址、ip、端口等此时为了避免每次都修改全部信息,我们则可以采用以上的属性处理此类异常spring.profiles.active属性例:配置文件,可使用以下方式定义application-${profile}.properties开发环境配置文件:application-dev
打印1:defsum(i)i=i+[2]end$x=[1]sum($x)print$x打印12:defsum(i)i.push(2)end$x=[1]sum($x)print$x后者是修改全局变量$x。为什么它在第二个例子中被修改而不是在第一个例子中?类Array的任何方法(不仅是push)都会发生这种情况吗? 最佳答案 变量范围在这里无关紧要。在第一段代码中,您仅使用赋值运算符=为变量i赋值,而在第二段代码中,您正在修改$x(也称为i)使用破坏性方法push。赋值从不修改任何对象。它只是提供一个名称来引用一个对象。方法要么是破坏性
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
Ruby中的Fixnum方法.next和.succ有什么区别?看起来它的工作原理是一样的:1.next=>21.succ=>2如果有什么不同,为什么有两种方法做同样的事情? 最佳答案 它们是等价的。Fixnum#succ只是Fixnum#next的同义词。他们甚至在thereferencemanual中共享同一block. 关于ruby-Ruby中.next和.succ的区别,我们在StackOverflow上找到一个类似的问题: https://stacko
我明白了defa(&block)block.call(self)end和defa()yieldselfend导致相同的结果,如果我假设有这样一个blocka{}。我的问题是-因为我偶然发现了一些这样的代码,它是否有任何区别或者是否有任何优势(如果我不使用变量/引用block):defa(&block)yieldselfend这是一个我不理解&block用法的具体案例:defrule(code,name,&block)@rules=[]if@rules.nil?@rules 最佳答案 我能想到的唯一优点就是自省(introspecti