转载

极客玩转辐射4 pip boy设备的正确姿势

上周跟大多数游戏玩家一样,我购买了期待已久的辐射4。与其早前版本一样,辐射4也配备有一个pip boy设备,这设备十分炫酷,今天我们就来好好玩玩吧!

极客玩转辐射4 pip boy设备的正确姿势

这次的开发者Bethesda同时还给我们带来了一款兄弟App用来远程访问咱们的Pip Boy设备。你可以浏览地图,查看库存,修改武器以及快速旅行!

在发现我正在运行的PS4之后,我脑子立即想到:

“嘿,它是如何发现我网络中的游戏的呢?”

首先通过nmap扫描网络找到我的PS4以及正在监听的服务:

$ nmap 192.168.1.*  Nmap scan report for unknown0CFE45340EE1 (192.168.1.71)  Starting Nmap 6.47 ( http://nmap.org ) at 2015-11-19 22:20 CST  ...  Host is up (0.00056s latency).  Not shown: 999 closed ports  PORT      STATE SERVICE  27000/tcp open  flexlm0  ...

有了这些,我可以辨别在端口27000运行有一个TCP服务:

$ curl 192.168.1.71:27000  #{"lang":"en","version":"1.1.21.0"}

哇!HTTP正在工作,可悲的是我们不知道REST端点。

然而pip boy应用不可能知道PS4的IP地址,所以它肯定开启了一个服务允许其他设备发现它。兴奋于预期的脱离App获取数据,从我的同事 Jon Frederic 捕获到的一些数据包中看来这个发现协议和TCPdump很相像。

在移动App上运行扫描控制台,就这会足以看到一个UDP payload从移动手机发送到广播地址(255.255.255.255),端口28000:

{    "cmd" : "autodiscover"  }

服务器响应:

{     "IsBusy" : false,     "MachineType" : "PS4"  }

如果你有安装socat,你可以直接这么搞:

echo '{"cmd":"autodiscover"}' | /    socat - UDP-DATAGRAM:255.255.255.255:28000,broadcast

至今我们得知辐射4服务至少有2个监听服务:28000端口上的UDP,27000端口上的TCP。由于对这个协议不太了解,所以我们还需要更多的研究研究从pip boy到控制台的正常通信。我们可以继续嗅探通信,通过ARP投毒进行中间人攻击,或者我们可以写一个Relay

Relay抓取数据

relay功能建立另一个辐射4移动应用服务进行连接,实际上数据包是发送到合法的那一个。

极客玩转辐射4 pip boy设备的正确姿势

你可以使用类似socat的工具来完成这一步,但是我选择使用Node.js来完成这个工作。为什么这么选择在之后你应该会了解的。

UDP relay

对于relay我们还得在真是客户端(pip boy app)和辐射4服务器之间写一个函数作为媒介。每次客户端连接到relay,我们都会创建一个假的客户端来连接到真实的辐射4服务器。客户端与服务端通信,在它们传递消息的同时复制这些消息。

首先我们得打开服务端socket:

var upstreamInfo = {     address: YOUR_CONSOLE_OR_PC_IP  port: 28000 // The Fallout 4 UDP Port  }  var server = dgram.createSocket('udp4')  server.bind(upstreamInfo.port, '0.0.0.0')

对于每条接收到消息,我们都要设置另外一个socket作为假客户端。接着在真实服务端和pip boy客户端直接转发消息。

server.on('message', function (message, clientInfo) {    var fakeClient = dgram.createSocket('udp4')       // fakeClient.on('message', ...) // Defined below       // fakeClient.bind(...)  })

上面注释的两部分,下面写的更详细。我们每次获得消息都会复制,注意遥测数据,将消息发送给真实客户端并提供复制缓冲和遥测的callback

fakeClient.on('message', function (message, serverInfo) {    var copiedBuffer = new Buffer(message.length)     message.copy(copiedBuffer)     // Now emulate our server     server.send(message, 0, message.length, clientInfo.port, clientInfo.address)   var telemetry = {      'src': serverInfo,           'dst': clientInfo     }    cb(copiedBuffer, telemetry)  })

绑定客户端,同样复制消息,将消息发送给服务器并将数据传给callback

// As soon as our client is ready, go ahead and send their message onward  fakeClient.bind(undefined, undefined, function () {     var copiedBuffer = new Buffer(message.length)      message.copy(copiedBuffer)   fakeClient.send(message, 0, message.length, upstreamInfo.port, upstreamInfo.address)   var telemetry = {      'src': clientInfo,      'dst': upstreamInfo      }    cb(copiedBuffer, telemetry) })

TCP relay

TCP relay的设置类似,我们将创建一个TCPRelay,其下还有一个net.Server。最大的不同是我们得维持所有的正在使用的假客户端。

/**    * Create a TCP relay for an upstream server    * @constructor    */  /**    * Listen for traffic to relay to/from an upstream server    * @param {Object} upstreamInfo    * @param {string} upstreamInfo.address    * @param {number} upstreamInfo.port    * @param {relayCallback} - callback that handles new data    */  var TCPRelay = function TCPRelay () {     this.server = net.createServer({'allowHalfOpen': true})  }

提供TCPRelay.listen来模拟net.Server.listen

TCPRelay.prototype.listen = function listen (upstreamInfo, cb) {    this.server.on('connection', function (client) {      // Now we create our fake client      var fakeClient = new net.Socket()      fakeClient.connect(upstreamInfo.port, upstreamInfo.address)      // Get the actual client info for logging where the traffic really came from      var actualClientInfo = {}      actualClientInfo.address = client.remoteAddress      actualClientInfo.port = client.remotePort      actualClientInfo.family = client.remoteFamily      // Register handlers for the fakeClient      // These each get explained below but should be inserted here      // fakeClient.on('connect', function() { ... })      // fakeClient.on('data', function() { ... })      // fakeClient.on('close', function() { ... })      // fakeClient.on('end', function() { ... })           })    this.server.listen({'port': upstreamInfo.port}) }

当连接到假客户端,我们准备记录来自客户端的数据。从客户端向假客户端发送消息,这些数据也会发送给辐射4服务器

fakeClient.on('connect', function () {   // Once we're connected, we can get each message from the client   client.on('data', function (message) {    var copiedBuffer = new Buffer(message.length)     message.copy(copiedBuffer)     // To the server    fakeClient.write(message)     var serverInfo = {}     serverInfo.address = fakeClient.remoteAddress     serverInfo.port = fakeClient.remotePort     serverInfo.family = fakeClient.remoteFamily     var telemetry = {       'src': actualClientInfo,       'dst': serverInfo     }     cb(copiedBuffer, telemetry)       }) }) 

每次假客户端接收到的数据,都来自辐射4服务器并且会将其转发给真实客户端

fakeClient.on('data', function (message) {   var copiedBuffer = new Buffer(message.length)   message.copy(copiedBuffer)      var serverInfo = {}   serverInfo.address = fakeClient.remoteAddress   serverInfo.port = fakeClient.remotePort   serverInfo.family = fakeClient.remoteFamily      var telemetry = {        'src': serverInfo,        'dst': actualClientInfo      }         client.write(message)               cb(copiedBuffer, telemetry) }) 

另一面我们也需要处理关闭假客户端和真实客户端。记住我们需要直接进行镜像操作,同样的我们也需要关闭客户端。

fakeClient.on('close', function (hadError) {    if (hadError) {        console.log('closure error')    }   client.close() })  fakeClient.on('end', function () {    client.end()   })

碎片整理

现在我们有一个TCPRelay和一个UDPRelay,可以自动发现一个运行的服务,当然也可以做一个小工具来帮助完成任务

我已经将这两个relays打包

pipboylib

pipboyrelay

第二个pipboyrelay是一个CLI工具,其依赖于pipboylib你可以使用这个工具转储数据。

pip boy设备relay

如果你满足以下条件你可以直接运行relay

1.PC或者PS4版本的辐射4(Xbox版本还未确认) 2.Android或者iOS版本的pip boy app 3.在辐射4中启用了in-game选项 4.Node.js及npm

Node.js和npm下,安装pipboyrelay就像安装CLI工具:

npm install -g pipboyrelay

使用以下命令行运行pipboyrelay:

$ pipboyrelay  Discovered:  { IsBusy: false,     MachineType: 'PS4',     info: { address: '192.168.1.71', family: 'IPv4', port: 28000, size: 50 } }

它会自动发现在本地网络中活动的游戏服务,并创建Android或者iOS app可识别的端点。打开移动App并导航到连接设置

极客玩转辐射4 pip boy设备的正确姿势

连接到地址,你应该能够看到这些数据飘过:

UDP and TCP Relay created for:  { address: '192.168.1.71', family: 'IPv4', port: 28000, size: 50 }  listening  [TCP Relay] 192.168.1.71:27000 -> ::ffff:192.168.1.67:55232 00000000: 2300 0000 017b 226c 616e 6722 3a22 656e  #....{"lang":"en  00000010: 222c 2276 6572 7369 6f6e 223a 2231 2e31  ","version":"1.1  00000020: 2e32 312e 3022 7d0a                      .21.0"}.  [TCP Relay] 192.168.1.71:27000 -> ::ffff:192.168.1.67:55232  00000000: 754e 0600 0306 5290 0f00 2447 656e 6572  uN....R...$Gener  00000010: 616c 0003 6290 0f00 1e00 0000 0661 900f  al..b........a..  00000020: 004c 6f63 6174 696f 6e73 2044 6973 636f  .Locations.Disco  ...  [TCP Relay] 192.168.1.71:27000 -> ::ffff:192.168.1.67:55232  00000000: 7565 002d 910f 0074 6578 7400 2f91 0f00  ue.-...text./...  00000010: 7368 6f77 4966 5a65 726f 0000 0003 3291  showIfZero....2.  00000020: 0f00 0000 0000 0631 910f 0046 6974 7320  .......1...Fits.  ...

注意观察0×18 (0x1e),"Locations Discovered"发生之前:

[TCP Relay] 192.168.1.71:27000 -> ::ffff:192.168.1.67:55232  00000000: 754e 0600 0306 5290 0f00 2447 656e 6572  uN....R...$Gener  00000010: 616c 0003 6290 0f00 1e00 0000 0661 900f  al..b........a..  ------------------------------^^  00000020: 004c 6f63 6174 696f 6e73 2044 6973 636f  .Locations.Disco

0x1e是我使用的locations discovered当前数量,30

看起来辐射4格式是一个二进制格式并且是一个纯文本,这是一个好消息,这样我们就更容易找到格式并创造新东西。

当你探索荒地时运行这个relay,你可以在relay中看到坐标滚动。

STAT转储

在OS X和Linux你可以使用nc(netcat)直接从PC或者控制台获取所有STAT

$ nc 192.168.1.71 27000 | xxd | head -n 16  00000000: 2300 0000 017b 226c 616e 6722 3a22 656e  #....{"lang":"en  00000010: 222c 2276 6572 7369 6f6e 223a 2231 2e31  ","version":"1.1  00000020: 2e32 312e 3022 7d0a 59f0 0600 0306 81cc  .21.0"}.Y.......  00000030: 1e00 2447 656e 6572 616c 0003 91cc 1e00  ..$General......  00000040: 2200 0000 0690 cc1e 004c 6f63 6174 696f  "........Locatio  00000050: 6e73 2044 6973 636f 7665 7265 6400 0092  ns Discovered...  00000060: cc1e 0001 088f cc1e 0003 0091 cc1e 0076  ...............v  00000070: 616c 7565 0090 cc1e 0074 6578 7400 92cc  alue.....text...  00000080: 1e00 7368 6f77 4966 5a65 726f 0000 0003  ..showIfZero....  00000090: 95cc 1e00 0400 0000 0694 cc1e 004c 6f63  .............Loc  000000a0: 6174 696f 6e73 2043 6c65 6172 6564 0000  ations Cleared..  000000b0: 96cc 1e00 0108 93cc 1e00 0300 95cc 1e00  ................  000000c0: 7661 6c75 6500 94cc 1e00 7465 7874 0096  value.....text..  000000d0: cc1e 0073 686f 7749 665a 6572 6f00 0000  ...showIfZero...  000000e0: 0399 cc1e 000a 0000 0006 98cc 1e00 4461  ..............Da  000000f0: 7973 2050 6173 7365 6400 009a cc1e 0001  ys Passed....... ... more data ...

*参考来源: Getcarina ,编译/FB小编鸢尾,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)

正文到此结束
Loading...