• Welcome to Valhalla Legends Archive.
 

Rudimentary Warden information

Started by iago, February 28, 2008, 05:07 PM

Previous topic - Next topic
|

Paladin

#60
I noticed something weird while packetlogging my official SC client...

The first warden message that I am receiving from BNCS looks like that:


ff 5e 29 00 d3 2b 67 a5  58 29 21 61 13 44 9d 48 [...]


That looks fine.
However, unless I am missing something here, my client sent an additionnal byte (FB) in the 0x00 message:


ff 5e 05 00 fb


I even tried sending that same byte but I kept getting disconnected by Battle.net
What could the problem be and why would it send that extra 0xFB byte ???

EDIT: Nevermind, someone (Ringo) helped me ;)
I am so stupid. Haha.

iago

Quote from: Paladin on March 07, 2008, 06:45 AM
I noticed something weird while packetlogging my official SC client...

The first warden message that I am receiving from BNCS looks like that:


ff 5e 29 00 d3 2b 67 a5  58 29 21 61 13 44 9d 48 [...]


That looks fine.
However, unless I am missing something here, my client sent an additionnal byte (FB) in the 0x00 message:


ff 5e 05 00 fb


I even tried sending that same byte but I kept getting disconnected by Battle.net
What could the problem be and why would it send that extra 0xFB byte ???

