移転ディアンとは何ですか
移転は、オフセット補正は、ビットアドレス0x401234、IMAGEBASE = 0x400000として意味ことを意味している。1234それはRVA IMAGEBASEが変更された補正がIMAGEBASE + RVA = 0X300000 + 1234 = 0x301234で、その後の後に、0x300000になった場合。
まず第一に、私たちは、EXEファイルを知っている。DLLの多く(PE)PE、複数のファイルを呼び出します。
ベースアドレス(IMAGEBASE)を起動するためのexeファイルがに0x40000である。我々は3 DLL AB C.を呼び出すと仮定
ベースアドレス位置に配備DLL EXEは0x10000000であります
これは、0x1000000番地2 DLL展開位置が同じ場所である。問題は、発生するB DLL展開位置に発生します。
図は次のとおりです。
このオペレーティングシステムは。B DLLに。私たちに別のメモリ位置を修正するための時間を与える展開される。これは、システムがあなたの再配置のさまざまな情報を助けることができるので、ゲームのプラグイン。、等の多くは、DLLインジェクションを選択している理由です。コードで書かれましたDLLをすることができます。
図は次のとおりの0x20から起動BのDLLを....同じアドレスを避けます。
これは解決するが入り口のベースアドレスは、メモリ拡張が同じではありません。同じではありません。しかし、我々はRVA .RVAが相対IMAGEBASEを保存することがオフセットされた多くの.PEファイルがあることを知っている。RVAあるPEファイルならば、それが簡単に処理するために、 。
しかし、必ずしも国。
コードで示されるように:
書式#include <stdio.hに> する#include <stdlib.h>に含ま する#include <はWindows.h> int型g_Value。 int型のmain() { g_Value = 10 。 }
その解体を参照してください。
私たちは、アドレスがグローバル変数の代入に一定の時間があるで見つかった。彼はRVAではありません
スクリーンショットは、再び実行します。
私たちは、アドレスが変更されていた。そして、ハードコードされたが固定されている。0x012c813c、彼はバイナリファイルに直接コンパイル。
彼は。RVAの+値。バイナリに直接コンパイルされたと言うことです。このアドレスグローバル変数をIMAGEBASE RVA + IMAGEBASEアドレスです。しかし、彼は直接バイナリにコンパイルされました。
問題:
そのアドレスグローバル変数を仮定し、コンパイルがRVA + IMAGEBASEの仮定で、その後、展開位置の0x10 0x1012345です.....その後、グローバル変数のアドレスが正しいです。しかし、Bの時間をコンパイルした場合。ただし、モジュールのベースアドレスは1012345です。サイトの負荷は、以下に示すように同じではないという問題になります:
我々上記によると、問題を発見した。だから今、私たちは場所を記録するテーブルが再配置される必要がある。我々はそれを変更するには、この場所を評価する必要があります。
それは我々がチャートを逆アセンブルビューの上に再配置コードを変更する必要がある位置を記録すること、です。
あなたが必要な再配置を記録することができますところです。
再配置テーブルには、すべての必要な改正がいる限り、我々は位置を占めていない私たちのIMAGEBASEを心配する必要はありませんとして再配置テーブルでは、アドレスを記録することです。
テーブルには非常に重要。
二ディアン再配置テーブルと位置決め構造
再配置テーブル位置決め拡張ヘッダデータディレクトリにおいて項目6オフセット再配置テーブルのデータディレクトリRVAおよび再配置テーブルのサイズです。
再配置テーブルを配置し、付加的な構造は、再配置テーブルが記載されています。
typedef 構造体_IMAGE_BASE_RELOCATION { DWORD VirtualAddress; DWORD SizeOfBlock; //存储的值以字节为单位.字节多大.表示了一个重定位快有多大. // WORD TypeOffset[1]; } IMAGE_BASE_RELOCATION; typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
看着重定位表就两个成员. 其实非常复杂. 我们设 VirtualAddress 为 x 设 SizeofBlock为Y
如下图所示,一个格子为1个字节.
第一行四个字节为x.也就是 Virtualaddress.. y则是第二个成员
SizeOfBlock 成员你的意思. 以字节为单位.代表重定位的快由多大. 我们知道.一个PE文件需要很多地方进行重定位的.比如这个记录的
大小为16. 也就是两个重定位块,那么我们的重定位表的大小就是如下图所示:
下面则是新的重定位表.结构就是重定位表的结构,如果SzieofBlock大小为20个字节.那么重定位表大小就是20个自己.
第三个依次类推,重定位表的结束是不停的往下找,知道最后一个重定位表的结构成员你都为0
这样设计的原因:
算术题解惑.
比如我们有地址 101234 101235 101236 这种修正的地址有10000个.
那么每个地址有4个字节的. 那么 4 * 10000 = 4万个字节. 也就是我们要准备一张4万个字节的表来保存重定位的.
但是我们发现一个规律.我们要修正的表的偏移都很近, 1234 1235 ....
那么我们可不可以这样那. 我们把 100000取出来. 两个字节存储1234 另外两个地址存储1235,不用准备四个字节了.小的偏移我们两个字节存储.这样的话我们的表的字节就会缩小一半.
VirtuallAddress 就是存储了 100000这个值,也就是需要 ""基址"" 公用的地址.
SizeofBlock 就是下面的偏移由多大, 我们要修正的偏移是 VirtualAddress + sizeofBlock下面的值.
如下图:
我们的重定位表,需要修正的基址是 0x11000,大小是54. 那么需要修正的偏移是 "36b0" "36bc" "36e0"....
我们基址 + 偏移就是要修正的位置.
偏移的概念:
重定位表,是按照一个物理页(4kb)进行存储的. 也就是一个4kb内存,有一个重定位块, 一个重定位表只管自己当前的物理页的重定位.
一个重定位表的记录偏移的大小是2个字节,也就是16位. 而记录偏移的大小. 是由 SizeofBlock决定的.
但是我们记录偏移的位置,12位就够了. 高4位.挪作他用. 并不是记录的才会修正偏移.只有高4位为3的时候.才会进行重定位(基址 + 偏移)
真正修复的位置 virtualaddress + (高四位为3 ? 低12位偏移 : 无所谓的值.)
也就是高四位为3 Vir + 低12位偏移就等于真正要修复的RVA 例如 36b0 高位为3 低12位就是6b0 要修复的RVA = vir + 6b0 ,如果加上当前DLL的ImagebASE 才是真正要修复的虚拟地址 (VA) 我们计算出的是RVA
如果高位不为3,那么这个值是无所谓了.因为内存对齐的原因.
例如上图重定位表. 0x11000代表了当前要进行修复的块位置. 要修复偏移的地址第一个是36b0 . 高位为3是要进行修复.
所以低位为6B0. 所以修复的位置是 0x116b0的位置. 0x116b0 + 当前PE文件的ImageBase就是要进行重定位的位置
当前PE的Imagebase为0x400000 重定位地方为 0x4116b0位置.
我们第一个修正的位置是4116b0位置,从内存中.反汇编查看. 4116b0的位置的值是0x0041813c. 也就是说.这个位置的值.是我们需要重定位的. 也就是我们上面写的程序.为全局变量赋值的时候.全局变量的地址.需要进行更改.
而需要重定位的值. 则是 全局变量的RVA值 + Imagebase 填写到这里面了. 全局变量是在内存中的data节存储着.所以观看前几篇博客.能知道如何定位全局变量在文件的位置.
三丶总结重定位
重定位表有两个成员. VirtuallAddress sizeofBlock
1.virtualladdress 记录了当前物理页需要进行重定位的起始地址.
2.sizeofBlock 记录了重定位表多大.去掉8个字节(重定位表大小) 下面都是记录了重定位表需要重定位的偏移.
3.偏移是2个字节存储. 12位存储偏移. 高4位存储是否进行重定位. 高4位为3则需要进行重定位. virtuall + 低12位 就是要修正的 RVA偏移.