rgbkrk / pipboyrelay

:zap: Pip boy relay for Fallout 4
79 stars 6 forks source link

[WIP] Dump binary data to files. #2

Closed rgbkrk closed 9 years ago

rgbkrk commented 9 years ago

Relaying the data is all well and good. How about dumping it and analyzing it? I'm going to start dissecting this a bit to see what I can glean.

First data packet is pretty easy.

In [1]: data0 = open("dumpy.00.27000.59169.bin", 'rb').read()

In [2]: data0
Out[2]: b'#\x00\x00\x00\x01{"lang":"en","version":"1.1.21.0"}\n'

In [3]: # First 4 bytes are the length of the rest

In [4]: struct.unpack("I", data0[:4])[0]
Out[4]: 35

In [5]: data0[4:4+struct.unpack("I", data0[:4])[0]]
Out[5]: b'\x01{"lang":"en","version":"1.1.21.0"}'

Note that it's missing the newline above. What I think this means is that the \x01 in the 4th byte (0-indexed) is actually an op code while bytes 0-3 are the length.

This would then mean we're looking at:

[header [bytes 0 - 3 are length] [byte 4 opcode (?)] ] [payload of length from before]
rgbkrk commented 9 years ago

Same with the follow on packet after that.

In [38]: data1 = open("dumpy.01.27000.59169.bin", 'rb').read()

In [39]: data1
Out[39]: b'\x92\x0f\x07\x00\x03'

In [40]: followLength = struct.unpack("I", data1[:4])[0]

In [41]: followLength
Out[41]: 462738

I know this is the right length because I read the next set of binary data all the way through for a perfect fit:

In [42]: data = r("dumpy.02.27000.59169.bin") + r("dumpy.03.27000.59169.bin") + r("dumpy.04.27000.59169.bin") + r("dumpy.05.27000.59169.bin") + r("dumpy.06.27000.59169.bin") + r("dumpy.07.27000.59169.bin") + r("dumpy.08.27000.59169.bin") + r("dumpy.09.27000.59169.bin") + r("dumpy.10.27000.59169.bin") + r("dumpy.11.27000.59169.bin") + r("dumpy.12.27000.59169.bin")

In [43]: followLength - len(data)
Out[43]: 0

After that, we get the 5 null byte packets that get sent client -> server, server -> client:

In [44]: data13 = r("dumpy.13.59169.27000.bin")

In [45]: data13
Out[45]: b'\x00\x00\x00\x00\x00'
nelix commented 9 years ago

Awesome, I wonder if this is a known protocol of some kind? I had started on these notes, there is some overlap with what you have. Figure I share it anyway.

Struct

var length = buffer.slice(0, 4);
var type = buffer.slice(4, 5);
var payload = buffer.slice(5, length);

Commands

var COMMANDS = {
  0: 'KEEP_ALIVE', // we can now start sending x00/x00/x00/x00/x00 back periodically
  1: 'CONNECTION_ACCEPTED', // JSON.parse
  2: 'CONNECTION_REFUSED', // disconnect
  3: 'DATA_UPDATE', // 1 byte DATA_UPDATE_TYPE then 4 byte nodeId, see data_update_types for 5th byte+
  4: 'MAP_UPDATE', // dunno :(
  5: 'COMMAND', // payload looks like a cheap json RPC?
  6: 'COMMAND_RESPONSE', // ^^^
  // ????
};

Data Types

var DATA_UPDATE_TYPES = { // length : details
  0: 'BOOL', // 1: true if non zero
  1: 'INT_8', // 1: signed
  2: 'UINT_8', // 1: unsigned
  3: 'INT_32', // 4: signed
  4: 'UINT_32', // 4: unsigned
  5: 'FLOAT', // 4: float
  6: 'STRING', // n: null terminated, dynamic length
  7: 'ARRAY', // 2: element count; then $n 4 byte nodeId
  8: 'OBJECT', // 2: element count; then $n 4 byte nodeId with null terminated string following; then 2: removed element count; then $n 4 byte removed nodeId with null terminated string following
};
nelix commented 9 years ago

