Author Topic: PBO packet analysis  (Read 1158 times)

0 Members and 1 Guest are viewing this topic.

s0beit

  • Relentless Teamkiller
  • **
  • Posts: 94
    • View Profile
PBO packet analysis
« on: May 30, 2011, 11:36:02 pm »
I've spent some time debugging and fucking around with packets (under bi.key, not bi2.key), and i think I've figured it out for the most part

Code: [Select]
WORD PacketSize = *( WORD* )( buf );
BYTE PacketType = *( BYTE* )( buf + 0x02 );
BYTE PacketID = *( BYTE* )( buf + 0x03 );
DWORD UnknownHash = *( DWORD* )( buf + 0x04 );
DWORD PBONumber = *( DWORD* )( buf + 0x08 );
DWORD PBOGroup = *( DWORD* )( buf + 0x0C );
DWORD UnknownFF = *( DWORD* )( buf + 0x10 );
DWORD PreviousPBONum = *( DWORD* )( buf + 0x14 );

After that it gets a little murky, but here, I'll try to explain

Here is a visual aid for some people
Code: [Select]
//[B4 01][00][A0][9E AC 1A CC][09 00 00 00][1B 00 00 00][FF FF FF 07][07 00 00 00][03 20][61 00 00 02][CE 01][72-character-hash][00][C7 01 03]
//[68 01][80][A0][9B AE 5F A3][0A 00 00 00][1B 00 00 00][FF FF FF 07][09 00 00 00][C7 01 20][61 00 00 03]
//[6C 01][80][A0][DD 65 E5 A3][10 00 00 00][1B 00 00 00][FF FF FF 07][0F 00 00 00][C7 01 20][61 00 00 03]
//[8B 01][00][A0][81 FB 44 01][73 00 00 00][22 00 00 00][FF FF FF FF][72 00 00 00][03 20][61 00 00 02][C7 01 03]
//[84 01][00][A0][2C 20 C8 F4][74 00 00 00][22 00 00 00][FF FF FF FF][73 00 00 00][03 20][61 00 00 03][C7 01 FC C2 02]

After the bytes with the [] it gets a little murky and unpredictable, as far as i can tell (but right after the end of each of these is a string containing the PBO name)

What i do know, however, is that after the string, which looks like
[PBO_NAME][00][BI KEY][OTHER KEY]

Now, the issue here is, the BI KEY can have different lengths.

Code: [Select]
#define BIKEY_SIZE 153
#define BI2KEY_SIZE BIKEY_SIZE + 1

If the start of [BI KEY] is 'bi' then it's a version 1 bikey, if the start of [BI KEY] is 'bi2' then it's a version 2 key, all you _really_ need to know about these is that the bi2 key contains one more byte (because it has one extra character, '2', in the header)

The bikey data, the first one anyway, is the actual key content from bi.key or bi2.key, depending on how it decides to roll.

The second key i assume is related to the PBO itself  :icon_teehee

There _can_ be some extra data after this key, but I've only seen that occur when unsigned pbos are passed through packets

I hope i was able to shed some light on how this entire process works, I'm hoping somebody can tell me what the bytes at the tail end of the packets above mean, or the UnknownFF area, but that wasn't really the purpose of this topic. Have fun with that!
« Last Edit: May 30, 2011, 11:45:45 pm by s0beit »

Jurugi

  • Online Villain
  • ***
  • Posts: 190
    • View Profile
Re: PBO packet analysis
« Reply #1 on: May 31, 2011, 04:47:33 am »
Good analysis, it's quite interesting to mess with packets on Arma2 xD
You can spawn fake players in Arma2 or use the one ALuigi made with a tweak or two to make it work.

[PBO_NAME][00][BI KEY][OTHER KEY][VERSION][0x00end]

I never noticed anything after the BI key: the BI key of the pbo seems to be the last 22 bytes - the last 2, because there is a trailing hex of [0x02 (version)] [0x00 (end)]. BE packets always seem to start with BE; but I haven't really messed with it lately at all. I at least want to look into BattleEye and see if I can find anything to mess with it personally, but it's not a priority because it never effected me.

s0beit

  • Relentless Teamkiller
  • **
  • Posts: 94
    • View Profile
Re: PBO packet analysis
« Reply #2 on: May 31, 2011, 05:36:17 am »
There is certainly another key after the BI KEY, you can tell if you open the bi.key in a hex editor and see what it ends with, there is data beyond that which is definitely different depending on the PBO.

