Category Archives: Things

Playing with Perl :P

I always had problems in reading my RSS feeds because I never found any good RSS reader (Google things are not an option here). The fact is: I’m not able to read my friends – or enemies – feeds, but I’m a good email reader so I decided to search a way to send the feeds to my email so, I will be able to read them.

I found a nice toy to do that, it is called: rss2email. Really nice toy. I just placed it to run on my server and it started to deliver my content.

After one week using it, I saw that I didn’t subscribe any new feed. Imagine yourself logging in a server to add a new RSS feed… nah too complicated. Too much work for me.

So I decided to create a new mail alias to receive commands and process them by its procmail rules. Well ok, what about the security? And if that MTFK friend decide to clean up my entire feeds? That is why I decided to verify my gpg signature before process the commands and for that a combination of procmail rules and my cute Perl script is amazing.

Here goes my Perl script and enjoy:

#!/usr/bin/perl
#
# Copyright (C) 2009 Felipe Zimmerle by N. Costa
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#

# Config.
$ Config {'trusted'} = 'E8B11277';
$config{'debug'} = 1;
$config{'rss2email'} = '/your/path/to/rss2email/rss2email.py';
$config{'dat'} = '/your/path/to/rss2email/feeds.dat';
$config{'mailto'} = 'your@mail.something';
$config{'sendmail'} = '/usr/sbin/sendmail';
$config{'label'} = '/your/path/to/labels.txt';
$config{'mail'} =<<EOT;
To: $ config {'mailto'}
From: RMO Report <felipe-rss\@zimmerle.org>
Subject: rmo report

RMO Results:

RESULTS

EOT

# Do not edit above this line.
use IPC::Open3;
use IO::Handle;
use Encode;

undef $/;
my $mail = <>;
$mail =~ s/=(\n|\r|\n\r|\r\n)//gom;
$mail =~ s/=3D/=/gom;
$mail =~ s/=20/ /gom;

my ($ IN, $ OUT, $ ERR) = (IO :: Handle-> new (), IO :: Handle-> new (),
IO :: Handle-> new ());
open3 ($ IN, $ OUT, $ ERR "gpg") | | die "Unable to run: $ \ n";
print $IN $mail;
close($IN);

my $from,@cmd,$results,$pr,$ops;

# Parser the commands.
my $o = <$OUT>;
$o = ~ s / ^ add (\ "[A-z0-9_. -] + \" | [A-z0-9_. -] +) (. *) / @ {[Eval {$ pr + +; $ cmd [@ cmd] =
["add", "$2", "@{[eval {$a = $1; $a =~ s@^(\")(.*)(\"$)@$2@; $a;}]}"] }]}/gome;
$o = ~ s / ^ (the | delete) ([0-9] +) / @ {[eval {$ pr + +; $ cmd [@ cmd] = ["delete", "$ 2"] if $ pr 1 }]}/gome;
$o = ~ s / ^ list / @ {[$ cmd [@ cmd] = ["list"]]} / gome;
close($OUT);

# Check signature.
my $ e = <$ ERR>;
$from = $1 if $e =~ m/.*key ID ([A-z0-9]+)(\n|\r|\n\r|\r\n)gpg: Good signature from.*/m;
close($ERR);

die "Wow a hacker:\n$mail" if $from ne $config{'trusted'};

foreach my $c (@cmd) {
my $ config = $ c_ {'rss2email'}. "". $ Config {'dat'}.
" " . $c->[0] . " " . $c->[1];
$results .= "Command: $c_\n" . `$c_` . "\n";
`echo $c->[2],$c->[1] >> $config{'label'}` if $c->[0] eq "add";
}
$results .= "\nDelete request is just welcome if its come " .
" alone. $ops delete" .
"s"?"":$ops>1 . " ignored.\n" if ($ops > 0);

$config{'mail'} =~ s/RESULTS/$results/;

open (S, "| $ config {'sendmail'} t $ config {'mailto'}") or die "."
"Unable to run sendmail: $!\n";
print S $config{'mail'};
close(S);

I really love Perl. Amazing, just few lines and my problem was solved ;P

WUSB Cable Association

