Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > General > Decrypting

Reply
 
Thread Tools Search this Thread Display Modes
Old 11th September 2008, 21:59   #121  |  Link
Oopho2ei
Guest
 
Posts: n/a
Some notes about how to implement Trap_AES(0x001EF748, 0x001EF748, 0x00000080, 0x00016764, 0xFFF10001) and similar.

Remember the declaration: UINT32 TRAP_Aes(UINT8 *dst, UINT8 *src, UINT32 len, UINT8 *key, UINT32 opOrKeyID);

The last parameter (opOrKeyID) is 0xFFF10001 so we have to decrypt [len] 128bit blocks of [*src] using ECB mode with the 16-byte key [*key] and write the results to [*dst]. In ECB mode every 128 bit block is decrypted independently from all other blocks so i will only demonstrate the decryption steps for a single block.

Example snapshots: http://uploaded.to/?id=7sz6pu
This archive contains two snapshots. One was taken directly before the Trap_AES call we are looking at and one directly afterwards. You can use this to verify your implementation.

Let's look at address 0x001EF748 to find the first data block we have to decrypt and at address 0x00016764 we will find the key we have to use:
Code:
data: c5 ed 4c 67 e4 45 ca e9 40 e0 b7 89 3a c9 54 a6
key : e6 d3 0c b1 d4 29 4c 88 e4 66 29 06 34 35 25 be
Our memory content has been converted from big endian to little endian which breaks the decryption process using default aes implementations but we can simply revert the conversion:
Code:
data: 67 4c ed c5 e9 ca 45 e4 89 b7 e0 40 a6 54 c9 3a
key : b1 0c d3 e6 88 4c 29 d4 06 29 66 e4 be 25 35 34
We apply this to all 80h blocks (16 bytes each) we have to decrypt and then pass the result to a default aes-128-ecb implementation. In this example I simply put the first block in a file source.bin and called openssl from the command line:
Code:
openssl aes-128-ecb -d -K b10cd3e6884c29d4062966e4be253534 -iv 00000000000000000000000000000000 -in source.bin -out result.bin
The result is:
Code:
9d df 63 6e 37 cf b6 c6 dc b0 2d c3 a3 ca a7 f1
Now all that's left to do is to convert this block from big endian to little endian again and write the result to 0x001EF748. You can verify these steps by looking at the two snapshots i posted above. If the decryption completed without any errors we return 0 (return values are written into r01)

Quote:
Originally Posted by bmnot View Post
Okay, I made things a little simpler:
The binaries, a readme and an ant build script are included in this updated version:
I got it running!!

Some suggestions:
- for branches you better show the absolute address and the not the relative address
- could you automatically load the snapshots?
- add a data view window (maybe double the number of columns for the register view and cut its height by half to make space for a small data view window below)
- reset the watchdog timer with ever trap call to 0x7FFFFFFF
- display the parameters of the trap call directly before it is executed (e.g. by commenting the values in the stack window)
- support of data breakpoints
- color the registers red which have been changed since the last step/run
- maybe assign some hotkeys

Again good work!

Last edited by Oopho2ei; 13th September 2008 at 23:45.
  Reply With Quote
Old 12th September 2008, 10:09   #122  |  Link
derbeDeus
Registered User
 
Join Date: Mar 2008
Posts: 98
Quote:
Originally Posted by sakman View Post
Thanks derbeDeus. Matches what I saw looking at several .svm files from different discs. I did notice that the 4 bytes of "?unk9" changed to 2000h with that bunch of March/April 2008 discs (Hitman, Jumper, Alvin, etc.). Interesting that those discs also broke the initial BD+ support in AnyDVDHD.
I think the change was later, with Alvin and AVP2 (as they also changed to MKBv7).
In my copy of Hitman it is 1 (!?)

As a side note, Fox has still MKBv7 for its titles, while others (Lionsgate) changed to 8 and 9. Probably they trust their BD+ code more than AACS protection. duh
derbeDeus is offline   Reply With Quote
Old 12th September 2008, 15:40   #123  |  Link
gioowe
Registered User
 
Join Date: Jun 2007
Posts: 95
trap addition

Maybe someone would like to implement the following trap:

UINT32 TRAP_DebugLog(UINT8 *txt, UINT32 len);
It's the trap number 0x8010.

