我试图使一个程序,提取原始部门的数据,从光盘的各种类型,开始与CD(数据和音频)。
这没什么特别的,这个概念本身很好,可以在具有类似IOCTL的Linux上工作。
我在Windows上遇到的问题是ECC/EDC数据不正确(基本上是零)。你可以通过比较命令返回的内容与其他程序输出(如IsoBuster或ImgBurn)(或在Linux上使用等效命令)来发现这一点。
这些数据是Windows安全策略由于某种原因而影响的吗?还是驱动程序错误?
请注意,我在Windows 10上看到了这种情况。我以管理员身份运行时得到了相同的结果。
要清楚哪些数据受到影响,请参阅此处的漂亮表格:https://en.wikipedia.org/wiki/CD-ROM#CD-ROM_format。在普通数据CD(模式1)上,它是2352扇区的最后288字节。
演示问题的代码:
#include <windows.h>
#include <winioctl.h> // From the Win32 SDK \Mstools\Include
#include "ntddcdrm.h" // From the Windows NT DDK \Ddk\Src\Storage\Inc
int main()
{
HANDLE hCD = CreateFile(L"\\\\.\\D:", GENERIC_READ,
FILE_SHARE_READ,
0, OPEN_EXISTING, 0,
0);
//the sector to read
int lba = 0;
RAW_READ_INFO rawReadInfo;
rawReadInfo.DiskOffset.QuadPart = (long long)lba * 2048;
rawReadInfo.SectorCount = 1;
rawReadInfo.TrackMode = RawWithC2AndSubCode;
DWORD x_size;
char* buf = (char*)malloc(CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE);
int rc = DeviceIoControl(hCD, IOCTL_CDROM_RAW_READ,
&rawReadInfo, sizeof(rawReadInfo),
buf, CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE,
&x_size, NULL);
printf("rc: %d\n", rc);
printf("x_size: %d\n", x_size);
int i;
printf("\nSync, Addr, Mode (16 bytes)\n");
for (i = 0; i < 16; i++) {
printf("%hhX", buf[i]); //this data comes back fine
}
printf("\nData (2048 bytes)\n");
for (i = 16; i < 16+2048; i++) {
printf("%hhX", buf[i]); //this data comes back fine
}
printf("\nED, RZ, EC (288 bytes)\n");
for (i = 16 + 2048; i < 16 + 2048 + 288; i++) {
printf("%hhX", buf[i]); //this data comes back wrong
}
printf("\nC2, Sub (392 bytes)\n");
for (i = 16 + 2048 + 288; i < 2744; i++) {
printf("%hhX", buf[i]); //not sure if this is right or not
}
//dumb code to block terminal from closing
char str[80];
fgets(str, 10, stdin);
return 0;
}
字符串
输出和IsoBuster扇区视图之间的并排比较:x1c 0d1x
供参考的任何人来这里在未来,下一个最好的事情,让这工作肯定是使用SPTI如这里所述:How to issue a READ CD command to a CD-ROM drive in Windows?。我不想考虑这是一个答案,为什么Windows IOCTL不工作,虽然(省略EDC)!
1条答案
按热度按时间sdnqo3pr1#
答案可能有点晚,但在这里,简短的一个:你不能使用
IOCTL_CDROM_RAW_READ
控制代码以原始的方式读取模式1轨道。冗长的回答:当你看到
x_size
时,你会发现函数没有读取你期望的数据量。你期望的是CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE
,即2744,但是你只收到了2456。这个事实的另一个泄露是在你的屏幕截图中显示的0xCD
字符。Visual C在调试模式下将内存中的值设置为0xCD
,以便于调试。所以这部分数组可能根本没有被写入。那么你实际上从函数调用中接收到了哪些数据呢?在我看来,你收到了12字节的同步数据,然后是4字节的扇区头(3字节用于地址,在您的情况下为
0x00 0x02 0x00
,1字节用于模式,在您的情况下为0x01
),然后是2048字节的用户数据,然后是296字节的C2错误信息,然后是96字节的子码。你可以很容易地识别子码,因为MSB在所有字节中都设置为1,这是CD上每个轨道开始的情况。我没有成功地找到一个文档,关于这个控制代码返回的C2错误信息的确切含义。但是因为它有足够的空间来容纳原始扇区的每个字节的一位,我的猜测是,每一位都表示在C2纠错之后,相应的字节是否仍然可能包含错误。如果只返回数据磁道的用户数据,这个假设是否仍然成立,更不用说这些信息是毫无意义的,因为函数返回的用户数据应该已经被随后的P和Q奇偶校验纠正了,即使它最初可能包含C2错误。
尝试读取模式1数据时,其他磁道模式的行为如下:
YellowMode2
和XAForm2
将失败。RawWithC2
和RawWithSubCode
的行为类似于RawWithC2AndSubCode
。CDDA
将产生乱码数据。另外,请注意,如果
printf
模式的值小于0x10
,则每个字符只打印一位数字。如果您希望始终打印两位数字,则"%02hhX"
将是合适的。