我想编写一个测试脚本或程序,断言给定目录中的所有DLL文件都是特定的构建类型。
我会在SDK构建过程结束时使用它作为完整性检查,以确保64位版本中没有某些32位DLL文件,反之亦然。
是否有一种简单的方法来查看DLL文件并确定其类型?
解决方案应该在xp32和xp64上都能工作。
我想编写一个测试脚本或程序,断言给定目录中的所有DLL文件都是特定的构建类型。
我会在SDK构建过程结束时使用它作为完整性检查,以确保64位版本中没有某些32位DLL文件,反之亦然。
是否有一种简单的方法来查看DLL文件并确定其类型?
解决方案应该在xp32和xp64上都能工作。
当前回答
血淋淋的细节
DLL使用PE可执行格式,从文件中读取该信息并不太棘手。
有关PE文件格式的概述,请参阅MSDN文章。您需要读取MS-DOS报头,然后读取IMAGE_NT_HEADERS结构。它包含IMAGE_FILE_HEADER结构,该结构包含您在Machine成员中需要的信息,该成员包含以下值之一
IMAGE_FILE_MACHINE_I386 (0 x014c) IMAGE_FILE_MACHINE_IA64 (0 x0200) IMAGE_FILE_MACHINE_AMD64 (0 x8664)
这个信息应该在文件中有一个固定的偏移量,但是我仍然建议遍历文件并检查MS-DOS头和IMAGE_NT_HEADERS的签名,以确保您能够应对未来的任何更改。
使用ImageHelp读取标题…
你也可以使用ImageHelp API来做这件事——用LoadImage加载DLL,你会得到一个LOADED_IMAGE结构,它包含一个指向IMAGE_NT_HEADERS结构的指针。使用ImageUnload释放LOADED_IMAGE。
...或者改编这个粗糙的Perl脚本
下面是一个粗略的Perl脚本,它可以完成这项工作。它检查文件是否有DOS头,然后从IMAGE_DOS_HEADER中读取60字节的PE偏移量到文件中。
然后查找PE部分的开头,读取签名并进行检查,然后提取我们感兴趣的值。
#!/usr/bin/perl
#
# usage: petype <exefile>
#
$exe = $ARGV[0];
open(EXE, $exe) or die "can't open $exe: $!";
binmode(EXE);
if (read(EXE, $doshdr, 64)) {
($magic,$skip,$offset)=unpack('a2a58l', $doshdr);
die("Not an executable") if ($magic ne 'MZ');
seek(EXE,$offset,SEEK_SET);
if (read(EXE, $pehdr, 6)){
($sig,$skip,$machine)=unpack('a2a2v', $pehdr);
die("No a PE Executable") if ($sig ne 'PE');
if ($machine == 0x014c){
print "i386\n";
}
elsif ($machine == 0x0200){
print "IA64\n";
}
elsif ($machine == 0x8664){
print "AMD64\n";
}
else{
printf("Unknown machine type 0x%lx\n", $machine);
}
}
}
close(EXE);
其他回答
我写了一个非常简单的工具,它就是PE解构器。
简单地启动它并加载您的DLL文件:
在上面的示例中,加载的DLL是32位的。
你可以在这里下载它(我只有64位编译的ATM版本): https://files.quickmediasolutions.com/exe/pedeconstructor_0.1_amd64.exe
旧的32位版本可以在这里找到: https://dl.dropbox.com/u/31080052/pedeconstructor.zip
一种粗略的方法是在每个DLL上使用Visual Studio工具的headers选项调用dumpbin,并寻找适当的输出:
dumpbin /headers my32bit.dll PE signature found File Type: DLL FILE HEADER VALUES 14C machine (x86) 1 number of sections 45499E0A time date stamp Thu Nov 02 03:28:10 2006 0 file pointer to symbol table 0 number of symbols E0 size of optional header 2102 characteristics Executable 32 bit word machine DLL OPTIONAL HEADER VALUES 10B magic # (PE32)
您可以在输出中看到一些线索,表明它是一个32位DLL,包括Paul提到的14C值。应该很容易在脚本中找到。
依赖行者会告诉你一切(几乎)。 http://www.dependencywalker.com/
它不“安装”—只是获取它,提取它并运行exec。 它适用于任何x32或x64 windows模块|应用程序。
正如我回忆的那样,看到所有的依赖关系是相当简单的,即dll模块,而自从appl。是依赖项的总和,可以确定它是完整的x64、x32(x86)还是每一个的一部分。
模块构建的CPU类型在“CPU”列中。大多数64位ap仍然是每个位,但32位ap w/b都是x86。
为极客/程序员设计的漂亮程序,而且是免费的…
如果你安装了Cygwin(或MobaXTerm,或Git Bash for Windows,或WSL,或…)(出于各种原因,我强烈推荐),你可以使用DLL上的'file'实用程序
file <filename>
它会给出这样的输出:
icuuc36.dll: MS-DOS executable PE for MS Windows (DLL) (GUI) Intel 80386 32-bit
血淋淋的细节
DLL使用PE可执行格式,从文件中读取该信息并不太棘手。
有关PE文件格式的概述,请参阅MSDN文章。您需要读取MS-DOS报头,然后读取IMAGE_NT_HEADERS结构。它包含IMAGE_FILE_HEADER结构,该结构包含您在Machine成员中需要的信息,该成员包含以下值之一
IMAGE_FILE_MACHINE_I386 (0 x014c) IMAGE_FILE_MACHINE_IA64 (0 x0200) IMAGE_FILE_MACHINE_AMD64 (0 x8664)
这个信息应该在文件中有一个固定的偏移量,但是我仍然建议遍历文件并检查MS-DOS头和IMAGE_NT_HEADERS的签名,以确保您能够应对未来的任何更改。
使用ImageHelp读取标题…
你也可以使用ImageHelp API来做这件事——用LoadImage加载DLL,你会得到一个LOADED_IMAGE结构,它包含一个指向IMAGE_NT_HEADERS结构的指针。使用ImageUnload释放LOADED_IMAGE。
...或者改编这个粗糙的Perl脚本
下面是一个粗略的Perl脚本,它可以完成这项工作。它检查文件是否有DOS头,然后从IMAGE_DOS_HEADER中读取60字节的PE偏移量到文件中。
然后查找PE部分的开头,读取签名并进行检查,然后提取我们感兴趣的值。
#!/usr/bin/perl
#
# usage: petype <exefile>
#
$exe = $ARGV[0];
open(EXE, $exe) or die "can't open $exe: $!";
binmode(EXE);
if (read(EXE, $doshdr, 64)) {
($magic,$skip,$offset)=unpack('a2a58l', $doshdr);
die("Not an executable") if ($magic ne 'MZ');
seek(EXE,$offset,SEEK_SET);
if (read(EXE, $pehdr, 6)){
($sig,$skip,$machine)=unpack('a2a2v', $pehdr);
die("No a PE Executable") if ($sig ne 'PE');
if ($machine == 0x014c){
print "i386\n";
}
elsif ($machine == 0x0200){
print "IA64\n";
}
elsif ($machine == 0x8664){
print "AMD64\n";
}
else{
printf("Unknown machine type 0x%lx\n", $machine);
}
}
}
close(EXE);