EDIT: Nevermind, someone (Ringo) helped me ;)
I am so stupid. Haha.
I know you've figured it out, but just in case somebody doesn't know -- that "fb" is the encrypted response to the 0x00 packet (either 01 or 00 encrypted, depending on whether or not he'd connected before).
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Barabajagal

#62
Hrm... turns out the examples HDX gave me were wrong... Anyway, here's my (currently working) code and implementation for VB6:

clsWarden.cls:
Option Explicit
Private Declare Function StandardSHA Lib "RSHA.dll" (sVal As String) As String
Private Position        As Long
Private RandomData()    As Byte
Private RandomSource1() As Byte
Private RandomSource2() As Byte
Public Sub Initialize(Seed As String)
Dim Length1 As Long
Dim Length2 As Long
Dim Seed1() As Byte
Dim Seed2() As Byte
Dim I       As Long
    Length1 = RShift(Len(Seed), 1)
    Length2 = Len(Seed) - Length1
    ReDim Seed1(Length1 - 1)
    ReDim Seed2(Length2 - 1)
    For I = 0 To Length1 - 1
        Seed1(I) = Asc(Mid$(Seed, I + 1, 1))
    Next I
    For I = 0 To Length2 - 1
        Seed2(I) = Asc(Mid$(Seed, I + Length1 + 1, 1))
    Next I
    ReDim RandomData(&H13) As Byte
    StrToByteArray StandardSHA(ByteArrayToStr(Seed1)), RandomSource1
    StrToByteArray StandardSHA(ByteArrayToStr(Seed2)), RandomSource2
    Update
    Position = 0
End Sub
Private Sub Update()
    StrToByteArray StandardSHA(ByteArrayToStr(RandomSource1) & ByteArrayToStr(RandomData) & ByteArrayToStr(RandomSource2)), RandomData
End Sub
Private Function GetByte() As Byte
    GetByte = RandomData(Position)
    Position = Position + 1
    If Position >= &H14 Then
        Position = 0
        Update
    End If
End Function
Public Function GetBytes(ByVal bytes As Long) As String
Dim I           As Integer
Dim Buffer()    As Byte
    ReDim Buffer(bytes) As Byte
    For I = 0 To bytes
        Buffer(I) = GetByte
    Next I
    GetBytes = ByteArrayToStr(Buffer)
End Function
Private Sub StrToByteArray(ByVal sStr As String, ByRef Ary() As Byte)
Dim I As Integer
    ReDim Ary(Len(sStr) - 1) As Byte
    For I = 1 To Len(sStr)
        Ary(I - 1) = Asc(Mid$(sStr, I, 1))
    Next I
End Sub
Private Function ByteArrayToStr(ByRef bByt() As Byte) As String
Dim sStr As String
Dim I    As Integer
    For I = 1 To UBound(bByt) + 1
        sStr = sStr & Chr$(bByt(I - 1))
    Next I
    ByteArrayToStr = sStr
End Function
Public Function SimpleCrypt(ByVal sBase As String) As String
Dim bKey()   As Byte
Dim bBase()  As Byte
Dim lVal     As Long
Dim I       As Long
Dim lPos     As Long
Dim temp    As Byte
    StrToByteArray sBase, bBase
    ReDim bKey(&H101) As Byte
    For I = 0 To &HFF
        bKey(I) = I
    Next I
    For I = 1 To &H40
        lVal = lVal + bKey(I * 4 - 4) + bBase(lPos Mod (UBound(bBase) + 1))
        lPos = lPos + 1
        temp = bKey(I * 4 - 4)
        bKey(I * 4 - 4) = bKey(lVal And &HFF)
        bKey(lVal And &HFF) = temp
       
        lVal = lVal + bKey(I * 4 - 3) + bBase(lPos Mod (UBound(bBase) + 1))
        lPos = lPos + 1
        temp = bKey(I * 4 - 3)
        bKey(I * 4 - 3) = bKey(lVal And &HFF)
        bKey(lVal And &HFF) = temp
       
        lVal = lVal + bKey(I * 4 - 2) + bBase(lPos Mod (UBound(bBase) + 1))
        lPos = lPos + 1
        temp = bKey(I * 4 - 2)
        bKey(I * 4 - 2) = bKey(lVal And &HFF)
        bKey(lVal And &HFF) = temp
       
        lVal = lVal + bKey(I * 4 - 1) + bBase(lPos Mod (UBound(bBase) + 1))
        lPos = lPos + 1
        temp = bKey(I * 4 - 1)
        bKey(I * 4 - 1) = bKey(lVal And &HFF)
        bKey(lVal And &HFF) = temp
    Next I
    SimpleCrypt = ByteArrayToStr(bKey)
End Function
Public Function DoCrypt(ByVal sData As String, ByRef sKey As String) As String
Dim bKey() As Byte
Dim Data() As Byte
Dim I      As Long
Dim temp   As Byte
Dim Y      As Long
Dim Z      As Long
    StrToByteArray sKey, bKey
    Y = bKey(&H100)
    Z = bKey(&H101)
    StrToByteArray sData, Data
    For I = 0 To UBound(Data)
        Y = (Y + 1) And &HFF
        Z = (Z + bKey(Y)) And &HFF
        temp = bKey(Y)
        bKey(Y) = bKey(Z)
        bKey(Z) = temp
        Data(I) = Data(I) Xor bKey((CInt(bKey(Y)) + CInt(bKey(Z))) And &HFF)
    Next I
    bKey(&H100) = Y
    bKey(&H101) = Z
    sKey = ByteArrayToStr(bKey)
    DoCrypt = ByteArrayToStr(Data)
End Function


Top of Whatever handles BNCS packets:
Private wKeyOut     As String
Private wKeyIn      As String
Private cWarden     As New clsWarden


In SID_AUTH_CHECK:
    BNCSPacket.InsertString KeyHash
    cWarden.Initialize Left$(KeyHash, 4)
    wKeyOut = cWarden.SimpleCrypt(cWarden.GetBytes(&HF))
    wKeyIn = cWarden.SimpleCrypt(cWarden.GetBytes(&HF))



For handling 5E:
Private Sub SID_Recv_Warden()
Dim sData As String
Dim wPack As New clsPacket
Static pMD5  As String
Static pKey  As String
Static pLen  As Long
Static pData As String
Dim dLen     As Long
Dim tData    As String
Dim cMD5     As New clsMD5
Dim tMD5     As String
Dim nFile    As Integer
Dim EventNo  As Byte
Dim I        As Long
Dim Loops    As Long
Dim Vals()   As String
Dim cmd      As Integer
Dim addr()   As Long
Dim readlen  As Byte
Dim LastByte As Byte
Dim ToSend   As String
Dim Checksum As Long
Const Req1   As Long = &H497FB0
Const Req2   As Long = &H49C33D
Const Req3   As Long = &H4A2FF7
    sData = BNCSPacket.GetNull
    wPack.SetData cWarden.DoCrypt(sData, wKeyIn)
    Select Case wPack.GetByte
        Case &H0
            pMD5 = wPack.GetString(16)
            pKey = wPack.GetString(16)
            pLen = wPack.GetDWORD
            BNCSPacket.ClearOutbound
            'If LenB(Dir$(SettingsFolder & "\Tmp\Warden\" & StH(pMD5) & ".bas")) = 0 Then
            '    pData = vbNullString
            '    BNCSPacket.InsertByte &H0
            '    ToSend = cWarden.DoCrypt(BNCSPacket.GetOutbound, wKeyOut)
            '    BNCSPacket.ClearOutbound
            '    BNCSPacket.InsertString ToSend
            '    AddQueue BNCSPacket.SendBNCSPacket(SID_WARDEN)
            'Else
                BNCSPacket.InsertByte &H1
                ToSend = cWarden.DoCrypt(BNCSPacket.GetOutbound, wKeyOut)
                BNCSPacket.ClearOutbound
                BNCSPacket.InsertString ToSend
                AddQueue BNCSPacket.SendBNCSPacket(SID_WARDEN)
            'End If
        'Case &H1
        '    dLen = wPack.GetWORD
        '    tData = wPack.GetString(dLen)
        '    pData = pData & tData
        '    If Len(pData) >= pLen Then
        '        tMD5 = cMD5.DigestStrToHexStr(pData)
        '        BNCSPacket.ClearOutbound
        '        If StH(pMD5) = tMD5 Then
        '            nFile = FreeFile
        '            Open SettingsFolder & "\Tmp\Warden\" & StH(pMD5) & ".mod" For Binary Access Write As #nFile
        '            Put #nFile, , cWarden.DoCrypt(pData, cWarden.SimpleCrypt(pKey))
        '            Close #nFile
        '            BNCSPacket.InsertByte &H1
        '            ToSend = cWarden.DoCrypt(BNCSPacket.GetOutbound, wKeyOut)
        '            BNCSPacket.ClearOutbound
        '            BNCSPacket.InsertString ToSend
        '            AddQueue BNCSPacket.SendBNCSPacket(SID_WARDEN)
        '        Else
        '            pData = vbNullString
        '            BNCSPacket.InsertByte &H0
        '            ToSend = cWarden.DoCrypt(BNCSPacket.GetOutbound, wKeyOut)
        '            BNCSPacket.ClearOutbound
        '            BNCSPacket.InsertString ToSend
        '            AddQueue BNCSPacket.SendBNCSPacket(SID_WARDEN)
        '        End If
        '    End If
        Case &H2
            EventNo = wPack.GetByte
            Loops = (Len(sData) - 3) / 7
            ReDim Vals(Loops - 1) As String
            ReDim addr(Loops - 1) As Long
            nFile = FreeFile
            Open Config.HashPath & "\StarCraft.exe" For Binary Access Read As #nFile
            For I = 0 To Loops - 1
                cmd = wPack.GetWORD
                addr(I) = wPack.GetDWORD
                readlen = wPack.GetByte
                Vals(I) = String$(readlen, 0)
                Get #nFile, addr(I) - &H400000 + 1, Vals(I)
            Next I
            Close #nFile
            LastByte = wPack.GetByte
            If addr(0) = Req1 And addr(1) = Req2 And addr(2) = Req3 Then
                Checksum = &H193E73E8
            ElseIf addr(0) = Req2 And addr(1) = Req1 And addr(2) = Req3 Then
                Checksum = &HD6557DEF
            ElseIf addr(0) = Req1 And addr(1) = Req3 And addr(2) = Req2 Then
                Checksum = &H2183172A
            ElseIf addr(0) = Req2 And addr(1) = Req3 And addr(2) = Req1 Then
                Checksum = &HCA841860
            ElseIf addr(0) = Req3 And addr(1) = Req2 And addr(2) = Req1 Then
                Checksum = &H9F2AD2C3
            ElseIf addr(0) = Req3 And addr(1) = Req1 And addr(2) = Req2 Then
                Checksum = &HC04CF757
            Else
                RaiseEvent BNetError("Unknown Warden Request: " & Hex$(addr(1)) & " " & Hex$(addr(2)) & " " & Hex$(addr(3)))
            End If
            For I = 0 To Loops - 1
                BNCSPacket.InsertByte &H0
                BNCSPacket.InsertString Vals(I)
            Next I
            ToSend = BNCSPacket.GetOutbound
            ToSend = Chr$(&H2) & BNCSPacket.CreateWORD(Len(ToSend)) & BNCSPacket.CreateDWORD(Checksum) & ToSend
            ToSend = cWarden.DoCrypt(ToSend, wKeyOut)
            BNCSPacket.ClearOutbound
            BNCSPacket.InsertString ToSend
            AddQueue BNCSPacket.SendBNCSPacket(SID_WARDEN)
        Case Else
            RaiseEvent BNetError("Unknown Warden Packet: " & StH(wPack.GetData))
    End Select
End Sub


Note that I've currently got the actual downloading, 0x01 and such commented out, since it's pretty much useless at this point... Once it's publicly released how the checksums are generated, like as not full downloading, decrypting, expanding and everything of the file will be needed. Until then, this works.

BTW, big thanks to both Blake (HDX) and Ringo, and of course iago. I'm sure some of my users will be happy about it...

Ringo

#63
Quote from: Andy on March 07, 2008, 04:47 PM
and Ringo
NO!
uh, oh, ouch, that gives VB6 a bad name! :P
Mines not exacly great, but its way more cleaner :P
Try somthing like this:

Public Type RANDOMDATA
    Pos   As Long
    Data  As String * 20
    Sorc1 As String * 20
    Sorc2 As String * 20
End Type

Private bR(255) As Byte

Public Sub RC4Key(ByRef S As String, ByRef B() As Byte)
    Dim i As Long, A As Long, C As Byte
    B(256) = 0
    B(257) = 0
    A = Len(S)
    For i = 0 To 255
        bR(i) = Asc(Mid(S, (i Mod A) + 1, 1))
        B(i) = i
    Next i
    A = 0
    For i = 0 To 255
        A = (A + B(i) + bR(i)) Mod 256
        C = B(i)
        B(i) = B(A)
        B(A) = C
    Next i
End Sub
Public Sub RC4Crypt(ByRef S As String, ByRef bK() As Byte)
    Dim A As Long, B As Long, C As Byte, i As Long
    A = bK(256)
    B = bK(257)
    For i = 1 To Len(S)
        A = (A + 1) Mod 256
        B = (B + bK(A)) Mod 256
        C = bK(A)
        bK(A) = bK(B)
        bK(B) = C
        Mid(S, i, 1) = Chr(Asc(Mid(S, i, 1)) Xor bK((CInt(bK(A)) + bK(B)) Mod 256))
    Next i
    bK(256) = A
    bK(257) = B
End Sub

Public Sub Data_Init(ByRef R As RANDOMDATA, ByVal lngSeed As Long)
    Dim S  As String * 4
    Call CopyMemory(ByVal S, lngSeed, 4)
    R.Sorc1 = BSHA1(Left(S, 2), True, True)
    R.Sorc2 = BSHA1(Right(S, 2), True, True)
    R.Data = String(20, 0)
    R.Data = BSHA1(R.Sorc1 & R.Data & R.Sorc2, True, True)
    R.Pos = 1
End Sub
Public Function Data_Get_Bytes(ByRef R As RANDOMDATA, ByVal lngBytes As Long) As String
    Dim i As Long, S As String
    S = String(lngBytes, 0)
    For i = 1 To lngBytes
        Mid(S, i, 1) = Mid(R.Data, R.Pos, 1)
        R.Pos = R.Pos + 1
        If R.Pos > 20 Then
            R.Pos = 1
            R.Data = BSHA1(R.Sorc1 & R.Data & R.Sorc2, True, True)
        End If
    Next i
    Data_Get_Bytes = S
End Function

iago

For all who have asked, here's how to load a binary in IDA. Start by opening Battle.snp in the standard way, then:
File->Load File->Additional Binary File
   Pick the .bin file
   Set:
      Loading segment: 0x0
      Loading offset: The base address you want
      File offset in bytes: 0x0
      Number of bytes: 0x0
      Create segments: yes
      Code segment: yes
View->Open Subviews->Segments
   Right-click on the new segment (seg000), edit segment
   Set:
      "Segment name" to something useful
      Select "32-bit segment"
Options->general
   Tab: Analysis
   Reanalyze program

Any code that's left, you can fiddle with using Create Function (p) or Convert to Code (c).



I also uploaded my .idb file, and decided I don't care about keeping it private:
http://www.javaop.com/~ron/tmp/battle_warden.zip

0x02000000: A downloaded module (cc19c0a67a90318e157e6a5325a9bd2e.bin)
0x02e30000: Default module

I also identified sha1 functions in there, because they're so easy to find, and I commented/named the function imports.
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Barabajagal

#65
Quote from: Ringo on March 08, 2008, 09:12 AM
Quote from: Andy on March 07, 2008, 04:47 PM
and Ringo
NO!
uh, oh, ouch, that gives VB6 a bad name! :P
Mines not exacly great, but its way more cleaner :P
It's an almost line by line port of the example code iago posted... Of course it's not clean.


However, I just added speed timings to Initialize, GetBytes, SimpleCrypt, and DoCrypt, and they all ran instantly... as in... 0 ms. So I'm happy.

Paladin

Quote from: Andy on March 08, 2008, 02:29 PM
Quote from: Ringo on March 08, 2008, 09:12 AM
Quote from: Andy on March 07, 2008, 04:47 PM
and Ringo
NO!
uh, oh, ouch, that gives VB6 a bad name! :P
Mines not exacly great, but its way more cleaner :P
It's an almost line by line port of the example code iago posted... Of course it's not clean.


However, I just added speed timings to Initialize, GetBytes, SimpleCrypt, and DoCrypt, and they all ran instantly... as in... 0 ms. So I'm happy.

I actually tried your code to see if it worked and it gave me a "Can't find DLL entry point StandardSHA in RSHA.dll".  :o
By the way, I got your RSHA.dll by downloading your bot.

iago

For any who care, here's my Java implementation: http://www.javaop.com/~ron/tmp/warden.tgz

I'm not including all the utility classes, but you can find them on my wiki if you actually want to run it instead of use it for a reference.
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Barabajagal

Hasn't been released in that ver prolly...  Here's a current ver of my RSHA.dll with vb declares of all the API calls for ya.

Ringo

Quote from: iago on March 08, 2008, 10:41 AM
For all who have asked, here's how to load a binary in IDA. Start by opening Battle.snp in the standard way, then:
File->Load File->Additional Binary File
   Pick the .bin file
   Set:
      Loading segment: 0x0
      Loading offset: The base address you want
      File offset in bytes: 0x0
      Number of bytes: 0x0
      Create segments: yes
      Code segment: yes
View->Open Subviews->Segments
   Right-click on the new segment (seg000), edit segment
   Set:
      "Segment name" to something useful
      Select "32-bit segment"
Options->general
   Tab: Analysis
   Reanalyze program

Any code that's left, you can fiddle with using Create Function (p) or Convert to Code (c).



I also uploaded my .idb file, and decided I don't care about keeping it private:
http://www.javaop.com/~ron/tmp/battle_warden.zip

0x02000000: A downloaded module (cc19c0a67a90318e157e6a5325a9bd2e.bin)
0x02e30000: Default module

I also identified sha1 functions in there, because they're so easy to find, and I commented/named the function imports.

Neat, thanks!, you have motivated me into learning ASM :)
Great work!