This document explains the Cable Association (cba) between a MS Windows host and a IOGear HUB [1] using the WiMedia application [2]. The logs analyzed here have been generated by a usb sniffer, usbsnoop [3]. This analysis was made to clarify the cable association specification. It’s the result of one day’s work by me and my friend Alex.

According to the specifications something like that should happens:

iogear association final

Our analysis is divided into blocks. Each block has a USB control message. They are:

ASSOCIATION INFORMATION

Our first usb_message_control is a request of information association [4].

[12 ms]  >>>  URB 5 going down  >>>
-- URB_FUNCTION_CLASS_INTERFACE:
  TransferFlags          = 00000001 (USBD_TRANSFER_DIRECTION_IN, ~USBD_SHORT_TRANSFER_OK)
  TransferBufferLength = 00000100
  TransferBuffer       = 897ffd48
  TransferBufferMDL    = 00000000
  UrbLink                 = 00000000
  RequestTypeReservedBits = 00000001
  Request                 = <span style="background: #ff5d5d; border: none; padding-left: 3px; padding-right: 3px;">00000001</span>
  Value                   = 00000000
  Index                   = 00000000
[12 ms] UsbSnoop - MyInternalIOCTLCompletion(bab39db0) : fido=00000000, Irp=896c8008, Context=897bd968, IRQL=2
[12 ms]  &lt;&lt;&lt;  URB 5 coming back  &lt;&lt;&lt;
-- URB_FUNCTION_CONTROL_TRANSFER:
  PipeHandle           = 89923990
  TransferFlags        = 0000000b (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
  TransferBufferLength = 00000019
  TransferBuffer       = 897ffd48
  TransferBufferMDL    = 8a37b4c0
00000000: 19 00 02 00 00 01 00 01 00 00 00 00 00 00 00 02

 

00000010: 00 01 00 01 00 6c 00 00 00

UrbLink = 00000000 SetupPacket = 00000000: a1 01 00 00 00 00 00 01

These colored bytes represent:

Request:
00000001 Represent a CBAF GET_ASSOCIATION_INFORMATION request
Response:
19 00 The full size of this structurre (including this two bytes), in this case 25 (0×19) bytes
02 Number of association requests, in this case: 2. See the arrays bellow
02 00 Fixed value for this kind of association
Association Requests Array:
First array element:
01 Index value. 01 in this case
00 Reserved byte…
01 00 Certified Wireless USB should have value: 0×1 in this field.
00 00 00 00 == RetriveHostInfo, in this case the host should send its CHID value to the device, should happend before the AssociateWUSB, as happend here.
00 00 00 00 Represent the size of the association type, zero in this case.
Last array element:
02 Index of the array, 02 in this case
00 Reserved byte…
01 00 Certified Wireless USB should have value: 0×1 in this field.
01 00 00 01 == AssociateWUSB, in this case the host will generate a response that contains the CC and return it to the device as the RetriveHostInfo it is mandatory in the association
6c 00 00 00 Association type info size, in this case 108 bytes.

In this block we have a GET_ASSICIATION_INFORMATION [4] request with an ASSOCIATION_INFORMATION [5] anwser. This ASSOCIATION_INFORMATION are composed by two ASSOCIATION_REQUEST [6], one is a RetriveHostInfo request and the another one is AssociateWUSB [7].

arrow-back-to-top Back to top

HOST INFORMATION

 

As a response of our first usb_message_control request, bellow is the host info.

[12 ms]  &gt;&gt;&gt;  URB 6 going down  &gt;&gt;&gt;
-- URB_FUNCTION_CLASS_INTERFACE:
  TransferFlags          = 00000000 (USBD_TRANSFER_DIRECTION_OUT, ~USBD_SHORT_TRANSFER_OK)
  TransferBufferLength = 00000054
  TransferBuffer       = 8a365268
  TransferBufferMDL    = 00000000
00000000: 00 00 02 00 01 00 01 00 02 00 00 00 00 10 10 00 00000010: 13 c7 31 42 52 44 30 30 32 30 30 30 c4 9a d5 70 00000020: 08 00 02 00 10 33 0c 00 2a 00 57 00 69 00 43 00 00000030: 65 00 6e 00 74 00 65 00 72 00 20 00 57 00 69 00 00000040: 72 00 65 00 6c 00 65 00 73 00 73 00 20 00 55 00 00000050: 53 00 42 00 UrbLink = 00000000 RequestTypeReservedBits = 00000001 Request = 00000003 Value = 00000101 Index = 00000000 [12 ms] UsbSnoop – MyInternalIOCTLCompletion(bab39db0) : fido=00000000, Irp=896c8008, Context=89b253a8, IRQL=2 [12 ms] <<< URB 6 coming back <<< — URB_FUNCTION_CONTROL_TRANSFER: PipeHandle = 89923990 TransferFlags = 0000000a (USBD_TRANSFER_DIRECTION_OUT, USBD_SHORT_TRANSFER_OK) TransferBufferLength = 00000054 TransferBuffer = 8a365268 TransferBufferMDL = 8a37b4c0 UrbLink = 00000000 SetupPacket = 00000000: 21 03 01 01 00 00 54 00

These colored bytes represent:

USB Control Message:
00000003 SET_ASSOCIATION_RESPONSE
00 00 02 00 01 00 Association type id as expected, this values are filled with the values of the last request. Attribute id: 0×0, Attribute length: 0×2 and data 0×1.
01 00 02 00 00 00 Association sub type id.
13 c7 31 42 52 44 30 30 32 30 30 30 c4 9a d5 70 CHID¹.
08 00 02 00 10 33 Lang ID, Unicode language id code used in the next field.
0c 00 2a 00 57 00 69 00 43 00 65 00 6e 00 74 00 65 00 72 00 20 00 57 00 69 00 72 00 65 00 6c 00 65 00 73 00 73 00 20 00 55 00 53 00 42 00 Host friendly name, in unicode form. In this case: “WiCenter Wireless USB” ( \x57\x69\x43\x65\x6e\x74\x65\x72\x20\x57\x69\x72\x65\x6c\x65\x73\x73\x20\x55\x53\x42 )

This is block is structured as a HOST_INFO [8]. Its request is SET_ASSOCIATION_RESPONSE.

arrow-back-to-top Back to top

ASSOCIATION REQUEST

 

As requested at the first data exchange, this is the information about the device:

[12 ms]  &gt;&gt;&gt;  URB 7 going down  &gt;&gt;&gt;
-- URB_FUNCTION_CLASS_INTERFACE:
  TransferFlags          = 00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
  TransferBufferLength = 0000002c
  TransferBuffer       = 8a4c50a8
  TransferBufferMDL    = 00000000
  UrbLink                 = 00000000
  RequestTypeReservedBits = 00000001
  Request                 = <span style="background: #ff5d5d; border: none; padding-left: 3px; padding-right: 3px;">00000002</span>
  Value                   = 00000200
  Index                   = 00000000
[13 ms] UsbSnoop - MyInternalIOCTLCompletion(bab39db0) : fido=00000000, Irp=896c8008, Context=8a3c0f58, IRQL=2
[13 ms]  &lt;&lt;&lt;  URB 7 coming back  &lt;&lt;&lt;
-- URB_FUNCTION_CONTROL_TRANSFER:
  PipeHandle           = 89923990
  TransferFlags        = 0000000b (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
  TransferBufferLength = 0000002c
  TransferBuffer       = 8a4c50a8
  TransferBufferMDL    = 8a37b4c0
    00000000: <span style="background: #FA8DFA; border: none; padding-left: 3px; padding-right: 3px;">02 00 04 00 6c 00 00 00</span> <span style="background: #93FF64; border: none; padding-left: 3px; padding-right: 3px;">01 10 10 00 2a 5e 70 14</span>
    00000010: <span style="background: #93FF64; border: none; padding-left: 3px; padding-right: 3px;">ab 74 ec 49 e1 59 15 03 ee f6 f9 6c </span> <span style="background: #FFCC00; border: none; padding-left: 3px; padding-right: 3px;">04 10 02 00</span>
    00000020: <span style="background: #FFCC00; border: none; padding-left: 3px; padding-right: 3px;">01 00</span> <span style="background: #FFD2A6; border: none; padding-left: 3px; padding-right: 3px;">08 00 02 00 09 04</span> <span style="background: #b3e4f4; border: none; padding-left: 3px; padding-right: 3px;">0b 00 40 00</span>
  UrbLink              = 00000000
  SetupPacket          =
    00000000: a1 02 00 02 00 00 2c 00

These colored bytes represent:

Request:
00000002 GET_ASSOCIATION_REQUEST
Response:
02 00 04 00 6c 00 00 00 Size of this structure. 0×2 represents the attribute type id and 0×4 represents the attribute length. 108 bytes in this case
01 10 10 00 2a 5e 70 14 ab 74 ec 49 e1 59 15 03 ee f6 f9 6c CDID
04 10 02 00 01 00 The last 4 bytes is the band group. See section 7.4.1 of WUSB specification
08 00 02 00 09 04 Language ID, used by the next field.
0b 00 40 00 Device friendly name, in unicode format.

This block contains the information about the device, it exchange information about the device id, supported band groups and device friendly name [9].

arrow-back-to-top Back to top

SECOND ASSOCIATION REQUEST

 

The same request as above but now the response is complete with the device friendly name.

[13 ms]  &gt;&gt;&gt;  URB 8 going down  &gt;&gt;&gt;
-- URB_FUNCTION_CLASS_INTERFACE:
  TransferFlags          = 00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
  TransferBufferLength = 0000006c
  TransferBuffer       = 89ae84c0
  TransferBufferMDL    = 00000000
  UrbLink                 = 00000000
  RequestTypeReservedBits = 00000001
  Request                 = <span style="background: #ff5d5d; border: none; padding-left: 3px; padding-right: 3px;">00000002</span>
  Value                   = 00000200
  Index                   = 00000000
[13 ms] UsbSnoop - MyInternalIOCTLCompletion(bab39db0) : fido=00000000, Irp=896c8008, Context=8a573930, IRQL=2
[13 ms]  &lt;&lt;&lt;  URB 8 coming back  &lt;&lt;&lt;
-- URB_FUNCTION_CONTROL_TRANSFER:
  PipeHandle           = 89923990
  TransferFlags        = 0000000b (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
  TransferBufferLength = 0000006c
  TransferBuffer       = 89ae84c0
  TransferBufferMDL    = 8a37b4c0
    00000000: <span style="background: #FA8DFA; border: none; padding-left: 3px; padding-right: 3px;">02 00 04 00 6c 00 00 00</span> <span style="background: #93FF64; border: none; padding-left: 3px; padding-right: 3px;">01 10 10 00 2a 5e 70 14</span>
    00000010: <span style="background: #93FF64; border: none; padding-left: 3px; padding-right: 3px;">ab 74 ec 49 e1 59 15 03 ee f6 f9 6c</span> <span style="background: #FFCC00; border: none; padding-left: 3px; padding-right: 3px;">04 10 02 00</span>
    00000020: <span style="background: #FFCC00; border: none; padding-left: 3px; padding-right: 3px;">01 00</span> <span style="background: #FFD2A6; border: none; padding-left: 3px; padding-right: 3px;">08 00 02 00 09 04</span> <span style="background: #b3e4f4; border: none; padding-left: 3px; padding-right: 3px;">0b 00 40 00 49 00 4f 00</span>
    00000030: <span style="background: #b3e4f4; border: none; padding-left: 3px; padding-right: 3px;">47 00 45 00 41 00 52 00 20 00 57 00 55 00 53 00</span>
    00000040: <span style="background: #b3e4f4; border: none; padding-left: 3px; padding-right: 3px;">42 00 20 00 48 00 75 00 62 00 00 00 00 00 00 00</span>
    00000050: <span style="background: #b3e4f4; border: none; padding-left: 3px; padding-right: 3px;">00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00</span>
    00000060: <span style="background: #b3e4f4; border: none; padding-left: 3px; padding-right: 3px;">00 00 00 00 00 00 00 00 00 00 00 00</span>
  UrbLink              = 00000000
  SetupPacket          =
    00000000: a1 02 00 02 00 00 6c 00

These colored bytes represent:

Request:
00000002 GET_ASSOCIATION_REQUEST
Response:
02 00 04 00 6c 00 00 00 Size of this structure. 108 bytes in this case
01 10 10 00 2a 5e 70 14 ab 74 ec 49 e1 59 15 03 ee f6 f9 6c CDID
04 10 02 00 01 00 Group band. See section 7.4.1 of WUSB specification.
08 00 02 00 09 04 Language ID, used by the next field.
0b 00 40 00 49 00 4f 00 47 00 45 00 41 00 52 00 20 00 57 00 55 00 53 00 42 00 20 00 48 00 75 00 62 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Device friendly name, in unicode format. In this case: “IOGEAR WUSB Hub” ( \x49\x4f\x47\x45\x41\x52\x20\x57\x55\x53\x42\x20\x48\x75\x62 )

Back to top

SETTING ASSOCIATION REQUEST

 

This block communicates the success of the cable association operation [10]. If the association is not succeded an AssociationStatus (Attr id: 0×4 and Attr length: 0×4) is expected with the reason. The reason should be one of the listed bellow:

  • 0×1, Association unsuccessful
  • 0×2, Malformated association request
  • 0×3, Association type not supported
[10589 ms]  &gt;&gt;&gt;  URB 9 going down  &gt;&gt;&gt;
-- URB_FUNCTION_CLASS_INTERFACE:
  TransferFlags          = 00000000 (USBD_TRANSFER_DIRECTION_OUT, ~USBD_SHORT_TRANSFER_OK)
  TransferBufferLength = 0000004e
  TransferBuffer       = 8a003530
  TransferBufferMDL    = 00000000
    00000000: <span style="background: #FA8DFA; border: none; padding-left: 3px; padding-right: 3px;">00 00 02 00 01 00</span> <span style="background: #93FF64; border: none; padding-left: 3px; padding-right: 3px;">01 00 02 00 01 00</span> <span style="background: #FFCC00; border: none; padding-left: 3px; padding-right: 3px;">02 00 04 00</span>
    00000010: <span style="background: #FFCC00; border: none; padding-left: 3px; padding-right: 3px;">4e 00 00 00</span> <span style="background: #FFD2A6; border: none; padding-left: 3px; padding-right: 3px;">02 10 30 00 13 c7 31 42 52 44 30 30</span>
    00000020: <span style="background: #FFD2A6; border: none; padding-left: 3px; padding-right: 3px;">32 30 30 30 c4 9a d5 70 2a 5e 70 14 ab 74 ec 49</span>
    00000030: <span style="background: #FFD2A6; border: none; padding-left: 3px; padding-right: 3px;">e1 59 15 03 ee f6 f9 6c d7 a6 f4 4c 6d 88 0f be</span>
    00000040: <span style="background: #FFD2A6; border: none; padding-left: 3px; padding-right: 3px;">b6 0c 25 ef 6f 24 a3 ed</span> <span style="background: #b3e4f4; border: none; padding-left: 3px; padding-right: 3px;">04 10 02 00 01 00</span>
  UrbLink                 = 00000000
  RequestTypeReservedBits = 00000001
  Request                 = <span style="background: #ff5d5d; border: none; padding-left: 3px; padding-right: 3px;">00000003</span>
  Value                   = 00000201
  Index                   = 00000000
[10623 ms] UsbSnoop - MyInternalIOCTLCompletion(bab39db0) : fido=00000000, Irp=896f0008, Context=896caa40, IRQL=2
[10623 ms]  &lt;&lt;&lt;  URB 9 coming back  &lt;&lt;&lt;
-- URB_FUNCTION_CONTROL_TRANSFER:
  PipeHandle           = 89923990
  TransferFlags        = 0000000a (USBD_TRANSFER_DIRECTION_OUT, USBD_SHORT_TRANSFER_OK)
  TransferBufferLength = 0000004e
  TransferBuffer       = 8a003530
  TransferBufferMDL    = 898aac20
  UrbLink              = 00000000
  SetupPacket          =
    00000000: 21 03 01 02 00 00 4e 00

These colored bytes represent:

Request:
00000003 SET_ASSOCIATION_REQUEST
Response:
00 00 02 00 01 00 Association Type ID
01 00 02 00 01 00 Association Sub Type ID
02 00 04 00 4e 00 00 00 Length of this data structure
02 10 30 00 13 c7 31 42 52 44 30 30 32 30 30 30 c4 9a d5 70 2a 5e 70 14 ab 74 ec 49 e1 59 15 03 ee f6 f9 6c d7 a6 f4 4c 6d 88 0f be b6 0c 25 ef 6f 24 a3 ed CC²
04 10 02 00 01 00 Band group

arrow-back-to-top Back to top


¹ CHID, Conection Host Identify
² CC, Connection Context

[1] http://www.iogear.com/product/GUWH104KIT/
[2] http://www.iogear.com/support/dm/driver/GUWH104KIT#display
[3] http://benoit.papillault.free.fr/usbsnoop/
[4] Association Models Supplement to the Certified Wireless Universal Serial Bus Specification
Revision 1.0 – Table 4-1
[5] Association Models Supplement to the Certified Wireless Universal Serial Bus Specification
Revision 1.0 – Table 4-3
[6] Association Models Supplement to the Certified Wireless Universal Serial Bus Specification
Revision 1.0 – Table 4-4
[7] Association Models Supplement to the Certified Wireless Universal Serial Bus Specification
Revision 1.0 – Table 4-5
[8] Association Models Supplement to the Certified Wireless Universal Serial Bus Specification
Revision 1.0 – Table 4-7
[9] Association Models Supplement to the Certified Wireless Universal Serial Bus Specification
Revision 1.0 – Table 4-8
[10] Association Models Supplement to the Certified Wireless Universal Serial Bus Specification
Revision 1.0 – Table 4-9
[11] Association Models Supplement to the Certified Wireless Universal Serial Bus Specification
Revision 1.0 – Table 4-10

 

Exchangeable image file format for Digital Still Cameras: Exif

After some google searches I concluded that doesn’t exist a python library that’s able me to manipulate some data in a JPEG Exif. I need this, cause I’m involved in a project called Syncropated, and this software wants to embed a thumbnail in JPEGs files. As you can see at Exif_2-1_V1.PDF, section 2.5.5 it’s possible.

But if I will code something to write this thumbnail, why do not put some code to parse data and something else?

Below you can read how the Exif works and in another post I will talk more about the Python Exif library that I’m coding.

First we want to know if the file is a JPEG or not, so we can simple check the two first bytes of the file. If the byte[0] equal then ‘FF’ and the second one is ‘D8′ (Figure 1, bnt_green) the file can be considered a JPEG candidate. To be a JPEG, it must follow others rules shown below. JPEG files that has Exif must have the word `Exif` in the header. To be more specific these words are supposed to start at the 6th byte of the file, forming a sequence like the green () one that you can see at Figure 1.

The 49 49 (Figure 1, ) represent the ordering of the data sequences, if its is Big-endian or Little-endian. Little-endian is represented by `II` (Intel format) and Big-endian is `MM` (Motorola format).


exif-khexedit

Figure 1. JPEG File raw bytes.

Other important thing to know about Exit is the organization of the data, Exif is divided in:

  • JPEG HEADER
  • 0th IFD
  • 0th IFD Values
  • 1st IFD
  • 1st IFD Values
  • 1st Thumbnail – Image Data
  • 0th (Primary) – Image Data

An IFD (Image File Directory) is used to store tags, with values and data types. IFDs works like a chained lists. The IF0 points to ID1 and so so…

All IFDs have the same structure, the first two bytes represent the number of tags in the directories and all tags in IFD is stored in the same way:

  • Tag (Bytes 0 – 1)
  • Type (Bytes 2 – 3)
  • Count (Bytes 4 – 7)
  • Value Offset (bytes 7 – 11)

If the value can be represented in 4 bytes or smaller, it will be saved in the offset space else the offset will point the data and the “x” IFD value will be used.
The pointer to the next IFD is represented at the final of the IFD block, before the IFD values block. If you get the numbers of tags (2 first bytes) and times 12 (where 12 is the size of an IFD tag) you will get the offset to the next IFD postion (represented by 4 bytes).

I have a particular interest in the thumbnail, so as you can see in the explanation above (Exif organization), I need to have an IFD0 and IFD1 to have a thumbnail. IFD1 have two special tags, that points me to the thumbnail. The first one is the JPEGInterchangeFormat (0×0201) and the other one is the JPEGInterchangeFormatLength (0×0202).

The JPEGInterchangeFormat value is an offset to the beginning of the thumbnail and the JPEGInterchangeFormatLength contains the thumbnail size. With this two informations we are able to get any thumbnail embeded in JPEG Exif files ;P