<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.2.0">Jekyll</generator><link href="https://0x44.cc/feed.xml" rel="self" type="application/atom+xml" /><link href="https://0x44.cc/" rel="alternate" type="text/html" /><updated>2026-03-01T00:36:48+00:00</updated><id>https://0x44.cc/feed.xml</id><title type="html">0x44.cc</title><subtitle>InfoSec, Reverse Engineering, and more (soon&amp;trade;)</subtitle><author><name>Sami ALAOUI KENDIL</name></author><entry><title type="html">Reverse engineering a car key fob signal (Part 1)</title><link href="https://0x44.cc/radio/2024/03/13/reversing-a-car-key-fob-signal.html" rel="alternate" type="text/html" title="Reverse engineering a car key fob signal (Part 1)" /><published>2024-03-13T00:00:00+00:00</published><updated>2024-03-13T00:00:00+00:00</updated><id>https://0x44.cc/radio/2024/03/13/reversing-a-car-key-fob-signal</id><content type="html" xml:base="https://0x44.cc/radio/2024/03/13/reversing-a-car-key-fob-signal.html">&lt;h3 id=&quot;context&quot;&gt;Context&lt;/h3&gt;

&lt;p&gt;I’ve had the curiosity to explore radio communication protocols for a few years now, ever since I’ve started fiddling around with an RTL-SDR dongle. I always had the goal of figuring out how data is transmitted in remote controls (car key fobs particularly), trying replay attacks, and other possible attack vectors.&lt;/p&gt;

&lt;p&gt;Despite capturing some car key fob signals over the years, I haven’t had the chance of doing meaningful analysis on them, and that’s mainly due to the limited access I had to cars I could test on.&lt;/p&gt;

&lt;p&gt;This blog post aims to bring the uninitiated through my journey of having successfully reverse engineered and replayed a car’s key fob signal last year, starting from the very basic concepts of radio frequency and going all the way through my entire thought process while I was working on this project.&lt;/p&gt;

