|
Luigi Auriemmaaluigi.org (ARCHIVE-ONLY FORUM!) |
|
It is currently 19 Jul 2012 19:40
|
View unanswered posts | View active topics
Author |
Message |
Revolty
|
Post subject: Algorithm works, but no love from GS. Posted: 21 Dec 2007 06:58 |
|
Joined: 21 Dec 2007 04:27 Posts: 16
|
Hi Luigi,
Im really new to programming (got VB 2 weeks ago) so the questions might be really dumb, and i've no idea how to write anything in C.
Anyways, Im using VB.Net and imports an DLL, Gsmsalg.dll that i found in BF2AL's open-source. Im not sure you are the one that compiled it or not, but it does reutrn a valid response for method 0 & 2. If i use method 1 I get the same respons as for method 0.
The game Im using it for are Battlefield 2, that supose to use method 1. But in the header of gsmalg.h it says that method 2 can be used for any game, so i guess i can use that?
But when i send this packet:
Code: "\basic\gamename\battlefield2\enctype\2\validate\" & CALCULATED RESPONSE & "\final\list\gamename\battlefield2\where\final\"
And decode the bytes received to ASCII it gives some random characters like this:
Quote: ??4?????????????}????
And thats all.. the rest is 8000x Chr(0), if i replace the calculated responce with something else like u8bzykso i dont get anything as response so i guess something is allright atlest..
/EDIT
I just noticed there was a few more packets to receive.
Do you know how to either compile your method 2 decoder to an .Dll that i can use, or if the code is ported to VB somewere.
|
|
Top |
|
|
|
|
|
|
|
aluigi
|
Post subject: Posted: 21 Dec 2007 11:34 |
|
Joined: 13 Aug 2007 21:44 Posts: 4068 Location: http://aluigi.org
|
Uhmmm the response for enctype 0, 1 and 2 is ever different so if you receive the same one for both 0 and 1 means there is something wrong.
if you want to query the master server you can use both enctype 1 or 2, enctype 2 is better since is the one used usually for the games and produces a smaller amount of data to receive.
Now, after your query the master server will send you the encrypted data which contains the sequence of 4 bytes for IP and 2 for port in big endian order.
In attachment I have added a basic tool which demonstrate the usage of gsmsalg and enctype2_decoder in the most simple way (NRXWKV is the challenge and d4kZca the gamekey used).
Compiling the source as a dll is very simple (the following example is with mingw/gcc):
gcc -s -shared -o enctype2_decoder.dll enctype2_decoder.c enctype_shared.c
Naturally remember that the GPL license must be respected also with dll in case you want to redestribuite your work ("dynamic linking creates a derivative work, and so any program designed to run with a GPL-ed DLL, must be GPL itself")
Attachments: |
test.zip [10.4 KiB]
Downloaded 238 times
|
|
|
Top |
|
|
Revolty
|
Post subject: Posted: 21 Dec 2007 11:54 |
|
Joined: 21 Dec 2007 04:27 Posts: 16
|
Hi,
That clear things up a bit. But i think you forgot to attacht the tool (or i must have been up way to long).
I used MiniGW like you said;
gcc -s -shared -o enctype2_decoder.dll enctype2_decoder.c enctype_shared.c
And got a DLL that i reference too like i do with the gsmalg like so:
Code: Private Declare Auto Function Encode Lib "C:\enctype2_decoder.dll" _ Alias "enctype2_decoder" (ByVal gamekey() As Byte, ByVal buffer() As Byte, ByVal buffer_len As Long) As String
Then i used following code: Code: Dim GameKey() As Byte = Encoding.Default.GetBytes("hW6m9a") Dim Buffer() As Byte = Encoding.Default.GetBytes(strReceived) Dim Length As Long = Buffer.Length Dim hmm As String = Encode(GameKey, Buffer, Length)
When i debug it i get:
Quote: "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
StackTrace: at WindowsApplication1.Form1.Encode(Byte[] gamekey, Byte[] buffer, Int64 buffer_len)
Im not sure if i should use Byte when calling the Dll but thats what i do with the Gsmalg and its working (allso tryed string but with same result). Neither am i sure if lenght is correct, half of the received packets are NULL data but VB include it as lenght.
Last edited by Revolty on 21 Dec 2007 14:08, edited 1 time in total.
|
|
Top |
|
|
aluigi
|
Post subject: Posted: 21 Dec 2007 14:07 |
|
Joined: 13 Aug 2007 21:44 Posts: 4068 Location: http://aluigi.org
|
This is very strange, the attachment is online but is not visible... mah
The link is the following:
/download.rar?id=29
|
|
Top |
|
|
aluigi
|
Post subject: Posted: 21 Dec 2007 14:16 |
|
Joined: 13 Aug 2007 21:44 Posts: 4068 Location: http://aluigi.org
|
the third parameter is not an integer but a pointer to integer.
in short that value must contain the size of the buffer before you call the function and when this one returns it will contain the new size of the data pointed by your hmm
|
|
Top |
|
|
Revolty
|
Post subject: Posted: 21 Dec 2007 15:06 |
|
Joined: 21 Dec 2007 04:27 Posts: 16
|
But if haven't got this wrong;
Your 'data' is equal to the packets that i receive from GS, that i declare as Buffer. Then you use "len = sizeof(data) - 1" which equals to my "Length = Buffer.Length - 1"?
So when i call the function, Length will be = encrypted packets lenght, but when the function is executed the "Lenght" can change to the value that enctype2_decoder want it to.
Isn't that right?
Im just making sure i diden't confuse you with calling my 'data' as 'buffer'.
|
|
Top |
|
|
aluigi
|
Post subject: Posted: 21 Dec 2007 20:08 |
|
Joined: 13 Aug 2007 21:44 Posts: 4068 Location: http://aluigi.org
|
"sizeof(data) - 1" is a C instruction for getting the lenght of a [] array, so in VB it should be only Buffer.Length
And yes, when enctype2_decoder is executed the length parameter will be changed by it.
|
|
Top |
|
|
Revolty
|
Post subject: Posted: 22 Dec 2007 02:05 |
|
Joined: 21 Dec 2007 04:27 Posts: 16
|
I tested with the values within test.c, like so;
Code: Private Declare Ansi Function Encode Lib "C:\enctype2_decoder.dll" _ Alias "enctype2_decoder" (ByVal gamekey() As Byte, ByVal buffer() As Byte, ByVal buffer_len As Int32) AS BYTE() <--?
Dim data As Byte() = _ {&HEA, &HC8, &H4, &H96, &H67, &H19, &H99, &H64, &HF5, &H2F, &HAB, &H35, &H50, &HF4, &H3F, &H4B, _ &H8, &H6, &H89, &HD8, &H71, &HE6, &HF9, &HFA, &H2B, &H55, &H18, &H14, &H31, &H3F, &HC6, &H87, _ &H38, &H62, &HB8, &HD6, &HB1, &H72}
Dim len As Int32 = data.Length Dim key() As Byte = Encoding.Default.GetBytes("d4kZca")
Dim Pointer = Encode(key, data, len)
It looks like the problem is how i receive the decoded result, as 'String' i get corrupted memory, i changed it to 'Byte[]' and i now get different error message:
Quote: Cannot marshal 'return value': Invalid managed/unmanaged type combination.
When i send data to gsmalg i use 'Byte[]' instead of C's unsigned char, and that work well. But with the decoder it dont seem to be able to cast result right? I've google the issue n it seems like the right way to do is receive as 'variant' but that wont work either (plues vb changes variant to object). Isn't the return value a byte array?
|
|
Top |
|
|
evan1715
|
Post subject: Posted: 22 Dec 2007 02:33 |
|
Joined: 05 Oct 2007 01:20 Posts: 402 Location: Florida
|
1. shouldn't this be under programming?
2. vb looks like easy html, hmm o_O
cheers :)
|
|
Top |
|
|
aluigi
|
Post subject: Posted: 22 Dec 2007 15:43 |
|
Joined: 13 Aug 2007 21:44 Posts: 4068 Location: http://aluigi.org
|
all the data handled there is BYTE (aka unsigned char) so don't use String, never.
Anyway in your example the third parameter is still wrong because it's not a pointer.
Take a look to the following link or search VB integer pointer on Google:
http://p2p.wrox.com/topicindex/39551.htm
|
|
Top |
|
|
Revolty
|
Post subject: Posted: 22 Dec 2007 16:29 |
|
Joined: 21 Dec 2007 04:27 Posts: 16
|
Ah.. changed ByVal to ByRef and now its working.
Guess I'll spend the night with this then..
Code: printf("\n- IP list:\n"); for(l = p + len; (p + 6) < l; p += 6) { printf("%02hhu.%02hhu.%02hhu.%02hhu %04hu\n", p[0], p[1], p[2], p[3], (p[4] << 8) | p[5]);
Thanks!!
|
|
Top |
|
|
aluigi
|
Post subject: Posted: 22 Dec 2007 17:35 |
|
Joined: 13 Aug 2007 21:44 Posts: 4068 Location: http://aluigi.org
|
naaa this is the most simple part.
In short you must just get the IP addresses and ports from the buffer.
The p I use there is a pointer but you can use other ways for doing it (like an int which is incremented of 6 for each IP/port)
IP = p[0].p[1].p[2].p[3]
port = (p[4] * 256) + p[5]
remember that usually len is longer than the 4+2 blocks so you must not consider the last part if can't contain 6 bytes.
|
|
Top |
|
|
Revolty
|
Post subject: Posted: 23 Dec 2007 11:49 |
|
Joined: 21 Dec 2007 04:27 Posts: 16
|
Yes that wasn't hard it looks so complicated in C :)
Code: For i As Integer = 0 To len Step 6 ServerList.Add( _ Asc(P(i)) & "." & _ Asc(P(i + 1)) & "." & _ Asc(P(i + 2)) & "." & _ Asc(P(i + 3)) & ":" & _ Asc(P(i + 4)) * 256 + Asc(P(i + 5))) Next Now gsmalg & decoder works fine, but still no serverlist, o well it looks like it but theres 25 of them and its not IP:s. Im sending this packet (5nioxk5R is the key from gsmalg) Code: \basic\gamename\battlefield2\enctype\2\validate\5nioxk5R\final\\queryid\1.1\list\cmp\gamename\battlefield2\where\\final\ Then i receive this: Code: H????d????????@_??:??4??]??4????????????????????????????????????.?????~)Z07????7k???%????iT"??Q{_j??"????6{??????????D???????KN??dI??>????????z]S??3m??5'D??&5??v5m???x??G??e&??E??@??~WJ??C;????#??????iO??k>_????????I?????)}??????KZ %@)g??D???????qI?????????????;????????????????????Q??#a8f????KB?????8??????????f??q??????+??F????a\W(???????l???????lF?????5??;??<$??l??h??????II!???w0???????t';'?????7;??????J??c??????????????F??]w ???c???/????3??X??-K??`.Z ????????3ZR??bG?????1????????????????crT?????(??c??KE ??0??????:?? ~?????B???? ???oM~xL??L??g????????c?????%??????*"!Q|??=|Q??????\I??9????LSkL0[[?????????K??&M???????????8?????{???5???????1??I?? ????#t????v??Q???gSc????????????<??????????-K??5b??C???8??? ??pq@r??O??#?????? ??
Im not sure that challange is correct or not, i tested 10 types from sources they are all uniqe and noone works.
Whats confusing me is that Gslist says something like:
Quote: battlefield2 uB2gak -> jkfaAtd2kc. And in your cfg it says: Quote: Battlefield 2 battlefield2 hW6m9a
But when i use "hW6m9a" as gamekey and "uB2gak" as secure i dont get "jkfaAtd2kc" so i guess you use some different gamekey? is that why i dont get any servers or is the challange wrong?
|
|
Top |
|
|
aluigi
|
Post subject: Posted: 23 Dec 2007 11:53 |
|
Joined: 13 Aug 2007 21:44 Posts: 4068 Location: http://aluigi.org
|
by default gslist uses ever the same gamename/gamekey so you must consider it only if you force the usage of a specific enctype and gamename:
gslist -n battlefield2 -t 2 -Y battlefield2 hW6m9a
be sure to have used the hW6m9a gamekey in both gsmsalg and enctype2
|
|
Top |
|
|
Revolty
|
Post subject: Posted: 01 Jan 2008 17:22 |
|
Joined: 21 Dec 2007 04:27 Posts: 16
|
Hi,
I removed my last post and made a new one.
It seems like i do receive a list of servers, however, its not the full list.
I know you said that i should send as Byte, but when i receive the packet as Byte and send it direcly as Byte[] to the encoder it fail to encode after a few bytes everytime.
So i tested with char[] and got a few servers, but it allways fail if there is a chr(0) in the string. So i replace every chr(0) with " " and i got about 50 servers, then i kept replace each char that encoder fail to read witch seems to be char 0 to 30 and a few more, and now i got up to 800 servers so far (look at screenshot).
But it seems really dumb that i have to replace characters like that, i guess i encode the bytes wrong, im using Default (European) but allso tested; ASCII, Unicode, UTF32, 8 & 7 but no luck on those.
I think i seen somewere that unsigned chr in C is equal to 8 byte, and since im dealing with ASCII i guess i should use 8 byte ASCII encoding but VB says its 7 bytes?
In short is like this:
Code: Dim reader As New StreamReader(tcpClient.GetStream, Encoding.Default)
Dim buffer As String = reader.ReadToEnd
For i As Integer = 0 To 29 buffer = buffer.Replace(Chr(i), " ") Next
Dim p As String = Encode("d4kZca", buffer.ToCharArray, buffer.Length - 1)
Try For i As Integer = 0 To p.Length Step 6 aServer.Add( _ Asc(p(i)) & "." & _ Asc(p(i + 1)) & "." & _ Asc(p(i + 2)) & "." & _ Asc(p(i + 3)) & ":" & _ Asc(p(i + 4)) * 256 + Asc(p(i + 5))) Next
Catch End Try
Attachments: |
Untitled.jpg [ 167.27 KiB | Viewed 2535 times ]
|
|
|
Top |
|
|
aluigi
|
Post subject: Posted: 02 Jan 2008 14:36 |
|
Joined: 13 Aug 2007 21:44 Posts: 4068 Location: http://aluigi.org
|
In my opinion the error is still in buffer.Length for at least two reasons:
- it's not a pointer to int but just int
- on which is calculated Length? total size of buffer or something like strlen(buffer)?
anyway I don't know VB so I can't do more than this
|
|
Top |
|
|
Revolty
|
Post subject: Posted: 04 Jan 2008 21:59 |
|
Joined: 21 Dec 2007 04:27 Posts: 16
|
VB does not suport pointers. Byref does work tho, it has a value of the buffer size before encoding, and after it contain the new size of bytes encoded, and its strlen like.
Thanks for your help anyways.
|
|
Top |
|
|
Avatar
|
Post subject: Posted: 05 Jan 2008 15:25 |
|
Joined: 02 Jan 2008 19:34 Posts: 12
|
Revolty wrote: VB does not suport pointers. Byref does work tho, it has a value of the buffer size before encoding, and after it contain the new size of bytes encoded, and its strlen like.
Thanks for your help anyways.
How did you resolv your problem? And how did you import gsseckey() to VB.NET? I'm trying to do a C# tool using the .DLL...
|
|
Top |
|
|
Revolty
|
Post subject: Posted: 05 Jan 2008 18:34 |
|
Joined: 21 Dec 2007 04:27 Posts: 16
|
I didn't, its not working..
Heres the port from gsmsalg.h tho:
Code: Public Class gsmalg2 Public Function Valid(ByVal SecureKey As String) As String Dim Buffer(255) As Byte Dim src(5) As Byte Dim Temp(3) As Integer Dim i As Integer Dim Validate As String = Nothing Dim key() As Byte = System.Text.Encoding.Default.GetBytes("d4kZca")
'/* 1) buffer creation with incremental data */
For i = 0 To 255 ' for(i = 0; i < 256; i++) Buffer(i) = i '*p++ = i; Next
'/* 2) buffer scrambled with key */
For i = 0 To 255 'for(i = num = 0; i < 256; i++) Temp(0) = (Temp(0) + Buffer(i) + key(i Mod 6)) And 255 'num = (num + *p + key[i % keysz]) & 0xff; Temp(1) = Buffer(Temp(0))
Buffer(Temp(0)) = Buffer(i) 'x = enctmp[num]; (UPDATE BUFFER) Buffer(i) = Temp(1) '*p++ = x; Next
Temp(0) = 0
'/* 3) source string scrambled with the buffer */
For i = 0 To 5 src(i) = Asc(Mid$(SecureKey, i + 1, 1))
Temp(0) = (Temp(0) + src(i) + 1) And 255 'num = (num + *p + 1) & 0xff; Temp(1) = Buffer(Temp(0)) 'x = enctmp[num]; Temp(2) = (Temp(2) + Temp(1)) And 255 'num2 = (num2 + x) & 0xff; Temp(3) = Buffer(Temp(2)) 'y = enctmp[num2];
src(i) = src(i) Xor Buffer((Temp(1) + Temp(3)) And 255) '*p++ ^= enctmp[(x + y) & 0xff]; Buffer(Temp(0)) = Temp(3) 'enctmp[num2] = x; (UPDATE BUFFER) Buffer(Temp(2)) = Temp(1) 'enctmp[num] = y; Next
'/* 4) enctype management */
For i = 0 To 5 'for(i = 0; i < size; i++) { src(i) = src(i) Xor key(i Mod 6) 'src[i] ^= key[i % keysz]; Next
i = 0 '// Create the valid validatekey: For j As Byte = 0 To 1 Temp(1) = src(i) Temp(3) = src(i + 1)
createChar(Validate, RShift(Temp(1), 2)) createChar(Validate, LShift(Temp(1) And 3, 4) Or RShift(Temp(3), 4))
Temp(1) = src(i + 2)
createChar(Validate, LShift(Temp(3) And 15, 2) Or RShift(Temp(1), 6)) createChar(Validate, Temp(1) And 63)
i = i + 3 Next
Return Validate '// Return the valid ValidateKey End Function
Private Sub createChar(ByRef Validate As String, ByVal Number As Byte) Dim newChar As String = Nothing
'// Check the Charcode, create a new Char ... Select Case Number Case Is < 26 newChar = Chr(Number + 65) Case Is < 52 newChar = Chr(Number + 71) Case Is < 62 newChar = Chr(Number - 4) Case 62 newChar = "+" Case 63 newChar = "/" End Select
'// ... and add it to the ValidateKey Validate = Validate & newChar End Sub
'// The << (LShift) and >> (RShift) functions: Private Function LShift(ByVal Value As Byte, ByVal Shift As Byte) As Byte LShift = Value * (2 ^ Shift) End Function
Private Function RShift(ByVal Value As Byte, ByVal Shift As Byte) As Byte RShift = Value \ (2 ^ Shift) End Function End Class
Call it like this: Code: Dim sA As New gsmalg2 sA.Valid(Secure)
|
|
Top |
|
|
Avatar
|
Post subject: Posted: 05 Jan 2008 18:53 |
|
Joined: 02 Jan 2008 19:34 Posts: 12
|
Is this VB.NET? And you are using pointers? Hmm...
Anyway, this algo is only the half, I need to decrypt the server response to get the serverlist.
|
|
Top |
|
|
Revolty
|
Post subject: Posted: 05 Jan 2008 23:51 |
|
Joined: 21 Dec 2007 04:27 Posts: 16
|
Yes its VB.Net, encoding the list is the part that won't work correcly.. read posts above for how to create a dll to call in Vb.
|
|
Top |
|
|
Avatar
|
Post subject: Posted: 06 Jan 2008 11:06 |
|
Joined: 02 Jan 2008 19:34 Posts: 12
|
Revolty wrote: Yes its VB.Net, encoding the list is the part that won't work correcly.. read posts above for how to create a dll to call in Vb.
Hi,
I already made that .dll, just cant use it in C#. Maybe its because the return value of the decoding function is a pointer? I get the same error like you. So it seems we need a .net implementation.
|
|
Top |
|
|
Revolty
|
Post subject: Posted: 06 Jan 2008 17:06 |
|
Joined: 21 Dec 2007 04:27 Posts: 16
|
Ah C.. Yes, its probebly pointer problem.. i can only recive the result as string..byte array or anything else fails.
I'd love a port for VB, but i can't understand half of that code. Would it be hard to change this code to not use pointers Luigi? so it return a buffer like gsmalg (not asking you to ofcourse).
|
|
Top |
|
|
Avatar
|
Post subject: Posted: 06 Jan 2008 19:18 |
|
Joined: 02 Jan 2008 19:34 Posts: 12
|
Revolty wrote: (not asking you to ofcourse).
But would be nice, so we can use the .dll in other programs too.
|
|
Top |
|
|
aluigi
|
Post subject: Posted: 07 Jan 2008 11:52 |
|
Joined: 13 Aug 2007 21:44 Posts: 4068 Location: http://aluigi.org
|
you can just add a small mini C function for handling this stuff more easily from any other language:
Code: int enctype2_wrapper(unsigned char *key, unsigned char *data, int size) { unsigned char *p;
p = enctype2_decoder(key, data, &size); memmove(data, p, size); return(size); }
so you can use it as usual with the difference that it will return the final size of the buffer and the input buffer will be decrypted without return pointers (so the data starts from byte 0)
|
|
Top |
|
|
Revolty
|
Post subject: Posted: 07 Jan 2008 16:08 |
|
Joined: 21 Dec 2007 04:27 Posts: 16
|
Sorry to say it won't work.
I think the decryption is allright, becouse the full input buffer beeing decoded. Tho i can't be sure its right or wrong, but i think the problem is the start byte..
You know this test tool you attatched, i thougt if it was possible to return 6 bytes of decrypted IP/Port (instead of printf) Then it could be used like so; For each(return) ad a server/ip.
Code: for(l = p + len; (p + 6) < l; p += 6) { printf("%02hhu.%02hhu.%02hhu.%02hhu %04hu\n", p[0], p[1], p[2], p[3], (p[4] << 8) | p[5]); }
I get invalid cast errors in attempt editing the sample my self.
|
|
Top |
|
|
Avatar
|
Post subject: Posted: 07 Jan 2008 16:39 |
|
Joined: 02 Jan 2008 19:34 Posts: 12
|
aluigi wrote: you can just add a small mini C function for handling this stuff more easily from any other language: Code: int enctype2_wrapper(unsigned char *key, unsigned char *data, int size) { unsigned char *p;
p = enctype2_decoder(key, data, &size); memmove(data, p, size); return(size); }
so you can use it as usual with the difference that it will return the final size of the buffer and the input buffer will be decrypted without return pointers (so the data starts from byte 0)
I'm not sure how this can help me, since I can't get any result of this function. Revolty seems at least to get a result. How did you do it?
|
|
Top |
|
|
Avatar
|
Post subject: Posted: 07 Jan 2008 16:55 |
|
Joined: 02 Jan 2008 19:34 Posts: 12
|
aluigi wrote: you can just add a small mini C function for handling this stuff more easily from any other language: Code: int enctype2_wrapper(unsigned char *key, unsigned char *data, int size) { unsigned char *p;
p = enctype2_decoder(key, data, &size); memmove(data, p, size); return(size); }
so you can use it as usual with the difference that it will return the final size of the buffer and the input buffer will be decrypted without return pointers (so the data starts from byte 0)
I'm not sure how this can help me, since I can't get any result of this function. Revolty seems at least to get a result. How did you do it?
|
|
Top |
|
|
Revolty
|
Post subject: Posted: 07 Jan 2008 17:07 |
|
Joined: 21 Dec 2007 04:27 Posts: 16
|
Im probebly the last one that can help you mate..
In VB i declare it like this:
Code: Declare Ansi Function decode Lib "C:\enctype2_decoder.dll" Alias "enctype2_wrapper" (ByVal gamekey() As Byte, ByVal buffer() As Byte, ByVal len As Int32) As Integer Then: Code: Dim Length as integer = decode(key, data, len)
So now i guess the "data" array should be decoded and "length" should have the new array length.
/EDIT
Got a few servers now (50-70) but then its getting corrupted, same problem as before, i have to remove chr(0) from the data before decoding or it getting corrupted.
|
|
Top |
|
|
Avatar
|
Post subject: Posted: 07 Jan 2008 18:21 |
|
Joined: 02 Jan 2008 19:34 Posts: 12
|
Well you used:
Alias "enctype2_decoder" (ByVal gamekey() As Byte, ByVal buffer() As Byte, ByVal buffer_len As Int32) AS BYTE()
I declared it as byte too, in C#:
[DllImport("enctype2_decoder.dll")]
public static extern byte[] enctype2_decoder(byte[] key, byte[] data, int size);
I get "Cannot marshal return value: Invalid managed/unmanaged type combination."
So you see, I'm still not at the point where I would need the data length :(
|
|
Top |
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum
|
|