1

我想使用驱动器序列号 + 分区偏移量 + 分区大小创建自己的卷 ID,但我需要知道如何在 OS X 上获取分区信息。我(未成功)尝试了以下操作:


int fd;
if ((fd = open("/dev/disk0s1", O_RDONLY|O_NONBLOCK)) >= 0) {
    struct hd_geometry geom;
    if (ioctl(fd, 0x0301, &geom) == 0){ //0x0301 is HDIO_GETGEO
        printf("Index = %u\n", geom.start);
    }
    close(fd);
}

但即使成功了,这也是一个有缺陷的解决方案,因为正如本文所述:hd_geometry.start 是一个无符号长整数,“对于大小超过 219 Gb 的磁盘将不包含有意义的值”。此外,我相信它需要管理权限,这也很糟糕。有没有其他方法可以做到这一点?

4

2 回答 2

5

好的,先说最后一点。需要管理员权限,因为您正在尝试读取原始磁盘;例如,您可能会寻找写入私有加密密钥的块并将其作为非特权用户读取,然后我们会在哪里?

其次,/dev/disk0s1 只是一个分区,它也是它的块设备版本。您需要读取磁盘的字符设备版本,即 /dev/rdisk0。

第三,HDIO_GETGEO 是一个 linux 内核 ioctl(特别是考虑到它的 0x0301 值)你不会在达尔文上走得太远;查看<sys/disk.h>相关的磁盘 IOCTL。我认为 DKIOCGETFEATURES / DKIOCGETPHYSICALBLOCKSIZE 等应该让你继续前进。

如果您对这些概念有疑问,我强烈建议您在可以破坏的虚拟机中进行此开发,因为您不想意外使用会搞砸磁盘的 IOCTL。

附录(可能是答案)

GUID 分区表

所以你在 Mac OS X / Darwin 上工作;我们将假设 GUID 分区表

LBA == 逻辑块寻址 ... ; 1 块 = 512 字节

LBA 0 - Master Boot Record  (also contained old partition table) 
LBA 1 - GUID Partition Table (standard for OS X) 
LBA 2 - first 4 entries 
LBA 3 - 33 - next 124 entries making for a total of 128 entries
LBA 34 - Partition 1

您可以抓住第二个块并开始跟踪信息

阅读http://en.wikipedia.org/wiki/GUID_Partition_Table

它的定义很好。GUID 对整数值使用 little-endian 字节顺序(参见维基百科页面底部的示例)

测试建议

制作一个副本,这样您就不会弄乱实际的磁盘:

dd if=/dev/rdisk0 of=fakedisk count=33

这将创建前 33 个块或磁盘的副本。使用 fakedisk 来测试你的程序。

MBR

如果您的磁盘使用 MBR,请使用与 GPT 相同的概念

http://en.wikipedia.org/wiki/Master_Boot_Record

对行业有很好的描述。

使用 dtruss fdisk -d /dev/rdisk0 dump 获取提示

dtrussing fdisk dump 表明 fdisk 使用上述方法。

dtruss fdisk -d /dev/rdisk0

SYSCALL(args)            = return
open("/dev/dtracehelper\0", 0x2, 0x7FFF5CFDD5C0)                 = 3 0
__sysctl(0x7FFF5CFDD084, 0x2, 0x7FFF5CFDD070)            = 0 0
bsdthread_register(0x7FFF8BCA41D4, 0x7FFF8BCA41C4, 0x2000)               = 0 0
[[ .... content edited  ... ]]
open("/dev/rdisk0\0", 0x0, 0x7FFF5CFDDD7A)               = 3 0
fstat64(0x3, 0x7FFF5CFDDA10, 0x0)                = 0 0
fstat64(0x3, 0x7FFF5CFDDAC8, 0x0)                = 0 0
ioctl(0x3, 0x40086419, 0x7FFF5CFDDB60)           = 0 0
ioctl(0x3, 0x40046418, 0x7FFF5CFDDB5C)           = 0 0
close(0x3)               = 0 0
open("/dev/rdisk0\0", 0x0, 0x0)          = 3 0
fstat64(0x3, 0x7FFF5CFDDAD0, 0x0)                = 0 0
open("/dev/rdisk0\0", 0x0, 0x0)          = 4 0
fstat64(0x4, 0x7FFF5CFDDA80, 0x0)                = 0 0
lseek(0x4, 0x0, 0x0)             = 0 0
issetugid(0x102C22000, 0x3, 0x7FFF5CFDDC00)              = 0 0
geteuid(0x102C22000, 0x3, 0x0)           = 0 0
[[ tracing data suppressed ]]
read(0x4, "\0", 0x200)           = 512 0
close(0x4)               = 0 0
getrlimit(0x1008, 0x7FFF5CFDCFA8, 0x7FFF8BD0D470)                = 0 0
fstat64(0x1, 0x7FFF5CFDCEF8, 0x7FFF5CFDCFBC)             = 0 0
ioctl(0x1, 0x4004667A, 0x7FFF5CFDCF94)           = 0 0
write_nocancel(0x1, "1,625142447,0xEE,-,1023,254,63,1023,254,63\n\0", 0x2B)              = 43 0
write_nocancel(0x1, "0,0,0x00,-,0,0,0,0,0,0\n\0", 0x17)          = 23 0
write_nocancel(0x1, "0,0,0x00,-,0,0,0,0,0,0\n\0", 0x17)          = 23 0
write_nocancel(0x1, "0,0,0x00,-,0,0,0,0,0,0\n\0", 0x17)          = 23 0
close(0x3)               = 0 0

破译ioctl

我怎么知道使用的是这些 ioctl。

dtruss 转储是:

ioctl(0x3, 0x40086419, 0x7FFF5CFDDB60) = 0 0 ioctl(0x3, 0x40046418, 0x7FFF5CFDDB5C) = 0 0

并且 0x40086518 对应于 DKIOCGETBLOCKSIZE 这是通过追溯 disk.h 收集的(并注意 _IOR 在 ioccom.h 中扩展为 _IOC),最后 8 位对应于 IOCTL 常量定义中的第二个数字。

#define DKIOCGETBLOCKSIZE _IOR('d', 24, uint32_t)

在 0x40086418 尾随 18(hex) == 24(dec)

所以现在我们注意到 fdisk 执行 DKIOCGETBLOCKCOUNT 和 DKIOCGETBLOCKSIZE 来获取物理范围,因为从技术上讲,您应该使用结果来计算 LBA 偏移量(请参阅下面的解密 ioctls)

fdisk 中的实际读取

这就是 fdisk 的做法:

打开(“/dev/rdisk0\0”,0x0,0x0)= 4 0 读取(0x4,“\0”,0x200)= 512 0 关闭(0x4)= 0 0

您可以照做,确保将 0x200 替换为实际的块大小。

此外,如果您要使用上面的 dd 命令进行复制,请使用此处显示的块大小。

于 2013-05-20T19:03:59.787 回答
0

你试过DKIOCGETPHYSICALEXTENTioctl吗?它填充一个dk_physical_extent_t包含 64 位偏移量和 64 位长度的结构。

于 2013-05-21T00:03:47.047 回答