&lt;p&gt;Another goal I guess is to also prove that most cars are definitely not that easy to steal using replay attacks (unless it’s a &lt;a href=&quot;https://rollingpwn.github.io/rolling-pwn/&quot;&gt;Honda&lt;/a&gt;, lol), despite Canada’s recent ban of the Flipper Zero, and them claiming the risk warrants the ban of a device made of very cheap and accessible wireless modules.&lt;/p&gt;

&lt;h3 id=&quot;hardware-used&quot;&gt;Hardware used&lt;/h3&gt;

&lt;h4 id=&quot;rtl-sdr&quot;&gt;RTL-SDR&lt;/h4&gt;

&lt;p&gt;I’ve had my first dive into the world of radio frequency back in 2016 when I learned that a very cheap (~$10) terrestrial TV/radio USB dongle can easily be turned into a multi-purpose RF receiver to inspect and decode pretty much anything happening in the range of 24 to 1750 MHz - this device is widely known as ‘RTL-SDR’:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/rtl-sdr.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The secret why this cheap device is very powerful, is the simple fact that it uses a chip which allows the use of &lt;a href=&quot;https://en.wikipedia.org/wiki/Software-defined_radio&quot;&gt;SDR (software defined radio)&lt;/a&gt;. It turns out that this chip (RTL2832U) allowed skipping the signal processing that usually happens on the hardware-level which converts the raw signal into ‘meaningful’ data to be used by the host device (a TV/radio feed in the case of this device).&lt;/p&gt;

&lt;p&gt;By having direct access to the raw I/Q data, we can receive, visualize and save pretty much any signal in raw format, without needing to know the specifics of the RF configuration used to transmit (modulation, bandwidth, data rate, etc.), since we can analyze/process the raw data ourselves. This effectively gives us a window to scan for virtually any activity on the radio spectrum under the 1.7 GHz frequency.&lt;/p&gt;

&lt;h4 id=&quot;flipper-zero&quot;&gt;Flipper Zero&lt;/h4&gt;

&lt;p&gt;The Flipper Zero is an electronic gadget which attracted a lot of attention lately for being a hacker/troll’s ultimate Swiss knife, since it hosts a bunch of wireless hardware modules that allow ‘interacting with’ everyday electronics and consumer appliances.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/flipper-zero.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The module that’s interesting to us in the Flipper is the Sub-GHz one, which is essentially a &lt;a href=&quot;https://www.ti.com/product/CC1101&quot;&gt;CC1101&lt;/a&gt; chip that supports frequencies that are typically used in wireless consumer devices, and that are under 1 GHz, hence the name of the module.&lt;/p&gt;

&lt;p&gt;It’s important to note, however, that one could just buy the CC1101 module separately ($5+) and make it work with an Arduino/Raspberry Pi or simply a USB-to-TTL adapter, but the Flipper is definitely cooler and more practical. ¯\_(ツ)_/¯&lt;/p&gt;

&lt;h4 id=&quot;cc1101-vs-rtl2832u&quot;&gt;CC1101 vs RTL2832U&lt;/h4&gt;

&lt;p&gt;The CC1101 chip in the Flipper Zero, unlike the RTL2832U chip that’s on the RTL-SDR, is actually a transceiver module (supports sending and receiving), which means the Flipper Zero is the device we’ll be using to send signals.&lt;/p&gt;

&lt;p&gt;However, the CC1101 chip doesn’t support SDR, which means that it would only send back data that it had completely processed. In other terms, the CC1101 will only be useful to us if we set the right RF configuration of the transmitted signal.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt; &lt;/th&gt;
      &lt;th&gt;Flipper Zero (CC1101)&lt;/th&gt;
      &lt;th&gt;RTL-SDR dongle (RTL2832U)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Receiving signals&lt;/td&gt;
      &lt;td&gt;✔️&lt;/td&gt;
      &lt;td&gt;✔️&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Sending signals&lt;/td&gt;
      &lt;td&gt;✔️&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Receiving/analyzing raw signals&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;✔️&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt; Transceiver SDR devices do exist of course, but they tend to be very pricey.&lt;/p&gt;

&lt;h3 id=&quot;radio-frequency-signal-basics-oversimplified&quot;&gt;Radio frequency signal basics (&lt;em&gt;oversimplified&lt;/em&gt;)&lt;/h3&gt;

&lt;p&gt;Now that we know a bit about the hardware we’ll be using, let’s go through some minimum basic concepts that are needed to tackle this subject.&lt;/p&gt;

&lt;h4 id=&quot;intro&quot;&gt;Intro&lt;/h4&gt;

&lt;p&gt;Radio frequency transmissions use radio waves, which are a type of electromagnetic radiation, in order to send signals.&lt;/p&gt;

&lt;p&gt;These waves are of a typically higher frequency than the original signal we’re transmitting and this is to ensure reliability in sending data, since signals can have varying characteristics that make sending them as radio waves impractical and susceptible to interference and weak travel distance.&lt;/p&gt;

&lt;p&gt;These waves are called carrier waves, since they are essentially modified to carry the original signal reliably through the air (more on this below).&lt;/p&gt;

&lt;p&gt;Let’s take a look at &lt;em&gt;some&lt;/em&gt; of the basic information needed to send/receive a radio signal:&lt;/p&gt;

&lt;h4 id=&quot;frequency&quot;&gt;Frequency&lt;/h4&gt;

&lt;p&gt;This one is self-explanatory, it’s the number of times a second a carrier wave occurs. Frequency affects the wavelength (the higher the frequency the shorter the waves). This parameter is also typically used to define the communication channel.&lt;/p&gt;

&lt;h4 id=&quot;modulation&quot;&gt;Modulation&lt;/h4&gt;

&lt;p&gt;This refers to the way a signal is represented in the radio waves. The two most common modulation types, which I’m sure most people already know of, are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AM&lt;/strong&gt; (&lt;em&gt;amplitude&lt;/em&gt; modulation) and &lt;strong&gt;FM&lt;/strong&gt; (&lt;em&gt;frequency&lt;/em&gt; modulation).&lt;/p&gt;

&lt;p&gt;The difference between these is simply the fact that for AM, the signal is modulated (encoded) in &lt;em&gt;amplitude&lt;/em&gt; (or strength), which roughly means that the &lt;em&gt;change&lt;/em&gt; in signal &lt;em&gt;strength&lt;/em&gt; on the carrier waves is how the data is represented.&lt;/p&gt;

&lt;p&gt;For FM, as one can guess, the data is rather modulated in &lt;em&gt;frequency&lt;/em&gt;. So, changes in the frequency of the waves are used here to determine the data.&lt;/p&gt;

&lt;p&gt;This is well visualized in this animation I found on Wikipedia (the ‘signal’ graph represents the data we’re trying to transmit):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/radio-fm-vs-am-anim.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Modulations can also have different subtypes and characteristics which we’ll talk about later on.&lt;/p&gt;

&lt;h4 id=&quot;bandwidth&quot;&gt;Bandwidth&lt;/h4&gt;

&lt;p&gt;This refers to the range of frequencies occupied by a modulated RF signal, or in other words, the difference between the highest and the lowest frequency a modulated signal can have. This essentially dictates the amount of data a signal can carry.&lt;/p&gt;

&lt;p&gt;Since the rest of the radio characteristics are not terribly important for us to know at this stage, let’s move on to the fun stuff!&lt;/p&gt;

&lt;h3 id=&quot;visual-analysis&quot;&gt;Visual analysis&lt;/h3&gt;

&lt;h4 id=&quot;sdr&quot;&gt;SDR#&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;https://airspy.com/download/&quot;&gt;SDR#&lt;/a&gt; is a free, intuitive, computer-based DSP (Digital Signal Processing) application for SDR written in C# with a focus on performance. It allows visualizing the radio spectrum in real time, and supports the demodulation of some common modulations. It also supports third-party plugins for custom modulations and integrations.&lt;/p&gt;

&lt;p&gt;We’ll be using this software for our signal discovery and initial analysis phase.&lt;/p&gt;

&lt;h4 id=&quot;signal-discovery&quot;&gt;Signal discovery&lt;/h4&gt;

&lt;p&gt;By tuning into the 433.92 MHz frequency with our RTL-SDR dongle plugged in (using the WinUSB driver instead of the stock DVB-T one), we can watch the activity of most remote controls in close proximity (433.92 MHz being the standard unregulated frequency in the EU and other neighboring countries, including Morocco, where I live).&lt;/p&gt;

&lt;p&gt;On each car key fob button press we instantly notice that there’s 3 successive short bursts generated, as can be seen on the waterfall view under the spectrum visualizer:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/sdrsharp-key-fob-433.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;small style=&quot;display: block; text-align: center;&quot;&gt;SDR# visualizing the key fob signal (X axis = frequency, Y axis = signal intensity)&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;We can also notice that the signal has two major ‘peaks’ on both sides of the 433.92 MHz frequency (the red line in the middle is the exact tuning frequency).&lt;/p&gt;

&lt;p&gt;Doing some research on common modulation schemes, we come across 2-FSK that sounds interesting:&lt;/p&gt;

&lt;h4 id=&quot;2-fsk&quot;&gt;2-FSK&lt;/h4&gt;

&lt;p&gt;FSK stands for Frequency-Shift Keying, which is a frequency modulation scheme in which data is encoded on a carrier signal by periodically shifting the frequency of the carrier between several discrete frequencies.&lt;/p&gt;

&lt;p&gt;Pretty straightforward so far, sounds like we’re dealing with FM here.&lt;/p&gt;

&lt;p&gt;The interesting part is the ‘2’ however, which here stands for the number of channels used in the encoding. So, we’re actually encoding binary data in two separate frequencies here, one for the &lt;strong&gt;0&lt;/strong&gt; and the other for the &lt;strong&gt;1&lt;/strong&gt;, which would explain the two peaks we’re noticing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt; One might wonder what the other smaller ‘peaks’ are in that screen capture - those are basically unwanted frequencies that are generated accidentally by the emitter chip, due to the cheap nature of the hardware, and due to the very close proximity of the remote and the antenna. So, it’s just a bunch of ‘noise’ that we can safely ignore.&lt;/p&gt;

&lt;h3 id=&quot;practical-analysis&quot;&gt;Practical analysis&lt;/h3&gt;

&lt;p&gt;Now that we checked what the signal looks like visually, let’s explore how we can work on analyzing it in order to read the bits from the RF waves in hopes to spot some sort of structure/consistency.&lt;/p&gt;

&lt;h4 id=&quot;universal-radio-hacker&quot;&gt;Universal Radio Hacker&lt;/h4&gt;

&lt;p&gt;As the README of its repository states, the &lt;a href=&quot;https://github.com/jopohl/urh&quot;&gt;Universal Radio Hacker (URH)&lt;/a&gt; is a complete open-source suite for wireless protocol investigation with native support for many common SDRs. URH allows easy demodulation of signals combined with an automatic detection of modulation parameters making it a breeze to identify the bits and bytes that fly over the air.&lt;/p&gt;

&lt;p&gt;This is precisely the software we need to decode radio waves into bits.&lt;/p&gt;

&lt;p&gt;As we open URH, we’re invited to either open a file or record directly from a device.&lt;/p&gt;

&lt;p&gt;Before recording, we have to select the source device, and set some basic radio parameters (I actually only made sure to put the right frequency and left everything else as default):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-record-dialog-rtlsdr.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After recording a signal, URH will try to autodetect the right configuration to use when decoding the radio waves.&lt;/p&gt;

&lt;p&gt;On my initial recordings, I wasn’t able to get URH to find the right parameters for me, which gave me wrong results. I have however later figured out that recording multiple repetitive signals in one go increases the chance that URH will figure out the right configuration, which turned out to be in my case: 50 samples/symbol, FSK.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-signal-interpretation.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Zooming in on one of the signals, we notice the 3 bursts we identified on SDR# (the second of which is made of 3 separate ones - so we have 5 sections to analyze now):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-signal-zoom-in.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For each of these sections, a bit sequence is automatically extracted, which we can also convert to hex for a better visualization:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-signal-zoom-in-hex.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We can already notice a lot of consistency and repeating patterns in the bytes, which is a sign that we’re on the right path.&lt;/p&gt;

&lt;p&gt;However, to my eyes, we’re still missing something here, because we notice the same 5 hex digits being repeated, with a lot of 0x55 bytes (01010101) also, which is pretty intriguing.&lt;/p&gt;

&lt;p&gt;Going over to the next tab labeled ‘Analysis’, we can see the bytes we’ve just extracted from each burst, each represented in a line, and there’s a decoding option that shows up with a bunch of curious algorithms:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-analysis-decoding-options.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;By brute forcing my way and trying them consecutively, I noticed that one of them (Manchester II) converted all the 0x55 bytes to null ones, and without producing any decoding errors:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-manchester-decoded.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;These bytes look more legit now.&lt;/p&gt;

&lt;h5 id=&quot;manchester-encoding&quot;&gt;Manchester encoding&lt;/h5&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Manchester_code&quot;&gt;Manchester&lt;/a&gt; is a very simple digital modulation scheme that ensures that the signal never remains at logic low or logic high for an extended period of time, and also converts the data signal into a data-plus-synchronization signal (for &lt;a href=&quot;https://en.wikipedia.org/wiki/Clock_recovery&quot;&gt;clock recovery&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;These characteristics are very useful when sending digital data over analog mediums that tend to be susceptible to noise and interference.&lt;/p&gt;

&lt;p&gt;In Manchester, binary data is encoded in two opposite bits, therefore:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;0&lt;/strong&gt; becomes &lt;strong&gt;01&lt;/strong&gt; and &lt;strong&gt;1&lt;/strong&gt; becomes &lt;strong&gt;10&lt;/strong&gt; (or the other way around, depending on the convention):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/manchester-visualization-wiki.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s go back and continue our investigation.&lt;/p&gt;

&lt;p&gt;By doing some manual examination and comparison of the different captures, we’re able to note that each button press generates a signal with the following characteristics:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A &lt;span style=&quot;color:yellow&quot;&gt;long burst&lt;/span&gt; with no data (decodes to 100 null bytes).&lt;/li&gt;
  &lt;li&gt;3 bursts which look very similar with only 2 bytes partially &lt;span style=&quot;color:red&quot;&gt;changing&lt;/span&gt;.&lt;/li&gt;
  &lt;li&gt;A &lt;span style=&quot;color:lightgreen&quot;&gt;final burst&lt;/span&gt; which is shorter but still looks fairly similar to the previous 3 bursts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-initial-signal-structure-highlight.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I decided to look more closely at the 3 bursts (let’s call them packets) in the middle since they seem to be the important part of the signal, and I was quickly able to spot what seems to be an &lt;span style=&quot;color:deepskyblue&quot;&gt;incremental ID&lt;/span&gt; which increases by 1 on each new signal:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-incremental-id-spotted.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To be able to move forward with our analysis, we must learn about a very important remote control security mechanism:&lt;/p&gt;

&lt;h4 id=&quot;rolling-codes&quot;&gt;Rolling codes&lt;/h4&gt;

&lt;p&gt;A rolling code is used in keyless entry systems to prevent a simple form of replay attack, where an eavesdropper records the transmission and replays it at a later time to cause the receiver to ‘unlock’. Such systems are typical in garage door openers and keyless car entry systems. More on &lt;a href=&quot;https://en.wikipedia.org/wiki/Rolling_code&quot;&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The gist of this system is that the key and the car both ‘agree’ on a cryptographically secure algorithm in order to generate rolling codes that are used to authenticate the remote.&lt;/p&gt;

&lt;p&gt;These keys are generated and tracked using a &lt;em&gt;counter&lt;/em&gt; which has to stay in sync between the remote and the car. This ensures that the car doesn’t reuse an old key, and that the remote always generates fresh keys.&lt;/p&gt;

&lt;p&gt;An example of a rolling code implementation is pictured below &lt;small&gt;(credits: &lt;a href=&quot;https://www.youtube.com/watch?v=8P_Wgl89jPU&quot;&gt;RuhrSec 2017&lt;/a&gt;)&lt;/small&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/rolling-code-explanation.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;uid&lt;/strong&gt;: ID of the car/remote link&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;enc&lt;sub&gt;k&lt;/sub&gt;&lt;/strong&gt;: Implementation of the rolling code algorithm&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ctr&lt;/strong&gt;: The car’s counter&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ctr’&lt;/strong&gt;: The remote’s counter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The validity window permits the remote to not go out of sync if the car doesn’t happen to receive the signal (typically with a max of 255 out-of-range button presses on most implementations, after which the remote has to be manually resynchronized).&lt;/p&gt;

&lt;p&gt;Alright, let’s go back to the drawing board.&lt;/p&gt;

&lt;p&gt;Since we now know that rolling codes are &lt;em&gt;cryptographically&lt;/em&gt; secure, it becomes easy for us to spot the &lt;span style=&quot;color:lightgreen&quot;&gt;part of the signal&lt;/span&gt; responsible for this implementation (which would be the one with the highest entropy):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-rolling-code-spotted.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We can also make the assumption that the &lt;span style=&quot;color:deepskyblue&quot;&gt;incremental ID&lt;/span&gt; we’ve identified earlier is the counter for the rolling code system. As it also conveniently sits right next to the code.&lt;/p&gt;

&lt;p&gt;By comparing lock and unlock signals, I was also able to quickly spot &lt;span style=&quot;color:plum&quot;&gt;the byte&lt;/span&gt; responsible for the command (8 = unlock, 4 = lock):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-command-byte-spotted.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now all that’s left for us to guess from the signal’s ‘variable parts’ are the two &lt;span style=&quot;color:red&quot;&gt;red changes&lt;/span&gt; we marked earlier:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1)&lt;/strong&gt; For the first one, we notice that the same values repeat themselves across the other captured signals.&lt;/p&gt;

&lt;p&gt;Converting the 3 values to binary, we notice the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;0x6: &lt;strong&gt;01&lt;/strong&gt;10&lt;/li&gt;
  &lt;li&gt;0xA: &lt;strong&gt;10&lt;/strong&gt;10&lt;/li&gt;
  &lt;li&gt;0xE: &lt;strong&gt;11&lt;/strong&gt;10&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Interesting, looks as if it’s packing some sort of sequence number for the packets.&lt;/p&gt;

&lt;p&gt;And what if we check the final (4th) packet as well?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;0x13: &lt;strong&gt;100&lt;/strong&gt;11&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yup, our theory seems to check out &lt;small&gt;(ignore the lowest bit that changed here)&lt;/small&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2)&lt;/strong&gt; Let’s guess the last byte now.&lt;/p&gt;

&lt;p&gt;We can notice that this one not only changes for each packet, but it does so completely across all signals as well.&lt;/p&gt;

&lt;p&gt;Seeing that this is the last byte on the packet and that it changes pretty randomly, leads me to suspect this being a checksum.&lt;/p&gt;

&lt;p&gt;One thing we can try doing is a XOR of this byte with the other byte we just analyzed, to see if we can end up with a static value (since pretty much &lt;em&gt;everything&lt;/em&gt; besides these two bytes actually stays &lt;em&gt;static&lt;/em&gt; when it comes to the 3 rolling code packets).&lt;/p&gt;

&lt;p&gt;Let’s try with these two examples:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-checksum-theory-test.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Example 1:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;0x06 ^ 0xB9 = &lt;strong&gt;0xBF&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;0x0A ^ 0xB5 = &lt;strong&gt;0xBF&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;0x0E ^ 0xB1 = &lt;strong&gt;0xBF&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example 2:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;0x06 ^ 0xCC = &lt;strong&gt;0xCA&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;0x0A ^ 0xC0 = &lt;strong&gt;0xCA&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;0x0E ^ 0xC4 = &lt;strong&gt;0xCA&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bingo. This is definitely a XOR checksum.&lt;/p&gt;

&lt;p&gt;By applying XOR on all the bytes of the packets, we notice that the value always ends up being off by 1:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-bad-checksum.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This leads us to conclude that the first 2 bytes of the packet are likely excluded from the checksum (which is where the 1 is coming from):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-synchronization-bytes.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And this actually makes sense, since these bytes would act here as a &lt;a href=&quot;https://en.wikipedia.org/wiki/Syncword&quot;&gt;syncword&lt;/a&gt; to synchronize the receiver and indicate the beginning of the data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you’re wondering about the utility of the initial &lt;span style=&quot;color:yellow&quot;&gt;long burst&lt;/span&gt; highlighted in yellow in the captures - that one serves to basically wake up the radio receiver and prepare it to start receiving data (since it goes in an idle low power state on inactivity). And if you’re also wondering why the remote sends 3 packets with roughly the same data, it’s simply to insure some sort of reliability. In case one of the packets gets corrupted on the way (which we saw happen on an earlier screenshot).&lt;/p&gt;

&lt;h4 id=&quot;final-result&quot;&gt;Final result&lt;/h4&gt;

&lt;p&gt;After labeling the rest of the bytes to my best guess, this is the result I ended up with:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/urh-final-labelization.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Neat. We’ve just reverse engineered a car key fob signal.&lt;/p&gt;

&lt;p&gt;Tune in next time when I (hopefully) write about how I integrated support for this signal format on the Flipper Zero in order to be able to read, re-serialize, and replay it.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you’ve noticed inaccurate information, or room for improvement regarding this article, and would like to improve it, feel free to &lt;a href=&quot;https://github.com/thedroidgeek/0x44.cc/edit/master/_posts/2024-03-13-reversing-a-car-key-fob-signal.md&quot;&gt;submit a pull request&lt;/a&gt; on GitHub.&lt;/p&gt;</content><author><name>Sami ALAOUI KENDIL</name></author><category term="radio" /><summary type="html">Context I’ve had the curiosity to explore radio communication protocols for a few years now, ever since I’ve started fiddling around with an RTL-SDR dongle. I always had the goal of figuring out how data is transmitted in remote controls (car key fobs particularly), trying replay attacks, and other possible attack vectors. Despite capturing some car key fob signals over the years, I haven’t had the chance of doing meaningful analysis on them, and that’s mainly due to the limited access I had to cars I could test on. This blog post aims to bring the uninitiated through my journey of having successfully reverse engineered and replayed a car’s key fob signal last year, starting from the very basic concepts of radio frequency and going all the way through my entire thought process while I was working on this project. Another goal I guess is to also prove that most cars are definitely not that easy to steal using replay attacks (unless it’s a Honda, lol), despite Canada’s recent ban of the Flipper Zero, and them claiming the risk warrants the ban of a device made of very cheap and accessible wireless modules. Hardware used RTL-SDR I’ve had my first dive into the world of radio frequency back in 2016 when I learned that a very cheap (~$10) terrestrial TV/radio USB dongle can easily be turned into a multi-purpose RF receiver to inspect and decode pretty much anything happening in the range of 24 to 1750 MHz - this device is widely known as ‘RTL-SDR’: The secret why this cheap device is very powerful, is the simple fact that it uses a chip which allows the use of SDR (software defined radio). It turns out that this chip (RTL2832U) allowed skipping the signal processing that usually happens on the hardware-level which converts the raw signal into ‘meaningful’ data to be used by the host device (a TV/radio feed in the case of this device). By having direct access to the raw I/Q data, we can receive, visualize and save pretty much any signal in raw format, without needing to know the specifics of the RF configuration used to transmit (modulation, bandwidth, data rate, etc.), since we can analyze/process the raw data ourselves. This effectively gives us a window to scan for virtually any activity on the radio spectrum under the 1.7 GHz frequency. Flipper Zero The Flipper Zero is an electronic gadget which attracted a lot of attention lately for being a hacker/troll’s ultimate Swiss knife, since it hosts a bunch of wireless hardware modules that allow ‘interacting with’ everyday electronics and consumer appliances. The module that’s interesting to us in the Flipper is the Sub-GHz one, which is essentially a CC1101 chip that supports frequencies that are typically used in wireless consumer devices, and that are under 1 GHz, hence the name of the module. It’s important to note, however, that one could just buy the CC1101 module separately ($5+) and make it work with an Arduino/Raspberry Pi or simply a USB-to-TTL adapter, but the Flipper is definitely cooler and more practical. ¯\_(ツ)_/¯ CC1101 vs RTL2832U The CC1101 chip in the Flipper Zero, unlike the RTL2832U chip that’s on the RTL-SDR, is actually a transceiver module (supports sending and receiving), which means the Flipper Zero is the device we’ll be using to send signals. However, the CC1101 chip doesn’t support SDR, which means that it would only send back data that it had completely processed. In other terms, the CC1101 will only be useful to us if we set the right RF configuration of the transmitted signal.   Flipper Zero (CC1101) RTL-SDR dongle (RTL2832U) Receiving signals ✔️ ✔️ Sending signals ✔️ ❌ Receiving/analyzing raw signals ❌ ✔️ Note: Transceiver SDR devices do exist of course, but they tend to be very pricey. Radio frequency signal basics (oversimplified) Now that we know a bit about the hardware we’ll be using, let’s go through some minimum basic concepts that are needed to tackle this subject. Intro Radio frequency transmissions use radio waves, which are a type of electromagnetic radiation, in order to send signals. These waves are of a typically higher frequency than the original signal we’re transmitting and this is to ensure reliability in sending data, since signals can have varying characteristics that make sending them as radio waves impractical and susceptible to interference and weak travel distance. These waves are called carrier waves, since they are essentially modified to carry the original signal reliably through the air (more on this below). Let’s take a look at some of the basic information needed to send/receive a radio signal: Frequency This one is self-explanatory, it’s the number of times a second a carrier wave occurs. Frequency affects the wavelength (the higher the frequency the shorter the waves). This parameter is also typically used to define the communication channel. Modulation This refers to the way a signal is represented in the radio waves. The two most common modulation types, which I’m sure most people already know of, are: AM (amplitude modulation) and FM (frequency modulation). The difference between these is simply the fact that for AM, the signal is modulated (encoded) in amplitude (or strength), which roughly means that the change in signal strength on the carrier waves is how the data is represented. For FM, as one can guess, the data is rather modulated in frequency. So, changes in the frequency of the waves are used here to determine the data. This is well visualized in this animation I found on Wikipedia (the ‘signal’ graph represents the data we’re trying to transmit): Modulations can also have different subtypes and characteristics which we’ll talk about later on. Bandwidth This refers to the range of frequencies occupied by a modulated RF signal, or in other words, the difference between the highest and the lowest frequency a modulated signal can have. This essentially dictates the amount of data a signal can carry. Since the rest of the radio characteristics are not terribly important for us to know at this stage, let’s move on to the fun stuff! Visual analysis SDR# SDR# is a free, intuitive, computer-based DSP (Digital Signal Processing) application for SDR written in C# with a focus on performance. It allows visualizing the radio spectrum in real time, and supports the demodulation of some common modulations. It also supports third-party plugins for custom modulations and integrations. We’ll be using this software for our signal discovery and initial analysis phase. Signal discovery By tuning into the 433.92 MHz frequency with our RTL-SDR dongle plugged in (using the WinUSB driver instead of the stock DVB-T one), we can watch the activity of most remote controls in close proximity (433.92 MHz being the standard unregulated frequency in the EU and other neighboring countries, including Morocco, where I live). On each car key fob button press we instantly notice that there’s 3 successive short bursts generated, as can be seen on the waterfall view under the spectrum visualizer: SDR# visualizing the key fob signal (X axis = frequency, Y axis = signal intensity) We can also notice that the signal has two major ‘peaks’ on both sides of the 433.92 MHz frequency (the red line in the middle is the exact tuning frequency). Doing some research on common modulation schemes, we come across 2-FSK that sounds interesting: 2-FSK FSK stands for Frequency-Shift Keying, which is a frequency modulation scheme in which data is encoded on a carrier signal by periodically shifting the frequency of the carrier between several discrete frequencies. Pretty straightforward so far, sounds like we’re dealing with FM here. The interesting part is the ‘2’ however, which here stands for the number of channels used in the encoding. So, we’re actually encoding binary data in two separate frequencies here, one for the 0 and the other for the 1, which would explain the two peaks we’re noticing. Note: One might wonder what the other smaller ‘peaks’ are in that screen capture - those are basically unwanted frequencies that are generated accidentally by the emitter chip, due to the cheap nature of the hardware, and due to the very close proximity of the remote and the antenna. So, it’s just a bunch of ‘noise’ that we can safely ignore. Practical analysis Now that we checked what the signal looks like visually, let’s explore how we can work on analyzing it in order to read the bits from the RF waves in hopes to spot some sort of structure/consistency. Universal Radio Hacker As the README of its repository states, the Universal Radio Hacker (URH) is a complete open-source suite for wireless protocol investigation with native support for many common SDRs. URH allows easy demodulation of signals combined with an automatic detection of modulation parameters making it a breeze to identify the bits and bytes that fly over the air. This is precisely the software we need to decode radio waves into bits. As we open URH, we’re invited to either open a file or record directly from a device. Before recording, we have to select the source device, and set some basic radio parameters (I actually only made sure to put the right frequency and left everything else as default): After recording a signal, URH will try to autodetect the right configuration to use when decoding the radio waves. On my initial recordings, I wasn’t able to get URH to find the right parameters for me, which gave me wrong results. I have however later figured out that recording multiple repetitive signals in one go increases the chance that URH will figure out the right configuration, which turned out to be in my case: 50 samples/symbol, FSK. Zooming in on one of the signals, we notice the 3 bursts we identified on SDR# (the second of which is made of 3 separate ones - so we have 5 sections to analyze now): For each of these sections, a bit sequence is automatically extracted, which we can also convert to hex for a better visualization: We can already notice a lot of consistency and repeating patterns in the bytes, which is a sign that we’re on the right path. However, to my eyes, we’re still missing something here, because we notice the same 5 hex digits being repeated, with a lot of 0x55 bytes (01010101) also, which is pretty intriguing. Going over to the next tab labeled ‘Analysis’, we can see the bytes we’ve just extracted from each burst, each represented in a line, and there’s a decoding option that shows up with a bunch of curious algorithms: By brute forcing my way and trying them consecutively, I noticed that one of them (Manchester II) converted all the 0x55 bytes to null ones, and without producing any decoding errors: These bytes look more legit now. Manchester encoding Manchester is a very simple digital modulation scheme that ensures that the signal never remains at logic low or logic high for an extended period of time, and also converts the data signal into a data-plus-synchronization signal (for clock recovery). These characteristics are very useful when sending digital data over analog mediums that tend to be susceptible to noise and interference. In Manchester, binary data is encoded in two opposite bits, therefore: 0 becomes 01 and 1 becomes 10 (or the other way around, depending on the convention): Let’s go back and continue our investigation. By doing some manual examination and comparison of the different captures, we’re able to note that each button press generates a signal with the following characteristics: A long burst with no data (decodes to 100 null bytes). 3 bursts which look very similar with only 2 bytes partially changing. A final burst which is shorter but still looks fairly similar to the previous 3 bursts. I decided to look more closely at the 3 bursts (let’s call them packets) in the middle since they seem to be the important part of the signal, and I was quickly able to spot what seems to be an incremental ID which increases by 1 on each new signal: To be able to move forward with our analysis, we must learn about a very important remote control security mechanism: Rolling codes A rolling code is used in keyless entry systems to prevent a simple form of replay attack, where an eavesdropper records the transmission and replays it at a later time to cause the receiver to ‘unlock’. Such systems are typical in garage door openers and keyless car entry systems. More on Wikipedia. The gist of this system is that the key and the car both ‘agree’ on a cryptographically secure algorithm in order to generate rolling codes that are used to authenticate the remote. These keys are generated and tracked using a counter which has to stay in sync between the remote and the car. This ensures that the car doesn’t reuse an old key, and that the remote always generates fresh keys. An example of a rolling code implementation is pictured below (credits: RuhrSec 2017): uid: ID of the car/remote link enck: Implementation of the rolling code algorithm ctr: The car’s counter ctr’: The remote’s counter The validity window permits the remote to not go out of sync if the car doesn’t happen to receive the signal (typically with a max of 255 out-of-range button presses on most implementations, after which the remote has to be manually resynchronized). Alright, let’s go back to the drawing board. Since we now know that rolling codes are cryptographically secure, it becomes easy for us to spot the part of the signal responsible for this implementation (which would be the one with the highest entropy): We can also make the assumption that the incremental ID we’ve identified earlier is the counter for the rolling code system. As it also conveniently sits right next to the code. By comparing lock and unlock signals, I was also able to quickly spot the byte responsible for the command (8 = unlock, 4 = lock): Now all that’s left for us to guess from the signal’s ‘variable parts’ are the two red changes we marked earlier: 1) For the first one, we notice that the same values repeat themselves across the other captured signals. Converting the 3 values to binary, we notice the following: 0x6: 0110 0xA: 1010 0xE: 1110 Interesting, looks as if it’s packing some sort of sequence number for the packets. And what if we check the final (4th) packet as well? 0x13: 10011 Yup, our theory seems to check out (ignore the lowest bit that changed here). 2) Let’s guess the last byte now. We can notice that this one not only changes for each packet, but it does so completely across all signals as well. Seeing that this is the last byte on the packet and that it changes pretty randomly, leads me to suspect this being a checksum. One thing we can try doing is a XOR of this byte with the other byte we just analyzed, to see if we can end up with a static value (since pretty much everything besides these two bytes actually stays static when it comes to the 3 rolling code packets). Let’s try with these two examples: Example 1: 0x06 ^ 0xB9 = 0xBF 0x0A ^ 0xB5 = 0xBF 0x0E ^ 0xB1 = 0xBF Example 2: 0x06 ^ 0xCC = 0xCA 0x0A ^ 0xC0 = 0xCA 0x0E ^ 0xC4 = 0xCA Bingo. This is definitely a XOR checksum. By applying XOR on all the bytes of the packets, we notice that the value always ends up being off by 1: This leads us to conclude that the first 2 bytes of the packet are likely excluded from the checksum (which is where the 1 is coming from): And this actually makes sense, since these bytes would act here as a syncword to synchronize the receiver and indicate the beginning of the data. Note: If you’re wondering about the utility of the initial long burst highlighted in yellow in the captures - that one serves to basically wake up the radio receiver and prepare it to start receiving data (since it goes in an idle low power state on inactivity). And if you’re also wondering why the remote sends 3 packets with roughly the same data, it’s simply to insure some sort of reliability. In case one of the packets gets corrupted on the way (which we saw happen on an earlier screenshot). Final result After labeling the rest of the bytes to my best guess, this is the result I ended up with: Neat. We’ve just reverse engineered a car key fob signal. Tune in next time when I (hopefully) write about how I integrated support for this signal format on the Flipper Zero in order to be able to read, re-serialize, and replay it. Thanks for reading! Note: If you’ve noticed inaccurate information, or room for improvement regarding this article, and would like to improve it, feel free to submit a pull request on GitHub.</summary></entry><entry><title type="html">Reversing for dummies - x86 assembly and C code (Beginner/ADHD friendly)</title><link href="https://0x44.cc/reversing/2021/07/21/reversing-x86-and-c-code-for-beginners.html" rel="alternate" type="text/html" title="Reversing for dummies - x86 assembly and C code (Beginner/ADHD friendly)" /><published>2021-07-21T00:00:00+00:00</published><updated>2021-07-21T00:00:00+00:00</updated><id>https://0x44.cc/reversing/2021/07/21/reversing-x86-and-c-code-for-beginners</id><content type="html" xml:base="https://0x44.cc/reversing/2021/07/21/reversing-x86-and-c-code-for-beginners.html">&lt;h3 id=&quot;context&quot;&gt;Context&lt;/h3&gt;

&lt;p&gt;Before I got into reverse engineering, executables always seemed like black magic to me. I always wondered how stuff worked under the hood, and how binary code is represented inside .exe files, and how hard it is to modify this ‘compiled code’ without access to the original source code.&lt;/p&gt;

&lt;p&gt;But one of the main intimidating hurdles always seemed to be the assembly language, it’s the thing that scares most people away from trying to learn about this field.&lt;/p&gt;

&lt;p&gt;That’s the main reason why I thought of writing this straight-to-the-point article that only contains the essential stuff that you encounter the most when reversing, albeit missing crucial details for the sake of brevity, and assumes the reader has a reflex of finding answers online, looking up definitions, and more importantly, coming up with examples/ideas/projects to practice on.&lt;/p&gt;

&lt;p&gt;The goal is to hopefully guide an aspiring reverse engineer and arouse motivation towards learning more about this seemingly elusive passion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note&lt;/em&gt;&lt;/strong&gt;: This article assumes the reader has elementary knowledge regarding the &lt;a href=&quot;https://en.wikipedia.org/wiki/Hexadecimal&quot;&gt;hexadecimal numeral system&lt;/a&gt;, as well as the &lt;a href=&quot;https://en.wikipedia.org/wiki/C_(programming_language)&quot;&gt;C programming language&lt;/a&gt;, and is based on a 32-bit Windows executable case study - results might differ across different OSes/architectures.&lt;/p&gt;

&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;

&lt;h4 id=&quot;compilation&quot;&gt;Compilation&lt;/h4&gt;

&lt;p&gt;After writing code using a &lt;a href=&quot;https://en.wikipedia.org/wiki/Compiled_language&quot;&gt;compiled language&lt;/a&gt;, a compilation takes place &lt;del&gt;(duh)&lt;/del&gt;, in order to generate the output binary file (an example of such is an .exe file).&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;img src=&quot;https://i.0x44.cc/b/compilation-c-to-exe-file.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;Compilers are sophisticated programs which do this task. They make sure the syntax of your &lt;del&gt;ugly&lt;/del&gt; code is correct, before compiling and optimizing the resulting machine code by minimizing its size and improving its performance, whenever applicable.&lt;/p&gt;

&lt;h4 id=&quot;binary-code&quot;&gt;Binary code&lt;/h4&gt;

&lt;p&gt;As we were saying, the resulting output file contains binary code, which can only be ‘understood’ by a CPU, it’s essentially a succession of varying-length instructions to be executed in order - here’s what some of them look like:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;CPU-readable instruction data (in hex)&lt;/th&gt;
      &lt;th&gt;Human-readable interpretation&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;55&lt;/td&gt;
      &lt;td&gt;push    ebp&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;8B EC&lt;/td&gt;
      &lt;td&gt;mov     ebp, esp&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;83 EC 08&lt;/td&gt;
      &lt;td&gt;sub     esp, 8&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;33 C5&lt;/td&gt;
      &lt;td&gt;xor     eax, ebp&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;83 7D 0C 01&lt;/td&gt;
      &lt;td&gt;cmp     dword ptr [ebp+0Ch], 1&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;These instructions are predominantly arithmetical, and they manipulate CPU registers/flags as well as volatile memory, as they’re executed.&lt;/p&gt;

&lt;h4 id=&quot;cpu-registers&quot;&gt;CPU registers&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Processor_register&quot;&gt;A CPU register&lt;/a&gt; is almost like a temporary integer variable - there’s a small fixed number of them, and they exist because they’re quick to access, unlike memory-based variables, and they help the CPU keep track of its data (results, operands, counts, etc.) during execution.&lt;/p&gt;

&lt;p&gt;It’s important to note the presence of a special register called the &lt;a href=&quot;https://en.wikipedia.org/wiki/FLAGS_register&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FLAGS&lt;/code&gt; register&lt;/a&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EFLAGS&lt;/code&gt; on 32-bit), which houses a bunch of flags (boolean indicators), which hold information about the state of the CPU, which include details about the last arithmetic operation (zero: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ZF&lt;/code&gt;, overflow: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OF&lt;/code&gt;, parity: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PF&lt;/code&gt;, sign: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SF&lt;/code&gt;, etc.).&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;img src=&quot;https://i.0x44.cc/b/x32dbg-cpu-registers.png&quot; /&gt;
  &lt;small&gt;CPU registers visualized while debugging a 32-bit process on x64dbg, a debugging tool.&lt;/small&gt;
&lt;/p&gt;

&lt;p&gt;Some of these registers can also be spotted on the assembly excerpt mentioned &lt;a href=&quot;#binary-code&quot;&gt;previously&lt;/a&gt;, namely: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EAX&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ESP&lt;/code&gt; (stack pointer) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EBP&lt;/code&gt; (base pointer).&lt;/p&gt;

&lt;h4 id=&quot;memory-access&quot;&gt;Memory access&lt;/h4&gt;

&lt;p&gt;As the CPU executes stuff, it needs to access and interact with memory, that’s when the role of the &lt;em&gt;stack&lt;/em&gt; and the &lt;em&gt;heap&lt;/em&gt; comes.&lt;/p&gt;

&lt;p&gt;These are (without getting into too much detail) the 2 main ways of ‘keeping track of variable data’ during the execution of a program:&lt;/p&gt;

&lt;h5 id=&quot;-stack&quot;&gt;🥞 &lt;em&gt;Stack&lt;/em&gt;&lt;/h5&gt;
&lt;p&gt;The simpler and faster of the two - it’s a linear contiguous LIFO (last in = first out) data structure with a push/pop mechanism, it serves to remember function-scoped variables, arguments, and keeps track of calls (ever heard of a &lt;a href=&quot;https://en.wikipedia.org/wiki/Stack_trace&quot;&gt;stack trace&lt;/a&gt;?)&lt;/p&gt;

&lt;h5 id=&quot;-heap&quot;&gt;⛰ &lt;em&gt;Heap&lt;/em&gt;&lt;/h5&gt;
&lt;p&gt;The heap, however, is pretty unordered, and is for more complicated data structures, it’s typically used for dynamic allocations, where the size of the buffer isn’t initially known, and/or if it’s too big, and/or needs to be modified later.&lt;/p&gt;

&lt;h3 id=&quot;assembly-instructions&quot;&gt;Assembly instructions&lt;/h3&gt;

&lt;p&gt;As I’ve mentioned earlier, assembly instructions have a varying ‘byte-size’, and a varying number of arguments.&lt;/p&gt;

&lt;p&gt;Arguments can also be either immediate (‘hardcoded’), or they can be registers, depending on the instruction:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;55         push    ebp     ; size: 1 byte,  argument: register
6A 01      push    1       ; size: 2 bytes, argument: immediate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s quickly run through a very small set of some of the common ones we’ll get to see - feel free to do your own research for more detail:&lt;/p&gt;

&lt;h4 id=&quot;stack-operations&quot;&gt;Stack operations&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;push &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt;&lt;/strong&gt; &lt;em&gt;; pushes a value into the stack (decrements &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ESP&lt;/code&gt; by 4, the size of one stack ‘unit’).&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;pop &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;register&lt;/code&gt;&lt;/strong&gt; &lt;em&gt;; pops a value to a register (increments &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ESP&lt;/code&gt; by 4).&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;data-transfer&quot;&gt;Data transfer&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;mov &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;destination&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;source&lt;/code&gt;&lt;/strong&gt; ; &lt;em&gt;&lt;del&gt;moves&lt;/del&gt; copies a value from/to a register.&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;mov &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;destination&lt;/code&gt;, [&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;expression&lt;/code&gt;]&lt;/strong&gt; ; &lt;em&gt;copies a value from a memory address resolved from a ‘register expression’ (single register or arithmetic expression involving one or more registers) into a register.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;flow-control&quot;&gt;Flow control&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;jmp &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;destination&lt;/code&gt;&lt;/strong&gt; ; &lt;em&gt;jumps into a code location (sets &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EIP&lt;/code&gt; (instruction pointer)).&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;jz/je &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;destination&lt;/code&gt;&lt;/strong&gt; ; &lt;em&gt;jumps into a code location if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ZF&lt;/code&gt; (the zero flag) is set.&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;jnz/jne &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;destination&lt;/code&gt;&lt;/strong&gt; ; &lt;em&gt;jumps into a code location if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ZF&lt;/code&gt; is not set.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;operations&quot;&gt;Operations&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;cmp &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operand1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operand2&lt;/code&gt;&lt;/strong&gt; ; &lt;em&gt;compares the 2 operands and sets &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ZF&lt;/code&gt; if they’re equal.&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operand1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operand2&lt;/code&gt;&lt;/strong&gt; ; &lt;em&gt;operand1 += operand2;&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;sub &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operand1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operand2&lt;/code&gt;&lt;/strong&gt; ; &lt;em&gt;operand1 -= operand2;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;function-transitions&quot;&gt;Function transitions&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;function&lt;/code&gt;&lt;/strong&gt; ; &lt;em&gt;calls a function (pushes current &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EIP&lt;/code&gt;, then jumps to the function).&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;retn&lt;/strong&gt; ; &lt;em&gt;returns to caller function (pops back the previous &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EIP&lt;/code&gt;).&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note&lt;/em&gt;&lt;/strong&gt;: You might notice the words ‘equal’ and ‘zero’ being used interchangeably in x86 terminology - that’s because comparison instructions internally perform a subtraction, which means if the 2 operands are equal, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ZF&lt;/code&gt; is set.&lt;/p&gt;

&lt;h3 id=&quot;assembly-patterns&quot;&gt;Assembly patterns&lt;/h3&gt;

&lt;p&gt;Now that we have a rough idea of the main elements used during the execution of a program, let’s get familiarized with the patterns of instructions that you can encounter reverse engineering your average everyday 32-bit &lt;a href=&quot;https://en.wikipedia.org/wiki/Portable_Executable&quot;&gt;PE&lt;/a&gt; binary.&lt;/p&gt;

&lt;h4 id=&quot;function-prologue&quot;&gt;Function prologue&lt;/h4&gt;

&lt;p&gt;A &lt;a href=&quot;https://en.wikipedia.org/wiki/Function_prologue&quot;&gt;function prologue&lt;/a&gt; is some initial code embedded in the beginning of most functions, it serves to set up a new stack frame for said function.&lt;/p&gt;

&lt;p&gt;It typically looks like this (X being a number):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;55          push    ebp        ; preserve caller function's base pointer in stack
8B EC       mov     ebp, esp   ; caller function's stack pointer becomes base pointer (new stack frame)
83 EC XX    sub     esp, X     ; adjust the stack pointer by X bytes to reserve space for local variables
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;function-epilogue&quot;&gt;Function epilogue&lt;/h4&gt;

&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Function_epilogue&quot;&gt;epilogue&lt;/a&gt; is simply the opposite of the prologue - it undoes its steps to restore the stack frame of the caller function, before it returns to it:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;8B E5    mov    esp, ebp    ; restore caller function's stack pointer (current base pointer) 
5D       pop    ebp         ; restore base pointer from the stack
C3       retn               ; return to caller function
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now at this point, you might be wondering - how do functions talk to each other? How exactly do you send/access arguments when calling a function, and how do you receive the return value? That’s precisely why we have calling conventions.&lt;/p&gt;

&lt;h4 id=&quot;calling-conventions-__cdecl&quot;&gt;Calling conventions: __cdecl&lt;/h4&gt;

&lt;p&gt;A &lt;a href=&quot;https://en.wikipedia.org/wiki/Calling_convention&quot;&gt;calling convention&lt;/a&gt; is basically a protocol used to communicate with functions, there’s a few variations of them, but they share the same principle.&lt;/p&gt;

&lt;p&gt;We will be looking at the &lt;a href=&quot;https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl&quot;&gt;__cdecl (C declaration) convention&lt;/a&gt;, which is the standard one when compiling C code.&lt;/p&gt;

&lt;p&gt;In __cdecl (32-bit), function arguments are passed on the stack (pushed in reverse order), while the return value is returned in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EAX&lt;/code&gt; register (assuming it’s not a float).&lt;/p&gt;

&lt;p&gt;This means that a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;func(1, 2, 3);&lt;/code&gt; call will generate the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;6A 03             push    3
6A 02             push    2
6A 01             push    1
E8 XX XX XX XX    call    func
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;putting-everything-together&quot;&gt;Putting everything together&lt;/h4&gt;

&lt;p&gt;Assuming &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;func()&lt;/code&gt; simply does an addition on the arguments and returns the result, it would probably look like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;int __cdecl func(int, int, int):

           prologue:
55           push    ebp               ; save base pointer
8B EC        mov     ebp, esp          ; new stack frame

           body:
8B 45 08     mov     eax, [ebp+8]      ; load first argument to EAX (return value)
03 45 0C     add     eax, [ebp+0Ch]    ; add 2nd argument
03 45 10     add     eax, [ebp+10h]    ; add 3rd argument

           epilogue:
5D           pop     ebp               ; restore base pointer
C3           retn                      ; return to caller
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now if you’ve been paying attention and you’re still confused, you might be asking yourself one of these 2 questions:&lt;/p&gt;

&lt;p&gt;1) Why do we have to adjust &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EBP&lt;/code&gt; by 8 to get to the first argument?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If you &lt;a href=&quot;#assembly-instructions&quot;&gt;check the definition&lt;/a&gt; of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt; instruction we mentioned earlier, you’ll realize that, internally, it actually pushes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EIP&lt;/code&gt; to the stack. And if you also check the definition for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;push&lt;/code&gt;, you’ll realize that it decrements &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ESP&lt;/code&gt; (which is copied to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EBP&lt;/code&gt; after the prologue) by 4 bytes. In addition, the prologue’s first instruction is also a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;push&lt;/code&gt;, so we end up with 2 decrements of 4, hence the need to add 8.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2) What happened to the prologue and epilogue, why are they seemingly ‘truncated’?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It’s simply because we haven’t had a use for the stack during the execution of our function - if you’ve noticed, we haven’t modified &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ESP&lt;/code&gt; at all, which means we also don’t need to restore it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;if-conditions&quot;&gt;If conditions&lt;/h4&gt;

&lt;p&gt;To demo the flow control assembly instructions, I’d like to add one more example to show how an if condition was compiled to assembly.&lt;/p&gt;

&lt;p&gt;Assume we have the following function:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;print_equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;equal&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nah&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After compiling it, here’s the disassembly that I got with the help of &lt;a href=&quot;https://hex-rays.com/ida-pro/&quot;&gt;IDA&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;void __cdecl print_equal(int, int):

     10000000   55                push   ebp
     10000001   8B EC             mov    ebp, esp
     10000003   8B 45 08          mov    eax, [ebp+8]       ; load 1st argument
     10000006   3B 45 0C          cmp    eax, [ebp+0Ch]     ; compare it with 2nd
  ┌┅ 10000009   75 0F             jnz    short loc_1000001A ; jump if not equal
  ┊  1000000B   68 94 67 00 10    push   offset aEqual  ; &quot;equal&quot;
  ┊  10000010   E8 DB F8 FF FF    call   _printf
  ┊  10000015   83 C4 04          add    esp, 4
┌─┊─ 10000018   EB 0D             jmp    short loc_10000027
│ ┊
│ └ loc_1000001A:
│    1000001A   68 9C 67 00 10    push   offset aNah    ; &quot;nah&quot;
│    1000001F   E8 CC F8 FF FF    call   _printf
│    10000024   83 C4 04          add    esp, 4
│
└── loc_10000027:
     10000027   5D                pop    ebp
     10000028   C3                retn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Give yourself a minute and try to make sense of this disassembly output (for simplicity’s sake, I’ve changed the real addresses and made the function start from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10000000&lt;/code&gt; instead).&lt;/p&gt;

&lt;p&gt;In case you’re wondering about the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add esp, 4&lt;/code&gt; part, it’s simply there to adjust &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ESP&lt;/code&gt; back to its initial value (same effect as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pop&lt;/code&gt;, except without modifying any register), since we had to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;push&lt;/code&gt; the printf string argument.&lt;/p&gt;

&lt;h3 id=&quot;basic-data-structures&quot;&gt;Basic data structures&lt;/h3&gt;

&lt;p&gt;Now let’s move on and talk about how data is stored (integers and strings especially).&lt;/p&gt;

&lt;h4 id=&quot;endianness&quot;&gt;Endianness&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Endianness&quot;&gt;Endianness&lt;/a&gt; is the order of the sequence of bytes representing a value in computer memory.&lt;/p&gt;

&lt;p&gt;There’s 2 types - big-endian and little-endian:&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;img src=&quot;https://i.0x44.cc/b/big-endian-dark.svg&quot; alt=&quot;&quot; /&gt;&lt;/td&gt;
      &lt;td&gt;&lt;img src=&quot;https://i.0x44.cc/b/little-endian-dark.svg&quot; alt=&quot;&quot; /&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;For reference, x86 family processors (the ones on pretty much any computer you can find) always use little-endian.&lt;/p&gt;

&lt;p&gt;To give you a live example of this concept, I’ve compiled a Visual Studio C++ console app, where I declared an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt; variable with the value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1337&lt;/code&gt; assigned to it, then I printed the variable’s address using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;printf()&lt;/code&gt;, on the main function.&lt;/p&gt;

&lt;p&gt;Then I ran the program attached to the debugger in order to check the printed variable’s address on the memory hex view, and here’s the result I obtained:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/vs-debug-memory-view.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To elaborate more on this - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt; variables are 4 bytes long (32 bits) (in case you didn’t know), so this means that if the variable starts from the address &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D2FCB8&lt;/code&gt; it would end right before &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D2FCBC&lt;/code&gt; (+4).&lt;/p&gt;

&lt;p&gt;To go from human readable value to memory bytes, follow these steps:&lt;/p&gt;

&lt;p&gt;decimal: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1337&lt;/code&gt; -&amp;gt; hex: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;539&lt;/code&gt; -&amp;gt; bytes: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;00 00 05 39&lt;/code&gt; -&amp;gt; little-endian: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;39 05 00 00&lt;/code&gt;&lt;/p&gt;

&lt;h4 id=&quot;signed-integers&quot;&gt;Signed integers&lt;/h4&gt;

&lt;p&gt;This part is interesting yet relatively simple. What you should know here is that integer signing (positive/negative) is typically done on computers with the help of a concept called &lt;a href=&quot;https://en.wikipedia.org/wiki/Signed_number_representations#Two's_complement&quot;&gt;two’s complement&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The gist of it is that the lowest/first half of an integer is reserved for positive numbers, while the highest/last half is for negative numbers, here’s what this looks like in hex, for a 32-bit signed int (highlighted = hex, in parenthesis = decimal):&lt;/p&gt;

&lt;p&gt;Positives (1/2): &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;00000000&lt;/code&gt; (0) -&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;7FFFFFFF&lt;/code&gt; (2,147,483,647 or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INT_MAX&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;Negatives (2/2): &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;80000000&lt;/code&gt; (-2,147,483,648 or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INT_MIN&lt;/code&gt;) -&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FFFFFFFF&lt;/code&gt; (-1)&lt;/p&gt;

&lt;p&gt;If you’ve noticed, we’re always &lt;em&gt;ascending&lt;/em&gt; in value. Whether we go up in hex or decimal. And that’s the crucial point of this concept - arithmetical operation do not have to do anything special to handle signing, they can simply treat all values as unsigned/positive, and the result would still be interpreted correctly (as long as we don’t go beyond &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INT_MAX&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INT_MIN&lt;/code&gt;), and that’s because integers will also &lt;em&gt;‘rollover’&lt;/em&gt; on overflow/underflow by design, kinda like an analog odometer.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;img src=&quot;https://i.0x44.cc/b/odometer-rollover.jpg&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Protip&lt;/em&gt;&lt;/strong&gt;: The Windows calculator is a very helpful tool - you can set it to programmer mode and set the size to DWORD (4 bytes), then enter negative decimal values and visualize them in hex and binary, and have fun performing operations on them.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/calcexe-int-signing.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;strings&quot;&gt;Strings&lt;/h4&gt;

&lt;p&gt;In C, strings are stored as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;char&lt;/code&gt; arrays, therefore, there’s nothing special to note here, except for something called null termination.&lt;/p&gt;

&lt;p&gt;If you ever wondered how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strlen()&lt;/code&gt; is able to know the size of a string, it’s very simple - strings have a character that indicates their end, and that’s the null byte/character - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;00&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'\0'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you declare a string constant in C code, and hover over it in Visual Studio, for instance, it will tell you the size of the generated array, and as you can see, for this reason, it’s one element more than the ‘visible’ string size.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/vs-null-termination.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note&lt;/em&gt;&lt;/strong&gt;: The endianness concept is not applicable on arrays, only on single variables. Therefore, the order of characters in memory would be normal here - low to high.&lt;/p&gt;

&lt;h3 id=&quot;making-sense-of-call-and-jmp-instructions&quot;&gt;Making sense of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jmp&lt;/code&gt; instructions&lt;/h3&gt;

&lt;p&gt;Now that you know all of this, you’re likely able to start making sense of some machine code, and emulate a CPU with your brain, to some extent, so to speak.&lt;/p&gt;

&lt;p&gt;Let’s take the &lt;a href=&quot;#if-conditions&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;print_equal()&lt;/code&gt; example&lt;/a&gt;, but let’s only focus on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;printf()&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt; instructions this time.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;void print_equal(int, int):
...
     10000010   E8 DB F8 FF FF    call   _printf
...
     1000001F   E8 CC F8 FF FF    call   _printf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You might be wondering to yourself - wait a second, if these are the same instructions, then why are their bytes different?&lt;/p&gt;

&lt;p&gt;That’s because, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt; (and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jmp&lt;/code&gt;) instructions (usually) take an &lt;em&gt;offset&lt;/em&gt; (relative address) as an argument, not an absolute address.&lt;/p&gt;

&lt;p&gt;An offset is basically the difference between the current location, and the destination, which also means that it can be either negative or positive.&lt;/p&gt;

&lt;p&gt;As you can see, the &lt;a href=&quot;https://en.wikipedia.org/wiki/Opcode&quot;&gt;opcode&lt;/a&gt; of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt; instruction that takes a 32-bit offset, is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E8&lt;/code&gt;, and is followed by said offset - which makes the full instruction: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E8 XX XX XX XX&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Pull out your calculator, &lt;del&gt;why’d you close it so early?!&lt;/del&gt; and calculate the difference between the offset of both instructions (don’t forget the endianness).&lt;/p&gt;

&lt;p&gt;You’ll notice that (the absolute value of) this difference is the same as the one between the instruction addresses (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1000001F&lt;/code&gt; - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10000010&lt;/code&gt; = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;F&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/calcexe-call-inst-diff.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Another small detail that we should add, is the fact that the CPU only executes an instruction after fully ‘reading’ it, which means that by the time the CPU starts ‘executing’, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EIP&lt;/code&gt; (the instruction pointer) is already pointing at the &lt;em&gt;next&lt;/em&gt; instruction to be executed.&lt;/p&gt;

&lt;p&gt;That’s why these offsets are actually accounting for this behaviour, which means that in order to get the &lt;em&gt;real&lt;/em&gt; address of the target function, we have to also &lt;em&gt;add&lt;/em&gt; the size of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt; instruction: 5.&lt;/p&gt;

&lt;p&gt;Now let’s apply all these steps in order to resolve &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;printf()&lt;/code&gt;’s address from the first instruction on the example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;10000010   E8 DB F8 FF FF    call   _printf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;1) Extract the offset from the instruction: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E8 (DB F8 FF FF)&lt;/code&gt; -&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FFFFF8DB&lt;/code&gt; (-1829)&lt;/p&gt;

&lt;p&gt;2) Add it to the instruction address: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10000010&lt;/code&gt; + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FFFFF8DB&lt;/code&gt; = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0FFFF8EB&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;3) And finally, add the instruction size: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0FFFF8EB&lt;/code&gt; + 5 = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0FFFF8F0&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;printf&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;The exact same principle applies to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jmp&lt;/code&gt; instruction:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
┌─── 10000018   EB 0D             jmp    short loc_10000027
...
└── loc_10000027:
     10000027   5D                pop    ebp
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The only difference in this example is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EB XX&lt;/code&gt; is a short version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jmp&lt;/code&gt; instruction - which means it only takes an 8-bit (1 byte) offset.&lt;/p&gt;

