⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jiurl pe 格式学习总结(四)-- pe文件中的资源.htm

📁 关于win2000核心编程的文章
💻 HTM
📖 第 1 页 / 共 2 页
字号:
      80&nbsp;<BR>可以看到结构成员,第一个字段的第一个字节00h的二进制为00000000,最高位为0,所以低两个字节中的值为Id,Id为3。第二个字段的第一个字节80h(如果你不明白为什么第一个字节是80h而不是30h的话,请看 
      《JIURL PE 格式学习总结(一)》中关于 big-endian和little-endian的介绍)的二进制为10000000,最高位为1 
      所以说明还有下一层,还没有到叶子,所以第二字段代表到下一层某个节点的偏移 OffsetToData 值为30。</P>
      <P align=left>一个data_entry结构 E0 23 03 00 / 30 01 00 00 / E4 04 00 00 / 00 
      00 00 
      00&nbsp;<BR>可以看到结构成员,OffsetToData为323E0h(这是一个内存中的RVA,要转化成文件中的位置,需要用这个值减去资源节的开始RVA,资源节的开始RVA可以由Optional 
      Header中的DataDirectory数组中的第三项中的VirtualAddress的值得到。或者节表中,资源节那项中的VirtualAddress的值得到。相减之后,就可以得到相对于资源节开始的偏移。再加上资源节在文件中的开始位置,节表中资源节那项中的PointerToRawData的值,就是资源在文件中的位置。),Size为130h,CodePage为4E4h,Reserved为0。</P>
      <P align=left>下面就是telnet.exe中的内容,可以用16进制编辑器打开附带的telnet.exe对照着看。</P>
      <P align=left>00013600h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 
      / 04 
      00&nbsp;<BR>(directory结构,16字节长。图4.1中11中的directory。0个NamedEntries,4个IdEntries。)<BR>00013610h: 
      03 00 00 00 / 30 00 00 
      80<BR>(directory_entry结构,8字节长。图4.1中11中的directory_entry数组第一个元素。第一个字段高位为0,说明第一个字段表示id,由于是第一层,所以类型id为3。第二个字段高位为1,说明还有下一层,第二字段中的低31位为到图4.1中21的偏移,30+00013600h=00013630h。)<BR>00013618h: 
      06 00 00 00 / 50 00 00 80<BR>00013620h: 0E 00 00 00 / A0 00 00 
      80<BR>00013628h: 10 00 00 00 / B8 00 00 80<BR>00013630h: 00 00 00 00 / 00 
      00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory21)<BR>00013640h: 01 00 
      00 00 / D0 00 00 80 (d0+00013600h=000136d0h。)<BR>00013648h: 02 00 00 00 / 
      F0 00 00 80<BR>00013650h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 
      00 / 08 00&nbsp; (directory22)<BR>00013660h: 08 00 00 00 / 10 01 00 
      80<BR>00013668h: 09 00 00 00 / 30 01 00 80<BR>00013670h: 0C 00 00 00 / 50 
      01 00 80<BR>00013678h: 0D 00 00 00 / 70 01 00 80<BR>00013680h: 10 00 00 00 
      / 90 01 00 80<BR>00013688h: 11 00 00 00 / B0 01 00 80<BR>00013690h: 12 00 
      00 00 / D0 01 00 80<BR>00013698h: 39 00 00 00 / F0 01 00 80<BR>000136a0h: 
      00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 01 00 / 00 
      00&nbsp;<BR>(directory结构,16字节长。图4.1中23。1个NamedEntries,0个IdEntries。)<BR>000136b0h: 
      D0 03 00 80 / 10 02 00 
      80<BR>(directory结构中已经表明这是一个NamedEntries,第一个字段中的高位为1,说明第一个字段中的值为一个指向IMAGE_RESOURCE_DIR_STRING结构的偏移,3D0+00013600h=000139D0h。)<BR>000136b8h: 
      00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 01 
      00&nbsp;(directory24)<BR>000136c8h: 01 00 00 00 / 30 02 00 
      80<BR>000136d0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 
      00&nbsp;(directory31)<BR>000136e0h: 09 04 00 00 / 50 02 00 
      00&nbsp;<BR>(directory_entry结构,8字节长。第一个字段高位为0,说明第一个字段表示id,由于是第三层,所以Language 
      id为409h。第二个字段高位为0,说明已经是叶子了,第二字段中的低31位为到一个data_entry结构的偏移,250+00013600h=00013850h。)<BR>000136e8h: 
      04 08 00 00 / 60 02 00 00<BR>000136f0h: 00 00 00 00 / 00 00 00 00 / 04 00 
      / 00 00 / 00 00 / 02 00&nbsp;(directory32)<BR>00013700h: 09 04 00 00 / 70 
      02 00 00<BR>00013708h: 04 08 00 00 / 80 02 00 00<BR>00013710h: 00 00 00 00 
      / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory33)<BR>00013720h: 
      09 04 00 00 / 90 02 00 00<BR>00013728h: 04 08 00 00 / A0 02 00 
      00<BR>00013730h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 
      (directory34)<BR>00013740h: 09 04 00 00 / B0 02 00 00<BR>00013748h: 04 08 
      00 00 / C0 02 00 00<BR>00013750h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 
      00 / 00 00 / 02 00 (directory35)<BR>00013760h: 09 04 00 00 / D0 02 00 
      00<BR>00013768h: 04 08 00 00 / E0 02 00 00<BR>00013770h: 00 00 00 00 / 00 
      00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory36)<BR>00013780h: 09 04 
      00 00 / F0 02 00 00<BR>00013788h: 04 08 00 00 / 00 03 00 00<BR>00013790h: 
      00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 
      (directory37)<BR>000137a0h: 09 04 00 00 / 10 03 00 00<BR>000137a8h: 04 08 
      00 00 / 20 03 00 00<BR>000137b0h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 
      00 / 00 00 / 02 00 (directory38)<BR>000137c0h: 09 04 00 00 / 30 03 00 
      00<BR>000137c8h: 04 08 00 00 / 40 03 00 00<BR>000137d0h: 00 00 00 00 / 00 
      00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory39)<BR>000137e0h: 09 04 
      00 00 / 50 03 00 00<BR>000137e8h: 04 08 00 00 / 60 03 00 00<BR>000137f0h: 
      00 00 00 00 / 00 00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 
      (directory310)<BR>00013800h: 09 04 00 00 / 70 03 00 00<BR>00013808h: 04 08 
      00 00 / 80 03 00 00<BR>00013810h: 00 00 00 00 / 00 00 00 00 / 04 00 / 00 
      00 / 00 00 / 02 00 (directory311)<BR>00013820h: 09 04 00 00 / 90 03 00 
      00<BR>00013828h: 04 08 00 00 / A0 03 00 00<BR>00013830h: 00 00 00 00 / 00 
      00 00 00 / 04 00 / 00 00 / 00 00 / 02 00 (directory312)<BR>00013840h: 09 
      04 00 00 / B0 03 00 00<BR>00013848h: 04 08 00 00 / C0 03 00 
      00<BR>00013850h: E0 23 03 00 / 30 01 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>(data_entry结构,16字节长,存有一个资源的RVA和大小。资源节开始处的RVA为32000。先算出该资源相对于资源开始处的偏移323E0-32000=3E0h。再用偏移加上资源节开始处的文件偏移13600得到该资源在文件中的位置,3E0+13600=139E0h。)<BR>00013850h: 
      10 25 03 00 / 30 01 00 00 / E4 04 00 00 / 00 00 00 00<BR>00013850h: 40 26 
      03 00 / E8 02 00 00 / E4 04 00 00 / 00 00 00 00<BR>00013860h: 28 29 03 00 
      / E8 02 00 00 / E4 04 00 00 / 00 00 00 00<BR>00013870h: 10 2C 03 00 / 70 
      00 00 00 / E4 04 00 00 / 00 00 00 00<BR>00013880h: 80 2C 03 00 / 70 00 00 
      00 / E4 04 00 00 / 00 00 00 00<BR>00013890h: F0 2C 03 00 / 56 03 00 00 / 
      E4 04 00 00 / 00 00 00 00<BR>000138a0h: 48 30 03 00 / C0 01 00 00 / E4 04 
      00 00 / 00 00 00 00<BR>000138b0h: F0 2C 03 00 / 56 03 00 00 / E4 04 00 00 
      / 00 00 00 00<BR>000138c0h: 48 30 03 00 / C0 01 00 00 / E4 04 00 00 / 00 
      00 00 00<BR>000138d0h: 08 32 03 00 / A8 01 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>000138e0h: B0 33 03 00 / F4 00 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>000138f0h: A4 34 03 00 / B6 00 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>00013900h: 5C 35 03 00 / 94 00 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>00013910h: F0 35 03 00 / 40 04 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>00013920h: 30 3A 03 00 / DC 02 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>00013930h: 0C 3D 03 00 / 32 02 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>00013940h: 40 3F 03 00 / 90 01 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>00013950h: D0 40 03 00 / FC 04 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>00013960h: CC 45 03 00 / C0 03 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>00013970h: 8C 49 03 00 / B6 00 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>00013980h: 44 4A 03 00 / 84 00 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>00013990h: C8 4A 03 00 / 22 00 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>000139a0h: EC 4A 03 00 / 22 00 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>000139b0h: 10 4B 03 00 / 60 03 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>000139c0h: 70 4E 03 00 / 60 03 00 00 / E4 04 00 00 / 00 00 00 
      00<BR>000139d0h: 06 00 / 54 00 45 00 4C 00 4E 00 45 00 54 00 00 
      00<BR>(IMAGE_RESOURCE_DIR_STRING结构,长度可变。第一个字段2个字节长,值为6。表明其后的Unicode字符串长度为6。第二字段是一个Unicode字符串,不包括最后的结束符,长度为6,内容是"TELNET\0")<BR>000139e0h: 
      28 00 00 00 20 00 00 00 40 00 00 00 01 00 01 00<BR>000139f0h: ...
      <P 
      align=left>需要补充说明的是,每个directory后面紧跟的是directory_entry数组,directory_entry数组的每个元素,有两个字段,每个字段的高位用来判断该字段代表的含义。尤其是第二字段 
      OffsetToData 
      ,如果高位为1表明还有下一层,指向另一个directory。如果高位为0,表明指向一个data_entry。directory_entry第一个字段通常都是作为id,里面低WORD中的值,用来标示这个directory_entry,很少的情况下,第一字段保存一个到unicode字符串的偏移(本例中000136a0h),用字符串来标示这个directory_entry。如果一个directory后两个字段都不为0的话,即后面紧跟的directory_entry数组既有NamedEntries,又有IDEntries,那么directory_entry数组首先是NamedEntries之后紧跟着IDEntries。一般情况下都是一般来说都是有三层,第一层中的directory_entry数组的每个元素的id,代表不同的类型,不同类型的值在 
      WINGDI.H 中定义如下<BR>#define RT_CURSOR MAKEINTRESOURCE(1)<BR>#define 
      RT_BITMAP MAKEINTRESOURCE(2)<BR>#define RT_ICON 
      MAKEINTRESOURCE(3)<BR>#define RT_MENU MAKEINTRESOURCE(4)<BR>#define 
      RT_DIALOG MAKEINTRESOURCE(5)<BR>#define RT_STRING 
      MAKEINTRESOURCE(6)<BR>#define RT_FONTDIR MAKEINTRESOURCE(7)<BR>#define 
      RT_FONT MAKEINTRESOURCE(8)<BR>#define RT_ACCELERATOR 
      MAKEINTRESOURCE(9)<BR>#define RT_RCDATA MAKEINTRESOURCE(10)<BR>#define 
      RT_MESSAGETABLE MAKEINTRESOURCE(11)<BR><BR>#define DIFFERENCE 
      11<BR>#define RT_GROUP_CURSOR MAKEINTRESOURCE((DWORD)RT_CURSOR + 
      DIFFERENCE)<BR>#define RT_GROUP_ICON MAKEINTRESOURCE((DWORD)RT_ICON + 
      DIFFERENCE)<BR>#define RT_VERSION MAKEINTRESOURCE(16)<BR>#define 
      RT_DLGINCLUDE MAKEINTRESOURCE(17)<BR>#if(WINVER &gt;= 0x0400)<BR>#define 
      RT_PLUGPLAY MAKEINTRESOURCE(19)<BR>#define RT_VXD 
      MAKEINTRESOURCE(20)<BR>#define RT_ANICURSOR MAKEINTRESOURCE(21)<BR>#define 
      RT_ANIICON MAKEINTRESOURCE(22)<BR>#endif /* WINVER &gt;= 0x0400 
      */<BR>#define RT_HTML 
      MAKEINTRESOURCE(23)<BR>也有可能有不到三层的情况,比如只有类型和Name两层,没有Language层。
      <P align=left>我们再来看几个data_entry<BR>00013850h: 10 25 03 00 / 30 01 00 00 / 
      E4 04 00 00 / 00 00 00 00<BR>00013850h: 40 26 03 00 / E8 02 00 00 / E4 04 
      00 00 / 00 00 00 00<BR>00013860h: 28 29 03 00 / E8 02 00 00 / E4 04 00 00 
      / 00 00 00 00<BR>可以算出 00013850h 处的 data_entry 中,资源的文件位置为 
      13B10h(32510-32000+13600) 长度为 130h,所以该资源结束处的位置在文件中的 13C40 
      h处。而一下个data_entry (00013850h处)中,资源在文件中的位置为 13C40h (32640-32000+13600) 长度为 
      2E8h。我们可以看到两个资源是首尾相接的,就是说一个资源和另一个资源是紧挨在一起的,中间没有空隙,其他的资源用相同的方法计算,也可以得到同样的结论。
      <P 
      align=left>总结,找到资源节开始的位置,首先是一个directory,后面紧跟着directory_entry数组,数组的每个元素代表的资源类型不同,通过每个元素,我们可以找到第二层另一个directory,后面紧跟着directory_entry数组。这一层的数组的每个元素代表的资源Name不同。然后我们可以找到第三层的每个directory,后面紧跟着directory_entry数组。这一层的数组的每个元素代表的资源Language不同。然后通过每个directory_entry我们可以找到每个data_entry。通过每个data_entry,我们就可以找到每个真正的资源。<BR>本部分内容较为复杂,需要多阅读几遍。
      <P align=left><B>三 遍历PE文件中的资源</B>
      <P align=left><B>&nbsp;&nbsp;&nbsp; </B>遍历那个树型结构,找到每个资源的方法之一是,
      <P align=left>&nbsp;&nbsp;&nbsp; 
      一个函数,用来处理directory和它后面紧跟着的directory_entry数组。比如叫&nbsp; 
      DumpResourceDirectory(),它的参数中的一个是一个directory的地址,函数根据这个地址,得到一个directory结构,从中得到directory_entry数组元素的个数。然后for循环遍历每个元素,对于每个元素做判断看是否已经到了叶子,也就是directory_entry的第二个字段的高位是否为0,是1表示没有到叶子,递归调用本函数,不过传入的参数,是根据这个directory_entry中保存的另一个directory的地址。是0表示已经到了叶子,调用另一个处理叶子的函数,传入相关地址。
      <P align=left>&nbsp;&nbsp; 
      处理叶子的函数,用来处理data_entry结构,负责根据data_entry结构找到真正的资源。比如叫DumpResourceEntry(),它的参数中的一个是一个data_entry的地址。然后跟据data_entry中的值作处理。
      <P align=left>&nbsp;&nbsp; 这样,通过递归和判断,就能遍历PE文件中所有的资源。
      <P align=left>&nbsp;&nbsp; 
      用这种方法遍历图4.1中的树,顺序会是11,21,31,32,22,33,34,35,36,37,38,39,310,23,311,24,312。
      <P align=left>&nbsp;&nbsp;&nbsp; 这种遍历方法的源程序,可以参考 PEDUMP - Matt Pietrek 
      1995 。《Windows95系统程式设计大奥秘》附书源码中有。
      <P align=left><B>完</B>
      <P align=center><A 
      href="http://jiurl.cosoft.org.cn/jiurl/document/jiurlpe/telnet.zip">本文所使用的PE文件 
      telnet</A> </P></TD></TR></TBODY></TABLE></DIV></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -