public long getOverlayOffset() throws IOException {
if (offset == null) {
SectionTable table = data.getSectionTable();
offset = 0L;
for (SectionTableEntry section : table.getSectionEntries()) {
long pointerToRaw = section.get(POINTER_TO_RAW_DATA);
long sizeOfRaw = section.get(SIZE_OF_RAW_DATA);
long virtSize = section.get(VIRTUAL_SIZE);
//see https://code.google.com/p/corkami/wiki/PE#section_table: "if bigger than virtual size, then virtual size is taken. "
//and: "a section can have a null VirtualSize: in this case, only the SizeOfRawData is taken into consideration. "
if(virtSize != 0 && sizeOfRaw > virtSize) {
sizeOfRaw = virtSize;
}
long endPoint = pointerToRaw + sizeOfRaw;
if (offset < endPoint) {
offset = endPoint;
}
}
}
if(offset > file.length()) {
offset = file.length();
}
return offset;
}
我使用corkami作为源,以了解计算叠加偏移的一些可能性。我不仅希望它坚固而且准确。
我错过了什么吗?我还需要考虑什么?
注意:这里有一个类似的问题:如何提取便携式可执行文件的附加数据?到目前为止,可靠的算法。据我了解,使用工具就足以解决这个问题。
#1 楼
您似乎缺少了一些极端情况,例如未对齐的指针(应向下舍入)和大小(应向上舍入)。不管标头中的值如何,都可以减小到512的倍数,但是通过使用文件对齐和4kb的组合来将读取大小四舍五入。不管标头中的值如何,虚拟大小总是四舍五入为4kb的倍数。数字签名必须是叠加的。出于安全原因,这是Windows现在强制执行的检查。如果没有覆盖,则文件将不会加载。
您需要类似的内容(并且filealign来自PE标头): />然后,您将“ alignedpointerToRaw”作为起始位置,并将“ readsize”作为该节中的字节数。对它们求和以找到本节的结尾。您需要对所有部分执行此计算(因为物理数据在文件中可能不是顺序的)。最大的和是图像的结尾。除此之外的任何东西都可以叠加。
评论
关于alignedPointerToRaw:规范指出,它应该是fileAlignment的倍数。 fileAlignment的默认值为512,但是假设它未设置为默认值。该部分从pointerToRaw和〜0x1ff开始是否仍然正确?
– Karsten Hahn
2014年5月14日7:00
关于fileAlignment的另一个问题:我是否应该将fileAlignment改正为:“该值应为512到64 K(含)之间的2的幂。” (pecoff规格)?非常感谢你的帮助。
– Karsten Hahn
2014年5月14日7:23
无论标头中的值如何,对齐PointerToRaw为512。真。对于fileAlignment的可能值,它是2的幂,最大为64kb,但包括1(即2 ^^ 0)。
–彼得·弗里
2014年5月14日15:40
如果不是,我应该将文件对齐方式向上/向下取整为2的幂吗?
– Karsten Hahn
2014年5月15日7:35
如果文件不是2的幂,则文件将不会加载。您无需担心这种情况。
–彼得·弗里
2014年5月15日15:38
#2 楼
为了完整起见:这是我根据Peter Ferrie的建议编写的代码/**
* Calculates the beginning of the overlay
*
* @return the file offset to the beginning of overlay
*/
public long getOverlayOffset() {
SectionTable table = data.getSectionTable();
OptionalHeader opt = data.getOptionalHeader();
offset = 0L;
List<SectionHeader> headers = table.getSectionHeaders();
if(headers.size() == 0) {
offset = file.length(); //offset for sectionless PE's
}
for (SectionTableEntry section : table.getSectionEntries()) {
long alignedPointerToRaw = section.get(POINTER_TO_RAW_DATA)
& ~0x1ff;
long endPoint = getReadSize(section) + alignedPointerToRaw;
if (offset < endPoint) {
offset = endPoint;
}
}
if (offset > file.length()) {
offset = file.length();
}
return offset;
}
/**
* Determines the the number of bytes that is read for the section.
*
* @param section
* @return section bytes that are read
*/
private long getReadSize(SectionTableEntry section) {
long pointerToRaw = section.get(POINTER_TO_RAW_DATA);
long virtSize = section.get(VIRTUAL_SIZE);
long sizeOfRaw = section.get(SIZE_OF_RAW_DATA);
long fileAlign = data.getOptionalHeader().get(
WindowsEntryKey.FILE_ALIGNMENT);
long alignedPointerToRaw = section.get(POINTER_TO_RAW_DATA) & ~0x1ff;
long readSize = alignedUp(pointerToRaw + sizeOfRaw, fileAlign)
- alignedPointerToRaw;
readSize = Math.min(readSize,
alignedUp(section.get(SIZE_OF_RAW_DATA), 0x1000));
if (virtSize != 0) {
readSize = Math.min(readSize,
alignedUp(section.get(VIRTUAL_SIZE), 0x1000));
}
return readSize;
}
/**
* Returns the value rounded up to a multiple of alignTo.
*
* @param value
* @param alignTo
* @return value rounded up to a multiple of alignTo
*/
private long alignedUp(long value, long alignTo) {
if (value % alignTo != 0) {
value = (value + alignTo - 1) & ~(alignTo - 1);
}
return value;
}
评论
常数0x1000是SectionAlignment的值吗?根据MSDN,这是默认设置-但由于提供了一个值,因此您可能仍要使用它。
–杂件
2014年5月14日14:31
@Jongware,始终为0x1000。尽管文档中有说明,但它和512(当前)在Windows中(当前)是硬编码的(请注意,这都是未记录的,因此理论上可能会改变一天)。标头中的节对齐用于内存分配,而不是文件内容。
–彼得·弗里
2014年5月14日15:42
@Veitch,看起来不错。
–彼得·弗里
2014年5月14日15:52
#3 楼
您是否考虑过使用Microsoft的代码来做到这一点?反转加载程序刚好足以找到加载图像后要查找的指针,阻止其执行除解析PE之外的任何实际代码。 ntdll或任何特定版本中所需指针的偏移量,但是您将获得超准确的解析器。评论
解析是在内核模式下完成的,而不是在用户模式下完成的,您仍然缺乏实际的算法。不建议盲目执行可能会更改的代码(即使格式不变)。
–彼得·弗里
2014年5月23日15:45
我要求一种算法,因为我写了一个PE库。所以这不是一个选择。
– Karsten Hahn
2014年5月23日20:16
那么参考实现显然将无济于事。
–offbyseveral
2014年5月23日在21:49
评论
您是否关心代码签名(如果有)?这是在其中一个目录中指出的,但实际上是像覆盖图一样附加的。@ 0xC0000022L好的问题。如果不在某节中,则将其定义为叠加。