It seems to just log debug information from the BD+ VM to somewhere.
txt is a pointer within VM space to a character sequence (single byte) with length len (not null terminated).

Maybe the BD+ implementations use it and we'll see them send some information
gioowe is offline   Reply With Quote
Old 12th September 2008, 17:29   #124  |  Link
Oopho2ei
Guest
 
Posts: n/a
More and more people keep asking the same question about why a particular trap call didn't change anything in the guest system (that 4MB memory + registers you see).
The answer: The traps are executed on the host system side in which the guest system is 'embedded'. So a trap can make changes in the host system (e.g. replace some bytes in the audio or video stream) which are invisible to you because i only show you the embedded guest system for obvious reasons. So when you don't see any changes in the snapshots before and after a trap execution the trap can still have made changes in the host system.

Quote:
Originally Posted by gioowe View Post
UINT32 TRAP_DebugLog(UINT8 *txt, UINT32 len);
It's the trap number 0x8010.

It seems to just log debug information from the BD+ VM to somewhere.
txt is a pointer within VM space to a character sequence (single byte) with length len (not null terminated).
This would be an example of such a trap. It changes the host system but not the guest system. Thank you gioowe for sharing this information.

Edit: schluppo has found a mistake in the post_trap_snapshot archive from posting #114 (post_trap_mem_002.bin and post_trap_reg_002.bin were wrong). I have recorded a second independent series of snapshots and replaced the link accordingly. Note that starting with post_trap_mem_004.bin the two series differ at address 0x4514 and 0x4518-0x451B so the third call of TRAP_DeviceDiscovery seems to introduce random data? Maybe someone could check who is writing to these locations. We need data breakpoints too, bmnot

Last edited by Oopho2ei; 12th September 2008 at 21:45.
  Reply With Quote
Old 12th September 2008, 22:00   #125  |  Link
schluppo
Guest
 
Posts: n/a
Here are some more details on the traps :

Code:
instruction #00417:

trap_110(0x1A64C,0x5550,1,0x5570,7)

returns 0x80000001

no memory / registers changed
Code:
instruction #00475:

trap_110(0x1A64C,0x5550,1,0x5560,8)

returns 0x80000001

no memory / registers changed
Code:
instruction #00839:

trap_520(1,1,0x21A0,0x1EFF84)

returns 0

writes 284/0x11C bytes to 0x21A0 (these 284 bytes seem to contain around 84 bytes header).
the last parameter holds available / written length.
second parameter is the question-id or op-id.
maximum reply length for questions / ops #1 and #2 is 0x140, for question /op #3, it's 0x1000.
Code:
instruction #02319:

trap_520(1,2,0x2358,0x1EFF84)

returns 0

writes 292/0x124 bytes to 0x2358 (these 292 bytes seem to contain around 88 bytes header).
Code:
instruction #03539:

trap_520(1,3,0x4514,0x1EFF84)

returns 0

has 4096 bytes reserved (as 0x00) at 0x4514, writes only 60/0x3C bytes to 0x4514.
Code:
instruction #04289:

trap_110(0x156DC,0x156DC,3,0x571C,4)

returns 0

writes 48 bytes to 0x156DC.
Code:
instruction #04360:

trap_110(0x17764,0x17764,2,0x16764,5)

returns 0

writes 32 bytes to 0x17764.
Code:
instruction #04435:

trap_110(0x16764,0x56B0,1,0x16764,5)

returns 0

writes 16 bytes to 0x16764.
Code:
instruction #04527:

trap_540(0x1B428,1,0,0x1EFF54,0x22060)

returns 0

this trap writes 0x74F9C bytes to 0x22060. fourth parameter adress contains number of written bytes, fifth parameter is the dst adress.
I could not find any documented trap in the patent text that would fit to trap_540.

Decryption of the result of trap_540 happens by the following sequences of trap_110 and trap_230. Blocks of 2kb are decrypted by each iteration:
Code:
instruction #13536:

trap_110(0x1EF748,0x1EF748,0x80,0x16764,0xFFF10001)

returns 0

writes 2048 (0x80 times 16) bytes to 0x1EF748.
Code:
instruction #13547:

trap_230(0x22060,0x1EF748,0x200)

returns 0