I have been messing around some more, it's a little aimless but should I try to contribute this back to the project somehow?

#!/usr/bin/env node
var hexy = require('hexy');
var util = require('util');
var _ = require('lodash');

var dissolve = require('dissolve');
var concentrate = require('concentrate');

var pipboylib = require('pipboylib');
var relay = require('pipboylib/lib/relay');

var UDPRelay = relay.UDPRelay;
var TCPRelay = relay.TCPRelay;

var falloutClient = new pipboylib.DiscoveryClient();

var COMMANDS = {
  0: function keepAlive(o) {
    // TODO: raise an event, so caller might reply?
    return o;
  },
  1: function connectionAccepted(o) {
    o.serverInfo = JSON.parse(o.payload);
    return o;
  },
  2: function connectionRefused(o) {
    // TODO: raise an event, we might want to disconnect
    return o;
  },
  3: function dataUpdate(o) {
    // TODO: this needs to be parsed inside the dissolve.loop
    o.data = hexy.hexy(o.payload.slice(0, Math.min(o.payload.length, 256)));
    return o;
  },
  4: function mapUpdate(o) {
    // TODO: this needs to be parsed inside the dissolve.loop
    o.data = hexy.hexy(o.payload.slice(0, Math.min(o.payload.length, 256)));
    return o;
  },
  5: function command(o) {
    // TODO: this needs to be parsed inside the dissolve.loop
    o.data = hexy.hexy(o.payload.slice(0, Math.min(o.payload.length, 256)));
    return o;
  },
  6: function comandReply(o) {
    // TODO: this needs to be parsed inside the dissolve.loop
    o.data = hexy.hexy(o.payload.slice(0, Math.min(o.payload.length, 256)));
    return o;
  },
};

function opcodeMissing(o) {
  o.error = 'has no handler or previous command not handled correctly';
  o.name = opcodeMissing.name;
  return o;
}

var parser = dissolve().loop(function(end) {
  this.uint32('length').tap(function() {
    this.uint8('typeId').tap(function() {
      if (this.vars.length) {
        this.buffer('payload', this.vars.length);
      }
    })
  }).tap(function() {
    var command = COMMANDS[this.vars.typeId];
    if (typeof command === 'function') {
      var message = command(this.vars);
      message.name = command.name;

      this.push(message);
    } else {
      this.push(opcodeMissing(this.vars));
    }

    this.vars = {}; // reset
  });
});

parser.on('readable', function() {
  var e;
  while (e = parser.read()) {
    console.log(e.name, _.omit(e, 'name', 'payload', 'data'));
    e.data && console.log(e.data);
  }
});

function logMessage(name, data, t) {
  false && console.log(name,
    util.format(
      '%s:%d -> %s:%d',
      t.src.address,
      t.src.port,
      t.dst.address,
      t.dst.port
    )
  );

  parser.write(data);
}

falloutClient.discover(function (error, server) {
  if (error) {
    return console.error(error);
  }
  console.log('Discovered: ', server)

  var udpRelay = new UDPRelay();
  udpRelay.bind(server.info, function (data, telemetry) {
    logMessage('[UDP Relay] ', data, telemetry);
  });

  var tcpServerInfo = {};
  tcpServerInfo.address = server.info.address;
  tcpServerInfo.port = pipboylib.FALLOUT_TCP_PORT;
  tcpServerInfo.family = server.info.family;

  var tcpRelay = new TCPRelay();
  tcpRelay.listen(tcpServerInfo, function (data, telemetry) {
    logMessage('[TCP Relay] ', data, telemetry)
  });
  console.log('UDP and TCP Relay created for: ', server.info);
});

It produces this:

Discovered:  { IsBusy: false,
  MachineType: 'PC',
  info: { address: '192.168.1.10', family: 'IPv4', port: 28000, size: 49 } }
