在C#中使用PtrToStructure进行二进制文件反序列化

时间:2011-11-23 00:04:59

标签: c# .net data-structures reverse-engineering binary-data

我正在尝试对我公司的一堆遗留二进制数据进行逆向工程,以便我可以将其转换为更耐用的格式。我们不再支持用于创建此数据的应用程序。

我已经发现我可以在一系列结构中描述数据,并且我已经能够使用Marshal.PtrToStructure将它们编组到托管环境,但一个文件除外。

下面我给出了一个我试图解析的结构样本。原始数据都是顺序的,我试图一步反序列化。

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct DrillTPD
{
    public short Header;
    public short Header2;
    public short Header3;
    public short RecordCount;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 999)]
    public TPDHeader[] Templates;
} 
[StructLayout(LayoutKind.Sequential, Pack = 1, Size=18)]
struct TPDHeader
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string TemplateName;
    public int TPDIndex;
}

TPDIndex是从文件开头偏移的字节。如何添加属性以正确反序列化此数据?

[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 76)]
struct TPDParent
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
    public string TemplateName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 25)]
    public string Description;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string Field;
    public double Width;
    public double Length;
    public double Thickness;
    public short WL;
    public short XY;
    public short Origin;
    public short Features;
    [MarshalAs(UnmanagedType.ByValArray)]
    public TPDDetail[] Details;
}
[StructLayout(LayoutKind.Sequential, Pack=1, Size=350)]
struct TPDDetail
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 350)]
    public string Text;
}

TPDParent中的TPDDetail数组由结构中的Features定义。如果没有功能,则TPDParent之后不存在TPDDetail数据。

如何动态地让反序列化器知道TPDDetail数组的大小?

此数据的伪XML结构理想情况如下:

<DrillTPD>
    <TPDHeader>
        <TPDParent>
            <TPDDetail/>
            <TPDDetail/>
            <TPDDetail/>
        </TPDParent>
    </TPDHeader>
    <TPDHeader>
        .....
    </TPDHeader>
</DrillTPD>

最后一条评论:我只使用.NET语言,但我试图了解事情的非管理方面。谢谢你减少你的答案。 :)

2 个答案:

答案 0 :(得分:0)

尝试创建结构层次结构的简单实例,然后将其作为字节保存到文件中。然后,您可以使用十六进制编辑器将输出的内容与您认为输出的内容进行比较。差异将突出显示它没有按预期工作的地方。

否则,您正在尝试创建结构的完美定义,并且它将拒绝工作,直到它完美,并且很难实现相当复杂的设置。

答案 1 :(得分:0)

从我的pov中它是最干净的,如果你有两个类 - 一个输入类与非托管数据和第二个类只有托管数据有一个构造函数将输入类作为参数,并相应标记为序列化 - 如果所有数据被管理,然后数组大小将由框架内部管理。