writes 2048 (0x200 times 4) bytes to 0x22060.
Code:
instruction #22408:

trap_110(0x1EF748,0x1EF748,0x80,0x16764,0xFFF10001)

returns 0

writes 2048 (0x80 times 16) bytes to 0x1EF748.
Code:
instruction #22419:

trap_230(0x22860,0x1EF748,0x200)

returns 0

writes 2048 (0x200 times 4) bytes to 0x22860.
Code:
instruction #31289:

trap_110(0x1EF748,0x1EF748,0x80,0x16764,0xFFF10001)

returns 0

writes 2048 (0x80 times 16) bytes to 0x1EF748.
Code:
instruction #31300:

trap_230(0x23060,0x1EF748,0x200)

returns 0

writes 2048 (0x200 times 4) bytes to 0x23060.
Code:
instruction #40161:

trap_110(0x1EF748,0x1EF748,0x80,0x16764,0xFFF10001)

returns 0

writes 2048 (0x80 times 16) bytes to 0x1EF748.
Code:
instruction #40172:

trap_230(0x23860,0x1EF748,0x200)

returns 0?

writes 2048 (0x200 times 4) bytes to 0x23860?
This finishes the first 16 traps.

Last edited by schluppo; 13th September 2008 at 23:42.
  Reply With Quote
Old 12th September 2008, 22:22   #126  |  Link
Oopho2ei
Guest
 
Posts: n/a
Quote:
Originally Posted by schluppo View Post
Code:
instruction #04527:

trap_540(0x1B428,1,0,0x1EFF54,0x22060)

returns 0

