Log in

View Full Version : Finally handling BD+ (?)


Pages : 1 2 3 4 [5] 6 7 8 9 10 11 12 13 14 15 16

Oopho2ei
7th October 2008, 21:11
Ok, the last repository update looks fine. Now i would suggest we introduce some structure to the code. I have this (http://uploaded.to/?id=4nn0a3) in mind. You can already find the "bdsvm_player_interface.java" (unfinished) in the repository together with another new class "bdsvm_globals.java" which is supposed to be used for constants or global variables (if needed).

When i wrote the bdsvm_player_interface.java i had the BDVM.java still open and the autosave function seemed to have overwritten your latest patch. I have corrected this in revision 54. Sorry! :rolleyes:

Edit: The svg image can be displayed by your browser.

Oopho2ei
7th October 2008, 23:37
We were able to find all the curve parameters for the ECDSA algorithm used by TRAP_PrivateKey. They can be found in posting #188 (http://forum.doom9.org/showthread.php?p=1190187#post1190187).

You can now use any ECDSA implementation which fits your programming language. :)

Edit: The public key given in posting #188 can be found in the output of TRAP_DeviceDiscovery.

RunningSkittle
7th October 2008, 23:55
For the non technical readers following this, could you give an update to how things are progressing? :]

schluppo
8th October 2008, 04:29
Here (http://uploaded.to/?id=pvjwnc)'s a nice RAM.bin, if you put it in the same dir as the newest version of the debugger, this will take care of TRAP_DiscoveryRAM :)

This trap gives same result for same parameters and also same result for same parameters on both movies, so it seems like it really checks 'constant' areas of the virtual RAM. Most of the 'footprints' are by the way very similar to each other, maybe they are just offset to each other. I will investigate this when I have more time (could allow for a nicer treatment of this trap).

TRAP_SHA is fixed too (intermediate results were a pain in the *** for me).

Now only TRAP_PrivateKey remains to be treated for the first 5000 trap-calls and both movies. Will do that next...

Unguided execution stays in sync till trap call ~#500 (gets out of sync one trap call after TRAP_PrivateKey).

Edit: Sorry about the SVN-trouble, I was using a bad client and didn't think anyone would be bothered by it. The situation is fixed now.

Oopho2ei
8th October 2008, 13:56
For the non technical readers following this, could you give an update to how things are progressing? :]
The whole project consists of three major tasks:
1. vm instruction processing (95% done)
2. trap implementations (80% done)
3. event/callback processing (10 % done)

With the memory snapshots and traces (for the movies "The Day After Tomorrow" and "I Robot") from a licensed player we are able to debug and test parts of our implementations on real world examples.

All the keys we currently use for debugging will probably be revoked soon (if they have not been revoked already) so you probably won't be able to watch the latest BD+ protected movies with mplayer without new keys in the future.
The result of this project will hopefully be a working open source BD+ implementation which can be used together with linux and other free operating systems. I am hoping that DRM companies will look for bugs in our code to exploit so we can constantly improve the source until it finally meets the requirements of the secret BD+ specification.

I will investigate this when I have more time (could allow for a nicer treatment of this trap).
Have you (and other) looked at my idea of a modular BD+ implementation in posting #201? I believe it will be easier to understand and maintain the code. If you keep on squeezing everything into BDVM.java it will probably become even harder to "reorganize" the code later. Maybe bmnot can assist you and i am willing to help too. :)

FoxDisc
8th October 2008, 16:50
All the keys we currently use for debugging will probably be revoked soon (if they have not been revoked already) so you probably won't be able to watch the latest BD+ protected movies with mplayer without new keys in the future.

Thanks for the summary. Are the keys used by BD+ the same keys defined in the AACS spec, or do they use their own keys?

Oopho2ei
8th October 2008, 17:49
Thanks for the summary. Are the keys used by BD+ the same keys defined in the AACS spec, or do they use their own keys?
As for the ECDSA algorithm used by TRAP_PrivateKey we know that it uses different curve parameters (q,n, etc are different) so there is no relationship. I don't know about the 7 aes keys used by TRAP_Aes because they are all transformed (obfuscated) and nobody has bothered to reverse the transformation yet so we still use the corresponding transformed aes implementation. It's like using the keys without really knowing them. See postings #158 (http://forum.doom9.org/showthread.php?p=1187262#post1187262) and #163 (http://forum.doom9.org/showthread.php?p=1187564#post1187564) for details. It's some kind of whitebox attack resistant aes implementation. The basic idea to introduce random bijections which are applied at the end of one round and reversed before the beginning of the next round so to introduces a lot of noise to hide the underlying calculations and the round keys (including the key itself). Afaik unless those implementations don't use extremely large lookup tables they are all insecure. So that's the status on the keys. :)

Oopho2ei
9th October 2008, 02:06
I think qID =1 and qID=2 for TRAP_DeviceDiscovery might be the question for the primary and the secondary player certificate. Each certificate contains among other things the corresponding public key. You can find both public keys in posting #188 (http://forum.doom9.org/showthread.php?p=1190187#post1190187). The structure of each certificate could be similar to those in the AACS specification which you can find in this pdf (http://www.aacsla.com/specifications/specs091/AACS_Spec_Common_0.91.pdf) on page 42 (4.1 Drive Certificate).

I have furthermore analyzed the event snapshots i made (see posting #195 (http://forum.doom9.org/showthread.php?p=1191362#post1191362)). The differences are shown in this file (http://uploaded.to/?id=4zgboh). The following is an example of what was changed during the time the vm instruction processing was suspended (because watchdog <= 0):
PC = 000994C4 -> PC = 00001000
r28 = 000994D8 -> r28 = 000994C4
00000000 : 64DE004B E25BE65D 8D18BD98 14710E79 -> 00000220 00000000 00000001 00000057
00000020 : 96D3A639 B57F047B 6462D48B 7BFF5510 -> 00000000 00000000 6462D48B 7BFF5510
This shows you that the PC has been set to 0x1000 (a copy of the PC is stored in r28) and that the first 16 bytes of vm memory were replaced by "00000220 00000000 00000001 00000056". I currently think that 0x0220 is the event ID and then other 3 dwords are the parameters. When you study the file you will see, that the last parameter is incremented with every new event (which occurred about every 30s). If it suddenly jumps to a different value than this is because of me switching to a different scene in the movie :rolleyes:
Finally 8 bytes at address 00000020h are overwritten with zeros but i don't know why. :confused:

Assuming the value at 00000000h really is the event id then i have witnessed those events:
00000010 = occurred when i pressed the drive eject buttion, 1 parameter
00000110 = occurred at start of movie playback, 2 parameters
00000210 = occurred at start of movie playback, 2 parameters
00000220 = regular event (about every 30s), 3 parameters

I think i will find some answers when i follow the content code starting at 0x1000. :)

schluppo
9th October 2008, 03:35
The snapshot-packages contained some breaks too:

DAT v1.02:

... // Initialization etc.
TRAP_Finished;

break 0x110(0,0xFFFF);
TRAP_0x20(0,0x1000);
TRAP_Finished;

break 0x210(0,1);
TRAP_0x510(2,1,0x1EFB6C); // TRAP_DeviceAccess?
TRAP_0x510(0,1,0x1EFB6C); // TRAP_DeviceAccess?
TRAP_Finished;

break 0x110(0,1);
... // Lots of trap-testing here
TRAP_0x20(0xFCD9E,0xEFAF8);
TRAP_Finished;

break 0x010(0);


I Robot v1.02:

... // Initialization etc.
TRAP_Finished;

break 0x110(0,0xFFFF);
TRAP_0x20(0,0x1000);
TRAP_Finished;

break 0x210(0,1);
TRAP_0x510(2,1,0x3DFB70); // TRAP_DeviceAccess?
TRAP_0x510(0,1,0x3DFB70); // TRAP_DeviceAccess?
TRAP_Finished;

break 0x110(0,1);
... // Lots of trap-testing here
TRAP_0x20(0xFCBDA,0x2DFAFC);
TRAP_Finished;

break 0x010(0);


As you can see, the 'program' seems to be the same for both movies.

The player can tell the content code what to do by changing the first 20 bytes before it 'reactivates' the VM:
break 0x110(0,0xFFFF): ?
break 0x210(0,1): check whether disc is in drive and ready (?)
break 0x110(0,1): test bd+ system / player and get ready for playback
break 0x220(0,1,n): decrypt block <n>
break 0x010(0): shut down

Most interesting would be to see which traps are called after break 0x220(0,1,n) was invoked. The content code needs to get data, decrypt it and output it somehow. We don't know yet which traps are used for input and output (slots? 0x510? 0x20?).

Oopho2ei
9th October 2008, 13:08
Most interesting would be to see which traps are called after break 0x220(0,1,n) was invoked.
You can start implementing an event handler which writes the above data to the to the beginning of vm memory and sets registers pc and r28 appropriately. Then you only need to run your emulator and see what happens.
We don't know yet which traps are used for input and output (slots? 0x510? 0x20?).
Certainly not via slots. Probably through area 0x000000-0x000FFF and the results from the content code can maybe be passed to the player via Trap#0020.