&lt;p&gt;Therefore: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10000018&lt;/code&gt; + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0D&lt;/code&gt; + 2 = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10000027&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;That’s it! You should now have enough information (and hopefully, motivation) to start your journey reverse engineering executables.&lt;/p&gt;

&lt;p&gt;Start by writing dummy C code, compiling it, and debugging it while single-stepping through the disassembly instructions (Visual Studio allows you to do this, by the way).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://godbolt.org/&quot;&gt;Compiler Explorer&lt;/a&gt; is also an extremely helpful website which compiles C code to assembly for you in real time using multiple compilers (select the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x86 msvc&lt;/code&gt; compiler for Windows 32-bit).&lt;/p&gt;

&lt;p&gt;After that, you can try your luck with closed-source native binaries, by the help of disassemblers such as &lt;a href=&quot;https://ghidra-sre.org/&quot;&gt;Ghidra&lt;/a&gt; and &lt;a href=&quot;https://hex-rays.com/ida-free&quot;&gt;IDA&lt;/a&gt;, and debuggers such as &lt;a href=&quot;https://x64dbg.com/&quot;&gt;x64dbg&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note&lt;/em&gt;&lt;/strong&gt;: If you’ve noticed inaccurate information, or room for improvement regarding this article, and would like to improve it, feel free to &lt;a href=&quot;https://github.com/thedroidgeek/0x44.cc/edit/master/_posts/2021-07-21-reversing-x86-and-c-code-for-beginners.md&quot;&gt;submit a pull request&lt;/a&gt; on GitHub.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/thedroidgeek/0x44.cc/commits/master/_posts/2021-07-21-reversing-x86-and-c-code-for-beginners.md&quot;&gt;(edited)&lt;/a&gt;&lt;/p&gt;</content><author><name>Sami ALAOUI KENDIL</name></author><category term="reversing" /><summary type="html">Context Before I got into reverse engineering, executables always seemed like black magic to me. I always wondered how stuff worked under the hood, and how binary code is represented inside .exe files, and how hard it is to modify this ‘compiled code’ without access to the original source code. But one of the main intimidating hurdles always seemed to be the assembly language, it’s the thing that scares most people away from trying to learn about this field. That’s the main reason why I thought of writing this straight-to-the-point article that only contains the essential stuff that you encounter the most when reversing, albeit missing crucial details for the sake of brevity, and assumes the reader has a reflex of finding answers online, looking up definitions, and more importantly, coming up with examples/ideas/projects to practice on. The goal is to hopefully guide an aspiring reverse engineer and arouse motivation towards learning more about this seemingly elusive passion. Note: This article assumes the reader has elementary knowledge regarding the hexadecimal numeral system, as well as the C programming language, and is based on a 32-bit Windows executable case study - results might differ across different OSes/architectures. Introduction Compilation After writing code using a compiled language, a compilation takes place (duh), in order to generate the output binary file (an example of such is an .exe file). Compilers are sophisticated programs which do this task. They make sure the syntax of your ugly code is correct, before compiling and optimizing the resulting machine code by minimizing its size and improving its performance, whenever applicable. Binary code As we were saying, the resulting output file contains binary code, which can only be ‘understood’ by a CPU, it’s essentially a succession of varying-length instructions to be executed in order - here’s what some of them look like: CPU-readable instruction data (in hex) Human-readable interpretation 55 push ebp 8B EC mov ebp, esp 83 EC 08 sub esp, 8 33 C5 xor eax, ebp 83 7D 0C 01 cmp dword ptr [ebp+0Ch], 1 These instructions are predominantly arithmetical, and they manipulate CPU registers/flags as well as volatile memory, as they’re executed. CPU registers A CPU register is almost like a temporary integer variable - there’s a small fixed number of them, and they exist because they’re quick to access, unlike memory-based variables, and they help the CPU keep track of its data (results, operands, counts, etc.) during execution. It’s important to note the presence of a special register called the FLAGS register (EFLAGS on 32-bit), which houses a bunch of flags (boolean indicators), which hold information about the state of the CPU, which include details about the last arithmetic operation (zero: ZF, overflow: OF, parity: PF, sign: SF, etc.). CPU registers visualized while debugging a 32-bit process on x64dbg, a debugging tool. Some of these registers can also be spotted on the assembly excerpt mentioned previously, namely: EAX, ESP (stack pointer) and EBP (base pointer). Memory access As the CPU executes stuff, it needs to access and interact with memory, that’s when the role of the stack and the heap comes. These are (without getting into too much detail) the 2 main ways of ‘keeping track of variable data’ during the execution of a program: 🥞 Stack The simpler and faster of the two - it’s a linear contiguous LIFO (last in = first out) data structure with a push/pop mechanism, it serves to remember function-scoped variables, arguments, and keeps track of calls (ever heard of a stack trace?) ⛰ Heap The heap, however, is pretty unordered, and is for more complicated data structures, it’s typically used for dynamic allocations, where the size of the buffer isn’t initially known, and/or if it’s too big, and/or needs to be modified later. Assembly instructions As I’ve mentioned earlier, assembly instructions have a varying ‘byte-size’, and a varying number of arguments. Arguments can also be either immediate (‘hardcoded’), or they can be registers, depending on the instruction: 55 push ebp ; size: 1 byte, argument: register 6A 01 push 1 ; size: 2 bytes, argument: immediate Let’s quickly run through a very small set of some of the common ones we’ll get to see - feel free to do your own research for more detail: Stack operations push value ; pushes a value into the stack (decrements ESP by 4, the size of one stack ‘unit’). pop register ; pops a value to a register (increments ESP by 4). Data transfer mov destination, source ; moves copies a value from/to a register. mov destination, [expression] ; copies a value from a memory address resolved from a ‘register expression’ (single register or arithmetic expression involving one or more registers) into a register. Flow control jmp destination ; jumps into a code location (sets EIP (instruction pointer)). jz/je destination ; jumps into a code location if ZF (the zero flag) is set. jnz/jne destination ; jumps into a code location if ZF is not set. Operations cmp operand1, operand2 ; compares the 2 operands and sets ZF if they’re equal. add operand1, operand2 ; operand1 += operand2; sub operand1, operand2 ; operand1 -= operand2; Function transitions call function ; calls a function (pushes current EIP, then jumps to the function). retn ; returns to caller function (pops back the previous EIP). Note: You might notice the words ‘equal’ and ‘zero’ being used interchangeably in x86 terminology - that’s because comparison instructions internally perform a subtraction, which means if the 2 operands are equal, ZF is set. Assembly patterns Now that we have a rough idea of the main elements used during the execution of a program, let’s get familiarized with the patterns of instructions that you can encounter reverse engineering your average everyday 32-bit PE binary. Function prologue A function prologue is some initial code embedded in the beginning of most functions, it serves to set up a new stack frame for said function. It typically looks like this (X being a number): 55 push ebp ; preserve caller function's base pointer in stack 8B EC mov ebp, esp ; caller function's stack pointer becomes base pointer (new stack frame) 83 EC XX sub esp, X ; adjust the stack pointer by X bytes to reserve space for local variables Function epilogue The epilogue is simply the opposite of the prologue - it undoes its steps to restore the stack frame of the caller function, before it returns to it: 8B E5 mov esp, ebp ; restore caller function's stack pointer (current base pointer) 5D pop ebp ; restore base pointer from the stack C3 retn ; return to caller function Now at this point, you might be wondering - how do functions talk to each other? How exactly do you send/access arguments when calling a function, and how do you receive the return value? That’s precisely why we have calling conventions. Calling conventions: __cdecl A calling convention is basically a protocol used to communicate with functions, there’s a few variations of them, but they share the same principle. We will be looking at the __cdecl (C declaration) convention, which is the standard one when compiling C code. In __cdecl (32-bit), function arguments are passed on the stack (pushed in reverse order), while the return value is returned in the EAX register (assuming it’s not a float). This means that a func(1, 2, 3); call will generate the following: 6A 03 push 3 6A 02 push 2 6A 01 push 1 E8 XX XX XX XX call func Putting everything together Assuming func() simply does an addition on the arguments and returns the result, it would probably look like this: int __cdecl func(int, int, int): prologue: 55 push ebp ; save base pointer 8B EC mov ebp, esp ; new stack frame body: 8B 45 08 mov eax, [ebp+8] ; load first argument to EAX (return value) 03 45 0C add eax, [ebp+0Ch] ; add 2nd argument 03 45 10 add eax, [ebp+10h] ; add 3rd argument epilogue: 5D pop ebp ; restore base pointer C3 retn ; return to caller Now if you’ve been paying attention and you’re still confused, you might be asking yourself one of these 2 questions: 1) Why do we have to adjust EBP by 8 to get to the first argument? If you check the definition of the call instruction we mentioned earlier, you’ll realize that, internally, it actually pushes EIP to the stack. And if you also check the definition for push, you’ll realize that it decrements ESP (which is copied to EBP after the prologue) by 4 bytes. In addition, the prologue’s first instruction is also a push, so we end up with 2 decrements of 4, hence the need to add 8. 2) What happened to the prologue and epilogue, why are they seemingly ‘truncated’? It’s simply because we haven’t had a use for the stack during the execution of our function - if you’ve noticed, we haven’t modified ESP at all, which means we also don’t need to restore it. If conditions To demo the flow control assembly instructions, I’d like to add one more example to show how an if condition was compiled to assembly. Assume we have the following function: void print_equal(int a, int b) { if (a == b) { printf(&quot;equal&quot;); } else { printf(&quot;nah&quot;); } } After compiling it, here’s the disassembly that I got with the help of IDA: void __cdecl print_equal(int, int): 10000000 55 push ebp 10000001 8B EC mov ebp, esp 10000003 8B 45 08 mov eax, [ebp+8] ; load 1st argument 10000006 3B 45 0C cmp eax, [ebp+0Ch] ; compare it with 2nd ┌┅ 10000009 75 0F jnz short loc_1000001A ; jump if not equal ┊ 1000000B 68 94 67 00 10 push offset aEqual ; &quot;equal&quot; ┊ 10000010 E8 DB F8 FF FF call _printf ┊ 10000015 83 C4 04 add esp, 4 ┌─┊─ 10000018 EB 0D jmp short loc_10000027 │ ┊ │ └ loc_1000001A: │ 1000001A 68 9C 67 00 10 push offset aNah ; &quot;nah&quot; │ 1000001F E8 CC F8 FF FF call _printf │ 10000024 83 C4 04 add esp, 4 │ └── loc_10000027: 10000027 5D pop ebp 10000028 C3 retn Give yourself a minute and try to make sense of this disassembly output (for simplicity’s sake, I’ve changed the real addresses and made the function start from 10000000 instead). In case you’re wondering about the add esp, 4 part, it’s simply there to adjust ESP back to its initial value (same effect as a pop, except without modifying any register), since we had to push the printf string argument. Basic data structures Now let’s move on and talk about how data is stored (integers and strings especially). Endianness Endianness is the order of the sequence of bytes representing a value in computer memory. There’s 2 types - big-endian and little-endian: For reference, x86 family processors (the ones on pretty much any computer you can find) always use little-endian. To give you a live example of this concept, I’ve compiled a Visual Studio C++ console app, where I declared an int variable with the value 1337 assigned to it, then I printed the variable’s address using printf(), on the main function. Then I ran the program attached to the debugger in order to check the printed variable’s address on the memory hex view, and here’s the result I obtained: To elaborate more on this - int variables are 4 bytes long (32 bits) (in case you didn’t know), so this means that if the variable starts from the address D2FCB8 it would end right before D2FCBC (+4). To go from human readable value to memory bytes, follow these steps: decimal: 1337 -&amp;gt; hex: 539 -&amp;gt; bytes: 00 00 05 39 -&amp;gt; little-endian: 39 05 00 00 Signed integers This part is interesting yet relatively simple. What you should know here is that integer signing (positive/negative) is typically done on computers with the help of a concept called two’s complement. The gist of it is that the lowest/first half of an integer is reserved for positive numbers, while the highest/last half is for negative numbers, here’s what this looks like in hex, for a 32-bit signed int (highlighted = hex, in parenthesis = decimal): Positives (1/2): 00000000 (0) -&amp;gt; 7FFFFFFF (2,147,483,647 or INT_MAX) Negatives (2/2): 80000000 (-2,147,483,648 or INT_MIN) -&amp;gt; FFFFFFFF (-1) If you’ve noticed, we’re always ascending in value. Whether we go up in hex or decimal. And that’s the crucial point of this concept - arithmetical operation do not have to do anything special to handle signing, they can simply treat all values as unsigned/positive, and the result would still be interpreted correctly (as long as we don’t go beyond INT_MAX or INT_MIN), and that’s because integers will also ‘rollover’ on overflow/underflow by design, kinda like an analog odometer. Protip: The Windows calculator is a very helpful tool - you can set it to programmer mode and set the size to DWORD (4 bytes), then enter negative decimal values and visualize them in hex and binary, and have fun performing operations on them. Strings In C, strings are stored as char arrays, therefore, there’s nothing special to note here, except for something called null termination. If you ever wondered how strlen() is able to know the size of a string, it’s very simple - strings have a character that indicates their end, and that’s the null byte/character - 00 or '\0'. If you declare a string constant in C code, and hover over it in Visual Studio, for instance, it will tell you the size of the generated array, and as you can see, for this reason, it’s one element more than the ‘visible’ string size. Note: The endianness concept is not applicable on arrays, only on single variables. Therefore, the order of characters in memory would be normal here - low to high. Making sense of call and jmp instructions Now that you know all of this, you’re likely able to start making sense of some machine code, and emulate a CPU with your brain, to some extent, so to speak. Let’s take the print_equal() example, but let’s only focus on the printf() call instructions this time. void print_equal(int, int): ... 10000010 E8 DB F8 FF FF call _printf ... 1000001F E8 CC F8 FF FF call _printf You might be wondering to yourself - wait a second, if these are the same instructions, then why are their bytes different? That’s because, call (and jmp) instructions (usually) take an offset (relative address) as an argument, not an absolute address. An offset is basically the difference between the current location, and the destination, which also means that it can be either negative or positive. As you can see, the opcode of a call instruction that takes a 32-bit offset, is E8, and is followed by said offset - which makes the full instruction: E8 XX XX XX XX. Pull out your calculator, why’d you close it so early?! and calculate the difference between the offset of both instructions (don’t forget the endianness). You’ll notice that (the absolute value of) this difference is the same as the one between the instruction addresses (1000001F - 10000010 = F): Another small detail that we should add, is the fact that the CPU only executes an instruction after fully ‘reading’ it, which means that by the time the CPU starts ‘executing’, EIP (the instruction pointer) is already pointing at the next instruction to be executed. That’s why these offsets are actually accounting for this behaviour, which means that in order to get the real address of the target function, we have to also add the size of the call instruction: 5. Now let’s apply all these steps in order to resolve printf()’s address from the first instruction on the example: 10000010 E8 DB F8 FF FF call _printf 1) Extract the offset from the instruction: E8 (DB F8 FF FF) -&amp;gt; FFFFF8DB (-1829) 2) Add it to the instruction address: 10000010 + FFFFF8DB = 0FFFF8EB 3) And finally, add the instruction size: 0FFFF8EB + 5 = 0FFFF8F0 (&amp;amp;printf) The exact same principle applies to the jmp instruction: ... ┌─── 10000018 EB 0D jmp short loc_10000027 ... └── loc_10000027: 10000027 5D pop ebp ... The only difference in this example is that EB XX is a short version jmp instruction - which means it only takes an 8-bit (1 byte) offset. Therefore: 10000018 + 0D + 2 = 10000027 Conclusion That’s it! You should now have enough information (and hopefully, motivation) to start your journey reverse engineering executables. Start by writing dummy C code, compiling it, and debugging it while single-stepping through the disassembly instructions (Visual Studio allows you to do this, by the way). Compiler Explorer is also an extremely helpful website which compiles C code to assembly for you in real time using multiple compilers (select the x86 msvc compiler for Windows 32-bit). After that, you can try your luck with closed-source native binaries, by the help of disassemblers such as Ghidra and IDA, and debuggers such as x64dbg. Note: If you’ve noticed inaccurate information, or room for improvement regarding this article, and would like to improve it, feel free to submit a pull request on GitHub. Thanks for reading! (edited)</summary></entry><entry><title type="html">Google Assistant YouTube command for smart TVs</title><link href="https://0x44.cc/automation/2021/03/02/google-assistant-youtube-smart-tvs.html" rel="alternate" type="text/html" title="Google Assistant YouTube command for smart TVs" /><published>2021-03-02T00:00:00+00:00</published><updated>2021-03-02T00:00:00+00:00</updated><id>https://0x44.cc/automation/2021/03/02/google-assistant-youtube-smart-tvs</id><content type="html" xml:base="https://0x44.cc/automation/2021/03/02/google-assistant-youtube-smart-tvs.html">&lt;h3 id=&quot;context&quot;&gt;Context&lt;/h3&gt;

