首页 > 解决方案 > 为什么从 winapi 复制到我的代码中的结构定义没有相同的行为?

问题描述

我正在尝试使用crate中该结构的定义IMAGE_DOS_HEADER来读取模块的。winapi

这是我的工作代码:

let mut IDH: IMAGE_DOS_HEADER = uninitialized();
copy_nonoverlapping(library, (&mut IDH as *mut IMAGE_DOS_HEADER) as *mut c_void, size_of::<IMAGE_DOS_HEADER>());

我意识到它winapi太大了,我希望我的二进制文件小于 1 兆字节,所以我IMAGE_DOS_HEADER自己声明了结构:

#[derive(Copy, Clone)]
pub struct _IMAGE_DOS_HEADER{
    pub e_magic: u16,
    pub e_cblp: u16,
    pub e_cp: u16,
    pub e_crlc: u16,
    pub e_cparhdr: u16,
    pub e_minalloc: u16,
    pub e_maxalloc: u16,
    pub e_ss: u16,
    pub e_sp: u16,
    pub e_csum: u16,
    pub e_ip: u16,
    pub e_cs: u16,
    pub e_lfarlc: u16,
    pub e_ovno: u16,
    pub e_res: [u16; 4],
    pub e_oemid: u16,
    pub e_oeminfo: u16,
    pub e_res2: [u16; 10],
    pub e_lfanew: i32,
}

当我这样做时,结构的所有字段都会得到奇怪的值(例如:)e_magic = 0x3

我决定在这两种情况下都将结构转换为数组,即使它们在编程上完全相同。

println!("{:?}", std::mem::transmute::<IMAGE_DOS_HEADER, [u8;0x40]>(IDH).to_vec());

对于他们俩,它都打印了:

[77, 90, 144, 0, 3, 0, 0, 0, 4, 0, 0, 0, 255, 255, 0, 0, 184, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 0, 0, 0]

这真的很奇怪。他们的字段值之间不应该有任何差异。然后我复制打印的数组并将其转换为我的结构,看看是否所有字段都正常。

let dos: [u8;0x40] = [77, 90, 144, 0, 3, 0, 0, 0, 4, 0, 0, 0, 255, 255, 0, 0, 184, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 0, 0, 0];
println!("{}", std::mem::transmute::<[u8;0x40], _IMAGE_DOS_HEADER>(dos).e_magic);

第一个字段等于3。我有两个结构,具有相同的字段和完全相同的大小(我已验证),我采用一个数组,将其转换为这些结构,然后得到不同的字段。

如您所见3,数组转储中有一个,但它不应该与结构的第一个字段(e_magic)相关联,这没有意义,为什么它会与另一个字段一起使用?

我想我在初始化结构时遗漏了一些东西,但是什么?

标签: winapirust

解决方案


没有复制相同的定义,而是复制了文档中显示的部分。这是(截断的)实际定义

STRUCT!{struct IMAGE_DOS_HEADER {
    e_magic: WORD,
    e_cblp: WORD,
    // ...
    e_res2: [WORD; 10],
    e_lfanew: LONG,
}}

值得注意的是,这使用了STRUCT,它定义了一些特征,但更重要的是将类型标记为repr(C)

#[repr(C)] #[derive(Copy)] $(#[$attrs])*
pub struct $name {
    $(pub $field: $ftype,)+
}

没有指定 Rust 结构的布局,因此与 C 结构相比,您的结构有一些其他的排序和填充,并且不会工作。


我意识到winapi太大了,我希望我的二进制文件小于一兆,所以我自己声明了IMAGE_DOS_HEADER结构

这是不正确的推理。未使用的库中的代码将从最终的二进制文件中删除。

也可以看看:


推荐阅读