我试图读取文件的PE头来获取一些信息。对于.NET和C#,我使用BitConverter将读取文件后获得的字节数组转换为等效整数。我希望对C++也这样做,但不确定最佳的方法。我使用的是unsigned char array作为Byte array等效项。
代码给出如下..
uint16_t GetAppCompiledMachineType(string fileName)
{
const int ptr_offset = 4096;
const int mac_offset = 4;
char *data = new char[4096];
fstream f;
f.open(fileName, ios::in | ios::binary );
f.read(data, 4096);
int32_t pe_addr= *reinterpret_cast<int32_t*>(data, ptr_offset);
uint16_t machineUint = *reinterpret_cast<std::uint16_t*>(data, pe_addr + mac_offset);
return machineUint;
}
int _tmain(int argc, _TCHAR* argv[])
{
string fileName = "<some_path>\\depends.exe";
uint16_t tempInt = GetAppCompiledMachineType(fileName);
cout<<tempInt;
std::getchar();
return 0;
}我将使用O/P查询PE头以获取信息。这里需要BitCOnverter的等价物。希望它能成功。
更新:谢谢你的回复。正如建议的那样,我试图使用强制转换,将character array转换为Int,读取PE Header,但它给了我一个访问冲突,未处理的异常。这是完整的代码,文件是有效的,正在读取。我尝试过调试,并禁用了优化,但没有效果。
敬请指教。
非常感谢。
发布于 2014-10-08 11:02:07
您有一个字节数组指针(char* data),然后简单地移动指针以偏移您需要的data + PE_POINTER_OFFSET,转换为指向整数(int*)(data + PE_POINTER_OFFSET)的指针,并根据指针来获得值:
int32_t head_addr = *reinterpret_cast<int32_t*>(data + PE_POINTER_OFFSET);
uint16_t machineUint = *reinterpret_cast<uint16_t*>(data + head_addr + macoffset);编辑1:您正在尝试读取PE,所以我可以放心地假设您的环境是Windows。x86和x64都支持非对齐内存访问(当然,您将为此付出性能上的代价,但您可能不会注意到这一点,也会保存memcpy)。
Itanimum (如果您必须支持它)和(非常老的) ARM可能是一个问题:对于第一个只对char数组使用__unaligned,对于第二个(如果不让编译器为您完成工作),可以使用__packed。
还请注意,这个假设(加上endianness)是有效的,因为您在Windows环境下处理PE文件,如果您必须编写可移植代码或读取其他内容,那么这不是正确的方法(简而言之,您必须对单个字节进行寻址并使用固定顺序复制它们)。
编辑2:根据您正在使用的问题是*reinterpret_cast<int32_t*>(data, ptr_offset)的更新代码,请注意,您没有将指针与偏移量相加,偏移量也是无效的(如果我没有错)。您在那里所做的是从地址4096的绝对位置读取,这将导致访问冲突。代码:
uint16_t GetAppCompiledMachineType(string fileName)
{
const int32_t PE_POINTER_OFFSET = 60;
const int32_t MACHINE_OFFSET = 4;
char data[4096];
fstream f;
f.open(fileName, ios::in | ios::binary);
f.read(data, sizeof(data));
int32_t pe_header_offset = *reinterpret_cast<int32_t*>(
data + PE_POINTER_OFFSET);
// assert(pe_header_offset + MACHINE_OFFSET < sizeof(data));
return *reinterpret_cast<std::uint16_t*>(
data + pe_header_offset + MACHINE_OFFSET);
}此代码仍远未达到生产质量,但请注意很少有更改:
data,则不需要释放该内存(您没有释放分配的内存,当进程退出时,Windows将为您释放内存,但是如果您多次调用该函数,您将消耗内存)。sizeof()来确定缓冲区大小(作为read()的输入)。PE_POINTER_OFFSET现在有了正确的值(60而不是4096)。data的偏移量( data与PE_POINTER_OFFSET之和)。所有这些都表明,我们仍然在使用缓冲方法,但在这里它是非常无用的,因为fstream将为我们处理这个问题。让我们简化我们的代码(为了使它更健壮,我们不假设PE头适合我们的4K缓冲区)。
uint16_t GetAppCompiledMachineType(string fileName)
{
const int32_t PE_POINTER_OFFSET = 60;
const int32_t MACHINE_OFFSET = 4;
fstream f(fileName, ios::in | ios::binary);
int32_t pe_header_offset:
f.seekg(PE_POINTER_OFFSET); f >> pe_header_offset;
uint16_t machineType;
f.seekg(pe_header_offset + MACHINE_OFFSET); f >> machineType;
return machineType;
}现在,它不需要强制转换和转换(但仍然假设PE和机器特性匹配)。
发布于 2014-10-08 11:14:10
重构以消除某些体系结构上的数据对齐问题:
template<class T>
T from_buffer(uint8_t* buffer, size_t offset)
{
T t_buf = 0;
memcpy(&t_buf, buffer + offset, sizeof(T));
return t_buf;
}..。
int32_t head_addr = from_buffer<in32_t>(buffer, PE_POINTER_OFFSET);
uint16_t machineUint = from_buffer<uint16_t>(buffer, size_t(head_addr + macoffset));发布于 2014-10-08 12:02:39
最好的方法是声明PE文件格式的结构。示例:
struct dos_header {
char signature[2] = "MZ";
boost::int16_t lastsize;
..
boost::int16_t reserved2[10];
boost::int32_t e_lfanew;
}备注:
#pragma pack(8) )。windows.h中声明的,但是对于跨平台开发,我建议您单独声明和移植。有映射结构时,可以将缓冲区转换为指向结构的指针并访问成员。
示例:
if (offset + sizeof(dos_header) > size_data) {
// handle the error
// exit
}
const dos_header* dh = static_cast<const dos_header*>(data + offset);
std::cout << dh->e_lfanew << std::endl;https://stackoverflow.com/questions/26255229
复制相似问题