Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion. Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules. |
|
24th August 2008, 14:25 | #1 | Link |
Registered User
Join Date: Jun 2007
Posts: 95
|
Finally handling BD+ (?)
Now that MKBv7 is public I think it's time to concentrate on BD+. I can't imagine that SlySoft is the only one to manage that protection. So how do they do it? Magic? I don't think so! And obviously they didn't reverse engineer PowerDVD - this was the third time that AnyDVD handles BD+ but PowerDVD can't. PowerDVD users had to wait for an update. So, did they kill a player? Could be easier. Did anyone ever tried something like this? What's the current status of BD+?
Let's wind up and find a strategy. How can hardware players help? Has anyone any information about BD+ (beside that marketing crap from Macrovision)? Only productive posts welcome. |
24th August 2008, 15:15 | #2 | Link |
Guest
Posts: n/a
|
Could be an implementation problem in powerdvd. For example you could accidentally do if (some_array[123] == 0x01) {...} and some_array is an array of integers (32 bit). You were supposed to compare one BYTE of the array and not 4. As long as there are enough zeros following the 01 you will never notice the bug. For some discs that is not true so they fail to playback because of that bug. Normally you will notice such mistakes when you reverse engineer the code.
Is there a list of BD+ discs so i could choose which one to buy? Edit: here are some: 28 Days Later 28 Weeks Later August Rush Cast Away Dan in Real Life Die Hard 1-4 Dogma Fantastic 4 ROSS From Hell (Region A) Gattaca Hitman I Robot Independence Day Man on Fire Master and Commander Mr & Mrs Smith Mr Brooks No Country For Old Men Rescue Dawn Robocop Ronin Sleuth Sunshine The Day After Tomorrow The Simpsons Movie and almost all recent releases: http://bluray.highdefdigest.com/rele...istorical.html Last edited by Oopho2ei; 24th August 2008 at 15:36. |
4th September 2008, 14:50 | #3 | Link | |
Registered User
Join Date: Mar 2008
Posts: 98
|
In an older post you had
Quote:
August Rush (Warner) Dan in Real Life (Walt Disney) Dogma (Sony) Gattaca (Sony) No Country for Old Men (Walt Disney) Sleuth (2007) (Sony) are BD+ titles. They are just titles released on March 11, 2008 together with Hitman, Independence Day and I Robot from Fox. The only titles that have BD+ so far are the ones from Fox and MGM (but that's still Fox contribution). |
|
24th August 2008, 17:04 | #4 | Link |
Registered User
Join Date: Jun 2007
Posts: 95
|
I doubt that PowerDVD can implement their own BD+ code - they surely get a library from Macrovision. Closed source. Everything else would be extremely stupid. So the bug is in Macrovision's library. That would encourage my opinion that SlySoft has something in the loop with hardware players.
Last edited by gioowe; 24th August 2008 at 17:06. |
24th August 2008, 17:19 | #5 | Link | |
SlySoft Team Member
Join Date: May 2007
Posts: 173
|
Quote:
__________________
SlySoft Inc. |
|
24th August 2008, 18:19 | #7 | Link |
Guest
Posts: n/a
|
I am guessing he means that because bd+ enforces a certain memory footprint (e.g. keys, video etc have to be at a certain fix virtual memory address) he can use a memory dump of the virtual machine interpreter and include it in anydvd as precompiled code module. He would only have to make sure the remaining data vm opcode/keys/video content is at the correct address.
|
24th August 2008, 19:44 | #8 | Link | |
SlySoft Team Member
Join Date: May 2007
Posts: 173
|
Quote:
Actually you'd have to know how BD+ really works, to know what I meant (and even then you probably wouldn't ). But if I start unraveling that, I'd be finding myself looking for a new job by next week So, I'll better shut up from this point on - should have done that in the first place, sorry...
__________________
SlySoft Inc. |
|
24th August 2008, 19:49 | #9 | Link | |
Registered User
Join Date: Jun 2007
Posts: 95
|
Quote:
|
|
26th August 2008, 06:37 | #10 | Link |
Registered User
Join Date: Sep 2004
Location: Near LA, California, USA
Posts: 1,545
|
Sounds like what I had to go through with my GF.
__________________
Pirate: Now how would you like to die? Would you like to have your head chopped off or be burned at the stake? Curly: Burned at the stake! Moe: Why? Curly: A hot steak is always better than a cold chop. |
25th September 2008, 17:27 | #11 | Link | |
I swallow bugs!
Join Date: Jan 2007
Location: Whitehouse corner Office
Posts: 49
|
Quote:
Dam good work. Slysoft, Is still the best investment out there! |
|
25th September 2008, 17:54 | #12 | Link | |
Guest
Posts: n/a
|
Quote:
Btw it's not only me and schluppo. There are other people hiding behind my back which have so far helped me a lot. Big |
|
24th August 2008, 17:23 | #13 | Link | |
Guest
Posts: n/a
|
Quote:
|
|
24th August 2008, 18:07 | #14 | Link | |
Registered User
Join Date: Jun 2007
Posts: 95
|
Quote:
Anyway, if AnyDVD can play all BD+ and PowerDVD requires an update - that's something very, very interesting. |
|
27th August 2008, 23:13 | #16 | Link |
Guest
Posts: n/a
|
I have looked at section 2 of 000001.svm. It is decrypted with some sort of stream cipher. I have uploaded the first 64 kb of the decrypted section payload (skipping the 0x17 header bytes): http://uploaded.to/?id=59db0f
Note that the byte order for every dword has be reversed before application (xor) of the bitstream from the stream cipher (big endian <--> little endian conversion). So Code:
0000:0000 c4 4e e6 65 00 01 00 00 02 00 00 00 Code:
0000:0000 65 e6 4e c4 00 00 01 00 00 00 00 02 Last edited by Oopho2ei; 27th August 2008 at 23:16. |
29th August 2008, 20:46 | #17 | Link |
Guest
Posts: n/a
|
The VM is at least involved (if not doing it all alone) in the decryption of those sections.
An typical instruction I (32 bit) is decoded like that: Code:
Instruction I: C R[X], R[Y], R[Z] C = I >> 0x1A X = ((I >> 0x13) & 0x7C) >> 2 Y = ((I >> 0x0E) & 0x7C) >> 2 Z = ((I >> 0x09) & 0x7C) >> 2 The machine: - 32 registers each 32 bit long - probably big endian - 4MB address space (first 128 bytes are register?) instruction/command decoding: Code:
cmd00: NOP cmd01: ADD R[X],R[Y],R[Z] -> R[X] = R[Y] + R[Z] cmd02: SUB R[X],R[Y],R[Z] -> R[X] = R[Y] - R[Z] cmd03: MUL R[X],R[Y],R[Z] -> R[X] = R[Y] * R[Z] cmd04: IDIV R[X],R[Y],R[Z] -> R[X] = unsigned(R[Y]) / R[Z] cmd05: DIV R[X],R[Y],R[Z] -> R[X] = signed(R[Y]) / R[Z] cmd06: SHL R[X],R[Y],R[Z] -> R[X] = R[Y] << (R[Z] & 0x1F) cmd07: SHR R[X],R[Y],R[Z] -> R[X] = R[Y] >> (R[Z] & 0x1F) cmd08: SAR R[X],R[Y],R[Z] -> R[X] = signed(R[Y]) >> (R[Z] & 0x1F) cmd09: AND R[X],R[Y],R[Z] -> R[X] = R[Y] & R[Z] cmd0A: OR R[X],R[Y],R[Z] -> R[X] = R[Y] | R[Z] cmd0B: XOR R[X],R[Y],R[Z] -> R[X] = R[Y] ^ R[Z] cmd0C: EQU R[X],R[Y],R[Z] -> if (R[Y] == R[Z]) R[X] = 1 else R[X] = 0 cmd0D: NEQU R[X],R[Y],R[Z] -> if (R[Y] != R[Z]) R[X] = 1 else R[X] = 0 cmd0E: LESS R[X],R[Y],R[Z] -> if (signed(R[Y]) < signed(R[Z])) R[X] = 1 else R[X] = 0 cmd0F: BLW R[X],R[Y],R[Z] -> if (unsigned(R[Y]) < unsigned(R[Z])) R[X] = 1 else R[X] = 0 cmd10: GRE R[X],R[Y],R[Z] -> if (signed(R[Y]) > signed(R[Z])) R[X] = 1 else R[X] = 0 cmd11: ABV R[X],R[Y],R[Z] -> if (unsigned(R[Y]) > unsigned(R[Z])) R[X] = 1 else R[X] = 0 cmd12: LEQ R[X],R[Y],R[Z] -> if (signed(R[Y]) <= signed(R[Z])) R[X] = 1 else R[X] = 0 cmd13: BEQ R[X],R[Y],R[Z] -> if (unsigned(R[Y]) <= unsigned(R[Z])) R[X] = 1 else R[X] = 0 cmd14: GEQ R[X],R[Y],R[Z] -> if (signed(R[Y]) >= signed(R[Z])) R[X] = 1 else R[X] = 0 cmd15: AEQ R[X],R[Y],R[Z] -> if (unsigned(R[Y]) >= unsigned(R[Z])) R[X] = 1 else R[X] = 0 cmd16: JMP R[Y] -> PC = R[Y] cmd17: CALL R[Y] -> R[0x1F] = PC; PC = R[Y] cmd18: ADDE R[X],R[Y],C -> C = sign_extend(I & 0xFFFF); R[X] := R[Y] + C cmd19: ADD R[X],R[Y],C -> C = I & 0xFFFF; R[X] := R[Y] + C cmd1A: SUBE R[X],R[Y],C -> C = sign_extend(I & 0xFFFF); R[X] := R[Y] - C cmd1B: SUB R[X],R[Y],C -> C = I & 0xFFFF; R[X] := R[Y] - C cmd1C: SHL R[X],R[Y],C -> C = I & 0x1F; R[X] = unsigned(R[Y]) << C cmd1D: SHR R[X],R[Y],C -> C = I & 0x1F; R[X] = unsigned(R[Y]) >> C cmd1E: SAR R[X],R[Y],C -> C = I & 0x1F; R[X] = signed(R[Y]) >> C cmd1F: AND R[X],R[Y],C -> C = I & 0xFFFF; R[X] = R[Y] & C cmd20: OR R[X],R[Y],C -> C = I & 0xFFFF; R[X] := R[Y] | C cmd21: XOR R[X],R[Y],C -> C = I & 0xFFFF; R[X] := R[Y] ^ C cmd22: EQU R[X],R[Y],C -> C = sign_extend(I & 0xFFFF); if (R[Y] == C) R[X] = 1 else R[X] = 0 cmd23: NEQU R[X],R[Y],C -> C = sign_extend(I & 0xFFFF); if (R[Y] != C) R[X] = 1 else R[X] = 0 cmd24: GRE R[X],R[Y],C -> C = sign_extend(I & 0xFFFF); if (signed(C) > signed(R[Y])) R[X] = 1 else R[X] = 0 cmd25: ABV R[X],R[Y],C -> C = I & 0xFFFF; if (unsigned(C) > unsigned(R[Y])) R[X] = 1 else R[X] = 0 cmd26: LESS R[X],R[Y],C -> C = sign_extend(I & 0xFFFF); if (signed(C) < signed(R[Y])) R[X] = 1 else R[X] = 0 cmd27: BLW R[X],R[Y],C -> C = I & 0xFFFF; if (unsigned(t0) < unsigned(R[Y])) R[X] = 1 else R[X] = 0 cmd28: GEQ R[X],R[Y],C -> C = sign_extend(I & 0xFFFF); if (signed(C) >= signed(R[Y])) R[X] = 1 else R[X] = 0 cmd29: AEQ R[X],R[Y],C -> C = I & 0xFFFF; if (unsigned(C) >= unsigned(R[Y])) R[X] = 1 else R[X] = 0 cmd2A: LEQ R[X],R[Y],C -> C = sign_extend(I & 0xFFFF); if (signed(C) <= signed(R[Y])) R[X] = 1 else R[X] = 0 cmd2B: BEQ R[X],R[Y],C -> C = I & 0xFFFF; if (unsigned(C) <= unsigned(R[Y])) R[X] = 1 else R[X] = 0 cmd2C: JMP C -> C = PC + signed(unsigned(I) << 6) >> 6; PC = C cmd2D: CALL C -> C = PC + signed(unsigned(I) << 6) >> 6; R[0x1F] = PC; PC = C cmd2E: JZ R[Y], C -> C = PC + sign_extend(I & 0xFFFF); if (R[Y] == 0) PC = C cmd2F: JNZ R[Y], C -> C = PC + sign_extend(I & 0xFFFF); if (R[Y] != 0) PC = C cmd30: STR R[X] -> R[X] = I << 0x10 cmd31: LBSE R[X],R[Y] -> R[X] = sign_extended(mem[((R[Y] + sign_extended(I & 0xFFFF)) & 0x3FFFFF) ^ 0x03] & 0xFF) cmd32: LB R[X],R[Y] -> R[X] = mem[((R[Y] + sign_extended(I & 0xFFFF)) & 0x3FFFFF) ^ 0x03] & 0xFF cmd33: LWSE R[X],R[Y] -> R[X] = sign_extended(mem[((R[Y] + sign_extended(I & 0xFFFF)) & 0x3FFFFE) ^ 0x02] & 0xFFFF) cmd34: LW R[X],R[Y] -> R[X] = mem[((R[Y] + sign_extended(I & 0xFFFF)) & 0x3FFFFE) ^ 0x02] & 0xFFFF) cmd35: LDW R[X],R[Y] -> R[X] = mem[(R[Y] + sign_extended(I & 0xFFFF)) & 0x3FFFFC] cmd36: MOVB R[X],[R[Y]+C] -> C = sign_extended(I & 0xFFFF); mem[((R[Y]+C) & 0x3FFFFF) ^ 0x03] = (unsigned char) R[X] cmd37: MOVW R[X],[R[Y]+C] -> C = sign_extended(I & 0xFFFF); mem[((R[Y]+C) & 0x3FFFFE) ^ 0x02] = (unsigned int16) R[X] cmd38: MOVDW R[X],[R[Y]+C] -> C = sign_extended(I & 0xFFFF); mem[(R[Y]+C) & 0x3FFFFC] = (unsigned int32) R[X] cmd39: TRAP C -> trap[immediate] cmd3A: SWDC R[Y] -> watch_cat_counter = R[Y]; cmd3B-cmd3F: NOP PC = program counter C = a constant (part of instruction word) I = the instruction word (uint32) watchcat_counter = some counter which is set by cmd3A and decremented by every instruction by a command specific value. As long as the counter is > 0 program execution continues. mem[] = the virtual machine memory R[X] = register number X (uint32 R[32]) sign_extend(V) = MSB(V) ? 0xFFFF0000 | V : V; MSB() = get the most significant bit signed() = make it a signed integer (int32) unsigned() = make it an unsigned integer (uint32) Note that by the time the command handler is called the program counter (pc) has already been incremented by 4 (pointing at the next instruction). It would be great if someone could start implementing the command interpreter (open source please). Please feel free to ask for more details. I will post the purpose of the remaining commands soon. Last edited by Oopho2ei; 3rd September 2008 at 17:38. Reason: added some commands; fixed some mistakes; |
30th August 2008, 11:59 | #18 | Link |
Guest
Posts: n/a
|
I have added some more commands. It is becoming increasingly difficult to find good names eg. BEQ (for 'below or equal' inintel terms) is usually used for 'branch if equal'. If you can think of better names/abbreviations you are also welcome to post your ideas.
|
31st August 2008, 02:39 | #19 | Link |
Guest
Posts: n/a
|
I can see that things are getting more complicated and my C-like expressions become quite ugly. A lot of people are following this thread but no one dares to say something. So i decided to give a very small example of how this works.
You have probably seen the BDSVM folder on your blue rays with BD+ protection. Now open the 00000.svm in a hex editor (like khexedit) and scroll down to address around 0x1000. You are looking now at some of the instructions which are executed by the virtual machine at the very beginning. Code:
... 0000:1000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000:1010 00 00 00 00 00 00 00 00 b0 00 00 40 e0 3d 00 08 0000:1020 e3 fd 00 04 d4 20 00 00 e0 1d 00 00 d7 e0 11 54 0000:1030 e3 e0 11 50 b4 01 9b 0c d7 e0 11 58 e3 e0 11 50 0000:1040 e0 20 00 04 d7 fd 00 04 d4 3d 00 08 67 bd 00 1c 0000:1050 e4 00 00 10 b3 ff ff fc 00 00 00 00 bc 00 ff fc 0000:1060 bc 01 ff fc bc 02 ff fc bc 03 ff fc bc 04 ff fc 0000:1070 bc 05 ff fc bc 06 ff fc bc 07 ff fc bc 08 ff fc 0000:1080 bc 09 ff fc bc 0a ff fc bc 0b ff fc bc 0c ff fc 0000:1090 bc 0d ff fc bc 0e ff fc bc 0f ff fc bc 10 ff fc 0000:10a0 bc 11 ff fc bc 12 ff fc bc 13 ff fc bc 14 ff fc 0000:10b0 bc 15 ff fc bc 16 ff fc bc 17 ff fc bc 18 ff fc 0000:10c0 bc 19 ff fc bc 1a ff fc bc 1b ff fc bc 1c ff fc 0000:10d0 bc 1d ff fc bc 1e ff fc bc 1f ff fc c3 a0 00 00 0000:10e0 67 bd 11 5c c3 80 00 00 67 9c 10 00 d7 bd 00 00 ... 1. Fetch: Execution starts with PC = 0x1000. Because we have a 0x18 byte long header this translates to the start address 0x1000+0x18=0x1018. If we look at the section from 00000.svm posted above we see our first instruction: "b0 00 00 40". 2. Decode: If we look at the highest 6 bits of the leftmost byte of this instruction. The binary represenation of 0xB0 = 0b10110000. The highest 6 bits are 0b101100 which is 0x2C. (Instead of converting it binary representation and back we could have simply divided by 4: 0xB0/4 = 0x2C.) Now if we lookup 0x2C in the table i posted above you will see that this is the encoding of the command "JMP C". 3. Execute: Now lets look at what this instruction does. The corresponding entry of the table says: "C = PC + signed(unsigned(I) << 6) >> 6; PC = C". So we first calculate a constant C = PC + signed(unsigned(I) << 6) >> 6. What the second part does is simply setting the highest 6 bits of our instruction I = 0xB0000040 to the value of the 7th highest bit. This is done here by first doing a logic shift left and then an arithmetic shift right. (The expressions "signed" and "unsigned" are used to distinguish between logic and arithmetic shift because C handles the shift operator differently of signed and unsigned values.) Now in our case the 7th highest bit is 0 so we can just overwrite the highest 6 bits with zeros. The result is C = PC + 0x40. Now when the command dispatcher runs it already increments the value of the program counter (pc) by 4 (4 bytes is the length of every instruction) so that it is pointing at the next instruction even before the command handler (in this case for "jmp c") is executed. So in this case our program counter is PC = 0x1000 + 4 = 0x1004. Now according to the description "PC = PC + signed(unsigned(I) << 6) >> 6" our new program counter is PC = 0x1004 + 0x40 = 0x1044. 4. Write back: PC = 0x1044 Now lets look at the next instruction. 1. Fetch: At 0x1044+0x18 we have "bc 00 ff fc" 2. Decode: 0xBC / 4 = 2F so we have a "JNZ R[X],C". Looking in the instruction table we find the description "C = PC + sign_extend(I & 0xFFFF); if (R[Y] != 0) PC = C". 3. We first calculate C. Therefor we overwrite the 16 highest bits with the value of the 17th highest bit (this is what this expression simply does). The 17th highest bit is 1 so we result is C = PC + 0xFFFFFFFC = 0x1044. Now we see that R[Y] is checked for being different from zero. According to the description Y = ((I >> 0x0E) & 0x7C) >> 2. This expression reads the 5 bits directly following the command number (highest 6 bits) from the instruction. In our case this is Y = 0 so we have to check register 0 (R[0]) for being zero. In this case it is really zero because the virtual machine has just been started and we haven't manipulated anything except the program counter so far. Consequently "PC = C" is not being executed and we can forget C and proceed with the next instruction. 4. Write back: nothing.... Execution proceeds at 0x1048 ... You will find more details scattered across the postings of this thread. Feel free to ask if you have questions. Explaining things to other people really helps finding bugs. Last edited by Oopho2ei; 31st August 2008 at 11:40. |
|
|