UDP and TCP Relay created for:  { address: '192.168.1.10', family: 'IPv4', port: 28000, size: 49 }
connectionAccepted { length: 35,
  typeId: 1,
  serverInfo: { lang: 'en', version: '1.1.30.0' } }
dataUpdate { length: 404963, typeId: 3 }
00000000: 052d 3800 0000 00c8 4205 2e38 0000 0000  .-8....HB..8....
00000010: c842 043a 3800 0036 0000 0006 3d38 0000  HB.:8..6....=8..
00000020: 5045 5200 053e 3800 0000 0080 3f00 4138  PER..>8.....?.A8
00000030: 0000 0105 3f38 0000 0000 0000 0040 3800  ....?8.......@8.
00000040: 0000 083c 3800 0005 003d 3800 004e 616d  ...<8....=8..Nam
00000050: 6500 3e38 0000 5661 6c75 6500 4138 0000  e.>8..Value.A8..
00000060: 4973 4163 7469 7665 003f 3800 0064 7572  IsActive.?8..dur
00000070: 6174 696f 6e00 4038 0000 7368 6f77 4173  ation.@8..showAs
00000080: 5065 7263 656e 7400 0000 073b 3800 0001  Percent....;8...
00000090: 003c 3800 0006 3938 0000 466f 7274 6966  .<8...98..Fortif
000000a0: 7920 5065 7263 6570 7469 6f6e 0008 3838  y.Perception..88
000000b0: 0000 0300 3a38 0000 7479 7065 003b 3800  ....:8..type.;8.
000000c0: 0045 6666 6563 7473 0039 3800 0053 6f75  .Effects.98..Sou
000000d0: 7263 6500 0000 043d 7400 002a 0000 0006  rce....=t..*....
000000e0: 4074 0000 4850 0005 4174 0000 0000 003f  @t..HP..At.....?
000000f0: 0044 7400 0001 0542 7400 0000 0020 4100  .Dt....Bt.....A.

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
command { length: 28, typeId: 5 }
00000000: 7b22 7479 7065 223a 3134 2c22 6172 6773  {"type":14,"args
00000010: 223a 5b5d 2c22 6964 223a 317d            ":[],"id":1}

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
command { length: 28, typeId: 5 }
00000000: 7b22 7479 7065 223a 3134 2c22 6172 6773  {"type":14,"args
00000010: 223a 5b5d 2c22 6964 223a 327d            ":[],"id":2}

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
command { length: 28, typeId: 5 }
00000000: 7b22 7479 7065 223a 3134 2c22 6172 6773  {"type":14,"args
00000010: 223a 5b5d 2c22 6964 223a 337d            ":[],"id":3}

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
command { length: 42, typeId: 5 }
00000000: 7b22 7479 7065 223a 302c 2261 7267 7322  {"type":0,"args"
00000010: 3a5b 3432 3037 3630 3137 3730 2c30 2c32  :[4207601770,0,2
00000020: 345d 2c22 6964 223a 347d                 4],"id":4}

keepAlive { length: 0, typeId: 0 }
dataUpdate { length: 4583, typeId: 3 }
00000000: 037d 7300 0003 0000 0005 7c73 0000 e338  .}s.......|s..c8
00000010: 5e42 0582 7300 0086 a7d7 4203 8973 0000  ^B..s...'WB..s..
00000020: 0300 0000 0588 7300 0040 b290 4203 8f73  ......s..@2.B..s
00000030: 0000 fdff ffff 058e 7300 00ba 1eb5 c103  ..}.....s..:.5A.
00000040: 9673 0000 fdff ffff 0595 7300 00ba 1eb5  .s..}.....s..:.5
00000050: c103 9d73 0000 fdff ffff 059c 7300 00ba  A..s..}.....s..:
00000060: 1eb5 c103 a473 0000 fdff ffff 05a3 7300  .5A.$s..}....#s.
00000070: 00ba 1eb5 c103 ab73 0000 fdff ffff 05aa  .:.5A.+s..}....*
00000080: 7300 00ba 1eb5 c103 b273 0000 fdff ffff  s..:.5A.2s..}...
00000090: 05b1 7300 00ba 1eb5 c103 b973 0000 0300  .1s..:.5A.9s....
000000a0: 0000 05b8 7300 009a 9905 4103 c073 0000  ...8s.....A.@s..
000000b0: 0100 0000 05bf 7300 0000 0000 4104 d974  .....?s.....A.Yt
000000c0: 0000 0a00 0000 03d7 7400 0069 0000 0004  .......Wt..i....
000000d0: d874 0000 0000 0000 03d5 7400 0000 0000  Xt.......Ut.....
000000e0: 0006 d674 0000 4372 796f 0005 d474 0000  ..Vt..Cryo..Tt..
000000f0: 0000 0000 08d3 7400 0006 00d9 7400 0064  .....St....Yt..d

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
command { length: 28, typeId: 5 }
00000000: 7b22 7479 7065 223a 342c 2261 7267 7322  {"type":4,"args"
00000010: 3a5b 305d 2c22 6964 223a 357d            :[0],"id":5}