&lt;p&gt;After I’ve noticed my 2019 Samsung TV had support for Google Assistant commands for basic controls such as power, volume, channel, input source, etc., I thought it would be cool to also be able to cast media content using my voice, but I then realized that the only officially supported TVs were labeled ‘Chromecast-enabled’, and that people without those generally end up buying the Chromecast TV stick, for the ‘full compatibility’, which sounds like a waste when you already own a ‘smart’ TV.&lt;/p&gt;

&lt;p&gt;As YouTube takes up the largest part of my ‘media consumption’, one day, &lt;del&gt;and after procrastinating for months,&lt;/del&gt; I went ahead and checked out the inner-workings of the existing casting functionnality, by casting YouTube videos from the Android app to the TV, to try to figure out a way to automate that process, to then link it to the Google Assistant.&lt;/p&gt;

&lt;h3 id=&quot;dial-protocol&quot;&gt;DIAL protocol&lt;/h3&gt;

&lt;p&gt;By doing a quick capture of the network traffic between the phone and the TV - by using the Intercepter-NG app (requires root), I’ve already noticed a very simple and easy-to-spot HTTP endpoint that was being hit during the cast connection:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://tizen:8080/ws/apps/YouTube&lt;/code&gt; (‘tizen’ being the TV’s LAN hostname)&lt;/p&gt;

