gl2gb/public/posts/reverse-engineering-of-a-fl.../index.html

349 lines
29 KiB
HTML

<!DOCTYPE html>
<html lang="en"><head>
<title>GoatPr0n.farm</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="format-detection" content="telephone=no" />
<meta name="theme-color" content="#000084" />
<link rel="icon" href="https://goatpr0n.farm//favicon.ico">
<link rel="canonical" href="https://goatpr0n.farm/">
<link rel="stylesheet" href="/css/bootstrap.css">
<link rel="stylesheet" href="/css/bootstrap-responsive.css">
<link rel="stylesheet" href="/css/style.css">
</head><body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"></button>
<a class="brand" href="https://goatpr0n.farm/">GoatPr0n.farm</a>
<div class="nav-collapse collapse">
<ul class="nav">
<li>
<a href="/posts/">
<span>All posts</span>
</a>
</li>
</ul>
</div>
</div>
</div>
</nav><div id="content" class="container">
<div class="row-fluid navmargin">
<div class="page-header">
<h1>Reverse Engineering of a Flash Programmer :: EZP2010 - Thu, Nov 28, 2019</h1>
</div>
<p class="lead"></p>
<h2 id="preface">Preface</h2>
<p>In today&rsquo;s adventure I like to take you with me on my journey of reverse engineering <a href="https://goatpr0n.farm/?p=35">another</a> USB device. The EZP2010 is an USB programmer for flash memory as used by mainboard manufactures to store the BIOS, or embedded devices to store the firmware (or settings). When it comes to data recovery on hard drives, or similar storage devices, these flashers can also become handy.</p>
<p><img src="https://dl.goatpr0n.events/$/7KvdF" alt=""></p>
<p>EZP2010 USB-Highspeed programmer</p>
<p>This particular programmer can be bought on many Chinese store or Amazon. The prize range varies form $8 to $24. Unfortunately the software and drivers which come with this programmer are windows only.</p>
<p>The micro controller unit (<em>MCU</em>) used is the <a href="https://www.silabs.com/documents/public/data-sheets/C8051F34x.pdf">C8051F340</a>. It was easily identified by opening the enclosure and looking at the markings of the <em>MCU</em>.</p>
<h2 id="start-of-an-adventure">Start of an adventure</h2>
<p><img src="https://dl.goatpr0n.events/$/Ulrgo" alt=""></p>
<p>Realistic representation of me, being outside and enjoining it. But without the running and the joy. I also have shoes and longer trousers.</p>
<p>As already mentioned, this adventure will be about reversing the USB protocol of this programmer.</p>
<p>To start with analyzing the programmer a virtual machine would be an easy solution. And here I came across another problem this programmer has. It is not necessarily the fault of the hardware, but of the drivers and software provided to use it.</p>
<p>I worked on this project on different host machines and different versions of a virtual machine. The main difference was the architecture used. One VM was a 64bit Windows 10 and the other a 32bit Windows 10. Trying to run the software on a 32bit system failed, the software was unable to connect to the programmer, but I could not find any drawback in using a 64bit Windows.</p>
<h3 id="information-gathering">Information Gathering</h3>
<p><img src="https://dl.goatpr0n.events/$/4vfbw" alt=""></p>
<p>Me looking for information.</p>
<p>The most obvious things to do are <code>lsusb</code> and opening up the enclosure. <code>Lsusb</code> will output all connected USB devices connected on a Linux machine and get the description, as well as the vendor id and product id for device identification.</p>
<p>The output of <code>lsusb</code> gives information on how to talk to the device. With the product and vendor id the verbose output of <code>lsusb</code> can be limited to display only the device of interest. USB devices have separate input and output &ldquo;endpoints&rdquo;. On this particular device the endpoint to send our data to is <code>0x02 EP 2 OUT</code> and <code>0x81 EP 1 IN</code> where I can receive the responses and incoming data.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$ lsusb
<span style="color:#ae81ff">\[</span>...<span style="color:#ae81ff">\]</span>
Bus <span style="color:#ae81ff">003</span> Device 027: ID 10c4:f5a0 Cygnal Integrated Products, Inc.
<span style="color:#ae81ff">\[</span>...<span style="color:#ae81ff">\]</span>
$ lsusb -v -d 10c4:f5a0
Bus <span style="color:#ae81ff">003</span> Device 027: ID 10c4:f5a0 Cygnal Integrated Products, Inc.
Couldn<span style="color:#960050;background-color:#1e0010">&#39;</span>t open device, some information will be missing
Device Descriptor:
bLength <span style="color:#ae81ff">18</span>
bDescriptorType <span style="color:#ae81ff">1</span>
bcdUSB 2.00
bDeviceClass <span style="color:#ae81ff">0</span>
bDeviceSubClass <span style="color:#ae81ff">0</span>
bDeviceProtocol <span style="color:#ae81ff">0</span>
bMaxPacketSize0 <span style="color:#ae81ff">64</span>
** idVendor 0x10c4 Cygnal Integrated Products, Inc.
idProduct 0xf5a0**
bcdDevice 0.00
iManufacturer <span style="color:#ae81ff">0</span>
iProduct <span style="color:#ae81ff">0</span>
iSerial <span style="color:#ae81ff">0</span>
**bNumConfigurations 1**
Configuration Descriptor:
bLength <span style="color:#ae81ff">9</span>
bDescriptorType <span style="color:#ae81ff">2</span>
wTotalLength 0x0020
**bNumInterfaces 1**
bConfigurationValue <span style="color:#ae81ff">1</span>
**iConfiguration 0**
bmAttributes 0x80
<span style="color:#f92672">(</span>Bus Powered<span style="color:#f92672">)</span>
MaxPower 480mA
Interface Descriptor:
bLength <span style="color:#ae81ff">9</span>
bDescriptorType <span style="color:#ae81ff">4</span>
**bInterfaceNumber 0**
bAlternateSetting <span style="color:#ae81ff">0</span>
**bNumEndpoints 2**
bInterfaceClass <span style="color:#ae81ff">0</span>
bInterfaceSubClass <span style="color:#ae81ff">0</span>
bInterfaceProtocol <span style="color:#ae81ff">0</span>
**iInterface 0**
Endpoint Descriptor:
bLength <span style="color:#ae81ff">7</span>
bDescriptorType <span style="color:#ae81ff">5</span>
**bEndpointAddress 0x81 EP <span style="color:#ae81ff">1</span> IN**
bmAttributes <span style="color:#ae81ff">2</span>
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x <span style="color:#ae81ff">64</span> bytes
bInterval <span style="color:#ae81ff">5</span>
Endpoint Descriptor:
bLength <span style="color:#ae81ff">7</span>
bDescriptorType <span style="color:#ae81ff">5</span>
**bEndpointAddress 0x02 EP <span style="color:#ae81ff">2</span> OUT**
bmAttributes <span style="color:#ae81ff">2</span>
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x <span style="color:#ae81ff">64</span> bytes
bInterval <span style="color:#ae81ff">5</span>
</code></pre></div><p>In the beginning of this post, I already mentioned the used MCU for this programmer. It will not be of much of significance for this project but information is always nice to have. So the <em>C8051F340</em> by Silicon Labs can do different things, but the most important ones are Universal Serial Bus (USB) Controller and the Serial Peripheral Interface (SPI). The USB connection manages the communication between the host (PC) and the device. The SPI will manage the programming of the flash memory.</p>
<h3 id="vm-setup">VM Setup</h3>
<p>As previously told, I have used a 64bit Windows 10 virtual machine. For capturing the USB traffic I used <a href="https://wiki.wireshark.org/CaptureSetup/USB#Windows">Wireshark and USBPcap</a>. The workflow is the same as it is with network packet capturing. Instead of selecting a network interface, a USB root hub is selected where the device of interest is connected.</p>
<h3 id="packet-capturing">Packet Capturing</h3>
<p>At first I setup the packet capturing with Wireshark and select the USB root hub I want to monitor - and where I connect the programmer.</p>
<p>The next steps include a straight forward workflow, after Wireshark was configured and running. I started the programmer software. If Wireshark is configured correctly it reports the first packets captured during device initialization and opening the device by the software.</p>
<p>As there are not special device specific commands transferred during device and software initialization, these steps won&rsquo;t be necessary to cover here.</p>
<p>Now, if I press any button in the software to interact with the programmer, a corresponding reaction should be captured in Wireshark. To keep track which action resulted in which packets, Wireshark supports <em>comments</em> for their <em>pcapng</em> fileformat. When I press a button in the software, I comment the first packet captured and the last packet incoming.</p>
<p><img src="https://dl.goatpr0n.events/$/ijnRU" alt=""></p>
<p>Firmware version read from programmer device.</p>
<p>To keep it simple, I will illustrate this on the command to request the firmware version of the device. The button is labeled &ldquo;Ver&rdquo; in the toolbar. When clicked, two messages are transmitted between the host and the device which are captured by Wireshark.</p>
<p><img src="https://dl.goatpr0n.events/$/Pmke9" alt=""></p>
<p>Request and response packet content.</p>
<p>In the screen shot above, I commented the outgoing packet from the host to the programmer and labeled it &ldquo;Request firmware&rdquo;. The answer - which came immediately after the outgoing message. I labeled the packet as &ldquo;Request firmware: Answer&rdquo;. When I look into this dump a few days later, I will still be able to figure out what the cause of these packets were.</p>
<p>The firmware version request command are two bytes (<em>Leftover Capture Data</em> in the Wireshark window) <code>0x17 0x00</code>. The answer will be the version string <code>EZP2010 V3.0</code> and a few more bytes.</p>
<p>This way I worked through every function provided by the software to capture all possible commands. The &ldquo;Read&rdquo; and &ldquo;Prog&rdquo; ROM commands will produce a few more packets depending on the size of the flash chip. The outgoing or incoming packets either be the contents read from the flash chip or the data going to be written to the flash chip.</p>
<p>While capturing the packets should be almost enough, a look at the decompiled code of the program can help finding possible pitfalls.</p>
<h3 id="reversing-the-programmer-windows-software">Reversing the Programmer Windows Software</h3>
<p>This part was not really necessary, but helped in the process of packet analysis as well in matching the captured command packets with a function in the disassembled program.</p>
<p><img src="https://dl.goatpr0n.events/$/SeDcb" alt=""></p>
<p>Functions interacting with the programmer.</p>
<p>Each command supported by the programmer has a corresponding function. Matching all functions and command codes, I could see if I had found and captured all available commands the programmer hardware supports.</p>
<p>Refactoring the code generated by <a href="https://ghidra-sre.org/">Ghidra</a>, the result of reversing engineering a function could look like this. I am going through the code to request the firmware version.</p>
<p><img src="https://dl.goatpr0n.events/$/pKHQO" alt=""></p>
<p>Example of a reversed function to query the firmware version.</p>
<p>The code in the screenshot above sends two bytes to the programmer and than tries to read 23 (0x17) bytes as answer. The while loop at the bottom copies the contents of the <code>bufferIn</code> variable into the output argument variable <code>version</code>.</p>
<p>Just to clarify, the variables are pointers to a memory location at this point. the variable will store the address where the value (version string) is stored.</p>
<h3 id="writing-a-poc">Writing a POC</h3>
<p><img src="https://dl.goatpr0n.events/$/DQSgq" alt=""></p>
<p>Actual video of me coding a POC.</p>
<h4 id="python-poc">Python POC</h4>
<p>I often try to build my first proof of concept, or to validate my ideas, with a small Python program.</p>
<p>The code is based on the tutorial example provided by <a href="https://github.com/walac/pyusb/blob/master/docs/tutorial.rst">PyUSB</a>. I just added the other endpoint to read the responses from the programmer.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#75715e">#!/usr/bin/env python</span>
<span style="color:#f92672">import</span> usb.core
<span style="color:#f92672">import</span> usb.util
dev <span style="color:#f92672">=</span> usb<span style="color:#f92672">.</span>core<span style="color:#f92672">.</span>find(idVendor<span style="color:#f92672">=</span><span style="color:#ae81ff">0x10c4</span>, idProduct<span style="color:#f92672">=</span><span style="color:#ae81ff">0xf5a0</span>)
dev<span style="color:#f92672">.</span>set_configuration()
cfg <span style="color:#f92672">=</span> dev<span style="color:#f92672">.</span>get\_active\_configuration()
intf <span style="color:#f92672">=</span> cfg\[(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>)\]
epo <span style="color:#f92672">=</span> usb<span style="color:#f92672">.</span>util<span style="color:#f92672">.</span>find\_descriptor(intf, custom\_match<span style="color:#f92672">=</span><span style="color:#66d9ef">lambda</span> e:
usb<span style="color:#f92672">.</span>util<span style="color:#f92672">.</span>endpoint_direction(e<span style="color:#f92672">.</span>bEndpointAddress)
<span style="color:#f92672">==</span> usb<span style="color:#f92672">.</span>util<span style="color:#f92672">.</span>ENDPOINT_OUT)
epi <span style="color:#f92672">=</span> usb<span style="color:#f92672">.</span>util<span style="color:#f92672">.</span>find\_descriptor(intf, custom\_match<span style="color:#f92672">=</span><span style="color:#66d9ef">lambda</span> e:
usb<span style="color:#f92672">.</span>util<span style="color:#f92672">.</span>endpoint_direction(e<span style="color:#f92672">.</span>bEndpointAddress)
<span style="color:#f92672">==</span> usb<span style="color:#f92672">.</span>util<span style="color:#f92672">.</span>ENDPOINT_IN)
epo<span style="color:#f92672">.</span>write(\[<span style="color:#ae81ff">0x17</span>, <span style="color:#ae81ff">0x00</span>\])
s_buf <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;&#39;</span><span style="color:#f92672">.</span>join(\[chr(c) <span style="color:#66d9ef">for</span> c <span style="color:#f92672">in</span> epi<span style="color:#f92672">.</span>read(<span style="color:#ae81ff">256</span>)\])
<span style="color:#66d9ef">print</span>(s_buf)
</code></pre></div><p>Executing the test program will give something like &ldquo;<code>EZP2010 V3.0</code>&rdquo; and a few more additional bytes. Which should be expected, as the receiving buffer is defined with a size of 0x17 (23 bytes).</p>
<p>At the moment I have not looked into the remaining bytes and their purpose. The original software does not display any more information, but the version string.</p>
<h4 id="c-poc">C POC</h4>
<p>Doing it in C requires a bit more work. Below is the whole POC program source I have used to verify my work. The main part of the program is the USB device tree traversal to open and configure our target device. There is an easier to use function to do this with <a href="https://libusb.info/">libusb</a>.</p>
<p>But the function <a href="http://libusb.sourceforge.net/api-1.0/group__libusb__dev.html#ga11ba48adb896b1492bbd3d0bf7e0f665"><code>libusb_open_device_with_vid_pid()</code></a> gave me a bit of a trouble, as I was not able to configure the device properly to write and read data.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"> <span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;stdlib.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e"></span> <span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;stdio.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e"></span> <span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;unistd.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e"></span>
<span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;libusb-1.0/libusb.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e"></span>
<span style="color:#75715e">#define EZP2010_VID 0x10c4
</span><span style="color:#75715e"></span> <span style="color:#75715e">#define EZP2010_PID 0xf5a0
</span><span style="color:#75715e"></span>
<span style="color:#66d9ef">static</span> libusb_device_handle <span style="color:#f92672">*</span>devh <span style="color:#f92672">=</span> NULL;
libusb_device_handle <span style="color:#f92672">*</span><span style="color:#a6e22e">open_ezp2010</span>()
{
ssize_t devc;
libusb_device <span style="color:#f92672">**</span>dev_list;
<span style="color:#66d9ef">static</span> libusb_device <span style="color:#f92672">*</span>dev <span style="color:#f92672">=</span> NULL;
<span style="color:#66d9ef">struct</span> libusb_device_descriptor dev_desc;
<span style="color:#66d9ef">struct</span> libusb_config_descriptor <span style="color:#f92672">*</span>dev_cfg <span style="color:#f92672">=</span> NULL;
<span style="color:#66d9ef">const</span> <span style="color:#66d9ef">struct</span> libusb_interface <span style="color:#f92672">*</span>intf <span style="color:#f92672">=</span> NULL;
<span style="color:#66d9ef">const</span> <span style="color:#66d9ef">struct</span> libusb_interface_descriptor <span style="color:#f92672">*</span>intf_desc <span style="color:#f92672">=</span> NULL;
<span style="color:#66d9ef">int</span> r <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
devc <span style="color:#f92672">=</span> libusb_get_device_list(NULL, <span style="color:#f92672">&amp;</span>dev_list);
<span style="color:#66d9ef">if</span> (devc <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">1</span>)
<span style="color:#66d9ef">return</span> NULL;
<span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">int</span> i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; i <span style="color:#f92672">&lt;</span> devc; i<span style="color:#f92672">++</span>) {
dev <span style="color:#f92672">=</span> dev_list[i];
<span style="color:#66d9ef">if</span> (libusb_get_device_descriptor(dev, <span style="color:#f92672">&amp;</span>dev_desc))
<span style="color:#66d9ef">continue</span>;
<span style="color:#66d9ef">if</span> ((dev_desc.idVendor <span style="color:#f92672">!=</span> EZP2010_VID <span style="color:#f92672">||</span> dev_desc.idProduct <span style="color:#f92672">!=</span> EZP2010_PID))
<span style="color:#66d9ef">continue</span>;
r <span style="color:#f92672">=</span> libusb_open(dev, <span style="color:#f92672">&amp;</span>devh);
<span style="color:#66d9ef">if</span> (r <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0</span>) {
perror(<span style="color:#e6db74">&#34;libusb_open&#34;</span>);
<span style="color:#66d9ef">return</span> NULL;
}
<span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">int</span> j <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; j <span style="color:#f92672">&lt;</span> dev_desc.bNumConfigurations; j<span style="color:#f92672">++</span>) {
<span style="color:#66d9ef">if</span> (libusb_get_config_descriptor(dev, j, <span style="color:#f92672">&amp;</span>dev_cfg))
<span style="color:#66d9ef">continue</span>;
<span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">int</span> k <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; k <span style="color:#f92672">&lt;</span> dev_cfg<span style="color:#f92672">-&gt;</span>bNumInterfaces; k<span style="color:#f92672">++</span>) {
intf <span style="color:#f92672">=</span> <span style="color:#f92672">&amp;</span>dev_cfg<span style="color:#f92672">-&gt;</span>interface[k];
<span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">int</span> l <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; l <span style="color:#f92672">&lt;</span> intf<span style="color:#f92672">-&gt;</span>num_altsetting; l<span style="color:#f92672">++</span>) {
intf_desc <span style="color:#f92672">=</span> <span style="color:#f92672">&amp;</span>intf<span style="color:#f92672">-&gt;</span>altsetting[l];
<span style="color:#66d9ef">if</span> (libusb_kernel_driver_active(devh, intf_desc<span style="color:#f92672">-&gt;</span>bInterfaceNumber))
libusb_detach_kernel_driver(devh, intf_desc<span style="color:#f92672">-&gt;</span>bInterfaceNumber);
libusb_set_configuration(devh, dev_cfg<span style="color:#f92672">-&gt;</span>bConfigurationValue);
libusb_claim_interface(devh, intf_desc<span style="color:#f92672">-&gt;</span>bInterfaceNumber);
<span style="color:#66d9ef">int</span> e <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
<span style="color:#66d9ef">while</span> (libusb_claim_interface(devh, intf_desc<span style="color:#f92672">-&gt;</span>bInterfaceNumber) \
<span style="color:#f92672">&amp;&amp;</span> (e <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">10</span>)) {
sleep(<span style="color:#ae81ff">1</span>);
e<span style="color:#f92672">++</span>;
}
}
}
libusb_free_config_descriptor(dev_cfg);
}
<span style="color:#66d9ef">return</span> devh;
}
devh <span style="color:#f92672">=</span> NULL;
<span style="color:#66d9ef">return</span> NULL;
}
<span style="color:#66d9ef">int</span> <span style="color:#a6e22e">main</span>(<span style="color:#66d9ef">int</span> argc, <span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>argv[])
{
<span style="color:#66d9ef">int</span> r <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
<span style="color:#66d9ef">int</span> transferred <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
<span style="color:#66d9ef">unsigned</span> <span style="color:#66d9ef">char</span> buf[<span style="color:#ae81ff">256</span>];
r <span style="color:#f92672">=</span> libusb_init(NULL);
<span style="color:#66d9ef">if</span> (r <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0</span>)
<span style="color:#66d9ef">return</span> <span style="color:#ae81ff">1</span>;
open_ezp2010();
buf[<span style="color:#ae81ff">0</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;\x17&#39;</span>;
buf[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;\x0&#39;</span>;
r <span style="color:#f92672">=</span> libusb_bulk_transfer(devh, <span style="color:#ae81ff">0x2</span>, buf, <span style="color:#ae81ff">2</span>, <span style="color:#f92672">&amp;</span>transferred, <span style="color:#ae81ff">500</span>);
<span style="color:#66d9ef">if</span> (r <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0</span>) {
perror(<span style="color:#e6db74">&#34;libusb_claim_interface&#34;</span>);
fprintf(stderr, <span style="color:#e6db74">&#34;Error: %s</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, libusb_strerror(r));
}
printf(<span style="color:#e6db74">&#34;Bytes sent: %d</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, transferred);
r <span style="color:#f92672">=</span> libusb_bulk_transfer(devh, <span style="color:#ae81ff">0x81</span>, buf, <span style="color:#ae81ff">0x20</span>, <span style="color:#f92672">&amp;</span>transferred, <span style="color:#ae81ff">500</span>);
<span style="color:#66d9ef">if</span> (r <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0</span>) {
perror(<span style="color:#e6db74">&#34;libusb_claim_interface&#34;</span>);
fprintf(stderr, <span style="color:#e6db74">&#34;Error: %s</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, libusb_strerror(r));
}
printf(<span style="color:#e6db74">&#34;Bytes received: %d</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, transferred);
printf(<span style="color:#e6db74">&#34;Packet: %s</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, buf);
libusb_release_interface(devh, <span style="color:#ae81ff">0</span>);
libusb_reset_device(devh);
libusb_close(devh);
libusb_exit(NULL);
<span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>;
}
</code></pre></div><h3 id="future-work">Future Work</h3>
<p>My idea is to integrate it into existing programmer software, or to implement a small standalone tool for this programmer.</p>
<p>There is also still some research to do on the support for different flash chips. The original software provides a database with known and supported flash chips.</p>
<p>Looking at the code and figuring out the database structure might be the next step in further reverse engineering and developing further support for this programmer.</p>
<h4><a href="https://goatpr0n.farm/">Back to Home</a></h4>
</div>
</div><footer class="container">
<hr class="soften">
<p>
&copy;
Julian Knauer
<span id="thisyear">2020</span>
</p>
<p class="text-center">
</p>
</footer>
<script src="/js/jquery.js"></script>
<script src="/js/bootstrap-386.js"></script>
<script src="/js/bootstrap-transition.js"></script>
<script src="/js/bootstrap-alert.js"></script>
<script src="/js/bootstrap-modal.js"></script>
<script src="/js/bootstrap-dropdown.js"></script>
<script src="/js/bootstrap-scrollspy.js"></script>
<script src="/js/bootstrap-tab.js"></script>
<script src="/js/bootstrap-tooltip.js"></script>
<script src="/js/bootstrap-popover.js"></script>
<script src="/js/bootstrap-button.js"></script>
<script src="/js/bootstrap-collapse.js"></script>
<script src="/js/bootstrap-carousel.js"></script>
<script src="/js/bootstrap-typeahead.js"></script>
<script src="/js/bootstrap-affix.js"></script>
<script>
_386 = {
fastLoad: false ,
onePass: false ,
speedFactor: 1
};
function ThisYear() {
document.getElementById('thisyear').innerHTML = new Date().getFullYear();
};
</script></body>
</html>