Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Library for Decoding Wireless Advertising Packets. We believe in an open Internet of Things.
Library for wireless advertising packet decoding. Currently supports the following protocols:
For a live, interactive version of advlib visit reelyactive.github.io/advlib.
npm install advlib
var advlib = require('advlib');
var rawHexPacket = '421655daba50e1fe0201050c097265656c79416374697665';
var processedPacket = advlib.ble.process(rawHexPacket);
console.log(JSON.stringify(processedPacket, null, " "));
The console output should appear as follows:
{
type: "ADVA-48",
value: "fee150bada55",
advHeader: {
type: "ADV_NONCONNECT_IND",
length: 22,
txAdd: "random",
rxAdd: "public"
},
advData: {
flags: [ "LE Limited Discoverable Mode", "BR/EDR Not Supported" ],
completeLocalName: "reelyActive"
}
}
Process a raw packet (as a hexadecimal string) with the following command:
advlib.ble.process(rawHexPacket);
The library is organised hierarchically so that the separate elements of a packet can be processed individually. Refer to the index below for details on each element:
Process a 16-bit header (as a hexadecimal string) with the following command:
advlib.ble.header.process(rawHexHeader);
For reference, the 16-bit header is as follows (reading the hexadecimal string from left to right):
Bit(s) | Function |
---|---|
15 | RxAdd: 0 = public, 1 = random |
14 | TxAdd: 0 = public, 1 = random |
13-12 | Reserved for Future Use (RFU) |
11-8 | Type (see table below) |
7-6 | Reserved for Future Use (RFU) |
5-0 | Payload length in bytes |
And the advertising packet types are as follows:
Type | Packet | Purpose |
---|---|---|
0 | ADV_IND | Connectable undirected advertising |
1 | ADV_DIRECT_IND | Connectable directed advertising |
2 | ADV_NONCONN_IND | Non-connectable undirected advertising |
3 | SCAN_REQ | Scan for more info from advertiser |
4 | SCAN_RSP | Response to scan request from scanner |
5 | CONNECT_REQ | Request to connect |
6 | ADV_DISCOVER_IND | Scannable undirected advertising |
For example:
advlib.ble.header.process('4216');
would yield:
{
rxAdd: "public",
txAdd: "random",
type: "ADV_NONCONNECT_IND",
length: 22
}
Process a 48-bit address (as a hexadecimal string) with the following command:
advlib.ble.address.process(rawHexAddress);
For reference, the 48-bit header is as follows (reading the hexadecimal string from left to right):
Bit(s) | Address component |
---|---|
47-40 | xx:xx:xx:xx:xx:## |
39-32 | xx:xx:xx:xx:##:xx |
31-24 | xx:xx:xx:##:xx:xx |
23-16 | xx:xx:##:xx:xx:xx |
15-8 | xx:##:xx:xx:xx:xx |
7-0 | ##:xx:xx:xx:xx:xx |
This is best illustrated with an example:
advlib.ble.address.process('0123456789ab');
Would yield:
{
type: "ADVA-48",
value: "ab8967452301"
}
which can alternatively be represented as ab:89:67:45:23:01.
Process GAP data (as a hexadecimal string) with the following command:
advlib.ble.data.process(rawHexData);
For reference, the structure of the data is as follows:
Byte(s) | Data component |
---|---|
0 | Length of the data in bytes (including type and data) |
1 | GAP Data Type (see table below) |
2 to length | Type-specifc data |
The Generic Access Profile Data Types are listed on the Bluetooth GAP Assigned Numbers website. The following table lists the Data Types, their names and the section in this document in which they are described.
Data Type | Data Type Name | See advlib section |
---|---|---|
0x01 | Flags | Flags |
0x02 | Incomplete List of 16-bit UUIDs | UUID |
0x03 | Complete List of 16-bit UUIDs | UUID |
0x04 | Incomplete List of 32-bit UUIDs | UUID |
0x05 | Complete List of 32-bit UUIDs | UUID |
0x06 | Incomplete List of 128-bit UUIDs | UUID |
0x07 | Complete List of 128-bit UUIDs | UUID |
0x08 | Shortened Local Name | Local Name |
0x09 | Complete Local Name | Local Name |
0x0a | Tx Power Level | Tx Power |
0x0d | Class of Device | Generic Data |
0x0e | Simple Pairing Hash C-192 | Generic Data |
0x0f | Simple Pairing Randomizer R-192 | Generic Data |
0x10 | Security Manager TK Value | Generic Data |
0x11 | Security Manager OOB Flags | Generic Data |
0x12 | Slave Connection Interval Range | SCIR |
0x14 | 16-bit Solicitation UUIDs | Solicitation |
0x15 | 128-bit Solicitation UUIDs | Solicitation |
0x16 | Service Data 16-bit UUID | Service Data |
0x17 | Public Target Address | Generic Data |
0x18 | Random Target Address | Generic Data |
0x19 | Public Target Address | Generic Data |
0x1a | Advertising Interval | Generic Data |
0x1b | LE Bluetooth Device Address | Generic Data |
0x1c | LE Bluetooth Role | Generic Data |
0x1d | Simple Pairing Hash C-256 | Generic Data |
0x1e | Simple Pairing Hash Randomizer C-256 | Generic Data |
0x1f | 32-bit Solicitation UUIDs | Solicitation |
0x20 | Service Data 32-bit UUID | Service Data |
0x21 | Service Data 128-bit UUID | Service Data |
0x3d | 3-D Information Data | Generic Data |
0xff | Manufacturer Specific Data | Mfr. Specific Data |
Process a UUID assigned to the device with any of the following commands:
advlib.ble.data.gap.uuid.nonComplete16BitUUIDs(payload, cursor, advertiserData);
advlib.ble.data.gap.uuid.complete16BitUUIDs(payload, cursor, advertiserData);
advlib.ble.data.gap.uuid.nonComplete128BitUUIDs(payload, cursor, advertiserData);
advlib.ble.data.gap.uuid.complete128BitUUIDs(payload, cursor, advertiserData);
This is best illustrated with an example:
var payload = '16074449555520657669746341796c656572';
advlib.ble.data.gap.uuid.complete128BitUUIDs(payload, 0, {});
For reference, the example payload is interpreted as follows:
Byte(s) | Hex String | Description |
---|---|---|
0 | 16 | Length, in bytes, of type and data |
1 | 07 | GAP Data Type for Complete 128-bit UUID |
2 to 16 | 4449555520657669746341796c656572 | reelyActive's 128-bit UUID |
Which would add the following property to advData:
complete128BitUUIDs: "7265656c794163746976652055554944"
Process the device's local name, complete or shortened, with the following commands, respectively:
advlib.ble.data.gap.localname.completeLocalName(payload, cursor, advertiserData);
advlib.ble.data.gap.localname.shortenedLocalName(payload, cursor, advertiserData);
This is best illustrated with an example:
advlib.ble.data.gap.localname.completeLocalName('12097265656c79416374697665', 0, {});
For reference, the example payload is interpreted as follows:
Byte(s) | Hex String | Description |
---|---|---|
0 | 12 | Length, in bytes, of type and data |
1 | 09 | GAP Data Type for Complete Local Name |
2 to 12 | 7265656c79416374697665 | ASCII representation of 'reelyActive' |
Which would add the following property to advData:
completeLocalName: "reelyActive"
Process the flags with the following command:
advlib.ble.data.gap.flags.process(payload, cursor, advertiserData);
For reference, the flags are as follows:
Bit | Description |
---|---|
0 | LE Limited Discoverable Mode |
1 | LE General Discoverable Mode |
2 | BR/EDR Not Supported |
3 | Simultaneous LE and BR/EDR to Same Device Capable (Controller) |
4 | Simultaneous LE and BR/EDR to Same Device Capable (Host) |
5 | Reserved |
This is best illustrated with an example:
advlib.ble.data.gap.flags.process('020104', 0, {});
For reference, the example payload is interpreted as follows:
Byte | Hex String | Description |
---|---|---|
0 | 02 | Length, in bytes, of type and data |
1 | 01 | GAP Data Type for flags |
2 | 04 | See table above |
Which would add the following property to advData:
flags: [ "BR/EDR Not Supported" ]
Process manufacturer specific data with the following command:
advlib.ble.data.gap.manufacturerspecificdata.process(payload, cursor, advertiserData);
This is best illustrated with an example:
advlib.ble.data.gap.manufacturerspecificdata.process('03ff8c00', 0, {});
For reference, the example payload is interpreted as follows:
Byte(s) | Hex String | Description |
---|---|---|
0 | 03 | Length, in bytes, of type and data |
1 | ff | GAP Data Type for manufacturer specific data |
2-3 | 8c00 | Gimbal company identifier code (bytes reversed) |
Which would add the following property to advData:
manufacturerSpecificData: {
companyIdentifierCode: "008c",
data: ""
}
A specific case of manufacturer specific data is the iBeacon:
var payload = '26ff4c000215b9407f30f5f8466eaff925556b57fe6d294c903974';
advlib.ble.data.gap.manufacturerspecificdata.process(payload, 0, {});
For reference, the iBeacon payload is interpreted as follows:
Byte(s) | Hex String | Description |
---|---|---|
0 | 26 | Length, in bytes, of type and data |
1 | ff | GAP Data Type for manufacturer specific data |
2-3 | 4c00 | Apple company identifier code (bytes reversed) |
4-5 | 0215 | Identifier code for iBeacon |
6-21 | b9407f30f5f8466eaff925556b57fe6d | UUID (assigned by Apple) |
21-22 | 294c | Major |
23-24 | 9039 | Minor |
25 | 74 | TxPower (see TxPower section) |
Which would add the following property to advData:
manufacturerSpecificData: {
iBeacon: {
uuid: "b9407f30f5f8466eaff925556b57fe6d",
major: "294c",
minor: "9039",
txPower: "116dBm",
licenseeName: "Estimote"
}
}
A specific case of manufacturer specific data is that of StickNFind. The following proprietary payloads are supported:
Process Tx Power Level with the following command:
advlib.ble.data.gap.txpower.process(payload, cursor, advertiserData);
This is best illustrated with an example:
advlib.ble.data.gap.txpower.process('020a7f', 0, {});
For reference, the example payload is interpreted as follows:
Byte(s) | Hex String | Description |
---|---|---|
0 | 02 | Length, in bytes, of type and data |
1 | 0a | GAP Data Type for TxPower |
2 | 7f | TxPower (see table below) |
TxPower is a two's complement value which is interpreted as follows:
Hex String | Power dBm |
---|---|
7f | 127 dBm |
00 | 0 dBm |
ff | -128 dBm |
Which would add the following property to advData:
txPower: "127dBm"
Process the Slave Connection Interval Range with the following command:
advlib.ble.data.gap.slaveconnectionintervalrange.process(payload, cursor, advertiserData);
This is best illustrated with an example:
advlib.ble.data.gap.slaveconnectionintervalrange.process('061200060c80', 0, {});
For reference, the example payload is interpreted as follows:
Byte(s) | Hex String | Description |
---|---|---|
0 | 06 | Length, in bytes, of type and data |
1 | 12 | GAP Data Type for Slave Connection Interval Range |
2-6 | 00060c80 | Min and max intervals (see table below) |
And the intervals are intepreted as follows:
Byte(s) | Hex String | Description |
---|---|---|
0-1 | 0006 | Min interval = 6 x 1.25 ms = 7.5 ms |
2-3 | 0c80 | Max interval = 12128 x 1.25 ms = 15160 ms |
Which would add the following property to advData:
slaveConnectionIntervalRange: "00060c80"
Process a Service Solicitation UUID with any of the following commands:
advlib.ble.data.gap.solicitation.solicitation16BitUUIDs(payload, cursor, advertiserData);
advlib.ble.data.gap.solicitation.solicitation128BitUUIDs(payload, cursor, advertiserData);
This is best illustrated with an example:
advlib.ble.data.gap.uuid.solicitation16BitUUIDs('0314d8fe', 0, {});
For reference, the example payload is interpreted as follows:
Byte(s) | Hex String | Description |
---|---|---|
0 | 03 | Length, in bytes, of type and data |
1 | 14 | GAP Data Type for 16-bit Service Solicitation UUID |
2-3 | d8fe | Google's UriBeacon UUID (bytes reversed) |
Which would add a property to advData as follows:
solicitation16BitUUIDs: "fed8"
Process service data assigned to the device.
advlib.ble.data.gap.servicedata.process(payload, cursor, advertiserData);
This is best illustrated with an example:
advlib.ble.data.gap.servicedata.process('09160a181204eb150000', 0, {});
For reference, the example payload is interpreted as follows:
Byte(s) | Hex String | Description |
---|---|---|
0 | 09 | Length, in bytes, of type and data |
1 | 16 | GAP Data Type for service data |
2-3 | 0a18 | UUID (bytes reversed) |
4-9 | 1204eb150000 | Service Data |
Which would add the following properties to advData:
serviceData: {
uuid : "180a",
data : "1204eb150000",
specificationName: "Device Information"
}
In this case, the service UUID represents one of the GATT Standard Services and is processed as such.
Additional examples for service UUIDs among the GATT Member Services are given in that section below.
Process GATT service data (as a hexadecimal string) with the following command:
advlib.ble.data.gatt.process(advData);
Where advData contains a serviceData object (see Service Data), for instance:
advData: {
serviceData: {
uuid: "fed8",
data: "00f2027265656c7961637469766507"
}
}
Based on the UUID, the serviceData will be parsed as either a member service or a standard service, as applicable. Note that not all services are yet implemented.
Based on a pilot program for members which allows the SIG to allocate a 16-bit Universally Unique Identifier (UUID) for use with a custom GATT-based service defined by the member.
UUID | Member | Description |
---|---|---|
0xfed8 | UriBeacon (Physical Web) | |
0xfeaa | Eddystone |
Supports Eddystone (UID, URL & TLM) and the UriBeacon of the Physical Web.
Process UriBeacon data (UUID = 0xfed8).
advlib.ble.data.gatt.services.members.process(advData);
This is best illustrated with an example using the following input:
advData: {
serviceData: {
uuid: "fed8",
data: "00f2027265656c7961637469766507"
}
}
For reference, the example serviceData.data is interpreted as follows, based on the UriBeacon Advertising Packet Specification:
Byte(s) | Hex String | Description |
---|---|---|
0 | 00 | UriBeacon flags |
1 | f2 | UriBeacon TxPower level |
3 | 02 | Uri Scheme Prefix (http://) |
4-15 | 7265656c7961637469766507 | Encoded Uri (reelyactive.com) |
Which would add the following properties to advData:
serviceData: {
uuid: "fed8",
data: "00f2027265656c7961637469766507",
companyName: "Google",
uriBeacon: {
invisibleHint: false,
txPower: "-14dBm",
url: "http://reelyactive.com"
}
}
Process Eddystone-UID data (UUID = 0xfeaa).
advlib.ble.data.gatt.services.members.process(advData);
This is best illustrated with an example using the following input:
advData: {
serviceData: {
uuid: "feaa",
data: "00128b0ca750095477cb3e770011223344550000"
}
}
For reference, the example serviceData.data is interpreted as follows, based on the Eddystone-UID specification:
Byte(s) | Hex String | Description |
---|---|---|
0 | 00 | Eddystone-UID Frame Type |
1 | 12 | Calibrated TxPower at 0m |
2-11 | 8b0ca750095477cb3e77 | 10-byte ID Namespace |
12-17 | 001122334455 | 6-byte ID Instance |
18-19 | 0000 | Reserved for Future Use |
Which would add the following properties to advData:
serviceData: {
uuid: "feaa",
data: "00128b0ca750095477cb3e770011223344550000",
eddystone: {
type: "UID",
txPower: "18dBm",
uid: {
namespace: "8b0ca750095477cb3e77",
instance: "001122334455"
}
}
}
Process Eddystone-URL data (UUID = 0xfeaa).
advlib.ble.data.gatt.services.members.process(advData);
This is best illustrated with an example using the following input:
advData: {
serviceData: {
uuid: "feaa",
data: "1012027265656c7961637469766507"
}
}
For reference, the example serviceData.data is interpreted as follows, based on the Eddystone-URL specification:
Byte(s) | Hex String | Description |
---|---|---|
0 | 10 | Eddystone-URL Frame Type |
1 | 12 | Calibrated TxPower at 0m |
2 | 02 | URL Scheme (http://) |
3-14 | 7265656c7961637469766507 | Encoded URL (reelyactive.com) |
Which would add the following properties to advData:
serviceData: {
uuid: "feaa",
data: "1012027265656c7961637469766507",
eddystone: {
type: "URL",
txPower: "18dBm",
url: "http://reelyactive.com"
}
}
Process Eddystone-TLM data (UUID = 0xfeaa).
advlib.ble.data.gatt.services.members.process(advData);
This is best illustrated with an example using the following input:
advData: {
serviceData: {
uuid: "feaa",
data: "20000bb81800000000010000000a"
}
}
For reference, the example serviceData.data is interpreted as follows, based on the Eddystone-TLM specification:
Byte(s) | Hex String | Description |
---|---|---|
0 | 20 | Eddystone-TLM Frame Type |
1 | 00 | TLM Version |
2-3 | 0bb8 | Battery Voltage (mV) |
4-5 | 1800 | Temperature (8:8 fixed point) |
6-9 | 00000001 | Advertising PDU Count |
10-13 | 0000000a | Uptime (0.1s resolution) |
Which would add the following properties to advData:
serviceData: {
uuid: 'feaa',
data: '20000bb81800000000010000000a',
eddystone: {
type: "TLM",
version: "00",
batteryVoltage: "3000mV",
temperature: "24C",
advertisingCount: 1,
uptime: "1s"
}
}
The following GATT Services, assigned in the GATT Specification are identified but not parsed:
Process a raw packet (as a hexadecimal string) with the following command:
advlib.reelyactive.process(rawHexPacket);
This is an active work in progress. Expect regular changes and updates, as well as improved documentation!
MIT License
Copyright (c) 2015 reelyActive
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FAQs
Open source, protocol-agnostic library for decoding ambient wireless packets. We believe in an open Internet of Things.
The npm package advlib receives a total of 79 weekly downloads. As such, advlib popularity was classified as not popular.
We found that advlib demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.