schluppo
9th October 2008, 22:48
I looked a bit into the trap-call behaviour after different kind of breaks (all for DATv1.02).

When manually invoked after VM-initialization (i.e. after the first 5000 trap-calls), break 0x110(0,0xFFFF), break 0x210(0,1), break 0x110(0,1) and break 0x010(0) behave as expected.

Here's what I saw for break 0x220(0,1,n):

Depending on the value of <n>, several different traps are being checked (40-500 trap calls, some with bogus parameters, some with real parameters - they are being checked in exactly the same order as in break 0x110(0,1) - I found no new traps being called and there are no calls of known traps with new parameters).

I went through break 0x220(0,1,n) with 10 different values for n, and everytime, the last 5 trap calls in my log were identical:

IC: 75197 Trap #169: trap_0x410(0,14)= TRAP-SlotAttach
IC: 75203 Trap #170: trap_0x420(1ef964,0)= TRAP-SlotRead
IC: 75689 Trap #171: trap_0x520(1,1,22b48,1efa58)= TRAP_DeviceDiscovery
IC: 75789 Trap #172: trap_0x520(1,2,22b48,1efa58)= TRAP_DeviceDiscovery
IC: 78102 Trap #173: trap_0x10(ffffffff)= TRAP_Finished

By the way, everything before these 5 trap-calls is 'trap self-checking'.

So, the content code tries to read slot 0, but the current implementation of TRAP-SlotRead does not give the wanted result, hence the content code calls TRAP_DeviceDiscovery twice and then finishes (seems to be some kind of standard behavior in case that a trap gives a bad result).

Oopho2ei
9th October 2008, 23:48
Thanks for that information. So it looks like you need even longer snapshot packages now :rolleyes:

In the meantime could you check where the trap id is accessed in the content code and against what values it is compared to. Or maybe there is a lookup table which leads to the event id specific code. You can also record program counter traces for different event ids and compare them to see up to which point they are identical. The reason for this is simply to get a list of all event IDs that exist/handled by the content code. There are supposed to be 5 other event IDs (so 9 in total).

schluppo
10th October 2008, 02:33
From now on, I will write 'events' instead of 'breaks', whenever apropriate.

The code directly (first thirty instructions) after the break checks for equality of memory[0] (which holds <event_id>) with values from here:


0x22070: 18210200 80270200 FFFFFFFF 10020000
0x22080: 24250200 20020000 C4230200 10010000
0x22090: 60220200 00000000 18210200 10000000
0x220A0: 54260200 00000000 00000000 1000BD6F
0x220B0: 0C00DDE3 1000DD67 F8FFFEE3 00005DE0


(first from 0x2207C, then 0x22084 etc.)

If for instance <event_id> = 0x220, the according adress 0x223C4 is reached with IC = 47.

This indicates, that this version of BD+ has just the four events we saw so far (plus maybe event 0x0?).

Edit: Here's a small list of the traps which are called for the events in DATv1.02:

event 0x0: trap calls #1529-#2676 (the first 1528 trap calls are loading files and setting up the machine etc.).

event 0x10: execute just TRAP_Finished.

event 0x110(1): trap calls #2682-#5053.
event 0x110(2): trap calls #2682-#5053 (plus 4 additional TRAP_Random calls in the middle of testing TRAP_Random).
event 0x110(0xFFFF): execute TRAP_0x20 and then TRAP_Finished.

event 0x210: execute just TRAP_Finished (?)

Each of the following continues as stated in posting #211 after the testing is done:
event 0x210(1,1): trap calls #2682 - #2850 (= test TRAP_AddWithCarry).
event 0x210(1,2): trap calls #3760 - #3843 (= test TRAP_Random).
event 0x210(1,3): identical to event 0x210(1,1).
event 0x210(1,4): trap calls #3894 - #4001 (= test TRAP_AES).
event 0x210(1,5): trap calls #3473 - #3550 (= test TRAP_MemMove). Then custom test TRAP_MemMove.
event 0x210(1,6): trap calls #3551 - #3612 (= test TRAP_MemSearch). Then custom test TRAP_MemSearch.
event 0x210(1,7): trap calls #3142 - #3342 (= test TRAP_XorBlock).
event 0x210(1,8): identical to event 0x210(1,6).
event 0x210(1,9): identical to event 0x210(1,1).
event 0x210(1,a): trap calls #2851 - #3141 (= test TRAP_MultiplyWithRipple).
event 0x210(1,b): identical to event 0x210(1,5).
event 0x210(1,c): identical to event 0x210(1,2).
event 0x210(1,d): trap calls #4003 - #4442 (= test TRAP_DeviceDiscovery).
event 0x210(1,e): trap calls #4443 - #5049 (= test TRAP_DiscoveryRAM). Also trap calls #2070 - #2674 are the same.
event 0x210(1,f): trap calls #3614 - #3759 (= test TRAP_SHA).
event 0x210(1,10): identical to event 0x210(1,2).
event 0x210(1,11): identical to event 0x210(1,d).
event 0x210(1,12): identical to event 0x210(1,4).
event 0x210(1,13): identical to event 0x210(1,d).
event 0x210(1,14): trap calls #3344 - #3473 (= test TRAP_MemSet). Then custom test TRAP_MemSet.
event 0x210(1,15): identical to event 0x210(1,d).
event 0x210(1,16): identical to event 0x210(1,14).
...
event 0x210(1,0x56): custom test TRAP_MemMove.
event 0x210(1,0x85): trap calls #3844 - #3893 (= test TRAP_PrivateKey).
event 0x210(1,0xD3): identical to event 0x210(1,1).
event 0x210(1,0xE1): identical to event 0x210(1,f).
event 0x210(1,0x107): identical to event 0x210(1,d).
event 0x210(1,0x145): custom test TRAP_MemMove.
This should now cover all the trap-testing for Event 0x210. Note that it seems as if the current debugger gets past all of these tests (I logged all of this without snapshot- or PC/WD-guidance).

Oopho2ei
10th October 2008, 12:38
So the table is actually:
event ID | handler
--------------------
00000210 | 00022524
00000220 | 000223C4
00000110 | 00022260
00000000 | 00022118
00000010 | 00022654

So we got a new unknown event ID: 0. :)

I am planning to upload the new code base for the debugger soon (when it can be compiled without error/warning). I will help you finding the mistakes i made. Remember what i told you about the parameter checking: if the return value is wrong i get the trap parameters and the expected return value so i can fix the documentation :)

Edit: a possible terribly broken snapshot of the new codebase is in the repository. At least it compiles without errors. A new file "flash.bin" (link removed) is needed which contains all slots and 256 byte extra data (so 128kb).

Edit: the debugger with the new code base runs fairly stable now :) . There are still some bugs which will be sorted out soon. You need a new flash.bin (http://uploaded.to/?id=q55it2) because the one above had the the wrong byte order. A visible change for the user is the new monospace font and the leading zeros.

http://img101.imageshack.us/img101/7963/debuggerguixh1.th.jpg (http://img101.imageshack.us/my.php?image=debuggerguixh1.jpg)http://img101.imageshack.us/images/thpix.gif (http://g.imageshack.us/thpix.php)

I hope schluppo is not too mad at me about what i did to his code :D

schluppo
12th October 2008, 02:12
Looks quite fine.

One thing I noticed, is that you don't print out the value of trap-counter, instruction-counter or the trap-name, whenever a trap is executed. Also you always output 6 parameters even though a trap may have less parameters. I found the logging from previous versions more helpful when trying to quickly analyze which traps had actually been called during a run of the debugger.

Parameter Checking for TRAP_SlotRead is not correct - trap call #2037 is problematic:
IC: 37177656 Trap #2037: trap_0x420(1efd08,ffffffff)= TRAP-SlotRead


Parameter Checking for TRAP_AddWithCarry is not correct - trap call #2686 is throwing Array-Out-of-Bounds exception:
IC: 37506486 Trap #2686: trap_0x210(1ef928,3fffe0,8)= TRAP_AddWithCarry


Apart from that, I have no objections, nice work :)

Currently, I am idle. So, It would be great if you could provide a new snapshot-package, containing one or two calls of event 0x220.

Oopho2ei
12th October 2008, 10:42
One thing I noticed, is that you don't print out the value of trap-counter, instruction-counter or the trap-name, whenever a trap is executed. Also you always output 6 parameters even though a trap may have less parameters. I found the logging from previous versions more helpful when trying to quickly analyze which traps had actually been called during a run of the debugger.
I don't mind if you change it to something more useful. But please use System.out.format("bla = %08X, foo = %04d \n", bla, foo); or similar for console outputs.

Parameter Checking for TRAP_SlotRead is not correct - trap call #2037 is problematic:
IC: 37177656 Trap #2037: trap_0x420(1efd08,ffffffff)= TRAP-SlotRead

Yes and i have tried to fix it but without success. The slotid = 0xFFFFFFFF in TRAP_SlotRead means: read the currently attached slot. I have seen the check for slotid == 0xFFFFFFFF in the parameter checking code but didn't trace it into the following calls. My current guess is that something is wrong with the currently attached slot or there is no (valid?) slot attached.

