├── history ├── .swp ├── build ├── notes ├── fibmap.c ├── info.c ├── 1.c ├── 4.cpp ├── 2.cpp ├── 3.cpp ├── 7.cpp ├── 6.cpp ├── 6-1.cpp └── 5.cpp ├── Makefile ├── main.cpp ├── DVDRipper.h ├── info.c ├── README.md └── DVDRipper.cpp /history/.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cweiske/dvdripper/master/history/.swp -------------------------------------------------------------------------------- /history/build: -------------------------------------------------------------------------------- 1 | g++ `pkg-config --cflags --libs libdvdcss libudf libiso9660` 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | OBJS = main.o DVDRipper.o 2 | CC = g++ 3 | LFLAGS := -Wall $(shell pkg-config --cflags --libs libdvdcss libiso9660) 4 | CFLAGS := $(LFLAGS) -c 5 | OUTPUT = dvdripper 6 | 7 | $(OUTPUT): $(OBJS) 8 | $(CC) $(OBJS) $(LFLAGS) -o $(OUTPUT) 9 | 10 | %.o: DVDRipper.h %.cpp 11 | $(CC) $(CFLAGS) -c $*.cpp 12 | 13 | clean: 14 | rm -f *.o *~ 15 | 16 | realclean: clean 17 | rm -f $(OUTPUT) 18 | -------------------------------------------------------------------------------- /history/notes: -------------------------------------------------------------------------------- 1 | int i_ret, i_index; 2 | 3 | i_ret = dvdcss->pf_read( dvdcss, p_buffer, i_blocks ); 4 | 5 | for( i_index = i_ret; i_index; i_index-- ) 6 | { 7 | if( ((uint8_t*)p_buffer)[0x14] & 0x30 ) 8 | { 9 | print_error( dvdcss, "no key but found encrypted block" ); 10 | /* Only return the initial range of unscrambled blocks? */ 11 | /* or fail completely? return 0; */ 12 | break; 13 | } 14 | p_buffer = (void *) ((uint8_t *)p_buffer + DVDCSS_BLOCK_SIZE); 15 | } 16 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012 Shaya Potter */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include "DVDRipper.h" 7 | 8 | int main(int argc, char *argv[]) { 9 | bool test = false; 10 | int flags = O_RDWR; 11 | 12 | if (argc == 3 && !strcmp(argv[2], "-test")) { 13 | flags = O_RDONLY; 14 | test = true; 15 | } 16 | 17 | if (argc < 2) { 18 | printf("usage:\n\t %s [-test]\n", argv[0]); 19 | return 1; 20 | } 21 | 22 | DVDRipper * dvdripper = new DVDRipper(argv[1], flags); 23 | dvdripper->open_disc(); 24 | dvdripper->find_start_blocks(); 25 | dvdripper->info(); 26 | 27 | if (test) { 28 | return 0; 29 | } 30 | 31 | return dvdripper->rip(); 32 | } 33 | -------------------------------------------------------------------------------- /DVDRipper.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012 Shaya Potter */ 2 | 3 | #pragma once 4 | #ifndef DVDRIPPER_H 5 | #define DVDRIPPER_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class DVDRipper { 13 | std::vector start_blocks; 14 | std::map end_blocks; 15 | std::map start_map; 16 | 17 | iso9660_t *p_iso; 18 | int flags; 19 | int total_blocks; 20 | int fd; 21 | char * path; 22 | 23 | dvdcss_t input; 24 | 25 | unsigned long long preamble; 26 | 27 | public: 28 | DVDRipper(char *, int); 29 | int open_disc(); 30 | void find_start_blocks(); 31 | void info(); 32 | int rip(); 33 | }; 34 | 35 | #endif /* DVDRIPPER_H */ 36 | -------------------------------------------------------------------------------- /history/fibmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main(int argc, char **argv) { 13 | int fd, 14 | i, 15 | block, 16 | blocksize, 17 | bcount; 18 | struct stat st; 19 | 20 | assert(argv[1] != NULL); 21 | 22 | assert(fd=open(argv[1], O_RDONLY)); 23 | 24 | assert(ioctl(fd, FIGETBSZ, &blocksize) == 0); 25 | 26 | assert(!fstat(fd, &st)); 27 | 28 | bcount = (st.st_size + blocksize - 1) / blocksize; 29 | 30 | // printf("File: %s Size: %d Blocks: %d Blocksize: %d\n", 31 | // argv[1], st.st_size, bcount, blocksize); 32 | 33 | block=0; 34 | if (ioctl(fd, FIBMAP, &block)) { 35 | printf("FIBMAP ioctl failed - errno: %s\n", 36 | strerror(errno)); 37 | } 38 | printf("%d\n", block); 39 | /* for(i=0;i < bcount;i++) { 40 | block=i; 41 | if (ioctl(fd, FIBMAP, &block)) { 42 | printf("FIBMAP ioctl failed - errno: %s\n", 43 | strerror(errno)); 44 | } 45 | printf("%3d %10d\n", i, block); 46 | } */ 47 | 48 | close(fd); 49 | } 50 | 51 | -------------------------------------------------------------------------------- /info.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() 10 | { 11 | dvd_struct s; 12 | 13 | int layer = 0; 14 | int fd; 15 | 16 | if ( (fd = open("/dev/dvd", O_RDONLY)) == -1) { 17 | perror("failed to open /dev/dvd"); 18 | } 19 | 20 | while (layer < 2) { 21 | s.type = DVD_STRUCT_PHYSICAL; 22 | s.physical.layer_num = layer; 23 | 24 | if ( ioctl(fd, DVD_READ_STRUCT, &s) == -1) { 25 | perror("ioctl failed"); 26 | } 27 | 28 | printf("layer = %d\nbook_version = %d, book_type = %d, min_rate = %d, disc_size = %d, layer_type = %d, track_path = %d, nlayers = %d, track_density = %d, linear_density = %d, bca = %d, start_sector = %u, end_sector = %u, end_sector_l0 = %u\n\n", layer, s.physical.layer[layer].book_version, s.physical.layer[layer].book_type, s.physical.layer[layer].min_rate, s.physical.layer[layer].disc_size, s.physical.layer[layer].layer_type, s.physical.layer[layer].track_path, s.physical.layer[layer].nlayers, s.physical.layer[layer].track_density, s.physical.layer[layer].linear_density, s.physical.layer[layer].bca, s.physical.layer[layer].start_sector, s.physical.layer[layer].end_sector, s.physical.layer[layer].end_sector_l0); 29 | 30 | bzero(&s, sizeof(dvd_struct)); 31 | layer++; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /history/info.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() 10 | { 11 | dvd_struct s; 12 | 13 | int layer = 0; 14 | int fd; 15 | 16 | if ( (fd = open("/dev/dvd", O_RDONLY)) == -1) { 17 | perror("failed to open /dev/dvd"); 18 | } 19 | 20 | while (layer < 2) { 21 | s.type = DVD_STRUCT_PHYSICAL; 22 | s.physical.layer_num = layer; 23 | 24 | if ( ioctl(fd, DVD_READ_STRUCT, &s) == -1) { 25 | perror("ioctl failed"); 26 | } 27 | 28 | printf("layer = %d\nbook_version = %d, book_type = %d, min_rate = %d, disc_size = %d, layer_type = %d, track_path = %d, nlayers = %d, track_density = %d, linear_density = %d, bca = %d, start_sector = %u, end_sector = %u, end_sector_l0 = %u\n\n", layer, s.physical.layer[layer].book_version, s.physical.layer[layer].book_type, s.physical.layer[layer].min_rate, s.physical.layer[layer].disc_size, s.physical.layer[layer].layer_type, s.physical.layer[layer].track_path, s.physical.layer[layer].nlayers, s.physical.layer[layer].track_density, s.physical.layer[layer].linear_density, s.physical.layer[layer].bca, s.physical.layer[layer].start_sector, s.physical.layer[layer].end_sector, s.physical.layer[layer].end_sector_l0); 29 | 30 | bzero(&s, sizeof(dvd_struct)); 31 | layer++; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dvdripper 2 | ========= 3 | 4 | Remove CSS from a DVD .iso file. 5 | 6 | Project motivated by the need to recover scratched DVDs within my 7 | collection. Most DVD ripping software doesn't handle scratches well, 8 | as they either give you the option to die, ignore or retry the error. 9 | 10 | ddrescue (from GNU) actually can work very well for this as it keeps a 11 | bitmap of what content one was able to read and then can fill in the 12 | missing pieces later, however, it doesn't decrypt data. Most 13 | decryption software doesn't decrypt ISO's with CSS scrambled sectors 14 | (though VLC and other tools built around libdvdcss can play them fine 15 | due to libdvdcss brute forcing the crypto), as they expect ISO's to be 16 | already decrypted and query the device for the content's keys instead 17 | of brute forcing the crypto. 18 | 19 | This software decrypts the scrambled sectors in place enabling you to 20 | then extract the iso to a file system or use another ripping tool to 21 | extract the desired content from the already decrypted image. 22 | 23 | For protection mechanisms that protect the disc by including invalid 24 | sectors, ddrescue will mark those sectors as unreadable, but it 25 | doesn't matter as they aren't needed. However. if the disc is 26 | protected with that, and it's damaged (such as scratches that make 27 | needed data unreadable), one will not be able to tell the difference. 28 | 29 | If the disc has protection mechanisms that cause it to be viewed as a 30 | very large file system (i.e. a DVD that looks like a 100GB file 31 | system), this will remove the encryption and enable you to mount the 32 | image, but you will not be able to simply extract the contents of the 33 | images (without wasting a lot of space). Tools that understand the 34 | IFO structure are neccessary to extract the correct files. 35 | 36 | 37 | Usage 38 | ----- 39 | 1. Use `ddrescue` to get a `.iso` file from your DVD 40 | 2. Use `dvdripper` to remove CSS from the `.iso` file: 41 | ``` 42 | $ dvdripper mydvd.iso 43 | ``` 44 | 45 | The `.iso` file is directly modified. 46 | 47 | 48 | Dependencies 49 | ------------ 50 | Ubuntu 20.04 package names: 51 | 52 | - `libcdio-dev` 53 | - `libiso9660-dev` 54 | -------------------------------------------------------------------------------- /history/1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define _FILE_OFFSET_BITS 64 8 | #define _LARGEFILE64_SOURCE 1 9 | #define _LARGEFILE_SOURCE 1 10 | 11 | int my_fwrite(void * buffer, size_t size, size_t number, FILE * stream) 12 | { 13 | int wrote = number; 14 | int count; 15 | 16 | while (wrote > 0) { 17 | count = fwrite(buffer, size, number, stream); 18 | if (count < 0) { 19 | return count; 20 | } 21 | if (count != wrote) { 22 | printf("handling short read\n"); 23 | } 24 | wrote -= count; 25 | buffer += size * count; 26 | } 27 | return number; 28 | } 29 | 30 | int main(int argc, char *argv[]) 31 | { 32 | dvdcss_t file; 33 | int fd; 34 | char buffer[540000*DVDCSS_BLOCK_SIZE]; 35 | long long blocks_read; 36 | int count = 0; 37 | int block_count = 0; 38 | int loop = 1; 39 | int len; 40 | struct stat buf; 41 | int blocks; 42 | int i; 43 | 44 | if (stat(argv[1], &buf) < 0) { 45 | perror("failed to stat input iso\n"); 46 | return 1; 47 | } 48 | 49 | blocks = buf.st_blocks / 4; 50 | 51 | if (!(file = dvdcss_open(argv[1]))) { 52 | printf("failed to open iso\n"); 53 | return 0; 54 | } 55 | 56 | if ((fd = open(argv[2], O_RDWR | O_CREAT | O_TRUNC)) < 0) { 57 | printf("failed to open output file\n"); 58 | return 0; 59 | } 60 | 61 | if (! dvdcss_is_scrambled(file)) { 62 | printf("dvd isn't scrambled\n"); 63 | return 0; 64 | } 65 | 66 | for(i=3; i <= argc; i++) { 67 | len = atoi(argv[i]) - block_count; //-1? 68 | 69 | if ((blocks_read = dvdcss_read(file, buffer, len, DVDCSS_READ_DECRYPT)) != len) { 70 | printf("didn't read %d blocks, read %lld blocks\n", len, blocks_read); 71 | } 72 | if (blocks_read < 0) { 73 | printf("blocks_read is < 0: %s\n", dvdcss_error(file)); 74 | return 0; 75 | } 76 | block_count += blocks_read; 77 | if (write(fd, buffer, 2048 * blocks_read) != 2048 * blocks_read) { 78 | printf("write didn't write enough\n"); 79 | return 0; 80 | } 81 | if ( dvdcss_seek(file, block_count, DVDCSS_SEEK_KEY) < 0) { 82 | printf("failed to seek to %d: %s\n", block_count, dvdcss_error(file)); 83 | } 84 | } 85 | 86 | len = blocks - block_count; 87 | if ((blocks_read = dvdcss_read(file, buffer, len, DVDCSS_READ_DECRYPT)) != len) { 88 | printf("didn't read %d blocks, read %lld blocks\n", len, blocks_read); 89 | } 90 | if (blocks_read < 0) { 91 | printf("blocks_read is < 0: %s\n", dvdcss_error(file)); 92 | return 0; 93 | } 94 | block_count += blocks_read; 95 | if (write(fd, buffer, 2048 * blocks_read) != 2048 * blocks_read) { 96 | printf("write didn't write enough\n"); 97 | return 0; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /history/4.cpp: -------------------------------------------------------------------------------- 1 | #define _FILE_OFFSET_BITS 64 2 | #define _LARGEFILE64_SOURCE 1 3 | #define _LARGEFILE_SOURCE 1 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace std; 19 | 20 | vector start_blocks; 21 | 22 | #define MAX 2000 23 | 24 | static void add_block(const udf_dirent_t *p_udf_dirent) 25 | { 26 | char *psz_fname=(char *) udf_get_filename(p_udf_dirent); 27 | int len = strlen(psz_fname); 28 | 29 | unsigned int start; 30 | 31 | for(int i=0; i < len; i++) { 32 | psz_fname[i] = tolower(psz_fname[i]); 33 | } 34 | if (! strcmp(psz_fname + (len-3), "vob")) { 35 | start = udf_get_start_block(p_udf_dirent); 36 | start_blocks.push_back(start); 37 | //printf("start block for %s = %u\n", psz_fname, start); 38 | } else { 39 | //printf("didn't match on name %s\n", psz_fname); 40 | } 41 | } 42 | 43 | void find_start_blocks(udf_t *p_udf, udf_dirent_t *p_udf_dirent) 44 | { 45 | if (!p_udf_dirent) 46 | return; 47 | 48 | while(udf_readdir(p_udf_dirent)) { 49 | if (udf_is_dir(p_udf_dirent)) { 50 | udf_dirent_t *p_udf_dirent2 = udf_opendir(p_udf_dirent); 51 | if (p_udf_dirent) { 52 | find_start_blocks(p_udf, p_udf_dirent2); 53 | } 54 | } else { 55 | add_block(p_udf_dirent); 56 | } 57 | } 58 | } 59 | 60 | int main(int argc, char *argv[]) 61 | { 62 | dvdcss_t input; 63 | int fd; 64 | 65 | struct stat stat_buf; 66 | int total_blocks; 67 | unsigned long long pos = 0; 68 | 69 | udf_t *p_udf; 70 | udf_dirent_t *p_udf_root; 71 | 72 | char * buffer; 73 | unsigned long long preamble; 74 | 75 | unsigned long long count = 0; 76 | 77 | if (!(buffer = (char *) malloc(MAX*DVDCSS_BLOCK_SIZE))) { 78 | printf("failed to allocate space for buffer\n"); 79 | return 0; 80 | } 81 | 82 | if (argc != 2) { 83 | printf("usage:\n\t %s \n", argv[0]); 84 | return 1; 85 | } 86 | 87 | /* figure out how big the ISO image is */ 88 | if (stat(argv[1], &stat_buf) < 0) { 89 | perror("failed to stat input iso"); 90 | return 1; 91 | } 92 | 93 | total_blocks = stat_buf.st_size / DVDCSS_BLOCK_SIZE; 94 | if (stat_buf.st_size != (long long) total_blocks * DVDCSS_BLOCK_SIZE) { 95 | printf("partial block?????\n"); 96 | return 1; 97 | } 98 | printf("total_blocks = %d\n", total_blocks); 99 | start_blocks.push_back(total_blocks); 100 | 101 | /* find locations where have to rekey CSS */ 102 | if ((p_udf = udf_open(argv[1])) == NULL) { 103 | fprintf(stderr, "couldn't open %s as UDF\n", argv[1]); 104 | return 1; 105 | } 106 | 107 | if (!(p_udf_root = udf_get_root(p_udf, true, 0))) { 108 | fprintf(stderr, "couldn't find / in %s\n", argv[1]); 109 | return 1; 110 | } 111 | 112 | find_start_blocks(p_udf, p_udf_root); 113 | 114 | sort(start_blocks.begin(), start_blocks.end()); 115 | 116 | /* prep CSS */ 117 | if (!(input = dvdcss_open(argv[1]))) { 118 | fprintf(stderr, "dvdcss_open failed\n"); 119 | return 1; 120 | } 121 | 122 | if ((fd = open(argv[1], O_RDWR)) < 0) { 123 | printf("failed to open input/output file\n"); 124 | return 1; 125 | } 126 | 127 | /* if not scrambled skip! */ 128 | if (! dvdcss_is_scrambled(input)) { 129 | printf("dvd isn't scrambled\n"); 130 | return 0; 131 | } 132 | 133 | preamble = start_blocks[0]; 134 | start_blocks.erase(start_blocks.begin()); 135 | 136 | lseek64(fd, preamble*DVDCSS_BLOCK_SIZE, SEEK_SET); 137 | 138 | pos = preamble; 139 | 140 | while (! start_blocks.empty()) { 141 | int len = MAX; 142 | int blocks_read; 143 | 144 | int end = start_blocks[0]; 145 | start_blocks.erase(start_blocks.begin()); 146 | 147 | //printf("syncing at position = %llu, next sync point at %u\n", pos, end); 148 | 149 | if ( dvdcss_seek(input, pos, DVDCSS_SEEK_KEY) < 0) { 150 | fprintf(stderr, "failed to seek to %llu: %s\n", pos, dvdcss_error(input)); 151 | } 152 | 153 | while (pos < end) { 154 | int read_size; 155 | char * tmp_buffer; 156 | int reseek; 157 | 158 | if (pos + len > end) { 159 | len = end - pos; 160 | } 161 | 162 | read_size = len * DVDCSS_BLOCK_SIZE; 163 | 164 | if ((blocks_read = read(fd, buffer, read_size)) != read_size) { 165 | printf("short read, not handled yet\n"); 166 | return 1; 167 | } 168 | 169 | tmp_buffer = buffer; 170 | reseek = 0; 171 | 172 | for(int index = 0; index < len; index++) { 173 | if( ((uint8_t*)tmp_buffer)[0x14] & 0x30 ) { 174 | count++; 175 | if (dvdcss_seek(input, pos+index, DVDCSS_NOFLAGS) < 0) { 176 | fprintf(stderr, "failed to seek to %llu (index %d): %s\n", pos+index, index, dvdcss_error(input)); 177 | return 1; 178 | } 179 | if (dvdcss_read(input, tmp_buffer, 1, DVDCSS_READ_DECRYPT) != 1) { 180 | fprintf(stderr, "dvdcss_read failed\n"); 181 | return 1; 182 | } 183 | lseek64(fd, (pos+index) * DVDCSS_BLOCK_SIZE, SEEK_SET); 184 | if (write(fd, tmp_buffer, DVDCSS_BLOCK_SIZE) != DVDCSS_BLOCK_SIZE) 185 | { 186 | printf("failed to write block correctly\n"); 187 | return 1; 188 | } 189 | reseek = 1; 190 | } 191 | tmp_buffer = tmp_buffer + DVDCSS_BLOCK_SIZE; 192 | } 193 | 194 | pos += len; 195 | if (reseek) { 196 | lseek64(fd, pos * DVDCSS_BLOCK_SIZE, SEEK_SET); 197 | } 198 | } 199 | } 200 | printf("descrambled %llu blocks\n", count); 201 | printf("\n"); 202 | 203 | return 0; 204 | } 205 | -------------------------------------------------------------------------------- /history/2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | #define _FILE_OFFSET_BITS 64 17 | #define _LARGEFILE64_SOURCE 1 18 | #define _LARGEFILE_SOURCE 1 19 | 20 | vector start_blocks; 21 | 22 | #define MAX 2000 23 | 24 | static void add_block(const udf_dirent_t *p_udf_dirent) 25 | { 26 | char *psz_fname=(char *) udf_get_filename(p_udf_dirent); 27 | int len = strlen(psz_fname); 28 | 29 | unsigned int start; 30 | 31 | for(int i=0; i < len; i++) { 32 | psz_fname[i] = tolower(psz_fname[i]); 33 | } 34 | if (! strcmp(psz_fname + (len-3), "vob")) { 35 | start = udf_get_start_block(p_udf_dirent); 36 | start_blocks.push_back(start); 37 | printf("start block for %s = %u\n", psz_fname, start); 38 | } else { 39 | printf("didn't match on name %s\n", psz_fname); 40 | } 41 | } 42 | 43 | void find_start_blocks(udf_t *p_udf, udf_dirent_t *p_udf_dirent) 44 | { 45 | if (!p_udf_dirent) 46 | return; 47 | 48 | while(udf_readdir(p_udf_dirent)) { 49 | if (udf_is_dir(p_udf_dirent)) { 50 | udf_dirent_t *p_udf_dirent2 = udf_opendir(p_udf_dirent); 51 | if (p_udf_dirent) { 52 | find_start_blocks(p_udf, p_udf_dirent2); 53 | } 54 | } else { 55 | add_block(p_udf_dirent); 56 | } 57 | } 58 | } 59 | 60 | int main(int argc, char *argv[]) 61 | { 62 | dvdcss_t input; 63 | int fd; 64 | int fd_in; 65 | 66 | struct stat stat_buf; 67 | int total_blocks; 68 | unsigned int pos = 0; 69 | 70 | udf_t *p_udf; 71 | udf_dirent_t *p_udf_root; 72 | 73 | char * buffer; 74 | unsigned int preamble; 75 | 76 | if (!(buffer = (char *) malloc(MAX*DVDCSS_BLOCK_SIZE))) { 77 | printf("failed to allocate space for buffer\n"); 78 | return 0; 79 | } 80 | 81 | if (argc != 3) { 82 | printf("usage:\n\t %s \n", argv[0]); 83 | return 1; 84 | } 85 | 86 | /* figure out how big the ISO image is */ 87 | if (stat(argv[1], &stat_buf) < 0) { 88 | perror("failed to stat input iso"); 89 | return 1; 90 | } 91 | 92 | total_blocks = stat_buf.st_size / 2048; 93 | if (stat_buf.st_size != (long long) total_blocks * 2048) { 94 | printf("partial block?????\n"); 95 | return 1; 96 | } 97 | printf("total_blocks = %d\n", total_blocks); 98 | start_blocks.push_back(total_blocks); 99 | 100 | /* find locations where have to rekey CSS */ 101 | if ((p_udf = udf_open(argv[1])) == NULL) { 102 | fprintf(stderr, "couldn't open %s as UDF\n", argv[1]); 103 | return 1; 104 | } 105 | 106 | if (!(p_udf_root = udf_get_root(p_udf, true, 0))) { 107 | fprintf(stderr, "couldn't find / in %s\n", argv[1]); 108 | return 1; 109 | } 110 | 111 | find_start_blocks(p_udf, p_udf_root); 112 | 113 | sort(start_blocks.begin(), start_blocks.end()); 114 | 115 | /* for(vector::iterator it = start_blocks.begin(); it != start_blocks.end(); it++) { 116 | printf("end pos = %d\n", *it); 117 | } */ 118 | 119 | /* prep CSS */ 120 | if (!(input = dvdcss_open(argv[1]))) { 121 | fprintf(stderr, "dvdcss_open failed\n"); 122 | return 1; 123 | } 124 | 125 | /* prep output file */ 126 | if ((fd = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) { 127 | printf("failed to open output file\n"); 128 | return 1; 129 | } 130 | 131 | if ((fd_in = open(argv[1], O_RDONLY)) < 0) { 132 | printf("failed to open output file\n"); 133 | return 1; 134 | } 135 | 136 | /* if not scrambled skip! */ 137 | if (! dvdcss_is_scrambled(input)) { 138 | printf("dvd isn't scrambled\n"); 139 | return 0; 140 | } 141 | 142 | preamble = start_blocks[0]; 143 | start_blocks.erase(start_blocks.begin()); 144 | 145 | if (preamble > MAX) { 146 | printf("preamble is too big (%u)\n", preamble); 147 | return 0; 148 | } 149 | 150 | pos = read(fd_in, buffer, preamble*2048); 151 | if (pos != preamble * 2048) { 152 | printf("didn't read enough (%u vs %d)\n", preamble*2048, pos); 153 | return 0; 154 | } 155 | 156 | if (write(fd, buffer, pos) != pos) { 157 | printf("didn't write enough\n"); 158 | return 0; 159 | } 160 | 161 | pos = pos / 2048; 162 | 163 | while (! start_blocks.empty()) { 164 | int len = MAX; 165 | int blocks_read; 166 | 167 | int end = start_blocks[0]; 168 | // start_blocks.pop_back(); 169 | start_blocks.erase(start_blocks.begin()); 170 | 171 | printf("current position = %u, next sync point at %u\n", pos, end); 172 | 173 | // don't dvdcss_seek first time around or last element (last block of dvd 174 | printf("syncing at position %u\n", pos); 175 | if ( dvdcss_seek(input, pos, DVDCSS_SEEK_KEY) < 0) { 176 | fprintf(stderr, "failed to seek to %d: %s\n", pos, dvdcss_error(input)); 177 | /* } else { 178 | printf("not seeking as at beginning, no sync points yet\n"); */ 179 | } 180 | 181 | while (pos < end) { 182 | //printf("current pos = %u\n", pos); 183 | if (pos + len > end) { 184 | //printf("going to a read shorter then %d as end is near\n", len); 185 | len = end - pos; 186 | } 187 | //printf("going to read %d\n", len); 188 | 189 | if ((blocks_read = dvdcss_read(input, buffer, len, DVDCSS_READ_DECRYPT)) != len) { 190 | fprintf(stderr, "didn't read %d blocks! read %d blocks\n", len, blocks_read); 191 | } 192 | //printf("read %d\n", blocks_read); 193 | pos += blocks_read; 194 | 195 | if (write(fd, buffer, 2048 * blocks_read) != 2048 * blocks_read) { 196 | fprintf(stderr, "write didn't write enough\n"); 197 | return 0; 198 | } 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /history/3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | #define _FILE_OFFSET_BITS 64 17 | #define _LARGEFILE64_SOURCE 1 18 | #define _LARGEFILE_SOURCE 1 19 | 20 | vector start_blocks; 21 | 22 | #define MAX 2000 23 | 24 | static void add_block(const udf_dirent_t *p_udf_dirent) 25 | { 26 | char *psz_fname=(char *) udf_get_filename(p_udf_dirent); 27 | int len = strlen(psz_fname); 28 | 29 | unsigned int start; 30 | 31 | for(int i=0; i < len; i++) { 32 | psz_fname[i] = tolower(psz_fname[i]); 33 | } 34 | if (! strcmp(psz_fname + (len-3), "vob")) { 35 | start = udf_get_start_block(p_udf_dirent); 36 | start_blocks.push_back(start); 37 | printf("start block for %s = %u\n", psz_fname, start); 38 | } else { 39 | printf("didn't match on name %s\n", psz_fname); 40 | } 41 | } 42 | 43 | void find_start_blocks(udf_t *p_udf, udf_dirent_t *p_udf_dirent) 44 | { 45 | if (!p_udf_dirent) 46 | return; 47 | 48 | while(udf_readdir(p_udf_dirent)) { 49 | if (udf_is_dir(p_udf_dirent)) { 50 | udf_dirent_t *p_udf_dirent2 = udf_opendir(p_udf_dirent); 51 | if (p_udf_dirent) { 52 | find_start_blocks(p_udf, p_udf_dirent2); 53 | } 54 | } else { 55 | add_block(p_udf_dirent); 56 | } 57 | } 58 | } 59 | 60 | int main(int argc, char *argv[]) 61 | { 62 | dvdcss_t input; 63 | int fd; 64 | int fd_in; 65 | 66 | struct stat stat_buf; 67 | int total_blocks; 68 | unsigned int pos = 0; 69 | 70 | udf_t *p_udf; 71 | udf_dirent_t *p_udf_root; 72 | 73 | char * buffer; 74 | unsigned int preamble; 75 | 76 | if (!(buffer = (char *) malloc(MAX*DVDCSS_BLOCK_SIZE))) { 77 | printf("failed to allocate space for buffer\n"); 78 | return 0; 79 | } 80 | 81 | if (argc != 3) { 82 | printf("usage:\n\t %s \n", argv[0]); 83 | return 1; 84 | } 85 | 86 | /* figure out how big the ISO image is */ 87 | if (stat(argv[1], &stat_buf) < 0) { 88 | perror("failed to stat input iso"); 89 | return 1; 90 | } 91 | 92 | total_blocks = stat_buf.st_size / 2048; 93 | if (stat_buf.st_size != (long long) total_blocks * 2048) { 94 | printf("partial block?????\n"); 95 | return 1; 96 | } 97 | printf("total_blocks = %d\n", total_blocks); 98 | start_blocks.push_back(total_blocks); 99 | 100 | /* find locations where have to rekey CSS */ 101 | if ((p_udf = udf_open(argv[1])) == NULL) { 102 | fprintf(stderr, "couldn't open %s as UDF\n", argv[1]); 103 | return 1; 104 | } 105 | 106 | if (!(p_udf_root = udf_get_root(p_udf, true, 0))) { 107 | fprintf(stderr, "couldn't find / in %s\n", argv[1]); 108 | return 1; 109 | } 110 | 111 | find_start_blocks(p_udf, p_udf_root); 112 | 113 | sort(start_blocks.begin(), start_blocks.end()); 114 | 115 | /* for(vector::iterator it = start_blocks.begin(); it != start_blocks.end(); it++) { 116 | printf("end pos = %d\n", *it); 117 | } */ 118 | 119 | /* prep CSS */ 120 | if (!(input = dvdcss_open(argv[1]))) { 121 | fprintf(stderr, "dvdcss_open failed\n"); 122 | return 1; 123 | } 124 | 125 | /* prep output file */ 126 | if ((fd = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) { 127 | printf("failed to open output file\n"); 128 | return 1; 129 | } 130 | 131 | if ((fd_in = open(argv[1], O_RDWR)) < 0) { 132 | printf("failed to open output file\n"); 133 | return 1; 134 | } 135 | 136 | /* if not scrambled skip! */ 137 | if (! dvdcss_is_scrambled(input)) { 138 | printf("dvd isn't scrambled\n"); 139 | return 0; 140 | } 141 | 142 | preamble = start_blocks[0]; 143 | start_blocks.erase(start_blocks.begin()); 144 | 145 | if (preamble > MAX) { 146 | printf("preamble is too big (%u)\n", preamble); 147 | return 0; 148 | } 149 | 150 | pos = read(fd_in, buffer, preamble*2048); 151 | if (pos != preamble * 2048) { 152 | printf("didn't read enough (%u vs %d)\n", preamble*2048, pos); 153 | return 0; 154 | } 155 | 156 | if (write(fd, buffer, pos) != pos) { 157 | printf("didn't write enough\n"); 158 | return 0; 159 | } 160 | 161 | pos = pos / 2048; 162 | 163 | while (! start_blocks.empty()) { 164 | int len = MAX; 165 | int blocks_read; 166 | 167 | int end = start_blocks[0]; 168 | start_blocks.erase(start_blocks.begin()); 169 | 170 | printf("current position = %u, next sync point at %u\n", pos, end); 171 | 172 | // don't dvdcss_seek first time around or last element (last block of dvd 173 | printf("syncing at position %u\n", pos); 174 | if ( dvdcss_seek(input, pos, DVDCSS_SEEK_KEY) < 0) { 175 | fprintf(stderr, "failed to seek to %d: %s\n", pos, dvdcss_error(input)); 176 | } 177 | 178 | while (pos < end) { 179 | int read_size; 180 | char * tmp_buffer = buffer; 181 | //printf("current pos = %u\n", pos); 182 | if (pos + len > end) { 183 | //printf("going to a read shorter then %d as end is near\n", len); 184 | len = end - pos; 185 | } 186 | //printf("going to read %d\n", len); 187 | 188 | read_size = len * 2048; 189 | 190 | if ((blocks_read = read(fd_in, buffer, read_size)) != read_size) { 191 | printf("short read, not handled yet\n"); 192 | } 193 | 194 | for(int index = 0; index < len; index++) { 195 | if( ((uint8_t*)tmp_buffer)[0x14] & 0x30 ) { 196 | printf("index %d block needs to be decrypted\n", index); 197 | if (dvdcss_seek(input, pos+index, DVDCSS_NOFLAGS) < 0) { 198 | printf("dvdcss_seek failed\n"); 199 | return 1; 200 | } 201 | if (dvdcss_read(input, tmp_buffer, 1, DVDCSS_READ_DECRYPT) != 1) { 202 | printf("dvdcss_read failed\n"); 203 | return 1; 204 | } 205 | } 206 | tmp_buffer = tmp_buffer + DVDCSS_BLOCK_SIZE; 207 | } 208 | 209 | //printf("read %d\n", blocks_read); 210 | pos += len; 211 | 212 | if (write(fd, buffer, read_size) != read_size) { 213 | fprintf(stderr, "write didn't write enough\n"); 214 | return 1; 215 | } 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /DVDRipper.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012 Shaya Potter */ 2 | 3 | #define _FILE_OFFSET_BITS 64 4 | #define _LARGEFILE64_SOURCE 1 5 | #define _LARGEFILE_SOURCE 1 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "DVDRipper.h" 14 | 15 | #define MAX 1 16 | #define CEILING(x, y) ((x+(y-1))/y) //ripped from libudf 17 | 18 | ssize_t my_write(int fd, const void * buf, size_t count) { 19 | int ret; 20 | size_t my_count = count; 21 | char * my_buf = (char *) buf; 22 | 23 | while (my_count) { 24 | if (my_count != count) { 25 | printf("looped in my_write, last write = %d\n", ret); 26 | } 27 | if ((ret = write(fd, my_buf, my_count)) == -1) { 28 | if (errno != EINTR) { 29 | perror("write failed!"); 30 | goto out; 31 | } 32 | } else { 33 | my_count -= ret; 34 | my_buf += ret; 35 | } 36 | } 37 | 38 | ret = count; 39 | 40 | out: 41 | return ret; 42 | } 43 | 44 | DVDRipper::DVDRipper(char * p, int f) { 45 | path = p; 46 | flags = f; 47 | 48 | } 49 | 50 | int DVDRipper::open_disc() { 51 | off64_t disc_len; 52 | int total_blocks; 53 | 54 | if ((fd = open(path, flags)) < 0) { 55 | printf("failed to open input/output file\n"); 56 | return 1; 57 | } 58 | 59 | /* figure out how big the ISO image is */ 60 | if ((disc_len = lseek64(fd, 0, SEEK_END)) < 0) { 61 | perror("lseek64 failed"); 62 | return 1; 63 | } 64 | 65 | if (lseek64(fd, 0, SEEK_SET) < 0) { 66 | perror("lseek64 failed"); 67 | return 1; 68 | } 69 | 70 | total_blocks = disc_len / DVDCSS_BLOCK_SIZE; 71 | if (disc_len != (long long) total_blocks * DVDCSS_BLOCK_SIZE) { 72 | printf("partial block?????\n"); 73 | return 1; 74 | } 75 | printf("total_blocks = %d\n", total_blocks); 76 | start_blocks.push_back(total_blocks); 77 | 78 | /* find locations where have to rekey CSS */ 79 | if ((p_iso = iso9660_open(path)) == NULL) { 80 | printf("couldn't open %s as ISO\n", path); 81 | return 1; 82 | } 83 | 84 | return 0; 85 | } 86 | 87 | void DVDRipper::find_start_blocks() { 88 | CdioList_t *p_entlist; 89 | CdioListNode_t *p_entnode; 90 | 91 | if (!p_iso) 92 | return; 93 | 94 | p_entlist = iso9660_ifs_readdir (p_iso, "/video_ts/"); 95 | 96 | if (p_entlist) { 97 | _CDIO_LIST_FOREACH (p_entnode, p_entlist) { 98 | unsigned long long start; 99 | unsigned long long blocks; 100 | 101 | char filename[4096]; 102 | int len; 103 | 104 | iso9660_stat_t *p_statbuf = 105 | (iso9660_stat_t *) _cdio_list_node_data (p_entnode); 106 | iso9660_name_translate(p_statbuf->filename, filename); 107 | len = strlen(filename); 108 | 109 | if (!(2 == p_statbuf->type) ) { 110 | if (! strcmp(filename + (len-3), "vob")) { 111 | start = p_statbuf->lsn; 112 | blocks = CEILING(p_statbuf->size, DVDCSS_BLOCK_SIZE); 113 | 114 | start_map[start] = strdup(filename); 115 | 116 | if (blocks == 0) { 117 | //file length of 0 would result in a blocks of 0, and don't want 118 | //to subtract one from it. 119 | end_blocks[start] = start; 120 | } else { 121 | //-1 as start block is included in count of blocks 122 | end_blocks[start] = start - 1 + blocks; 123 | } 124 | 125 | printf("%s: %llu->%llu (%llu blocks)\n", filename, start, end_blocks[start], blocks); 126 | 127 | if (blocks) { 128 | if (find(start_blocks.begin(), start_blocks.end(), start) == start_blocks.end()) { 129 | start_blocks.push_back(start); 130 | } 131 | } 132 | } 133 | } 134 | } 135 | 136 | _cdio_list_free (p_entlist, true, NULL); 137 | } 138 | 139 | sort(start_blocks.begin(), start_blocks.end()); 140 | preamble = start_blocks[0]; 141 | start_blocks.erase(start_blocks.begin()); 142 | } 143 | 144 | void DVDRipper::info() { 145 | for(std::vector::iterator it = start_blocks.begin(); it != start_blocks.end(); it++) { 146 | printf("end pos = %llu\n", *it); 147 | } 148 | 149 | for(std::map::iterator p = start_map.begin(); p != start_map.end(); p++) { 150 | printf("%s : %llu\n", p->second, p->first); 151 | } 152 | } 153 | 154 | int DVDRipper::rip() { 155 | unsigned long long pos = preamble; 156 | unsigned long long count = 0; 157 | char * buffer; 158 | 159 | /* prep CSS */ 160 | if (!(input = dvdcss_open(path))) { 161 | printf("dvdcss_open failed\n"); 162 | return 1; 163 | } 164 | 165 | /* if not scrambled skip! */ 166 | /* this doesn't do anything on iso input */ 167 | if (! dvdcss_is_scrambled(input)) { 168 | printf("dvd isn't scrambled\n"); 169 | return 1; 170 | } 171 | 172 | if (!(buffer = (char *) malloc(MAX*DVDCSS_BLOCK_SIZE))) { 173 | printf("failed to allocate space for buffer\n"); 174 | return 1; 175 | } 176 | 177 | while (! start_blocks.empty()) { 178 | int len = MAX; 179 | int blocks_read; 180 | 181 | int cur = pos; 182 | unsigned long long end = start_blocks[0]; 183 | //int seek_failed = 0; 184 | 185 | fflush(NULL); 186 | 187 | //Q1. Can it ever fail to get key here? 188 | //A1. Probably yes, 189 | //a) since in ISO bruteforced, may not have enough data? 190 | //b) perhaps simply a bad location to brute force? 191 | //Q2. Will we be able to find the key elsewhere? 192 | //A2. Don't know. Need to learn more 193 | printf("syncing at position = %llu, next sync point at %llu\n", pos, end); 194 | if ( dvdcss_seek(input, pos, DVDCSS_SEEK_KEY) < 0) { 195 | printf("failed to seek to %llu: %s\n", pos, dvdcss_error(input)); 196 | //seek_failed = 1; 197 | } else { 198 | //seek_failed = 0; 199 | } 200 | 201 | start_blocks.erase(start_blocks.begin()); 202 | 203 | while (pos < end) { 204 | int read_size; 205 | char * tmp_buffer; 206 | bool reseek; 207 | 208 | fflush(NULL); 209 | 210 | if (pos + len > end) { 211 | len = end - pos; 212 | } 213 | 214 | read_size = len * DVDCSS_BLOCK_SIZE; 215 | 216 | if ((blocks_read = read(fd, buffer, read_size)) != read_size) { 217 | printf("short read, not handled yet, block_read = %d\n", blocks_read); 218 | return 1; 219 | } 220 | 221 | tmp_buffer = buffer; 222 | 223 | reseek = false; 224 | 225 | for(int index = 0; index < len; index++) { 226 | tmp_buffer = tmp_buffer + DVDCSS_BLOCK_SIZE*index; 227 | 228 | //is this block scrambled? 229 | if( ((uint8_t*) tmp_buffer)[0x14] & 0x30 ) { 230 | if (pos + index > end_blocks[cur]) { 231 | printf("skipping decode of supposed encrypted block (%llu) as not within VOB\n", pos+index); 232 | continue; 233 | } 234 | 235 | if (dvdcss_seek(input, pos+index, DVDCSS_NOFLAGS) < 0) { 236 | printf("failed to seek to %llu (index %d): %s\n", pos+index, index, dvdcss_error(input)); 237 | return 1; 238 | } 239 | 240 | if (dvdcss_read(input, tmp_buffer, 1, DVDCSS_READ_DECRYPT) != 1) { 241 | printf("dvdcss_read failed\n"); 242 | return 1; 243 | } 244 | 245 | lseek64(fd, (pos+index) * DVDCSS_BLOCK_SIZE, SEEK_SET); 246 | if (my_write(fd, tmp_buffer, DVDCSS_BLOCK_SIZE) < 0) { 247 | return 1; 248 | } 249 | 250 | //as we just seeked fd away fron its position. 251 | reseek = true; 252 | count++; 253 | } 254 | } 255 | 256 | pos += len; 257 | if (reseek) { 258 | lseek64(fd, pos * DVDCSS_BLOCK_SIZE, SEEK_SET); 259 | } 260 | } 261 | } 262 | 263 | fflush(NULL); 264 | 265 | printf("descrambled %llu blocks\n", count); 266 | printf("\n"); 267 | 268 | return 0; 269 | } 270 | -------------------------------------------------------------------------------- /history/7.cpp: -------------------------------------------------------------------------------- 1 | #define _FILE_OFFSET_BITS 64 2 | #define _LARGEFILE64_SOURCE 1 3 | #define _LARGEFILE_SOURCE 1 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | using namespace std; 22 | 23 | #define MAX 2000 24 | #define CEILING(x, y) ((x+(y-1))/y) //ripped from libudf 25 | 26 | vector start_blocks; 27 | map end_blocks; 28 | map start_map; 29 | 30 | ssize_t my_write(int fd, const void * buf, size_t count) 31 | { 32 | int ret; 33 | size_t my_count = count; 34 | char * my_buf = (char *) buf; 35 | 36 | while (my_count) { 37 | if (my_count != count) { 38 | printf("looped in my_write, last write = %d\n", ret); 39 | } 40 | if ((ret = write(fd, my_buf, my_count)) == -1) { 41 | if (errno != EINTR) { 42 | perror("write failed!"); 43 | goto out; 44 | } 45 | } else { 46 | my_count -= ret; 47 | my_buf += ret; 48 | } 49 | } 50 | 51 | ret = count; 52 | 53 | out: 54 | return ret; 55 | } 56 | 57 | void find_start_blocks(iso9660_t *p_iso) 58 | { 59 | CdioList_t *p_entlist; 60 | CdioListNode_t *p_entnode; 61 | 62 | if (!p_iso) 63 | return; 64 | 65 | p_entlist = iso9660_ifs_readdir (p_iso, "/video_ts/"); 66 | 67 | if (p_entlist) { 68 | _CDIO_LIST_FOREACH (p_entnode, p_entlist) { 69 | unsigned long long start; 70 | unsigned long long blocks; 71 | 72 | char filename[4096]; 73 | int len; 74 | 75 | iso9660_stat_t *p_statbuf = 76 | (iso9660_stat_t *) _cdio_list_node_data (p_entnode); 77 | iso9660_name_translate(p_statbuf->filename, filename); 78 | len = strlen(filename); 79 | 80 | if (!(2 == p_statbuf->type) ) { 81 | if (! strcmp(filename + (len-3), "vob")) { 82 | start = p_statbuf->lsn; 83 | blocks = CEILING(p_statbuf->size, DVDCSS_BLOCK_SIZE); 84 | 85 | start_map[start] = strdup(filename); 86 | 87 | if (blocks == 0) { 88 | //file length of 0 would result in a blocks of 0, and don't want 89 | //to subtract one from it. 90 | end_blocks[start] = start; 91 | } else { 92 | //-1 as start block is included in count of blocks 93 | end_blocks[start] = start - 1 + blocks; 94 | } 95 | 96 | printf("%s: %llu->%llu (%llu blocks)\n", filename, start, end_blocks[start], blocks); 97 | 98 | if (blocks) { 99 | if (find(start_blocks.begin(), start_blocks.end(), start) == start_blocks.end()) { 100 | start_blocks.push_back(start); 101 | } 102 | } 103 | } 104 | } 105 | } 106 | 107 | _cdio_list_free (p_entlist, true); 108 | } 109 | } 110 | 111 | int main(int argc, char *argv[]) 112 | { 113 | dvdcss_t input; 114 | int fd; 115 | int flags = O_RDWR; 116 | 117 | off64_t disc_len; 118 | int total_blocks; 119 | unsigned long long pos = 0; 120 | 121 | iso9660_t * p_iso; 122 | 123 | char * buffer; 124 | unsigned long long preamble; 125 | 126 | unsigned long long count = 0; 127 | 128 | if (argc == 3 && !strcmp(argv[2], "-test")) { 129 | flags = O_RDONLY; 130 | } 131 | 132 | if (!(buffer = (char *) malloc(MAX*DVDCSS_BLOCK_SIZE))) { 133 | printf("failed to allocate space for buffer\n"); 134 | return 0; 135 | } 136 | 137 | if (argc < 2) { 138 | printf("usage:\n\t %s \n", argv[0]); 139 | return 1; 140 | } 141 | 142 | if ((fd = open(argv[1], flags)) < 0) { 143 | printf("failed to open input/output file\n"); 144 | return 1; 145 | } 146 | 147 | /* figure out how big the ISO image is */ 148 | if ((disc_len = lseek64(fd, 0, SEEK_END)) < 0) { 149 | perror("lseek64 failed"); 150 | return 1; 151 | } 152 | 153 | total_blocks = disc_len / DVDCSS_BLOCK_SIZE; 154 | if (disc_len != (long long) total_blocks * DVDCSS_BLOCK_SIZE) { 155 | printf("partial block?????\n"); 156 | return 1; 157 | } 158 | printf("total_blocks = %d\n", total_blocks); 159 | start_blocks.push_back(total_blocks); 160 | 161 | /* find locations where have to rekey CSS */ 162 | if ((p_iso = iso9660_open(argv[1])) == NULL) { 163 | printf("couldn't open %s as UDF\n", argv[1]); 164 | return 1; 165 | } 166 | 167 | find_start_blocks(p_iso); 168 | 169 | sort(start_blocks.begin(), start_blocks.end()); 170 | 171 | for(vector::iterator it = start_blocks.begin(); it != start_blocks.end(); it++) { 172 | printf("end pos = %llu\n", *it); 173 | } 174 | 175 | for(map::iterator p = start_map.begin(); p != start_map.end(); p++) { 176 | printf("%s : %llu\n", p->second, p->first); 177 | } 178 | 179 | if (argc == 3 && !strcmp(argv[2], "-test")) { 180 | return 0; 181 | } 182 | 183 | /* prep CSS */ 184 | if (!(input = dvdcss_open(argv[1]))) { 185 | printf("dvdcss_open failed\n"); 186 | return 1; 187 | } 188 | 189 | /* if not scrambled skip! */ 190 | /* this doesn't do anything on iso input */ 191 | if (! dvdcss_is_scrambled(input)) { 192 | printf("dvd isn't scrambled\n"); 193 | return 0; 194 | } 195 | 196 | preamble = start_blocks[0]; 197 | start_blocks.erase(start_blocks.begin()); 198 | 199 | lseek64(fd, preamble*DVDCSS_BLOCK_SIZE, SEEK_SET); 200 | 201 | pos = preamble; 202 | 203 | while (! start_blocks.empty()) { 204 | int len = MAX; 205 | int blocks_read; 206 | 207 | int cur = pos; 208 | unsigned long long end = start_blocks[0]; 209 | int seek_failed = 0; 210 | 211 | fflush(NULL); 212 | 213 | start_blocks.erase(start_blocks.begin()); 214 | 215 | //printf("syncing at position = %llu, next sync point at %u\n", pos, end); 216 | 217 | if ( dvdcss_seek(input, pos, DVDCSS_SEEK_KEY) < 0) { 218 | //Q. Can it ever fail to get key here, but have the key 219 | //elsewhere? perhaps have some accounting if this fails, 220 | //know no point in trying to dvdcss_read() till next 221 | //DVDCSS_SEEK_KEY? 222 | printf("failed to seek to %llu: %s\n", pos, dvdcss_error(input)); 223 | seek_failed = 1; 224 | } else { 225 | seek_failed = 0; 226 | } 227 | 228 | while (pos < end) { 229 | int read_size; 230 | char * tmp_buffer; 231 | int reseek; 232 | 233 | fflush(NULL); 234 | 235 | if (pos + len > end) { 236 | len = end - pos; 237 | } 238 | 239 | read_size = len * DVDCSS_BLOCK_SIZE; 240 | 241 | if ((blocks_read = read(fd, buffer, read_size)) != read_size) { 242 | printf("short read, not handled yet\n"); 243 | return 1; 244 | } 245 | 246 | tmp_buffer = buffer; 247 | reseek = 0; 248 | 249 | for(int index = 0; index < len; index++) { 250 | char block[2048]; 251 | 252 | if( ((uint8_t*)tmp_buffer)[0x14] & 0x30 ) { 253 | if (pos + index > end_blocks[cur]) { 254 | printf("should skipping decode of supposed encrypted block (%llu) as not within VOB\n", pos+index); 255 | } 256 | 257 | if (! dvdseek_failed) { 258 | if (dvdcss_seek(input, pos+index, DVDCSS_NOFLAGS) < 0) { 259 | printf("failed to seek to %llu (index %d): %s\n", pos+index, index, dvdcss_error(input)); 260 | return 1; 261 | } 262 | 263 | if (dvdcss_read(input, tmp_buffer, 1, DVDCSS_READ_DECRYPT) != 1) { 264 | printf("dvdcss_read failed\n"); 265 | return 1; 266 | } 267 | 268 | lseek64(fd, (pos+index) * DVDCSS_BLOCK_SIZE, SEEK_SET); 269 | if (my_write(fd, tmp_buffer, DVDCSS_BLOCK_SIZE) < 0) { 270 | return 1; 271 | } 272 | 273 | reseek = 1; 274 | count++; 275 | } 276 | } 277 | tmp_buffer = tmp_buffer + DVDCSS_BLOCK_SIZE; 278 | } 279 | 280 | pos += len; 281 | if (reseek) { 282 | lseek64(fd, pos * DVDCSS_BLOCK_SIZE, SEEK_SET); 283 | } 284 | } 285 | } 286 | printf("descrambled %llu blocks\n", count); 287 | printf("\n"); 288 | 289 | return 0; 290 | } 291 | -------------------------------------------------------------------------------- /history/6.cpp: -------------------------------------------------------------------------------- 1 | #define _FILE_OFFSET_BITS 64 2 | #define _LARGEFILE64_SOURCE 1 3 | #define _LARGEFILE_SOURCE 1 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | using namespace std; 22 | 23 | #define MAX 2000 24 | #define CEILING(x, y) ((x+(y-1))/y) //ripped from libudf 25 | 26 | vector start_blocks; 27 | map end_blocks; 28 | map start_map; 29 | 30 | ssize_t my_write(int fd, const void * buf, size_t count) 31 | { 32 | int ret; 33 | size_t my_count = count; 34 | char * my_buf = (char *) buf; 35 | 36 | while (my_count) { 37 | if (my_count != count) { 38 | printf("looped in my_write, last write = %d\n", ret); 39 | } 40 | if ((ret = write(fd, my_buf, my_count)) == -1) { 41 | if (errno != EINTR) { 42 | perror("write failed!"); 43 | goto out; 44 | } 45 | } else { 46 | my_count -= ret; 47 | my_buf += ret; 48 | } 49 | } 50 | 51 | ret = count; 52 | out: 53 | return ret; 54 | } 55 | 56 | void find_start_blocks(iso9660_t *p_iso) 57 | { 58 | CdioList_t *p_entlist; 59 | CdioListNode_t *p_entnode; 60 | 61 | if (!p_iso) 62 | return; 63 | 64 | p_entlist = iso9660_ifs_readdir (p_iso, "/video_ts/"); 65 | 66 | if (p_entlist) { 67 | _CDIO_LIST_FOREACH (p_entnode, p_entlist) 68 | { 69 | unsigned long long start; 70 | unsigned long long blocks; 71 | 72 | char filename[4096]; 73 | int len; 74 | 75 | iso9660_stat_t *p_statbuf = 76 | (iso9660_stat_t *) _cdio_list_node_data (p_entnode); 77 | iso9660_name_translate(p_statbuf->filename, filename); 78 | len = strlen(filename); 79 | 80 | if (!(2 == p_statbuf->type) ) { 81 | if (! strcmp(filename + (len-3), "vob")) { 82 | start = p_statbuf->lsn; 83 | blocks = CEILING(p_statbuf->size, DVDCSS_BLOCK_SIZE); 84 | 85 | start_map[start] = strdup(filename); 86 | 87 | if (blocks == 0) { 88 | //file length of 0 would result in a blocks of 0, and don't want 89 | //to subtract one from it. 90 | end_blocks[start] = start; 91 | } else { 92 | //-1 as start block is included in count of blocks 93 | end_blocks[start] = start - 1 + blocks; 94 | } 95 | printf("%s: %llu->%llu (%llu blocks)\n", filename, start, end_blocks[start], blocks); 96 | if (blocks) { 97 | if (find(start_blocks.begin(), start_blocks.end(), start) == start_blocks.end()) { 98 | start_blocks.push_back(start); 99 | } 100 | } 101 | } 102 | } 103 | } 104 | 105 | _cdio_list_free (p_entlist, true); 106 | } 107 | } 108 | 109 | int main(int argc, char *argv[]) 110 | { 111 | dvdcss_t input; 112 | int fd; 113 | int flags = O_RDWR; 114 | 115 | off64_t disc_len; 116 | int total_blocks; 117 | unsigned long long pos = 0; 118 | 119 | iso9660_t * p_iso; 120 | 121 | char * buffer; 122 | unsigned long long preamble; 123 | 124 | unsigned long long count = 0; 125 | 126 | if (argc == 3 && !strcmp(argv[2], "-test")) { 127 | flags = O_RDONLY; 128 | } 129 | 130 | if (!(buffer = (char *) malloc(MAX*DVDCSS_BLOCK_SIZE))) { 131 | printf("failed to allocate space for buffer\n"); 132 | return 0; 133 | } 134 | 135 | if (argc < 2) { 136 | printf("usage:\n\t %s \n", argv[0]); 137 | return 1; 138 | } 139 | 140 | if ((fd = open(argv[1], flags)) < 0) { 141 | printf("failed to open input/output file\n"); 142 | return 1; 143 | } 144 | 145 | /* figure out how big the ISO image is */ 146 | if ((disc_len = lseek64(fd, 0, SEEK_END)) < 0) { 147 | perror("lseek64 failed"); 148 | return 1; 149 | } 150 | 151 | total_blocks = disc_len / DVDCSS_BLOCK_SIZE; 152 | if (disc_len != (long long) total_blocks * DVDCSS_BLOCK_SIZE) { 153 | printf("partial block?????\n"); 154 | return 1; 155 | } 156 | printf("total_blocks = %d\n", total_blocks); 157 | start_blocks.push_back(total_blocks); 158 | 159 | /* find locations where have to rekey CSS */ 160 | if ((p_iso = iso9660_open(argv[1])) == NULL) { 161 | printf("couldn't open %s as UDF\n", argv[1]); 162 | return 1; 163 | } 164 | 165 | find_start_blocks(p_iso); 166 | 167 | sort(start_blocks.begin(), start_blocks.end()); 168 | 169 | for(vector::iterator it = start_blocks.begin(); it != start_blocks.end(); it++) { 170 | printf("end pos = %llu\n", *it); 171 | } 172 | 173 | for(map::iterator p = start_map.begin(); p != start_map.end(); p++) { 174 | printf("%s : %llu\n", p->second, p->first); 175 | } 176 | 177 | if (argc == 3 && !strcmp(argv[2], "-test")) { 178 | return 0; 179 | } 180 | 181 | /* prep CSS */ 182 | if (!(input = dvdcss_open(argv[1]))) { 183 | printf("dvdcss_open failed\n"); 184 | return 1; 185 | } 186 | 187 | /* if not scrambled skip! */ 188 | /* this doesn't do anything on iso input */ 189 | if (! dvdcss_is_scrambled(input)) { 190 | printf("dvd isn't scrambled\n"); 191 | return 0; 192 | } 193 | 194 | preamble = start_blocks[0]; 195 | start_blocks.erase(start_blocks.begin()); 196 | 197 | lseek64(fd, preamble*DVDCSS_BLOCK_SIZE, SEEK_SET); 198 | 199 | pos = preamble; 200 | 201 | while (! start_blocks.empty()) { 202 | int len = MAX; 203 | int blocks_read; 204 | 205 | int cur = pos; 206 | unsigned long long end = start_blocks[0]; 207 | 208 | fflush(NULL); 209 | 210 | start_blocks.erase(start_blocks.begin()); 211 | 212 | //printf("syncing at position = %llu, next sync point at %u\n", pos, end); 213 | 214 | if ( dvdcss_seek(input, pos, DVDCSS_SEEK_KEY) < 0) { 215 | //Q. Can it ever fail to get key here, but have the key 216 | //elsewhere? perhaps have some accounting if this fails, 217 | //know no point in trying to dvdcss_read() till next 218 | //DVDCSS_SEEK_KEY? 219 | printf("failed to seek to %llu: %s\n", pos, dvdcss_error(input)); 220 | } 221 | 222 | while (pos < end) { 223 | int read_size; 224 | char * tmp_buffer; 225 | int reseek; 226 | 227 | fflush(NULL); 228 | 229 | if (pos + len > end) { 230 | len = end - pos; 231 | } 232 | 233 | read_size = len * DVDCSS_BLOCK_SIZE; 234 | 235 | if ((blocks_read = read(fd, buffer, read_size)) != read_size) { 236 | printf("short read, not handled yet\n"); 237 | return 1; 238 | } 239 | 240 | tmp_buffer = buffer; 241 | reseek = 0; 242 | 243 | for(int index = 0; index < len; index++) { 244 | char block[2048]; 245 | 246 | if( ((uint8_t*)tmp_buffer)[0x14] & 0x30 ) { 247 | int skip=0; 248 | if (pos + index > end_blocks[cur]) { 249 | printf("should skipping decode of supposed encrypted block (%llu) as not within VOB\n", pos+index); 250 | memcpy(block, tmp_buffer, 2048); 251 | skip=1; 252 | } 253 | count++; 254 | if (dvdcss_seek(input, pos+index, DVDCSS_NOFLAGS) < 0) { 255 | printf("failed to seek to %llu (index %d): %s\n", pos+index, index, dvdcss_error(input)); 256 | return 1; 257 | } 258 | 259 | if (dvdcss_read(input, tmp_buffer, 1, DVDCSS_READ_DECRYPT) != 1) { 260 | printf("dvdcss_read failed\n"); 261 | return 1; 262 | } 263 | if (skip) { 264 | printf("testing block we are skipping anyways\n"); 265 | if( ((uint8_t*)tmp_buffer)[0x14] & 0x30 ) { 266 | printf("dvdcss \"decoded\" block still has bit set\n"); 267 | if (!memcmp(tmp_buffer, block, 2048)) { 268 | printf("dvdcss \"decoded\" block didn't change!\n"); 269 | } else { 270 | printf("dvdcss \"decoded\" block changed!\n"); 271 | } 272 | } else { 273 | printf("dvdcss \"decoded\" block got bit removed!\n"); 274 | } 275 | } else { 276 | lseek64(fd, (pos+index) * DVDCSS_BLOCK_SIZE, SEEK_SET); 277 | if (my_write(fd, tmp_buffer, DVDCSS_BLOCK_SIZE) < 0) { 278 | return 1; 279 | } 280 | reseek = 1; 281 | } 282 | } 283 | tmp_buffer = tmp_buffer + DVDCSS_BLOCK_SIZE; 284 | } 285 | 286 | pos += len; 287 | if (reseek) { 288 | lseek64(fd, pos * DVDCSS_BLOCK_SIZE, SEEK_SET); 289 | } 290 | } 291 | } 292 | printf("descrambled %llu blocks\n", count); 293 | printf("\n"); 294 | 295 | return 0; 296 | } 297 | -------------------------------------------------------------------------------- /history/6-1.cpp: -------------------------------------------------------------------------------- 1 | #define _FILE_OFFSET_BITS 64 2 | #define _LARGEFILE64_SOURCE 1 3 | #define _LARGEFILE_SOURCE 1 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | using namespace std; 22 | 23 | #define MAX 2000 24 | #define CEILING(x, y) ((x+(y-1))/y) //ripped from libudf 25 | 26 | vector start_blocks; 27 | map end_blocks; 28 | map start_map; 29 | 30 | ssize_t my_write(int fd, const void * buf, size_t count) 31 | { 32 | int ret; 33 | size_t my_count = count; 34 | char * my_buf = (char *) buf; 35 | 36 | while (my_count) { 37 | if (my_count != count) { 38 | printf("looped in my_write, last write = %d\n", ret); 39 | } 40 | if ((ret = write(fd, my_buf, my_count)) == -1) { 41 | if (errno != EINTR) { 42 | perror("write failed!"); 43 | goto out; 44 | } 45 | } else { 46 | my_count -= ret; 47 | my_buf += ret; 48 | } 49 | } 50 | 51 | ret = count; 52 | out: 53 | return ret; 54 | } 55 | 56 | void find_start_blocks(iso9660_t *p_iso) 57 | { 58 | CdioList_t *p_entlist; 59 | CdioListNode_t *p_entnode; 60 | 61 | if (!p_iso) 62 | return; 63 | 64 | p_entlist = iso9660_ifs_readdir (p_iso, "/video_ts/"); 65 | 66 | if (p_entlist) { 67 | _CDIO_LIST_FOREACH (p_entnode, p_entlist) 68 | { 69 | unsigned long long start; 70 | unsigned long long blocks; 71 | 72 | char filename[4096]; 73 | int len; 74 | 75 | iso9660_stat_t *p_statbuf = 76 | (iso9660_stat_t *) _cdio_list_node_data (p_entnode); 77 | iso9660_name_translate(p_statbuf->filename, filename); 78 | len = strlen(filename); 79 | 80 | if (!(2 == p_statbuf->type) ) { 81 | if (! strcmp(filename + (len-3), "vob")) { 82 | start = p_statbuf->lsn; 83 | blocks = CEILING(p_statbuf->size, DVDCSS_BLOCK_SIZE); 84 | 85 | start_map[start] = strdup(filename); 86 | 87 | if (blocks == 0) { 88 | //file length of 0 would result in a blocks of 0, and don't want 89 | //to subtract one from it. 90 | end_blocks[start] = start; 91 | } else { 92 | //-1 as start block is included in count of blocks 93 | end_blocks[start] = start - 1 + blocks; 94 | } 95 | printf("%s: %llu->%llu (%llu blocks)\n", filename, start, end_blocks[start], blocks); 96 | if (blocks) { 97 | if (find(start_blocks.begin(), start_blocks.end(), start) == start_blocks.end()) { 98 | start_blocks.push_back(start); 99 | } 100 | } 101 | } 102 | } 103 | } 104 | 105 | _cdio_list_free (p_entlist, true); 106 | } 107 | } 108 | 109 | int main(int argc, char *argv[]) 110 | { 111 | dvdcss_t input; 112 | int fd; 113 | int flags = O_RDWR; 114 | 115 | off64_t disc_len; 116 | int total_blocks; 117 | unsigned long long pos = 0; 118 | 119 | iso9660_t * p_iso; 120 | 121 | char * buffer; 122 | unsigned long long preamble; 123 | 124 | unsigned long long count = 0; 125 | 126 | if (argc == 3 && !strcmp(argv[2], "-test")) { 127 | flags = O_RDONLY; 128 | } 129 | 130 | if (!(buffer = (char *) malloc(MAX*DVDCSS_BLOCK_SIZE))) { 131 | printf("failed to allocate space for buffer\n"); 132 | return 0; 133 | } 134 | 135 | if (argc < 2) { 136 | printf("usage:\n\t %s \n", argv[0]); 137 | return 1; 138 | } 139 | 140 | if ((fd = open(argv[1], flags)) < 0) { 141 | printf("failed to open input/output file\n"); 142 | return 1; 143 | } 144 | 145 | /* figure out how big the ISO image is */ 146 | if ((disc_len = lseek64(fd, 0, SEEK_END)) < 0) { 147 | perror("lseek64 failed"); 148 | return 1; 149 | } 150 | 151 | total_blocks = disc_len / DVDCSS_BLOCK_SIZE; 152 | if (disc_len != (long long) total_blocks * DVDCSS_BLOCK_SIZE) { 153 | printf("partial block?????\n"); 154 | return 1; 155 | } 156 | printf("total_blocks = %d\n", total_blocks); 157 | start_blocks.push_back(total_blocks); 158 | 159 | /* find locations where have to rekey CSS */ 160 | if ((p_iso = iso9660_open(argv[1])) == NULL) { 161 | printf("couldn't open %s as UDF\n", argv[1]); 162 | return 1; 163 | } 164 | 165 | find_start_blocks(p_iso); 166 | 167 | sort(start_blocks.begin(), start_blocks.end()); 168 | 169 | for(vector::iterator it = start_blocks.begin(); it != start_blocks.end(); it++) { 170 | printf("end pos = %llu\n", *it); 171 | } 172 | 173 | for(map::iterator p = start_map.begin(); p != start_map.end(); p++) { 174 | printf("%s : %llu\n", p->second, p->first); 175 | } 176 | 177 | if (argc == 3 && !strcmp(argv[2], "-test")) { 178 | return 0; 179 | } 180 | 181 | /* prep CSS */ 182 | if (!(input = dvdcss_open(argv[1]))) { 183 | printf("dvdcss_open failed\n"); 184 | return 1; 185 | } 186 | 187 | /* if not scrambled skip! */ 188 | /* this doesn't do anything on iso input */ 189 | if (! dvdcss_is_scrambled(input)) { 190 | printf("dvd isn't scrambled\n"); 191 | return 0; 192 | } 193 | 194 | preamble = start_blocks[0]; 195 | start_blocks.erase(start_blocks.begin()); 196 | 197 | lseek64(fd, preamble*DVDCSS_BLOCK_SIZE, SEEK_SET); 198 | 199 | pos = preamble; 200 | 201 | while (! start_blocks.empty()) { 202 | int len = MAX; 203 | int blocks_read; 204 | 205 | int cur = pos; 206 | unsigned long long end = start_blocks[0]; 207 | 208 | fflush(NULL); 209 | 210 | start_blocks.erase(start_blocks.begin()); 211 | 212 | //printf("syncing at position = %llu, next sync point at %u\n", pos, end); 213 | 214 | if ( dvdcss_seek(input, pos, DVDCSS_SEEK_KEY) < 0) { 215 | //Q. Can it ever fail to get key here, but have the key 216 | //elsewhere? perhaps have some accounting if this fails, 217 | //know no point in trying to dvdcss_read() till next 218 | //DVDCSS_SEEK_KEY? 219 | printf("failed to seek to %llu: %s\n", pos, dvdcss_error(input)); 220 | } 221 | 222 | while (pos < end) { 223 | int read_size; 224 | char * tmp_buffer; 225 | int reseek; 226 | 227 | fflush(NULL); 228 | 229 | if (pos + len > end) { 230 | len = end - pos; 231 | } 232 | 233 | read_size = len * DVDCSS_BLOCK_SIZE; 234 | 235 | if ((blocks_read = read(fd, buffer, read_size)) != read_size) { 236 | printf("short read, not handled yet\n"); 237 | return 1; 238 | } 239 | 240 | tmp_buffer = buffer; 241 | reseek = 0; 242 | 243 | for(int index = 0; index < len; index++) { 244 | char block[2048]; 245 | 246 | if( ((uint8_t*)tmp_buffer)[0x14] & 0x30 ) { 247 | int skip=0; 248 | if (pos + index > end_blocks[cur]) { 249 | printf("should skipping decode of supposed encrypted block (%llu) as not within VOB\n", pos+index); 250 | memcpy(block, tmp_buffer, 2048); 251 | skip=1; 252 | } 253 | count++; 254 | if (dvdcss_seek(input, pos+index, DVDCSS_NOFLAGS) < 0) { 255 | printf("failed to seek to %llu (index %d): %s\n", pos+index, index, dvdcss_error(input)); 256 | return 1; 257 | } 258 | 259 | if (dvdcss_read(input, tmp_buffer, 1, DVDCSS_READ_DECRYPT) != 1) { 260 | printf("dvdcss_read failed\n"); 261 | return 1; 262 | } 263 | if (skip) { 264 | printf("testing block we are skipping anyways\n"); 265 | if( ((uint8_t*)tmp_buffer)[0x14] & 0x30 ) { 266 | printf("dvdcss \"decoded\" block still has bit set\n"); 267 | if (!memcmp(tmp_buffer, block, 2048)) { 268 | printf("dvdcss \"decoded\" block didn't change!\n"); 269 | } else { 270 | printf("dvdcss \"decoded\" block changed!\n"); 271 | } 272 | } else { 273 | printf("dvdcss \"decoded\" block got bit removed!\n"); 274 | } 275 | } else { 276 | lseek64(fd, (pos+index) * DVDCSS_BLOCK_SIZE, SEEK_SET); 277 | if (my_write(fd, tmp_buffer, DVDCSS_BLOCK_SIZE) < 0) { 278 | return 1; 279 | } 280 | reseek = 1; 281 | } 282 | } 283 | tmp_buffer = tmp_buffer + DVDCSS_BLOCK_SIZE; 284 | } 285 | 286 | pos += len; 287 | if (reseek) { 288 | lseek64(fd, pos * DVDCSS_BLOCK_SIZE, SEEK_SET); 289 | } 290 | } 291 | } 292 | printf("descrambled %llu blocks\n", count); 293 | printf("\n"); 294 | 295 | return 0; 296 | } 297 | -------------------------------------------------------------------------------- /history/5.cpp: -------------------------------------------------------------------------------- 1 | #define _FILE_OFFSET_BITS 64 2 | #define _LARGEFILE64_SOURCE 1 3 | #define _LARGEFILE_SOURCE 1 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | using namespace std; 21 | 22 | #define MAX 2000 23 | #define CEILING(x, y) ((x+(y-1))/y) //ripped from libudf 24 | 25 | vector start_blocks; 26 | map end_blocks; 27 | map start_map; 28 | 29 | ssize_t my_write(int fd, const void * buf, size_t count) 30 | { 31 | int ret; 32 | size_t my_count = count; 33 | char * my_buf = (char *) buf; 34 | 35 | while (my_count) { 36 | if (my_count != count) { 37 | printf("looped in my_write, last write = %d\n", ret); 38 | } 39 | if ((ret = write(fd, my_buf, my_count)) == -1) { 40 | if (errno != EINTR) { 41 | perror("write failed!"); 42 | goto out; 43 | } 44 | } else { 45 | my_count -= ret; 46 | my_buf += ret; 47 | } 48 | } 49 | 50 | ret = count; 51 | out: 52 | return ret; 53 | } 54 | 55 | static void add_block(const udf_dirent_t *p_udf_dirent) 56 | { 57 | char *psz_fname=(char *) udf_get_filename(p_udf_dirent); 58 | char *name = strdup(psz_fname); 59 | int len = strlen(psz_fname); 60 | unsigned long long file_length; 61 | unsigned long long start; 62 | unsigned long long blocks; 63 | 64 | start = udf_get_start_block(p_udf_dirent); 65 | blocks = CEILING(udf_get_file_length(p_udf_dirent), DVDCSS_BLOCK_SIZE); 66 | 67 | start_map[start] = name; 68 | 69 | if (blocks == 0) { 70 | //file length of 0 would result in a blocks of 0, and don't want 71 | //to subtract one from it. 72 | end_blocks[start] = start; 73 | } else { 74 | //-1 as start block is included in count of blocks 75 | end_blocks[start] = start - 1 + blocks; 76 | } 77 | printf("%s: %llu->%llu (%llu blocks)\n", psz_fname, start, end_blocks[start], blocks); 78 | 79 | for(int i=0; i < len; i++) { 80 | psz_fname[i] = tolower(psz_fname[i]); 81 | } 82 | 83 | if (! strcmp(psz_fname + (len-3), "vob")) { 84 | if (blocks) { 85 | if (find(start_blocks.begin(), start_blocks.end(), start) == start_blocks.end()) { 86 | start_blocks.push_back(start); 87 | } 88 | } 89 | } 90 | } 91 | 92 | void find_start_blocks(udf_t *p_udf, udf_dirent_t *p_udf_dirent) 93 | { 94 | if (!p_udf_dirent) 95 | return; 96 | 97 | while(udf_readdir(p_udf_dirent)) { 98 | if (udf_is_dir(p_udf_dirent)) { 99 | udf_dirent_t *p_udf_dirent2 = udf_opendir(p_udf_dirent); 100 | if (p_udf_dirent) { 101 | find_start_blocks(p_udf, p_udf_dirent2); 102 | } 103 | } else { 104 | add_block(p_udf_dirent); 105 | } 106 | } 107 | } 108 | 109 | int main(int argc, char *argv[]) 110 | { 111 | dvdcss_t input; 112 | int fd; 113 | int flags = O_RDWR; 114 | 115 | off64_t disc_len; 116 | int total_blocks; 117 | unsigned long long pos = 0; 118 | 119 | udf_t *p_udf; 120 | udf_dirent_t *p_udf_root; 121 | 122 | char * buffer; 123 | unsigned long long preamble; 124 | 125 | unsigned long long count = 0; 126 | 127 | if (argc == 3 && !strcmp(argv[2], "-test")) { 128 | flags = O_RDONLY; 129 | } 130 | 131 | if (!(buffer = (char *) malloc(MAX*DVDCSS_BLOCK_SIZE))) { 132 | printf("failed to allocate space for buffer\n"); 133 | return 0; 134 | } 135 | 136 | if (argc < 2) { 137 | printf("usage:\n\t %s \n", argv[0]); 138 | return 1; 139 | } 140 | 141 | if ((fd = open(argv[1], flags)) < 0) { 142 | printf("failed to open input/output file\n"); 143 | return 1; 144 | } 145 | 146 | /* figure out how big the ISO image is */ 147 | if ((disc_len = lseek64(fd, 0, SEEK_END)) < 0) { 148 | perror("lseek64 failed"); 149 | return 1; 150 | } 151 | 152 | total_blocks = disc_len / DVDCSS_BLOCK_SIZE; 153 | if (disc_len != (long long) total_blocks * DVDCSS_BLOCK_SIZE) { 154 | printf("partial block?????\n"); 155 | return 1; 156 | } 157 | printf("total_blocks = %d\n", total_blocks); 158 | start_blocks.push_back(total_blocks); 159 | 160 | /* find locations where have to rekey CSS */ 161 | if ((p_udf = udf_open(argv[1])) == NULL) { 162 | fprintf(stderr, "couldn't open %s as UDF\n", argv[1]); 163 | return 1; 164 | } 165 | 166 | if (!(p_udf_root = udf_get_root(p_udf, true, 0))) { 167 | fprintf(stderr, "couldn't find / in %s\n", argv[1]); 168 | return 1; 169 | } 170 | 171 | find_start_blocks(p_udf, p_udf_root); 172 | 173 | sort(start_blocks.begin(), start_blocks.end()); 174 | 175 | for(vector::iterator it = start_blocks.begin(); it != start_blocks.end(); it++) { 176 | printf("end pos = %llu\n", *it); 177 | } 178 | 179 | for(map::iterator p = start_map.begin(); p != start_map.end(); p++) { 180 | printf("%s : %llu\n", p->second, p->first); 181 | } 182 | 183 | if (argc == 3 && !strcmp(argv[2], "-test")) { 184 | return 0; 185 | } 186 | 187 | /* prep CSS */ 188 | if (!(input = dvdcss_open(argv[1]))) { 189 | fprintf(stderr, "dvdcss_open failed\n"); 190 | return 1; 191 | } 192 | 193 | /* if not scrambled skip! */ 194 | /* this doesn't do anything on iso input */ 195 | if (! dvdcss_is_scrambled(input)) { 196 | printf("dvd isn't scrambled\n"); 197 | return 0; 198 | } 199 | 200 | preamble = start_blocks[0]; 201 | start_blocks.erase(start_blocks.begin()); 202 | 203 | lseek64(fd, preamble*DVDCSS_BLOCK_SIZE, SEEK_SET); 204 | 205 | pos = preamble; 206 | 207 | while (! start_blocks.empty()) { 208 | int len = MAX; 209 | int blocks_read; 210 | 211 | int cur = pos; 212 | int end = start_blocks[0]; 213 | 214 | int seeked = DVDCSS_NOFLAGS; 215 | 216 | start_blocks.erase(start_blocks.begin()); 217 | 218 | //printf("syncing at position = %llu, next sync point at %u\n", pos, end); 219 | 220 | if ( dvdcss_seek(input, pos, DVDCSS_SEEK_KEY) < 0) { 221 | fprintf(stderr, "failed to seek to %llu: %s\n", pos, dvdcss_error(input)); 222 | seeked = DVDCSS_SEEK_KEY; 223 | } 224 | 225 | while (pos < end) { 226 | int read_size; 227 | char * tmp_buffer; 228 | int reseek; 229 | 230 | if (pos + len > end) { 231 | len = end - pos; 232 | } 233 | 234 | read_size = len * DVDCSS_BLOCK_SIZE; 235 | 236 | if ((blocks_read = read(fd, buffer, read_size)) != read_size) { 237 | printf("short read, not handled yet\n"); 238 | return 1; 239 | } 240 | 241 | tmp_buffer = buffer; 242 | reseek = 0; 243 | 244 | for(int index = 0; index < len; index++) { 245 | char block[2048]; 246 | 247 | if( ((uint8_t*)tmp_buffer)[0x14] & 0x30 ) { 248 | int skip=0; 249 | if (pos + index > end_blocks[cur]) { 250 | printf("should skipping decode of supposed encrypted block (%llu) as not within VOB\n", pos+index); 251 | bcopy(tmp_buffer, block, 2048); 252 | skip=1; 253 | } 254 | count++; 255 | if (dvdcss_seek(input, pos+index, seeked) < 0) { 256 | fprintf(stderr, "failed to seek to %llu (index %d): %s\n", pos+index, index, dvdcss_error(input)); 257 | return 1; 258 | } 259 | seeked = DVDCSS_NOFLAGS; 260 | 261 | if (dvdcss_read(input, tmp_buffer, 1, DVDCSS_READ_DECRYPT) != 1) { 262 | fprintf(stderr, "dvdcss_read failed\n"); 263 | return 1; 264 | } 265 | if (skip) { 266 | printf("testing block we are skipping anyways\n"); 267 | if( ((uint8_t*)tmp_buffer)[0x14] & 0x30 ) { 268 | printf("dvdcss \"decoded\" block still has bit set\n"); 269 | if (!memcmp(tmp_buffer, block, 2048)) { 270 | printf("dvdcss \"decoded\" block didn't change!\n"); 271 | } else { 272 | printf("dvdcss \"decoded\" block changed!\n"); 273 | } 274 | } else { 275 | printf("dvdcss \"decoded\" block got bit removed!\n"); 276 | } 277 | } else { 278 | lseek64(fd, (pos+index) * DVDCSS_BLOCK_SIZE, SEEK_SET); 279 | if (my_write(fd, tmp_buffer, DVDCSS_BLOCK_SIZE) < 0) { 280 | return 1; 281 | } 282 | reseek = 1; 283 | } 284 | } 285 | tmp_buffer = tmp_buffer + DVDCSS_BLOCK_SIZE; 286 | } 287 | 288 | pos += len; 289 | if (reseek) { 290 | lseek64(fd, pos * DVDCSS_BLOCK_SIZE, SEEK_SET); 291 | } 292 | } 293 | } 294 | printf("descrambled %llu blocks\n", count); 295 | printf("\n"); 296 | 297 | return 0; 298 | } 299 | --------------------------------------------------------------------------------