the snapshots indicate that this trap changes 477301 bytes of the vm memory, so i guessed that the snapshot is bad and stopped here.
I could not find any documented trap in the patent text that would fit to trap_540.
Sorry, I forgot to upload the 00001.svm. This trap (trap_540) seems to load the second section of the second file (00001.svm) at the address given by the last parameter (0x22060). The section is being decrypted later (see posting #114)

Here it is (finally): http://uploaded.to/?id=tn6kle

Thanks for reminding me.
  Reply With Quote
Old 12th September 2008, 23:08   #127  |  Link
schluppo
Guest
 
Posts: n/a
The difference in your snapshot series appears since these bytes hold a timestamp.

0C09D807 2D353013 => 12-09-2008 19:48:53:45
0A09D807 550F0014 => 10-09-2008 20:00:15:85

Edit (answering to Oopho):

-i.e.
0x0C=12, 0x09=09, 0x07D8=2008
0x13=19, 0x30=48, 0x35=53, 0x2D=45
0x0A=10, 0x09=09, 0x07D8=2008
0x14=20, 0x00=00, 0x0F=15, 0x55=85

-Further, it's hard, to make out a pattern in the outputs of the calls of TRAP_DeviceDiscovery(..). In the case, that the question has an answer of max-length 0x140, the output seems to have a header of around 90 bytes containing (each word of length 32 bits, little endian, parameters are _not_ identical to - but probably depend on - the trap parameters):
Code:
<length_of_result>, 0x100010, 0x4, param2, param3, param4, ~16 times: 0x00000000, <manufacturing_date>
The ~200 bytes following the header are incomprehensible to me without any hint of interpretation. Anyway, they are the 'answer' to the 'question' asked to the device.

I'd say that more calls of this trap need to be snapshot in order to get a better base for estimations.

-More details on the traps here: http://uploaded.to/?id=xqibd0

Edit: updated text file with info on all the first 16 traps.

Last edited by schluppo; 14th September 2008 at 00:13.
  Reply With Quote
Old 13th September 2008, 11:00   #128  |  Link
Oopho2ei
Guest
 
Posts: n/a
Thank you. Were you able to trace the key from posting #121 back to a trap result?

Quote:
Originally Posted by schluppo View Post
I'd say that more calls of this trap need to be snapshot in order to get a better base for estimations
I will try to record a long series of snapshots automatically now.

In general for those traps you have already implemented you should still load the corresponding snapshot for verification. If yours and mine don't match you probably made a mistake. I provide these snapshots primarily for you to test your implementations. But they of course also useful to study traps which are currently unknown.

Last edited by Oopho2ei; 13th September 2008 at 11:02.
  Reply With Quote
Old 13th September 2008, 14:37   #129  |  Link
schluppo
Guest
 
Posts: n/a
The key from post #121 is the result of this trap:
Code:
instruction #04435:

trap_110(0x16764,0x56B0,1,0x16764,5)

returns 0

writes these 16 bytes to 0x16764:

E6D30CB1 D4294C88 E4662906 343525BE
trap_110/TRAP_Aes is called three times in a row, first returning 48, then 32 and finally 16 bytes, the calls are:
Code:
trap_110(0x156DC,0x156DC,3,0x571C,4)
...
71 non-trap instructions
...
trap_110(0x17764,0x17764,2,0x16764,5)
...
75 non-trap instructions
...
trap_110(0x16764,0x56B0,1,0x16764,5)
  Reply With Quote
Old 14th September 2008, 00:20   #130  |  Link
Oopho2ei
Guest
 
Posts: n/a
These are the first 5000 snapshots. Each snapshot was taken automatically after every trap execution. I have made multiple independent packages you can download.

Warning: You may not mix snapshots from different series therefor i have removed the link to the old snapshot series in posting #114. If you have already implemented Trap_DeviceDiscovery you have to set the timestamp according to the snapshot series you use.

Attention: All the snapshots are little endian (swapped for performance reasons) but the DLX is a big endian processor. So depending on your implementation might have to swap the byte order when loading a snapshot.

Note:: Starting with package version v1.03 we use the new diffarchive format to store the snapshots. A sample implementation can be found here.

current packages:
Package (v1.03) for "The Day After Tomorrow": http://uploaded.to/?id=5dwn30
Package (v1.02) for "I Robot": http://uploaded.to/?id=svpn7q

old/deprecated packages:
Package (v1.02) for "The Day After Tomorrow": http://uploaded.to/?id=g93e2g
Package (v1.01) for "The Day After Tomorrow": http://uploaded.to/?id=yodttu
Package (v1.00) for "I Robot": http://uploaded.to/?id=mej65b

Current package contents:
Code:
/
AACS/
post_trap_snapshots/
post_break_snapshots/
BDSVM/
traces/
aacskeys_output.txt
title.txt
version.txt
How to use these snapshots:
- implement a counter 'cnt' (or any other name) which is incremented after every execution of cmd39. The initial value of the counter is 0.
- load the files with filenames [snapshot_reg] and [snapshot_mem] with sprintf(snapshot_reg,"post_trap_reg_%03d.bin",cnt); sprintf(snapshot_mem,"post_trap_mem_%03d.bin",cnt); from the trap_snapshots directory
- after your implementation of the trap terminates compare your memory and register file with the snapshot you have loaded
- if your memory and register file contents doesn't match the provided snapshot then print a warning (or whatever you think is appropriate) and overwrite your register file and memory contents with the snapshot and continue execution
- use the post-break snapshots in the same way when the watchdog timer reaches zero (or becomes negative)

Benefits:
- automatic testing of your implementation on a real world example
- program execution up to the point where video/audio playback starts
- black box analysis of currently unknown traps by looking at input and output

Last edited by Oopho2ei; 20th October 2008 at 13:33. Reason: added new packages
  Reply With Quote
Old 14th September 2008, 21:38   #131  |  Link
Oopho2ei
Guest
 
Posts: n/a
Another mistake i made was found: cmd3A is INSTF so it sets the instruction filter value and not the watchdog timer. I have corrected this immediately in posting #27. For a short explanation of what INSTF does please see posting #44

Thanks for reporting this!
  Reply With Quote
Old 15th September 2008, 00:52   #132  |  Link
schluppo
Guest
 
Posts: n/a
Here is an edited version of bmnot's quite usefull java debugger (I apologize in advance in case that anyone is offended by my bad coding style or use of bmnot's ideas):

http://uploaded.to/?id=ph017s

Things I changed:

