1 You want to help? Excellent!
2 -----------------------------
3 Barry currently only supports about 3 database record formats. A
4 database dump reveals over 50 different databases types, and you can help
7 Use the following command to dump the Database Database to stdout:
11 Pick a database you are interested in, and run the following command to
12 dump the protocol to stdout:
17 Protocol Documentation:
18 -----------------------
19 Once you have the raw protocol dump, you need to reverse engineer it.
20 There are a number of places you can find documentation on this.
22 The original source that I started with was the Cassis project docs.
23 You can find them here:
25 http://off.net/cassis/protocol-description.html
27 While these docs are quite helpful, they only cover the serial protocol.
29 The USB protocol is more data-block based. There are no checksums, since
30 USB provides a reliable data transfer. The common protocol headers are
31 struct based, until you get to the variable sized data. (This is also
32 struct based, but requires pointer arithmetic.)
34 See the following Barry source file for protocol structure information:
41 These structures are all low level in nature, and MUST be packed. You
42 will notice that every struct in this header is flagged with the gcc
43 extension "__attribute__ ((packed))", which makes it useful to apply
44 structure to raw protocol data.
46 You can build / deconstruct a protocol packet in this manner:
48 Imagine you have a packet of raw data in the following buffer:
52 You can apply the Packet struct to it directly:
54 struct Packet *packet = (struct Packet *) buff;
56 Looking at the structure, this gives you a lot of fixed-position data:
60 ///////////////////////////////////////////////////////////////////////////////
65 uint16_t socket; // socket ID... 0 is always there
66 uint16_t size; // total size of data packet
73 SequenceCommand sequence;
74 ModeSelectCommand mode;
78 } __attribute__ ((packed)) u;
79 } __attribute__ ((packed));
83 In the case of database records, you are interested in the DBAccess union
89 ///////////////////////////////////////////////////////////////////////////////
90 // Database access command structure
92 // even fragmented packets have a tableCmd
101 CommandTableField table[1];
105 } __attribute__ ((packed)) u;
106 } __attribute__ ((packed));
110 When downloading database records, they all arrive in a DBResponse packet.
119 DBR_OldTaggedRecord tagged;
120 DBR_OldDBDBRecord old_dbdb;
123 } __attribute__ ((packed)) u;
125 } __attribute__ ((packed));
128 Depending on the command you use, the format of the record will change.
129 Also, newer versions of Blackberries have new "GET" commands that
130 return a slightly different record header. Barry currenly uses
131 the "old" command, which is supported by all USB Blackberries tested
132 so far, so it has the greatest compatibility.
134 Some database records are tagged with a unique ID. These databases
135 include the Contact records, Service Book records, and Calendar
136 records. This allows for intelligent syncing, as Barry can reference,
137 update, and delete records individually instead of a group.
139 struct DBR_OldTaggedRecord
148 CommonField field[1];
149 } __attribute__ ((packed)) u;
150 } __attribute__ ((packed));
154 This is enough information to get you to the data you need to reverse
155 engineer. That data will be located at:
157 packet->u.db.u.response.u.tagged.u.field[0]
160 So, taking an Address Book record as an example:
162 00000000: 06 00 37 00 40 03 44 00 08 00 80 82 b1 22 00 06 ..7.@.D......"..
163 00000010: 00 20 43 68 72 69 73 00 05 00 20 46 72 65 79 00 . Chris... Frey.
164 00000020: 14 00 01 63 64 66 72 65 79 40 6e 65 74 64 69 72 ...cdfrey@netdir
165 00000030: 65 63 74 2e 63 61 00 ect.ca.
169 06 00 - packet->socket
172 03 - packet->u.db.tableCmd
173 44 - packet->u.db.u.response.operation
174 00 - packet->u.db.u.response.u.tagged.unknown
175 08 00 - packet->u.db.u.response.u.tagged.index
176 80 82 b1 22 - packet->u.db.u.response.u.tagged.uniqueId
177 00 - packet->u.db.u.response.u.tagged.unknown2
178 06 00 - packet->u.db.u.response.u.tagged.u.field[0].size
179 20 - packet->u.db.u.response.u.tagged.u.field[0].type
180 ... - continued data from sequential CommonField packets
182 Note that CommonField packets are variable size, so you can only use
183 field[0] the first time. You'll need to do pointer arithmetic to
184 calculate the start of the next CommonField.
186 This is a common theme in the database records. There is a static header
187 (eg. DBR_OldTaggedRecord) followed by a number of fields, which each contains
188 a common field header (eg. CommonField), followed by a variable sized block
189 of data (CommonField's u.raw field). The next field starts size bytes later,
194 This should give you enough information to begin hacking on additional
195 database records. Once you have a "Record" header struct, you are ready
196 to begin parsing into an API class.
203 Record API Classes are intended to be consistent, C++-friendly structures
204 for storing the parsed data. You can find them in:
208 These classes may be broken out into multiple files someday.
210 The requirements of these classes are as follows:
212 - no virtual functions
213 - must be valid STL container items
214 - generally contain all public data
215 - provide member functions for:
217 - parsing downloaded data blocks from the BlackBerry
218 - building data blocks for the BlackBerry for uploads
219 - must have absolutely no low level protocol contamination
221 The final point deserves some commentary. When using gcc-specific extensions
222 like __attribute__, and when using pointer arithmetic and pointer casts
223 across types, as is necessary in some of the low level parsing code,
224 special compiler flags are required.
226 Specifically, g++ requires -fno-strict-aliasing to stop it from optimizing
227 away some of the pointer casts and data accesses. This is not desireable
228 in an end-user application, so care must be taken to hide all low level
229 parsing in the library, while exposing the record class structures and
230 member function APIs to the application.
232 Therefore src/record.h (or any new record header you add) must not include
233 src/protostructs.h. Your .cc code may include protostructs.h, but not
234 the header, which will be used by the application.
237 Good luck, and happy hacking!