我有几个流在DICOM
文件中看起来很奇怪。简而言之,DICOM非常接近于二进制 XML 的样子。几乎所有来自这些 DICOM 文件的信息都是直接的,可以使用DCMTK和/或GDCM很好地读取和解释。
但是,文件末尾存储了两个二进制字段,看起来像是私有编码信息。由于 DICOM 主要用于系统之间的互操作性,因此供应商实际上将自己的内部文件格式存储在 DICOM 文件的字段之一中(声明为私有字段,就像 TIFF 世界中的人们会做的那样)。在我过去的经验中,编码是微不足道的(简单地struct
存储为二进制),例如参见此处或此处。
现在,如果我从 DICOM 文件 (debian/jessie amd64) 中提取二进制 blob,我会看到以下内容:
$ gdcmraw -t 7101,1000 input.dcm file1000.gz
$ gdcmraw -t 7101,1002 input.dcm file1002.gz
$ file file1000.gz file1000.gz: gzip compressed data, max compression, from FAT filesystem (MS-DOS, OS/2, NT)
$ gunzip file1000.gz
gzip: file1000.gz: invalid compressed data--format violated
但是gunzip
不能解压它们。有更多 gzip 知识的人可以检查这些文件是否真的是 gzip 压缩的吗?看起来可以解压缩它们,因为在医疗行业,我们倾向于尽可能重用代码。例如,一个众所周知的MRI厂商也采用gzip
压缩的流来存储自己的专用文件格式,看到这里例如(全螺纹在这里)。
混淆也应该非常简单,因为它需要通过医疗行业的许可。根据过去的经验,我只看到使用字节反转或简单的增量异或。
我在这里上传了文件:
图像可以很好地提取,所以我怀疑只有一些额外的私人供应商信息(仅限元数据)存储在此字段(MRI 序列号...)中。
更具体地说,假gzip
流成对出现,例如(file1000.gz
&file1002.gz
取自同一个 DICOM 文件)。从另一个 DICOM 文件中,我发现第二个假 gzip 流(按位)与 相同file1002.gz
,所以我只上传file1000_other1.gz
(同样适用于file1000_other2.gz
、file1000_other3.gz
和file1000_other4.gz
)。所以也许file1002.gz
这里有点特别。由于我无法物理访问生成这些图像的 MRI 工作站,因此我只能在这里使用蛮力方法。
更新:我确实检查过这些文件不仅仅是使用unz.py和runme(binwalk -X
也没有透露任何内容)的带有损坏标头的压缩码流。所以它们不是直接的简单gzip
文件。
更新 2:我确实尝试使用此代码向后读取流,但这仍然看起来不像放气流。
更新 3:到目前为止,我发现的所有流都有适当的 gzip 标头,并且它们都以 4 个零 (0) 字节结束,就像任何有效的 gzip 一样。我应该能够使用最后 4 个字节恢复文件,因为它们用于存储 crc32(根据 gzip RFC)。
更新 4:感谢这里的帮助,我发现这些私人标签实际上有一些记录:
Table A.2.1.2.1.3-3 Private Elements for MR Scanner or MR Workstation Images
When exporting Marconi MR Scanner or MR Workstation images the following
private elements may be included.
Tag Name Value Representation
7101,0010 Private MR Creator Data element LO
7101,1000 MR Processing Field 1 OB
7101,1001 MR Processing Field 1 Length SL
7101,1002 MR Processing Field 2 OB
7101,1003 MR Processing Field 2 Length SL
7101,1004 Scan Duration SH
7101,1005 MR Processing Field 3 SH
7101,1006 MR Processing Field 4 SH
我确实检查了提取的 fake-gzip 的长度是否与存储在关联属性中的值相匹配(因此属性 7101,1000 的长度匹配存储在属性 7101,1001 中的值,而属性 7101,1002 的长度匹配存储在属性中的值7101,1003)。例如:
$ gdcmdump input3.dcm
[...]
(07a1,0010) ?? (LO) [ELSCINT1] # 8,1 Private Creator
(07a1,1013) ?? (UL) 62940 # 4,1 ?
(7101,0000) ?? (UL) 24242 # 4,1 Generic Group Length
(7101,0010) ?? (LO) [Picker MR Private Group ] # 24,1 Private Creator
(7101,1000) ?? (OB) 1f\8b\08\00\00\00\00\00\02\00\14\5d\4b\8d\db\48\6e\3e\ec\53\4f\7b\28\c3\1e\ef\8c\d8\2d\86\e8\86\57\01\c9\d9\96\4a\bd\76\45\35\92\99\dc\33\e5\1b\08\78\04\25\94\93\04\f3\80\7a\03\fa\cd\34\02\40 # 10784,1 ?
(7101,1001) ?? (SL) 10784 # 4,1 ?
(7101,1002) ?? (OB) 1f\8b\08\00\00\00\00\00\02\00\14\3c\6d\8d\da\48\6d\9f\93\a1\31\e5\9c\2f\f6\6b\c1\48\44\d8\9e\26\67\ab\78\8d\1d\8a\6d\a0\80\6c\36\31\dd\95\b6\96\84\2f\13\90\a8\49\d8\0f\fe\fa\15\97\19\97\24\c0 # 13328,1 ?
(7101,1003) ?? (SL) 13328 # 4,1 ?
(7101,1004) ?? (SH) [00:48 ] # 6,1 ?
(7101,1005) ?? (SH) [ECHO\CARDIAC] # 12,2 ?
(7101,1006) ?? (SH) [115204\4187\0\0 ] # 16,4 ?
更新 5:DICOM 只能将偶数字节长度存储为属性。一个伪造的 gzipped 流实际上被填充到下一个偶数长度,但 7101,1001 中报告的实际长度是奇数 (10765)。我已更新file1000_other4.gz
为具有适当的长度(尾随字节不再是03 00 00 00
,但是0B 03 00 00
)