Quote from: Andy on March 08, 2008, 02:29 PM
It's an almost line by line port of the example code iago posted... Of course it's not clean.

However, I just added speed timings to Initialize, GetBytes, SimpleCrypt, and DoCrypt, and they all ran instantly... as in... 0 ms. So I'm happy.
I was refering to things like StrToByteArray() and ByteArrayToStr().
You shouldnt need to switch between data types all the time, and if you do, try useing somthing like rtlMoveMemory() api.

Rob

The current warden modules will handle packets 0x00, 0x01, 0x02, 0x03, 0x04.

For 0x02, there appear to be multiple 'commands' that the server could request.  These also differ per module.

The solutions for 0x02 in this thread should be considered temporary at best.  Blizzard could activate any of these other packets/commands at any given time.
Rob@USEast

Hdx

Unless I was mistaken while reading Maiev.mod [SC's warden loader] only packets 0-2 are supported. It simply ignores other opcodes.
I know that 0-4 are enabled on D2's version of warden. But meh.
As well, anyone who thinks that this solution for 0x02 is permanent doesn't understand how Warden works...
We're just doing it as far as we can sofar.
As for the current modules.. Still can't find where it calcs the checksum, but it jsut seems to be a 'test' module. Applying some simple memory patches, trying to tighten security around it a little, nothing major.

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

Archangel.

So who have passed the challenge so far?

I know the solution of 0x02 is temprorary right now since you need to do things related with the modules.
aka: Archangel, i can't login into the account or request the password, weird problem.

Rob

Quote from: Hdx on March 10, 2008, 08:58 PM
Unless I was mistaken while reading Maiev.mod [SC's warden loader] only packets 0-2 are supported. It simply ignores other opcodes.

You are correct.  Maiev.mod only has handling for 0x00, 0x01, and 0x02.  Once the new module is prepared, Maive is unloaded and the new module is loaded in its place.  The new module takes over for Maive to handle packets, crypto, etc.
Rob@USEast

Hdx

Ah duaa :P brain fart.
*points at the init struct* pretty !
Anyways, ya, when it comes to warden, due to its nature, everything is temporary.
BUT, its the whole does Blizzard give enough shit to change it?
Has anyone checked if the addresses change if you join a game as opposed to the 3 that are checked while in chat?

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

|