&lt;p&gt;A quick search online revealed that this endpoint is part of a protocol called DIAL, for Discovery and Launch, which is used to initiate applications on “1st screen” devices, such as TVs, via small factor (“2nd screen”) devices, such as phones and tablets. (&lt;a href=&quot;https://en.wikipedia.org/wiki/Discovery_and_Launch&quot;&gt;More on Wikipedia&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;It turns out that a simple empty POST request to the previously mentionned endpoint would launch the application on the target TV, and a GET would return various metadata around the application, in XML format, including its status (running/stopped), and other application-specific information:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;service&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;urn:dial-multiscreen-org:schemas:dial&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns:atom=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://www.w3.org/2005/Atom&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dialVer=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2.1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;name&amp;gt;&lt;/span&gt;YouTube&lt;span class=&quot;nt&quot;&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;options&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;allowStop=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;state&amp;gt;&lt;/span&gt;running&lt;span class=&quot;nt&quot;&gt;&amp;lt;/state&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.1.493&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;run&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;run&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;additionalData&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;testYWRkaXR&amp;gt;&lt;/span&gt;c0ef1ca&lt;span class=&quot;nt&quot;&gt;&amp;lt;/testYWRkaXR&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;screenId&amp;gt;&lt;/span&gt;[REDACTED]&lt;span class=&quot;nt&quot;&gt;&amp;lt;/screenId&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;theme&amp;gt;&lt;/span&gt;cl&lt;span class=&quot;nt&quot;&gt;&amp;lt;/theme&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;deviceId&amp;gt;&lt;/span&gt;[REDACTED]&lt;span class=&quot;nt&quot;&gt;&amp;lt;/deviceId&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;loungeToken&amp;gt;&lt;/span&gt;AGdO5p9wG5CgVGkvneeZ4MSaEJMnJrailH5e4YBwEa4zDZl9C-J5Hju0dxT-PzOJsNQcojxt5ih1K5cY72mPFR-IJUVBC-KU-WaLBriZMnc9KFv1DBLXlhY&lt;span class=&quot;nt&quot;&gt;&amp;lt;/loungeToken&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;loungeTokenRefreshIntervalMs&amp;gt;&lt;/span&gt;1500000&lt;span class=&quot;nt&quot;&gt;&amp;lt;/loungeTokenRefreshIntervalMs&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/additionalData&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/service&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Great, we now have an easy way of launching the app on the target TV so that it’s ready to receive casted content.&lt;/p&gt;

&lt;p&gt;After doing more research, it seems there’s also an ‘easy’ way of playing actual videos using this same endpoint, by simply adding a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v&lt;/code&gt; parameter on the body of the POST request, which would be the YouTube video ID.&lt;/p&gt;

&lt;p&gt;However though, it seems that this method was recently (late 2020) rendered useless, as it now requires manual confirmation on the TV each time a video is requested.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/yt-shady-cast-prompt.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Time to dig deeper.&lt;/p&gt;

&lt;h3 id=&quot;youtube-cast-functionnality&quot;&gt;YouTube cast functionnality&lt;/h3&gt;

&lt;p&gt;In order to proceed with further network traffic inspection, it was needed to achieve HTTPS interception, which would require bypassing SSL-pinning on the Android YouTube app, in order to be able to decrypt its traffic.&lt;/p&gt;

&lt;p&gt;Luckily though, it turns out that the Google Chrome browser also supports the casting functionnality on YouTube - so I’ve simply fired up &lt;a href=&quot;https://www.telerik.com/download/fiddler&quot;&gt;Fiddler&lt;/a&gt; and started watching the web requests.&lt;/p&gt;

&lt;p&gt;When a compatible TV is discovered, a casting icon pops up on the YouTube player control bar, like so:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/yt-cast-icon.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After clicking the icon and choosing the cast device, the YouTube player starts acting as a remote.&lt;/p&gt;

&lt;p&gt;Behind the scenes, a private YouTube API called ‘Lounge’ is used, in order to do the pairing and the remote control functionnality for YouTube Leanback (big screen) devices.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/yt-lounge-api-capture.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;By analysing these requests, I’ve noticed that the API was fairly complicated, with a mix of body and URL parameters, comprising tokens, IDs, as well as some weird changing alphanumeric values.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/yt-lounge-api-params.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The responses were also seemingly in a custom JSON-based format.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;174&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;105&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;onStateChange&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;currentTime&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;50&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;duration&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;318.321&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cpn&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;7s_Qx1i3xE4fXNVX&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;loadedTime&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;50&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;state&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;seekableStartTime&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;seekableEndTime&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;318.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, I was able to find some very useful code on GitHub, which saved me the hassle of reverse engineering the API, which quite frankly, I might’ve gave up doing. 👀&lt;/p&gt;

&lt;h3 id=&quot;youtube-remote-by-mutantmonkey&quot;&gt;youtube-remote by @mutantmonkey&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/mutantmonkey/youtube-remote&quot;&gt;youtube-remote&lt;/a&gt; allows us to play/queue a video, and pause/resume the playback, using the YouTube Lounge API.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;usage: remote.py [-h] (--play PLAY | --queue [QUEUE ...] | --pause | --unpause)

Command-line YouTube Leanback remote

optional arguments:
  -h, --help           show this help message and exit
  --play PLAY          Play a video immediately
  --queue [QUEUE ...]  Add a video to the queue
  --pause              Pause the current video
  --unpause            Unpause the current video
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first phase is the pairing phase.&lt;/p&gt;

&lt;p&gt;Upon running the script, you are instructed to provide a pairing code - which is seemingly the method used to pair with ‘old-school’ leanback devices, that aren’t necessarily on the same network and/or don’t support casting protocols like DIAL.&lt;/p&gt;

&lt;p&gt;The pairing code is then used to retreive the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loungeToken&lt;/code&gt; using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/lounge/pairing/get_screen&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;We can skip this part, as in our case, the TV seems to always allocate its own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loungeToken&lt;/code&gt;, as seen on the &lt;a href=&quot;#dial-protocol&quot;&gt;‘DIAL endpoint’ response&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After commenting out the pairing code part, and manually assigning the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loungeToken&lt;/code&gt; of the TV, the script worked!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/yt-remote-demo.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Sweet! We now have a decent way of playing YouTube videos on the TV.&lt;/p&gt;

&lt;h3 id=&quot;automation&quot;&gt;Automation&lt;/h3&gt;

&lt;p&gt;Now that we’ve figured out the main part, it’s now time to find a method of automating the whole process.&lt;/p&gt;

&lt;p&gt;First off, &lt;a href=&quot;https://ifttt.com/&quot;&gt;IFTTT&lt;/a&gt; allows us to have &lt;a href=&quot;https://support.google.com/googlenest/answer/7194656&quot;&gt;custom Google Assistant commands&lt;/a&gt;, so we can use that as a starting point.&lt;/p&gt;

&lt;p&gt;IFTTT has a &lt;a href=&quot;https://ifttt.com/maker_webhooks&quot;&gt;webhook plugin&lt;/a&gt;, which would allow us to receive actions following a Google Assistant command, via HTTP.&lt;/p&gt;

&lt;p&gt;But in order for us to receive these commands locally, we would have to expose a local webserver to the internet, which means that we have to use either a reverse proxy service such as &lt;a href=&quot;https://ngrok.com/&quot;&gt;ngrok&lt;/a&gt; or &lt;a href=&quot;https://localtunnel.me/&quot;&gt;localtunnel&lt;/a&gt;, or do port forwarding on the router, and configure a dynamic DNS (I went with the former option, for reference).&lt;/p&gt;

&lt;p&gt;So, In short, here’s the complete execution flow:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;“Hey Google, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;searchQuery&lt;/code&gt; on YouTube.”&lt;/li&gt;
  &lt;li&gt;Google Assistant executes the IFTTT command.&lt;/li&gt;
  &lt;li&gt;Which calls IFTTT’s Maker Webhooks on a public webhook.&lt;/li&gt;
  &lt;li&gt;Which forwards to our local webserver.&lt;/li&gt;
  &lt;li&gt;Which would execute the following sequence:
    &lt;ul&gt;
      &lt;li&gt;Do a YouTube video search by scraping &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;youtube.com/results?search_query={searchQuery}&lt;/code&gt;, in order to find/parse the video ID.&lt;/li&gt;
      &lt;li&gt;Launch the YouTube app on the TV (POST :8080/ws/apps/YouTube).&lt;/li&gt;
      &lt;li&gt;Wait for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loungeToken&lt;/code&gt; to be available (GET).&lt;/li&gt;
      &lt;li&gt;Use the Lounge API to play the video on the TV (youtube-remote on GitHub).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;extras&quot;&gt;Extras&lt;/h3&gt;

&lt;h4 id=&quot;1-multiple-search-results&quot;&gt;1. Multiple search results&lt;/h4&gt;

&lt;p&gt;As my TV already supported Google Assistant commands such as next and previous, I thought about queuing a dozen of YouTube videos that come up on the search, instead of just one, so I can go through the search results, in case the video I want is not the first one to show up.&lt;/p&gt;

&lt;p&gt;After I’ve noticed that queuing each video would show an annoying notification on the TV, I looked for better way to do the job.&lt;/p&gt;

&lt;p&gt;Luckily, after some analysis of YouTube JS code, and some trial and error, I was able to figure out how to use the Lounge API command &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setPlaylist&lt;/code&gt;, which takes 2 arguments, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;videoId&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;videoIds&lt;/code&gt; - the first one is the initial video to play, while the second one is a comma-separated list of the rest of the videos to be queued.&lt;/p&gt;

&lt;p&gt;Cool, no more pesky notifications, and a single command can do it all now.&lt;/p&gt;

&lt;h4 id=&quot;2-wake-on-lan&quot;&gt;2. Wake-on-LAN&lt;/h4&gt;

&lt;p&gt;I’ve also implemented Wake-on-LAN, so that the TV would turn on in case it was off.&lt;/p&gt;

&lt;p&gt;This is especially useful since, for some reason, there’s a &lt;a href=&quot;https://community.smartthings.com/t/samsung-tv-cant-turn-on/114960&quot;&gt;known issue&lt;/a&gt;, at least on some select models, where if the TV is connected via Ethernet instead of Wi-Fi, it loses connection to &lt;a href=&quot;https://www.smartthings.com/&quot;&gt;SmartThings&lt;/a&gt; soon after it’s turned off - which means you can’t turn it on from the cloud/Google Assistant.&lt;/p&gt;

&lt;h4 id=&quot;3-youtube-player-ui-visibility&quot;&gt;3. YouTube player UI visibility&lt;/h4&gt;

&lt;p&gt;Lastly, a small UX improvement: I send a pause + play command (you can send multiple commands on a single request) after the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setPlaylist&lt;/code&gt; command, to force the YouTube player UI to show up initially (so that one’s able to see the video title), as it doesn’t do so by default when casting.&lt;/p&gt;

&lt;h3 id=&quot;demo&quot;&gt;Demo&lt;/h3&gt;

&lt;p style=&quot;position: relative; padding: 30px 0px 57% 0px; height: 0; overflow: hidden;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/2viK_LeoT4M&quot; width=&quot;100%&quot; height=&quot;100%&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;display: block; margin: 0px auto; position: absolute; top: 0; left: 0;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;

&lt;h3 id=&quot;code&quot;&gt;Code&lt;/h3&gt;

&lt;p&gt;I’ve &lt;a href=&quot;https://github.com/thedroidgeek/youtube-cast-automation-api&quot;&gt;shared my code on GitHub&lt;/a&gt; - it’s a python script with a micro API that needs to be exposed to the internet, to then be linked to the Google Assistant through IFTTT, as previously explained - the details on how to do so as well as the API documentation can be found on the README of the repository.&lt;/p&gt;

&lt;h3 id=&quot;potential-future-plans&quot;&gt;Potential future plans&lt;/h3&gt;

&lt;p&gt;Since I’m currently running my little server on a Raspberry Pi anyway, I might soon check out &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt;, so I can perhaps port my code to it, and potentially get into more home automation stuff - so I &lt;em&gt;might&lt;/em&gt; diversify my future posts with more of such content as well, pending positive feedback.&lt;/p&gt;

&lt;p&gt;See you in 2 years! /s&lt;/p&gt;

&lt;p&gt;“Hey Google, publish blog post.” 😂👌💯🌈&lt;/p&gt;</content><author><name>Sami ALAOUI KENDIL</name></author><category term="automation" /><summary type="html">Context After I’ve noticed my 2019 Samsung TV had support for Google Assistant commands for basic controls such as power, volume, channel, input source, etc., I thought it would be cool to also be able to cast media content using my voice, but I then realized that the only officially supported TVs were labeled ‘Chromecast-enabled’, and that people without those generally end up buying the Chromecast TV stick, for the ‘full compatibility’, which sounds like a waste when you already own a ‘smart’ TV. As YouTube takes up the largest part of my ‘media consumption’, one day, and after procrastinating for months, I went ahead and checked out the inner-workings of the existing casting functionnality, by casting YouTube videos from the Android app to the TV, to try to figure out a way to automate that process, to then link it to the Google Assistant. DIAL protocol By doing a quick capture of the network traffic between the phone and the TV - by using the Intercepter-NG app (requires root), I’ve already noticed a very simple and easy-to-spot HTTP endpoint that was being hit during the cast connection: http://tizen:8080/ws/apps/YouTube (‘tizen’ being the TV’s LAN hostname) A quick search online revealed that this endpoint is part of a protocol called DIAL, for Discovery and Launch, which is used to initiate applications on “1st screen” devices, such as TVs, via small factor (“2nd screen”) devices, such as phones and tablets. (More on Wikipedia) It turns out that a simple empty POST request to the previously mentionned endpoint would launch the application on the target TV, and a GET would return various metadata around the application, in XML format, including its status (running/stopped), and other application-specific information: &amp;lt;service xmlns=&quot;urn:dial-multiscreen-org:schemas:dial&quot; xmlns:atom=&quot;http://www.w3.org/2005/Atom&quot; dialVer=&quot;2.1&quot;&amp;gt; &amp;lt;name&amp;gt;YouTube&amp;lt;/name&amp;gt; &amp;lt;options allowStop=&quot;true&quot;/&amp;gt; &amp;lt;state&amp;gt;running&amp;lt;/state&amp;gt; &amp;lt;version&amp;gt;2.1.493&amp;lt;/version&amp;gt; &amp;lt;link rel=&quot;run&quot; href=&quot;run&quot;/&amp;gt; &amp;lt;additionalData&amp;gt; &amp;lt;testYWRkaXR&amp;gt;c0ef1ca&amp;lt;/testYWRkaXR&amp;gt; &amp;lt;screenId&amp;gt;[REDACTED]&amp;lt;/screenId&amp;gt; &amp;lt;theme&amp;gt;cl&amp;lt;/theme&amp;gt; &amp;lt;deviceId&amp;gt;[REDACTED]&amp;lt;/deviceId&amp;gt; &amp;lt;loungeToken&amp;gt;AGdO5p9wG5CgVGkvneeZ4MSaEJMnJrailH5e4YBwEa4zDZl9C-J5Hju0dxT-PzOJsNQcojxt5ih1K5cY72mPFR-IJUVBC-KU-WaLBriZMnc9KFv1DBLXlhY&amp;lt;/loungeToken&amp;gt; &amp;lt;loungeTokenRefreshIntervalMs&amp;gt;1500000&amp;lt;/loungeTokenRefreshIntervalMs&amp;gt; &amp;lt;/additionalData&amp;gt; &amp;lt;/service&amp;gt; Great, we now have an easy way of launching the app on the target TV so that it’s ready to receive casted content. After doing more research, it seems there’s also an ‘easy’ way of playing actual videos using this same endpoint, by simply adding a v parameter on the body of the POST request, which would be the YouTube video ID. However though, it seems that this method was recently (late 2020) rendered useless, as it now requires manual confirmation on the TV each time a video is requested. Time to dig deeper. YouTube cast functionnality In order to proceed with further network traffic inspection, it was needed to achieve HTTPS interception, which would require bypassing SSL-pinning on the Android YouTube app, in order to be able to decrypt its traffic. Luckily though, it turns out that the Google Chrome browser also supports the casting functionnality on YouTube - so I’ve simply fired up Fiddler and started watching the web requests. When a compatible TV is discovered, a casting icon pops up on the YouTube player control bar, like so: After clicking the icon and choosing the cast device, the YouTube player starts acting as a remote. Behind the scenes, a private YouTube API called ‘Lounge’ is used, in order to do the pairing and the remote control functionnality for YouTube Leanback (big screen) devices. By analysing these requests, I’ve noticed that the API was fairly complicated, with a mix of body and URL parameters, comprising tokens, IDs, as well as some weird changing alphanumeric values. The responses were also seemingly in a custom JSON-based format. B2 174 [[105,[&quot;onStateChange&quot;,{&quot;currentTime&quot;:&quot;50&quot;,&quot;duration&quot;:&quot;318.321&quot;,&quot;cpn&quot;:&quot;7s_Qx1i3xE4fXNVX&quot;,&quot;loadedTime&quot;:&quot;50&quot;,&quot;state&quot;:&quot;3&quot;,&quot;seekableStartTime&quot;:&quot;0&quot;,&quot;seekableEndTime&quot;:&quot;318.3&quot;}]] ] 0 However, I was able to find some very useful code on GitHub, which saved me the hassle of reverse engineering the API, which quite frankly, I might’ve gave up doing. 👀 youtube-remote by @mutantmonkey youtube-remote allows us to play/queue a video, and pause/resume the playback, using the YouTube Lounge API. usage: remote.py [-h] (--play PLAY | --queue [QUEUE ...] | --pause | --unpause) Command-line YouTube Leanback remote optional arguments: -h, --help show this help message and exit --play PLAY Play a video immediately --queue [QUEUE ...] Add a video to the queue --pause Pause the current video --unpause Unpause the current video The first phase is the pairing phase. Upon running the script, you are instructed to provide a pairing code - which is seemingly the method used to pair with ‘old-school’ leanback devices, that aren’t necessarily on the same network and/or don’t support casting protocols like DIAL. The pairing code is then used to retreive the loungeToken using the /api/lounge/pairing/get_screen endpoint. We can skip this part, as in our case, the TV seems to always allocate its own loungeToken, as seen on the ‘DIAL endpoint’ response. After commenting out the pairing code part, and manually assigning the loungeToken of the TV, the script worked! Sweet! We now have a decent way of playing YouTube videos on the TV. Automation Now that we’ve figured out the main part, it’s now time to find a method of automating the whole process. First off, IFTTT allows us to have custom Google Assistant commands, so we can use that as a starting point. IFTTT has a webhook plugin, which would allow us to receive actions following a Google Assistant command, via HTTP. But in order for us to receive these commands locally, we would have to expose a local webserver to the internet, which means that we have to use either a reverse proxy service such as ngrok or localtunnel, or do port forwarding on the router, and configure a dynamic DNS (I went with the former option, for reference). So, In short, here’s the complete execution flow: “Hey Google, searchQuery on YouTube.” Google Assistant executes the IFTTT command. Which calls IFTTT’s Maker Webhooks on a public webhook. Which forwards to our local webserver. Which would execute the following sequence: Do a YouTube video search by scraping youtube.com/results?search_query={searchQuery}, in order to find/parse the video ID. Launch the YouTube app on the TV (POST :8080/ws/apps/YouTube). Wait for the loungeToken to be available (GET). Use the Lounge API to play the video on the TV (youtube-remote on GitHub). Extras 1. Multiple search results As my TV already supported Google Assistant commands such as next and previous, I thought about queuing a dozen of YouTube videos that come up on the search, instead of just one, so I can go through the search results, in case the video I want is not the first one to show up. After I’ve noticed that queuing each video would show an annoying notification on the TV, I looked for better way to do the job. Luckily, after some analysis of YouTube JS code, and some trial and error, I was able to figure out how to use the Lounge API command setPlaylist, which takes 2 arguments, videoId and videoIds - the first one is the initial video to play, while the second one is a comma-separated list of the rest of the videos to be queued. Cool, no more pesky notifications, and a single command can do it all now. 2. Wake-on-LAN I’ve also implemented Wake-on-LAN, so that the TV would turn on in case it was off. This is especially useful since, for some reason, there’s a known issue, at least on some select models, where if the TV is connected via Ethernet instead of Wi-Fi, it loses connection to SmartThings soon after it’s turned off - which means you can’t turn it on from the cloud/Google Assistant. 3. YouTube player UI visibility Lastly, a small UX improvement: I send a pause + play command (you can send multiple commands on a single request) after the setPlaylist command, to force the YouTube player UI to show up initially (so that one’s able to see the video title), as it doesn’t do so by default when casting. Demo Code I’ve shared my code on GitHub - it’s a python script with a micro API that needs to be exposed to the internet, to then be linked to the Google Assistant through IFTTT, as previously explained - the details on how to do so as well as the API documentation can be found on the README of the repository. Potential future plans Since I’m currently running my little server on a Raspberry Pi anyway, I might soon check out Home Assistant, so I can perhaps port my code to it, and potentially get into more home automation stuff - so I might diversify my future posts with more of such content as well, pending positive feedback. See you in 2 years! /s “Hey Google, publish blog post.” 😂👌💯🌈</summary></entry><entry><title type="html">Unlocking IAM’s Nokia G-240W-A router (Part 1)</title><link href="https://0x44.cc/reversing/2019/10/08/unlocking-nokia-g240wa.html" rel="alternate" type="text/html" title="Unlocking IAM’s Nokia G-240W-A router (Part 1)" /><published>2019-10-08T00:00:00+00:00</published><updated>2019-10-08T00:00:00+00:00</updated><id>https://0x44.cc/reversing/2019/10/08/unlocking-nokia-g240wa</id><content type="html" xml:base="https://0x44.cc/reversing/2019/10/08/unlocking-nokia-g240wa.html">&lt;h3 id=&quot;context&quot;&gt;Context&lt;/h3&gt;

&lt;p&gt;As we recently upgraded our home internet to try out Maroc Telecom’s 100mbps fiber offer, I’ve noticed that the Nokia router they installed had horrible Wi-Fi speed - the max I could to get standing next to it was around 60mbps down, while in the opposite room, the speed was always under 10mbps.&lt;/p&gt;

&lt;p&gt;What’s interesting is the fact that it had decent range - I get full bars most of the time, and my Wi-Fi adapter reports a 300mbps data rate.&lt;/p&gt;

&lt;p&gt;This got me intrigued, so I tried to take a look at what’s running inside this thing.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/nokia-g-240w-a.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;first-look&quot;&gt;First look&lt;/h3&gt;

&lt;p&gt;Doing a little online research, you will find out that the firmware on this router had quite a &lt;a href=&quot;https://medium.com/tenable-techblog/gpon-home-gateway-rce-threatens-tens-of-thousands-users-c4a17fd25b97&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;bad&lt;/a&gt; &lt;a href=&quot;https://www.websec.ca/publication/Blog/backdoors-in-Zhone-GPON-2520-and-Alcatel-Lucent-I240Q&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;history&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There’s various blog posts showing that routers running on similar firmware were found to be vulnerable to unauthenticated RCE vulnerabilities, and had hardcoded Telnet backdoor accounts.&lt;/p&gt;

&lt;p&gt;The first thing I did, of course, is log into the web administration portal - there’s a sticker in the back of the router with the credentials, which seem device specific, which is good… Or so I thought - as it turns out there’s a known ‘superuser’ account for the web panel, which has a default password: AdminGPON / ALC#FGU&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/nokia-ont-back.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After fiddling with the web interface, trying to force the WiFi to use 802.11n and 40MHz bandwidth, I’ve noticed no difference. It was time to take a deeper dive.&lt;/p&gt;

&lt;p&gt;According to someone at &lt;a href=&quot;https://lafibre.info/cryptographie/probleme-dacces-en-ligne-de-commande-a-mon-ont/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;lafibre.info&lt;/a&gt; forum, Telnet access to this router was possible via the ONTUSER / SUGAR2A041 ‘backdoor’ account, before an update was deployed sometime in June 2018.&lt;/p&gt;

&lt;p&gt;I’ve tried the web account credentials as well as any backdoor credentials I was able to find, to no avail. The fact that Telnet access locks for 5 minutes every 3 failed attempts didn’t help as well.&lt;/p&gt;

&lt;p&gt;That’s when I’ve decided to take a look at the configuration backup and restore functionnality.&lt;/p&gt;

&lt;h3 id=&quot;analysing-the-backup-file&quot;&gt;Analysing the backup file&lt;/h3&gt;

&lt;p&gt;As the ‘AdminGPON’ user, you’re able to import and export the router configuration.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/nokia-ont-backup-restore.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As the exported config.cfg file wasn’t plain-text, I’ve tried looking for magic values, and binwalk was able to find something right away:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ binwalk config.cfg

DECIMAL     HEXADECIMAL   DESCRIPTION
--------------------------------------------------------------------
20          0x14          Zlib compressed data, default compression
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Being the lazy guy that I am, I’ve opened the file in a hex editor, stripped out the first 20 bytes, then pasted the hex dump in &lt;a href=&quot;https://gchq.github.io/CyberChef/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CyberChef&lt;/a&gt;, and a huge xml file showed up. Bingo!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/cyberchef-zlib.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Exploring the xml a bit, I was able to spot the Telnet credentials (or so I thought):&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;TelnetEnable&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RW&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;boolean&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;True&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/TelnetEnable&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;TelnetUserName&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ml=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;256&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RW&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;string&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;admin&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/TelnetUserName&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;TelnetPassword&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ml=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;256&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RW&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;string&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;OYdLWUVDdKQTPaCIeTqniA==&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ealgo=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ab&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/TelnetPassword&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Alrighty, now how do I crack/decrypt this admin password?&lt;/p&gt;

&lt;p&gt;Since this was 128-bit base64 encoded data, I tried MD5’ing known passwords, then I tried every other known hashing algorithm, but none of them gave me anything - so it has to be either salted or encryption.&lt;/p&gt;

&lt;p&gt;Exploring a little further, I’ve found another Telnet credential thingy:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;TelnetSshAccount.&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;n=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;TelnetSshAccount&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;staticObject&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;Enable&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RW&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;boolean&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;False&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/Enable&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;UserName&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ml=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;64&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RW&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;string&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/UserName&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;Password&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ml=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;64&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RW&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;string&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ealgo=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ab&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/Password&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/TelnetSshAccount.&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But it’s unused… Damn.&lt;/p&gt;

&lt;p&gt;Now that modifying the configuration file seemed more necessary, I tried to take a second look at the exported config.cfg.&lt;/p&gt;

&lt;h3 id=&quot;modifying-the-backup-file&quot;&gt;Modifying the backup file&lt;/h3&gt;

&lt;p&gt;I kept exporting backup files while changing the router settings to regenerate different files for me to look at.&lt;/p&gt;

&lt;p&gt;After a few comparisons with the not so naked eye (I wear glasses), I was able to tell that a single 32-bit value in the header was always changing radically, so this must be a checksum of sorts.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/cfg-header-comparison.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now before guessing what’s being checksumed and how, I first need to know where the zlib data ends and if there’s something else after it.&lt;/p&gt;

&lt;p&gt;So I tried recreating the compressed chunk, which was pretty trivial, again thanks to CyberChef.&lt;/p&gt;

&lt;p&gt;It turns out there’s about 300 bytes after it that are unknown, but still, CRC32 on the deflated data gave the exact value at offset 8, which was in big endian. Yay!&lt;/p&gt;

&lt;p&gt;Now the null bytes made more sense, and it was clear to me that the other values next to the checksum must be positive integers.&lt;/p&gt;

&lt;p&gt;Soon after, I was able to figure out that the first one (+4) was the length of the deflated data, while the second one (+C) was the size of the xml file.&lt;/p&gt;

&lt;p&gt;Since in all the config.cfg files that I’ve exported, the rest of the bytes were static, this seemed enough for me to generate my own backup file, and as expected, uploading my crafted config.cfg worked!&lt;/p&gt;

&lt;p&gt;Here’s a &lt;a href=&quot;https://gist.github.com/thedroidgeek/80c379aa43b71015d71da130f85a435a&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;simple python script&lt;/a&gt; I’ve made for this purpose, for those interested.&lt;/p&gt;

&lt;h3 id=&quot;unlocking-telnet-and-ssh-access&quot;&gt;Unlocking Telnet and SSH access&lt;/h3&gt;

&lt;p&gt;So I took the password that I’ve set for the the ‘AdminGPON’ web account from:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;WebAccount.&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;n=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;WebAccount&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;staticObject&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;Enable&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RW&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;boolean&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;True&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/Enable&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;Priority&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;max=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;10&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;min=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RW&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;unsignedInt&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/Priority&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;UserName&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ml=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;64&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RW&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;string&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;AdminGPON&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/UserName&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;Password&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ml=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;64&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RW&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;string&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[REDACTED]&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ealgo=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ab&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/Password&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;PresetPassword&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ml=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;64&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;R&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;string&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;xEKUBYh1yT50dQFNwAr/5A==&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ealgo=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ab&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/PresetPassword&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/WebAccount.&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And used it for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TelnetPassword&lt;/code&gt; config node, but logging in as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;admin&lt;/code&gt; still didn’t work.&lt;/p&gt;

&lt;p&gt;Since I can now generate these password hashes (or whatever they are) also, I tried changing my ‘AdminGPON’ password and comparing the resulting value with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TelnetPassword&lt;/code&gt; one (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OYdLWUVDdKQTPaCIeTqniA==&lt;/code&gt;), and after a couple of tries, I’ve realized that the password was simply: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;admin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since we all know that admin:admin is the first login combo that I, and everyone else, use, when trying to login on any panel that’s not ours, it seems like they now ignore these credentials.&lt;/p&gt;

&lt;p&gt;But don’t worry, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TelnetSshAccount&lt;/code&gt; comes to the rescue:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;TelnetSshAccount.&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;n=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;TelnetSshAccount&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;staticObject&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;Enable&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RW&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;boolean&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;True&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/Enable&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;UserName&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ml=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;64&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RW&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;string&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;hexdd&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/UserName&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;Password&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ml=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;64&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rw=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RW&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;t=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;string&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[REDACTED]&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ealgo=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ab&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/Password&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/TelnetSshAccount.&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ve set the ‘Enable’ flag to true, chose a username, and copied my password, and lo and behold, after a reboot, we have root!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/root-nokia-ont.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Stay tuned for more. :)&lt;/p&gt;</content><author><name>Sami ALAOUI KENDIL</name></author><category term="reversing" /><summary type="html">Context As we recently upgraded our home internet to try out Maroc Telecom’s 100mbps fiber offer, I’ve noticed that the Nokia router they installed had horrible Wi-Fi speed - the max I could to get standing next to it was around 60mbps down, while in the opposite room, the speed was always under 10mbps. What’s interesting is the fact that it had decent range - I get full bars most of the time, and my Wi-Fi adapter reports a 300mbps data rate. This got me intrigued, so I tried to take a look at what’s running inside this thing. First look Doing a little online research, you will find out that the firmware on this router had quite a bad history. There’s various blog posts showing that routers running on similar firmware were found to be vulnerable to unauthenticated RCE vulnerabilities, and had hardcoded Telnet backdoor accounts. The first thing I did, of course, is log into the web administration portal - there’s a sticker in the back of the router with the credentials, which seem device specific, which is good… Or so I thought - as it turns out there’s a known ‘superuser’ account for the web panel, which has a default password: AdminGPON / ALC#FGU After fiddling with the web interface, trying to force the WiFi to use 802.11n and 40MHz bandwidth, I’ve noticed no difference. It was time to take a deeper dive. According to someone at lafibre.info forum, Telnet access to this router was possible via the ONTUSER / SUGAR2A041 ‘backdoor’ account, before an update was deployed sometime in June 2018. I’ve tried the web account credentials as well as any backdoor credentials I was able to find, to no avail. The fact that Telnet access locks for 5 minutes every 3 failed attempts didn’t help as well. That’s when I’ve decided to take a look at the configuration backup and restore functionnality. Analysing the backup file As the ‘AdminGPON’ user, you’re able to import and export the router configuration. As the exported config.cfg file wasn’t plain-text, I’ve tried looking for magic values, and binwalk was able to find something right away: $ binwalk config.cfg DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------- 20 0x14 Zlib compressed data, default compression Being the lazy guy that I am, I’ve opened the file in a hex editor, stripped out the first 20 bytes, then pasted the hex dump in CyberChef, and a huge xml file showed up. Bingo! Exploring the xml a bit, I was able to spot the Telnet credentials (or so I thought): &amp;lt;TelnetEnable rw=&quot;RW&quot; t=&quot;boolean&quot; v=&quot;True&quot;&amp;gt;&amp;lt;/TelnetEnable&amp;gt; &amp;lt;TelnetUserName ml=&quot;256&quot; rw=&quot;RW&quot; t=&quot;string&quot; v=&quot;admin&quot;&amp;gt;&amp;lt;/TelnetUserName&amp;gt; &amp;lt;TelnetPassword ml=&quot;256&quot; rw=&quot;RW&quot; t=&quot;string&quot; v=&quot;OYdLWUVDdKQTPaCIeTqniA==&quot; ealgo=&quot;ab&quot;&amp;gt;&amp;lt;/TelnetPassword&amp;gt; Alrighty, now how do I crack/decrypt this admin password? Since this was 128-bit base64 encoded data, I tried MD5’ing known passwords, then I tried every other known hashing algorithm, but none of them gave me anything - so it has to be either salted or encryption. Exploring a little further, I’ve found another Telnet credential thingy: &amp;lt;TelnetSshAccount. n=&quot;TelnetSshAccount&quot; t=&quot;staticObject&quot;&amp;gt; &amp;lt;Enable rw=&quot;RW&quot; t=&quot;boolean&quot; v=&quot;False&quot;&amp;gt;&amp;lt;/Enable&amp;gt; &amp;lt;UserName ml=&quot;64&quot; rw=&quot;RW&quot; t=&quot;string&quot; v=&quot;&quot;&amp;gt;&amp;lt;/UserName&amp;gt; &amp;lt;Password ml=&quot;64&quot; rw=&quot;RW&quot; t=&quot;string&quot; v=&quot;&quot; ealgo=&quot;ab&quot;&amp;gt;&amp;lt;/Password&amp;gt; &amp;lt;/TelnetSshAccount.&amp;gt; But it’s unused… Damn. Now that modifying the configuration file seemed more necessary, I tried to take a second look at the exported config.cfg. Modifying the backup file I kept exporting backup files while changing the router settings to regenerate different files for me to look at. After a few comparisons with the not so naked eye (I wear glasses), I was able to tell that a single 32-bit value in the header was always changing radically, so this must be a checksum of sorts. Now before guessing what’s being checksumed and how, I first need to know where the zlib data ends and if there’s something else after it. So I tried recreating the compressed chunk, which was pretty trivial, again thanks to CyberChef. It turns out there’s about 300 bytes after it that are unknown, but still, CRC32 on the deflated data gave the exact value at offset 8, which was in big endian. Yay! Now the null bytes made more sense, and it was clear to me that the other values next to the checksum must be positive integers. Soon after, I was able to figure out that the first one (+4) was the length of the deflated data, while the second one (+C) was the size of the xml file. Since in all the config.cfg files that I’ve exported, the rest of the bytes were static, this seemed enough for me to generate my own backup file, and as expected, uploading my crafted config.cfg worked! Here’s a simple python script I’ve made for this purpose, for those interested. Unlocking Telnet and SSH access So I took the password that I’ve set for the the ‘AdminGPON’ web account from: &amp;lt;WebAccount. n=&quot;WebAccount&quot; t=&quot;staticObject&quot;&amp;gt; &amp;lt;Enable rw=&quot;RW&quot; t=&quot;boolean&quot; v=&quot;True&quot;&amp;gt;&amp;lt;/Enable&amp;gt; &amp;lt;Priority max=&quot;10&quot; min=&quot;1&quot; rw=&quot;RW&quot; t=&quot;unsignedInt&quot; v=&quot;1&quot;&amp;gt;&amp;lt;/Priority&amp;gt; &amp;lt;UserName ml=&quot;64&quot; rw=&quot;RW&quot; t=&quot;string&quot; v=&quot;AdminGPON&quot;&amp;gt;&amp;lt;/UserName&amp;gt; &amp;lt;Password ml=&quot;64&quot; rw=&quot;RW&quot; t=&quot;string&quot; v=&quot;[REDACTED]&quot; ealgo=&quot;ab&quot;&amp;gt;&amp;lt;/Password&amp;gt; &amp;lt;PresetPassword ml=&quot;64&quot; rw=&quot;R&quot; t=&quot;string&quot; v=&quot;xEKUBYh1yT50dQFNwAr/5A==&quot; ealgo=&quot;ab&quot;&amp;gt;&amp;lt;/PresetPassword&amp;gt; &amp;lt;/WebAccount.&amp;gt; And used it for TelnetPassword config node, but logging in as admin still didn’t work. Since I can now generate these password hashes (or whatever they are) also, I tried changing my ‘AdminGPON’ password and comparing the resulting value with the TelnetPassword one (OYdLWUVDdKQTPaCIeTqniA==), and after a couple of tries, I’ve realized that the password was simply: admin. Since we all know that admin:admin is the first login combo that I, and everyone else, use, when trying to login on any panel that’s not ours, it seems like they now ignore these credentials. But don’t worry, TelnetSshAccount comes to the rescue: &amp;lt;TelnetSshAccount. n=&quot;TelnetSshAccount&quot; t=&quot;staticObject&quot;&amp;gt; &amp;lt;Enable rw=&quot;RW&quot; t=&quot;boolean&quot; v=&quot;True&quot;&amp;gt;&amp;lt;/Enable&amp;gt; &amp;lt;UserName ml=&quot;64&quot; rw=&quot;RW&quot; t=&quot;string&quot; v=&quot;hexdd&quot;&amp;gt;&amp;lt;/UserName&amp;gt; &amp;lt;Password ml=&quot;64&quot; rw=&quot;RW&quot; t=&quot;string&quot; v=&quot;[REDACTED]&quot; ealgo=&quot;ab&quot;&amp;gt;&amp;lt;/Password&amp;gt; &amp;lt;/TelnetSshAccount.&amp;gt; I’ve set the ‘Enable’ flag to true, chose a username, and copied my password, and lo and behold, after a reboot, we have root! Stay tuned for more. :)</summary></entry><entry><title type="html">1-click RCE with Skype Web Plugin and Qt apps</title><link href="https://0x44.cc/infosec/2019/05/28/skype-web-plugin-ez-rce.html" rel="alternate" type="text/html" title="1-click RCE with Skype Web Plugin and Qt apps" /><published>2019-05-28T00:00:00+00:00</published><updated>2019-05-28T00:00:00+00:00</updated><id>https://0x44.cc/infosec/2019/05/28/skype-web-plugin-ez-rce</id><content type="html" xml:base="https://0x44.cc/infosec/2019/05/28/skype-web-plugin-ez-rce.html">&lt;h3 id=&quot;context&quot;&gt;Context&lt;/h3&gt;

