00001 #include "StdAfx.h"
00002 #include <io.h>
00003 #include "VobFile.h"
00004 #include "CSSauth.h"
00005 #include "CSSscramble.h"
00006 #include "udf.h"
00007
00008
00009
00010
00011
00012 CDVDSession::CDVDSession()
00013 : m_session(DVD_END_ALL_SESSIONS)
00014 , m_hDrive(INVALID_HANDLE_VALUE)
00015 {
00016 }
00017
00018 CDVDSession::~CDVDSession()
00019 {
00020 EndSession();
00021 }
00022
00023 bool CDVDSession::Open(LPCTSTR path)
00024 {
00025 Close();
00026
00027 CString fn = path;
00028 CString drive = _T("\\\\.\\") + fn.Left(fn.Find(':')+1);
00029
00030 m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, NULL,
00031 OPEN_EXISTING, FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)NULL);
00032 if(m_hDrive == INVALID_HANDLE_VALUE)
00033 return(false);
00034
00035 return(true);
00036 }
00037
00038 void CDVDSession::Close()
00039 {
00040 if(m_hDrive != INVALID_HANDLE_VALUE)
00041 {
00042 CloseHandle(m_hDrive);
00043 m_hDrive = INVALID_HANDLE_VALUE;
00044 }
00045 }
00046
00047 bool CDVDSession::BeginSession()
00048 {
00049 EndSession();
00050
00051 if(m_hDrive == INVALID_HANDLE_VALUE)
00052 return(false);
00053
00054 DWORD BytesReturned;
00055 if(!DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, NULL, 0, &m_session, sizeof(m_session), &BytesReturned, NULL))
00056 {
00057 m_session = DVD_END_ALL_SESSIONS;
00058 if(!DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), NULL, 0, &BytesReturned, NULL)
00059 || !DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, NULL, 0, &m_session, sizeof(m_session), &BytesReturned, NULL))
00060 {
00061 CloseHandle(m_hDrive);
00062 DWORD err = GetLastError();
00063 return(false);
00064 }
00065 }
00066
00067 return(true);
00068 }
00069
00070 void CDVDSession::EndSession()
00071 {
00072 if(m_session != DVD_END_ALL_SESSIONS)
00073 {
00074 DWORD BytesReturned;
00075 DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), NULL, 0, &BytesReturned, NULL);
00076 m_session = DVD_END_ALL_SESSIONS;
00077 }
00078 }
00079
00080 bool CDVDSession::Authenticate()
00081 {
00082 if(m_session == DVD_END_ALL_SESSIONS)
00083 return(false);
00084
00085 BYTE Challenge[10], Key[10];
00086
00087 for(int i = 0; i < 10; i++) Challenge[i] = i;
00088
00089 if(!SendKey(DvdChallengeKey, Challenge))
00090 return(false);
00091
00092 if(!ReadKey(DvdBusKey1, Key))
00093 return(false);
00094
00095 int varient = -1;
00096
00097 for(int i = 31; i >= 0; i--)
00098 {
00099 BYTE KeyCheck[5];
00100 CSSkey1(i, Challenge, KeyCheck);
00101 if(!memcmp(KeyCheck, Key, 5))
00102 varient = i;
00103 }
00104
00105 if(!ReadKey(DvdChallengeKey, Challenge))
00106 return(false);
00107
00108 CSSkey2(varient, Challenge, &Key[5]);
00109
00110 if(!SendKey(DvdBusKey2, &Key[5]))
00111 return(false);
00112
00113 CSSbuskey(varient, Key, m_SessionKey);
00114
00115 return(true);
00116 }
00117
00118 bool CDVDSession::GetDiscKey()
00119 {
00120 if(m_session == DVD_END_ALL_SESSIONS)
00121 return(false);
00122
00123 BYTE DiscKeys[2048];
00124 if(!ReadKey(DvdDiskKey, DiscKeys))
00125 return(false);
00126
00127 for(int i = 0; i < g_nPlayerKeys; i++)
00128 {
00129 for(int j = 1; j < 409; j++)
00130 {
00131 BYTE DiscKey[6];
00132 memcpy(DiscKey, &DiscKeys[j*5], 5);
00133 DiscKey[5] = 0;
00134
00135 CSSdisckey(DiscKey, g_PlayerKeys[i]);
00136
00137 BYTE Hash[6];
00138 memcpy(Hash, &DiscKeys[0], 5);
00139 Hash[5] = 0;
00140
00141 CSSdisckey(Hash, DiscKey);
00142
00143 if(!memcmp(Hash, DiscKey, 6))
00144 {
00145 memcpy(m_DiscKey, DiscKey, 6);
00146 return(true);
00147 }
00148 }
00149 }
00150
00151 return(false);
00152 }
00153
00154 bool CDVDSession::GetTitleKey(int lba, BYTE* pKey)
00155 {
00156 if(m_session == DVD_END_ALL_SESSIONS)
00157 return(false);
00158
00159 if(!ReadKey(DvdTitleKey, pKey, lba))
00160 return(false);
00161
00162 if(!(pKey[0]|pKey[1]|pKey[2]|pKey[3]|pKey[4]))
00163 return(false);
00164
00165 pKey[5] = 0;
00166
00167 CSStitlekey(pKey, m_DiscKey);
00168
00169 return(true);
00170 }
00171
00172 static void Reverse(BYTE* d, BYTE* s, int len)
00173 {
00174 if(d == s)
00175 {
00176 for(s += len-1; d < s; d++, s--)
00177 *d ^= *s, *s ^= *d, *d ^= *s;
00178 }
00179 else
00180 {
00181 for(int i = 0; i < len; i++)
00182 d[i] = s[len-1 - i];
00183 }
00184 }
00185
00186 bool CDVDSession::SendKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData)
00187 {
00188 CAutoPtr<DVD_COPY_PROTECT_KEY> key;
00189
00190 switch(KeyType)
00191 {
00192 case DvdChallengeKey:
00193 key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_CHALLENGE_KEY_LENGTH]);
00194 key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
00195 Reverse(key->KeyData, pKeyData, 10);
00196 break;
00197 case DvdBusKey2:
00198 key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_BUS_KEY_LENGTH]);
00199 key->KeyLength = DVD_BUS_KEY_LENGTH;
00200 Reverse(key->KeyData, pKeyData, 5);
00201 break;
00202 default:
00203 break;
00204 }
00205
00206 if(!key)
00207 return(false);
00208
00209 key->SessionId = m_session;
00210 key->KeyType = KeyType;
00211 key->KeyFlags = 0;
00212
00213 DWORD BytesReturned;
00214 return(!!DeviceIoControl(m_hDrive, IOCTL_DVD_SEND_KEY, key, key->KeyLength, NULL, 0, &BytesReturned, NULL));
00215 }
00216
00217 bool CDVDSession::ReadKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData, int lba)
00218 {
00219 CAutoPtr<DVD_COPY_PROTECT_KEY> key;
00220
00221 switch(KeyType)
00222 {
00223 case DvdChallengeKey:
00224 key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_CHALLENGE_KEY_LENGTH]);
00225 key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
00226 key->Parameters.TitleOffset.QuadPart = 0;
00227 break;
00228 case DvdBusKey1:
00229 key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_BUS_KEY_LENGTH]);
00230 key->KeyLength = DVD_BUS_KEY_LENGTH;
00231 key->Parameters.TitleOffset.QuadPart = 0;
00232 break;
00233 case DvdDiskKey:
00234 key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_DISK_KEY_LENGTH]);
00235 key->KeyLength = DVD_DISK_KEY_LENGTH;
00236 key->Parameters.TitleOffset.QuadPart = 0;
00237 break;
00238 case DvdTitleKey:
00239 key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_TITLE_KEY_LENGTH]);
00240 key->KeyLength = DVD_TITLE_KEY_LENGTH;
00241 key->Parameters.TitleOffset.QuadPart = 2048i64*lba;
00242 break;
00243 default:
00244 break;
00245 }
00246
00247 if(!key)
00248 return(false);
00249
00250 key->SessionId = m_session;
00251 key->KeyType = KeyType;
00252 key->KeyFlags = 0;
00253
00254 DWORD BytesReturned;
00255 if(!DeviceIoControl(m_hDrive, IOCTL_DVD_READ_KEY, key, key->KeyLength, key, key->KeyLength, &BytesReturned, NULL))
00256 {
00257 DWORD err = GetLastError();
00258 return(false);
00259 }
00260
00261 switch(KeyType)
00262 {
00263 case DvdChallengeKey:
00264 Reverse(pKeyData, key->KeyData, 10);
00265 break;
00266 case DvdBusKey1:
00267 Reverse(pKeyData, key->KeyData, 5);
00268 break;
00269 case DvdDiskKey:
00270 memcpy(pKeyData, key->KeyData, 2048);
00271 for(int i = 0; i < 2048/5; i++)
00272 pKeyData[i] ^= m_SessionKey[4-(i%5)];
00273 break;
00274 case DvdTitleKey:
00275 memcpy(pKeyData, key->KeyData, 5);
00276 for(int i = 0; i < 5; i++)
00277 pKeyData[i] ^= m_SessionKey[4-(i%5)];
00278 break;
00279 default:
00280 break;
00281 }
00282
00283 return(true);
00284 }
00285
00286
00287
00288
00289
00290 CLBAFile::CLBAFile()
00291 {
00292 }
00293
00294 CLBAFile::~CLBAFile()
00295 {
00296 }
00297
00298 bool CLBAFile::IsOpen()
00299 {
00300 return(m_hFile != hFileNull);
00301 }
00302
00303 bool CLBAFile::Open(LPCTSTR path)
00304 {
00305 Close();
00306
00307 return(!!CFile::Open(path, modeRead|typeBinary|shareDenyWrite|osSequentialScan));
00308 }
00309
00310 void CLBAFile::Close()
00311 {
00312 if(m_hFile != hFileNull)
00313 CFile::Close();
00314 }
00315
00316 int CLBAFile::GetLength()
00317 {
00318 return (int)(CFile::GetLength()/2048);
00319 }
00320
00321 int CLBAFile::GetPosition()
00322 {
00323 return (int)(CFile::GetPosition()/2048);
00324 }
00325
00326 int CLBAFile::Seek(int lba)
00327 {
00328 return (int)(CFile::Seek(2048i64*lba, CFile::begin)/2048);
00329 }
00330
00331 bool CLBAFile::Read(BYTE* buff)
00332 {
00333 return CFile::Read(buff, 2048) == 2048;
00334 }
00335
00336
00337
00338
00339
00340 CVobFile::CVobFile()
00341 {
00342 Close();
00343 }
00344
00345 CVobFile::~CVobFile()
00346 {
00347 }
00348
00349 bool CVobFile::IsDVD()
00350 {
00351 return m_fDVD;
00352 }
00353
00354 bool CVobFile::HasDiscKey(BYTE* key)
00355 {
00356 if(key) memcpy(key, m_DiscKey, 5);
00357 return m_fHasDiscKey;
00358 }
00359
00360 bool CVobFile::HasTitleKey(BYTE* key)
00361 {
00362 if(key) memcpy(key, m_TitleKey, 5);
00363 return m_fHasTitleKey;
00364 }
00365
00366 bool CVobFile::Open(CString fn, CList<CString>& vobs)
00367 {
00368 CFile f;
00369 if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
00370 return(false);
00371
00372 char hdr[13];
00373 f.Read(hdr, 12);
00374 hdr[12] = 0;
00375 if(strcmp(hdr, "DVDVIDEO-VTS"))
00376 return(false);
00377
00378 f.Close();
00379
00380 int offset = -1;
00381
00382 vobs.RemoveAll();
00383
00384 fn = fn.Left(fn.ReverseFind('.')+1);
00385 fn.TrimRight(_T(".0123456789"));
00386 for(int i = 0; i < 100; i++)
00387 {
00388 CString vob;
00389 vob.Format(_T("%s%d.vob"), fn, i);
00390
00391 CFileStatus status;
00392 if(!CFile::GetStatus(vob, status))
00393 {
00394 if(i == 0) continue;
00395 else break;
00396 }
00397
00398 if(status.m_size&0x7ff)
00399 {
00400 vobs.RemoveAll();
00401 break;
00402 }
00403
00404 if(status.m_size > 0)
00405 vobs.AddTail(vob);
00406
00407 if(i == 0)
00408 offset = (int)(status.m_size/0x800);
00409 }
00410
00411 return Open(vobs, offset);
00412 }
00413
00414 bool CVobFile::Open(CList<CString>& vobs, int offset)
00415 {
00416 Close();
00417
00418 if(vobs.GetCount() == 0)
00419 return(false);
00420
00421 if(vobs.GetCount() == 1)
00422 offset = -1;
00423
00424 m_offset = offset;
00425
00426 POSITION pos = vobs.GetHeadPosition();
00427 while(pos)
00428 {
00429 CString fn = vobs.GetNext(pos);
00430
00431 WIN32_FIND_DATA fd;
00432 HANDLE h = FindFirstFile(fn, &fd);
00433 if(h == INVALID_HANDLE_VALUE)
00434 {
00435 m_files.RemoveAll();
00436 return(false);
00437 }
00438 FindClose(h);
00439
00440 file_t f;
00441 f.fn = fn;
00442 f.size = (int)(((__int64(fd.nFileSizeHigh)<<32)|fd.nFileSizeLow)/2048);
00443 m_files.Add(f);
00444
00445 m_size += f.size;
00446 }
00447
00448 if(m_files.GetCount() > 0 && CDVDSession::Open(m_files[0].fn))
00449 {
00450 for(int i = 0; !m_fHasTitleKey && i < m_files.GetCount(); i++)
00451 {
00452 if(BeginSession())
00453 {
00454 m_fDVD = true;
00455 Authenticate();
00456 m_fHasDiscKey = GetDiscKey();
00457 EndSession();
00458 }
00459 else
00460 {
00461 CString fn = m_files[0].fn;
00462 fn.MakeLower();
00463
00464 if(fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM)
00465 {
00466 m_fDVD = true;
00467 }
00468
00469 break;
00470 }
00471
00472 if(tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(':')+1))))
00473 {
00474 DWORD start, end;
00475 if(udf_get_lba(m_hDrive, f, &start, &end))
00476 {
00477 if(BeginSession())
00478 {
00479 Authenticate();
00480 m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey);
00481 EndSession();
00482 }
00483 }
00484
00485 udf_free(f);
00486 }
00487
00488 BYTE key[5];
00489 if(HasTitleKey(key) && i == 0 && offset >= 0)
00490 {
00491 i++;
00492
00493 if(BeginSession())
00494 {
00495 m_fDVD = true;
00496 Authenticate();
00497 m_fHasDiscKey = GetDiscKey();
00498 EndSession();
00499 }
00500 else
00501 {
00502 break;
00503 }
00504
00505 if(tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(':')+1))))
00506 {
00507 DWORD start, end;
00508 if(udf_get_lba(m_hDrive, f, &start, &end))
00509 {
00510 if(BeginSession())
00511 {
00512 Authenticate();
00513 m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey);
00514 EndSession();
00515 }
00516 }
00517
00518 udf_free(f);
00519 }
00520
00521 if(!m_fHasTitleKey)
00522 {
00523 memcpy(m_TitleKey, key, 5);
00524 m_fHasTitleKey = true;
00525 }
00526 }
00527 }
00528 }
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541 m_offset = max(offset, 0);
00542
00543 return(true);
00544 }
00545
00546 void CVobFile::Close()
00547 {
00548 CDVDSession::Close();
00549 m_files.RemoveAll();
00550 m_iFile = -1;
00551 m_pos = m_size = m_offset = 0;
00552 m_file.Close();
00553 m_fDVD = m_fHasDiscKey = m_fHasTitleKey = false;
00554 }
00555
00556 int CVobFile::GetLength()
00557 {
00558 return(m_size - m_offset);
00559 }
00560
00561 int CVobFile::GetPosition()
00562 {
00563 return(m_pos - m_offset);
00564 }
00565
00566 int CVobFile::Seek(int pos)
00567 {
00568 pos = min(max(pos+m_offset, m_offset), m_size-1);
00569
00570 int i = -1;
00571 int size = 0;
00572
00573
00574 do size += m_files[++i].size;
00575 while(i < m_files.GetSize() && pos >= size);
00576
00577 if(i != m_iFile && i < m_files.GetSize())
00578 {
00579 if(!m_file.Open(m_files[i].fn))
00580 return(m_pos);
00581
00582 m_iFile = i;
00583 }
00584
00585 m_pos = pos;
00586
00587 pos -= (size - m_files[i].size);
00588 m_file.Seek(pos);
00589
00590 return(GetPosition());
00591 }
00592
00593 bool CVobFile::Read(BYTE* buff)
00594 {
00595 if(m_pos >= m_size) return(false);
00596
00597 if(m_file.IsOpen() && m_file.GetPosition() == m_file.GetLength())
00598 {
00599 m_file.Close();
00600 }
00601
00602 if(!m_file.IsOpen())
00603 {
00604 if(m_iFile >= m_files.GetSize()-1)
00605 {
00606 return(false);
00607 }
00608
00609 if(!m_file.Open(m_files[++m_iFile].fn))
00610 {
00611 m_iFile = -1;
00612 return(false);
00613 }
00614 }
00615
00616 if(!m_file.Read(buff))
00617 {
00618
00619 return(false);
00620 }
00621
00622 m_pos++;
00623
00624 if(buff[0x14] & 0x30)
00625 {
00626 if(m_fHasTitleKey)
00627 {
00628 CSSdescramble(buff, m_TitleKey);
00629 buff[0x14] &= ~0x30;
00630 }
00631 else
00632 {
00633
00634 ASSERT(0);
00635 }
00636 }
00637
00638 return(true);
00639 }