好的,先说最后一点。需要管理员权限,因为您正在尝试读取原始磁盘;例如,您可能会寻找写入私有加密密钥的块并将其作为非特权用户读取,然后我们会在哪里?
其次,/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 命令进行复制,请使用此处显示的块大小。