&lt;p&gt;Earlier this year, I’ve heard that you could send links with custom URI schemes through Discord, that can trigger without the user’s confirmation when using desktop clients.&lt;/p&gt;

&lt;p&gt;I’ve been experimenting with URI schemes ever since, I wanted to see how far I can push it in terms of exploitability, and I’ve found that you could do all sort of fun things in windows - stuff like opening the action center or the task switcher, etc. But I have quickly lost interest however, since I’ve realized there was a bunch of filters that Discord has in place, likely due to various reports from researchers, that prevent a lot of the known ‘malicious’ scheme links from triggering (though I still don’t understand Discord’s decision of not simply using a whitelist for schemes instead of adding regex filters ¯\_(ツ)_/¯).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Update&lt;/em&gt;&lt;/strong&gt;: Discord has now started &lt;a href=&quot;https://i.0x44.cc/b/discord-proto-warn.png&quot; target=&quot;_blank&quot;&gt;warning&lt;/a&gt; people when clicking on protocol links.&lt;/p&gt;

&lt;p&gt;A couple of months later, it hit the headlines that Electronic Arts’ digital distribution platform, Origin, was found to be vulnerable to an RCE through a URI scheme. This was due to an AngularJS template injection, that was met with some bad implementation that exposed Qt’s common desktop services to JavaScript - more on this &lt;a href=&quot;https://zeropwn.github.io/2019-05-13-xss-to-rce/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;a href=&quot;https://zeropwn.github.io/2019-05-22-fun-with-uri-handlers/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;second blog post&lt;/a&gt; from the same researcher emerged, a couple of days later, where he found another ‘flaw’ in Origin that can be leveraged for RCE, but unlike the first one, this one wasn’t exactly new - it was merely Qt’s plugin feature which can be abused with the right conditions to load arbitrary .dll files through SMB shares …&lt;/p&gt;

