View Full Version : Finally handling BD+ (?)
Pages :
1
2
3
[
4]
5
6
7
8
9
10
11
12
13
14
15
16
Oopho2ei
19th September 2008, 15:12
Upload complete (see posting #130). You should now have 3 independent traces (including the old/deprecated one).
ToDo:
- compare the two traces of "The Day After Tomorrow" to identify "random" data returned by the traps (like timestamps)
- compare one trace of "The Day After Tomorrow" with a trace of "I Robot" and look at the the result of the traps to identify disc/movie dependent data.
Good luck/have fun. I will continue to study Trap_AES as planned. :)
Edit: Trap_AES: the key with opOrKeyID=4 is a constant stored in the key section of the player. It's transformed and i need to reverse the transformation so you can use it with your unmodified AES implementations.
Edit: Trap_010 seems to update the Watchdog Timer. After the first call of Trap_010 in "The Day After Tomorrow" the timer is set to 0FA0h (or decimal: 4000) so program execution will break quickly afterwards. Very likely some changes are made to the guest system so don't panic if you run into problems after this trap. I will look into this soon.
Edit: After Trap_010 execution continues at *r28 (thanks to [anonymous])
Edit: I have compared two snapshots before and after the first Trap_020 call in "The Day After Tomorrow" and found no difference.
Edit: I made a snapshot before and after the first execution break (by the watchdog timer reaching 0) and found no differences. The watchdog timer was again set to 0FA0h (=4000) so this regular interruption is maybe to allow other player functions to be run on the processor of the player. But probably more likely this is a regular check for player events.
Oopho2ei
20th September 2008, 17:41
There seems to be a problem with the current post-trap snapshots after the first Trap_010 call. Please do not try to execute beyond Trap_010 and instead focus on the other traps which have been executed up to that point. I will notify you when this issue has been solved.
Edit: I've made new packages for irobot and dat which both contain an extra directory "post_break_snapshots" and an additional trace file "timer_trace.bin". Like with the post_trap_snapshots you have to implement a "break counter" which is incremented every time the watchdog timer (see timer_trace.bin) reaches zero (or becomes negative).
How to use this:
As usual you decrement the timer at the end of every instruction according to the table in posting #25. When this is done you check the value of the timer. Only if it is less or equal zero the program execution is interrupted and you load the snapshot post_break_???_[cnt].bin, increment the break counter [cnt] and then continue execution. As long as the timer is positive program execution continues normally and you don't have to worry about this. :)
Note: I now use %06d instead of %03d for the filenames.
The new packages will be available in a few hours.
Oopho2ei
21st September 2008, 10:57
The new packages are available now:
Package (v1.02) for "The Day After Tomorrow": http://uploaded.to/?id=g93e2g
Package (v1.02) for "I Robot": http://uploaded.to/?id=svpn7q
Oopho2ei
21st September 2008, 13:27
A quick note about the trap names: Some traps are mentioned in the pdf (http://securityevaluators.com/pdf/spdc_aacs_2005.pdf) which are not listed in the patent. For example TRAP_Finished (#010) and TRAP_DiscoveryRAM (possible #530). So maybe we can complete our list soon. :)
I keep on updating the list in posting #97: http://forum.doom9.org/showpost.php?p=1180641&postcount=97 Please use this as reference and do not make your own versions. If you see a mistake or maybe you want to add something please tell me. :)
schluppo
22nd September 2008, 14:55
Was busy the last few days, now I have time again...
Trap_Random (0x130) implemented, Trap_MediaReadFile (0x540) bug fixed. Trap_PrivateKey has different ordering of parameters than in the patent text:
UINT32 TRAP_PrivateKey(UINT32 controlWord, UINT8 *dst, UINT8 *src, UINT32 srcLen, UINT32 keyID);
vs
UINT32 TRAP_PrivateKey(UINT8 *dst, UINT8 *src, UINT32 srcLen, UINT32 controlWord, UINT32 keyID);
Next: slot traps.
I am still using the old snapshot-series, will get the new snapshots soon and start looking at the traps which appear there.
Will upload new edition of the debugger soon...
Edit: TRAP-SlotRead, TRAP-SlotWrite, TRAP-SlotAttach implemented (in a rather sloppy way - need to check how these are treated for in other BD-discs).
Oopho2ei
22nd September 2008, 17:31
UINT32 TRAP_PrivateKey(UINT32 controlWord, UINT8 *dst, UINT8 *src, UINT32 srcLen, UINT32 keyID);
Can you please also tell us your observations which make you believe Trap#120 really is "TRAP_PrivateKey" with that signature? I am not saying you are wrong or anything. It's just hard to tell if you are (almost) sure or just guessing. :)
Btw. Please use the version number when you refer to a particular snapshot package. Note that we we have now packages from two different blue ray discs.
schluppo
22nd September 2008, 18:13
I was using the old version of "Day after Tomorrow" with the 5000 snapshots in 5 big packages. Apart from the AES-Traps which are using player keys (especially TRAP_AES(..,..,..,..,0)) and apart from TRAP_Random which should produce random numbers, the first 1600 of those snapshots are identical to the memory after execution of the coded treatment of those traps. Anyway, I'm extracting v1.02 of both movies now and will look at them soon in order to improve the treatment of traps.
Further, trap 0x120 could have any other name, I have no observation telling me for sure, that it's "Trap_PrivateKey". I was just using that name since it's in the trap-list at this position.
Also, a thing about trap 0x410: I'm not sure wether this really is TRAP-SlotAttach, since that should have three parameters, according to the patent. Until now, I found just one call of trap 0x410:
trap 1002 at ic 6732573 is trap_410(0x1f3,0xc) // slot-attach(499,12)?
returns 0x80000001
Notice, that I think, that 0x800000001 is the 'error' return status number.
Later, the program tries to read from this slot 499 (just receiving 256 times 0x00 and returning 0x0 in R1) and afterwards tries to write to slot 499 (returning 0x0 in R1 indicating successfull execution of the write-process?).
Maybe BD+ is using a more simple variant of this trap without security code / hash.
Edit: I compared the behaviour of the traps in the old snapshot-pack (the one with the 5 big archives) and the new v1.02 (both packs are for the movie "Day After Tomorrow"). Here is a list of traps with different behaviour in the first 1600 trap-calls:
TRAP_DeviceDiscovery(1,3,4514,1eff84) - qID #3: ~5 bytes difference due to timestamp
TRAP_120(0, 0x5514, 0x2348, 0x10, 0) (TRAP_PrivateKey?) - all 40 bytes of the result are different
TRAP-SlotRead(0x1efb14,0) - 32 bytes different content in slot 0
The other trap-calls behave in exactly the same way as before (apart from TRAP_Random of course).
Edit2: For "I Robot", there's the following problematic traps:
TRAP_DeviceDiscovery(1,3): ~5 bytes difference due to timestamp and 16 bytes difference since the Volume-ID of this BD is different.
I will implement this soon (we need a text file (or so) input anyway, containing all the keys needed to emulate the traps).
The AES-Trap behaves badly - as expected (we still need a way to emulate AES-decryption using player-keys).
TRAP_120(0, 0x54F0, 0x2348, 0x10, 0): all 40 bytes of the result are different.
At IC 2123976, trap_0x550(0x7F868,0xF,0,0x13FFE00,0x3DFCC8,0x7F850) writes 20 bytes to 0x7F850 and returns 0x0 in R1. Don't know what this trap could be.
Another call of this: trap_0x550(0x81FBC,0xF,0,0,0x3DFC0C,0x3DFC10) writes 20 bytes to 0x3DFC10 and returns 0x0 in R1.
One more call writing 20 bytes to the last parameter and returning 0x0 in R1: trap_0x550(0x3D5E8,0x16,5,0x27123800,0x3DFC00,0x3DFC04)
TRAP-SlotRead(xx,0): 68 bytes different content in slot 0.
Edit 3:
For trap 0x120 (TRAP_PrivateKey?), I found the following: It's second parameter is a pointer <pDst> where the result is going to be put. It's third parameter is a pointer <pSrc> to the input of this trap. It's fourth parameter <source_len> is the length of this input (this input is 0xFF-terminated). Further, this trap seems to behave non-deterministic.
I would guess, it is indeed TRAP_PrivateKey, just because the parameters are so close to what they should be. Imagine we have controlWord=0 and keyID=0 (indicating the case where this trap produces a signature of it's input, using a private key), then a call of this trap looks similar to the specification of the trap in the patent text:
trap_120(0, <pDst>, <pSrc>, <source_len>, 0)
vs.
TRAP_PrivateKey(UINT8 *dst, UINT8 *src, UINT32 srcLen, UINT32 controlWord, UINT32 keyID);
Furthermore, the patent mentions, that the keyID is "normally" 0 for TRAP_PrivateKey, and in every call of trap_120 that I have seen so far, the first and last parameter were 0.
However, the patent also says, that for keyID=0, the result of TRAP_PrivateKey will be a "2048-bit RSA-Signature". I guess that means 256 bytes of result, but trap_120 just produces 40 bytes of result.
Oopho2ei
22nd September 2008, 23:33
The AES-Trap behaves badly - as expected (we still need a way to emulate AES-decryption using player-keys).
You can start to merge this into your code: http://uploaded.to/?id=w7qe3s
This sample program decrypts the given encrypted key using (a transformed version of) player key 4. The resulting decrypted key is transformed too so you need another obfuscated version of aes which i have not implemented yet. Together with this missing second half you will be able to use the player keys (to some extend) without really knowing them. These keys will probably be revoked quickly so it's not worth trying to remove all the different obfuscation layers just to find a "equivalent" key which can be used with a "normal" aes implementation.
Compile with:
gcc -o wbaes whitebox_aes_decrypt.c whitebox_aes_decrypt.h
Another thing: no trap is currently fully implemented because they all lack the initial parameter check. If a parameter combination is not allowed (eg. negative length, invalid address,...) the trap is supposed to refuse the execution (and maybe return 80000001h). But this isn't your fault because nobody has looked at this yet. :rolleyes:
schluppo
23rd September 2008, 02:56
Bug report for the basic debugger:
- Loading a big (>16mb) PC-trace file throws the following exception:
Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
at java.nio.HeapByteBuffer.<init>(Unknown Source)
at java.nio.ByteBuffer.allocate(Unknown Source)
This prevents people from using a PC-trace beyond ~8,000,000 instructions. Even splitting the big file into smaller 16mb-files and trying to reload traces after every 8,000,000 instructions does not help and throws the same exception.
- The VM hangs up after Trap#2044 for I Robot, v1.02 / Trap#2029 for DAT, v1.02 (I manually compared PC to the respective PC-traces and it is for both titles in sync up to these traps). This happens due to PC getting value FE83AAFD+ and thus causing array out-of-bounds access. IC is at 38,756,448 / 39,061,664 by this time. :confused: I guess the program takes at this point a jump that confuses the debugger's VM to jump somewhere else than it should.
On another note, I added a log of the first 2000+ trap-calls for both titles. It should be self-explanatory and also contains all the differences between the 'implemented' traps and the snapshots: http://uploaded.to/?id=f8kiq8
LoRd_MuldeR
23rd September 2008, 05:31
The nasty "Java heap space" OutOfMemoryError happens all the time, when your Java app needs a certain amount of memory.
But it can be solved by giving the JVM more memory for the heap space. You can do it like this:
java.exe -Xms128m -Xmx768m ...
Oopho2ei
23rd September 2008, 08:12
This prevents people from using a PC-trace beyond ~8,000,000 instructions. Even splitting the big file into smaller 16mb-files and trying to reload traces after every 8,000,000 instructions does not help and throws the same exception.
Try to read only 1MB from the traces into memory and store it in a ring buffer like:
uint32 ringsize = 0x40000;
unit32 ringbuffer[ringsize];
uint32 i = 0; // entry pointer in trace file
fopen(...)
// initialize the buffer
fread(ringbuffer, sizeof(uint32), ringsize, trace_file);
while (1)
{
printf("current pc is: %08d\n", ringbuffer[i % ringsize]);
i++; // switch to next pc entry
// usually we could write and read at the same time (two threads)
// i assume only one thread so i refresh/write the entire buffer at once
if( i % ringsize == 0) // check if are back to our starting point (walked the ring all the way around). if so refresh the buffer
{
// read the next MB into the buffer
fread(ringbuffer, sizeof(uint32), ringsize, trace_file);
}
}
I wrote this in only a few minutes (so there might be a mistake) but i hope it helps. :)
Oopho2ei
23rd September 2008, 20:51
This sample program decrypts the given encrypted key using (a transformed version of) player key 4. The resulting decrypted key is transformed too so you need another obfuscated version of aes which i have not implemented yet.
Wrong. I couldn't find any obfuscation downstream. So the output is the decrypted key you can use in your default aes implementations:
Run the program given in posting #158. It outputs 4 dwords: "3817007A 0D652D45 0A23A6B0 95876211" so the decrypted key is:
7A 00 17 38 45 2D 65 0D B0 A6 23 0A 11 62 87 95
This is the data which has to be decrypted with Trap_AES in "The Day After Tomorrow" using player key 4 (it's Trap call number 6):
21 BB 37 02 E1 CF F6 EE 92 82 3F B5 A0 A1 35 00
3D 97 95 F0 AB F6 41 86 9D 51 07 D7 E9 80 7F BC
B8 94 BB 0D 7F 72 34 C4 16 4C 6B 40 BC 8F 92 2C
Now i can again simply put this into a file "enc_data.bin" (appended some zeros...) and execute:
openssl aes-128-ecb -d -K 7A001738452D650DB0A6230A11628795 -iv 00000000000000000000000000000000 -in enc_data.bin -out decr_data.bin
The result is in decr_data.bin:d2 8a e3 fd 2e 66 63 55 b7 64 01 6e 4a da 41 2c
dc 7d fb e9 46 13 4b 76 5c 83 27 1c c6 6b 38 6a
00 00 00 00 00 00 00 00 00 00 00 01 00 00 44 22
Which matches the snapshot. :helpful:
Oopho2ei
23rd September 2008, 22:42
Those are the keys which can be used by Trap_AES (you already knew key 4 from the source code):
Key 0: B0 BF 21 C3 5C 19 A2 A1 E3 93 71 5F 4A BA F7 BD
Key 1: 90 13 DA 1D 3D F3 34 F9 D5 F1 7C 31 17 25 40 AC
Key 2: 3A CA 33 02 80 3E 29 F8 BD C0 21 24 B3 09 40 BC
Key 3: 3A E5 B0 C1 8D 32 04 85 32 CC 7C 4C BC 87 37 22
Key 4: DA 15 85 51 1B DF 6F EC D2 30 A5 4E 85 B4 57 2E
Key 5: 2E AD EA A1 96 D1 BC 7D F0 4B E0 51 DB D0 FA C0
Key 6: D5 A7 3B 9E 18 15 C4 D1 0E FD D0 BC 21 C0 86 D3
They only work with "my" obfuscated aes implementation given in posting #158 so it's perfectly correct to "hard code" them in your source. If someone feels bored and removes some obfuscation from the algorithm this will likely also change the keys. The two movies i provide snapshots for ("The Day After Tomorrow" and "I robot") only seem to use Key 4 and Key 5 together with Trap_AES. I think Trap_DeviceDiscovery accessed Key 0 too but i have to check this again... not sure. :)
This should be all you need to implement Trap_AES for the remaining parameters now. I will probably look at parameter checking next.
Good luck with your implementations! :p
Edit: the obfuscation scheme has been broken. Below are the keys you can use with your default/plain aes implementations:
key00 = 6C1AC6780E996094F04AEA2B12CCC382
key01 = B2E16A58560F8AF59E47881D037B5CDF
key02 = AD08B3F2571247488B1AB975137B707B
key03 = 6E8B9CF22A3F4B45E347B5FA8D0CFE74
key04 = FEBE6C124354A6D3E19E491A816CCD4D
key05 = 0ED1D4E6D287A85EFEDB32386FC1A913
key06 = 3100DE1D7EFF6CD013EB84C67CBDB9E9
schluppo
24th September 2008, 01:04
Debugger problems solved:
- Using "java.exe -Xms128m -Xmx768m -jar Debugger.jar" allows for loading the 150mb of pc-trace, so this problem is solved (for now without using a ringbuffer or similar). Thanks for the hint.
- The INSTF instruction was not correctly implemented. I corrected this and now the debugger goes without problems past trap #2044 (I Robot)/#2029 (DAT).
On another note: Great work on the AES-trap!
Edit:
Yet another bug in the basic VM:
for DAT v1.02, at IC=37079238, PC=0x357680, instruction 0xB00DFA1C is executed. This should be "JMP 0x370A0" but is interpreted as "JMP 0x4370A0". The first is a jump backwards 0x3205E0 bytes, the second is a jump forwards 0xDFA20. 0x3205E0 is (more or less) the 2's complement of 0xDFA20. So... the current debugger's VM doesn't handle long backward jumps right.
I am no bitshifter, so could someone help out?
Current code:
long i = IF ^ unsigned(mem32.get(pc / 4));
...
int JimmS = ((int)(i << 6)) >> 6; // Jump constant signed
...
case 0x2C: pc += JimmS; break; // J
Oopho2ei
24th September 2008, 08:20
This should be "JMP 0x370A0" but is interpreted as "JMP 0x4370A0".
You forgot the "AND 0x3FFFFC" (see posting #24). You have to do this for every address otherwise content code can break out of your sandbox environment and potentially execute arbitrary code on your computer. :devil:
schluppo
24th September 2008, 19:00
Ok, I got this fixed along with a few other bugs in the debugger's basic VM. It's staying in sync with PC till trap-call #2676 now (all the following is for DAT v1.02 - but I Robot v1.02 behaves quite similar).
The VM seems to self-check itself starting around trap-call #2000. It does some INSTF-tampering, but changes INSTF back to 0 and keeps it at 0 after a few hundred instructions. Further, it does very long / backward jumps or execute non-jump instructions at 0x003FFFFC afterwards resuming execution at 0x00000000. Around trap-call #2100, the bad parameter trap-calls are starting, such as reading from slot 0xFFFFFFFF (which does not exist) or reading (writing) from (to) memory outside of range for several traps. I fixed some of those, but some others remain to be treated.
Trap-call #2676 is finally the first call of trap_0x10(0);
And soon, I will upload that promised new debugger-edit and also logs of the first ~2700 trap-calls for both movies.
Edit: new version of the debugger: http://uploaded.to/?id=z3gq5g, logs: http://uploaded.to/?id=71kv7r
Oopho2ei
24th September 2008, 23:33
I have pushed some documentation into our repository: http://svn.assembla.com/svn/bdplus
To checkout the repository use:svn co http://svn.assembla.com/svn/bdplus
schluppo
25th September 2008, 00:54
Things are getting more interesting, I modified the debugger to get past the first few calls of trap_0x10 and the consequent breaks using the break_snapshots.
Traps 0x20 (GetEvent?), 0x510 (MediaReadRequest?), TRAP_Memset (?), TRAP_AddWithCarry (?), TRAP_MemMove (?) appear.
frogman
25th September 2008, 17:27
I'll just say: due to certain properties of BD+, once you're past a certain point, you can handle it pretty much without reversing - BD+ itself then helps you out - on any player ;)
I am wondering how true this statement really is.... Oopho2ei and schluppo you guy's must be pretty close to solveing the open source solution.
Dam good work.
Slysoft, Is still the best investment out there!:thanks:
Oopho2ei
25th September 2008, 17:54
I am wondering how true this statement really is.... Oopho2ei and schluppo you guy's must be pretty close to solveing the open source solution.
I think he was referring to all the self checks done before the content code actually does something useful. We have so far passed the memory management and instruction checks. Now a lot of trap checking lies ahead so the player interface is tested extensively. Once we have passed all those checks without the help of the snapshots (guided execution) we should be pretty close. Currently it's still a lot of work.
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 :thanks:
schluppo
25th September 2008, 18:26
I added parameter checking for the following traps to the debugger:
0x140 (Trap_Sha)
0x210 (Trap_AddWithCarry)
0x220 (Trap_MemSearch?)
0x230 (Trap_XorBlock)
0x310 (Trap_MemMove)
0x320
Edit:
new debugger: http://uploaded.to/?id=mq66ms
- Allows to load timer-trace-file (watchdog-trace). shows actual and expected watchdog-counter value. allows to manually set wd.
- Added option to set post_break_snapshot directory. If watchdog reaches 0, automatically load post_break_snapshot and compare registers + memory (same as with traps).
- Added break counter which is increased everytime, when post_break_snapshot needs to be loaded.
- Manually set trap-counter, instruction counter and break counter.
Here's an example of how to use this. I will load the machine to the state after trap-call #2676 in DAT v1.02.
So, put DAT v1.02 00000.svm, 00001.svm and 00002.svm inside the dir where Debugger.jar is. Start the debugger like this: java -Xms128m -Xmx768m -jar Debugger.jar. Load DAT v1.02 00000.svm. Load DAT v1.02 pc_trace.bin, Load DAT v1.02 timer_trace.bin. Load Memory: DAT v1.02 post_trap_mem_002675.bin, Load Registers: DAT v1.02 post_trap_reg_002675.bin. Set IC to 0x2382BDA (37235674), set PC to 0x1AC00, set TC to 0xA74 (2676). Now everything is set to the state past trap-call #2676 in DAT v1.02.
- Note: This debugger-edit also contains a non-working port of Oophoo's modified whitebox aes to java (functions XAES_SetKey(), XAES_Decrypt(), XAES_Block() and so on). I am no AES-expert, so I would appreciate any help in getting these non-working functions to work.
Edit 2: Player key AES-decryption added to the debugger - works fine now :devil: (thanks to Oopho). Lots of small bugs fixed. Will upload new version of the debugger soon.
Edit 3: Here it is: http://uploaded.to/?id=xbayxh. You can go to trap-call #3943 (DAT v1.02) / #3968 (I Robot v1.02) with PC/WD in sync. Trap-call logs up to this point: http://uploaded.to/?id=oe3azr
Oopho2ei
26th September 2008, 15:09
A few things which really need to be improved/changed:
private int trapXorBlock(int pDst, int pSrc, long len) {
if ( (pDst & 0x3FFFFC) >= MEMSIZE ) return 0x80000001;
...
if (((pDst & 0x3FFFFC) & 0x03) != 0 ) return 0x80000001;
...
If only one of the trap parameters is invalid (out of memory bounds) you don't execute the trap and return STATUS_ERROR (see status codes (http://svn.assembla.com/svn/bdplus/trunk/doc/misc/status_codes.txt)). The "& 0x3FFFFC" fools my parameter checking into 'thinking' that "pDst & 0x3FFFFC == pDst" so don't use it. You can use the mask when executing the trap just to be sure the content code can't break out of your sandbox in case the parameter checking is incomplete. If you are sure the parameter check covers all bad cases you should omit the mask from the entire trap.
The dword,word and byte masks (0x3FFFFC, 0x3FFFFE, 0x3FFFFF) can be derived from the memory size:
uint32 memsize = 0x400000;
uint32 MASK_DW = (memsize - 1) & 0xFFFFFFFC;
uint32 MASK_W = (memsize - 1) & 0xFFFFFFFE;
uint32 MASK_B = (memsize - 1) & 0xFFFFFFFF;
You should replace all occurrences of 0x3FFFFC etc. with the appropriate constant.
Finally please remove the case statement from Trap_AES and use something like:
if (opOrKeyID < 0xFFF10000)
{
If (opOrKeyID >= player_keys_count) BUG("TRAP_0110: unavailable key accessed") // some self checks (player_keys_count is currently 7)
...
... player_key[opOrKeyID] ...
...
return ... ;
}
if (opOrKeyID == 0xFFF10000)
{
...
return ... ;
}
if (opOrKeyID == 0xFFF10001)
{
...
return ... ;
}
// if the below statement is executed there is a bug in the parameter checking
BUG("TRAP_0110: invalid opOrKeyID");
After the parameter check (http://svn.assembla.com/svn/bdplus/trunk/doc/traps/param_check/0110.txt) passed opOrKeyID can only be 0,1,2,3,4,5,6,0xFFF10000 or 0xFFF10001. It's not a good programming style to copy/paste the same code 7 times in a row. :rolleyes:
If one of the BUG("...") statements is executed the parameter checking is wrong/incomplete.
Thanks for your new release. :)
Edit: and please only use spaces to format your code (no tabs). My obfuscated aes implementation looks really messed up (another layer of obfuscation added :D)...
Edit: added some more details to my suggestions
schluppo
26th September 2008, 17:24
I integrated your requests.
Furthermore, guided execution reached the end of both snap-shot packages (with PC/WD in sync). So far, the implementations of TRAP_XorBlock and TRAP_Aes behave fine for every call. Will add / fix parameter checking of other traps now.
Note that there remain several problematic traps which are not treated yet, such as 0x530, 0x550, 0x120.
Edit: Fixed TRAP_Random, TRAP_MemSet and TRAP_MemMove. They behave nice now for all calls (parameter checking ok too).
Edit2: TRAP_AddWithCarry implemented and it behaves nicely for all calls (parameter checking ok). There's a small bug in the parameter-checking from the repository though:
if ( dst + 4*len > src & dst <= src + 4*len & dst != src) return 0x80000001; (correct)
vs.
if ( dst + 4*len > src & dst >= src + 4*len & dst != src) return 0x80000001; (wrong)
TRAP_MediaReadFile and TRAP_DeviceDiscovery fixed and they behave nicely for all calls (TRAP_DeviceDiscovery results seem to be constants except for params device=1 and qId=3).
Edit 3: Trap 0x220 was in fact not TRAP_MemSearch but TRAP_MultiplyWithRipple(int pDst, int pSrc, int len, int multiplicator). It's implemented now, parameter check is ok and all calls of this trap behave nicely.
Oopho2ei
26th September 2008, 20:48
Thanks.
I have finished the documentation of the parameter check for trap groups 01XX, 02XX and 03XX: http://svn.assembla.com/svn/bdplus/trunk/doc/traps/param_check/
Group 04XX and 05XX will follow soon. :)
Btw trap #0120 is almost certainly UINT32 TRAP_PrivateKey(UINT32 keyID, UINT8 *dst, UINT8 *src, UINT32 srcLen, UINT32 controlWord);
Oopho2ei
27th September 2008, 13:46
Edit2: TRAP_AddWithCarry implemented and it behaves nicely for all calls (parameter checking ok). There's a small bug in the parameter-checking from the repository though:
if ( dst + 4*len > src & dst <= src + 4*len & dst != src) return 0x80000001; (correct)
vs.
if ( dst + 4*len > src & dst >= src + 4*len & dst != src) return 0x80000001; (wrong)
Almost. It's "dst > src + 4*len". I forgot to negate the check. Thanks!
TRAP_DeviceDiscovery results seem to be constants except for params device=1 and qId=3).
For dev=1 and qID=3 it outputs the volume id. Open the "aacskeys_output.txt" in your package and have a look. :)
Edit 3: Trap 0x220 was in fact not TRAP_MemSearch but TRAP_MultiplyWithRipple(int pDst, int pSrc, int len, int multiplicator). It's implemented now, parameter check is ok and all calls of this trap behave nicely.
Great. I have updated everything and added parameter checking for traps #0510 and #0520 to the repository. (revision 35 now)
Edit: can you make a list of possible status return codes for every call? When i write "return 0x80000001" it doesn't necessarily mean that 0x80000001 is written into r01.
Edit: i am done documenting the parameter checks. The next step is TRAP_PrivateKey() :)
schluppo
27th September 2008, 22:04
I added the other cases (SHA_init, SHA_finish, SHA_update) and parameter checking to TRAP_Sha. Intermediate results do not match yet, but results after SHA_finish match (patent says, intermediate results are undefined but "can be used to store data"). Apart from intermediate results, TRAP_Sha is fine for every call.
My guess for trap 0x320 is TRAP_MemSearch, will look into that soon.
Edit: Here's a new version (including parameter checks for all traps, feel free to bugfix or edit it yourself :)):
debugger: http://uploaded.to/?id=jtslin, logs: http://uploaded.to/?id=ave7c7
Traps 0x120 and 0x530 seem to be most important to me now (since they require player-data to be emulated). The fixing of the problems with other traps (0x320, 0x140, 0x4*0, 0x520) just takes some more time to implement.
Oopho2ei
28th September 2008, 11:57
1. You should work more with our repository so it contains always the latest version. Only upload source and documentation there and no files which can be derived from the source like binaries and logfiles.
I have updated the source in the repository now. You can still upload the binaries to "uploaded.to" for a daily/weekly snapshot.
2. In my parameter checking there is no bit masking and still you use this "MASK_UNS" which masks the most significant bit. All the checks should work perfectly as they are. If they don't please report the problem and we will see how to fix it.
3. You should store the player keys in an array of arrays so you can access them like this OBF_PLAYER_KEY[opOrKeyID] together with a range check.
if (((int)opOrKeyID) == 0x00000000){
return(obfAES(OBF_PLAYER_KEY0,pDst,pSrc,len,pKey));
}
if (((int)opOrKeyID) == 0x00000001){
return(obfAES(OBF_PLAYER_KEY1,pDst,pSrc,len,pKey));
}
if (((int)opOrKeyID) == 0x00000002){
return(obfAES(OBF_PLAYER_KEY2,pDst,pSrc,len,pKey));
}
if (((int)opOrKeyID) == 0x00000003){
return(obfAES(OBF_PLAYER_KEY3,pDst,pSrc,len,pKey));
}
if (((int)opOrKeyID) == 0x00000004){
return(obfAES(OBF_PLAYER_KEY4,pDst,pSrc,len,pKey));
}
if (((int)opOrKeyID) == 0x00000005){
return(obfAES(OBF_PLAYER_KEY5,pDst,pSrc,len,pKey));
}
if (((int)opOrKeyID) == 0x00000006){
return(obfAES(OBF_PLAYER_KEY6,pDst,pSrc,len,pKey));
}
It replaces all this by a single statement. :rolleyes:
4. I would like to see a separate file for each of those:
- instruction processing
- decoding of cmd39, parameter fetching, parameter checking, return code interpretation
- trap implementations
- obfuscated aes implementation and player keys
So the code looks well structured and we don't squeeze everything into BDVM.java which will grow larger over time.
Traps 0x120 and 0x530 seem to be most important to me now (since they require player-data to be emulated).
I am working on TRAP_PrivateKey() (#0120)
Oopho2ei
28th September 2008, 16:20
For the first call of UINT32 TRAP_PrivateKey(UINT32 keyID, UINT8 *dst, UINT8 *src, UINT32 srcLen, UINT32 controlWord) in dat with parameters:
keyID = 00000000
dst = 00005514
src = 00002348
srcLen = 00000010
controlWord = 00000000
The 16 bytes from src are placed after a 16 byte header consisting of "BDSVM_PK" and two dwords. The first dword is probably the control word and the second dword is probably the length. The result looks like this:
42 44 53 56 4d 5f 50 4b 00 00 00 00 00 00 00 10 <-- header "BDSVM_PK"....
35 52 B5 2A F2 7D BA 60 97 93 9C 66 5F 5C 84 F3 <-- 16 byte from src
The result is then hashed with SHA-1. Again i put these 32 bytes in a file and called "sha1sum -b sha_in.bin". The output is (spaces added):
b99b5c49 af55cb7e 9b1e7d90 6846d720 2b9c2908 *sha_in.bin
Which is correct. Now this is supposed to be signed with rsa. Let's see ... :)
Edit: I have modified the example so it matches the DAT v1.02 snapshots.
schluppo
28th September 2008, 17:57
1. Will do.
2. There were a few bugs in your parameter checking (usually mixup of '<' and '>' or '>=' instead of '>' etc.). I fixed those that came to my eyes. Some are still left - see the logs. And concerning MASK_UNS: Java interprets integers as signed numbers. So when doing this:
int bla = 0xFFFFFFFF;
if (bla>0x10) return 0x80000001;
return 0;
it will return 0 (since 0xFFFFFFFF is interpreted as a negative number), but for parameter checks we would want it to return 0x80000001 in this case. Hence I masked the first bit to avoid this trouble. Since it works as it is and my time is limited, feel free to work around this problem in any other way (by using longs to hold the parameters?).
3. Done
4. Will do so, if I find the time.
On another note: What you said so far about TRAP_PrivateKey can easily be coded :)
Oopho2ei
28th September 2008, 19:50
2. There were a few bugs in your parameter checking (usually mixup of '<' and '>' or '>=' instead of '>' etc.). I fixed those that came to my eyes. Some are still left - see the logs.
Please let me see what you found so i can verify it and update my documentation. :)
And concerning MASK_UNS: Java interprets integers as signed numbers.
Argh! Then we have to use long. We can't ignore the MSB in the parameter check. I did a quick search and a lot of people are furious about the lack of unsigned types (except for 'char') in java. :(
On another note: What you said so far about TRAP_PrivateKey can easily be coded :)
I have hit heavy obfuscation. It almost looks like the rsa procedure is executed on another virtual machine with a lot of garbage code. This will take some time...
schluppo
28th September 2008, 21:02
Some info about trap return values: So far, I have only observed the return values 0x0 (STATUS_OK), 0x80000001 (EXECUTION_ERROR?) and 0x80000002 (BAD_PARAMETERS?). I never saw any trap returning its value in another register than in R1. Only trap 0x110 is changing PC and WD, the other traps don't change any machine data besides memory and R1. And there are some traps which don't return anything (trap 0x10, 0x230). This last thing still needs to be handled correctly at the end of trap execution (easy to do).
And here's some information about TRAP_PrivateKey, taken from the patent (in case you didn't read it yet :)): " For the player's main RSA private key (keyID=0), this operation produces a 2048-bit RSA signature of a SHA-1 hash. The hash is computed as follows: (a) hashing the value of srcLen, encoded as 4 bytes (MSB first); (b) hashing the contents of the user-specified buffer (i.e., srcLen bytes at src); (c) hashing the value of controlWord, encoded as 4 bytes (MSB first); (d) If controlWord bit 31 (the MSB) is set, hashing the value of the media ID; (e) If controlWord bit 30 is set, setting the destination pointer to PC+4, overriding dst; (f) if controlWord bit 29 is set, hashing the (control word mod 2.sup.16) code bytes beginning with the current program counter; then (g) if controlWord bit 28 is set, incorporating the current value of PC in the hash. The SHA-1 hash result is then padded by prepending "0x001.parallel.0x01.parallel.0xFF (repeated 233 times).parallel.00" to the SHA-1 hash. The padded value is then raised to the player's secret exponent, modulo the player's public modulus. "
Oopho2ei
29th September 2008, 00:19
Thanks.
TRAP_PrivateKey: I was able to trace both the obfuscated key (~ 96 byte) and the hash result to the heavily obfuscated code (virtualized, lot's of garbage,...). Not sure if i can do it. You would probably kill me if i convert this mess to c code. :D
Looks like i have to record a instruction trace and then somehow analyze it automatically. I need to think about it.
Edit: Any idea of how the result of TRAP_PrivateKey is verified? It's obviously a 320-bit signature which is probably not created by the RSA algorithm. The footer of every section of in the 0000?.svm files is 40 bytes long too. Note that the signatures used in the AACS authentication process are 40 bytes long as well. The way the result of of TRAP_PrivateKey is verified would give us a vital clue of what algorithm created the signature.
Edit: When the hash is all zero the resulting signature is also all zero. If i overwrite the key with zeros i get stack overflows (wtf?)
schluppo
29th September 2008, 21:32
Actually, until trap-call ~5000, this trap is called just once with real parameters (for both movies). All other calls of this trap have bogus parameters and return 0x80000001.
And for this one real call, the program directly calls DeviceDiscovery(1,3) afterwards. The 40 bytes which are written by this call of TRAP_PrivateKey are (according to 'data read breakpoint' of the debugger) not accessed in the next 20 million instructions. Furthermore, before overwriting the register which is holding the adress of these 40 bytes, the progam writes this same adress to two places in memory which are also not accessed in the next 20 million instructions. So to me it seems as if this result is not verified at all (or maybe way later in the BD+ initialization).
I will try and check a bit more, whether I can find any code accessing the 40 bytes.
Oopho2ei
29th September 2008, 21:59
Just like i expected: the unknown algorithm produces different results for the same hash (and the same key). It furthermore always produces a signature consisting entirely of zeros (wtf?) when the input hash is all zero. So now it is even more likely that it's some elliptic-curve signature algorithm like the one used in AACS. I now need to find the third (random) parameter... :devil:
The 40 bytes which are written by this call of TRAP_PrivateKey are (according to 'data read breakpoint' of the debugger) not accessed in the next 20 million instructions.
Do the data read breakpoints work reliable yet? Maybe they are cleared when a new snapshot is loaded? Or maybe the result (40 bytes) is not accessed by the content code (instructions) and instead another trap call reads them? There must be a check somewhere... :confused:
Oopho2ei
30th September 2008, 08:00
I was told the first byte from Trap_PrivateKey(...) is accessed by instruction "C8440000h" at address "091A98h" (this is instruction number 6585958). So there must be a problem with the data breakpoints of the debugger.
schluppo
30th September 2008, 08:27
Hm, if I find some time, I will look into the breakpoint-system of the debugger.
On another note, some info on trap 0x550: It is not called in "DAT" v1.02, but it is called three times in "I Robot" v1.02.
It takes as first parameter a pointer to these strings:
1) "BDSVM/00002.svm"
2) "AACS/MKB_RO.inf"
3) "BDMV/STREAM/000012.mts"
The second parameter is the length of this string.
Parameter three holds 0x00, 0x00 and 0x05. Fourth parameter is either 0x00 or a big value (>0x3FFFFFF) - this is not a pointer, but four bytes of data.
The fifth parameter is a pointer to 0x200. The sixth parameter is the destination pointer (this trap seems to always write 20 bytes).
I assume this trap is computing some kind of hash of the file. Could be CRC or SHA, my bet is on SHA since that outputs 20 bytes anyway. The values in parameters three, four and five should be additional inputs to this hashing algorithm.
Oopho2ei
30th September 2008, 13:40
According to your description Trap#0550 would be something like:
UINT32 TRAP_MediaHashFile(UINT8 *FileName, UINT32 FileNameLen, UINT32 Unknown, UINT32 Unknown, UINT32 *len, UINT8 *dst);
When you look at the parameter checking (http://svn.assembla.com/svn/bdplus/trunk/doc/traps/param_check/0550.txt) you will see that it doesn't always produce 20 bytes. Instead it writes 20 * ( mem[len] / 0x200 ) bytes. Also the filename/path length may not exceed 1024 (!) bytes. :eek:
One of the two unknown parameters could be a file offset.
schluppo: could you please fix the data breakpoint problem? I need the value of n for testing (see ECDSA (http://en.wikipedia.org/wiki/Elliptic_Curve_DSA)). :)
Edit: Someone gave me a hint how to fix the problem with the data breakpoints. I have pushed the fix in the repository. :thanks:
Oopho2ei
30th September 2008, 23:12
I currently don't have the curve parameters (and therefor can't present a real example) but i don't want to withhold anything. The signature is created with ECDSA and consists of two 20 byte long numbers: r followed by s. How the signing process works is explained here (http://en.wikipedia.org/wiki/Elliptic_Curve_DSA).
You can forge signatures without the curve parameters simply by using a fixed point on the curve all the time which means your random number k and r (first 20 bytes) are constants.
So these are all the constants you need:
r = 7c7d84d310c42436daff10af116f80448dc3f88b
k = 7AA9A10C3E90AA8FDAF34DD28F665D3C609CACD7
d_A = 735E0356EA6356E099AD83152E2D81EA1164A866 (keyID == 0)
n = 96609d9e935e52c683dafdc49216143f9a24373d
That's the only variable - our message hash we have to create a valid signature for (see posting #178 about how this is calculated):
e = 1111111111111111111111111111111111111111
so now you calculate s: s = 1/k * (e + r * d_A) mod n
The result is: s = 532b4944f80565075ea9b8894e61c692ed71f3c8
Edit: this is arithmetic over a finite field with the numbers 0,1,2,...,n-1. Any other number (negative, fraction,...) doesn't exist.
Edit: you need the extended euclidean algorithm to calculate 1/k. The result is "1/k = 210974BC85725B5FB0E04FA473FD988001F89088h". So simply multiply with that value.
Edit: There were problems with the previous values so this is a new example and a new private key. It has been tested and should work fine.
Edit: If you the signature verification fails then TRAP_DeviceDiscovery will be called instead of TRAP_Aes after TRAP_PrivateKey (first call of TRAP_PrivateKey in DAT v1.02)
Edit: That's the second private key:
d_A = 87E22D06A699EE311CD73F19B91E67414C44F4F5 (keyID == 1)
It's the same curve (same parameters) so you can use the same (k,r) pair.
Edit: We have found the remaining curve parameters: q = 96609D9E935E52C683DBFC3A7D783EA942BDE8CB
a = 96609D9E935E52C683DBFC3A7D783EA942BDE8C8 = -3 (mod q)
b = 3E567D8DEC27873BCF86F5FBB595DB288C62C721
x_G = 05FC5B0B2360AC50A76E1511BC5C9AF67A004D0D
y_G = 09B0D43F319B09A5B679CCF264E1ABA4D56594EA
The corresponding public key for keyID == 0 (can be calculated from above values):
x_Q = 31dbb17fea9d7d0eb8bfbb6b8d29ac938c13b599
y_Q = 2465dd38f4214edee4da4e7f62b77a41ce962757
The corresponding public key for keyID == 1 (can be calculated from above values):
x_Q = 57305D64D1013FFFA4D72355B4C70B27A815A343
y_Q = 05E22B42F88A5C1AC5E70DF466353BDB0A83228A
Great job everyone! :)
Oopho2ei
1st October 2008, 08:01
Regarding Trap#0550 i was told that the fourth parameter is the file offset and that this trap really calculates the SHA-1 hash.
UINT32 TRAP_MediaHashFile(UINT8 *FileName, UINT32 FileNameLen, UINT32 FileOffsetHigh, UINT32 FileOffsetLow, UINT32 *len, UINT8 *dst);
It works fine unless the third parameter (still unknown) is not zero but 5. We don't know what this means yet. Maybe only every fifth block of the file is hashed. Or maybe a block larger than 512 bytes (5*512 bytes) is hashed and results in a 20 byte SHA-1 hash. This still has to be figured out... :)
Edit: The file offset is 64 bit (FileOffsetHigh << 32 | FileOffsetLow). A 32 bit address is too small for those large files (00001.m2ts is > 20GB).
Edit: TRAP_MediaHashFile is fully analyzed now and i have updated the documentation in svn (http://svn.assembla.com/svn/bdplus/trunk/doc/traps/)
Edit: We need proper names for Trap#0540 and Trap#0550. In alphabetical order name(Trap#0540) has to stand before name(Trap#0550) which is currently not true:
name(Trap#0540) = TRAP_MediaReadFile <-- maybe change in TRAP_MediaFileRead ?
name(Trap#0550) = TRAP_MediaHashFile <-- or maybe change this in TRAP_MediaSHA1HashFile
Suggestions?
Edit: The naming issue is solved. The "official" name for Trap#0550 is TRAP_MediaSHAFileHash
schluppo
2nd October 2008, 04:49
Great work on TRAP_PrivateKey! :)
Trap 0x550 is implemented now. Works fine (for the two files that I have :rolleyes:).
I named it 'trapMediaHashFile' in my code but do not care about the name actually. Just change it to whatever you think is appropriate.
trap 0x320 is trapMemSearch, will implement it soon.
is it possible to code trapPrivateKey yet or should I wait until you posted some more examples / parameters?
Only big thing remaining now is trap 0x530 aka DiscoveryRAM. This is called around 500 times, taking memory from lots of different areas of the player's RAM. Maybe we need a memory dump and let the trap-emulation read from that dump-file or something like that. :confused: I checked a few example trap-calls with identical parameters and did not see differing results. Maybe this trap is just asking for areas of the RAM which are constant throughout execution?
Oopho2ei
2nd October 2008, 12:30
trap 0x320 is trapMemSearch, will implement it soon.
Are the parameters identical to the TRAP_MemSearch() in the patent?
is it possible to code trapPrivateKey yet or should I wait until you posted some more examples / parameters?
You can start to implement it now. I am currently looking at events. The area 0x000-0xFFF seems to be used for passing events after the content code signals it's readiness to the player with Trap_Finished().
Only big thing remaining now is trap 0x530 aka DiscoveryRAM. This is called around 500 times, taking memory from lots of different areas of the player's RAM. Maybe we need a memory dump and let the trap-emulation read from that dump-file or something like that. :confused: I checked a few example trap-calls with identical parameters and did not see differing results. Maybe this trap is just asking for areas of the RAM which are constant throughout execution?
If you need to know where this data comes from i will look at this trap.
schluppo
2nd October 2008, 14:02
It's like this:
trapMemSearch(UINT8 *Region, UINT32 RegionLen, UINT8 *SearchData, UINT32 SearchDataLen, UINT8 *Dst)
I will be gone for a few days now. But I will try to implement 0x320 and fix 0x140 and 0x520 in the meantime.
Oopho2ei
2nd October 2008, 16:03
It's like this:
trapMemSearch(UINT8 *Region, UINT32 RegionLen, UINT8 *SearchData, UINT32 SearchDataLen, UINT8 *Dst)
Thanks. I assume at "dst" a pointer to the first match is stored? Also it can't be "UINT8 *Dst" because of:if ( Dst & 0x03 != 0 ) return 0x80000001
One of our anonymous contributers has suggest to use a optimized format for our snapshots. Instead of always storing the full snapshot only the differences to the previous snapshot are saved. This saves a large amount of disc space and probably also speeds up execution because the harddrive is currently the bottleneck.
The implementation would look like this: you load the first snapshot and compare as usual and continue execution but keep the last snapshot in memory. For the next snapshot you use the previous snapshot (saved in memory) and the difference to the previous snapshot (which is stored on disc now).
A sample implementation of how to handle the "differential snapshots" is given here (http://svn.assembla.com/svn/bdplus/trunk/diffarchive/)
I have updated the trap documentation of TRAP_Memsearch and made some minor changes to wbaes.
Also what traps actually return a value (write to r01)? According to the documentation (http://svn.assembla.com/svn/bdplus/trunk/doc/traps/overview.txt) most of them return "UINT32". I was only guessing. :rolleyes: Has anyone verified that?
Edit: All traps for which the parameters are checked return a value. I have corrected the documentation and also renamed Trap#0550. The "official" name is now TRAP_MediaSHAFileHash. Thanks again to our anonymous contributers :thanks:
Oopho2ei
2nd October 2008, 23:46
Now that the instruction processing seems to work without problems and only very few traps still have to be explored it is time to start looking at events. The event passing and handling will be quite a challenge not only because it's barely documented but also because events are somewhat nondeterministic. It should also be the last thing left to do. :)
These are some useful informations which are given by the pdf:
The interface defines 9 callbacks (Events), which devices may invoke to notify content code of outside events, or to request specific actions
examples for possible events are successful media reads/writes, shutdown or media eject events, player security operations and idle events sent with each frame displayed
Event data is provided to content code in the Event Parameter area, which is a section of memory designated by content code.
response values are returned to the device via the same area
Observations of event handling we have already made:
at the end of the initialization phase the content code seems to signal the player it's readiness to process events with Trap_Finished()
after the execution of Trap_Finished() the watchdog counter is set (and after a break reset) to 0xFA0 so execution is interrupted in very short intervals (4000 DLX clock cycles)
the regular interruption of content code execution is used to check for events
if an event occurred and the execution is interrupted (watchdog reached <= 0) the following things happen:
parts of the memory space 0x000000-0x000FFF (that possibly is or very likely contains the "Event Parameter area") are modified
the program counter is set to 0x1000 (always?) after a copy of it's current value is stored in r28
the watchdog counter is reset to 0x7FFFFFFF which stops the regular interruption now that the content code is already processing an event
if no event occurred then only the watchdog counter is reset (to 0xFA0) and execution resumes normally
on the next call of Trap_Finished the following things happen:
the program counter is restored from r28
the watchdog counter is set (and after a break reset) to 0xFA0
this call likely signals the completion of the event processing to the player so the player will probably read the designated memory area 0x000000-0x000FFF to fetch the requested results
the memory space 0x000000-0x00003F seem to be special and is likely to hold meta data like parameters or the event id.
A great deal of the above observations were made by our anonymous contributers. :thanks:
Oopho2ei
4th October 2008, 01:37
I would like to introduce a new snapshot file format for our event analysis. The structure is shown below:
struct
{
uint32 pc;
uint32 if;
uint32 regs[32];
uint32 event_area[1024];
} snapshot_t
struct
{
snapshot_t snapshot0
snapshot_t snapshot1
} event_snapshot_file_t
Each file contains two snapshots: one snapshot before and one after the interruption of instruction processing (due to watchdog <= 0). All files which contain two identical snapshots are discarded. The remaining files are left for analysis.
As you can see each snapshot contains the program counter, the instruction filter, all 32 registers and most importantly the first 1000h bytes of vm memory (address space 0x000000-0x000FFF). The filenames have the format "epa_diff_%06d.bin".
You can write a program which analyses all the differences made by the player in the dedicated memory space (Event Parameter area) and finally creates a list/summary of all changes. Aim is to identify the section where the event id and the event parameters are stored and to create a list of all event types.
A snapshot package of that kind will be available soon.
Edit: This is a sample package: http://uploaded.to/?id=rfr3ew
Edit: That's the event snapshot package i have promised you: http://uploaded.to/?id=6ca19v
It seems every time i fast forwards or rewind a event is created. During the movie playback i have noticed about every 30s a new event.
Oopho2ei
5th October 2008, 02:12
There are still some other minor issues apart from event passing/handling. For example there is still no exception handling for cases like "division by zero", "arithmetic overflow" etc. The literature says a trap call would handle the exception but in the case of BD+ they seem to have defined the result of a division (both signed and unsigned) by zero to be zero. I had expected that our debugger would crash in this case but it didn't. Instead a message box with the text "/ by zero" is displayed. :)
I will look at the other cases soon and upload a list to the repository.
Edit: the documentation can be found here (http://svn.assembla.com/svn/bdplus/trunk/doc/instructions/exceptions.txt)
Oopho2ei
6th October 2008, 01:58
I have looked at the remaining Traps #0020 and #0530 (TRAP_DiscoveryRAM).
Trap#0020 has two parameters which are both vm memory addresses from which the player is reading a lot of data. I don't know what is done with the data yet. This is probably related to TRAP_Finished because both traps are in the same group. We still need a name for this trap which fits in alphabetically between TRAP_Finished and TRAP_MediaReadFile.
For TRAP_DiscoveryRAM the player fills a section of memory with some pattern and then loads the data which the content code is expecting from different places and thereby overwrites parts of the pattern again. I don't know if the pattern is really needed or just some sort of vendor specific countermeasure against memory analysis by malicious content code. The memory organization can be found here (http://svn.assembla.com/svn/bdplus/trunk/doc/player/memory_layout.txt) (work in progress)
schluppo
6th October 2008, 14:45
Implementation of trap_0x320 (TRAP_MemSearch) finished, works fine (for the few examples).
The title's VolumeID is now taken from a file called "volume_id.bin" which has to be in the same dir as the .jar. When trap_0x520(..,..,1,3) (TRAP_DeviceDiscovery) is called, the VolumeID is inserted into the result. Works fine for the two movies.
Things to code / fix:
- trap_20 (TRAP_EventGet??) is still untreated.
- trap_120 (TRAP_PrivateKey) is still untreated.
- trap_140 (TRAP_Sha) intermediate results are still wrong. I will fix this soon.
- trap_510 (TRAP_DeviceAccess?) is still untreated - there are just two calls of this trap in the 5000 snapshots for both movies. They both don't change memory.
- trap_520 (TRAP_DeviceDiscovery) - for parameters 1,3 there needs to be a timestamp in the result. Currently the timestamp is static, I will fix this soon.
- trap_530 (TRAP_DiscoveryRAM) - is still untreated, I am planning to look at this later today.
- trap_560 (TRAP_RunNative?) - there are no example calls for this yet.
Will upload new sources to the repository later today.
Edit: They are in the repository now. Also contain a try at TRAP_PrivateKey. Up to the end of the SHA-part, it works fine. Feel free to bugfix :)
Edit2: Timestamp added to the result of TRAP_DeviceDiscovery(...,...,1,3); Should be fine now.
Edit3: TRAP_DiscoveryRAM is now reading <len> bytes from a file called "RAM.bin", starting at <offset>. It then writes this data to <pDst>. It would be convenient to have a player memory-dump of the first 4mb to read from. Since that's probably not possible, I am working on a different solution now.
Oopho2ei
6th October 2008, 15:21
trap_20 (TRAP_EventGet??) is still untreated
I was told that there is no TRAP_EventGet (see posting #145). The event passing is likely done via a dedicated memory area (probably 0x000000-0x000FFF). The implementation of this trap is a bit strange. Some details can be found in posting #197
- trap_120 (TRAP_PrivateKey) is still untreated.We are still trying to figure out the curve parameters but i was told it works fine with the fixed (k,r) pair from posting #188.
- trap_520 (TRAP_DeviceDiscovery) - for parameters 1,3 there needs to be a timestamp in the result. Currently the timestamp is static, I will fix this soon.
I was told that TRAP_DeviceDiscovery needs player specific keys too. Do you see some kind of signature in the output of this trap? Or is it just the timestamp which is different? Otherwise it's likely that the public key (used by the content code to verify the signature created by TRAP_PrivateKey) can be found somewhere in the output of the trap. I was able to see that two different keys were accessed for qID == 1 and qID == 2 but no key seems to be necessary for qID == 3. Sadly i didn't check if those keys were really used somewhere. :rolleyes:
- trap_560 (TRAP_RunNative?) - there are no example calls for this yet.
And i hope there won't be an example. :)
Will upload new sources to the repository later today.
Have a look here (http://trac.assembla.com/bdplus/changeset/42) to see what i changed to make the data breakpoints work. Please only upload the source code (*.java files) to the repository because we have only 200MB disc space and all revisions are stored. When you upload a snapshot (to uploaded.to or whatever) could you please include a description of what files have to be present and in which directory? The output of "find *" will probably be enough.
Oopho2ei
7th October 2008, 13:36
There are no updates visible in the repository for the latest changes you announced. Also for some reason you have deleted all sources in revision 48 (http://trac.assembla.com/bdplus/changeset/48) and added new sources in revision 49 (http://trac.assembla.com/bdplus/changeset/49) and 50 (http://trac.assembla.com/bdplus/changeset/50). One revision later (51 (http://trac.assembla.com/bdplus/changeset/51)) you have finally added the description of what files are needed.
The result (revision 51) is correct but the way you work with the repository (it's not a ftp server!) has to be improved. First of all to upload your latest changes you need a single simple command:
svn commit -m 'this is a little description of what i have changed'
This command compares your source with the current (locally stored) snapshot of the repository and analyses the lines of code you have changed. It creates a patch (like this one (http://trac.assembla.com/bdplus/changeset/42?format=diff&new=42)) which it tries to apply to the real repository on the assembla server (which might have changed because other people applied their changes in the meantime). When you delete one of the source files from the repository and upload your own version you destroy the work of other people which have made updates to the files in the meantime. You should commit your changes every time you made an important change which leads to a still working implementation.
Feel free to bugfix :)
I think people are discouraged from doing that because the latest version of the repository is already outdated (you have made other changes):
Edit2: Timestamp added to the result of TRAP_DeviceDiscovery(...,...,1,3); Should be fine now.
Edit3: TRAP_DiscoveryRAM is now reading <len> bytes from a file called "RAM.bin", starting at <offset>. It then writes this data to <pDst>. It would be convenient to have a player memory-dump of the first 4mb to read from. Since that's probably not possible, I am working on a different solution now.
In posting #197 i've tried to explain that TRAP_DiscoveryRAM doesn't read parts of memory (security problems (access to secret keys etc) -> data would have to be relocated -> other player threads which access the previous address in the meantime might crash ....) instead depending on the address the data the content code expects is fetched from different places to build the requested section of player memory. This could be called "reading the virtual player memory".
Also you don't have to edit the postings to announce your changes. People can read the latest changes here (http://trac.assembla.com/bdplus/timeline). :)
Anyway thanks for your work and the updates. :thanks:
Edit: i make daily backups of TRAC and SNV so we can quickly move if necessary. But reverse engineering for interoperability (bd+ for linux) is normally considered legal so i doubt there will be any problems. :)
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.