{"id":14969,"date":"2026-03-25T13:30:15","date_gmt":"2026-03-25T13:30:15","guid":{"rendered":"https:\/\/elusivedata.io\/?p=14969"},"modified":"2026-03-28T08:13:57","modified_gmt":"2026-03-28T08:13:57","slug":"protobuf-varint-forensics","status":"publish","type":"post","link":"https:\/\/elusivedata.io\/ar\/protobuf-varint-forensics\/","title":{"rendered":"Protocol Buffers for Forensic Examiners: The Varint Trap"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"14969\" class=\"elementor elementor-14969\" data-elementor-post-type=\"post\">\n\t\t\t\t<div class=\"elementor-element elementor-element-c7c3135 e-flex e-con-boxed e-con e-parent\" data-id=\"c7c3135\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-dd7231c elementor-widget elementor-widget-heading\" data-id=\"dd7231c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Introduction<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5551bc0 elementor-widget elementor-widget-text-editor\" data-id=\"5551bc0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>If you&#8217;ve parsed SQLite databases and you&#8217;re working in mobile forensics, you&#8217;ve encountered variable-length integers (varints). You\u2019ve seen how SQLite uses them to encode payload lengths, row IDs, and serial type codes in record headers.<\/p><p>Then one day you pull a BLOB from an Apple Note, decompress it, and try to parse the protobuf inside.<\/p><p>You see what appear to be varints\u2026 but when you decode them, your decoder gives you completely wrong answers. But they look correct. The lengths don\u2019t match. The fields are wrong. Everything breaks.<\/p><p>Protobuf varints are NOT SQLite varints.<\/p><p>They share a name. They both use a continuation bit in the most significant bit position. But that\u2019s where the similarities end. The byte order is reversed. And if you don\u2019t know that, you\u2019ll silently get the wrong answers that look plausible enough to waste hours of your time.<\/p><p>Welcome to Protocol Buffers.<\/p><p>In this post, we\u2019re going to parse a protobuf blob from scratch \u2014 a core skill in mobile forensics. First by hand, then in Python. No libraries, no shortcuts.<\/p><p>By the end, you\u2019ll extract a timestamp, identify an XOR key, and decrypt a hidden message. If you get the right answer, you know you understood every byte.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-49c3f16 e-flex e-con-boxed e-con e-parent\" data-id=\"49c3f16\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1505e39 elementor-widget elementor-widget-heading\" data-id=\"1505e39\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Where You'll Encounter Protobuf<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-64ed87a elementor-widget elementor-widget-text-editor\" data-id=\"64ed87a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><a href=\"https:\/\/protobuf.dev\/\" target=\"_blank\" rel=\"noopener\">Protocol Buffers<\/a> (protobuf) is Google\u2019s binary serialization format, and it has become the standard for structured data in mobile applications. As forensic examiners, you\u2019ll find protobuf-encoded data in:<\/p><ul><li><strong>Apple Notes<\/strong>: The \u2018ZDATA\u2019 BLOB in \u2018ZICNOTEDATA\u2019 is a gzip-compressed protobuf<\/li><li><strong>WhatsApp:<\/strong> Message metadata and media references<\/li><li><strong>Signal<\/strong>: Encrypted message payloads, after decryption<\/li><li><strong>Google apps<\/strong>: Maps timeline, Chrome sync data, Play Store records<\/li><li><strong>iCloud sync BLOBS<\/strong>: Various Apple services<\/li><\/ul><p>\u00a0<\/p><p>If you are parsing modern mobile forensic artifacts and you\u2019re not comfortable with protobuf, you have a blind spot in your toolkit. Protobuf varint forensics is a skill every examiner needs.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5c3532c e-flex e-con-boxed e-con e-parent\" data-id=\"5c3532c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d72a1d2 elementor-widget elementor-widget-heading\" data-id=\"d72a1d2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">The Challenge<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0581b40 elementor-widget elementor-widget-text-editor\" data-id=\"0581b40\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Here\u2019s a decompressed protobuf BLOB. It represents a simplified message record, the kind of structure you would find inside an Apple Notes \u2018ZDATA\u2019 BLOB or an app\u2019s internal message store.<\/p><p>Your job: decode every field, extract the timestamp, find the encryption key, and decrypt the message. This is protobuf varint forensics in action.<\/p><div style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 20px; overflow-x: auto; margin: 20px 0;\"><pre style=\"font-family: 'Courier New', Consolas, monospace; font-size: 14px; line-height: 1.6; color: #c8c8d4; margin: 0; white-space: pre;\">  <span style=\"color: #6a6a8a;\">0000:<\/span> 08 E9 07 12 05 <span style=\"color: #4ec9b0; font-weight: bold;\">4C 61 6E 63 65<\/span> 18 D2 CF 8D BB 06  <span style=\"color: #6a6a8a;\">.....<\/span><span style=\"color: #4ec9b0; font-weight: bold;\">Lance<\/span><span style=\"color: #6a6a8a;\">......<\/span>\n  <span style=\"color: #6a6a8a;\">0010:<\/span> 22 04 <span style=\"color: #f44747; font-weight: bold;\">DE AD BE EF<\/span> 2A B5 01 9A C8 CE 80 AD C4 CA  <span style=\"color: #6a6a8a;\">\".....<\/span><span style=\"color: #f44747;\">*<\/span><span style=\"color: #6a6a8a;\">........<\/span>\n  <span style=\"color: #6a6a8a;\">0020:<\/span> CF AA C5 DB CF B8 D8 D0 8B AD 8D D7 81 AA C2 9E  <span style=\"color: #6a6a8a;\">................<\/span>\n  <span style=\"color: #6a6a8a;\">0030:<\/span> 8E BD CE D1 9A B0 D9 9E DB EA 95 8F C2 EC 9F 87  <span style=\"color: #6a6a8a;\">................<\/span>\n  <span style=\"color: #6a6a8a;\">0040:<\/span> DF F3 9A 8F DA E8 8D DC 8A B8 C2 CC 8A FE EB CC  <span style=\"color: #6a6a8a;\">................<\/span>\n  <span style=\"color: #6a6a8a;\">0050:<\/span> 86 BA CC C7 C1 FE F8 CD 8A FE D9 D6 8A FE DE DF  <span style=\"color: #6a6a8a;\">................<\/span>\n  <span style=\"color: #6a6a8a;\">0060:<\/span> 82 BB 8D D3 8A AA C5 D1 8B FE CC CD CF B2 CC CD  <span style=\"color: #6a6a8a;\">................<\/span>\n  <span style=\"color: #6a6a8a;\">0070:<\/span> 9B FE D9 D7 82 BB 83 9E AB B1 8D D0 80 AA 8D DD  <span style=\"color: #6a6a8a;\">................<\/span>\n  <span style=\"color: #6a6a8a;\">0080:<\/span> 80 B0 D9 DF 8C AA 8D D3 8A FE C2 D0 CF AA C5 D7  <span style=\"color: #6a6a8a;\">................<\/span>\n  <span style=\"color: #6a6a8a;\">0090:<\/span> 9C FE C3 CB 82 BC C8 CC CF BF CA DF 86 B0 8D 93  <span style=\"color: #6a6a8a;\">................<\/span>\n  <span style=\"color: #6a6a8a;\">00A0:<\/span> CF AB DE DB CF AA C5 DB CF AD C8 DD 80 B0 C9 DF  <span style=\"color: #6a6a8a;\">................<\/span>\n  <span style=\"color: #6a6a8a;\">00B0:<\/span> 9D A7 8D DD 87 BF C3 D0 8A B2 83 9E AB BB DE CA  <span style=\"color: #6a6a8a;\">................<\/span>\n  <span style=\"color: #6a6a8a;\">00C0:<\/span> 9D B1 D4 9E 9B B6 C4 CD CF B0 C2 CA 8A F0        <span style=\"color: #6a6a8a;\">..............<\/span><\/pre><\/div><p>If you squint at offset 0x0005, you can see the hex representation of the ASCII characters \u201cLance\u201d. But most of the bytes are opaque. The structure holding them together is protobuf, and to read it, we need to understand two things: protobuf varints and wire types.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-bfa442b e-flex e-con-boxed e-con e-parent\" data-id=\"bfa442b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-64da34b elementor-widget elementor-widget-heading\" data-id=\"64da34b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">A Quick SQLite Varint Refresher<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-dc95c4d elementor-widget elementor-widget-text-editor\" data-id=\"dc95c4d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Before we get to protobuf, let\u2019s make sure we\u2019re on the same page about SQLite varints. In SQLite encoding:<\/p><p>The <strong>most significant bit (MSB)<\/strong> of each byte is the continuation flag. It\u2019s either 1 which means more bytes follow or it\u2019s 0 which means this is the last byte.<\/p><p>The remaining <strong>7 bits<\/strong> carry the actual data or payload<\/p><p>Bytes are read <strong>big-endian<\/strong> meaning the first byte carries the most significant data bits.<\/p><p>There\u2019s a maximum of 9 bytes (the 9<sup>th<\/sup> byte uses all 8 bits).<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3d6ef7e elementor-widget elementor-widget-html\" data-id=\"3d6ef7e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 24px; margin: 20px 0; color: #c8c8d4; font-family: 'Courier New',\r\n  Consolas, monospace; font-size: 16px; line-height: 1.8;\">\r\n\r\n    <div style=\"color: #ffffff; font-family: inherit; margin-bottom: 16px;\">\r\n      Here's the integer <span style=\"color: #4ec9b0; font-weight: bold;\">300<\/span> encoded as a SQLite varint:\r\n    <\/div>\r\n\r\n    <div style=\"margin-bottom: 12px; color: #ffffff;\">\r\n      300 in binary: <span style=\"color: #dcdcaa;\">00000001 00101100<\/span>\r\n    <\/div>\r\n\r\n    <!-- Bit value table -->\r\n    <table style=\"border-collapse: collapse; margin: 12px 0 16px 0; font-size: 16px;\">\r\n      <tr>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">256<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">128<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">64<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">32<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">16<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">8<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">4<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">2<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">1<\/td>\r\n      <\/tr>\r\n      <tr>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n      <\/tr>\r\n    <\/table>\r\n\r\n    <div style=\"margin-bottom: 16px; color: #ffffff;\">\r\n      <span style=\"color: #4ec9b0;\">256<\/span> + <span style=\"color: #4ec9b0;\">32<\/span> + <span style=\"color: #4ec9b0;\">8<\/span> + <span style=\"color:\r\n  #4ec9b0;\">4<\/span> = <span style=\"color: #4ec9b0; font-weight: bold;\">300<\/span>\r\n    <\/div>\r\n\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; margin-bottom: 12px; color: #ffffff;\">\r\n      Split into 7-bit groups (from the most significant):\r\n    <\/div>\r\n\r\n    <div style=\"margin-bottom: 4px;\">\r\n      <span style=\"color: #9a9ab0;\">Group 1:<\/span>    <span style=\"color: #dcdcaa;\">0000010<\/span> <span style=\"color: #9a9ab0;\">(high bits)<\/span>\r\n    <\/div>\r\n    <div style=\"margin-bottom: 16px;\">\r\n      <span style=\"color: #9a9ab0;\">Group 2:<\/span>    <span style=\"color: #dcdcaa;\">0101100<\/span> <span style=\"color: #9a9ab0;\">(low bits)<\/span>\r\n    <\/div>\r\n\r\n    <div style=\"margin-bottom: 12px; color: #ffffff;\">Add continuation bits:<\/div>\r\n\r\n    <div style=\"margin-bottom: 4px;\">\r\n      <span style=\"color: #9a9ab0;\">Byte 1:<\/span>    <span style=\"color: #f44747; font-weight: bold;\">1<\/span> | <span style=\"color: #dcdcaa;\">0000010<\/span>  =  <span\r\n   style=\"color: #4ec9b0; font-weight: bold;\">0x82<\/span>  <span style=\"color: #9a9ab0;\">(MSB = 1, more bytes follow)<\/span>\r\n    <\/div>\r\n    <div style=\"margin-bottom: 16px;\">\r\n      <span style=\"color: #9a9ab0;\">Byte 2:<\/span>    <span style=\"color: #4ec9b0; font-weight: bold;\">0<\/span> | <span style=\"color: #dcdcaa;\">0101100<\/span>  =  <span\r\n   style=\"color: #4ec9b0; font-weight: bold;\">0x2C<\/span>  <span style=\"color: #9a9ab0;\">(MSB = 0, last byte)<\/span>\r\n    <\/div>\r\n\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px;\">\r\n      <span style=\"color: #ffffff;\">SQLite varint for 300:<\/span>    <span style=\"color: #4ec9b0; font-weight: bold; font-size: 16px;\">0x82  0x2C<\/span>\r\n    <\/div>\r\n\r\n  <\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-995ba84 elementor-widget elementor-widget-text-editor\" data-id=\"995ba84\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>The key concept: you read left to right, each byte\u2019s 7-bit payload slots into the <strong>high<\/strong> end of your accumulator, and you shift the accumulator left to make room for the next byte.<\/p><p>But this is not how all varints work.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c2baa45 e-flex e-con-boxed e-con e-parent\" data-id=\"c2baa45\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e4ac237 elementor-widget elementor-widget-heading\" data-id=\"e4ac237\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">The Protobuf Difference: LEB128<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-425728f elementor-widget elementor-widget-text-editor\" data-id=\"425728f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Protobuf uses a varint encoding called <strong>LEB128<\/strong>: Little-Endian Base 128. Same continuation bit, same 7-bits-per-byte concept, but the byte order is <em>reversed<\/em>.<\/p><p>The first byte carries the least significant 7 bits<\/p><p>Each subsequent byte carries progressively higher-order bits<\/p><p>The continuation bit still works the same: \u20181\u2019 = more bytes, \u20180\u2019 = the last byte.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f174ba3 elementor-widget elementor-widget-html\" data-id=\"f174ba3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 24px; margin: 20px 0; color: #c8c8d4; font-family: 'Courier New',\r\n  Consolas, monospace; font-size: 16px; line-height: 1.8;\">\r\n\r\n    <div style=\"color: #ffffff; font-family: inherit; margin-bottom: 16px;\">\r\n      Here's <span style=\"color: #4ec9b0; font-weight: bold;\">300<\/span> encoded as a protobuf varint (LEB128):\r\n    <\/div>\r\n\r\n    <div style=\"margin-bottom: 12px; color: #ffffff;\">\r\n      300 in binary: <span style=\"color: #dcdcaa;\">00000001 00101100<\/span>\r\n    <\/div>\r\n\r\n    <!-- Bit value table -->\r\n    <table style=\"border-collapse: collapse; margin: 12px 0 16px 0; font-size: 16px;\">\r\n      <tr>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">256<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">128<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">64<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">32<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">16<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">8<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">4<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">2<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 6px 14px; text-align: center;\">1<\/td>\r\n      <\/tr>\r\n      <tr>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 14px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n      <\/tr>\r\n    <\/table>\r\n\r\n    <div style=\"margin-bottom: 16px; color: #ffffff;\">\r\n      <span style=\"color: #4ec9b0;\">256<\/span> + <span style=\"color: #4ec9b0;\">32<\/span> + <span style=\"color: #4ec9b0;\">8<\/span> + <span style=\"color:\r\n  #4ec9b0;\">4<\/span> = <span style=\"color: #4ec9b0; font-weight: bold;\">300<\/span>\r\n    <\/div>\r\n\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; margin-bottom: 12px; color: #ffffff;\">\r\n      Split into 7-bit groups (from the <span style=\"color: #f44747; font-weight: bold;\">LEAST<\/span> significant):\r\n    <\/div>\r\n\r\n    <div style=\"margin-bottom: 4px;\">\r\n      <span style=\"color: #9a9ab0;\">Group 1:<\/span>    <span style=\"color: #dcdcaa;\">0101100<\/span> <span style=\"color: #9a9ab0;\">(low bits -- goes <span style=\"color:\r\n  #f44747; font-weight: bold;\">FIRST<\/span>)<\/span>\r\n    <\/div>\r\n    <div style=\"margin-bottom: 16px;\">\r\n      <span style=\"color: #9a9ab0;\">Group 2:<\/span>    <span style=\"color: #dcdcaa;\">0000010<\/span> <span style=\"color: #9a9ab0;\">(high bits -- goes <span style=\"color:\r\n   #f44747; font-weight: bold;\">SECOND<\/span>)<\/span>\r\n    <\/div>\r\n\r\n    <div style=\"margin-bottom: 12px; color: #ffffff;\">Add continuation bits:<\/div>\r\n\r\n    <div style=\"margin-bottom: 4px;\">\r\n      <span style=\"color: #9a9ab0;\">Byte 1:<\/span>    <span style=\"color: #f44747; font-weight: bold;\">1<\/span> | <span style=\"color: #dcdcaa;\">0101100<\/span>  =  <span\r\n   style=\"color: #4ec9b0; font-weight: bold;\">0xAC<\/span>  <span style=\"color: #9a9ab0;\">(MSB = 1, more bytes follow)<\/span>\r\n    <\/div>\r\n    <div style=\"margin-bottom: 16px;\">\r\n      <span style=\"color: #9a9ab0;\">Byte 2:<\/span>    <span style=\"color: #4ec9b0; font-weight: bold;\">0<\/span> | <span style=\"color: #dcdcaa;\">0000010<\/span>  =  <span\r\n   style=\"color: #4ec9b0; font-weight: bold;\">0x02<\/span>  <span style=\"color: #9a9ab0;\">(MSB = 0, last byte)<\/span>\r\n    <\/div>\r\n\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; margin-bottom: 24px;\">\r\n      <span style=\"color: #ffffff;\">Protobuf varint for 300:<\/span>    <span style=\"color: #4ec9b0; font-weight: bold; font-size: 16px;\">0xAC  0x02<\/span>\r\n    <\/div>\r\n\r\n    <!-- Comparison table -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; margin-bottom: 8px; color: #ffffff; font-weight: bold;\">\r\n      Compare them side by side:\r\n    <\/div>\r\n\r\n    <table style=\"border-collapse: collapse; margin: 12px 0 0 0; font-size: 16px; width: 100%; max-width: 500px;\">\r\n      <tr>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 8px 16px;\">Encoding<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 8px 16px; text-align: center;\">Byte 1<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 8px 16px; text-align: center;\">Byte 2<\/td>\r\n        <td style=\"background-color: #d45a2a; color: #fff; font-weight: bold; padding: 8px 16px; text-align: center;\">Value<\/td>\r\n      <\/tr>\r\n      <tr>\r\n        <td style=\"background-color: #2a2a3e; color: #ffffff; padding: 8px 16px; border: 1px solid #3a3a5c;\">SQLite<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 8px 16px; text-align: center; border: 1px solid #3a3a5c;\">0x82<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 8px 16px; text-align: center; border: 1px solid #3a3a5c;\">0x2C<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 8px 16px; text-align: center; border: 1px solid #3a3a5c;\">300<\/td>\r\n      <\/tr>\r\n      <tr>\r\n        <td style=\"background-color: #2a2a3e; color: #ffffff; padding: 8px 16px; border: 1px solid #3a3a5c;\">Protobuf<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #f44747; font-weight: bold; padding: 8px 16px; text-align: center; border: 1px solid #3a3a5c;\">0xAC<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #f44747; font-weight: bold; padding: 8px 16px; text-align: center; border: 1px solid #3a3a5c;\">0x02<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 8px 16px; text-align: center; border: 1px solid #3a3a5c;\">300<\/td>\r\n      <\/tr>\r\n    <\/table>\r\n\r\n  <\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-774a1cf elementor-widget elementor-widget-text-editor\" data-id=\"774a1cf\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Same integer. Completely different bytes. Feed 0xAC02 into a SQLite varint decoder and you\u2019ll get a <em>different number<\/em>. Feed 0x822C into a protobuf decoder \u2013 same problem. This is the trap.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ea7987f e-flex e-con-boxed e-con e-parent\" data-id=\"ea7987f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-288828f elementor-widget elementor-widget-heading\" data-id=\"288828f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Protobuf Wire Types: The Road Map<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-187f90e elementor-widget elementor-widget-text-editor\" data-id=\"187f90e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Every protobuf message is a sequence of <strong>field tag + value<\/strong> pairs. No delimiters, no overall length header. You read fields sequentially until you run out of bytes.<\/p><p>Each field starts with a <strong>tag<\/strong>, which is itself a varint. The tag packs two things together using bit manipulation:<\/p><p>tag = (field_number &lt;&lt; 3) | wire_type<\/p><p>The low 3 bits are the wire type. They tell you <em>how to read<\/em> the value that follows. The remaining upper bits are the field number that tells us <strong><em>which<\/em><\/strong> field this is. To unpack a tag:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e44d514 elementor-widget elementor-widget-html\" data-id=\"e44d514\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 16px; margin: 16px 0; font-family: 'Courier New', Consolas, monospace;\r\n  font-size: 16px; line-height: 1.8; color: #dcdcaa; overflow-x: auto;\">wire_type    = tag & 0x07      <span style=\"color: #9a9ab0;\"># low 3 bits<\/span>\r\nfield_number = tag >> 3        <span style=\"color: #9a9ab0;\"># everything above the low 3<\/span><\/pre>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0390006 elementor-widget elementor-widget-text-editor\" data-id=\"0390006\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>The &amp; symbol is the bitwise AND operator. We use it to mask the value we are working with to isolate the 1 bits. Let\u2019s say our tag is 0x0A. The binary equivalent is: 0000 1010<\/p><p>We&#8217;ll break down exactly how AND, shift, and OR work at the bit level later in this post.<\/p><p>Here are the wire types you will encounter:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f7756ea elementor-widget elementor-widget-html\" data-id=\"f7756ea\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<table style=\"border-collapse: collapse; margin: 16px 0; font-size: 14px; width: 100%; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,\r\n  sans-serif;\">\r\n    <tr>\r\n      <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 10px 16px;\">Wire Type<\/td>\r\n      <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 10px 16px;\">Name<\/td>\r\n      <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 10px 16px;\">What Follows<\/td>\r\n      <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 10px 16px;\">Use Case<\/td>\r\n    <\/tr>\r\n    <tr>\r\n      <td style=\"background-color: #1a1a2e; color: #4ec9b0; font-weight: bold; padding: 10px 16px; border: 1px solid #3a3a5c; text-align: center;\">0<\/td>\r\n      <td style=\"background-color: #1a1a2e; color: #ffffff; padding: 10px 16px; border: 1px solid #3a3a5c;\">Varint<\/td>\r\n      <td style=\"background-color: #1a1a2e; color: #c8c8d4; padding: 10px 16px; border: 1px solid #3a3a5c;\">A single varint value<\/td>\r\n      <td style=\"background-color: #1a1a2e; color: #c8c8d4; padding: 10px 16px; border: 1px solid #3a3a5c;\">Integers, Booleans, enums, timestamps<\/td>\r\n    <\/tr>\r\n    <tr>\r\n      <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 10px 16px; border: 1px solid #3a3a5c; text-align: center;\">1<\/td>\r\n      <td style=\"background-color: #2a2a3e; color: #ffffff; padding: 10px 16px; border: 1px solid #3a3a5c;\">64-bit<\/td>\r\n      <td style=\"background-color: #2a2a3e; color: #c8c8d4; padding: 10px 16px; border: 1px solid #3a3a5c;\">Exactly 8 bytes<\/td>\r\n      <td style=\"background-color: #2a2a3e; color: #c8c8d4; padding: 10px 16px; border: 1px solid #3a3a5c;\">Double-precision floats, fixed int64<\/td>\r\n    <\/tr>\r\n    <tr>\r\n      <td style=\"background-color: #1a1a2e; color: #4ec9b0; font-weight: bold; padding: 10px 16px; border: 1px solid #3a3a5c; text-align: center;\">2<\/td>\r\n      <td style=\"background-color: #1a1a2e; color: #ffffff; padding: 10px 16px; border: 1px solid #3a3a5c;\">Length-delimited<\/td>\r\n      <td style=\"background-color: #1a1a2e; color: #c8c8d4; padding: 10px 16px; border: 1px solid #3a3a5c;\">A varint length, then that many bytes<\/td>\r\n      <td style=\"background-color: #1a1a2e; color: #c8c8d4; padding: 10px 16px; border: 1px solid #3a3a5c;\">Strings, byte arrays, nested messages<\/td>\r\n    <\/tr>\r\n    <tr>\r\n      <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 10px 16px; border: 1px solid #3a3a5c; text-align: center;\">5<\/td>\r\n      <td style=\"background-color: #2a2a3e; color: #ffffff; padding: 10px 16px; border: 1px solid #3a3a5c;\">32-bit<\/td>\r\n      <td style=\"background-color: #2a2a3e; color: #c8c8d4; padding: 10px 16px; border: 1px solid #3a3a5c;\">Exactly 4 bytes<\/td>\r\n      <td style=\"background-color: #2a2a3e; color: #c8c8d4; padding: 10px 16px; border: 1px solid #3a3a5c;\">Single-precision floats, fixed int32<\/td>\r\n    <\/tr>\r\n  <\/table>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f26573c elementor-widget elementor-widget-text-editor\" data-id=\"f26573c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Wire type 2 is by far the most common in forensic artifacts. It covers strings, raw bytes, and embedded sub-messages. And critically, its length prefix is a <em>protobuf<\/em> varint. Decode it with a SQLite decoder and every field boundary after that point will be wrong.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1e2850d e-flex e-con-boxed e-con e-parent\" data-id=\"1e2850d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-05ab004 elementor-widget elementor-widget-heading\" data-id=\"05ab004\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Parsing Protobuf Varints: Field by Field<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b0f3e66 elementor-widget elementor-widget-text-editor\" data-id=\"b0f3e66\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Now let\u2019s walk through the hex dump and parse every field by hand. This is exactly what your Python script will automate. But doing it manually first is how you build the intuition. Let&#8217;s put protobuf varint forensics to work.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-659910a elementor-widget elementor-widget-text-editor\" data-id=\"659910a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h4>Field 1: Record ID (Varint)<\/h4>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f07c8d9 elementor-widget elementor-widget-html\" data-id=\"f07c8d9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 24px; margin: 20px 0; color: #c8c8d4; font-family: 'Courier New',\r\n  Consolas, monospace; font-size: 16px; line-height: 1.8;\">\r\n\r\n    <!-- Offset and bytes -->\r\n    <div style=\"color: #ffffff; margin-bottom: 16px;\">\r\n      Starting at offset <span style=\"color: #4ec9b0;\">0x0000<\/span>:\r\n    <\/div>\r\n    <div style=\"color: #dcdcaa; font-size: 18px; font-weight: bold; margin-bottom: 20px;\">\r\n      08 E9 07\r\n    <\/div>\r\n\r\n    <!-- Read the tag -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; color: #ffffff; margin-bottom: 12px; font-weight: bold;\">\r\n      Read the tag \u2014 first byte is <span style=\"color: #4ec9b0;\">0x08<\/span>:\r\n    <\/div>\r\n    <div style=\"margin-bottom: 4px;\">\r\n      <span style=\"color: #4ec9b0;\">0x08<\/span> = <span style=\"color: #dcdcaa;\">0000 1000<\/span>\r\n    <\/div>\r\n    <div style=\"margin-bottom: 16px; color: #9a9ab0;\">\r\n      MSB is <span style=\"color: #4ec9b0; font-weight: bold;\">0<\/span>, so this is a single-byte varint. Tag value = <span style=\"color: #4ec9b0; font-weight:\r\n  bold;\">8<\/span>.\r\n    <\/div>\r\n\r\n    <div style=\"margin-bottom: 4px;\">\r\n      <span style=\"color: #9a9ab0;\">wire_type<\/span>    = 8 & 0x07 = <span style=\"color: #4ec9b0; font-weight: bold;\">0<\/span>    <span style=\"color:\r\n  #9a9ab0;\">(varint)<\/span>\r\n    <\/div>\r\n    <div style=\"margin-bottom: 20px;\">\r\n      <span style=\"color: #9a9ab0;\">field_number<\/span> = 8 >> 3   = <span style=\"color: #4ec9b0; font-weight: bold;\">1<\/span>\r\n    <\/div>\r\n\r\n    <div style=\"color: #ffffff; margin-bottom: 20px;\">\r\n      Field <span style=\"color: #4ec9b0; font-weight: bold;\">1<\/span>, wire type <span style=\"color: #4ec9b0; font-weight: bold;\">0<\/span>. The value is a varint \u2014 read\r\n   it next.\r\n    <\/div>\r\n\r\n    <!-- Read the value -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; color: #ffffff; margin-bottom: 12px; font-weight: bold;\">\r\n      Read the value \u2014 bytes <span style=\"color: #4ec9b0;\">E9 07<\/span>:\r\n    <\/div>\r\n\r\n    <div style=\"margin-bottom: 4px; color: #ffffff;\">Byte 1: <span style=\"color: #4ec9b0;\">0xE9<\/span> = <span style=\"color: #dcdcaa;\">1110 1001<\/span><\/div>\r\n    <div style=\"margin-bottom: 4px; color: #9a9ab0;\">  MSB = <span style=\"color: #f44747; font-weight: bold;\">1<\/span> (more bytes coming)<\/div>\r\n    <div style=\"margin-bottom: 16px; color: #9a9ab0;\">  Payload: <span style=\"color: #dcdcaa;\">110 1001<\/span> = 0x69 = <span style=\"color: #4ec9b0; font-weight:\r\n  bold;\">105<\/span><\/div>\r\n\r\n    <div style=\"margin-bottom: 4px; color: #ffffff;\">Byte 2: <span style=\"color: #4ec9b0;\">0x07<\/span> = <span style=\"color: #dcdcaa;\">0000 0111<\/span><\/div>\r\n    <div style=\"margin-bottom: 4px; color: #9a9ab0;\">  MSB = <span style=\"color: #4ec9b0; font-weight: bold;\">0<\/span> (last byte)<\/div>\r\n    <div style=\"margin-bottom: 20px; color: #9a9ab0;\">  Payload: <span style=\"color: #dcdcaa;\">000 0111<\/span> = 0x07 = <span style=\"color: #4ec9b0; font-weight:\r\n  bold;\">7<\/span><\/div>\r\n\r\n    <!-- Reconstruct -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; color: #ffffff; margin-bottom: 12px; font-weight: bold;\">\r\n      Reconstruct (LEB128 \u2014 least significant first):\r\n    <\/div>\r\n\r\n    <div style=\"margin-bottom: 4px;\">\r\n      <span style=\"color: #9a9ab0;\">result<\/span>  = <span style=\"color: #4ec9b0;\">105<\/span> << 0  = <span style=\"color: #4ec9b0; font-weight: bold;\">105<\/span>\r\n    <\/div>\r\n    <div style=\"margin-bottom: 20px;\">\r\n      <span style=\"color: #9a9ab0;\">result<\/span> |=   <span style=\"color: #4ec9b0;\">7<\/span> << 7  = 105 | 896 = <span style=\"color: #4ec9b0; font-weight:\r\n  bold;\">1001<\/span>\r\n    <\/div>\r\n\r\n    <!-- Visual breakdown -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; color: #ffffff; margin-bottom: 12px;\">\r\n      First byte stays in place (shift left 0):\r\n    <\/div>\r\n    <div style=\"margin-bottom: 16px; color: #dcdcaa;\">\r\n      0000000 1101001 <span style=\"color: #9a9ab0;\">= 105<\/span>\r\n    <\/div>\r\n\r\n    <div style=\"color: #ffffff; margin-bottom: 8px;\">\r\n      Second byte shifted left 7 bits:\r\n    <\/div>\r\n    <div style=\"margin-bottom: 8px; color: #dcdcaa;\">\r\n      0000111 0000000 <span style=\"color: #9a9ab0;\">= 896<\/span>\r\n    <\/div>\r\n\r\n    <!-- Shift table -->\r\n    <table style=\"border-collapse: collapse; margin: 8px 0 8px 0; font-size: 16px;\">\r\n      <tr>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">512<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">256<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">128<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">64<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">32<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">16<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">8<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">4<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">2<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">1<\/td>\r\n      <\/tr>\r\n      <tr>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n      <\/tr>\r\n    <\/table>\r\n\r\n    <div style=\"margin-bottom: 20px; color: #9a9ab0;\">\r\n      <span style=\"color: #4ec9b0;\">512<\/span> + <span style=\"color: #4ec9b0;\">256<\/span> + <span style=\"color: #4ec9b0;\">128<\/span> = <span style=\"color: #4ec9b0;\r\n  font-weight: bold;\">896<\/span>\r\n    <\/div>\r\n\r\n<!-- OR operation -->\r\n    <div style=\"color: #ffffff; margin-bottom: 12px; font-weight: bold;\">\r\n      Bitwise OR the two values:\r\n    <\/div>\r\n\r\n    <pre style=\"margin: 0 0 8px 0; padding: 0; background: transparent; border: none; font-family: 'Courier New', Consolas, monospace; font-size: 16px; line-height:\r\n  1.8; color: #dcdcaa;\">    0000000 1101001 <span style=\"color: #9a9ab0;\">(105)<\/span>\r\n  <span style=\"color: #ffffff;\">|<\/span> 0000111 0000000 <span style=\"color: #9a9ab0;\">(896)<\/span>\r\n    <span style=\"color: #4ec9b0; font-weight: bold;\">0000111 1101001<\/span> <span style=\"color: #9a9ab0;\">(1001)<\/span><\/pre>\r\n\r\n    <!-- Result table -->\r\n    <table style=\"border-collapse: collapse; margin: 8px 0 8px 0; font-size: 16px;\">\r\n      <tr>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">512<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">256<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">128<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">64<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">32<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">16<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">8<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">4<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">2<\/td>\r\n        <td style=\"background-color: #F37934; color: #fff; font-weight: bold; padding: 6px 12px; text-align: center;\">1<\/td>\r\n      <\/tr>\r\n      <tr>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #9a9ab0; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">0<\/td>\r\n        <td style=\"background-color: #2a2a3e; color: #4ec9b0; font-weight: bold; padding: 6px 12px; text-align: center; border: 1px solid #3a3a5c;\">1<\/td>\r\n      <\/tr>\r\n    <\/table>\r\n\r\n    <div style=\"margin-bottom: 20px; color: #9a9ab0;\">\r\n      <span style=\"color: #4ec9b0;\">512<\/span> + <span style=\"color: #4ec9b0;\">256<\/span> + <span style=\"color: #4ec9b0;\">128<\/span> + <span style=\"color:\r\n  #4ec9b0;\">64<\/span> + <span style=\"color: #4ec9b0;\">32<\/span> + <span style=\"color: #4ec9b0;\">8<\/span> + <span style=\"color: #4ec9b0;\">1<\/span> = <span style=\"color:\r\n  #4ec9b0; font-weight: bold;\">1001<\/span>\r\n    <\/div>\r\n\r\n    <!-- Final result -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px;\">\r\n      <span style=\"color: #ffffff; font-weight: bold;\">Field 1 =<\/span> <span style=\"color: #4ec9b0; font-weight: bold; font-size: 18px;\">1001<\/span> <span\r\n  style=\"color: #9a9ab0;\">(a record ID)<\/span>\r\n    <\/div>\r\n\r\n  <\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-66d61ce elementor-widget elementor-widget-text-editor\" data-id=\"66d61ce\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h4>Field 2: Sender Name (Length-Delimited String)<\/h4>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7b99db3 elementor-widget elementor-widget-html\" data-id=\"7b99db3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 24px; margin: 20px 0; color: #c8c8d4; font-family: 'Courier New',\r\n  Consolas, monospace; font-size: 16px; line-height: 1.8;\">\r\n\r\n    <!-- Offset and bytes -->\r\n    <div style=\"color: #ffffff; margin-bottom: 16px;\">\r\n      Next bytes at offset <span style=\"color: #4ec9b0;\">0x0003<\/span>:\r\n    <\/div>\r\n    <div style=\"color: #dcdcaa; font-size: 18px; font-weight: bold; margin-bottom: 20px;\">\r\n      12 05 <span style=\"color: #4ec9b0;\">4C 61 6E 63 65<\/span>\r\n    <\/div>\r\n\r\n    <!-- Read the tag -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; color: #ffffff; margin-bottom: 12px; font-weight: bold;\">\r\n      Tag <span style=\"color: #4ec9b0;\">0x12<\/span> = 18:\r\n    <\/div>\r\n\r\n    <div style=\"margin-bottom: 4px;\">\r\n      <span style=\"color: #9a9ab0;\">wire_type<\/span>    = 18 & 0x07 = <span style=\"color: #4ec9b0; font-weight: bold;\">2<\/span>    <span style=\"color:\r\n  #9a9ab0;\">(length-delimited)<\/span>\r\n    <\/div>\r\n    <div style=\"margin-bottom: 20px;\">\r\n      <span style=\"color: #9a9ab0;\">field_number<\/span> = 18 >> 3   = <span style=\"color: #4ec9b0; font-weight: bold;\">2<\/span>\r\n    <\/div>\r\n\r\n    <div style=\"color: #ffffff; margin-bottom: 20px;\">\r\n      Field <span style=\"color: #4ec9b0; font-weight: bold;\">2<\/span>, wire type <span style=\"color: #4ec9b0; font-weight: bold;\">2<\/span>. Read a length varint, then\r\n  that many bytes of data.\r\n    <\/div>\r\n\r\n    <!-- Length -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; margin-bottom: 12px;\">\r\n      <span style=\"color: #ffffff; font-weight: bold;\">Length:<\/span> <span style=\"color: #4ec9b0;\">0x05<\/span> = <span style=\"color: #4ec9b0; font-weight:\r\n  bold;\">5<\/span> <span style=\"color: #9a9ab0;\">\u2014 single byte, MSB is 0. Five bytes of data follow.<\/span>\r\n    <\/div>\r\n\r\n    <!-- Data -->\r\n    <div style=\"margin-bottom: 8px;\">\r\n      <span style=\"color: #ffffff; font-weight: bold;\">Data:<\/span> <span style=\"color: #4ec9b0;\">4C 61 6E 63 65<\/span> = <span style=\"color: #4ec9b0; font-weight:\r\n  bold; font-size: 18px;\">\"Lance\"<\/span> <span style=\"color: #9a9ab0;\">in ASCII\/UTF-8<\/span>\r\n    <\/div>\r\n\r\n  <\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fdc087c elementor-widget elementor-widget-text-editor\" data-id=\"fdc087c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h4>Field 3: Timestamp (Varint) &#8211; The Five-Byte Monster<\/h4>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-21599d1 elementor-widget elementor-widget-html\" data-id=\"21599d1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 24px; margin: 20px 0; color: #c8c8d4; font-family: 'Courier New',\r\n  Consolas, monospace; font-size: 16px; line-height: 1.8;\">\r\n\r\n    <!-- Offset and bytes -->\r\n    <div style=\"color: #ffffff; margin-bottom: 16px;\">\r\n      Offset <span style=\"color: #4ec9b0;\">0x000A<\/span>:\r\n    <\/div>\r\n    <div style=\"color: #dcdcaa; font-size: 18px; font-weight: bold; margin-bottom: 20px;\">\r\n      18 D2 CF 8D BB 06\r\n    <\/div>\r\n\r\n    <!-- Read the tag -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; color: #ffffff; margin-bottom: 12px; font-weight: bold;\">\r\n      Tag <span style=\"color: #4ec9b0;\">0x18<\/span> = 24:\r\n    <\/div>\r\n\r\n    <div style=\"margin-bottom: 4px;\">\r\n      <span style=\"color: #9a9ab0;\">wire_type<\/span>    = 24 & 0x07 = <span style=\"color: #4ec9b0; font-weight: bold;\">0<\/span>    <span style=\"color:\r\n  #9a9ab0;\">(varint)<\/span>\r\n    <\/div>\r\n    <div style=\"margin-bottom: 20px;\">\r\n      <span style=\"color: #9a9ab0;\">field_number<\/span> = 24 >> 3   = <span style=\"color: #4ec9b0; font-weight: bold;\">3<\/span>\r\n    <\/div>\r\n\r\n    <div style=\"color: #ffffff; margin-bottom: 20px;\">\r\n      Field <span style=\"color: #4ec9b0; font-weight: bold;\">3<\/span>, wire type <span style=\"color: #4ec9b0; font-weight: bold;\">0<\/span>. Now read the varint value \u2014\r\n  and this is where it gets interesting. Five bytes:\r\n    <\/div>\r\n\r\n    <!-- Five bytes breakdown -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; margin-bottom: 16px;\">\r\n\r\n      <div style=\"margin-bottom: 4px; color: #ffffff;\">Byte 1: <span style=\"color: #4ec9b0;\">0xD2<\/span> = <span style=\"color: #dcdcaa;\">1101 0010<\/span><\/div>\r\n      <div style=\"margin-bottom: 4px; color: #9a9ab0;\">  MSB = <span style=\"color: #f44747; font-weight: bold;\">1<\/span> (more coming) &nbsp;&nbsp;&nbsp; Payload: <span\r\n   style=\"color: #dcdcaa;\">101 0010<\/span> = <span style=\"color: #4ec9b0; font-weight: bold;\">82<\/span><\/div>\r\n\r\n      <div style=\"margin-bottom: 4px; color: #ffffff; margin-top: 12px;\">Byte 2: <span style=\"color: #4ec9b0;\">0xCF<\/span> = <span style=\"color: #dcdcaa;\">1100\r\n  1111<\/span><\/div>\r\n      <div style=\"margin-bottom: 4px; color: #9a9ab0;\">  MSB = <span style=\"color: #f44747; font-weight: bold;\">1<\/span> (more coming) &nbsp;&nbsp;&nbsp; Payload: <span\r\n   style=\"color: #dcdcaa;\">100 1111<\/span> = <span style=\"color: #4ec9b0; font-weight: bold;\">79<\/span><\/div>\r\n\r\n      <div style=\"margin-bottom: 4px; color: #ffffff; margin-top: 12px;\">Byte 3: <span style=\"color: #4ec9b0;\">0x8D<\/span> = <span style=\"color: #dcdcaa;\">1000\r\n  1101<\/span><\/div>\r\n      <div style=\"margin-bottom: 4px; color: #9a9ab0;\">  MSB = <span style=\"color: #f44747; font-weight: bold;\">1<\/span> (more coming) &nbsp;&nbsp;&nbsp; Payload: <span\r\n   style=\"color: #dcdcaa;\">000 1101<\/span> = <span style=\"color: #4ec9b0; font-weight: bold;\">13<\/span><\/div>\r\n\r\n      <div style=\"margin-bottom: 4px; color: #ffffff; margin-top: 12px;\">Byte 4: <span style=\"color: #4ec9b0;\">0xBB<\/span> = <span style=\"color: #dcdcaa;\">1011\r\n  1011<\/span><\/div>\r\n      <div style=\"margin-bottom: 4px; color: #9a9ab0;\">  MSB = <span style=\"color: #f44747; font-weight: bold;\">1<\/span> (more coming) &nbsp;&nbsp;&nbsp; Payload: <span\r\n   style=\"color: #dcdcaa;\">011 1011<\/span> = <span style=\"color: #4ec9b0; font-weight: bold;\">59<\/span><\/div>\r\n\r\n      <div style=\"margin-bottom: 4px; color: #ffffff; margin-top: 12px;\">Byte 5: <span style=\"color: #4ec9b0;\">0x06<\/span> = <span style=\"color: #dcdcaa;\">0000\r\n  0110<\/span><\/div>\r\n      <div style=\"margin-bottom: 4px; color: #9a9ab0;\">  MSB = <span style=\"color: #4ec9b0; font-weight: bold;\">0<\/span> (LAST byte) &nbsp;&nbsp;&nbsp;&nbsp; Payload:\r\n  <span style=\"color: #dcdcaa;\">000 0110<\/span> = <span style=\"color: #4ec9b0; font-weight: bold;\">6<\/span><\/div>\r\n\r\n    <\/div>\r\n\r\n    <!-- Reconstruction -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; color: #ffffff; margin-bottom: 12px; font-weight: bold;\">\r\n      Reconstruct (LEB128 \u2014 each byte's payload shifts 7 bits higher):\r\n    <\/div>\r\n\r\n    <pre style=\"margin: 0 0 20px 0; padding: 0; background: transparent; border: none; font-family: 'Courier New', Consolas, monospace; font-size: 16px; line-height:\r\n  1.8; color: #dcdcaa;\"><span style=\"color: #9a9ab0;\">  Byte 1:<\/span>  <span style=\"color: #4ec9b0;\">82<\/span> << 0  =            <span style=\"color: #4ec9b0;\">82<\/span>\r\n  <span style=\"color: #9a9ab0;\">Byte 2:<\/span>  <span style=\"color: #4ec9b0;\">79<\/span> << 7  =        <span style=\"color: #4ec9b0;\">10,112<\/span>     <span\r\n  style=\"color: #9a9ab0;\">running total:<\/span>        <span style=\"color: #4ec9b0;\">10,194<\/span>\r\n  <span style=\"color: #9a9ab0;\">Byte 3:<\/span>  <span style=\"color: #4ec9b0;\">13<\/span> << 14 =       <span style=\"color: #4ec9b0;\">212,992<\/span>     <span\r\n  style=\"color: #9a9ab0;\">running total:<\/span>       <span style=\"color: #4ec9b0;\">223,186<\/span>\r\n  <span style=\"color: #9a9ab0;\">Byte 4:<\/span>  <span style=\"color: #4ec9b0;\">59<\/span> << 21 =   <span style=\"color: #4ec9b0;\">123,731,968<\/span>     <span\r\n  style=\"color: #9a9ab0;\">running total:<\/span>   <span style=\"color: #4ec9b0;\">123,955,154<\/span>\r\n  <span style=\"color: #9a9ab0;\">Byte 5:<\/span>   <span style=\"color: #4ec9b0;\">6<\/span> << 28 = <span style=\"color: #4ec9b0;\">1,610,612,736<\/span>     <span\r\n  style=\"color: #9a9ab0;\">running total:<\/span> <span style=\"color: #4ec9b0; font-weight: bold;\">1,734,567,890<\/span><\/pre>\r\n\r\n    <!-- Result -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; margin-bottom: 20px;\">\r\n      <span style=\"color: #ffffff; font-weight: bold;\">Field 3 =<\/span> <span style=\"color: #4ec9b0; font-weight: bold; font-size: 18px;\">1,734,567,890<\/span> <span\r\n  style=\"color: #9a9ab0;\">\u2014 a Unix timestamp.<\/span>\r\n    <\/div>\r\n\r\n    <!-- Python conversion -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; margin-bottom: 12px; color: #ffffff; font-weight: bold;\">\r\n      Converting with Python:\r\n    <\/div>\r\n\r\n    <pre style=\"margin: 0 0 16px 0; padding: 0; background: transparent; border: none; font-family: 'Courier New', Consolas, monospace; font-size: 16px; line-height:\r\n  1.8; color: #dcdcaa;\"><span style=\"color: #9a9ab0;\">  >>><\/span> from datetime import datetime, timezone\r\n  <span style=\"color: #9a9ab0;\">>>><\/span> datetime.fromtimestamp(<span style=\"color: #4ec9b0;\">1734567890<\/span>, tz=timezone.utc)\r\n  <span style=\"color: #9a9ab0;\">datetime.datetime(2024, 12, 19, 0, 24, 50, tzinfo=datetime.timezone.utc)<\/span><\/pre>\r\n\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px;\">\r\n      <span style=\"color: #4ec9b0; font-weight: bold; font-size: 18px;\">December 19, 2024 at 00:24:50 UTC<\/span>\r\n    <\/div>\r\n\r\n  <\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5055aff elementor-widget elementor-widget-text-editor\" data-id=\"5055aff\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h5><em>What Happens if You Use a SQLite Decoder Instead?<\/em><\/h5>\nIf you mistakenly decoded <code>D2CF8DBB06<\/code> as a SQLite varint (big-endian, shift-accumulator-left), you would calculate:\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6d46581 elementor-widget elementor-widget-html\" data-id=\"6d46581\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 24px; margin: 20px 0; font-family: 'Courier New', Consolas, monospace;\r\n  font-size: 16px; line-height: 1.8; overflow-x: auto;\">\r\n\r\n    <div style=\"color: #ffffff; margin-bottom: 12px; font-weight: bold;\">SQLite-style:<\/div>\r\n\r\n    <pre style=\"margin: 0 0 20px 0; padding: 0; background: transparent; border: none; font-family: inherit; font-size: 16px; line-height: 2; color: #dcdcaa;\r\n  white-space: pre; overflow-x: auto;\"><span style=\"color: #9a9ab0;\">  acc<\/span> = <span style=\"color: #f44747;\">82<\/span>\r\n  <span style=\"color: #9a9ab0;\">acc<\/span> = (<span style=\"color: #f44747;\">82<\/span> << 7)          | 79 = <span style=\"color: #f44747;\">10,575<\/span>\r\n  <span style=\"color: #9a9ab0;\">acc<\/span> = (<span style=\"color: #f44747;\">10,575<\/span> << 7)      | 13 = <span style=\"color: #f44747;\">1,353,613<\/span>\r\n  <span style=\"color: #9a9ab0;\">acc<\/span> = (<span style=\"color: #f44747;\">1,353,613<\/span> << 7)   | 59 = <span style=\"color: #f44747;\">173,262,523<\/span>\r\n  <span style=\"color: #9a9ab0;\">acc<\/span> = (<span style=\"color: #f44747;\">173,262,523<\/span> << 7) |  6 = <span style=\"color: #f44747; font-weight:\r\n  bold;\">22,177,602,950<\/span><\/pre>\r\n\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px;\">\r\n      <span style=\"color: #f44747; font-weight: bold; font-size: 18px;\">22,177,602,950<\/span> <span style=\"color: #ffffff;\">as a Unix timestamp? That's the year<\/span>\r\n  <span style=\"color: #f44747; font-weight: bold; font-size: 18px;\">2672.<\/span>\r\n    <\/div>\r\n\r\n  <\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6e9fc99 elementor-widget elementor-widget-text-editor\" data-id=\"6e9fc99\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h4>Field 4: The XOR Key (Length-Delimited Bytes)<\/h4>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e5076a2 elementor-widget elementor-widget-html\" data-id=\"e5076a2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 24px; margin: 20px 0; color: #c8c8d4; font-family: 'Courier New',\r\n  Consolas, monospace; font-size: 16px; line-height: 1.8;\">\r\n\r\n    <!-- Offset and bytes -->\r\n    <div style=\"color: #ffffff; margin-bottom: 16px;\">\r\n      Offset <span style=\"color: #4ec9b0;\">0x0010<\/span>:\r\n    <\/div>\r\n    <div style=\"color: #dcdcaa; font-size: 18px; font-weight: bold; margin-bottom: 20px;\">\r\n      22 04 <span style=\"color: #f44747;\">DE AD BE EF<\/span>\r\n    <\/div>\r\n\r\n    <!-- Read the tag -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; color: #ffffff; margin-bottom: 12px; font-weight: bold;\">\r\n      Tag <span style=\"color: #4ec9b0;\">0x22<\/span> = 34:\r\n    <\/div>\r\n\r\n    <div style=\"margin-bottom: 4px;\">\r\n      <span style=\"color: #9a9ab0;\">wire_type<\/span>    = 34 & 0x07 = <span style=\"color: #4ec9b0; font-weight: bold;\">2<\/span>    <span style=\"color:\r\n  #9a9ab0;\">(length-delimited)<\/span>\r\n    <\/div>\r\n    <div style=\"margin-bottom: 20px;\">\r\n      <span style=\"color: #9a9ab0;\">field_number<\/span> = 34 >> 3   = <span style=\"color: #4ec9b0; font-weight: bold;\">4<\/span>\r\n    <\/div>\r\n\r\n    <div style=\"color: #ffffff; margin-bottom: 20px;\">\r\n      Field <span style=\"color: #4ec9b0; font-weight: bold;\">4<\/span>, wire type <span style=\"color: #4ec9b0; font-weight: bold;\">2<\/span>. Length varint: <span\r\n  style=\"color: #4ec9b0;\">0x04<\/span> = <span style=\"color: #4ec9b0; font-weight: bold;\">4<\/span>. Four bytes of data follow:\r\n    <\/div>\r\n\r\n    <!-- Data -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px;\">\r\n      <span style=\"color: #f44747; font-weight: bold; font-size: 20px;\">DE AD BE EF<\/span>\r\n    <\/div>\r\n\r\n  <\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-03ef1aa elementor-widget elementor-widget-text-editor\" data-id=\"03ef1aa\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>If you\u2019ve been around hex editors, you should recognize <strong>\u20180xDEADBEEF\u2019<\/strong> as a classic magic number used as a placeholder. In our case, it\u2019s a 4-byte XOR key. We\u2019ll need it for the next field.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d1cf3e1 elementor-widget elementor-widget-text-editor\" data-id=\"d1cf3e1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h4>Field 5: The Encrypted Message (Length-Delimited, Multi-Byte)<\/h4>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-800cdc8 elementor-widget elementor-widget-html\" data-id=\"800cdc8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 24px; margin: 20px 0; color: #c8c8d4; font-family: 'Courier New',\r\n  Consolas, monospace; font-size: 16px; line-height: 1.8;\">\r\n\r\n    <!-- Offset and bytes -->\r\n    <div style=\"color: #ffffff; margin-bottom: 16px;\">\r\n      Offset <span style=\"color: #4ec9b0;\">0x0016<\/span>:\r\n    <\/div>\r\n    <div style=\"color: #dcdcaa; font-size: 18px; font-weight: bold; margin-bottom: 20px;\">\r\n      2A B5 01 <span style=\"color: #9a9ab0; font-size: 16px; font-weight: normal;\">[181 bytes of encrypted data...]<\/span>\r\n    <\/div>\r\n\r\n    <!-- Read the tag -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; color: #ffffff; margin-bottom: 12px; font-weight: bold;\">\r\n      Tag <span style=\"color: #4ec9b0;\">0x2A<\/span> = 42:\r\n    <\/div>\r\n\r\n    <div style=\"margin-bottom: 4px;\">\r\n      <span style=\"color: #9a9ab0;\">wire_type<\/span>    = 42 & 0x07 = <span style=\"color: #4ec9b0; font-weight: bold;\">2<\/span>    <span style=\"color:\r\n  #9a9ab0;\">(length-delimited)<\/span>\r\n    <\/div>\r\n    <div style=\"margin-bottom: 20px;\">\r\n      <span style=\"color: #9a9ab0;\">field_number<\/span> = 42 >> 3   = <span style=\"color: #4ec9b0; font-weight: bold;\">5<\/span>\r\n    <\/div>\r\n\r\n    <div style=\"color: #ffffff; margin-bottom: 20px;\">\r\n      Field <span style=\"color: #4ec9b0; font-weight: bold;\">5<\/span>, wire type <span style=\"color: #4ec9b0; font-weight: bold;\">2<\/span>. Now read the length varint \u2014\r\n   and this one is two bytes:\r\n    <\/div>\r\n\r\n    <!-- Two byte length varint -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; margin-bottom: 16px;\">\r\n\r\n      <div style=\"margin-bottom: 4px; color: #ffffff;\">Byte 1: <span style=\"color: #4ec9b0;\">0xB5<\/span> = <span style=\"color: #dcdcaa;\">1011 0101<\/span><\/div>\r\n      <div style=\"margin-bottom: 4px; color: #9a9ab0;\">  MSB = <span style=\"color: #f44747; font-weight: bold;\">1<\/span> (more bytes) &nbsp;&nbsp;&nbsp;&nbsp; Payload:\r\n  <span style=\"color: #dcdcaa;\">011 0101<\/span> = <span style=\"color: #4ec9b0; font-weight: bold;\">53<\/span><\/div>\r\n\r\n      <div style=\"margin-bottom: 4px; color: #ffffff; margin-top: 12px;\">Byte 2: <span style=\"color: #4ec9b0;\">0x01<\/span> = <span style=\"color: #dcdcaa;\">0000\r\n  0001<\/span><\/div>\r\n      <div style=\"margin-bottom: 16px; color: #9a9ab0;\">  MSB = <span style=\"color: #4ec9b0; font-weight: bold;\">0<\/span> (last byte) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\r\n  Payload: <span style=\"color: #dcdcaa;\">000 0001<\/span> = <span style=\"color: #4ec9b0; font-weight: bold;\">1<\/span><\/div>\r\n\r\n    <\/div>\r\n\r\n    <!-- Length calculation -->\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px; margin-bottom: 16px;\">\r\n      <span style=\"color: #ffffff;\">Length =<\/span> <span style=\"color: #4ec9b0;\">53<\/span> | (<span style=\"color: #4ec9b0;\">1<\/span> << 7) = 53 + 128 = <span\r\n  style=\"color: #4ec9b0; font-weight: bold; font-size: 18px;\">181<\/span>\r\n    <\/div>\r\n\r\n    <div style=\"border-top: 1px solid #3a3a5c; padding-top: 16px;\">\r\n      <span style=\"color: #ffffff;\">The remaining<\/span> <span style=\"color: #4ec9b0; font-weight: bold;\">181 bytes<\/span> <span style=\"color: #ffffff;\">are the\r\n  encrypted message content.<\/span>\r\n    <\/div>\r\n\r\n  <\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-08a1f9b e-flex e-con-boxed e-con e-parent\" data-id=\"08a1f9b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d3bb0fc elementor-widget elementor-widget-heading\" data-id=\"d3bb0fc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Protobuf Varint Forensics: Bitwise Operations Behind the Decoder<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-61675f9 elementor-widget elementor-widget-text-editor\" data-id=\"61675f9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Three operations do all of the work. If you understand these, you can read any varint:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7607d8d elementor-widget elementor-widget-text-editor\" data-id=\"7607d8d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h4>AND (&#8216;&amp;&#8217;) &#8211; Stripping the continuation bit<\/h4><p><code>payload = byte &amp; 0x7F\u00a0\u00a0\u00a0 # 0x7F = 0111 1111<\/code><\/p><p>The mask \u20180x7F\u2019 has the MSB cleared and all other bits set. ANDing any byte with this mask zeros out the continuation flag and keeps the 7 data bits. Think of it as a stencil, only the bits where the mask has a \u20181\u2019 come through:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-dec0a05 elementor-widget elementor-widget-html\" data-id=\"dec0a05\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 16px; margin: 16px 0; font-family: 'Courier New', Consolas, monospace;\r\n  font-size: 16px; line-height: 1.8; color: #dcdcaa; overflow-x: auto; white-space: pre;\">    <span style=\"color: #dcdcaa;\">  1101 0010<\/span>   <span style=\"color:\r\n  #9a9ab0;\">(0xD2 -- our timestamp byte 1)<\/span>\r\n  <span style=\"color: #ffffff; font-weight: bold;\">AND<\/span> <span style=\"color: #dcdcaa;\">0111 1111<\/span>   <span style=\"color: #9a9ab0;\">(0x7F -- the mask)<\/span>\r\n    = <span style=\"color: #4ec9b0; font-weight: bold;\">0101 0010<\/span>   <span style=\"color: #9a9ab0;\">(0x52 = 82 -- just the data bits)<\/span><\/pre>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-490b2dc elementor-widget elementor-widget-text-editor\" data-id=\"490b2dc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>We also use AND with 0x80 to <em>test<\/em> the continuation bit without stripping it:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4b53d13 elementor-widget elementor-widget-code-highlight\" data-id=\"4b53d13\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>if (byte & 0x80) == 0:    # MSB is 0 -- this is the last byte\r\n     break\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-94ed8b8 elementor-widget elementor-widget-text-editor\" data-id=\"94ed8b8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h4>Left shift (&#8216;&lt;&lt;&#8216;) &#8211; Positioning the Payload<\/h4><p><code>payload &lt;&lt; shift\u00a0\u00a0\u00a0 # move bits into their correct lane<\/code><\/p><p>Left shift moves bits to higher positions. Each shift of 1 doubles the value. In LEB128, each successive byte carries bits 7 positions higher than the last.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8462ea9 elementor-widget elementor-widget-html\" data-id=\"8462ea9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 16px; margin: 16px 0; font-family: 'Courier New', Consolas, monospace;\r\n  font-size: 16px; line-height: 1.8; color: #dcdcaa; overflow-x: auto; white-space: pre;\"><span style=\"color: #9a9ab0;\">  Byte 1 payload:<\/span> <span style=\"color:\r\n  #4ec9b0;\">82<\/span> << 0  =           <span style=\"color: #4ec9b0;\">82<\/span>   <span style=\"color: #9a9ab0;\"> (bits 0-6)<\/span>\r\n  <span style=\"color: #9a9ab0;\">Byte 2 payload:<\/span> <span style=\"color: #4ec9b0;\">79<\/span> << 7  =       <span style=\"color: #4ec9b0;\">10,112<\/span>   <span\r\n  style=\"color: #9a9ab0;\"> (bits 7-13)<\/span>\r\n  <span style=\"color: #9a9ab0;\">Byte 3 payload:<\/span> <span style=\"color: #4ec9b0;\">13<\/span> << 14 =      <span style=\"color: #4ec9b0;\">212,992<\/span>   <span\r\n  style=\"color: #9a9ab0;\"> (bits 14-20)<\/span>\r\n  <span style=\"color: #9a9ab0;\">Byte 4 payload:<\/span> <span style=\"color: #4ec9b0;\">59<\/span> << 21 =  <span style=\"color: #4ec9b0;\">123,731,968<\/span>   <span\r\n  style=\"color: #9a9ab0;\"> (bits 21-27)<\/span>\r\n  <span style=\"color: #9a9ab0;\">Byte 5 payload:<\/span>  <span style=\"color: #4ec9b0;\">6<\/span> << 28 = <span style=\"color: #4ec9b0; font-weight:\r\n  bold;\">1,610,612,736<\/span>   <span style=\"color: #9a9ab0;\">(bits 28-30)<\/span><\/pre>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-48fab7a elementor-widget elementor-widget-text-editor\" data-id=\"48fab7a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>No overlaps. Each payload occupies its own 7-bit lane.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-05b79b0 elementor-widget elementor-widget-text-editor\" data-id=\"05b79b0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h4>OR (&#8216;|&#8217;) &#8211; Combining the Pieces<\/h4><p><code>result |= payload &lt;&lt; shift<\/code><\/p><p>OR merges bits. Where <strong>either<\/strong> input has a `1`, the output has a `1`. Since our shifted payloads never overlap, OR glues them together into the final value:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c6b4f9d elementor-widget elementor-widget-html\" data-id=\"c6b4f9d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 16px; margin: 16px 0; font-family: 'Courier New', Consolas, monospace;\r\n  font-size: 16px; line-height: 1.8; color: #dcdcaa; overflow-x: auto; white-space: pre;\">    <span style=\"color: #dcdcaa;\">  0000 0000 0000 0000 0000 0000 0101 0010<\/span>   <span style=\"color: #9a9ab0;\">(byte 1: 82)<\/span>\r\n   <span style=\"color: #ffffff; font-weight: bold;\">OR<\/span> <span style=\"color: #dcdcaa;\">0000 0000 0000 0000 0010 0111 1000 0000<\/span>   <span style=\"color:\r\n  #9a9ab0;\">(byte 2: 79 << 7)<\/span>\r\n   <span style=\"color: #ffffff; font-weight: bold;\">OR<\/span> <span style=\"color: #dcdcaa;\">0000 0000 0000 0011 0100 0000 0000 0000<\/span>   <span style=\"color:\r\n  #9a9ab0;\">(byte 3: 13 << 14)<\/span>\r\n   <span style=\"color: #ffffff; font-weight: bold;\">OR<\/span> <span style=\"color: #dcdcaa;\">0000 0111 0111 0000 0000 0000 0000 0000<\/span>   <span style=\"color:\r\n  #9a9ab0;\">(byte 4: 59 << 21)<\/span>\r\n   <span style=\"color: #ffffff; font-weight: bold;\">OR<\/span> <span style=\"color: #dcdcaa;\">0110 0000 0000 0000 0000 0000 0000 0000<\/span>   <span style=\"color:\r\n  #9a9ab0;\">(byte 5: 6 << 28)<\/span>\r\n    = <span style=\"color: #4ec9b0; font-weight: bold;\">0110 0111 0111 0011 0110 0111 1101 0010<\/span>   = <span style=\"color: #4ec9b0; font-weight: bold; font-size:\r\n  18px;\">1,734,567,890<\/span><\/pre>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4bbb193 elementor-widget elementor-widget-text-editor\" data-id=\"4bbb193\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>These three operations are the engine behind protobuf varint forensics.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-079adba e-flex e-con-boxed e-con e-parent\" data-id=\"079adba\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f318599 elementor-widget elementor-widget-heading\" data-id=\"f318599\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">What is a Protobuf \"Message\"?<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e54ce10 elementor-widget elementor-widget-text-editor\" data-id=\"e54ce10\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Before we write the script, one clarification that trips people up: in protobuf, &#8220;message&#8221; is a structural term. It doesn&#8217;t mean a chat message or a text. A protobuf *message* is simply a container or a collection of typed fields. Think of it like a row in a database, or a dictionary in Python.<\/p><p>A protobuf message can contain another message as one of its fields (wire type 2, length-delimited). The outer message&#8217;s field value is itself a sequence of tag+value pairs that you parse the same way. Apple Notes does exactly this: the top-level Note message contains a nested AttributedString message, which contains the note text and formatting runs as its own fields.<\/p><p>In our challenge blob, all five fields are at the top level. There is no nesting. But in the real world, you&#8217;ll encounter nested messages frequently. The parsing logic is the same: read the length-delimited bytes, then feed them back into your parser.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ea03e99 e-flex e-con-boxed e-con e-parent\" data-id=\"ea03e99\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-dec29c9 elementor-widget elementor-widget-heading\" data-id=\"dec29c9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">The Complete Python Script<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0528348 elementor-widget elementor-widget-text-editor\" data-id=\"0528348\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Now let&#8217;s put it all together. This script takes the raw protobuf bytes, parses every field, converts the timestamp, extracts the XOR key, and decrypts the message:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b2f0e54 elementor-widget elementor-widget-code-highlight\" data-id=\"b2f0e54\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>from datetime import datetime, timezone\r\n\r\n\r\ndef decode_varint(data, offset=0):\r\n    \"\"\"\r\n    Decode a protobuf varint (LEB128) from bytes.\r\n    Returns (value, bytes_consumed).\r\n    \"\"\"\r\n    result = 0\r\n    shift = 0\r\n    bytes_consumed = 0\r\n\r\n    while True:\r\n        byte = data[offset + bytes_consumed]\r\n        bytes_consumed += 1\r\n\r\n        # AND with 0x7F: strip MSB, keep 7 data bits\r\n        payload = byte & 0x7F\r\n\r\n        # OR with shifted payload: merge into result\r\n        result |= payload << shift\r\n\r\n        # AND with 0x80: test continuation bit\r\n        if (byte & 0x80) == 0:\r\n            break\r\n\r\n        shift += 7\r\n\r\n    return result, bytes_consumed\r\n\r\n\r\ndef parse_fields(data):\r\n    \"\"\"\r\n    Parse raw protobuf bytes into fields.\r\n    Returns list of (field_number, wire_type, value) tuples.\r\n    \"\"\"\r\n    offset = 0\r\n    fields = []\r\n\r\n    while offset < len(data):\r\n        # Read the field tag (varint)\r\n        tag, consumed = decode_varint(data, offset)\r\n        offset += consumed\r\n\r\n        # Unpack: low 3 bits = wire type, upper bits = field number\r\n        wire_type    = tag & 0x07\r\n        field_number = tag >> 3\r\n\r\n        if wire_type == 0:          # Varint\r\n            value, consumed = decode_varint(data, offset)\r\n            offset += consumed\r\n\r\n        elif wire_type == 1:        # 64-bit fixed\r\n            value = data[offset:offset + 8]\r\n            offset += 8\r\n\r\n        elif wire_type == 2:        # Length-delimited\r\n            length, consumed = decode_varint(data, offset)\r\n            offset += consumed\r\n            value = data[offset:offset + length]\r\n            offset += length\r\n\r\n        elif wire_type == 5:        # 32-bit fixed\r\n            value = data[offset:offset + 4]\r\n            offset += 4\r\n\r\n        else:\r\n            print(f\"Unknown wire type {wire_type} at offset {offset}\")\r\n            break\r\n\r\n        fields.append((field_number, wire_type, value))\r\n\r\n    return fields\r\n\r\n\r\ndef xor_decrypt(data, key):\r\n    \"\"\"XOR each byte of data with the repeating key.\"\"\"\r\n    return bytes(b ^ key[i % len(key)] for i, b in enumerate(data))\r\n\r\n\r\n# ============================================================\r\n# THE PROTOBUF BLOB (raw bytes)\r\n# ============================================================\r\n\r\nraw = bytes.fromhex(\r\n    \"08E90712054C616E636518D2CF8DBB06\"\r\n    \"2204DEADBEEF2AB5019AC8CE80ADC4CA\"\r\n    \"CFAAC5DBCFB8D8D08BAD8DD781AAC29E\"\r\n    \"8EBDCED19AB0D99EDBEA958FC2EC9F87\"\r\n    \"DFF39A8FDAE88DDC8AB8C2CC8AFEEBCC\"\r\n    \"86BACCC7C1FEF8CD8AFED9D68AFEDEDF\"\r\n    \"82BB8DD38AAAC5D18BFECCCDCFB2CCCD\"\r\n    \"9BFED9D782BB839EABB18DD080AA8DDD\"\r\n    \"80B0D9DF8CAA8DD38AFEC2D0CFAAC5D7\"\r\n    \"9CFEC3CB82BCC8CCCFBFCADF86B08D93\"\r\n    \"CFABDEDBCFAAC5DBCFADC8DD80B0C9DF\"\r\n    \"9DA78DDD87BFC3D08AB2839EABBBDECA\"\r\n    \"9DB1D49E9BB6C4CDCFB0C2CA8AF0\"\r\n)\r\n\r\nprint(f\"Parsing {len(raw)} bytes of protobuf data.\\n\")\r\n\r\n# Parse all protobuf fields\r\nfields = parse_fields(raw)\r\n\r\nwire_type_names = {\r\n    0: \"Varint\",\r\n    1: \"64-bit fixed\",\r\n    2: \"Length-delimited\",\r\n    5: \"32-bit fixed\"\r\n}\r\n\r\nxor_key = None\r\nencrypted_msg = None\r\n\r\nfor field_num, wire_type, value in fields:\r\n    wt_name = wire_type_names.get(wire_type, f\"Unknown({wire_type})\")\r\n    print(f\"--- Field {field_num} | Wire Type {wire_type} ({wt_name}) ---\")\r\n\r\n    if wire_type == 0:\r\n        print(f\"  Value: {value}\")\r\n        if field_num == 3:\r\n            # Convert Unix timestamp\r\n            dt = datetime.fromtimestamp(value, tz=timezone.utc)\r\n            print(f\"  As datetime: {dt.strftime('%Y-%m-%d %H:%M:%S UTC')}\")\r\n\r\n    elif wire_type == 2:\r\n        print(f\"  Length: {len(value)} bytes\")\r\n        # Try to display as text\r\n        try:\r\n            text = value.decode(\"utf-8\")\r\n            if all(c.isprintable() or c in \"\\n\\r\\t\" for c in text):\r\n                print(f'  As text: \"{text}\"')\r\n            else:\r\n                raise ValueError\r\n        except (UnicodeDecodeError, ValueError):\r\n            print(f\"  Hex: {value.hex()}\")\r\n\r\n        # Capture key and ciphertext\r\n        if field_num == 4:\r\n            xor_key = value\r\n            print(f\"  XOR Key: 0x{value.hex().upper()}\")\r\n        elif field_num == 5:\r\n            encrypted_msg = value\r\n\r\n    print()\r\n\r\n# Decrypt the message\r\nif xor_key and encrypted_msg:\r\n    print(\"=\" * 60)\r\n    print(\"DECRYPTING MESSAGE\")\r\n    print(\"=\" * 60)\r\n    plaintext = xor_decrypt(encrypted_msg, xor_key)\r\n    print(f\"\\n  {plaintext.decode('utf-8')}\\n\")\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9d2e601 elementor-widget elementor-widget-text-editor\" data-id=\"9d2e601\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Expected Output:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9b934ac elementor-widget elementor-widget-html\" data-id=\"9b934ac\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t <pre style=\"background-color: #0d1117; border: 1px solid #3a3a5c; border-radius: 8px; padding: 24px; margin: 16px 0; font-family: 'Courier New', Consolas, monospace;\r\n  font-size: 15px; line-height: 1.7; color: #c8c8d4; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;\">Parsing 206 bytes of protobuf data.\r\n\r\n  --- Field 1 | Wire Type 0 (Varint) ---\r\n      Value: <span style=\"color: #4ec9b0; font-weight: bold;\">1001<\/span>\r\n\r\n  --- Field 2 | Wire Type 2 (Length-delimited) ---\r\n      Length: 5 bytes\r\n      As text: <span style=\"color: #4ec9b0; font-weight: bold;\">\"Lance\"<\/span>\r\n\r\n  --- Field 3 | Wire Type 0 (Varint) ---\r\n      Value: 1734567890\r\n      As datetime: <span style=\"color: #4ec9b0; font-weight: bold;\">2024-12-19 00:24:50 UTC<\/span>\r\n\r\n  --- Field 4 | Wire Type 2 (Length-delimited) ---\r\n      Length: 4 bytes\r\n      Hex: <span style=\"color: #f44747;\">deadbeef<\/span>\r\n      XOR Key: <span style=\"color: #f44747; font-weight: bold;\">0xDEADBEEF<\/span>\r\n\r\n  --- Field 5 | Wire Type 2 (Length-delimited) ---\r\n      Length: 181 bytes\r\n      Hex: 9ac8ce80adc4cacf...\r\n\r\n  <span style=\"color: #F37934;\">============================================================\r\n  DECRYPTING MESSAGE\r\n  ============================================================<\/span>\r\n\r\n  <span style=\"color: #4ec9b0; font-weight: bold;\">  Deposit the funds into account 4481-2290-7156\r\n    before Friday. Use the same method as last time.\r\n    Do not contact me on this number again - use the\r\n    secondary channel. Destroy this note.<\/span><\/pre>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1d18d8b e-flex e-con-boxed e-con e-parent\" data-id=\"1d18d8b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-850d5ac elementor-widget elementor-widget-heading\" data-id=\"850d5ac\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Verify it Yourself in CyberChef<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9e8723c elementor-widget elementor-widget-text-editor\" data-id=\"9e8723c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>If you want to cross-check the XOR decryption without trusting the Python script, and as examiners, you shouldn&#8217;t blindly trust any script, paste the encrypted hex bytes from Field 5 into CyberChef:<\/p><p><strong>Input<\/strong> (the 181 bytes of encrypted data from Field 5):<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-63b3ecd elementor-widget elementor-widget-html\" data-id=\"63b3ecd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre style=\"background-color: #1a1a2e; border: 1px solid #3a3a5c; border-radius: 8px; padding: 16px; margin: 16px 0; font-family: 'Courier New', Consolas, monospace;\r\n  font-size: 16px; line-height: 1.8; color: #dcdcaa; overflow-x: auto; white-space: pre;\">  9A C8 CE 80 AD C4 CA CF AA C5 DB CF B8 D8 D0 8B\r\n  AD 8D D7 81 AA C2 9E 8E BD CE D1 9A B0 D9 9E DB\r\n  EA 95 8F C2 EC 9F 87 DF F3 9A 8F DA E8 8D DC 8A\r\n  B8 C2 CC 8A FE EB CC 86 BA CC C7 C1 FE F8 CD 8A\r\n  FE D9 D6 8A FE DE DF 82 BB 8D D3 8A AA C5 D1 8B\r\n  FE CC CD CF B2 CC CD 9B FE D9 D7 82 BB 83 9E AB\r\n  B1 8D D0 80 AA 8D DD 80 B0 D9 DF 8C AA 8D D3 8A\r\n  FE C2 D0 CF AA C5 D7 9C FE C3 CB 82 BC C8 CC CF\r\n  BF CA DF 86 B0 8D 93 CF AB DE DB CF AA C5 DB CF\r\n  AD C8 DD 80 B0 C9 DF 9D A7 8D DD 87 BF C3 D0 8A\r\n  B2 83 9E AB BB DE CA 9D B1 D4 9E 9B B6 C4 CD CF\r\n  B0 C2 CA 8A F0<\/pre>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-640ef19 elementor-widget elementor-widget-text-editor\" data-id=\"640ef19\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Recipe:<\/p><ol><li>`Remove whitespace` (spaces, carriage returns, line feeds, tabs)<\/li><li>`From Hex` (delimiter: Auto)<\/li><li>`XOR` (key: `DEADBEEF`, key type: <strong>Hex<\/strong>, scheme: Standard)<\/li><\/ol>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-616df0f elementor-widget elementor-widget-image\" data-id=\"616df0f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<figure class=\"wp-caption\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/gchq.github.io\/CyberChef\/\" target=\"_blank\">\n\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"800\" height=\"584\" src=\"https:\/\/elusivedata.io\/wp-content\/uploads\/2026\/03\/cyberchef.png\" class=\"attachment-large size-large wp-image-15096\" alt=\"CyberChef recipe showing XOR decryption of protobuf encrypted message using DEADBEEF hex key\" srcset=\"https:\/\/elusivedata.io\/wp-content\/uploads\/2026\/03\/cyberchef.png 965w, https:\/\/elusivedata.io\/wp-content\/uploads\/2026\/03\/cyberchef-300x219.png 300w, https:\/\/elusivedata.io\/wp-content\/uploads\/2026\/03\/cyberchef-768x560.png 768w, https:\/\/elusivedata.io\/wp-content\/uploads\/2026\/03\/cyberchef-16x12.png 16w, https:\/\/elusivedata.io\/wp-content\/uploads\/2026\/03\/cyberchef-600x438.png 600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t<figcaption class=\"widget-image-caption wp-caption-text\">CyberChef recipe: Remove whitespace, From Hex, then XOR with key DEADBEEF (Hex)<\/figcaption>\n\t\t\t\t\t\t\t\t\t\t<\/figure>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-dd518ca elementor-widget elementor-widget-text-editor\" data-id=\"dd518ca\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>You should see the plaintext message in the output. If you get garbled output, double-check that the XOR key type is set to &#8220;Hex&#8221; and not &#8220;UTF8&#8221;. The key is the 4-byte sequence `0xDE 0xAD 0xBE 0xEF`, not the ASCII characters D-E-A-D-B-E-E-F.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-e758142 e-flex e-con-boxed e-con e-parent\" data-id=\"e758142\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2430d52 elementor-widget elementor-widget-heading\" data-id=\"2430d52\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Why this Matters<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3df7a72 elementor-widget elementor-widget-text-editor\" data-id=\"3df7a72\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>As forensic examiners, we don\u2019t get to choose how application developers store their data. We have to meet the data where it is. Increasingly, that data is wrapped in Protocol Buffers, whether you recognize it or not.<\/p><p>This is exactly the kind of problem we built ED SQLite Visualizer to solve. When you\u2019re staring at a BLOB column in `NoteStore.sqlite`, the challenge is not accessing the data. The challenge is understanding it. SQLite Visualizer lets you go from compressed binary to structured protobuf fields in seconds. You can apply a Gunzip decoder, then chain a Protobuf decoder, and immediately see field numbers, wire types, and values without writing a single line of code. It is schema-agnostic, so it works on any protobuf data you encounter, whether it is Apple Notes, WhatsApp, or an app nobody has written a parser for yet.<\/p><p>But tools do not replace understanding. When you are on the stand explaining how you recovered evidence from a protobuf blob, \u201cI clicked a button\u201d is not a methodology. It is a liability. Knowing what LEB128 encoding is, why the first byte carries the least significant bits, and how wire types determine field boundaries is what makes your analysis defensible. The tool gets you there faster. The knowledge is what keeps you there.<\/p><p>If you learned varints from SQLite and assumed protobuf worked the same way, you are not alone. It is one of the most common mistakes examiners make. Understanding why they differ is what protobuf varint forensics is really about.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-18e1fcf e-flex e-con-boxed e-con e-parent\" data-id=\"18e1fcf\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d4c2f55 elementor-widget elementor-widget-heading\" data-id=\"d4c2f55\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Take it Further<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f64a4a9 elementor-widget elementor-widget-text-editor\" data-id=\"f64a4a9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>If you can decode this manually, you understand it.<\/p><p>If you need to do this at scale, across dozens of databases and thousands of records, you need the right tools.<\/p><p>To go deeper into protobuf varint forensics, check out our courses&#8230;<\/p><p><a href=\"https:\/\/elusivedata.io\/sqlite-visualizer\" target=\"_blank\" rel=\"noopener\"><strong>ED SQLite Visualizer<\/strong><\/a> \u2014 Our forensic database analysis platform is built for exactly this kind of work. Decode gzip, protobuf, base64, plists, and more \u2014 directly inside the tool. No external scripts. No context switching. Just raw data, fully exposed and ready for analysis.<\/p><p><a href=\"https:\/\/elusivedata.io\/python-for-mobile-forensics\" target=\"_blank\" rel=\"noopener\"><strong>Python for Mobile Forensics<\/strong><\/a> \u2014 Our 3-day hands-on course teaches you how to build your own parsers from scratch. You\u2019ll go beyond tools and learn how to handle unsupported apps, reverse custom formats, and confidently decode artifacts like the one in this post.<\/p><p><a href=\"https:\/\/elusivedata.io\/sqlite-forensics\" target=\"_blank\" rel=\"noopener\"><strong>Advanced SQLite Forensics<\/strong><\/a> \u2014 Take a deeper dive into SQLite internals \u2014 file headers, page structure, record formats, freelist analysis, WAL frames, and recovery of deleted data at the byte level.<\/p><p><strong>Previously<\/strong>: <a href=\"https:\/\/elusivedata.io\/decrypt-apple-notes-ios16\" target=\"_blank\" rel=\"noopener\">Decrypt Locked Apple Notes on iOS 16.x<\/a> \u2014 follow the full workflow that leads to the protobuf blob you just parsed.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Protobuf varints are not SQLite varints. Learn how to parse Protocol Buffer data from Apple Notes and mobile forensic artifacts, decode LEB128 varints step by step, and build a Python decoder with bitwise operations. Includes a hands-on XOR decryption challenge.<\/p>","protected":false},"author":1,"featured_media":15137,"comment_status":"open","ping_status":"open","sticky":false,"template":"elementor_theme","format":"standard","meta":{"content-type":"","footnotes":""},"categories":[120],"tags":[],"class_list":["post-14969","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sqlite"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.3 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Protocol Buffers for Forensic Examiners: The Varint Trap - Elusive Data<\/title>\n<meta name=\"description\" content=\"Protobuf varints are not SQLite varints. Learn to parse protobuf data from mobile forensic artifacts and decode LEB128 varints in Python.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/elusivedata.io\/ar\/protobuf-varint-forensics\/\" \/>\n<meta property=\"og:locale\" content=\"ar_AR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Protocol Buffers for Forensic Examiners: The Varint Trap\" \/>\n<meta property=\"og:description\" content=\"Protobuf varints are not SQLite varints. Learn to parse protobuf data from mobile forensic artifacts and decode LEB128 varints in Python.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/elusivedata.io\/ar\/protobuf-varint-forensics\/\" \/>\n<meta property=\"og:site_name\" content=\"Elusive Data\" \/>\n<meta property=\"article:published_time\" content=\"2026-03-25T13:30:15+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-03-28T08:13:57+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/elusivedata.io\/wp-content\/uploads\/2026\/03\/Python_DB_compressed.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1814\" \/>\n\t<meta property=\"og:image:height\" content=\"1080\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"James Eichbaum\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u0643\u064f\u062a\u0628 \u0628\u0648\u0627\u0633\u0637\u0629\" \/>\n\t<meta name=\"twitter:data1\" content=\"James Eichbaum\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u0648\u0642\u062a \u0627\u0644\u0642\u0631\u0627\u0621\u0629 \u0627\u0644\u0645\u064f\u0642\u062f\u0651\u0631\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 \u062f\u0642\u064a\u0642\u0629\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/elusivedata.io\\\/protobuf-varint-forensics\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/elusivedata.io\\\/protobuf-varint-forensics\\\/\"},\"author\":{\"name\":\"James Eichbaum\",\"@id\":\"https:\\\/\\\/elusivedata.io\\\/#\\\/schema\\\/person\\\/2c00b8313d6aef321fd69bf82e2aa436\"},\"headline\":\"Protocol Buffers for Forensic Examiners: The Varint Trap\",\"datePublished\":\"2026-03-25T13:30:15+00:00\",\"dateModified\":\"2026-03-28T08:13:57+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/elusivedata.io\\\/protobuf-varint-forensics\\\/\"},\"wordCount\":1456,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/elusivedata.io\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/elusivedata.io\\\/protobuf-varint-forensics\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/elusivedata.io\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/Python_DB_compressed.jpg\",\"articleSection\":[\"SQLite\"],\"inLanguage\":\"ar\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/elusivedata.io\\\/protobuf-varint-forensics\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/elusivedata.io\\\/protobuf-varint-forensics\\\/\",\"url\":\"https:\\\/\\\/elusivedata.io\\\/protobuf-varint-forensics\\\/\",\"name\":\"Protocol Buffers for Forensic Examiners: The Varint Trap - Elusive Data\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/elusivedata.io\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/elusivedata.io\\\/protobuf-varint-forensics\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/elusivedata.io\\\/protobuf-varint-forensics\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/elusivedata.io\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/Python_DB_compressed.jpg\",\"datePublished\":\"2026-03-25T13:30:15+00:00\",\"dateModified\":\"2026-03-28T08:13:57+00:00\",\"description\":\"Protobuf varints are not SQLite varints. Learn to parse protobuf data from mobile forensic artifacts and decode LEB128 varints in Python.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/elusivedata.io\\\/protobuf-varint-forensics\\\/#breadcrumb\"},\"inLanguage\":\"ar\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/elusivedata.io\\\/protobuf-varint-forensics\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"ar\",\"@id\":\"https:\\\/\\\/elusivedata.io\\\/protobuf-varint-forensics\\\/#primaryimage\",\"url\":\"https:\\\/\\\/elusivedata.io\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/Python_DB_compressed.jpg\",\"contentUrl\":\"https:\\\/\\\/elusivedata.io\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/Python_DB_compressed.jpg\",\"width\":1814,\"height\":1080,\"caption\":\"Protocol Buffers varint decoding in Python for digital forensics analysis\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/elusivedata.io\\\/protobuf-varint-forensics\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/elusivedata.io\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Protocol Buffers for Forensic Examiners: The Varint Trap\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/elusivedata.io\\\/#website\",\"url\":\"https:\\\/\\\/elusivedata.io\\\/\",\"name\":\"ElusiveData\",\"description\":\"Excellence in Digital Forensics Training and Consulting\",\"publisher\":{\"@id\":\"https:\\\/\\\/elusivedata.io\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/elusivedata.io\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ar\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/elusivedata.io\\\/#organization\",\"name\":\"ElusiveData\",\"url\":\"https:\\\/\\\/elusivedata.io\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ar\",\"@id\":\"https:\\\/\\\/elusivedata.io\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/elusivedata.io\\\/wp-content\\\/uploads\\\/2024\\\/11\\\/Asset-3_2x-scaled.png\",\"contentUrl\":\"https:\\\/\\\/elusivedata.io\\\/wp-content\\\/uploads\\\/2024\\\/11\\\/Asset-3_2x-scaled.png\",\"width\":2560,\"height\":370,\"caption\":\"ElusiveData\"},\"image\":{\"@id\":\"https:\\\/\\\/elusivedata.io\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.youtube.com\\\/@elusivedata\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/elusivedata.io\\\/#\\\/schema\\\/person\\\/2c00b8313d6aef321fd69bf82e2aa436\",\"name\":\"James Eichbaum\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ar\",\"@id\":\"https:\\\/\\\/elusivedata.io\\\/wp-content\\\/plugins\\\/ld-dashboard\\\/public\\\/img\\\/img_avatar.png\",\"url\":\"https:\\\/\\\/elusivedata.io\\\/wp-content\\\/plugins\\\/ld-dashboard\\\/public\\\/img\\\/img_avatar.png\",\"contentUrl\":\"https:\\\/\\\/elusivedata.io\\\/wp-content\\\/plugins\\\/ld-dashboard\\\/public\\\/img\\\/img_avatar.png\",\"caption\":\"James Eichbaum\"},\"sameAs\":[\"http:\\\/\\\/elusivedata.io\"],\"url\":\"https:\\\/\\\/elusivedata.io\\\/ar\\\/author\\\/eichbaumjamesgmail-com\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Protocol Buffers for Forensic Examiners: The Varint Trap - Elusive Data","description":"Protobuf varints are not SQLite varints. Learn to parse protobuf data from mobile forensic artifacts and decode LEB128 varints in Python.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/elusivedata.io\/ar\/protobuf-varint-forensics\/","og_locale":"ar_AR","og_type":"article","og_title":"Protocol Buffers for Forensic Examiners: The Varint Trap","og_description":"Protobuf varints are not SQLite varints. Learn to parse protobuf data from mobile forensic artifacts and decode LEB128 varints in Python.","og_url":"https:\/\/elusivedata.io\/ar\/protobuf-varint-forensics\/","og_site_name":"Elusive Data","article_published_time":"2026-03-25T13:30:15+00:00","article_modified_time":"2026-03-28T08:13:57+00:00","og_image":[{"width":1814,"height":1080,"url":"https:\/\/elusivedata.io\/wp-content\/uploads\/2026\/03\/Python_DB_compressed.jpg","type":"image\/jpeg"}],"author":"James Eichbaum","twitter_card":"summary_large_image","twitter_misc":{"\u0643\u064f\u062a\u0628 \u0628\u0648\u0627\u0633\u0637\u0629":"James Eichbaum","\u0648\u0642\u062a \u0627\u0644\u0642\u0631\u0627\u0621\u0629 \u0627\u0644\u0645\u064f\u0642\u062f\u0651\u0631":"13 \u062f\u0642\u064a\u0642\u0629"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/elusivedata.io\/protobuf-varint-forensics\/#article","isPartOf":{"@id":"https:\/\/elusivedata.io\/protobuf-varint-forensics\/"},"author":{"name":"James Eichbaum","@id":"https:\/\/elusivedata.io\/#\/schema\/person\/2c00b8313d6aef321fd69bf82e2aa436"},"headline":"Protocol Buffers for Forensic Examiners: The Varint Trap","datePublished":"2026-03-25T13:30:15+00:00","dateModified":"2026-03-28T08:13:57+00:00","mainEntityOfPage":{"@id":"https:\/\/elusivedata.io\/protobuf-varint-forensics\/"},"wordCount":1456,"commentCount":0,"publisher":{"@id":"https:\/\/elusivedata.io\/#organization"},"image":{"@id":"https:\/\/elusivedata.io\/protobuf-varint-forensics\/#primaryimage"},"thumbnailUrl":"https:\/\/elusivedata.io\/wp-content\/uploads\/2026\/03\/Python_DB_compressed.jpg","articleSection":["SQLite"],"inLanguage":"ar","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/elusivedata.io\/protobuf-varint-forensics\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/elusivedata.io\/protobuf-varint-forensics\/","url":"https:\/\/elusivedata.io\/protobuf-varint-forensics\/","name":"Protocol Buffers for Forensic Examiners: The Varint Trap - Elusive Data","isPartOf":{"@id":"https:\/\/elusivedata.io\/#website"},"primaryImageOfPage":{"@id":"https:\/\/elusivedata.io\/protobuf-varint-forensics\/#primaryimage"},"image":{"@id":"https:\/\/elusivedata.io\/protobuf-varint-forensics\/#primaryimage"},"thumbnailUrl":"https:\/\/elusivedata.io\/wp-content\/uploads\/2026\/03\/Python_DB_compressed.jpg","datePublished":"2026-03-25T13:30:15+00:00","dateModified":"2026-03-28T08:13:57+00:00","description":"Protobuf varints are not SQLite varints. Learn to parse protobuf data from mobile forensic artifacts and decode LEB128 varints in Python.","breadcrumb":{"@id":"https:\/\/elusivedata.io\/protobuf-varint-forensics\/#breadcrumb"},"inLanguage":"ar","potentialAction":[{"@type":"ReadAction","target":["https:\/\/elusivedata.io\/protobuf-varint-forensics\/"]}]},{"@type":"ImageObject","inLanguage":"ar","@id":"https:\/\/elusivedata.io\/protobuf-varint-forensics\/#primaryimage","url":"https:\/\/elusivedata.io\/wp-content\/uploads\/2026\/03\/Python_DB_compressed.jpg","contentUrl":"https:\/\/elusivedata.io\/wp-content\/uploads\/2026\/03\/Python_DB_compressed.jpg","width":1814,"height":1080,"caption":"Protocol Buffers varint decoding in Python for digital forensics analysis"},{"@type":"BreadcrumbList","@id":"https:\/\/elusivedata.io\/protobuf-varint-forensics\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/elusivedata.io\/"},{"@type":"ListItem","position":2,"name":"Protocol Buffers for Forensic Examiners: The Varint Trap"}]},{"@type":"WebSite","@id":"https:\/\/elusivedata.io\/#website","url":"https:\/\/elusivedata.io\/","name":"\u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a \u0627\u0644\u0645\u0631\u0627\u0648\u063a\u0629","description":"\u0627\u0644\u062a\u0645\u064a\u0632 \u0641\u064a \u0627\u0644\u062a\u062f\u0631\u064a\u0628 \u0648\u0627\u0644\u0627\u0633\u062a\u0634\u0627\u0631\u0627\u062a \u0641\u064a \u0645\u062c\u0627\u0644 \u0627\u0644\u0623\u062f\u0644\u0629 \u0627\u0644\u062c\u0646\u0627\u0626\u064a\u0629 \u0627\u0644\u0631\u0642\u0645\u064a\u0629","publisher":{"@id":"https:\/\/elusivedata.io\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/elusivedata.io\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ar"},{"@type":"Organization","@id":"https:\/\/elusivedata.io\/#organization","name":"\u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a \u0627\u0644\u0645\u0631\u0627\u0648\u063a\u0629","url":"https:\/\/elusivedata.io\/","logo":{"@type":"ImageObject","inLanguage":"ar","@id":"https:\/\/elusivedata.io\/#\/schema\/logo\/image\/","url":"https:\/\/elusivedata.io\/wp-content\/uploads\/2024\/11\/Asset-3_2x-scaled.png","contentUrl":"https:\/\/elusivedata.io\/wp-content\/uploads\/2024\/11\/Asset-3_2x-scaled.png","width":2560,"height":370,"caption":"ElusiveData"},"image":{"@id":"https:\/\/elusivedata.io\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.youtube.com\/@elusivedata"]},{"@type":"Person","@id":"https:\/\/elusivedata.io\/#\/schema\/person\/2c00b8313d6aef321fd69bf82e2aa436","name":"\u062c\u064a\u0645\u0633 \u0625\u064a\u0634\u0628\u0648\u0645","image":{"@type":"ImageObject","inLanguage":"ar","@id":"https:\/\/elusivedata.io\/wp-content\/plugins\/ld-dashboard\/public\/img\/img_avatar.png","url":"https:\/\/elusivedata.io\/wp-content\/plugins\/ld-dashboard\/public\/img\/img_avatar.png","contentUrl":"https:\/\/elusivedata.io\/wp-content\/plugins\/ld-dashboard\/public\/img\/img_avatar.png","caption":"James Eichbaum"},"sameAs":["http:\/\/elusivedata.io"],"url":"https:\/\/elusivedata.io\/ar\/author\/eichbaumjamesgmail-com\/"}]}},"_links":{"self":[{"href":"https:\/\/elusivedata.io\/ar\/wp-json\/wp\/v2\/posts\/14969","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/elusivedata.io\/ar\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/elusivedata.io\/ar\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/elusivedata.io\/ar\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/elusivedata.io\/ar\/wp-json\/wp\/v2\/comments?post=14969"}],"version-history":[{"count":114,"href":"https:\/\/elusivedata.io\/ar\/wp-json\/wp\/v2\/posts\/14969\/revisions"}],"predecessor-version":[{"id":15131,"href":"https:\/\/elusivedata.io\/ar\/wp-json\/wp\/v2\/posts\/14969\/revisions\/15131"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/elusivedata.io\/ar\/wp-json\/wp\/v2\/media\/15137"}],"wp:attachment":[{"href":"https:\/\/elusivedata.io\/ar\/wp-json\/wp\/v2\/media?parent=14969"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/elusivedata.io\/ar\/wp-json\/wp\/v2\/categories?post=14969"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/elusivedata.io\/ar\/wp-json\/wp\/v2\/tags?post=14969"}],"curies":[{"name":"\u062f\u0628\u0644\u064a\u0648 \u0628\u064a","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}