Parameter Checking for TRAP_AddWithCarry is not correct - trap call #2686 is throwing Array-Out-of-Bounds exception:
IC: 37506486 Trap #2686: trap_0x210(1ef928,3fffe0,8)= TRAP_AddWithCarry
Oups. I must have missed that one.

Currently, I am idle. So, It would be great if you could provide a new snapshot-package, containing one or two calls of event 0x220.
I would suggest we fix the code of the debugger so it can run without snapshots and look at what the content code does for the events we create. For example TRAP_PrivateKey is still broken (i believe the problem is the conversion of the ASN.1 SEQUENCE (~46 bytes) in which the signature is represented by bouncycastle to the 40 byte raw hex data we have to place at 'dst'.
In a longer snapshot package you will probably only see the changes in the 0x00-0x30 memory area so i am not sure if this can help us. The above problem with TRAP_SlotRead shows me that there are still some things to study before we can turn to event handling/passing. Creating new longer snapshot packages is a full day of work for me. :rolleyes:

schluppo
13th October 2008, 01:42
I don't mean to sound negative in any way, but I saw a few things :) I found that TRAP_AddWithCarry is broken now.


#002694 TRAP_AddWithCarry (001EF928, 003FFFE0, 00000008);
Byte 1EF92C: snapshot: FF execute: FE
Byte 1EF92E: snapshot: FF execute: FE
Byte 1EF930: snapshot: FF execute: FE
Byte 1EF932: snapshot: FF execute: FE
Byte 1EF934: snapshot: FF execute: FE
Byte 1EF936: snapshot: FF execute: FE
Byte 1EF938: snapshot: FF execute: FE
Byte 1EF93A: snapshot: FF execute: FE
Byte 1EF93C: snapshot: FF execute: FE
Byte 1EF93E: snapshot: FF execute: FE
Byte 1EF940: snapshot: FF execute: FE
Byte 1EF942: snapshot: FF execute: FE
Byte 1EF944: snapshot: FF execute: FE
Byte 1EF946: snapshot: FF execute: FE

and so on. Looks like the carry value is not respected. Also the return value is still not correct:
#002732 TRAP_AddWithCarry (001ED740, 001EFAB0, 00000001);
Register error at trap number 2732:
post_reg_snapshot:
00000000 00000001 00000000 00000000 0002282C 00000004 001ED740 00000000 001EB738
00000001 001EFA70 00000000 001EF9B0 001EF9F0 001EFA30 001EF748 001EF970 001EF9D0
001EF92C 00000200 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 000994B0 001EB6C4 001EFAD8 0005BF90
post_reg_execute:
00000000 00000000 00000000 00000000 0002282C 00000004 001ED740 00000000 001EB738
00000001 001EFA70 00000000 001EF9B0 001EF9F0 001EFA30 001EF748 001EF970 001EF9D0
001EF92C 00000200 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 000994B0 001EB6C4 001EFAD8 0005BF90
Byte 1ED741: snapshot: 67 execute: 68
Byte 1ED742: snapshot: 89 execute: 88
Memory Error at trap 2732
(you need to return the carry flag).

Furthermore, parameter checking (or implementation?) is not correct any more for TRAP_MultiplyWithRipple:

#002852 TRAP_MultiplyWithRipple(001EF7B0, 00000004, 00000008, 00000000);
java.lang.ArrayIndexOutOfBoundsException: 35
at bdvm.bdsvm_player_traps.MultiplyWithRipple(bdsvm_player_traps.java:847)
at bdvm.bdsvm_player_interface.TRAP_handler(bdsvm_player_interface.java:698)

Edit: Also, I thought that automatic loading of post-break-snapshots was convenient for testing the VM. Is there a reason to remove it already?

Oopho2ei
13th October 2008, 02:38
I don't mean to sound negative in any way, but I saw a few things :) I found that TRAP_AddWithCarry is broken now.

Furthermore, parameter checking (or implementation?) is not correct any more for TRAP_MultiplyWithRipple:

Those are the normal regressions when you make deeper changes in the code. I will fix it.

Edit: Also, I thought that automatic loading of post-break-snapshots was convenient for testing the VM. Is there a reason to remove it already?
Yes it is convenient and the code is not gone either (you can still load all different revisions we made from the repository). I didn't like the way it was implemented.

The signature generation in TRAP_PrivateKey seems to be working now with the Bouncycastle library. I have spent like 10 hours trying to figure out why the signature verification in the content code always failed. The reason was simply that in the Bouncycastle implementation "ECDSA" means = SHA-1 + ECDSA. What a waste of time :(

To install the library i have downloaded the bcprov-jdk16-141.jar (http://www.bouncycastle.org/download/bcprov-jdk16-141.jar) and placed the file in the directory "/usr/lib/j2sdk1.6-sun/jre/lib/ext". Furthermore i have added one line to the "java.security" located in the directory "/usr/lib/j2sdk1.6-sun/jre/lib/security" so it looks like this:
#
# List of providers and their preference orders (see above):
#
security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=com.sun.net.ssl.internal.ssl.Provider
security.provider.4=com.sun.crypto.provider.SunJCE
security.provider.5=sun.security.jgss.SunProvider
security.provider.6=com.sun.security.sasl.Provider
security.provider.7=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.8=sun.security.smartcardio.SunPCSC
security.provider.9=org.bouncycastle.jce.provider.BouncyCastleProvider
The last line is new ^

You can see if the signature verification succeeded by looking at the console output of the debugger when executing the BDSVM files from "The Day After Tomorrow":
#000496 TRAP_Random (00002348, 00000010);
#000497 TRAP_Sha (001EF924, 001EFB24, 00000020, 00000003);
#000498 TRAP_PrivateKey (00000000, 00005514, 00002348, 00000010, 00000000);
#000499 TRAP_DeviceDiscovery (00000001, 00000001, 001EF794, 001EF78C);
#000500 TRAP_Aes (0005B430, 0005B430, 00000001, 0004B470, 00000000);
#000501 TRAP_DeviceDiscovery (00000001, 00000002, 001EFCC8, 001EFCC4);
If the verification failed then the above TRAP_Aes call is replaced by another TRAP_DeviceDiscovery call.

Currently the debugger seems to run correctly up to the first TRAP_Finished without the help of snapshots. At least i get the impression by just looking at the console output.

To those java experts out there: Is there a way to add the Bouncycastle libraries without modifying the java installation on the user side? We only need the ECDSA implementation.

schluppo
13th October 2008, 03:29
Works fine for me. I'm glad that TRAP_PrivateKey is working now :)

I let the debugger run without guidance till the first call of TRAP_Finished and a quick compare of the snapshots 'post_trap_reg_002643.bin' and 'post_trap_mem_002643.bin' with the contents of memory and registers after unguided execution revealed lots of differences. Anyway, since the trap-execution is in correct order, I just hope/assume that these differences are stemming from normal (legitimate) changes in the random input data.

Feeding a memory-snapshot which is signalling event 0x220(0,1,n) to the debugger still does not get past the first TRAP_SlotRead. I assume that the data which is read from slot 0 should be of a specific pattern (which the debugger does not know yet).

#000252 TRAP-SlotAttach (00000000, 00000014);
#000253 TRAP-SlotRead (001EF964, 00000000);
#000254 TRAP_DeviceDiscovery (00000001, 00000001, 00022B48, 001EFA58);
#000255 TRAP_DeviceDiscovery (00000001, 00000002, 00022B48, 001EFA58);
#000256 TRAP_Finished ();

Edit: Warning - I just let "I Robot v1.02" run without guidance and even though I do not have the big stream file (BDMV\STREAM\00001.m2ts) which is being hashed by the content code, and the hash-result hence must have been wrong, the debugger reached TRAP_Finish with just a very minor change in the sequence of executed trap calls: #2052 to #2084 were omitted (these trap calls were just checking the slot-trap's parameter checks). So it seems to be the case, that bad trap-results do not necessarily lead to immediate shut down of the VM. This makes it harder to see whether traps (especially the ones with nondeterministic result, since snapshots help for the other traps) really behave well.

Also invoking event 0x110(0,1) on the memory/registers after unguided execution of "DAT v1.02" gives a different order of trap calls than in the snapshot package, indicating, that there might have been a trap-call with bad result.

Oopho2ei
13th October 2008, 15:20
I have rewritten the code for TRAP_AddWithCarry and TRAP_MultiplyWithRipple. The site where we host our repository ( assembla.com ) currently seems to have technical difficulties so here is the patch (http://uploaded.to/?id=ka3h2p). I will commit the changes as soon as the problems are solved.

Edit: there was still a bug in TRAP_AddWithCarry which is fixed now. So above is a new patch (only one line has changed).

Edit: The problems at assembla.com seem to be solved now. The latest changes are in the repository :)

Edit: TRAP_SlotAttach is likely completely wrong. The patent states:
Using the address and the specified length, the procedure then computes a cryptographic hash (e.g., using SHA-1) of the code. If the hash result does not match the value of the authorization hash stored in the slot then slot zero is attached and an error is returned.
What you do is comparing the specified content code section with a database of all code sections you have seen so far (array "slotCode[][]"). Can you explain to me why?

Edit: TRAP_SlotRead( *, 0xFFFFFFFF ) is wrong. This call writes the three dwords "0x00000000, 0x00000000, 0x00000007" to dst and returns unless the currently attached slot number is zero in which case it returns STATUS_INVALID_PARAMETER. It looks like the entire slot handling has to be rewritten :(

schluppo
13th October 2008, 19:59
This happens about 20 times:
#002843 TRAP_AddWithCarry (001EBC60, 001EDC60, 0000000F);
Register error at trap number 2843:
post_reg_snapshot:
00000000 00000000 001EBC60 001EFC60 001EFC60 0002282C 0000000F 00000190
00000190 001EFAD0 0000001F 000079E0 001EBAD0 001EDAD0 00000020 00000080
00000200 000088B8 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 000994B0 001EBA64 001EFAD8 00059488
post_reg_execute:
00000000 00000001 001EBC60 001EFC60 001EFC60 0002282C 0000000F 00000190
00000190 001EFAD0 0000001F 000079E0 001EBAD0 001EDAD0 00000020 00000080
00000200 000088B8 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 000994B0 001EBA64 001EFAD8 00059488
Memory Error at trap 2843
Seems like the current version returns 1 in R[1] all the time, whereas it should return 0 in case that the carry flag is not set and 1 only in the case that the carry flag is set.

Also:
#002963 TRAP_MultiplyWithRipple(001EDBE4, 001EEB5C, 0000002F, E9DE141D);
java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at bdvm.bdsvm_player_traps.MultiplyWithRipple(bdsvm_player_traps.java:688)
at bdvm.bdsvm_player_interface.TRAP_handler(bdsvm_player_interface.java:669)

Oopho2ei
13th October 2008, 20:53
Could you please post the values at src and dst so i can verify it? TRAP_AddWithCarry returns only '1' if the resulting number is one byte longer than both input numbers which can only happen if an overflow occurred.

You obviously have a modified version of the debugger (a branch). Why don't you upload your changes to the repository?

Edit: i found the problem. It's again the inability of java to tread unsigned numbers correctly. I have uploaded a workaround. Please report back if there are still issues with those traps. All our values are unsigned and java only knows signed numbers :rolleyes:

schluppo
13th October 2008, 23:53
I only re-added the automatic loading of post-break-snapshots so that I could let it run past the first TRAP_Finish again (otherwise there's no way to get to all those trap-tests). Since you did not like the way it was implemented, I did not want to add it to the repository again. Anyway, apart from that small change, I always use the newest version from the repository, especially I do not interfere with the implementation of traps or parameter checks.

TRAP_AddWithCarry and TRAP_MultiplyWithRipple are fine now. Next problematic one is this:

#003895 TRAP_Aes (001EE288, 001EE298, 00000000, 001EE238, FFF10000);
Register error at trap number 3895:
post_reg_snapshot:
00000000 00000000 00000000 00000000 0002282C 001EE298 001EE288 001EE238
001EE1D8 001EE248 001EE228 0003EC44 001EE198 001EE218 001EE158 00000200
00000200 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 000994B0 001EE0DC 001EFAD8 00062764
post_reg_execute:
00000000 80000001 00000000 00000000 0002282C 001EE298 001EE288 001EE238
001EE1D8 001EE248 001EE228 0003EC44 001EE198 001EE218 001EE158 00000200
00000200 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 000994B0 001EE0DC 001EFAD8 00062764

(bad parameter checking or bad treatmant of case OpOrKeyID=0xFFF10000)

another example:

#003899 TRAP_Aes (001EE288, 001EE248, 00000004, 001EE238, FFF10000);
Register error at trap number 3899:
post_reg_snapshot:
00000000 00000000 00000000 00000000 0002282C 001EE298 001EE288 001EE238
001EE1D8 001EE248 001EE228 00000000 001EE198 001EE218 001EE158 00000200
00000200 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 000994B0 001EE0DC 001EFAD8 00062978
post_reg_execute:
00000000 80000001 00000000 00000000 0002282C 001EE298 001EE288 001EE238
001EE1D8 001EE248 001EE228 00000000 001EE198 001EE218 001EE158 00000200
00000200 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 000994B0 001EE0DC 001EFAD8 00062978
Byte 1EE288: snapshot: 3A execute: 00
Byte 1EE289: snapshot: D7 execute: 00
Byte 1EE28A: snapshot: 7B execute: 00
Byte 1EE28B: snapshot: B4 execute: 00
...
Byte 1EE2C4: snapshot: 04 execute: 00
Byte 1EE2C5: snapshot: 72 execute: 00
Byte 1EE2C6: snapshot: 5D execute: 00
Byte 1EE2C7: snapshot: D4 execute: 00
Memory Error at trap 3899

And then TRAP_DeviceDiscovery (probably bad parameter check again?):


#004006 TRAP_DeviceDiscovery (00000002, 00000000, 001EE854, 001EE7D0);
Register error at trap number 4006:
post_reg_snapshot:
00000000 00000000 001EF850 0000000F 0002282C 001EE854 00000009 00000000
001EE854 00000000 00000080 00000027 07D6060D 00000000 00000000 FFFFFFC4
07D6060D 00000000 001EE7D0 0005CC60 001EF814 001EFAD0 00000000 00000000
001EE854 00000000 00000000 00000000 000994B0 001EE760 001EFAD8 0006CBB4
post_reg_execute:
00000000 80000001 001EF850 0000000F 0002282C 001EE854 00000009 00000000
001EE854 00000000 00000080 00000027 07D6060D 00000000 00000000 FFFFFFC4
07D6060D 00000000 001EE7D0 0005CC60 001EF814 001EFAD0 00000000 00000000
001EE854 00000000 00000000 00000000 000994B0 001EE760 001EFAD8 0006CBB4
Byte 1EE854: snapshot: 00 execute: 5C
Byte 1EE855: snapshot: 00 execute: AA
Byte 1EE856: snapshot: 00 execute: 14
Byte 1EE857: snapshot: 52 execute: 80
...
Byte 1EE8D0: snapshot: 00 execute: E6
Byte 1EE8D1: snapshot: 00 execute: 3C
Byte 1EE8D2: snapshot: 00 execute: D8
Byte 1EE8D3: snapshot: 00 execute: 27
Memory Error at trap 4006

Here the endianness of the result needs to be changed:

#004007 TRAP_DeviceDiscovery (00000002, 00000001, 001EE8D4, 001EE7D0);
Byte 1EE8D4: snapshot: 00 execute: 2A
Byte 1EE8D7: snapshot: 2A execute: 00
Byte 1EE8DC: snapshot: 00 execute: 02
Byte 1EE8DD: snapshot: 2C execute: 08
Byte 1EE8DE: snapshot: 08 execute: 2C
Byte 1EE8DF: snapshot: 02 execute: 00
Byte 1EE8E0: snapshot: 00 execute: 03
Byte 1EE8E3: snapshot: 03 execute: 00
Byte 1EE8E4: snapshot: 00 execute: 01
Byte 1EE8E7: snapshot: 01 execute: 00
Memory Error at trap 4007

...


#004436 TRAP_DeviceDiscovery (00000001, 00000001, 001EF814, 001EF810);
Register error at trap number 4436:
post_reg_snapshot:
00000000 80000001 80000001 001EF7E8 001EF7E8 0002282C 001EF810 001EF814
00000005 0006DD30 00000000 0003EC54 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 000994B0 001EF7E8 001EFAD8 0006D7E0
post_reg_execute:
00000000 00000000 80000001 001EF7E8 001EF7E8 0002282C 001EF810 001EF814
00000005 0006DD30 00000000 0003EC54 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 000994B0 001EF7E8 001EFAD8 0006D7E0
Byte 1EF812: snapshot: 00 execute: 01
Byte 1EF813: snapshot: 2A execute: 1C
Byte 1EF814: snapshot: 07 execute: 00
Byte 1EF815: snapshot: D8 execute: 00
...
Byte 1EF92C: snapshot: 75 execute: FA
Byte 1EF92D: snapshot: F2 execute: F3
Byte 1EF92E: snapshot: 13 execute: 72
Byte 1EF92F: snapshot: 8A execute: 6F


OK, apart from these two traps (TRAP_Aes and TRAP_DeviceDiscovery), there is only the problem with

IC: 37177656 Trap #2037: trap_0x420(1efd08,ffffffff)= TRAP-SlotRead

remaining.

Oopho2ei
14th October 2008, 02:18
Two mistakes were in the parameter check documentation/implementation of TRAP_Aes and TRAP_DeviceDiscovery. I have already committed the patch to fix those issues. The big endian issue is fixed too (not committed yet).

#004436 TRAP_DeviceDiscovery (00000001, 00000001, 001EF814, 001EF810);
I don 't know why this call should fail. My best guess is that buf and len are too close together but i couldn't find and check for that but i should be able to find the problem soon. Some checks are done deep inside the trap implementation which is a bit more difficult to study.

OK, apart from these two traps (TRAP_Aes and TRAP_DeviceDiscovery), there is only the problem with

IC: 37177656 Trap #2037: trap_0x420(1efd08,ffffffff)= TRAP-SlotRead

remaining.
I think the current implementations for TRAP_Slot* are all wrong. Take a look at page 5 of the patent (http://uploaded.to/?id=za7x4t) to see how complex the slot handling actually is. I have already expressed my concern in posting #220 (http://forum.doom9.org/showpost.php?p=1196007&postcount=220).

schluppo
14th October 2008, 02:43
Referring to posting #220: Of course the hashing for slots still needs to be done. I have no information about how the slot-traps work on the inside, so I could only do what the snapshots showed, the 'security code' treatment hence is rudimentary. Never meant to create any other impression.

Apart from that, I noticed one more bug in TRAP_Aes:

#003977 TRAP_Aes (001EFA90, 001EFA91, 00000002, 001EFAC0, FFF10000);
Register error at trap number 3977:
post_reg_snapshot:
00000000 80000001 80000001 0002282C 001EFA90 001EFAC0 0002282C 10010000
00000002 00063B24 00000000 0003EC44 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 000994B0 001EFA6C 001EFAD8 00061B60
post_reg_execute:
00000000 00000000 80000001 0002282C 001EFA90 001EFAC0 0002282C 10010000
00000002 00063B24 00000000 0003EC44 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 000994B0 001EFA6C 001EFAD8 00061B60
Byte 1EFA90: snapshot: 00 execute: D1
Byte 1EFA91: snapshot: 00 execute: 08
Byte 1EFA92: snapshot: 00 execute: 6A
Byte 1EFA93: snapshot: 00 execute: 97
...
Byte 1EFAAC: snapshot: 00 execute: 2B
Byte 1EFAAD: snapshot: 02 execute: 4A
Byte 1EFAAE: snapshot: 29 execute: 48
Byte 1EFAAF: snapshot: DC execute: 48
Memory Error at trap 3977


#003978 TRAP_Aes (001EFA90, 001EFA9F, 00000002, 001EFAC0, FFF10000);
Register error at trap number 3978:
post_reg_snapshot:
00000000 80000001 80000001 0002282C 001EFA90 001EFAC0 0002282C 10010000
00000002 00063B24 00000000 0003EC44 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 000994B0 001EFA6C 001EFAD8 00061BB4
post_reg_execute:
00000000 00000000 80000001 0002282C 001EFA90 001EFAC0 0002282C 10010000
00000002 00063B24 00000000 0003EC44 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 000994B0 001EFA6C 001EFAD8 00061BB4
Byte 1EFA90: snapshot: 00 execute: 8E
Byte 1EFA91: snapshot: 00 execute: 59
Byte 1EFA92: snapshot: 00 execute: 9F
Byte 1EFA93: snapshot: 00 execute: B9
...
Byte 1EFAAC: snapshot: 00 execute: 0C
Byte 1EFAAD: snapshot: 02 execute: 1F
Byte 1EFAAE: snapshot: 29 execute: 51
Byte 1EFAAF: snapshot: DC execute: D3
Memory Error at trap 3978

Oopho2ei
14th October 2008, 22:13
The TRAP_Aes parameter checking should be fine now. I had forgotten to copy an important check from my notes :rolleyes:
I am still not able to fix the checks for TRAP_SlotRead and TRAP_DeviceDiscovery though i made some observations. It's an illegal internal state which causes the failure of both calls. For TRAP_DeviceDiscovery i suggest we add a rule which lets the call fail if the "number of bytes written" pointer <len> points to a dword inside the output (which is written to <buf>). This has to be done on the trap implementation side because the interface (which does all the parameter checks) doesn't know the length of the output.

Regarding the slots i couldn't find any call of TRAP_SlotWrite which actually reads the data from <newContents>. Either all those calls i've checked have failed internally or the trap implementation of my player is wrong. I could see that slot 0 is read from non-volatile memory and that all 256 bytes are subsequently copied to the specified vm memory address.

Finally i suggest a command line interface for the debugger. The idea is to provide some basic commands to:
- set some environment variables (like where is the BDSVM or the snapshot directory)
- set/clear breakpoints (execution or data)
- execute n instructions or trap calls
- load a snapshot
- compare memory or register content with a snapshot
- dump or change parts of memory or registers
- record a instruction trace
- ...

All the snapshot stuff should be removed from the code. The user can run a script (maybe Tcl (http://www.usenix.org/publications/library/proceedings/tcl97/full_papers/lam/lam.pdf)?) which does all the work. :script:

Oopho2ei
15th October 2008, 11:56
Oopho2ei:

I've been reading your forum, reminds me of the good old 8-bit days and the reverse engineering I did back then. Anyway, I know nothing of java at all, but I certainly know C, and assembler.All my sources are OpenSource, and I must admit it is very tempting, but I am not sure where to start, or if the reference docs that you have done (?) that I would need are easy to get/read/understand. I know DVD and CSS fairly well (..now) but BD is new.
You can find the most important facts here (http://svn.assembla.com/svn/bdplus/trunk/doc/). A sample c(++) program is here (http://svn.assembla.com/svn/bdplus/trunk/bdvm.c).

The implementation consists of 3 basic steps:
1. implement the instruction processing (description of the instructions can be found here (http://svn.assembla.com/svn/bdplus/trunk/doc/instructions/list.txt) and search the web for the Hennessy and Patterson's DLX architecture)
2. trap processing (description of the traps can be found here (http://svn.assembla.com/svn/bdplus/trunk/doc/traps/), in the patent (http://uploaded.to/?id=za7x4t) and in this thread)
3. event handling (still under research)
4. debugging (we use snapshots and traces from a licensed player which can be found here (http://forum.doom9.org/showpost.php?p=1183289&postcount=130))

If you have any questions first look at this document (http://securityevaluators.com/pdf/spdc_aacs_2005.pdf) and the patent (http://uploaded.to/?id=za7x4t). If you can't find an answer there post your question here.

schluppo
15th October 2008, 23:33
There seems to be a new variant of BD+ out: http://forum.slysoft.com/showthread.php?t=21177

This is a nice oppurtunity for me to list the previous 'versions' (currently there are at least 65 titles which employ BD+):


The first version was on just the first twenty or so BD+ titles (such as "Day After Tomorrow", "Fantastic Four: Rise of the Silver Surfer" etc., maybe on all the titles released in 2007?). This version did not use TRAP_MediaSHAFileHash so that it was possible to first copy a disc to an image with AACS removed but BD+ still intact and then mount or burn this image and play it with a licensed player.
The second version of BD+ fixed this bug and used TRAP_MediaSHAFileHash to verify that the inserted disc still contained AACS (actually TRAP_MediaSHAFileHash just verifies that small parts of a few files on the disc have a hash which is identical to a hardcoded byte-sequence in the content code). Apart from that, there don't seem to be much differences between the first and the second version of BD+. This version appeared early in 2008 and was used till around the middle of 2008. (Maybe with a minor update around March 2008, I think I remember AnyDVDHD treatment of the BD+-version on "Hitman" to be problematic for a while.)
The next version of BD+ appeared in June 2008 (first title was "Jumper" - AnyDVDHD was not able to handle this for a while). I don't have much information about what may have changed with this version of BD+.
The newest 'version' just appeared a few days ago on "Die Another Day". Rather than it being a really new version of BD+, it seems to me as if this is just the first title with BD+ where the main feature is split across several files and not stuffed into one big file. This could become important when implementing the way in which the data is passed to the VM in execution of event 0x220.

It would be interesting to get more information about the newer versions of BD+, such as having a trace of trap-calls for a movie as new as or newer than e.g. "Jumper".

On another note, I am currently idle but willing to do more trap-analyzing whenever any snapshots or similar are handed to me :) The debugger may currently not run with correct memory contents to the first TRAP_Finished on it's own (because of the well known TRAP-SlotRead(*,ffffffff) problem). Otherwise, it would be possible to really start treating the event handling, since we could try and just feed any event to the VM (after it has initialized itself on it's own in the first ~2600 trap-calls) and see what happens.

Oopho2ei
16th October 2008, 13:53
It's really amazing how you and gioowe can read the hidden messages in those slysoft forum postings. When i look through my crystal ball at the posting i only see that he had chocolate cakes this morning and that his grandma is turning 80 next week. Maybe i need to look at the least significant bits of the fox image in the top left corner :rolleyes:

Seriously we should focus on the correct implementation of all traps before we start anything new. When i started looking at events i was under the impression that the trap implementation is almost complete (e.g. with the details from the patent) and the code is in a good condition but i was really wrong. There is still a lot to be done.
I am currently looking at TRAP_SlotAttach and TRAP_SlotWrite will be next. In the meantime you should review the code and correct the short trap descriptions you can find in bdsvm_player_traps.java. I will upload new snapshots when i think it is appropriate.

Oopho2ei
16th October 2008, 15:25
This is a description of how TRAP_SlotAttach works. The example below is for the first call of TRAP_SlotAttach in "The Day After Tomorrow":

call: TRAP_SlotAttach( slot = ?, codeLen = 0x0000000C )
PC = 0001AC70h (already incremented)

That's the data which is hashed with SHA-1:
00 01 ac 6c 00 00 00 00 ; PC-4 ( & 0x3FFFFC ) and instruction filter (IF)
6f bd 00 1c e0 3d 00 08 e3 fd 00 04 d4 20 00 00 ; 16 bytes from 0x1000
e4 00 04 10 58 1f 00 00 e4 00 04 20 58 1f 00 00 ; #codeLen dwords from PC-4
e4 00 04 30 58 1f 00 00 e4 00 02 30 58 1f 00 00
e4 00 80 10 58 1f 00 00 e4 00 80 20 58 1f 00 00
The resulting SHA-1 hash:
h = 78f623b22178c6150c420a3bff949c85ae7f75bd
SHA-1 hash from hash:
h' = 3ac6e39ffddc1c66429aae0600c61bf0ec340d8a
This is the resulting hash to be compared against the hash stored in the slot. I have no idea why the hash is hashed again (makes no sense to me). The offset of the hash within the slot is probably 0x30. I couldn't reliably determine the beginning and the end of the slot so the address (0x30) is a good guess based on some assumptions.

Edit: the unknown dword is the instruction filter (IF)

tteich
16th October 2008, 15:57
This is a description of how TRAP_SlotAttach works. The example below is for the first call of TRAP_SlotAttach in "The Day After Tomorrow":

call: TRAP_SlotAttach( slot = ?, codeLen = 0x0000000C )
PC = 0001AC70h (already incremented)

That's the data which is hashed with SHA-1:
00 01 ac 6c 00 00 00 00 ; PC-4 ( & 0x3FFFFC ) and unknown dword
6f bd 00 1c e0 3d 00 08 e3 fd 00 04 d4 20 00 00 ; 16 bytes from 0x1000
e4 00 04 10 58 1f 00 00 e4 00 04 20 58 1f 00 00 ; #codeLen dwords from PC-4
e4 00 04 30 58 1f 00 00 e4 00 02 30 58 1f 00 00
e4 00 80 10 58 1f 00 00 e4 00 80 20 58 1f 00 00
The resulting SHA-1 hash:
h = 78f623b22178c6150c420a3bff949c85ae7f75bd
SHA-1 hash from hash:
h' = 3ac6e39ffddc1c66429aae0600c61bf0ec340d8a
This is the resulting hash to be compared against the hash stored in the slot. I have no idea why the hash is hashed again (makes no sense to me). The offset of the hash within the slot is probably 0x30. I couldn't reliably determine the beginning and the end of the slot so the address (0x30) is a good guess based on some assumptions.

Perhaps they apply a Hash chain as authentication mechanism? http://en.wikipedia.org/wiki/Hash_chain

Oopho2ei
16th October 2008, 19:07
Perhaps they apply a Hash chain as authentication mechanism? http://en.wikipedia.org/wiki/Hash_chain
I don't know how a valid slot looks like so it might be possible that h' wasn't compared against the hash from the slot but against the hash from the hash from the slot. So you could be right. It makes me wonder how the entire system looks like if there is an insecure channel between the slot memory and the BD+ core. Maybe the slot data is stored inside a smartcard? It would also mean that the content code can only successfully attach to this slot twice.

Some details about TRAP_SlotWrite:

TRAP_SlotWrite(UINT8 *newContents);

p = some address inside the player (volatile) memory

- copy 0x10 bytes from newContents+0x20 to p
- copy 0x14 bytes from newContents+0x30 to p+0x10
- copy 0xB4 bytes from newContents+0x4C to p+0x2C
So the data at
newContents+0x00 ... newContents+0x1F and
newContents+0x44 ... newContents+0x4B is ignored and could be reserved memory (eg. for the hash) inside the slot. Altogether it adds up to 256 which is supposed to be the size of a slot.

Oopho2ei
16th October 2008, 21:48
This is what i assume is the structure of a slot. The example data is from slot 0 (DAT).

Addr : Data - Description
-----------------------------------------------------------------------------------
0000 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - Creator Media ID ?
0010 : 1d 2f c6 74 62 fd f9 86 35 7a 8f 80 8f a1 29 8b - Last Update Media ID ?
0020 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - Slot Private Data ?
0030 : a9 78 8b 0b b2 8d e0 e1 3f 40 af de e9 a3 31 6b 25 3c fa 21 - Attach Authentication Hash
0044 : 00 00 00 00 - ?
0048 : 00 00 00 8e - Last Update Sequence Counter ?
004C : d4 8e 75 57 c6 e6 0b 46 a7 14 60 99 46 ff 65 0d \
005C : fe e5 48 8a ee dd 48 ad dd 47 8d 1d 87 53 d7 04 |
006C : 59 5b 6d b1 57 b6 04 d9 aa 32 da c6 ff 9b fe 02 |
007C : 1f b2 1b 8e 5b 61 88 0d 85 8e 72 d1 5c c7 6f f2 |
008C : ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |
009C : ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff } Data Payload (180 bytes)
00AC : ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |
00BC : ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |
00CC : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
00DC : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
00EC : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
00FC : 00 00 00 00 /
Schluppo could you please start implementing the slot traps from the above notes so i can focus on research? :)

schluppo
17th October 2008, 00:12
I changed TRAP-SlotAttach according to posting #230. For the first call in "DAT v1.02", this gives the same h' as in the posting, so it seems to be fine. Then the new code compares the 20 bytes that are h' with the 20 bytes starting at 0x30 in slot number <slot> (where <slot> is the first parameter of the trap). If they are equal, the global variable AttachedSlot is set to <slot> and STATUS_OK is returned, otherwise AttachedSlot is set to 0 and STATUS_INVALID_PARAMETER is returned.

About TRAP-SlotWrite: What does the trap do if there is no slot attached? And since you changed the default-value of AttachedSlot (meaning 'no slot attached') to 0, what happens, if slot 0 is supposed to be attached?

tteich
17th October 2008, 13:33
I found an interesting patent which explains a bit how the different .svm files are used: http://www.freepatentsonline.com/EP1841120.html

00000.svm seems to contain code common to all players, and is supposed to select a different (player dependent) xxxxx.svm for known players, or a common file for all unknown players. The selected file contains security checks and content scrambling code.

Oopho2ei
17th October 2008, 15:25
I changed TRAP-SlotAttach according to posting #230. For the first call in "DAT v1.02", this gives the same h' as in the posting, so it seems to be fine. Then the new code compares the 20 bytes that are h' with the 20 bytes starting at 0x30 in slot number <slot> (where <slot> is the first parameter of the trap). If they are equal, the global variable AttachedSlot is set to <slot> and STATUS_OK is returned, otherwise AttachedSlot is set to 0 and STATUS_INVALID_PARAMETER is returned.
Thanks. I have made some changes on your code. Could you please run your tests again and see if everything is still alright? :rolleyes:

About TRAP-SlotWrite: What does the trap do if there is no slot attached? And since you changed the default-value of AttachedSlot (meaning 'no slot attached') to 0, what happens, if slot 0 is supposed to be attached?
I am trying to figure this out now.

I found an interesting patent which explains a bit how the different .svm files are used
Thanks a lot. I think it explains even more. Look at page 40 (FIG. 11) of the pdf version (http://uploaded.to/?id=1dn4ix). This is probably the player certificate which we get from TRAP_DeviceDiscovery with parameters dev = 1 (player?) and qID = 1 and 2. The first dword is the length which is obviously correct.

Edit: From this patent i can also tell that the 'S' in BDSVM stands for "Secure" (and not "Secret" like i thought).

Edit: FIG.5 (p.34) and FIG.6 (p.35) illustrate the event handling and the final correction of broken segments in the decrypted video and audio stream. The process is described starting with page 13. To see the differences in the output for "The Day After Tomorrow" look at posting #13 (http://forum.doom9.org/showpost.php?p=1174977&postcount=13).

schluppo
17th October 2008, 18:16
Your changes are fine, as far as I can see. :)

Oopho2ei
17th October 2008, 19:04
Your changes are fine, as far as I can see. :)
Good! ;)

Some scenarios which should give you an idea how the AttachedSlot mechanism works.

- the first trap which is executed is TRAP_SlotWrite:
-> writes to slot 0

- slot 0 is attached ( TRAP_SlotAttach( 0, 4 ) finished successfully ):
-> the following TRAP_SlotWrite writes to slot 0

- TRAP_SlotAttach( 0x1F3, 0c0C ) succeeded and the following trap "TRAP_SlotAttach( 0x1F3, 0c0C )" failed ( hash missmatch ):
-> the following TRAP_SlotWrite writes to slot 0

- TRAP_SlotAttach( 0x1F3, 0c0C ) succeeded:
-> TRAP_SlotWrite writes to slot 0x1F3
-> another TRAP_SlotWrite does not write to slot 0 (so probably writes to slot 0x1F3 as well)
-> the following TRAP_SlotRead calls read the contents of slots 0 (unchanged) and 0x1F3 correctly
If you need more information just ask.

Edit: As you might have noticed the (Creator/Last Update) Media ID in the Slot is the Volume ID. For "The Day After Tomorrow" it is 1D2FC67462FDF986357A8F808FA1298B.

Edit: i've added a new class to handle the slots. All changes can be viewed here (http://trac.assembla.com/bdplus/timeline) as usual.

Accident
17th October 2008, 23:35
The DLX reference documentation mention that R0 is always set to 0 and any writes are ignored. Is this the case here as well, should I force R0 read-only?

Oopho2ei
18th October 2008, 01:36
The DLX reference documentation mention that R0 is always set to 0 and any writes are ignored. Is this the case here as well, should I force R0 read-only?
Good question. All i know is that the licensed player i study has memory reserved for r00. I have placed a check in our java debugger to see if r00 has at any point a value different from zero but it seems this is never the case. So at least the compiler doesn't use it to store values. I suggest you output a warning when it's different from zero.

Some news about TRAP_SlotAttach and TRAP_SlotRead with parameter slot=0xFFFFFFFF. When TRAP_SlotRead is called with slot=0xFFFFFFFF it writes 3 dwords (DW0 DW1 DW2) to dst. DW1 and DW2 are two bytes B1 and B2 which were expanded to UINT32 and DW0 seems to be originally a 16 or 32 bit value. TRAP_SlotRead only seems to read and expand those values but TRAP_SlotAttach really changes them if called with slot = 0xFFFFFFFF which is supposed to be the way a new slot is allocated.

The output of TRAP_SlotRead before TRAP_SlotAttach (both with slot = 0xFFFFFFFF):
00000000 00000000 00000007

Looking at the source for DW0, DW1 and DW2 the following things happen now when TRAP_SlotAttach is called with slot = 0xFFFFFFFF:
if ( B2 > 2 )
{
B2 = B2 - 1;
}
B1 = B2;
Initially B1=0 and B2=7 so the result is B1=6 and B2=6. Also DW1 now contains a slot number. When TRAP_SlotRead is called now (with slot = 0xFFFFFFFF) the result is:
000001F2 00000006 00000006
When i try to read the slot 0x1F2 now with TRAP_SlotRead i get the output:
0000:0010 1d 2f c6 74 62 fd f9 86 35 7a 8f 80 8f a1 29 8b
0000:0010 1d 2f c6 74 62 fd f9 86 35 7a 8f 80 8f a1 29 8b
0000:0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0040 00 00 00 00 00 00 00 00 00 00 01 15 00 00 00 00
0000:0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
So the TRAP_SlotAttach did create a new slot and attached it as well (otherwise we would get 256 zeros). The "Creator Media ID" (first 16 bytes) and the "Last Update Media ID" are both set to the AACS Volume ID. For some reason the "Last Update Sequence Counter" already contains a value 0x00000115.

Now when i again call TRAP_SlotAttach followed by a call of TRAP_SlotRead (both with slot=0xFFFFFFFF) i get the result:
000001F1 0000005 00000005

So from these observations i can tell that TRAP_SlotAttach really allocates a new slot when called with parameter slot = 0xFFFFFFFF. But TRAP_SlotRead does not read the currently attached slot when called with parameter slot = 0xFFFFFFFF as described in the patent. Instead it returns three dwords which seem to describe what slot is currently attached and how many slots have been allocated or still can be allocated . Or something similar :rolleyes:

Edit: If attached successfully with TRAP_SlotAttach( 0x1F3, 4 ) then the output if TRAP_SlotRead( 0x100, 0xFFFFFFFF ) is: 000001F3 0000000 00000007
So this leaves now little doubt that the first dword always is the currently attached slot identifier.

bshep
18th October 2008, 02:05
So from these observations i can tell that TRAP_SlotAttach really allocates a new slot when called with parameter slot = 0xFFFFFFFF. But TRAP_SlotRead does not read the currently attached slot when called with parameter slot = 0xFFFFFFFF as described in the patent. Instead it returns three dwords which seem to describe what slot is currently attached and how many slots have been allocated or still can be allocated . Or something similar

This is just a wild guess but seems to fit:
DW0 = last allocated or currently attached slot ( you can test this by attaching a different slot and seeing if reading from slot 0xFFFFFFFF still give the last allocated slot or the currently attached slot )
DW1 and DW2 = seems to mean the number of slots available, would be interesting to see what happens if they are 0 and you try to allocate a new slot, if this asumption is true then 8 slots are avaiable to be allocated.

Edit: Just saw your edit, what does the test imply about DW1 and DW2, how many slots were already allocated in that test?

Accident
18th October 2008, 06:04
Sorry for the noise, but I have now got it running to this point:


[dlx] 0001A6F8 (I=18):ADDIE(R1 = R0 + 0007): 7 = 0 + 7
[dlx] 0001A6FC (I=38): SDW ([R29 + 10] = R1 ): 001EFF50 = 00000007
[dlx] 0001A700 (I=2D): JAL (R31 = 0001A704 ; PC += 04E8): 0001ABEC = PC + 1256
[dlx] 0001ABEC (I=39): TRAP([110]): TRAP 272
[dlx] 0001ABF0: TRAP 00000110 (272)
[dlx] TRAP_Aes()
[bdtest] executed 417 instructions


I am not sure it is all correct, but to verify I need to add TRAP_Aes first, since the snapshot is taken after the trap (correct yes?)

Since there is no stack, how are the arguments to TRAP_Aes passed? (or any trap for that matter).

(Edit1)
Ok, the param_check has details for at least Aes.
Here (http://svn.assembla.com/svn/bdplus/trunk/doc/traps/param_check/0110.txt)

(Edit2)
Although, not what to do with return code, but I will assume R1 as per DLX specification.

(Edit3)
My first trap to Aes return INVALID_PARAMETERS. So I need to do some debugging

Oopho2ei
18th October 2008, 12:35
Edit: Just saw your edit, what does the test imply about DW1 and DW2, how many slots were already allocated in that test?
Well DW2 is decremented each time a new slot is allocated. It's initial value is 7 so no new slots were allocated at that time. I am not sure when happens when i try to allocate a new slot and DW2 = 2. My guess about DW1 is that it shows the number of the private slot that is currently allocated if you think of a few (~ 6) consecutive slots as private slots. DW2 seems to limit the number of additional slots the content code can allocate in in one session (when watching the movie once). I have to run further tests. If you have read something in the patents which matches above observations please tell me.

Sorry for the noise, but I have now got it running to this point:
You should use the post-trap snapshots for all trap calls at the moment. You don't need to implement the parameter checking or the actual trap implementation yet. The stack pointer is (convention) r29 and the return value is stored in r01. Also you maybe don't want to send a message to the console for every instruction. When the initialization of the content code is complete (first call of TRAP_Finished) you will have executed millions of instructions and several thousands trap calls. :rolleyes:
You should first make sure that the instruction processing is working by comparing your program counter, instruction register and the timer with the traces given in the packages you can find in posting #130 (http://forum.doom9.org/showpost.php?p=1183289&postcount=130). If you fixed all the bugs (if any) you should proceed implementing the parameter checking for all traps and verify with the post trap register snapshot that r01 was set correctly.

Edit: You have probably missed to look at these (http://svn.assembla.com/svn/bdplus/trunk/doc/dlx/registers.txt) notes. ;)

Accident
18th October 2008, 12:55
You should first make sure that the instruction processing is working by comparing your program counter, instruction register and the timer with the traces given in the packages you can find in posting #130

Can I confirm that 000000.dat is AFTER the first trap executes.

I can use the register.dat to confirm my instructions, sans R1 return code. So I will do that right now.

It only prints all instructions if I ask it to, so far I just tell it to run " 1 trap" and then it stops. I have a CVS, but what is the deal with "secrecy"? Is there need to stay anonymous? (Referring to Jon and CSS)

I had read those notes and forgot, I was following the wikipedia notes on DLX more :) My bad, apologies. Also, your instructions list for arithmatic shift has "see note below" without a note :), but the wiki docs had it.

-----------------------------

Ok so the result is as expected, I guess it calls Aes with op=7 to test it. Please let me know if I am too noisy.


[dlx] 0001ABEC (I=39): TRAP([110]): TRAP 272
[dlx] ** TRAP 00000110 (272) return: 0001ABF0
[dlx] TRAP_Aes(): 80000001
[dlx] getPC (0001ABF0)
[bdtest] reached TRAP at 418: PC=0001ABF0.
[dlx] Comparing registers with 'dat/post_trap_snapshots/post_trap_reg_000000.bin'
Reg : VM Regs == Loaded Regs
R0 : 00000000 == 00000000 ; OK
R1 : 80000001 == 80000001 ; OK
R2 : 001EFF6C == 001EFF6C ; OK
R3 : 00005550 == 00005550 ; OK
R4 : 00005570 == 00005570 ; OK
R5 : 00005560 == 00005560 ; OK
R6 : 00017A50 == 00017A50 ; OK
R7 : 00017A4C == 00017A4C ; OK
R8 : 00000000 == 00000000 ; OK
R9 : 00000000 == 00000000 ; OK
R10 : 00000000 == 00000000 ; OK
R11 : 00000000 == 00000000 ; OK
R12 : 00000000 == 00000000 ; OK
R13 : 00000000 == 00000000 ; OK
R14 : 00000000 == 00000000 ; OK
R15 : 00000000 == 00000000 ; OK
R16 : 00000000 == 00000000 ; OK
R17 : 00000000 == 00000000 ; OK
R18 : 00000000 == 00000000 ; OK
R19 : 00000000 == 00000000 ; OK
R20 : 00000000 == 00000000 ; OK
R21 : 00000000 == 00000000 ; OK
R22 : 00000000 == 00000000 ; OK
R23 : 00000000 == 00000000 ; OK
R24 : 00000000 == 00000000 ; OK
R25 : 00000000 == 00000000 ; OK
R26 : 00000000 == 00000000 ; OK
R27 : 00000000 == 00000000 ; OK
R28 : 00001160 == 00001160 ; OK
R29 : 001EFF40 == 001EFF40 ; OK
R30 : 001EFF84 == 001EFF84 ; OK
R31 : 0001A704 == 0001A704 ; OK
[bdtest] executed 418 instructions, 1 trap


Having fun so far..

Oopho2ei
18th October 2008, 13:42
I have a CVS, but what is the deal with "secrecy"? Is there need to stay anonymous? (Referring to Jon and CSS)
Could you register at www.assembla.com and tell me your nickname so i can add you to the project. I make daily backups.
The goal of this project is to support BD+ in linux and other open source operating system so you can watch your movies without proprietary software on your pc. Reverse engineering to achieve interoperability is normally considered legal although patent owners usually try to fight this so you should stay anonymous.
Both AACS and BD+ were designed with renewability in mind so the system can quickly recover from a player compromise and leaked key material which is a major advantage over css. The key material which i provide for debugging will very likely soon be revoked so this implementation will very likely stop working for newly released movies. So this project is no threat to the security of the system. But both AACS and BD+ can only renew protection for movies released after the compromise.
Finally Slysoft has successfully reverse engineer BD+ a while ago and they sell their product commercially.

Please let me know if I am too noisy.
It's the purpose of this thread to guide the implementation efforts. It's likely that more people have the same questions. If you don't spam the thread with new postings it's fine. You can also write me private messages.

Edit: revision 86 now has experimental support for proper slot handling. @Schluppo and others: please run some tests :)

schluppo
18th October 2008, 18:13
Still:
#002037 TRAP-SlotRead (001EFD08, FFFFFFFF);
Register error at trap number 2037:
post_reg_snapshot:
00000000 00000000 00000000 10020000 00000101 00000001 0002282C 001EF9DC
001EFADC 00000100 00000000 0003E01C 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00001160 001D02CC 001EFD1C 0007C4D4
post_reg_execute:
00000000 80000001 00000000 10020000 00000101 00000001 0002282C 001EF9DC
001EFADC 00000100 00000000 0003E01C 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00001160 001D02CC 001EFD1C 0007C4D4
Byte 1EFD09: snapshot: 00 execute: 02
Byte 1EFD0A: snapshot: 00 execute: 28
Byte 1EFD0B: snapshot: 00 execute: 2C
Byte 1EFD13: snapshot: 07 execute: 00
Memory Error at trap 2037
All other calls of TRAP-Slot* behave as in the snapshots ("DAT v1.02") with the revision 86 of the debugger.

Oopho2ei
18th October 2008, 19:40
#002037 TRAP-SlotRead (001EFD08, FFFFFFFF);
All the time is was looking for a reason why this call should fail and why our debugger lets it execute successfully. :stupid:
The constant 0xFFFFFFFF gets signed extended when it is compared with a variable of type long. I made the same mistake several times so the last patch (to revision 87) fixes multiple bugs. Could you please check how the debugger behaves now after TRAP_Finished when you pass events (eg. write the event id and parameter manually to 0x00-0x030)?

schluppo
18th October 2008, 20:52
OK, until the first TRAP_Finished, only TRAP_Random, TRAP_DeviceDiscovery(1,3) and TRAP_PrivateKey give different results than the snapshots (due to 'random' data in these results).

I ran the debugger without guidance to the first break and then invoked some events with following results:

event 0x110(0,0xFF000) - TRAP_0x20 and then TRAP_Finished are executed. This event behaves as in the snapshot-package.
event 0x210(0,1) - Just TRAP_Finished is executed. This event behaves NOT as expected.
event 0x110(0,1) - Executes the whole bunch of trap testing. This event behaves as in the snapshot-package.
event 0x220(0,1,n) - Just TRAP_Finished is executed. This even behaves NOT as expected.

So, why do some events behave differently than in the snapshots?

1) Either there is an unnoticed fault/bug in the trap-treatment leading to a 'bad' state of memory when the first TRAP_Finished is reached. This bug could only be in the three traps which are introducing random data (since the other traps behave as in the snapshots).
2) Or the behaviour of the events could depend on the order in which they are executed. This would mean, that for instance event 0x220(0,1,n) can not be invoked unless event 0x110(0,1) has happened earlier. It seems to be somehow reasonable that BD+ first wants the traps to be tested before it is willing to decrypt movie data. Nevertheless, I tried and first let the debugger run to the first TRAP_Finished and then fed event 0x110(0,0xFF000) to the code. Then I invoked event 0x210(0,1) on the resulting state. This is the same order of events as in the snapshots and still event 0x210(0,1) behaved bad.
3) I may have made a mistake while doing these tests. I will double-check my method of event-invoking now.

Oopho2ei
18th October 2008, 21:04
Thanks. I will make a longer snapshot package now. In the meantime please look at figure 5 and 6 in this (http://uploaded.to/?id=1dn4ix) document and read the corresponding text (if you haven't done that already).

Edit: A new package (v1.03) for "The Day After Tomorrow" is available now: http://uploaded.to/?id=5dwn30

I compressed the snapshots with the diffarchive tool i introduced a few weeks ago. It was written by one of our anonymous contributers and manages to shrink the 50GB of snapshots to less than 20MB. There is no need to extract the archives on disc although the tool provides you with that option.

For every archive i've included the first snapshot so you can test if you handle the archive properly. The first snapshot is always compared against the empty snapshot (filled with zeros). A description about the archive structure can be found here (http://svn.assembla.com/svn/bdplus/trunk/diffarchive/). I also wrote a small readme which contains the syntax in EBNF.

@Schluppo: i am currently implementing support for the archives in the debugger as a new class "snapshots". Four instances (objects) of this class "snapshot_trap_mem", "snapshot_trap_reg", "snapshot_break_mem" and "snapshot_break_reg" for every snapshot type we have. The constructor gets the filename on instantiation and eg. with "snapshot_break_reg.next()" would you switch to the next snapshot. The current snapshot memory can be accessed with eg. "snapshot_break_reg.memory". I hope it get it working soon you can start your analysis of the event handling :)

Accident
19th October 2008, 05:21
It was going well, until trap milestone 484 showed I forgot instruction 0x1E. :)

Are there any saves of what the PC should be at each post_trap_mem milestone? My program runs on its on, and the registers all compare correctly (except R1 from the trap), it fixes R1, loads the next core and resumes.

But somewhere along the line the PC becomes very repetitive, until eventually it gets stuck on trap PC=0001AC74 (looping back to the trap). It stays here until post_trap_mem_002029.bin where PC goes really high (somewhere in the 3GB area, handled with the address masking, but there are only zero's there). So I must be doing something wrong earlier perhaps, which could be that my PC is lost.

I also do nothing with WD yet, apart from initialising it. I assume I should still be able to finish all the post_trap_mem milestones?

Boring output:

[bdtest] reached TRAP at 37019913:2026 PC=0001AC74.
[bdtest] loading 'dat/post_trap_snapshots/post_trap_mem_002026.bin'
[bdtest] reached TRAP at 37019929:2027 PC=0001AC74.
[bdtest] loading 'dat/post_trap_snapshots/post_trap_mem_002027.bin'
[bdtest] reached TRAP at 37021630:2028 PC=0001AC04.
[bdtest] loading 'dat/post_trap_snapshots/post_trap_mem_002028.bin'
[trap] trap_DeviceDiscovery()
[bdtest] reached TRAP at 37023357:2029 PC=0001ABFC.
[bdtest] loading 'dat/post_trap_snapshots/post_trap_mem_002029.bin'
[dlx] FE80103D (I=2C): J (PC += FFFFFFFC): FE80103D = FE801041 + FFFFFFFC
[endless loop]


Edit:
I wonder if it is related to port 164 (http://forum.doom9.org/showthread.php?p=1187583#post1187583) but checking my JMP, I get the following values:

U_Jimm = I & 0x3FFFFFF; // 25 bit constant
S_Jimm = (I & 0x2000000) ? ( (I & 0x3ffffff) | 0xFC000000) : (I & 0x3FFFFFF);

U_Jimm 0245AE89 S_Jimm FE45AE89
[dlx] 001EFC6C (I=2C): J (PC += FE45AE89): 0024AAF8 = 001EFC70 + -28987767

If Unsigned IMM is 0245AE89, then Signed Imm extended to 32bit becomes FE45AE89. Then if PC is 001EFC70, the out come is indeed: 0024AAF8.