- Treatment of parts of trap_110, treatment of trap_520.
- No treatment of actual AES functionality of trap_110 (didn't have time to implement this in java yet). No treatment of trap_540 and trap_230.
- Automatic input of "post_trap_mem_xxx" and "post_trap_reg_xxx" when untreated traps appear (Note that all the snapshots need to be located in the working dir - i.e. the dir containing the .jar - at this point).
- I added a "trap counter" to the debug-gui.
- After pressing "run", the VM will run till the 472th trap is reached (or till PC goes out of sync or breakpoint is reached).
- After that, pressing "run" will run till the next trap is reached (or till PC goes out of sync or breakpoint is reached).
- Whenever the memory is being dumped manually, a binary statistic of trap calls (trap_calls.bin) is written to the working dir.

Things to do:

- Further treatment of traps.
- Comparison of snapshots with results of treated traps.
- (Separate option to create trap-calls statistic.)
- (Separate option to select source dir for automatic snapshot input.)

Things learned:

- The debugger is quite slow on inputting PC-traces. 4,000,000 PC values take 10min+.
- The first ~2,080,000 instructions of the BD+-VM contain 477 trap calls:
Code:
239 times trap_110
234 times trap_230
003 times trap_520
001 times trap_540
- The first 477 traps do the following: 1) Setup the device 2) get some basic info on the device 3) let the device decrypt a key (taken from the .svm or from the device?) 4) load ~500kb of data from somewhere. 5) decrypt this data using the key from step 3) and also using the device's XOR-capabilities (?).
- Using the snapshots, the PC is not getting out of sync in the first 2 million instructions, indicating that the debugger's VM is quite correct (apart from the traps).

Some questions:

- What exactly does trap_540 do? I couldn't find the byte-sequences that it writes to the VM's memory anywhere in 00001.svm. Is it XORing the data from 00001.svm with the first parameter's value (0x30303030) before writing it to the VM's memory?
- Are you sure, trap_230 is pure XOR? The snapshots indicate that trap_230 is sometimes changing more than len (third parameter) times 4 byte (could also be some mistake in the snapshots / my calculations).

Last edited by schluppo; 15th September 2008 at 04:21.
  Reply With Quote
Old 15th September 2008, 04:05   #133  |  Link
schluppo
Guest
 
Posts: n/a
The traps from the previous post are followed by:
Code:
  • trap #477 at ic: 2081538 is trap_530(0,0x2514,0x2000); returns 0; writes 0x2000 bytes to 0x2514.
  • trap #478: trap_110(0x24FC,0x7D360,1,0x7D350,6); writes 16 bytes to 0x24FC.
  • trap #479: trap_110(0x24EC,0x7D360,1,0x7D350,5); writes 16 bytes to 0x24EC.
  • ...
  • trap #484: trap_110(0x249C,0x7D360,1,0x7D350,0); writes 16 bytes to 0x249C.
  • trap #485: trap_110(0x24FC,0x7D360,1,0x7D350,6); writes 16 bytes to 0x24FC.
  • trap #486: trap_110(0x24EC,0x7D360,1,0x7D350,5); writes 16 bytes to 0x24EC.
  • ...
  • trap #491: trap_110(0x249C,0x7D360,1,0x7D350,0); writes 16 bytes to 0x249C.
  • trap #492 at ic: 2687589 is trap_520(1,2,0x1EFA94,0x1EF890->0x190); returns 0; identical behaviour as previous trap_520 with same params :)
  • trap #493 at ic: 2687599 is trap_140(0x1ef894,0x1efa94,7c,3); returns 0; writes 0x7c bytes to 0x1ef894. this seems indeed to be trap_sha.
After trap #493, PC goes out of sync for me even when loading post_493 snapshots. The jump (BEQZ r6, 0x28) at 0x95064 (ic: 2691187) is not taken, but should be taken according to the PC-trace (r6 = 0xFF in my run).
  Reply With Quote
Old 15th September 2008, 08:04   #134  |  Link
Oopho2ei
Guest
 
Posts: n/a
Quote:
Originally Posted by schluppo View Post
- What exactly does trap_540 do? I couldn't find the byte-sequences that it writes to the VM's memory anywhere in 00001.svm. Is it XORing the data from 00001.svm with the first parameter's value (0x30303030) before writing it to the VM's memory?
Trap_540 is UINT32 TRAP_MediaReadFile(UINT8 *FileName, UINT32 SectionNumber, UINT32 Unknown, UINT32 *len, UINT8 *dst);

It reads [len] bytes(?) of stection [SectionNumber] from BDSVM/[FileName].svm and writes them to [dst].

