VobFile.cpp

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 // CDVDSession
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 // CLBAFile
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 // CVobFile
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         if(m_files.GetCount() > 0 && !m_fDVD)
00531         {
00532                 CString fn = m_files[0].fn;
00533                 fn.MakeLower();
00534 
00535                 if(fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM)
00536                 {
00537                         m_fDVD = true;
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         // this suxx, but won't take long
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                 // dvd still locked?
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                         // under win9x this is normal, but I'm not developing under win9x :P
00634                         ASSERT(0);
00635                 }
00636         }
00637 
00638         return(true);
00639 }

Generated on Tue Dec 13 14:47:06 2005 for guliverkli by  doxygen 1.4.5