<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>GDB on Rebel Zhangs Blog</title>
        <link>https://rebel1725.codeberg.page/blog/de/tags/gdb/</link>
        <description>Recent content in GDB on Rebel Zhangs Blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>de-DE</language>
        <managingEditor>rebel1725@tilde.club (Rebel Zhang)</managingEditor>
        <webMaster>rebel1725@tilde.club (Rebel Zhang)</webMaster>
        <lastBuildDate>Wed, 27 May 2026 23:56:34 +0800</lastBuildDate><atom:link href="https://rebel1725.codeberg.page/blog/de/tags/gdb/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>Ein Reverse-Engineering-Beispiel mit GDB und Iaito/Radare2</title>
            <link>https://rebel1725.codeberg.page/blog/de/post/a-reverse-engineering-example-with-gdb-and-iaito-radare2/</link>
            <pubDate>Wed, 27 May 2026 23:56:34 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/de/post/a-reverse-engineering-example-with-gdb-and-iaito-radare2/</guid>
            <description>&lt;p&gt;In den letzten Wochen habe ich Reverse Engineering gelernt und einen &lt;a class=&#34;link&#34; href=&#34;../a-brief-introduction-into-reverse-engineering/&#34; &gt;Blogbeitrag geschrieben&lt;/a&gt;, um meine allererste Erfahrung zu teilen. Inzwischen arbeite ich mich etwas weiter vor, löse eine CTF-Herausforderung mit einer Kombination aus statischer Analyse und dynamischer Analyse, und ich fand, dass sich das hervorragend eignet, um Reverse Engineering noch etwas weiter zu erklären.&lt;/p&gt;&#xA;&lt;p&gt;Ich hatte zuvor vor, einen Artikel über dynamische Analyse mit GDB zu schreiben. Allerdings stellte ich fest, dass diese Herausforderung ebenfalls ein sehr gutes Beispiel ist, um GDB zu erklären. Um diese Aufgabe zu lösen, werde ich ausserdem noch ein weiteres Werkzeug verwenden, &lt;strong&gt;iaito&lt;/strong&gt;, die grafische Oberfläche von radare2.&lt;/p&gt;&#xA;&lt;h2 id=&#34;die-herausforderung&#34;&gt;Die Herausforderung&#xA;&lt;/h2&gt;&lt;p&gt;cIMG ist gewissermassen ein Bildformat, das dazu dient, ein Bild aus Zeichen in unterschiedlichen Farben im Terminal darzustellen. Es besteht aus:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;der magischen Zahl, nämlich &lt;code&gt;cIMG&lt;/code&gt;;&lt;/li&gt;&#xA;&lt;li&gt;der Versionsnummer;&lt;/li&gt;&#xA;&lt;li&gt;Breite und Höhe;&lt;/li&gt;&#xA;&lt;li&gt;den Daten, wobei jedes Pixel R, G, B und das ASCII-Zeichen enthält.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Bei dieser Herausforderung geht es darum, einem ausführbaren Programm eine cIMG-Datei zu übergeben, das die Flag nur dann ausgibt, wenn die cIMG bestimmte Bedingungen erfüllt.&lt;/p&gt;&#xA;&lt;h2 id=&#34;der-quelltext&#34;&gt;Der Quelltext&#xA;&lt;/h2&gt;&lt;p&gt;Den &lt;a class=&#34;link&#34; href=&#34;https://raw.githubusercontent.com/pwncollege/intro-to-cybersecurity-dojo/refs/heads/main/reverse-engineering/cimg-framebuffer-mini-c/_0/cimg.c&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Quelltext&lt;/a&gt; der Herausforderung erhalten Sie hier. Dieser Quelltext scheint unter der BSD-2-Klausel-Lizenz zu stehen.&lt;/p&gt;&#xA;&lt;p&gt;Kompilieren Sie ihn mit GCC:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;ed5rc5&#34;&#34; data-lang=&#34;id=&#34;ed5rc5&#34;&#34;&gt;$ gcc -O3 challenge.c -o challenge&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Öffnen Sie Python und erstellen Sie eine Beispiel-cIMG-Datei:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;lk61ho&#34;&#34; data-lang=&#34;id=&#34;lk61ho&#34;&#34;&gt;$ python3&#xA;Python 3.13.5 (Jun 25 2025, 18:55:22) [GCC 14.2.0] on linux&#xA;Type &amp;#34;help&amp;#34;, &amp;#34;copyright&amp;#34;, &amp;#34;credits&amp;#34; or &amp;#34;license&amp;#34; for more information.&#xA;&amp;gt;&amp;gt;&amp;gt; with open(&amp;#34;example.cimg&amp;#34;, &amp;#34;wb&amp;#34;) as file:&#xA;...     file.write(b&amp;#34;cIMG\x02\0\x0a\x0a&amp;#34;)&#xA;...     file.write(b&amp;#34;\x50&amp;#34;*(10*10*4))&#xA;...     &#xA;8&#xA;400&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Verwenden Sie das Binärprogramm der Herausforderung, um die Beispiel-cIMG-Datei zu öffnen:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;rpl7sh&#34;&#34; data-lang=&#34;id=&#34;rpl7sh&#34;&#34;&gt;user@learnaarch64asm:~$ ./challenge ./example.cimg &#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Diese Datei gibt etwas aus, aber nicht die Flag.&lt;/p&gt;&#xA;&lt;h2 id=&#34;statische-analyse&#34;&gt;Statische Analyse&#xA;&lt;/h2&gt;&lt;p&gt;Wir müssen eine cIMG-Datei erstellen, die &lt;em&gt;die Flag ausgibt&lt;/em&gt;. Lassen Sie uns zunächst eine statische Analyse durchführen.&lt;/p&gt;&#xA;&lt;p&gt;Öffnen Sie die Datei in iaito. Führen Sie eine &lt;code&gt;aaa&lt;/code&gt;-Analyse aus und öffnen Sie den Graphen der Funktion &lt;code&gt;main&lt;/code&gt;. Sie erhalten:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://rebel1725.codeberg.page/blog/pic_20260527_001_417726312315916099.png&#34;&#xA;&#x9;width=&#34;3532&#34;&#xA;&#x9;height=&#34;5056&#34;&#xA;&#x9;loading=&#34;lazy&#34;&#xA;&#x9;&#xA;&#x9;&#x9;alt=&#34;den Graphen der Funktion main&#34;&#xA;&#x9;&#xA;&#x9;&#xA;&#x9;&#x9;class=&#34;gallery-image&#34; &#xA;&#x9;&#x9;data-flex-grow=&#34;69&#34;&#xA;&#x9;&#x9;data-flex-basis=&#34;167px&#34;&#xA;&#x9;&#xA;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Wir finden das Einlesen des Dateikopfs bei &lt;code&gt;0x00000cac&lt;/code&gt;, die Prüfung der magischen Zahl bei &lt;code&gt;0x00000cc4&lt;/code&gt;, die Versionsprüfung bei &lt;code&gt;0x00000cd0&lt;/code&gt; sowie das Einlesen von Breite und Höhe bei &lt;code&gt;0x00000ce0&lt;/code&gt;. Danach wird &lt;code&gt;malloc&lt;/code&gt; verwendet, um Speicher für die Bilddaten zu reservieren, und die Daten werden in diesen Speicher eingelesen.&lt;/p&gt;&#xA;&lt;p&gt;Die magische Zahl ist &lt;code&gt;cIMG&lt;/code&gt;, was in Hex &lt;code&gt;63 49 4d 47&lt;/code&gt; entspricht; die Version ist eine 32-Bit-Little-Endian-Ganzzahl; sowohl Höhe als auch Breite sind 8-Bit-Ganzzahlen.&lt;/p&gt;&#xA;&lt;h2 id=&#34;bedingung-für-die-flag&#34;&gt;Bedingung für die Flag&#xA;&lt;/h2&gt;&lt;p&gt;Gehen wir zum Ende der Funktion. Offensichtlich ist &lt;code&gt;sym.win&lt;/code&gt; die Funktion, die uns die Flag gibt. Sie wird bei &lt;code&gt;0x00000e8c&lt;/code&gt; aufgerufen, und dieser Aufruf erfolgt nach einer Prüfung bei &lt;code&gt;0x00000e58&lt;/code&gt;. Diese Prüfung verlangt, dass &lt;code&gt;w19&lt;/code&gt; nicht null ist.&lt;/p&gt;&#xA;&lt;h2 id=&#34;manipulation-des-kontrollflusses&#34;&gt;Manipulation des Kontrollflusses&#xA;&lt;/h2&gt;&lt;p&gt;Es ist Zeit, GDB zu starten.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;sl4pj9&#34;&#34; data-lang=&#34;id=&#34;sl4pj9&#34;&#34;&gt;$ gdb --args ./challenge ./example.cimg &#xA;GNU gdb (Debian 16.3-1) 16.3&#xA;Copyright (C) 2024 Free Software Foundation, Inc.&#xA;License GPLv3+ or later &amp;lt;http://gnu.org/licenses/gpl.html&amp;gt;&#xA;This is free software: you are free to change and redistribute it.&#xA;There is NO WARRANTY, to the extent permitted by law.&#xA;Type &amp;#34;show copying&amp;#34; and &amp;#34;show warranty&amp;#34; for details.&#xA;This GDB was configured as &amp;#34;aarch64-linux-gnu&amp;#34;.&#xA;Type &amp;#34;show configuration&amp;#34; for configuration details.&#xA;For bug reporting instructions, please see:&#xA;&amp;lt;https://www.gnu.org/software/gdb/bugs/&amp;gt;.&#xA;Find the GDB manual and other documentation resources online at:&#xA;    &amp;lt;http://www.gnu.org/software/gdb/documentation/&amp;gt;.&#xA;&#xA;For help, type &amp;#34;help&amp;#34;.&#xA;Type &amp;#34;apropos word&amp;#34; to search for commands related to &amp;#34;word&amp;#34;...&#xA;Reading symbols from ./challenge...&#xA;(No debugging symbols found in ./challenge)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Setzen Sie einen Breakpoint auf die Funktion &lt;code&gt;main&lt;/code&gt; und starten Sie das Programm:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;srt51i&#34;&#34; data-lang=&#34;id=&#34;srt51i&#34;&#34;&gt;(gdb) break *main&#xA;Breakpoint 1 at 0xc44&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;[Thread debugging using libthread_db enabled]&#xA;Using host libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1&amp;#34;.&#xA;&#xA;Breakpoint 1, 0x0000aaaaaaaa0c44 in main ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Wir merken uns, dass GDBs Datenadressen einen Versatz von &lt;code&gt;0xaaaaaaaa0000&lt;/code&gt; haben.&lt;/p&gt;&#xA;&lt;p&gt;Setzen Sie einen Breakpoint direkt vor der Prüfung der Flag-Bedingung und fahren Sie fort:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;upco7m&#34;&#34; data-lang=&#34;id=&#34;upco7m&#34;&#34;&gt;(gdb) break *0x0000aaaaaaaa0e58&#xA;Breakpoint 2 at 0xaaaaaaaa0e58&#xA;(gdb) continue&#xA;Continuing.&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;&#xA;Breakpoint 2, 0x0000aaaaaaaa0e58 in main ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ändern Sie den Inhalt des Registers &lt;code&gt;w19&lt;/code&gt; und fahren Sie fort:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;024n2e&#34;&#34; data-lang=&#34;id=&#34;024n2e&#34;&#34;&gt;(gdb) set $w19 = 1&#xA;(gdb) continue&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Dann wird das ausführbare Programm uns die Flag geben. Damit ist die Aufgabe beendet, und haben Sie einen schönen Tag :-p&lt;/p&gt;&#xA;&lt;p&gt;Nur ein Scherz. Wenn wir die Herausforderung tatsächlich so abschliessen würden, wäre der Reiz von RE weg. Gehen wir tiefer hinein.&lt;/p&gt;&#xA;&lt;h2 id=&#34;datenprüfung&#34;&gt;Datenprüfung&#xA;&lt;/h2&gt;&lt;p&gt;Gehen Sie zurück zu iaito. Klicken Sie im Graphen auf &lt;code&gt;w19&lt;/code&gt;. Dadurch wird dieses Register in allen Instruktionen des Graphen hervorgehoben. Scrollen Sie im Graphen zurück, um einen Hinweis zu finden.&lt;/p&gt;&#xA;&lt;p&gt;Wir können einige Aufrufe von &lt;code&gt;sym.imp.memcmp&lt;/code&gt; im Graphen sehen.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;memcmp&lt;/code&gt; ist eine Standardfunktion der C-Bibliothek, die in &lt;code&gt;&amp;lt;string.h&amp;gt;&lt;/code&gt; deklariert ist und zwei Speicherblöcke byteweise vergleicht:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;5yb0vi&#34;&#34; data-lang=&#34;id=&#34;5yb0vi&#34;&#34;&gt;int memcmp(const void *ptr1, const void *ptr2, size_t n);&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;ptr1&lt;/code&gt; und &lt;code&gt;ptr2&lt;/code&gt; zeigen jeweils auf die beiden Blöcke, und &lt;code&gt;n&lt;/code&gt; gibt die Anzahl der zu vergleichenden Bytes an. Wenn die beiden Blöcke identisch sind, gibt die Funktion &lt;code&gt;0&lt;/code&gt; zurück; andernfalls wird eine von null verschiedene Zahl zurückgegeben.&lt;/p&gt;&#xA;&lt;p&gt;Es gibt vier &lt;code&gt;memcmp&lt;/code&gt;-Aufrufe. Auf jeden Aufruf folgt &lt;code&gt;cmp w0, 0&lt;/code&gt;. Ausser beim ersten Aufruf gibt es ausserdem nach &lt;code&gt;cmp&lt;/code&gt; noch &lt;code&gt;cset w0, eq&lt;/code&gt; und &lt;code&gt;and w19, w19, w0&lt;/code&gt;. Daraus können wir schliessen, dass &lt;code&gt;w19&lt;/code&gt; gelöscht wird, wenn &lt;code&gt;memcmp&lt;/code&gt; einen Unterschied findet, da &lt;code&gt;w0&lt;/code&gt; dann null sein wird. Deshalb vermuten wir, dass wir die vier Paare von Speicherblöcken gleich machen müssen.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;x0&lt;/code&gt; und &lt;code&gt;x1&lt;/code&gt; sind die beiden zu vergleichenden Adressen. &lt;code&gt;x2&lt;/code&gt; enthält die Grösse; &lt;code&gt;mov x2, 0x18&lt;/code&gt; sagt uns, dass die Grösse 24 Bytes beträgt.&lt;/p&gt;&#xA;&lt;p&gt;Öffnen Sie GDB erneut und untersuchen Sie den Speicher vor dem ersten &lt;code&gt;memcmp&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;bzfvyb&#34;&#34; data-lang=&#34;id=&#34;bzfvyb&#34;&#34;&gt;(gdb) break *0x0000aaaaaaaa0e78&#xA;Breakpoint 1 at 0xaaaaaaaa0e78&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;[Thread debugging using libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1].&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;&#xA;Breakpoint 1, 0x0000aaaaaaaa0e78 in main ()&#xA;(gdb) info registers x0 x1&#xA;x0             0xaaaaaaac12a0      187649984565920&#xA;x1             0xaaaaaaac00c0      187649984561344&#xA;(gdb) x/24xb $x0&#xA;0xaaaaaaac12a0: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x30&#xA;0xaaaaaaac12a8: 0x38    0x30    0x3b    0x30    0x38    0x30    0x3b    0x30&#xA;0xaaaaaaac12b0: 0x38    0x30    0x6d    0x50    0x1b    0x5b    0x30    0x6d&#xA;(gdb) x/24xb $x1&#xA;0xaaaaaaac00c0 &amp;lt;desired_output&amp;gt;:        0x1b    0x5b    0x33    0x38    0x3b   0x32     0x3b    0x32&#xA;0xaaaaaaac00c8 &amp;lt;desired_output+8&amp;gt;:      0x33    0x31    0x3b    0x30    0x31   0x37     0x3b    0x31&#xA;0xaaaaaaac00d0 &amp;lt;desired_output+16&amp;gt;:     0x33    0x30    0x6d    0x63    0x1b   0x5b     0x30    0x6d&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Zufällige Bytes. Ich kann nicht herausfinden, was sie bedeuten.&lt;/p&gt;&#xA;&lt;p&gt;Gehen Sie zurück zu iaito. Der erste Speicherblock wird aus &lt;code&gt;x22&lt;/code&gt; geladen, und &lt;code&gt;x22&lt;/code&gt; wird aus der Adresse &lt;code&gt;var_48h&lt;/code&gt; geladen. &lt;code&gt;afv&lt;/code&gt; zeigt uns, dass sie &lt;code&gt;0x48&lt;/code&gt; von &lt;code&gt;sp&lt;/code&gt; entfernt liegt:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;y67rzq&#34;&#34; data-lang=&#34;id=&#34;y67rzq&#34;&#34;&gt;[0x00000e70]&amp;gt; afv&#xA;arg signed int argc @ x0&#xA;arg char ** s @ x1&#xA;var int64_t var_50h @ sp+0x0&#xA;var int64_t var_50h_2 @ sp+0x8&#xA;var int64_t var_10h @ sp+0x10&#xA;var int64_t var_10h_2 @ sp+0x18&#xA;var int64_t var_20h @ sp+0x20&#xA;var int64_t var_20h_2 @ sp+0x28&#xA;var void * buf @ sp+0x38&#xA;var int64_t var_3ch @ sp+0x3c&#xA;var int64_t var_3eh @ sp+0x3e&#xA;var int64_t var_3fh @ sp+0x3f&#xA;var int64_t var_40h @ sp+0x40&#xA;var int64_t var_48h @ sp+0x48&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Starten Sie GDB neu und überspringen Sie den Funktionsprolog, nachdem &lt;code&gt;main&lt;/code&gt; aufgerufen wurde:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;0se5x1&#34;&#34; data-lang=&#34;id=&#34;0se5x1&#34;&#34;&gt;(gdb) break *main&#xA;Breakpoint 1 at 0xaaaaaaaa0c44&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;[Thread debugging using libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1].&#xA;&#xA;Breakpoint 1, 0x0000aaaaaaaa0c44 in main ()&#xA;(gdb) si&#xA;0x0000aaaaaaaa0c48 in main ()&#xA;(gdb) si&#xA;0x0000aaaaaaaa0c4c in main ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Prüfen Sie den Wert des Stackpointers und setzen Sie einen Watchpoint:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;xkqjjg&#34;&#34; data-lang=&#34;id=&#34;xkqjjg&#34;&#34;&gt;(gdb) info registers sp&#xA;sp             0xfffffffff290      0xfffffffff290&#xA;(gdb) watch *(long long *)0xfffffffff2d8&#xA;Hardware watchpoint 2: *(long long *)0xfffffffff2d8&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Fahren Sie fort:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;qle3tg&#34;&#34; data-lang=&#34;id=&#34;qle3tg&#34;&#34;&gt;(gdb) continue&#xA;Continuing.&#xA;&#xA;Hardware watchpoint 2: *(long long *)0xfffffffff2d8&#xA;&#xA;Old value = 281474840286680&#xA;New value = 0&#xA;0x0000aaaaaaaa0c5c in main ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Lokalisieren Sie diese Adresse in iaito. Wir können sehen, dass bei &lt;code&gt;0x00000c58&lt;/code&gt; (der vorherigen Instruktion zu &lt;code&gt;0x00000c5c&lt;/code&gt;) &lt;code&gt;var_48h&lt;/code&gt; durch ein &lt;code&gt;str&lt;/code&gt; auf null gesetzt wird.&lt;/p&gt;&#xA;&lt;p&gt;Fahren Sie fort, um herauszufinden, wo die Variable gesetzt wird:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;uzul15&#34;&#34; data-lang=&#34;id=&#34;uzul15&#34;&#34;&gt;(gdb) continue&#xA;Continuing.&#xA;&#xA;Hardware watchpoint 2: *(long long *)0xfffffffff2d8&#xA;&#xA;Old value = 0&#xA;New value = 187649984565920&#xA;0x0000aaaaaaaa1358 in initialize_framebuffer ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Wir sehen eine neue Funktion, die wir bisher noch nicht untersucht haben: &lt;code&gt;initialize_framebuffer&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Gehen Sie in iaito zu dieser Funktion:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://rebel1725.codeberg.page/blog/pic_20260527_002_13426986448128896865.png&#34;&#xA;&#x9;width=&#34;1775&#34;&#xA;&#x9;height=&#34;1384&#34;&#xA;&#x9;loading=&#34;lazy&#34;&#xA;&#x9;&#xA;&#x9;&#x9;alt=&#34;den Graphen der Funktion initialize\_framebuffer&#34;&#xA;&#x9;&#xA;&#x9;&#xA;&#x9;&#x9;class=&#34;gallery-image&#34; &#xA;&#x9;&#x9;data-flex-grow=&#34;128&#34;&#xA;&#x9;&#x9;data-flex-basis=&#34;307px&#34;&#xA;&#x9;&#xA;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Wir können sehen, dass eine von &lt;code&gt;malloc&lt;/code&gt; reservierte Speicheradresse durch die Instruktion bei &lt;code&gt;0x00001354&lt;/code&gt; in der Variable gespeichert wird. Sie wird jedoch als &lt;code&gt;[x22, 0x10]&lt;/code&gt; dargestellt. Prüfen wir den Inhalt von &lt;code&gt;x22&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;2rkm7e&#34;&#34; data-lang=&#34;id=&#34;2rkm7e&#34;&#34;&gt;(gdb) info registers $x22&#xA;x22            0xfffffffff2c8      281474976707272&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;0xfffffffff2c8 + 0x10 = 0xfffffffff2d8&lt;/code&gt;. Genau die Adresse von &lt;code&gt;var_48h&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Ausserdem ist die an &lt;code&gt;malloc&lt;/code&gt; übergebene Grösse interessant. Sie wird berechnet, indem die Werte an den Offsets 6 und 7 miteinander multipliziert werden, dann das Ergebnis mit &lt;code&gt;w1&lt;/code&gt; multipliziert wird, welches &lt;code&gt;0x18&lt;/code&gt; (24) ist, und dann &lt;code&gt;x0&lt;/code&gt; addiert wird, welches 1 ist.&lt;/p&gt;&#xA;&lt;p&gt;Lassen Sie uns diese Werte an den Offsets ebenfalls untersuchen:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;kot0zb&#34;&#34; data-lang=&#34;id=&#34;kot0zb&#34;&#34;&gt;(gdb) x/1xb 0xfffffffff2ce&#xA;0xfffffffff2ce: 0x0a&#xA;(gdb) x/1xb 0xfffffffff2cf&#xA;0xfffffffff2cf: 0x0a&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Beide sind 10. Sie scheinen die von uns angegebene Bildbreite und Bildhöhe zu sein. Prüfen wir das mit Hardware-Watchpoints. Da AArch64 eine Ausrichtung verlangt, setzen wir den Hardware-Watchpoint bei &lt;code&gt;0xfffffffff2cc&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;man8re&#34;&#34; data-lang=&#34;id=&#34;man8re&#34;&#34;&gt;(gdb) watch *(unsigned int *)0xfffffffff2cc&#xA;Hardware watchpoint 1: *(unsigned int *)0xfffffffff2cc&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Überspringen Sie die Auslöser der GNU C Library:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;3kxuft&#34;&#34; data-lang=&#34;id=&#34;3kxuft&#34;&#34;&gt;Hardware watchpoint 1: *(unsigned int *)0xfffffffff2cc&#xA;&#xA;Old value = 0&#xA;New value = 65535&#xA;0x0000fffff7fccd08 in ?? () from /lib/ld-linux-aarch64.so.1&#xA;(gdb) continue&#xA;Continuing.&#xA;&#xA;Hardware watchpoint 1: *(unsigned int *)0xfffffffff2cc&#xA;&#xA;Old value = 65535&#xA;New value = 0&#xA;0x0000fffff7fd5668 in ?? () from /lib/ld-linux-aarch64.so.1&#xA;(gdb) continue&#xA;Continuing.&#xA;[Thread debugging using libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1&amp;#34;]&#xA;&#xA;Hardware watchpoint 1: *(unsigned int *)0xfffffffff2cc&#xA;&#xA;Old value = 0&#xA;New value = 65535&#xA;0x0000fffff7fcc3a4 in ?? () from /lib/ld-linux-aarch64.so.1&#xA;(gdb) continue&#xA;Continuing.&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Hier sehen wir, dass der Speicher bei &lt;code&gt;0x00000c54&lt;/code&gt; auf null gesetzt wird:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;7lsdni&#34;&#34; data-lang=&#34;id=&#34;7lsdni&#34;&#34;&gt;Hardware watchpoint 1: *(unsigned int *)0xfffffffff2cc&#xA;&#xA;Old value = 65535&#xA;New value = 0&#xA;0x0000aaaaaaaa0c58 in main ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Wir sehen ein &lt;code&gt;stp xzr, xzr, [buf]&lt;/code&gt;. Aus dem obigen &lt;code&gt;afv&lt;/code&gt; wissen wir, dass &lt;code&gt;buf&lt;/code&gt; &lt;code&gt;0x38&lt;/code&gt; vom Stackpointer entfernt liegt.&lt;/p&gt;&#xA;&lt;p&gt;Bei &lt;code&gt;0x00000cb8&lt;/code&gt; finden wir ein &lt;code&gt;ldr&lt;/code&gt; aus &lt;code&gt;buf&lt;/code&gt;, gefolgt von einer Prüfung der magischen Zahl.&lt;/p&gt;&#xA;&lt;p&gt;Bei &lt;code&gt;0x00000c9c&lt;/code&gt; finden wir etwas Interessantes:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;dephcs&#34;&#34; data-lang=&#34;id=&#34;dephcs&#34;&#34;&gt;0x00000c9c      add      x21,    sp,     0x38&#xA;0x00000ca0      mov      x2,     8                          ; size_t nbyte&#xA;0x00000ca4      mov      x1,     x21                        ; void *buf&#xA;0x00000ca8      mov      w0,     0&#xA;0x00000cac      bl       sym.imp.read                       ; ssize_t read(int fildes, void *buf, size_t nbyte)&#xA;; ssize_t read(0, 0x0000000000000000, 0x00000000)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Damit haben wir bestätigt, dass die beiden Werte an diesen Offsets Breite und Höhe sind.&lt;/p&gt;&#xA;&lt;p&gt;Gehen Sie in iaito und GDB zurück zur Funktion &lt;code&gt;initialize_framebuffer&lt;/code&gt;. Setzen Sie einen Watchpoint und untersuchen Sie den Speicher:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;751rxy&#34;&#34; data-lang=&#34;id=&#34;751rxy&#34;&#34;&gt;(gdb) break *0xaaaaaaaa1354&#xA;Breakpoint 1 at 0xaaaaaaaa1354&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;[Thread debugging using libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1].&#xA;&#xA;Breakpoint 1, 0x0000aaaaaaaa1354 in initialize_framebuffer ()&#xA;(gdb) info registers x0&#xA;x0             0xaaaaaaac12a0      187649984565920&#xA;(gdb) watch *(char *)0xaaaaaaac12a0&#xA;Hardware watchpoint 2: *(char *)0xaaaaaaac12a0&#xA;(gdb) continue&#xA;Continuing.&#xA;&#xA;Hardware watchpoint 2: *(char *)0xaaaaaaac12a0&#xA;&#xA;Old value = 0 &amp;#39;\000&amp;#39;&#xA;New value = 27 &amp;#39;\033&amp;#39;&#xA;0x0000aaaaaaaa13bc in initialize_framebuffer ()&#xA;(gdb) x/24xb 0xaaaaaaac12a0&#xA;0xaaaaaaac12a0: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x32&#xA;0xaaaaaaac12a8: 0x35    0x35    0x3b    0x32    0x35    0x35    0x3b    0x32&#xA;0xaaaaaaac12b0: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Vergleichen Sie das mit den obigen Daten:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;qjv2ky&#34;&#34; data-lang=&#34;id=&#34;qjv2ky&#34;&#34;&gt;(gdb) x/24xb $x0&#xA;0xaaaaaaac12a0: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x30&#xA;0xaaaaaaac12a8: 0x38    0x30    0x3b    0x30    0x38    0x30    0x3b    0x30&#xA;0xaaaaaaac12b0: 0x38    0x30    0x6d    0x50    0x1b    0x5b    0x30    0x6d&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;0xaaaaaaac12a7&lt;/code&gt; ist das erste Byte, das sich unterscheidet. Wir können dafür einen Watchpoint setzen:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;086nsv&#34;&#34; data-lang=&#34;id=&#34;086nsv&#34;&#34;&gt;(gdb) watch *(char *)0xaaaaaaac12a7&#xA;Hardware watchpoint 3: *(char *)0xaaaaaaac12a7&#xA;(gdb) continue&#xA;Continuing.&#xA;&#xA;Hardware watchpoint 3: *(char *)0xaaaaaaac12a7&#xA;&#xA;Old value = 50 &amp;#39;2&amp;#39;&#xA;New value = 48 &amp;#39;0&amp;#39;&#xA;0x0000aaaaaaaa128c in display ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Eine neue Funktion, die es zu untersuchen gilt. Öffnen Sie sie in iaito.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://rebel1725.codeberg.page/blog/pic_20260527_003_2825852626928846418.png&#34;&#xA;&#x9;width=&#34;1129&#34;&#xA;&#x9;height=&#34;2426&#34;&#xA;&#x9;loading=&#34;lazy&#34;&#xA;&#x9;&#xA;&#x9;&#x9;alt=&#34;den Graphen der Funktion initialize\_framebuffer&#34;&#xA;&#x9;&#xA;&#x9;&#xA;&#x9;&#x9;class=&#34;gallery-image&#34; &#xA;&#x9;&#x9;data-flex-grow=&#34;46&#34;&#xA;&#x9;&#x9;data-flex-basis=&#34;111px&#34;&#xA;&#x9;&#xA;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Wir können sehen, dass die Datenänderung bei &lt;code&gt;0x00001288&lt;/code&gt; in einer &lt;code&gt;stp&lt;/code&gt;-Instruktion stattfindet. Die &lt;code&gt;str&lt;/code&gt;-Instruktion bei &lt;code&gt;0x0000128c&lt;/code&gt; ist ebenfalls interessant; untersuchen wir hier den Speicher:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;cuc9oa&#34;&#34; data-lang=&#34;id=&#34;cuc9oa&#34;&#34;&gt;(gdb) x/24xb 0xaaaaaaac12a0&#xA;0xaaaaaaac12a0: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x30&#xA;0xaaaaaaac12a8: 0x38    0x30    0x3b    0x30    0x38    0x30    0x3b    0x30&#xA;0xaaaaaaac12b0: 0x35    0x35    0x6d    0x20    0x1b    0x5b    0x30    0x6d&#xA;(gdb) si&#xA;0x0000aaaaaaaa1290 in display ()&#xA;(gdb) x/24xb 0xaaaaaaac12a0&#xA;0xaaaaaaac12a0: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x30&#xA;0xaaaaaaac12a8: 0x38    0x30    0x3b    0x30    0x38    0x30    0x3b    0x30&#xA;0xaaaaaaac12b0: 0x38    0x30    0x6d    0x50    0x1b    0x5b    0x30    0x6d&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Der 8-Byte-Block ab &lt;code&gt;0xaaaaaaac12b0&lt;/code&gt; wurde durch die &lt;code&gt;str&lt;/code&gt;-Instruktion geändert. Das Register erzählt die Geschichte:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;w9u9cf&#34;&#34; data-lang=&#34;id=&#34;w9u9cf&#34;&#34;&gt;(gdb) info registers x2&#xA;x2             0xaaaaaaac12a0      187649984565920&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Wir müssen uns um &lt;code&gt;x2&lt;/code&gt; nicht zu sehr kümmern. Konzentrieren wir uns auf &lt;code&gt;x4&lt;/code&gt;, &lt;code&gt;x5&lt;/code&gt; und &lt;code&gt;x1&lt;/code&gt;. Bei &lt;code&gt;0x00001268&lt;/code&gt; und &lt;code&gt;0x00001270&lt;/code&gt; sehen wir ein sehr wichtiges Register, &lt;code&gt;x25&lt;/code&gt;. Es enthält die Adresse des Speichers, der die Daten enthält, die in den durch &lt;code&gt;x2&lt;/code&gt; adressierten Speicher geschrieben werden. Untersuchen wir diesen Speicher:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;lpbj45&#34;&#34; data-lang=&#34;id=&#34;lpbj45&#34;&#34;&gt;(gdb) x/24xb $x25&#xA;0xfffffffff270: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x30&#xA;0xfffffffff278: 0x38    0x30    0x3b    0x30    0x38    0x30    0x3b    0x30&#xA;0xfffffffff280: 0x38    0x30    0x6d    0x50    0x1b    0x5b    0x30    0x6d&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Bei &lt;code&gt;0x00001238&lt;/code&gt; wird die Adresse in &lt;code&gt;x25&lt;/code&gt; nach &lt;code&gt;x0&lt;/code&gt; kopiert. Danach werden die Datenstücke in die folgenden Register kopiert. Dann erfolgt ein Aufruf von &lt;code&gt;snprintf&lt;/code&gt;. &lt;code&gt;snprintf&lt;/code&gt; schreibt formatierten Output in ein Zeichenfeld:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;onjzdn&#34;&#34; data-lang=&#34;id=&#34;onjzdn&#34;&#34;&gt;int snprintf(char *str, size_t size, const char *format, ...);&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Es schreibt also eine formatierte Zeichenkette in den Speicher bei &lt;code&gt;x25&lt;/code&gt;. Starten wir GDB neu und untersuchen den von &lt;code&gt;x2&lt;/code&gt; adressierten Speicher:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;5694u3&#34;&#34; data-lang=&#34;id=&#34;5694u3&#34;&#34;&gt;(gdb) break *0xaaaaaaaa1258&#xA;Breakpoint 1 at 0xaaaaaaaa1258&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;[Thread debugging using libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1].&#xA;&#xA;Breakpoint 1, 0x0000aaaaaaaa1258 in display ()&#xA;(gdb) x/s $x2&#xA;0xaaaaaaaa1510: &amp;#34;\033[38;2;%03d;%03d;%03dm%c\033[0m&amp;#34;&#xA;(gdb) x/29xb $x2&#xA;0xaaaaaaaa1510: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x25&#xA;0xaaaaaaaa1518: 0x30    0x33    0x64    0x3b    0x25    0x30    0x33    0x64&#xA;0xaaaaaaaa1520: 0x3b    0x25    0x30    0x33    0x64    0x6d    0x25    0x63&#xA;0xaaaaaaaa1528: 0x1b    0x5b    0x30    0x6d    0x00&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Das ist die Formatzeichenkette. Wenn Sie mit der von &lt;code&gt;x/s&lt;/code&gt; zurückgegebenen Zeichenkette nicht zufrieden sind, können Sie Python verwenden, um die Zeichenkette Byte für Byte auszugeben:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;9hlb7o&#34;&#34; data-lang=&#34;id=&#34;9hlb7o&#34;&#34;&gt;&amp;gt;&amp;gt;&amp;gt; print(b&amp;#34;\x1b\x5b\x33\x38\x3b\x32\x3b\x25\x30\x33\x64\x3b\x25\x30\x33\x64\x3\&#xA;b\x25\x30\x33\x64\x6d\x25\x63\x1b\x5b\x30\x6d\x00&amp;#34;)&#xA;b&amp;#39;\x1b[38;2;%03d;%03d;%03dm%c\x1b[0m\x00&amp;#39;&#xA;&amp;gt;&amp;gt;&amp;gt; blob = b&amp;#39;\x1b[38;2;%03d;%03d;%03dm%c\x1b[0m\x00&amp;#39;&#xA;&amp;gt;&amp;gt;&amp;gt; for i1 in range(len(blob)):&#xA;...     blob[i1:i1+1]&#xA;...     &#xA;b&amp;#39;\x1b&amp;#39;&#xA;b&amp;#39;[&amp;#39;&#xA;b&amp;#39;3&amp;#39;&#xA;b&amp;#39;8&amp;#39;&#xA;b&amp;#39;;&amp;#39;&#xA;b&amp;#39;2&amp;#39;&#xA;b&amp;#39;;&amp;#39;&#xA;b&amp;#39;%&amp;#39;&#xA;b&amp;#39;0&amp;#39;&#xA;b&amp;#39;3&amp;#39;&#xA;b&amp;#39;d&amp;#39;&#xA;b&amp;#39;;&amp;#39;&#xA;b&amp;#39;%&amp;#39;&#xA;b&amp;#39;0&amp;#39;&#xA;b&amp;#39;3&amp;#39;&#xA;b&amp;#39;d&amp;#39;&#xA;b&amp;#39;;&amp;#39;&#xA;b&amp;#39;%&amp;#39;&#xA;b&amp;#39;0&amp;#39;&#xA;b&amp;#39;3&amp;#39;&#xA;b&amp;#39;d&amp;#39;&#xA;b&amp;#39;m&amp;#39;&#xA;b&amp;#39;%&amp;#39;&#xA;b&amp;#39;c&amp;#39;&#xA;b&amp;#39;\x1b&amp;#39;&#xA;b&amp;#39;[&amp;#39;&#xA;b&amp;#39;0&amp;#39;&#xA;b&amp;#39;m&amp;#39;&#xA;b&amp;#39;\x00&amp;#39;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Diese Formatzeichenkette hat vier Platzhalter. Die ersten drei sind &lt;code&gt;%03d&lt;/code&gt;, die eine Ganzzahl als Dezimalzahl mit mindestens drei Ziffern formatieren (zum Beispiel wird aus 7 &lt;code&gt;007&lt;/code&gt;, und aus 15 wird &lt;code&gt;015&lt;/code&gt;). Der letzte ist &lt;code&gt;%c&lt;/code&gt;, der nur ein einzelnes Zeichen akzeptiert.&lt;/p&gt;&#xA;&lt;p&gt;Nun haben wir das folgende Byte-Muster:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;7599l4&#34;&#34; data-lang=&#34;id=&#34;7599l4&#34;&#34;&gt;0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    [N1]&#xA;[N1]    [N1]    0x3b    [N2]    [N2]    [N2]    0x3b    [N3]&#xA;[N3]    [N3]    0x6d    [CH]    0x1b    0x5b    0x30    0x6d&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Wir können nun untersuchen, was die Platzhalter füllt:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;a6lcl7&#34;&#34; data-lang=&#34;id=&#34;a6lcl7&#34;&#34;&gt;(gdb) info registers x3 x4 x5 x6&#xA;x3             0x50                80&#xA;x4             0x50                80&#xA;x5             0x50                80&#xA;x6             0x50                80&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Alle sind &lt;code&gt;0x50&lt;/code&gt;, was offenbar die Daten sind, die wir in der Beispiel-cIMG verwenden. Erstellen wir die cIMG nun erneut, um das zu verdeutlichen:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;bntxni&#34;&#34; data-lang=&#34;id=&#34;bntxni&#34;&#34;&gt;&amp;gt;&amp;gt;&amp;gt; with open(&amp;#34;example.cimg&amp;#34;, &amp;#34;wb&amp;#34;) as file:&#xA;...     file.write(b&amp;#34;cIMG\x02\0\x0a\x0a\x12\x34\x56\x78&amp;#34;)&#xA;...     file.write(b&amp;#34;\x50&amp;#34;*(10*10*4-4))&#xA;...     &#xA;12&#xA;396&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-id=&#34;jigwea&#34;&#34; data-lang=&#34;id=&#34;jigwea&#34;&#34;&gt;(gdb) break *0xaaaaaaaa1258&#xA;Breakpoint 1 at 0xaaaaaaaa1258&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;[Thread debugging using libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1].&#xA;&#xA;Breakpoint 1, 0x0000aaaaaaaa1258 in display ()&#xA;(gdb) info registers x3 x4 x5 x6&#xA;x3             0x12                18&#xA;x4             0x34                52&#xA;x5             0x56                86&#xA;x6             0x78                120&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Damit entsprechen N1, N2 und N3 im obigen Hex-Muster R, G und B, und CH ist einfach das Zeichen, das wir einsetzen wollen.&lt;/p&gt;&#xA;&lt;p&gt;Nun können wir zu GDB zurückkehren, vor jedem &lt;code&gt;memcmp&lt;/code&gt; einen Breakpoint setzen, mit &lt;code&gt;x/24xb $x1&lt;/code&gt; die erwarteten Framebuffer ermitteln und daraus die erwarteten cIMG-Daten rekonstruieren. Anschliessend füllen wir die Daten mit einem Hex-Editor ein.&lt;/p&gt;&#xA;&lt;h2 id=&#34;grössenprüfung&#34;&gt;Grössenprüfung&#xA;&lt;/h2&gt;&lt;p&gt;Nach dem Einfügen der erwarteten Daten gibt das Programm jedoch immer noch nicht die Flag aus. Nachdem wir mit GDB den Speicher untersucht haben, sehen wir, dass die &lt;code&gt;memcmp&lt;/code&gt;-Aufrufe erwartungsgemäss Null zurückgeben. Es muss also noch andere Bedingungen geben, die nicht erfüllt sind.&lt;/p&gt;&#xA;&lt;p&gt;Gehen Sie in iaito zurück und scrollen Sie vom ersten &lt;code&gt;memcmp&lt;/code&gt; aus rückwärts. Wir sehen ein &lt;code&gt;cmp&lt;/code&gt; bei &lt;code&gt;0x00000d60&lt;/code&gt;, das &lt;code&gt;var_40h&lt;/code&gt; mit 4 vergleicht. Bei &lt;code&gt;0x00001348&lt;/code&gt; in &lt;code&gt;initialize_framebuffer&lt;/code&gt; finden wir ein &lt;code&gt;str&lt;/code&gt;, das das Produkt aus Breite und Höhe speichert.&lt;/p&gt;&#xA;&lt;p&gt;Das &lt;code&gt;cmp&lt;/code&gt; bei &lt;code&gt;0x00000d60&lt;/code&gt; bestimmt dann den Wert von &lt;code&gt;w0&lt;/code&gt;. Wenn &lt;code&gt;var_40h&lt;/code&gt; gleich 4 ist, wird &lt;code&gt;w0&lt;/code&gt; zu 1; andernfalls wird es 0.&lt;/p&gt;&#xA;&lt;p&gt;Bei &lt;code&gt;0x00000d78&lt;/code&gt; wird &lt;code&gt;w0&lt;/code&gt; mit 0 verglichen, was das Verhalten der Instruktion &lt;code&gt;ccmp&lt;/code&gt; bei &lt;code&gt;0x00000d84&lt;/code&gt; beeinflusst. Der Inhalt von &lt;code&gt;[x22, 0x13]&lt;/code&gt; wird in das Register &lt;code&gt;w0&lt;/code&gt; geladen, und &lt;code&gt;[x1, 0x13]&lt;/code&gt; wird in &lt;code&gt;w2&lt;/code&gt; geladen. Aus &lt;code&gt;memcmp&lt;/code&gt; können wir leicht erkennen, dass &lt;code&gt;x22&lt;/code&gt; die tatsächliche Adresse des Framebuffers ist und &lt;code&gt;x1&lt;/code&gt; die erwartete Adresse des Framebuffers. Da wir die Daten bereits so angepasst haben, dass sie mit den erwarteten Daten übereinstimmen, und der Offset 19 ein ASCII-Zeichen ist, sollten &lt;code&gt;w0&lt;/code&gt; und &lt;code&gt;w2&lt;/code&gt; gleich und ungleich null sein.&lt;/p&gt;&#xA;&lt;p&gt;Wir können daraus schliessen, dass, wenn &lt;code&gt;var_40h&lt;/code&gt; gleich 4 ist, &lt;code&gt;w2&lt;/code&gt; mit &lt;code&gt;w0&lt;/code&gt; verglichen wird, wodurch &lt;code&gt;w19&lt;/code&gt; auf 1 gesetzt wird. Andernfalls wird &lt;code&gt;w2&lt;/code&gt; mit 0 verglichen, wodurch &lt;code&gt;w19&lt;/code&gt; auf null gesetzt wird.&lt;/p&gt;&#xA;&lt;p&gt;Nach dem ersten &lt;code&gt;memcmp&lt;/code&gt; wird &lt;code&gt;w19&lt;/code&gt; mit 0 verglichen, da &lt;code&gt;w0&lt;/code&gt; bei &lt;code&gt;0x00000e7c&lt;/code&gt; gleich null ist. Dann setzt &lt;code&gt;cset&lt;/code&gt; &lt;code&gt;w19&lt;/code&gt; auf 1, wenn ungleich, andernfalls auf 0.&lt;/p&gt;&#xA;&lt;p&gt;Ändern Sie nun die cIMG mit einem Hex-Editor und setzen Sie Höhe und Breite auf Werte, deren Produkt 4 ergibt. Beispielsweise können wir &lt;code&gt;0202&lt;/code&gt; verwenden. Nun sollte das ausführbare Programm die Flag ausgeben.&lt;/p&gt;&#xA;&lt;h2 id=&#34;fazit&#34;&gt;Fazit&#xA;&lt;/h2&gt;&lt;p&gt;Das obige Verfahren umfasst:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;statische Analyse mit radare2 und iaito;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;dynamische Analyse mit GDB, einschliesslich:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Manipulation des Kontrollflusses;&lt;/li&gt;&#xA;&lt;li&gt;Speicherinspektion;&lt;/li&gt;&#xA;&lt;li&gt;Ganzzahlinspektion.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Das ist ein sehr typisches Vorgehen beim Reverse Engineering.&lt;/p&gt;&#xA;&lt;p&gt;Übrigens gibt es möglicherweise auch andere Ansätze, um dieses ausführbare Programm zu rekonstruieren. Doch unabhängig davon, welcher Ansatz verwendet wird, umfasst er normalerweise sowohl statische Analyse als auch dynamische Analyse.&lt;/p&gt;&#xA;</description>
        </item></channel>
</rss>