dataUpdate { length: 1325, typeId: 3 }
00000000: 035b 4800 0001 0000 0004 5c48 0000 1d00  .[H.......\H....
00000010: 0000 0487 7500 00fa 5900 0004 8875 0000  ....u..zY....u..
00000020: a259 0000 0489 7500 00aa 5a00 0004 8a75  "Y....u..*Z....u
00000030: 0000 525a 0000 048b 7500 006d 5b00 0004  ..RZ....u..m[...
00000040: 8c75 0000 2775 0000 048d 7500 00c3 7400  .u..'u....u..Ct.
00000050: 0004 8e75 0000 6248 0000 048f 7500 00a9  ...u..bH....u..)
00000060: 4900 0004 9075 0000 6473 0000 0491 7500  I....u..ds....u.
00000070: 00f8 5b00 0004 9275 0000 464c 0000 0493  .x[....u..FL....
00000080: 7500 00e5 5200 0004 9475 0000 f44b 0000  u..eR....u..tK..
00000090: 0495 7500 00cd 5100 0004 9675 0000 d94f  ..u..MQ....u..YO
000000a0: 0000 0497 7500 0080 5300 0004 9875 0000  ....u...S....u..
000000b0: 7251 0000 0499 7500 00e7 4c00 0004 9a75  rQ....u..gL....u
000000c0: 0000 6253 0000 049b 7500 0024 4d00 0004  ..bS....u..$M...
000000d0: 9c75 0000 424d 0000 049d 7500 005c 5500  .u..BM....u..\U.
000000e0: 0004 9e75 0000 3651 0000 049f 7500 00b8  ...u..6Q....u..8
000000f0: 5600 0004 a075 0000 d656 0000 04a1 7500  V....u..VV...!u.

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
command { length: 28, typeId: 5 }
00000000: 7b22 7479 7065 223a 3134 2c22 6172 6773  {"type":14,"args
00000010: 223a 5b5d 2c22 6964 223a 367d            ":[],"id":6}

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
command { length: 46, typeId: 5 }
00000000: 7b22 7479 7065 223a 322c 2261 7267 7322  {"type":2,"args"
00000010: 3a5b 3432 3037 3630 3137 3731 2c5b 305d  :[4207601771,[0]
00000020: 2c38 2c32 395d 2c22 6964 223a 377d       ,8,29],"id":7}

dataUpdate { length: 2470, typeId: 3 }
00000000: 0401 7600 000a 0000 0003 ff75 0000 d402  ..v........u..T.
00000010: 0000 0400 7600 0000 0000 0003 fd75 0000  ....v.......}u..
00000020: 0000 0000 06fe 7500 002e 3338 0005 fc75  .....~u...38..|u
00000030: 0000 0000 0000 08fb 7500 0006 0001 7600  .......{u.....v.
00000040: 0064 616d 6167 6554 7970 6500 ff75 0000  .damageType..u..
00000050: 5661 6c75 6500 0076 0000 5661 6c75 6554  Value..v..ValueT
00000060: 7970 6500 fd75 0000 6469 6666 5261 7469  ype.}u..diffRati
00000070: 6e67 00fe 7500 0074 6578 7400 fc75 0000  ng.~u..text.|u..
00000080: 6469 6666 6572 656e 6365 0000 0005 0676  difference.....v
00000090: 0000 e338 5e42 0407 7600 0002 0000 0003  ..c8^B..v.......
000000a0: 0476 0000 0300 0000 0605 7600 0024 524f  .v........v..$RO
000000b0: 4600 0503 7600 00e3 385e 4208 0276 0000  F...v..c8^B..v..
000000c0: 0500 0676 0000 5661 6c75 6500 0776 0000  ...v..Value..v..
000000d0: 5661 6c75 6554 7970 6500 0476 0000 6469  ValueType..v..di
000000e0: 6666 5261 7469 6e67 0005 7600 0074 6578  ffRating..v..tex
000000f0: 7400 0376 0000 6469 6666 6572 656e 6365  t..v..difference

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
command { length: 28, typeId: 5 }
00000000: 7b22 7479 7065 223a 3134 2c22 6172 6773  {"type":14,"args
00000010: 223a 5b5d 2c22 6964 223a 387d            ":[],"id":8}

command { length: 42, typeId: 5 }
00000000: 7b22 7479 7065 223a 302c 2261 7267 7322  {"type":0,"args"
00000010: 3a5b 3432 3037 3539 3934 3137 2c30 2c33  :[4207599417,0,3
00000020: 315d 2c22 6964 223a 397d                 1],"id":9}

command { length: 43, typeId: 5 }
00000000: 7b22 7479 7065 223a 302c 2261 7267 7322  {"type":0,"args"
00000010: 3a5b 3432 3037 3539 3934 3137 2c30 2c33  :[4207599417,0,3
00000020: 315d 2c22 6964 223a 3130 7d              1],"id":10}

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
command { length: 43, typeId: 5 }
00000000: 7b22 7479 7065 223a 302c 2261 7267 7322  {"type":0,"args"
00000010: 3a5b 3432 3037 3539 3933 3331 2c30 2c33  :[4207599331,0,3
00000020: 315d 2c22 6964 223a 3131 7d              1],"id":11}

dataUpdate { length: 9, typeId: 3 }
00000000: 03ea 6100 000e 0000 00                   .ja......

dataUpdate { length: 1869, typeId: 3 }
00000000: 064d 7600 0048 5000 054e 7600 0000 0000  .Mv..HP..Nv.....
00000010: 3f00 5176 0000 0105 4f76 0000 0000 2041  ?.Qv....Ov.....A
00000020: 0050 7600 0000 084c 7600 0005 004d 7600  .Pv....Lv....Mv.
00000030: 004e 616d 6500 4e76 0000 5661 6c75 6500  .Name.Nv..Value.
00000040: 5176 0000 4973 4163 7469 7665 004f 7600  Qv..IsActive.Ov.
00000050: 0064 7572 6174 696f 6e00 5076 0000 7368  .duration.Pv..sh
00000060: 6f77 4173 5065 7263 656e 7400 0000 0653  owAsPercent....S
00000070: 7600 0052 6164 7300 0554 7600 0000 00c0  v..Rads..Tv....@
00000080: 4000 5776 0000 0005 5576 0000 0000 0000  @.Wv....Uv......
00000090: 0056 7600 0000 0852 7600 0005 0053 7600  .Vv....Rv....Sv.
000000a0: 004e 616d 6500 5476 0000 5661 6c75 6500  .Name.Tv..Value.
000000b0: 5776 0000 4973 4163 7469 7665 0055 7600  Wv..IsActive.Uv.
000000c0: 0064 7572 6174 696f 6e00 5676 0000 7368  .duration.Vv..sh
000000d0: 6f77 4173 5065 7263 656e 7400 0000 073e  owAsPercent....>
000000e0: 7400 0003 003f 7400 004c 7600 0052 7600  t....?t..Lv..Rv.
000000f0: 0004 5c48 0000 2100 0000 0070 7600 0001  ..\H..!....pv...

dataUpdate { length: 15, typeId: 3 }
00000000: 073e 7400 0002 003f 7400 004c 7600 00    .>t....?t..Lv..

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
command { length: 29, typeId: 5 }
00000000: 7b22 7479 7065 223a 3134 2c22 6172 6773  {"type":14,"args
00000010: 223a 5b5d 2c22 6964 223a 3132 7d         ":[],"id":12}

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
command { length: 43, typeId: 5 }
00000000: 7b22 7479 7065 223a 302c 2261 7267 7322  {"type":0,"args"
00000010: 3a5b 3432 3037 3539 3933 3737 2c30 2c33  :[4207599377,0,3
00000020: 335d 2c22 6964 223a 3133 7d              3],"id":13}

dataUpdate { length: 6, typeId: 3 }
00000000: 0012 0000 0001                           ......

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
dataUpdate { length: 12, typeId: 3 }
00000000: 000f 0000 0001 0012 0000 0000            ............

command { length: 29, typeId: 5 }
00000000: 7b22 7479 7065 223a 3134 2c22 6172 6773  {"type":14,"args
00000010: 223a 5b5d 2c22 6964 223a 3134 7d         ":[],"id":14}

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
command { length: 29, typeId: 5 }
00000000: 7b22 7479 7065 223a 3134 2c22 6172 6773  {"type":14,"args
00000010: 223a 5b5d 2c22 6964 223a 3135 7d         ":[],"id":15}

keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
keepAlive { length: 0, typeId: 0 }
dataUpdate { length: 6, typeId: 3 }
00000000: 000f 0000 0000                           ......

keepAlive { length: 0, typeId: 0 }
dataUpdate { length: 6, typeId: 3 }
00000000: 0012 0000 0001                           ......

dataUpdate { length: 15, typeId: 3 }
00000000: 0012 0000 0000 0580 6f00 0035 e140 3e    ........o..5a@>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0087 7440 3e                   ..o...t@>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00d5 e43f 3e                   ..o..Ud?>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0027 b83f 3e                   ..o..'8?>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00b8 723f 3e                   ..o..8r?>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00cb 1e3f 3e                   ..o..K.?>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00d9 a73e 3e                   ..o..Y'>>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0096 5d3e 3e                   ..o...]>>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 001d d23c 3e                   ..o...R<>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 006f a53c 3e                   ..o..o%<>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0096 7d3c 3e                   ..o...}<>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00bc 553c 3e                   ..o..<U<>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00e3 2d3c 3e                   ..o..c-<>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 000a 063c 3e                   ..o....<>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0030 de3b 3e                   ..o..0^;>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0044 8a3b 3e                   ..o..D.;>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0057 363b 3e                   ..o..W6;>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 002b fb3a 3e                   ..o..+{:>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0052 933a 3e                   ..o..R.:>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 003a 443a 3e                   ..o..:D:>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 004d f039 3e                   ..o..Mp9>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 004d b039 3e                   ..o..M09>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0074 4839 3e                   ..o..tH9>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 005c f938 3e                   ..o..\y8>

keepAlive { length: 0, typeId: 0 }
dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 006f a538 3e                   ..o..o%8>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 006f 6538 3e                   ..o..oe8>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 006a 0238 3e                   ..o..j.8>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 007e ae37 3e                   ..o..~.7>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0065 5f37 3e                   ..o..e_7>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00f6 1937 3e                   ..o..v.7>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00f2 b636 3e                   ..o..r66>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0005 6336 3e                   ..o...c6>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0000 0036 3e                   ..o....6>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00a9 c935 3e                   ..o..)I5>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0079 6b35 3e                   ..o..yk5>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0061 1c35 3e                   ..o..a.5>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0074 c834 3e                   ..o..tH4>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0005 8334 3e                   ..o....4>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 002b 1b34 3e                   ..o..+.4>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0027 b833 3e                   ..o..'83>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0027 7833 3e                   ..o..'x3>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0027 3833 3e                   ..o..'83>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 004d d032 3e                   ..o..MP2>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 008c 7732 3e                   ..o...w2>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0048 2d32 3e                   ..o..H-2>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 001d f231 3e                   ..o...r1>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 006f 8531 3e                   ..o..o.1>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0057 3631 3e                   ..o..W61>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0096 dd30 3e                   ..o...]0>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 003f a730 3e                   ..o..?'0>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0065 3f30 3e                   ..o..e?0>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 004d f02f 3e                   ..o..Mp/>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 001d 922f 3e                   ..o..../>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 009b 602f 3e                   ..o...`/>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0096 fd2e 3e                   ..o...}.>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00d5 a42e 3e                   ..o..U$.>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00bc 552e 3e                   ..o..<U.>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00bc 152e 3e                   ..o..<..>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00b8 b22d 3e                   ..o..82->

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00f6 592d 3e                   ..o..vY->

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00b3 0f2d 3e                   ..o..3.->

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 009b c02c 3e                   ..o...@,>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00d9 672c 3e                   ..o..Yg,>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00ed 132c 3e                   ..o..m.,>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00d5 c42b 3e                   ..o..UD+>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00d5 842b 3e                   ..o..U.+>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00fb 1c2b 3e                   ..o..{.+>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 000e c92a 3e                   ..o...I*>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00f6 792a 3e                   ..o..vy*>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00f6 392a 3e                   ..o..v9*>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00f2 d629 3e                   ..o..rV)>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0005 8329 3e                   ..o....)>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0018 2f29 3e                   ..o.../)>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00d5 e428 3e                   ..o..Ud(>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00d0 8128 3e                   ..o..P.(>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00e3 2d28 3e                   ..o..c-(>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 009f e327 3e                   ..o...c'>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0074 a827 3e                   ..o..t('>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 009b 4027 3e                   ..o...@'>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00ae ec26 3e                   ..o...l&>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00c1 9826 3e                   ..o..A.&>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 0096 5d26 3e                   ..o...]&>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00bc f525 3e                   ..o..<u%>

dataUpdate { length: 9, typeId: 3 }
00000000: 0580 6f00 00d0 a125 3e                   ..o..P!%>

dataUpdate { length: 9, typeId: 3 }
00000000: 0000 0000 0005 806f 00                   .......o.
rgbkrk commented 9 years ago

Wow! That's great.

wonder if this is a known protocol of some kind

I was wondering the same thing, though I haven't dealt with enough binary formats

should I try to contribute this back to the project somehow?

Absolutely! Since pipboyrelay was made for exploration of this protocol and we're both getting the same findings, this makes perfect sense. While working on this PR I've been wanting to be able to set flags and args. Any preference you have on command line parsers? commander?

As for the protocol/format parsing bits, I think it makes sense to bring that in to pipboylib.

On a side note, I'm really glad you've pointed us towards dissolve. I noticed binary hasn't been touched in a while, even though there are PRs with bug fixes. Was going to pave ahead there until otherwise.

Time for me to dig into what's here more.

rgbkrk commented 9 years ago

Of note, I'm more than happy to shelve this PR if you contribute your work into the main cli.

nelix commented 9 years ago

Commander seems nice, there is a lib called concentrate I thought might be nice for building commands.

Both concentrate and dissolve are written by a friend of mine.

For a first pass maybe I add a new module to pipboyrelay that exports a parser and leave the coupling to the dependent?

rgbkrk commented 9 years ago

there is a lib called concentrate I thought might be nice for building commands

looks great to me!

For a first pass maybe I add a new module to pipboyrelay that exports a parser and leave the coupling to the dependent?

:+1:

rgbkrk commented 9 years ago

Closing, as I don't need this code in particular. Just wanted some more exploration. @nelix topped it off!