Also that "UnknownHash" seems to be a buffer CRC32 (meaning, before it's passed to sendto, they CRC32 hash the packet... I'll explain)
Code: [Select]
igned int __thiscall PboPacketSend(int this, int buf, struct sockaddr to)
{
  struct _RTL_CRITICAL_SECTION *v3; // edi@1
  int v4; // esi@1
  signed int result; // eax@2
  int pbuf; // edi@3
  int bufSize; // eax@3
  int v8; // eax@5
  int v9; // ebx@5
  SOCKET v10; // ST04_4@5
  char v11; // al@5
  int v12; // eax@6
  char v13; // al@7
  signed int v14; // eax@7
  char v15; // al@9
  signed int v16; // esi@12
  int optlen; // [sp+8h] [bp-Ch]@5
  char optval[4]; // [sp+Ch] [bp-8h]@5
  LPCRITICAL_SECTION lpCriticalSection; // [sp+10h] [bp-4h]@1
  signed int v20; // [sp+1Ch] [bp+8h]@3

  v4 = this;
  v3 = (struct _RTL_CRITICAL_SECTION *)(this + 8);
  lpCriticalSection = (LPCRITICAL_SECTION)(this + 8);
  sub_9893E9((LPCRITICAL_SECTION)(this + 8));
  if ( *(_DWORD *)(v4 + 112) == -1 )
  {
    sub_9893F7(v3);
    result = 0;
  }
  else
  {
    pbuf = buf;
    bufSize = *(_WORD *)buf;
    *(_DWORD *)(buf + 4) = 0;
    *(_DWORD *)(buf + 4) = CRC32(0, buf, bufSize, (unsigned __int64)bufSize >> 32);
    v20 = 12;
    while ( sendto(*(_DWORD *)(v4 + 0x70), (const char *)pbuf, *(_WORD *)pbuf, 0, &to, 16) == -1 )
    {
      v8 = WSAGetLastError();
      *(_DWORD *)optval = 0;
      v9 = v8;
      v10 = *(_DWORD *)(v4 + 112);
      optlen = 4;
      getsockopt(v10, 65535, 4103, optval, &optlen);
      WSASetLastError(0);
      v11 = (*(int (__thiscall **)(int))(*(_DWORD *)v4 + 24))(v4);
      sub_988047("Pe(%u):err-s(%d,%d)", v11);
      if ( v9 != 10054 )
      {
        v16 = 0;
        goto LABEL_13;
      }
      sub_961BF1(v4);
      v12 = *(_DWORD *)v4;
      if ( *(_DWORD *)(v4 + 112) == -1 )
      {
        v15 = (*(int (__thiscall **)(int))(v12 + 24))(v4);
        sub_988047("Pe(%u):rec-giveup", v15);
LABEL_10:
        sub_9893F7(lpCriticalSection);
        return 0;
      }
      v13 = (*(int (__thiscall **)(int))(v12 + 24))(v4);
      sub_988047("Pe(%u):rec-retry", v13);
      v14 = v20--;
      if ( !v14 )
        goto LABEL_10;
    }
    v16 = 9;
LABEL_13:
    sub_9893F7(lpCriticalSection);
    result = v16;
  }
  return result;
}

This is the hex-rays dump of the function which calls sendto, if you catch the buffer BEFORE sendto is called, it should be much, much more effective  :icon_devil

Also, I'm not 100% it's CRC32, but its definitely a hash function and it definitely returns a 4 byte (DWORD) hash, so, it makes sense.

Code: [Select]
signed int __cdecl CRC32(int a1, int a2, unsigned int a3, int a4)
{
  int v4; // edx@1
  signed int result; // eax@2
  int v6; // edi@3
  int v7; // esi@3
  int v8; // esi@5
  int v9; // edx@5
  int v10; // esi@5
  int v11; // esi@5
  int v12; // esi@5
  int v13; // esi@5
  int v14; // esi@5
  int v15; // esi@5
  unsigned __int8 v16; // cf@5
  unsigned __int8 v17; // cf@9

  v4 = a2;
  if ( a2 )
  {
    v6 = a4;
    v7 = ~a1;
    if ( a4 >= 0 )
    {
      if ( a4 <= 0 )
        goto LABEL_7;
      do
      {
        do
        {
          v8 = dword_C71BE0[(v7 ^ *(_BYTE *)v4) & 0xFF] ^ ((unsigned int)v7 >> 8);
          v9 = v4 + 1;
          v10 = dword_C71BE0[(v8 ^ *(_BYTE *)v9++) & 0xFF] ^ ((unsigned int)v8 >> 8);
          v11 = dword_C71BE0[(v10 ^ *(_BYTE *)v9++) & 0xFF] ^ ((unsigned int)v10 >> 8);
          v12 = dword_C71BE0[(v11 ^ *(_BYTE *)v9++) & 0xFF] ^ ((unsigned int)v11 >> 8);
          v13 = dword_C71BE0[(v12 ^ *(_BYTE *)v9++) & 0xFF] ^ ((unsigned int)v12 >> 8);
          v14 = dword_C71BE0[(v13 ^ *(_BYTE *)v9++) & 0xFF] ^ ((unsigned int)v13 >> 8);
          v15 = dword_C71BE0[(v14 ^ *(_BYTE *)v9++) & 0xFF] ^ ((unsigned int)v14 >> 8);
          v7 = dword_C71BE0[(v15 ^ *(_BYTE *)v9) & 0xFF] ^ ((unsigned int)v15 >> 8);
          v4 = v9 + 1;
          v16 = a3 >= 8;
          a3 -= 8;
          v6 = v16 + v6 - 1;
        }
        while ( v6 > 0 );
        if ( v6 < 0 )
          break;
LABEL_7:
        ;
      }
      while ( a3 >= 8 );
    }
    while ( v6 | a3 )
    {
      v7 = dword_C71BE0[(v7 ^ *(_BYTE *)v4++) & 0xFF] ^ ((unsigned int)v7 >> 8);
      v17 = a3-- >= 1;
      v6 = v17 + v6 - 1;
    }
    result = ~v7;
  }
  else
  {
    result = 0;
  }
  return result;
}

