解析 bplist 文件
本人研究医学图像 AI 的,现在有个需求,就是把医生在 Osirix (一个医生看影像的软件)上圈出来的 ROI ( region of interest ,就是一个闭合的多边形,将目标区域,比如肿瘤,围起来)转出来存成 json/xml 等 readable 的格式。
由于 Osirix 批量导出的时候导出的是它自己的一个格式,里面存的是一堆 bytes ,类似于这种
b'bplist00\xd4 后面很长
说白了这东西里面存的就是 ROI 上的每个点的坐标,以及医生标注的 ROI 的名字(比如恶性肿瘤,良性肿瘤)。
大概问了下 chatGPT ,说这是 bplist
的格式(我的理解大概是 Google protobuf 类似的东西,不过是 apple 的)。
目前我们尝试了两种方案去解析 Osirix 导出的文件:
逆向工程。我们尝试了逆向工程,通过标注一些特定坐标的标注,然后观察 Osirix 导出的文件格式,大概写了个解析的代码。问题是这个逆向并不完美,总有些 case 会出现无法解析的问题。这个成功率大概有个 92%。
直接用 python 的 bplist
解析库。这个错误率更高,成功率大概只有 20%。很多 case 都无法解析。
然后我今天突然发现 Osirix 居然有个开源版本Horos,并且有 ROI 导出的相关功能。
如果有了怎么编码 ROI 的源码,按理说就能开发一个完美的工具来逆向了。问题是这个开源项目比较大,难以定位相关代码。我大概用 bplist/roi/NSKeyedArchiver 等关键词搜了下,没找到。
有没有大哥比较熟悉 bplist 的,或者比较懂 MacOS 开发的,可以指点下如何快速定位源代码里相关代码的?
![]() |
1
levelworm 1 天前
|
![]() |
2
levelworm 1 天前
|
![]() |
3
scienhub OP @levelworm Thanks for checking the source! I’ll look into the two spots you mentioned, but might be tricky without a proper debug.
|
![]() |
4
levelworm 1 天前
@scienhub #3
Sorry I know very little about MacOS programming, and not a good programmer :) 92% doesn't look bad though, what are the rest of 8%? Just curious. |
![]() |
5
levelworm 1 天前
Also, try out this tool: ImHex, a hex editor for reverse engineering. It has a bplist pattern parser:
https://github.com/WerWolv/ImHex-Patterns/blob/master/patterns/bplist.hexpat |
![]() |
6
scienhub OP @levelworm
No clear pattern in the failed cases. All were exported from the same OsiriX version on the same Mac Studio server, and the patients are from the same hospital cohort. |
![]() |
7
ETiV 1 天前 via iPhone
macOS 自带一个 PlistBuddy 没在默认的 PATH 下,
/usr/libexec/PlistBuddy 。可以 dump 成 xml 再进行解析。 |
![]() |
8
shuax 1 天前
你把 python 的 bplist 代码改改就行了吧,那个比较简单的。
|
![]() |
9
ratazzi 1 天前
man plutil 可以转成 xml ,也可以从 xml 转回去
|
![]() |
10
ratazzi 1 天前
python plistlib 这个是标准库,也支持二进制的
|
![]() |
11
scienhub OP |
12
elgae 1 天前
发个 ROI 文件,我试试看
|
13
MozzieW 1 天前
按照开发改代码的思路,假设你已经把 Horos 运行起来了,可以找到页面按钮的文案,搜索文案找到对应页面,也就能找到对应的逻辑。
另外代码里面有个 ROIWindow 里面有 export xml 功能,不知道是不是你要找的 |
![]() |
14
icyalala 1 天前
直接把文件改名为 plist ,然后就能用 Xcode 直接打开。或者直接下个 plistedit pro 来导出其他格式
|
![]() |
15
rozbo 1 天前
这种有两个格式 plist ,其实就是 xml
bplist ,其实就是二进制的 plist ,b 代表 binary 是一种标准的格式,如果你只是想打开看一下,用 xcode 双击就可以 如果你想用编程的方式解析, 各个语言基本都有 libplist 可以支持到 针对你的情况,如果连 xcode 都无法打开,那有可能魔改了部分行为,就要具体去分析目标 app 的实现了。通过 ida 结合 lldb 调试去定位到。 |
![]() |
16
shuax 1 天前
plist 文件发来
|
17
nenseso 1 天前
先确认一下是不是 6270 开头的,如果是应该是标准的 bplist,随便整个 libplist 库可解
|
18
ihwbunny 1 天前
@scienhub
Plist 文件是 macOS 的属性列表 ( Property List ),用于保存系统和应用的配置和数据,被广泛应用于 macOS 系统中。 macOS 自带的命令行工具有 * defaults - 主要用来读写系统配置 Plist 文件 * plutil - 用于转换格式对 Plist 有限的操作 * PlistBuddy - 与 defaults 差不多, 不过语法上有时更灵活 Xcode 自带的功能 第三方的图形界面,PlistEdit pro 虽然是收费的当时可以免费使用。还有它的插件,比如 VS Code 等。 |
![]() |
19
scienhub OP @nenseso 最长公共前缀是 “bplist00\xd4”。
我把我的数据上传到 GitHub 了: https://github.com/batchfy/parse-osirix-bplist/tree/main/bplist/OsiriX_ROI_SR |
![]() |
20
scienhub OP |
![]() |
21
shuax 1 天前
@scienhub 你的不能解析的 bplist 末尾都多一个 0 ,然后 python 库 unsupported type: <class 'plistlib.UID'> 你自己补充一下应该就好吧。
|
![]() |
22
ETiV 1 天前
看了这 4 个文件,要是只需要坐标的话,直接正则匹配就行了:XY 坐标对儿都是 {a.b, m.n} 这样的字面量格式
strings {文件名} 先转一下,然后从 XNSObject 的下一行开始读,读到含有 NSMutableArray 的行截止 至于 [医生标注的 ROI 的名字(比如恶性肿瘤,良性肿瘤)] ,不知道是不是个枚举值,没有字面量的表示形式。 |
![]() |
23
icyalala 1 天前 ![]() 这就是 NSKeyedArchiver 生成的 plist 文件,我逆向了一下 osirix lite ,丢给 copliot 让它写个转 json 的工具:
https://pastebin.com/JMDB5h0m 这个 plist 可能会在结尾多一个或者两个 0 ,所以解析的时候要多尝试两次。 |
![]() |
24
icyalala 23 小时 59 分钟前
|
![]() |
25
scienhub OP |