&lt;p&gt;Following that blog post, I’ve re-enumerated the URL protocols on my machine (using &lt;a href=&quot;https://github.com/ChiChou/LookForSchemes&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;this&lt;/a&gt;), and went back to fiddling with URI schemes once more, and soon enough, I was able to find an interesting attack vector …&lt;/p&gt;

&lt;h3 id=&quot;qt-plugin-injection&quot;&gt;Qt plugin injection&lt;/h3&gt;

&lt;p&gt;According to Wikipedia, Qt is a free and open-source widget toolkit for creating GUIs and cross-platform applications, and it seems to be used by quite a lot of apps - a simple explorer search for the Qt core module revealed at least 9 64-bit apps currently installed on my machine:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/qtcoredll-explorer-search.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Most of the modern Qt apps you will find will support a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-platformpluginpath&lt;/code&gt; commandline option, which specifies a path to start with while loading plugins. What’s interesting here is the fact that SMB shares are also supported, which means one can load plugins remotely.&lt;/p&gt;

&lt;p&gt;So the question here would be, how can we start a Qt app with this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-platformpluginpath&lt;/code&gt; argument so we can have it load our malicious plugin?&lt;/p&gt;

&lt;p&gt;Yes, you guessed that right, URI schemes. In order for us to be able to launch an app with our custom input in the commandline, it has to have a registered custom URI handler so we can launch it via a webpage and have the URI be sent as an argument, here’s what that looks like on the registry:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/fdm-regedit.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://i.0x44.cc/b/fdm-regedit2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;However, there’s a slight problem with this approach (as explained in the second blog post I’ve mentionned earlier), and that’s the fact that modern browsers tend to apply URL encoding to the URI, before the app gets executed, which reduces our chance of pulling off the argument injection, since in most cases we would need to inject a double-quote to break out of the URI argument.&lt;/p&gt;

&lt;p&gt;This is where the Skype Web Plugin comes to play …&lt;/p&gt;

&lt;h3 id=&quot;skype-web-plugin&quot;&gt;Skype Web Plugin&lt;/h3&gt;

&lt;p&gt;When Skype for Web first launched, you could use Skype for instant messaging and share multimedia files, but not as a VoIP tool. To make voice and video calls in most supported browsers, people had to install a plugin.&lt;/p&gt;

&lt;p&gt;Doing a quick search online revealed the last available version of the plugin was 7.32.6.278, which was released sometime in 2017, but is still obtainable via their official CDN: &lt;a href=&quot;https://swx.cdn.skype.com/plugin/7.32.6.278/SkypeWebPlugin.msi&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://swx.cdn.skype.com/plugin/7.32.6.278/SkypeWebPlugin.msi&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After Microsoft introduced plugin-free Skype for Web for their supported browsers, they ditched the plugin and dropped support for Internet Explorer. However, the plugin remains available in systems where previously installed, with the only way to get rid of it being a manual uninstall.&lt;/p&gt;

&lt;p&gt;The ‘Skype Web Plugin’ registers a custom URI handler: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;swx&lt;/code&gt;, which launches &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SkypeShell.exe&lt;/code&gt;, which is what looks like to be some sort of Internet Explorer shell, which means that it uses IE’s rendering engine (mshtml.dll) to open webpages.&lt;/p&gt;

&lt;p&gt;To my surpise, this thing will open any HTTP URL, all you need to do is replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http(s)&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;swx&lt;/code&gt;, and you have a clickable link that forcefully renders your website using mshtml.dll, but here’s the real problem …&lt;/p&gt;

&lt;p&gt;First of all, protected mode is off by default, so this may potentially allow for more attack vectors that I’m currently not aware of, since I’m not familiar with what protected mode exactly even does, but this certainly doesn’t sound good.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/skypeshell-no-protected-mode.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Secondly (which is what’s more relevant to us), I can load any link with a custom URI from within the shell without having the user to confirm or know anything.&lt;/p&gt;

&lt;p&gt;For reference, here’s what trying to exploit a Qt app using plugin injection would prompt for, when running IE (11.116.18362.0) normally:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/ie-scheme-prompt.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So not only can we successfully inject arguments regardless of what browser the victim uses, we can also spawn a dosen of apps through URIs simultaneously.&lt;/p&gt;

&lt;h3 id=&quot;the-proof-of-concept&quot;&gt;The Proof of Concept&lt;/h3&gt;

&lt;p&gt;Now that we’ve got a clear idea of the attack vector we will be using, we’ll start on the implementation.&lt;/p&gt;

&lt;p&gt;The first thing we would need to do is find target Qt apps to exploit, which are essentially apps that allow loading plugins (nearly all of them do), and that have a registered URI handler.&lt;/p&gt;

&lt;p&gt;I’ve found 2 of them already installed on my machine:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;//freedownloadmanager.org&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Free Download Manager&lt;/a&gt; - The 2nd Google result when searching ‘download manager’.&lt;/li&gt;
  &lt;li&gt;And &lt;a href=&quot;//origin.com&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Origin&lt;/a&gt;, of course.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve tried to find more apps that meet the 2 conditions to verify my claims, and sure enough with little to no effort I was able to find the &lt;a href=&quot;https://github.com/transmission/transmission&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Transmission&lt;/a&gt; torrent client, which I’m also adding to the list.&lt;/p&gt;

&lt;p&gt;Like I said earlier, this is not exactly a new thing, 2 months ago someone wrote &lt;a href=&quot;https://www.zerodayinitiative.com/blog/2019/4/3/loading-up-a-pair-of-qt-bugs-detailing-cve-2019-1636-and-cve-2019-6739&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;this article&lt;/a&gt; explaining how Malwarebytes and Cisco Webex Teams (both of which are programs I’ve used before) were found to be vulnerable to this attack, but what’s interesting here, is the stealthiness and reliability that we can accomplish with the help of the Skype Web Plugin …&lt;/p&gt;

&lt;p&gt;So I started by simply spamming an .html file with iframes that have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;calculator://&lt;/code&gt; as a src attribute:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'calculator://'&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;frameborder=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'calculator://'&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;frameborder=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And as expected, I soon started to hear my CPU fan …&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.0x44.cc/b/calcspam.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So at the very least this can be used for DoS by spam launching resource heavy apps, so far so good.&lt;/p&gt;

&lt;p&gt;Now on to the code execution…&lt;/p&gt;

&lt;p&gt;I’ve fired up Visual Studio and made a quick DLL that shows a MessageBox on attach with the process file name as a message.&lt;/p&gt;

&lt;p&gt;To make our .dll loadable by Qt, we have to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.qtmetad&lt;/code&gt; section with valid plugin metadata:&lt;/strong&gt;
We make VS generate an empty one that we’ll fill out manually with a hex editor using content from the original plugin.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Find a plugin we can override:&lt;/strong&gt;
There’s this one called the Windows Integration Plugin (qwindows.dll) which all apps seem to require in order to run on Windows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make this stealthy, I’ve added an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExitProcess()&lt;/code&gt; right after the DLL is done executing to prevent the target app from showing up, so as of this stage there’s no visible interruption (besides the Skype shell) and the user won’t notice anything.&lt;/p&gt;

&lt;p&gt;Now all that’s left for us to have is an SMB share that will host our malicous plugins.&lt;/p&gt;

&lt;p&gt;Here’s a detailed video of the PoC in action, from crafting the .dll files to the MessageBox on the 3 apps:&lt;/p&gt;

&lt;p style=&quot;position: relative; padding: 30px 0px 57% 0px; height: 0; overflow: hidden;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/xVZU-2Y0Pzc&quot; width=&quot;100%&quot; height=&quot;100%&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;display: block; margin: 0px auto; position: absolute; top: 0; left: 0;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;

&lt;h3 id=&quot;dos-bonus&quot;&gt;DoS Bonus&lt;/h3&gt;

&lt;p&gt;I’ve come across this URI &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ms-cxh-full://&lt;/code&gt; that seems to be the fullscreen version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ms-cxh://&lt;/code&gt; which is something used in Microsoft account setup, but what’s interesting is that this one can cause a black screen that can’t be dismissed, forcing the user to sign out/reboot.
&lt;a href=&quot;ms-cxh-full://&quot;&gt;⚠️ Try at your own risk ⚠️&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Update (10/2020)&lt;/em&gt;&lt;/strong&gt;: Since I’ve noticed a recent surge in the malicious usage of this particular URI scheme, I’ve added simple steps you can follow, in case you need to recover your Windows 10 session, after an unintended click:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Press Ctrl + Shift + Esc to invoke the Task Manager.&lt;/li&gt;
  &lt;li&gt;You can use Alt + Tab to peek at open windows, but make sure to keep the Task Manager window focused, after you do so.&lt;/li&gt;
  &lt;li&gt;If the Task Manager is in &lt;a href=&quot;https://i.0x44.cc/b/taskmgr-simple.png&quot; target=&quot;_blank&quot;&gt;‘simple view’&lt;/a&gt;: Hit Tab, then Space - so that it switches to &lt;a href=&quot;https://i.0x44.cc/b/taskmgr-expand.png&quot; target=&quot;_blank&quot;&gt;‘expanded view’&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Blindly type the following on your keyboard (including the space): &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user oobe&lt;/code&gt;, in order to highlight the offending process.&lt;/li&gt;
  &lt;li&gt;Hit the Delete keyboard key, to end it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;update-062019&quot;&gt;Update (06/2019)&lt;/h3&gt;

&lt;p&gt;Microsoft released the &lt;a href=&quot;https://support.microsoft.com/en-us/help/4503293/windows-10-update-kb4503293&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;KB4503293&lt;/a&gt; cumulative update for Windows 10 version 1903 on June 11 of 2019, which updated Internet Explorer from .116 to .175, which includes sanitization for URI scheme links to prevent command-line argument injection:&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;img src=&quot;https://i.0x44.cc/b/ie-scheme-prompt-new.png&quot; /&gt; Internet Explorer 11.175.18362.0
&lt;/p&gt;

&lt;p&gt;As a result, this attack is no longer feasible on an up-to-date Windows system.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/thedroidgeek/0x44.cc/commits/master/_posts/2019-05-28-skype-web-plugin-ez-rce.md&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;(edited)&lt;/a&gt;&lt;/p&gt;</content><author><name>Sami ALAOUI KENDIL</name></author><category term="infosec" /><summary type="html">Context Earlier this year, I’ve heard that you could send links with custom URI schemes through Discord, that can trigger without the user’s confirmation when using desktop clients. I’ve been experimenting with URI schemes ever since, I wanted to see how far I can push it in terms of exploitability, and I’ve found that you could do all sort of fun things in windows - stuff like opening the action center or the task switcher, etc. But I have quickly lost interest however, since I’ve realized there was a bunch of filters that Discord has in place, likely due to various reports from researchers, that prevent a lot of the known ‘malicious’ scheme links from triggering (though I still don’t understand Discord’s decision of not simply using a whitelist for schemes instead of adding regex filters ¯\_(ツ)_/¯). Update: Discord has now started warning people when clicking on protocol links. A couple of months later, it hit the headlines that Electronic Arts’ digital distribution platform, Origin, was found to be vulnerable to an RCE through a URI scheme. This was due to an AngularJS template injection, that was met with some bad implementation that exposed Qt’s common desktop services to JavaScript - more on this here. A second blog post from the same researcher emerged, a couple of days later, where he found another ‘flaw’ in Origin that can be leveraged for RCE, but unlike the first one, this one wasn’t exactly new - it was merely Qt’s plugin feature which can be abused with the right conditions to load arbitrary .dll files through SMB shares … Following that blog post, I’ve re-enumerated the URL protocols on my machine (using this), and went back to fiddling with URI schemes once more, and soon enough, I was able to find an interesting attack vector … Qt plugin injection According to Wikipedia, Qt is a free and open-source widget toolkit for creating GUIs and cross-platform applications, and it seems to be used by quite a lot of apps - a simple explorer search for the Qt core module revealed at least 9 64-bit apps currently installed on my machine: Most of the modern Qt apps you will find will support a -platformpluginpath commandline option, which specifies a path to start with while loading plugins. What’s interesting here is the fact that SMB shares are also supported, which means one can load plugins remotely. So the question here would be, how can we start a Qt app with this -platformpluginpath argument so we can have it load our malicious plugin? Yes, you guessed that right, URI schemes. In order for us to be able to launch an app with our custom input in the commandline, it has to have a registered custom URI handler so we can launch it via a webpage and have the URI be sent as an argument, here’s what that looks like on the registry: However, there’s a slight problem with this approach (as explained in the second blog post I’ve mentionned earlier), and that’s the fact that modern browsers tend to apply URL encoding to the URI, before the app gets executed, which reduces our chance of pulling off the argument injection, since in most cases we would need to inject a double-quote to break out of the URI argument. This is where the Skype Web Plugin comes to play … Skype Web Plugin When Skype for Web first launched, you could use Skype for instant messaging and share multimedia files, but not as a VoIP tool. To make voice and video calls in most supported browsers, people had to install a plugin. Doing a quick search online revealed the last available version of the plugin was 7.32.6.278, which was released sometime in 2017, but is still obtainable via their official CDN: https://swx.cdn.skype.com/plugin/7.32.6.278/SkypeWebPlugin.msi After Microsoft introduced plugin-free Skype for Web for their supported browsers, they ditched the plugin and dropped support for Internet Explorer. However, the plugin remains available in systems where previously installed, with the only way to get rid of it being a manual uninstall. The ‘Skype Web Plugin’ registers a custom URI handler: swx, which launches SkypeShell.exe, which is what looks like to be some sort of Internet Explorer shell, which means that it uses IE’s rendering engine (mshtml.dll) to open webpages. To my surpise, this thing will open any HTTP URL, all you need to do is replace http(s) with swx, and you have a clickable link that forcefully renders your website using mshtml.dll, but here’s the real problem … First of all, protected mode is off by default, so this may potentially allow for more attack vectors that I’m currently not aware of, since I’m not familiar with what protected mode exactly even does, but this certainly doesn’t sound good. Secondly (which is what’s more relevant to us), I can load any link with a custom URI from within the shell without having the user to confirm or know anything. For reference, here’s what trying to exploit a Qt app using plugin injection would prompt for, when running IE (11.116.18362.0) normally: So not only can we successfully inject arguments regardless of what browser the victim uses, we can also spawn a dosen of apps through URIs simultaneously. The Proof of Concept Now that we’ve got a clear idea of the attack vector we will be using, we’ll start on the implementation. The first thing we would need to do is find target Qt apps to exploit, which are essentially apps that allow loading plugins (nearly all of them do), and that have a registered URI handler. I’ve found 2 of them already installed on my machine: Free Download Manager - The 2nd Google result when searching ‘download manager’. And Origin, of course. I’ve tried to find more apps that meet the 2 conditions to verify my claims, and sure enough with little to no effort I was able to find the Transmission torrent client, which I’m also adding to the list. Like I said earlier, this is not exactly a new thing, 2 months ago someone wrote this article explaining how Malwarebytes and Cisco Webex Teams (both of which are programs I’ve used before) were found to be vulnerable to this attack, but what’s interesting here, is the stealthiness and reliability that we can accomplish with the help of the Skype Web Plugin … So I started by simply spamming an .html file with iframes that have calculator:// as a src attribute: &amp;lt;iframe src='calculator://' height=&quot;0&quot; frameborder=&quot;0&quot;&amp;gt;&amp;lt;/iframe&amp;gt; &amp;lt;iframe src='calculator://' height=&quot;0&quot; frameborder=&quot;0&quot;&amp;gt;&amp;lt;/iframe&amp;gt; ... And as expected, I soon started to hear my CPU fan … So at the very least this can be used for DoS by spam launching resource heavy apps, so far so good. Now on to the code execution… I’ve fired up Visual Studio and made a quick DLL that shows a MessageBox on attach with the process file name as a message. To make our .dll loadable by Qt, we have to: Add a .qtmetad section with valid plugin metadata: We make VS generate an empty one that we’ll fill out manually with a hex editor using content from the original plugin. Find a plugin we can override: There’s this one called the Windows Integration Plugin (qwindows.dll) which all apps seem to require in order to run on Windows. To make this stealthy, I’ve added an ExitProcess() right after the DLL is done executing to prevent the target app from showing up, so as of this stage there’s no visible interruption (besides the Skype shell) and the user won’t notice anything. Now all that’s left for us to have is an SMB share that will host our malicous plugins. Here’s a detailed video of the PoC in action, from crafting the .dll files to the MessageBox on the 3 apps: DoS Bonus I’ve come across this URI ms-cxh-full:// that seems to be the fullscreen version of ms-cxh:// which is something used in Microsoft account setup, but what’s interesting is that this one can cause a black screen that can’t be dismissed, forcing the user to sign out/reboot. ⚠️ Try at your own risk ⚠️ Update (10/2020): Since I’ve noticed a recent surge in the malicious usage of this particular URI scheme, I’ve added simple steps you can follow, in case you need to recover your Windows 10 session, after an unintended click: Press Ctrl + Shift + Esc to invoke the Task Manager. You can use Alt + Tab to peek at open windows, but make sure to keep the Task Manager window focused, after you do so. If the Task Manager is in ‘simple view’: Hit Tab, then Space - so that it switches to ‘expanded view’. Blindly type the following on your keyboard (including the space): user oobe, in order to highlight the offending process. Hit the Delete keyboard key, to end it. Update (06/2019) Microsoft released the KB4503293 cumulative update for Windows 10 version 1903 on June 11 of 2019, which updated Internet Explorer from .116 to .175, which includes sanitization for URI scheme links to prevent command-line argument injection: Internet Explorer 11.175.18362.0 As a result, this attack is no longer feasible on an up-to-date Windows system. (edited)</summary></entry></feed>