Pride

  • Klass Klown
  • ***
  • Posts: 332
    • View Profile
Re: PBO packet analysis
« Reply #3 on: May 31, 2011, 08:36:32 am »
I haven't looked at ArmA in ages, but wasn't DWORD Unknownhash some sort of sequence counter because they were using UDP? (Which I don't think has a sequence counter built into the protocol like TCP) or was it something that was introduced with 1.59?

s0beit

  • Relentless Teamkiller
  • **
  • Posts: 94
    • View Profile
Re: PBO packet analysis
« Reply #4 on: May 31, 2011, 08:46:19 am »
If you look at the hex-rays dump i posted of the function which makes it (BUFFER + 4), it's not a sequence counter. Definitely some sort of hash of the packet to be sent.

Particularly this bit:
Code: [Select]
    pbuf = buf;
    bufSize = *(_WORD *)buf;
    *(_DWORD *)(buf + 4) = 0;
    *(_DWORD *)(buf + 4) = CRC32(0, buf, bufSize, (unsigned __int64)bufSize >> 32);
    v20 = 12;
    while ( sendto(*(_DWORD *)(v4 + 0x70), (const char *)pbuf, *(_WORD *)pbuf, 0, &to, 16) == -1 )

Pride

  • Klass Klown
  • ***
  • Posts: 332
    • View Profile
Re: PBO packet analysis
« Reply #5 on: May 31, 2011, 09:05:57 am »
Well, it's probably just a deterrant from using dumb packet editing tools.

I suppose if you look at the server code as well you may see it checking. BI love their weird hashing schemes.

KANAL seems to think that 00C71BE0 is CRC32 related as well...

Hell, while you're at it, see if you can send commands to the scripting interface via injection.
« Last Edit: May 31, 2011, 09:59:57 am by Pride »

MrMedic

  • MasstKer
  • ********
  • Posts: 8900
  • programmer/dev/software engineer
    • View Profile
Re: PBO packet analysis
« Reply #6 on: May 31, 2011, 03:58:04 pm »
i think bi get urges then forget what they were doing.
EnCoded Message: i3iy9yl8kr2xf3g2Txs3pr6ye3ya7jg5ty2z

https://www.youtube.com/watch?v=62_7-AYfdkQ
you need a paypal account for the private versions.

Website:
http://bit.ly/medic101

Teamspeak 3: 85.236.101.5:10157

stealthstick

  • Klass Klown
  • ***
  • Posts: 360
  • Computer Scientist
    • View Profile
Re: PBO packet analysis
« Reply #7 on: May 31, 2011, 06:02:53 pm »
i think bi get urges then forget what they were doing.

"Darn TKC! Always getting past our Battleeye! I know, we should release another bisign for them to try and crack! Herp D Derp!"
Bypassed.
It's been a good few years, becoming what I always wanted to be.

Jake

  • Cheater Apprentice
  • *
  • Posts: 20
    • View Profile
Re: PBO packet analysis
« Reply #8 on: August 22, 2011, 06:39:04 am »
Thanks For this m8 ALOT of help

i mss old ofp

  • Insane Joker
  • ****
  • Posts: 982
  • i love the fact that you hate me.
    • View Profile
    • TKC
Re: PBO packet analysis
« Reply #9 on: August 23, 2011, 02:07:07 am »
stealth did you get ban from a server yet? lol... i know somone looking for you to ban you ... lmao :icon_laugh
692063616E206C6F616420612070626F6F6E2074686520666C79206C6D616F00

the joke is you!!!!