Quote:
Originally Posted by schluppo View Post
Are you sure, trap_230 is pure XOR? The snapshots indicate that trap_230 is sometimes changing more than len (third parameter) times 4 byte (could also be some mistake in the snapshots / my calculations).
Yes it's pure Trap_Xor but i am currently not sure about the length.

Quote:
Originally Posted by schluppo View Post
The jump (BEQZ r6, 0x28) at 0x95064 (ic: 2691187) is not taken, but should be taken according to the PC-trace (r6 = 0xFF in my run).
Then you have a bug in your command dispatcher or and in at least one of the command handlers. Try to trace back why r06 is not zero. Btw I have heard reports of people who are already using snapshot number i (i>2000).

Edit: (removed)

Last edited by Oopho2ei; 15th September 2008 at 18:46.
  Reply With Quote
Old 15th September 2008, 18:36   #135  |  Link
Oopho2ei
Guest
 
Posts: n/a
The problem is the pc trace wasn't recorded at the same time as the snapshots. Through the traps "random" data is injected into the guest system which ultimately influences the instruction flow like you have experienced. So if that happens you either have to resynchronize your offset in the pc_trace.bin using the next snapshot data or simply don't use the pc trace at all. I haven't expected such non-deterministic behavior.

To provide evidence for this theory i made several pc traces and compared them. They all differ at offsets 01922478h, 019952D8h and higher. Please check if this matches your results.

I am sorry for all the confusion. It was my mistake (again)

Last edited by Oopho2ei; 15th September 2008 at 18:56.
  Reply With Quote
Old 16th September 2008, 01:23   #136  |  Link
schluppo
Guest
 
Posts: n/a
I finished implementation of trap_230 (Trap_XorBlock) and trap_540 (Trap_MediaReadfile) (implementation is correct, according to Oopho's snapshots).

Next: Implementation of trap_110 (Trap_AES) cases 0xFFF10000 and 0xFFF10001.

Last edited by schluppo; 16th September 2008 at 04:46.
  Reply With Quote
Old 16th September 2008, 03:48   #137  |  Link
frogman
I swallow bugs!
 
frogman's Avatar
 
Join Date: Jan 2007
Location: Whitehouse corner Office
Posts: 49
QUOTE Oopho2ei. I haven't expected such non-deterministic behavior.
It's a Sony!
Looking good boy's.
frogman is offline   Reply With Quote
Old 16th September 2008, 05:27   #138  |  Link
schluppo
Guest
 
Posts: n/a
I finished the Implementation of trap_110 (Trap_AES) cases 0xFFF10000 (AES_Encrypting) and 0xFFF10001 (AES_Decrypting).

This means, that the VM is now running correctly without using any snapshots for 2,081,361 instructions containing 477 trap calls. It initializes the device, obtains AES-keys, loads ~500kb from 00001.svm and then decrypts these ~500kb.

Dumping memory after the 477th call gives a snapshot that is identical to Oopho's post_trap_mem_476.bin (he starts counting at 0) and the registers are identical to post_trap_reg_476.bin at this point. Also the PC is in sync.

http://uploaded.to/?id=gn1mmh
Sorry for the terrible source.
  Reply With Quote
Old 16th September 2008, 09:36   #139  |  Link
derbeDeus
Registered User
 
Join Date: Mar 2008
Posts: 98
well, you didn't really implemented the aes trap for player keys, did u? hehe
and i don't think discovery will work with other titles either; you see... there's a key in the data for dev1/qid3
derbeDeus is offline   Reply With Quote
Old 16th September 2008, 16:49   #140  |  Link
Oopho2ei
Guest
 
Posts: n/a
Quote:
Originally Posted by schluppo View Post
I finished the Implementation of trap_110 (Trap_AES) cases 0xFFF10000 (AES_Encrypting) and 0xFFF10001 (AES_Decrypting).
Looks good so far. Please don't treat the output of some traps as constants if you are not sure they really are. Also what currently matters is that (1) your trap implementation works for all occurrences in the snapshots and (2) that you extensively comment your code. It's not important that you write perfect java code. As long as the code is sufficiently commented more experienced programmers can quickly fix all the mistakes you made.

Also could you please add your modified version to our repository? The codebase from Disabled is currently broken and hasn't been updated for a while.
  Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 08:56.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.