<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://blog.dream-wa1ker.tech/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.dream-wa1ker.tech/" rel="alternate" type="text/html" /><updated>2026-09-23T19:24:27+00:00</updated><id>https://blog.dream-wa1ker.tech/feed.xml</id><title type="html">dream-wa1ker::writeups</title><subtitle>Writeups from the wa1kerverse: reverse engineering, exploitation and protocols. Hand written.</subtitle><author><name>dream-wa1ker</name></author><entry><title type="html">Exploiting the CVE-2026-31431 in Ubuntu 20.04</title><link href="https://blog.dream-wa1ker.tech/exploiting-lpe-in-ubuntu-20.04/" rel="alternate" type="text/html" title="Exploiting the CVE-2026-31431 in Ubuntu 20.04" /><published>2026-08-27T00:00:00+00:00</published><updated>2026-08-27T00:00:00+00:00</updated><id>https://blog.dream-wa1ker.tech/exploiting-lpe-in-ubuntu-20.04</id><content type="html" xml:base="https://blog.dream-wa1ker.tech/exploiting-lpe-in-ubuntu-20.04/"><![CDATA[<section>

  <h2 id="the-introduction">The Introduction</h2>

  <div class="description section-label">

    <p>When this exploit first came, it freaked out an entire group of linux people and cybersecurity people. Especially - Low Level. Cause, it was just 732 bytes python code with zero external dependencies. Meaning, it can run in any program that has python installed, and virtually most of the linux kernels - versions starting from 4.14 to 7.0-rc. That is, this exploit is universal, and is a <strong>Local Previllege Escalation(LPE)</strong> - meaning - <em>It grants root access to unprevilleged users when the vulnerability is exploited</em>.</p>

    <p><strong>Clearance 1</strong> : I have got no hints, but just a binary file which you can download from <a href="/assets/blogs/binaries/copyfail">here</a>.</p>

    <p>There are several processes in making an exploit to work in a specific target machine. For example, we can take a VM (Virtual Machine), running Ubuntu 20.04.</p>

    <p><strong>NOTE : This exploit is purely for educational purposes only, and I will not be responsible for misuse of the code present here.</strong></p>

  </div>
</section>

<section>

  <h2 class="section-label" id="identifying-the-vulnerability">Identifying the Vulnerability</h2>

  <div class="description">

    <p>The first and foremost step in exploiting something, a VM, an OS or whatsoever, is by identifying the target, then identify or figure out what is vulnerable in a target machine. There can be multiple vulnerabilities in a system, or in some cases, only one vulnerability. The extent to which the vulnerability can be used to gain previlleges is also one thing to check with.</p>

    <p><strong>Consider this Scenario</strong></p>

    <ul>
      <li>A person is running an outdated apache2 server. There are some modules in apache2, which allows RCE (Remote code execution), or even has path traversal / directory traversal endpoints, which allows the user in web to access contents of the filesystem of server in which the webpage is being served through.</li>
      <li>In this case, the attacker can either do a RCE, or just do a directory traversal to disclose invaluable server information. The attacker might choose which one has highest previlleges, based on his/her intent. RCE almost always gives the highest previllege, since it is a code execution.</li>
    </ul>

    <p><strong>Clearance 2</strong> : There are several ways to identify vulnerabilities in a target system. An attacker should choose the most efficient and least noisy way to figure out the vulnerability. Below given are some of the ways to identify the vulnerability. Though the way I identified the vulnerability is pretty common.</p>

    <h3 id="how-did-i-find-it">How did I find it?</h3>

    <p>Just search the web. Be up to date with the latest security exploits, the 2026 is a year of massive linux exploits, sped up release of exploits and LPEs and CVEs because of the use of AI to figure out bugs in the code and build exploits. Mythos. So, the fact is that - I was already aware of the existence of the exploits and the details of those exploits, what the affect and the extent of damage caused by it. Those are called CVEs.</p>

    <p>So, our target machine is Ubuntu 20.04, that is running in my University Labs. But hey wait, I am not exploiting it, I am doing it in my own VM. And this is how it looks like.</p>

    <p><img src="/assets/blogs/blog3/ubuntu-20.04.png" alt="ubuntu" width="98%" /></p>

    <h3 id="find-the-kernel-version">Find the kernel version</h3>

    <p>The <code class="language-plaintext highlighter-rouge">uname -r</code> command is used for finding the Linux Kernel Version (Release Version). If the version is smaller than 7.0, then there is a massive probability that the <strong>copy fail</strong> exploit works in the system. To know if I am using the most up to date Ubuntu version, I need to check the <code class="language-plaintext highlighter-rouge">os-release</code>. Unlike the <code class="language-plaintext highlighter-rouge">uname -r</code>, there is not specific command, so we have to <code class="language-plaintext highlighter-rouge">cat</code> it out from <code class="language-plaintext highlighter-rouge">/etc/os-release</code>.</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># find the kernel version</span>
<span class="nb">uname</span> <span class="nt">-r</span>

<span class="c"># find all details about kernel</span>
<span class="nb">uname</span> <span class="nt">-a</span>

<span class="c"># find the ubuntu version</span>
<span class="nb">cat</span> /etc/os-release | <span class="nb">grep </span>Ubuntu
</code></pre></div>    </div>

    <p>Here are the exact outputs as in my <strong>victim</strong> VM, the screenshots of them, the <code class="language-plaintext highlighter-rouge">uname</code> and <code class="language-plaintext highlighter-rouge">os-release</code>.</p>

    <p><img src="/assets/blogs/blog3/uname-kernel-version.png" alt="uname" width="98%" /></p>

    <p><img src="/assets/blogs/blog3/ubuntu-flavour.png" alt="flavour" width="98%" /></p>

    <p>Very clear that the kernel version is very small, <code class="language-plaintext highlighter-rouge">5.15.0-67-generic</code>, whereas the latest is <code class="language-plaintext highlighter-rouge">7.x.x</code> thing. Usage of outdated kernels!!!</p>

  </div>
</section>

<section>

  <h2 class="section-label" id="verification-and-exploitation">Verification and Exploitation</h2>

  <div class="description">

    <p>But I wanted to cross check the compactability of that exploit in this current victim, so small google search would help us to make sure that we choose the correct exploit. Below given is Google AI verified fact that <strong>victim’s kernel is vulnerable</strong>.</p>

    <p><img src="/assets/blogs/blog3/check-if-vulnerable-kernel-confirmed.png" alt="vuln" width="98%" /></p>

    <p>Now, we need to download the exploit. The best place to go for <strong>linux</strong> exploits and CVEs is <strong>Open Source</strong>. And that is how most of the kernel bugs are exposed and fixed in the first place, and those bugs were literally hiding there for most of these years. Next step is to check if <code class="language-plaintext highlighter-rouge">git</code> is available in the victim machine. Unfortunately, in my case, it was not available…</p>

    <ul>
      <li>
        <p>So, open the firefox web browser, go to web, search for <code class="language-plaintext highlighter-rouge">cve-2026-31431</code>, which is the standard name for <strong>Copy Fail</strong> vulnerability. Tons of URLs will show up, use google dorking wisely to filter just <code class="language-plaintext highlighter-rouge">github.com</code> URLs. Click some random verifiable PoC, inspect the source code. In my case, I am using <code class="language-plaintext highlighter-rouge">C</code> code version of this exploit, which is originally a 732 byte file of <code class="language-plaintext highlighter-rouge">python</code>.</p>
      </li>
      <li>
        <p>Once that the code is verified, understandable and I know that it causes know threat to <em>Availability</em>, download the ZIP file.</p>
      </li>
    </ul>

    <p><img src="/assets/blogs/blog3/go-to-poc-exploit-download.png" alt="download" width="98%" /></p>

    <ul>
      <li>After the zip file has completed downloading, I need to open the terminal in the Downloads folder, and then unzip the zip using the <code class="language-plaintext highlighter-rouge">unzip</code> command - i.e, extract the contents of the zip file. Navigate to the exploits folder, where the C version of the exploit is there. Make sure that you understand the C code.</li>
    </ul>

    <p><img src="/assets/blogs/blog3/unzip-terminal.png" alt="uname" width="98%" /></p>

    <ul>
      <li>After verifying that <code class="language-plaintext highlighter-rouge">gcc</code> is there in the victim’s machine (which my lab had, so does the VM), we need to compile the binary. <code class="language-plaintext highlighter-rouge">gcc</code> without any <code class="language-plaintext highlighter-rouge">-o</code> flag will generate the default binary file named <code class="language-plaintext highlighter-rouge">a.out</code>.</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc exploit.c
<span class="c"># gcc &lt;file.c&gt; </span>
<span class="c"># a.out file is generated</span>
</code></pre></div>    </div>

    <ul>
      <li>Before continuing, we must have a way to verify if the exploit actually worked. We will use the <code class="language-plaintext highlighter-rouge">id</code> and <code class="language-plaintext highlighter-rouge">whoami</code> to verify the integrity of the current user, or if there is a switch in user, and escalation of previlleges.</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># whoami will tell you the current user</span>
<span class="nb">whoami</span>
<span class="c"># outputs your username</span>
<span class="nb">id</span>
<span class="c"># note that the uid should be 1000.</span>
</code></pre></div>    </div>

    <ul>
      <li>Proceed with exploitation, which will provide us with previllege escalation. The below given stuff in terminal is the command I type to get the exploit work.</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./a.out
<span class="c"># yeah, that's it, the exploit will work</span>
</code></pre></div>    </div>

    <p>Now, if we use this escalated permission to tamper the current system state, then it is breach of <em>Integrity</em> at this point. The exploit itself is a direct bypass of <em>Authentication</em> and hence the <em>Authorisation</em> also. After escalation, I ran <code class="language-plaintext highlighter-rouge">apt update</code> to update the system. Though this is legit naive harmless prank, the real attackers can cause a real <strong>prankless harm</strong> by  implanting a <strong>rootkit</strong> to ensure persistence, or whatever they are willing to do.</p>

    <p><img src="/assets/blogs/blog3/exploit-and-tamper-integrity.png" alt="uname" width="98%" /></p>

    <p>This exploit uses page cache poisoning, corrupts the page cache during a kernel authentication (cryptographic subsystem), and overwrites into the kernel page cache which is <strong>supposed to be read only memory section</strong>. This target’s a <em>setuid bit binary</em> such as <code class="language-plaintext highlighter-rouge">su</code> or <code class="language-plaintext highlighter-rouge">sudo</code>. I will not be going deep into the <code class="language-plaintext highlighter-rouge">setuid</code> bits, why they exist and stuffs. For now, this is just an exploitation of a CVE.</p>

    <p>It is a cache-only exploit - meaning that this exploit is not permanent. Once the system reboots, the cache in RAM, is deleted, and new cache page is provided, as RAM  is volatile memory. But we can just manually tell the kernel to drop the caches by running the following command as sudo.</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo </span>3 <span class="o">&gt;</span> /proc/sys/vm/drop_caches
</code></pre></div>    </div>

    <p><img src="/assets/blogs/blog3/de-escalate.png" alt="uname" width="98%" /></p>

    <p><strong>But…</strong>
If the <em>caches</em> are not dropped after the exploit, then the cached binary <code class="language-plaintext highlighter-rouge">su</code> will still be loaded, instead of whatever is in original <code class="language-plaintext highlighter-rouge">su</code>, which is dis, which is disk. Therefore, just running <code class="language-plaintext highlighter-rouge">su</code> will escalate the previllege from <code class="language-plaintext highlighter-rouge">user</code> to <code class="language-plaintext highlighter-rouge">root</code>.</p>

    <p><img src="/assets/blogs/blog3/escalate-previllege.png" alt="uname" width="98%" /></p>

    <p><strong>NOTE : THIS EXPLOIT IS PURELY FOR EDUCATIONAL PURPOSES.</strong></p>

  </div>
</section>]]></content><author><name>dream-wa1ker</name></author><category term="c" /><category term="cve" /><category term="linux" /><category term="lpe" /><category term="cybersec" /><summary type="html"><![CDATA[This is the first public exploitation that I am performing, because I know that this exploit exists, and know its targets. It is one of the many recent linux LPE exploits that were discovered in 2026 - CVE-2026-31431. This blog is about a complete writeup on how and why this exploit works, everything that's behind it.]]></summary></entry><entry><title type="html">A Quine in the Wild: Reconstructing C from x86-64 Assembly</title><link href="https://blog.dream-wa1ker.tech/first-disassembly-a-quine/" rel="alternate" type="text/html" title="A Quine in the Wild: Reconstructing C from x86-64 Assembly" /><published>2026-08-10T00:00:00+00:00</published><updated>2026-08-10T00:00:00+00:00</updated><id>https://blog.dream-wa1ker.tech/first-disassembly-a-quine</id><content type="html" xml:base="https://blog.dream-wa1ker.tech/first-disassembly-a-quine/"><![CDATA[<section>

  <h2 class="section-label" id="the-introduction">The Introduction</h2>

  <div class="description">

    <p>This is a single stripped ELF binary, that I don’t know what it is - the rule is that I should not execute it unless I figured out what it is. I tried <code class="language-plaintext highlighter-rouge">catting</code> it out, seems like it is just raw bytes.</p>

    <p><strong>Clearance 1</strong> : I have got no hints, but just a binary file which you can download from <a href="../assets/blogs/binaries/elf">here</a>.</p>

    <p>It turns out to be a <strong>quine</strong> - a program whose only output is its own source code. That makes it an interesting RE target because the format string hidden in <code class="language-plaintext highlighter-rouge">.rodata</code> <em>is</em> the answer, and finding it means reading raw bytes that the disassembler happily misinterprets as nonsense instructions. But remember, we still do not know what <code class="language-plaintext highlighter-rouge">elf</code> is.</p>

    <p>This post is a walkthrough of every step: stack mechanics, the System V AMD64 calling convention, variadic argument spilling onto the stack, and manual byte-by-byte decoding of a C string from a data section that <code class="language-plaintext highlighter-rouge">objdump</code> was never asked to decode. <code class="language-plaintext highlighter-rouge">objdump</code> does not show us all the bytes. Some bytes are meant to be transformed into assembly instructions, only some are valid strings.</p>

  </div>
</section>

<section>

  <h2 class="section-label" id="the-disassembly-section">The Disassembly Section</h2>

  <div class="description">

    <p>Here is the full <code class="language-plaintext highlighter-rouge">main</code>, straight from <code class="language-plaintext highlighter-rouge">objdump</code>:</p>

    <p><strong>Clearance 2</strong> : To get the similarly same output as below, you have to have <code class="language-plaintext highlighter-rouge">objdump</code> installed in your system and run the following command.</p>

    <div class="highlighter-rouge">
  <pre class="highlight"><code class="language-bash">objdump -d -M intel ./elf
# provided that you have the elf binary downloaded from the clearance 1.</code></pre>
</div>

    <div class="highlighter-rouge">
  <pre class="highlight"><code class="language-asm">0000000000001139 &lt;main&gt;:
    1139:  55                      push   rbp
    113a:  48 89 e5                mov    rbp,rsp
    113d:  48 83 ec 10             sub    rsp,0x10
    1141:  48 8d 05 c0 0e 00 00    lea    rax,[rip+0xec0]   # 2008
    1148:  48 89 45 f8             mov    QWORD PTR [rbp-0x8],rax
    114c:  48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8]
    1150:  48 83 ec 08             sub    rsp,0x8
    1154:  6a 0a                   push   0xa
    1156:  6a 0a                   push   0xa
    1158:  6a 09                   push   0x9
    115a:  6a 0a                   push   0xa
    115c:  6a 09                   push   0x9
    115e:  6a 0a                   push   0xa
    1160:  6a 22                   push   0x22
    1162:  ff 75 f8                push   QWORD PTR [rbp-0x8]
    1165:  6a 22                   push   0x22
    1167:  41 b9 09 00 00 00       mov    r9d,0x9
    116d:  41 b8 0a 00 00 00       mov    r8d,0xa
    1173:  b9 0a 00 00 00          mov    ecx,0xa
    1178:  ba 0a 00 00 00          mov    edx,0xa
    117d:  be 0a 00 00 00          mov    esi,0xa
    1182:  48 89 c7                mov    rdi,rax
    1185:  b8 00 00 00 00          mov    eax,0x0
    118a:  e8 a1 fe ff ff          call   1030 &lt;printf@plt&gt;
    118f:  48 83 c4 50             add    rsp,0x50
    1193:  b8 00 00 00 00          mov    eax,0x0
    1198:  c9                      leave
    1199:  c3                      ret</code></pre>
</div>

    <p>I have already a lot to unpack. Let’s go piece by piece.</p>

  </div>
</section>

<section>

  <h2 class="section-label" id="setting-up-the-stack-frame">Setting up the Stack Frame</h2>

  <div class="description">

    <p>The first three instructions are the standard prologue:</p>

    <div class="highlighter-rouge">
  <pre class="highlight"><code class="language-asm">push   rbp          ; save caller's base pointer
mov    rbp, rsp     ; set our own frame base
sub    rsp, 0x10    ; reserve 16 bytes of local space</code></pre>
</div>

    <p><code class="language-plaintext highlighter-rouge">push</code> is two micro-operations back to back: <code class="language-plaintext highlighter-rouge">sub rsp, 8</code> then <code class="language-plaintext highlighter-rouge">mov [rsp], value</code>. The stack grows <em>downward</em>, so pushing something expands it toward lower addresses.</p>

    <p>When the linker’s <code class="language-plaintext highlighter-rouge">_start</code> calls <code class="language-plaintext highlighter-rouge">main</code>, the return address is already sitting on the stack, which means RSP is 8-byte aligned but not 16-byte aligned at that moment. <code class="language-plaintext highlighter-rouge">push rbp</code> subtracts another 8 bytes, which brings RSP back to a 16-byte boundary. After that, <code class="language-plaintext highlighter-rouge">sub rsp, 0x10</code> keeps it aligned and carves out 16 bytes of local variable space.</p>

    <blockquote>
      <p>The System V AMD64 ABI requires RSP to be 16-byte aligned <strong>before</strong> every <code class="language-plaintext highlighter-rouge">call</code> instruction. The <code class="language-plaintext highlighter-rouge">push rbp</code> at the very top of <code class="language-plaintext highlighter-rouge">main</code> is what restores that invariant, since <code class="language-plaintext highlighter-rouge">_start</code> already knocked it off by 8 when it called us.</p>
    </blockquote>

    <p>With 16 bytes reserved, we have room for two 8-byte locals. Only one is actually used here: <code class="language-plaintext highlighter-rouge">[rbp-0x8]</code>.</p>

    <p>So, basically the first instruction <code class="language-plaintext highlighter-rouge">push</code> copies the caller’s base pointer onto the stack, writing 8 bytes (standard pointer size in x86-64), after making room to accommodate the pointer by micro-operation <code class="language-plaintext highlighter-rouge">sub rsp, 8</code>.</p>

    <p>Then the next instruction <code class="language-plaintext highlighter-rouge">mov</code> copies into the <code class="language-plaintext highlighter-rouge">rbp</code> (base pointer) the current <code class="language-plaintext highlighter-rouge">rsp</code>’s value (i.e, stack pointer) to setup a new stack frame for the <code class="language-plaintext highlighter-rouge">main</code> function.</p>

    <p>The final instruction in standard prologue is reserving the space, 16 bytes. (it is 16 and not any other lesser or non multiple as stack address requires to be a multiple of 16)</p>

  </div>
</section>

<section>

  <h2 class="section-label" id="loading-the-format-string-pointer">Loading the format string pointer</h2>

  <div class="description">

    <div class="highlighter-rouge">
  <pre class="highlight"><code class="language-asm">lea    rax, [rip+0xec0]      ; rax = address of something at 0x2008
mov    QWORD PTR [rbp-0x8], rax   ; store it as a local variable
mov    rax, QWORD PTR [rbp-0x8]   ; load it back into rax</code></pre>
</div>

    <p><code class="language-plaintext highlighter-rouge">lea</code> does not dereference - it just computes and stores the address. The comment from <code class="language-plaintext highlighter-rouge">objdump</code> tells us the resolved address is <code class="language-plaintext highlighter-rouge">0x2008</code>, which lands inside a section the disassembler labelled <code class="language-plaintext highlighter-rouge">_IO_stdin_used</code> (a read-only data sentinel the linker drops in). The actual string <em>starts</em> at <code class="language-plaintext highlighter-rouge">0x2008</code>.</p>

    <p>The store-then-immediately-load looks redundant and probably is - a compiler generating unoptimised code (<code class="language-plaintext highlighter-rouge">-O0</code>) will faithfully write and re-read every local even when it doesn’t have to. The net result: <code class="language-plaintext highlighter-rouge">rax</code> holds a pointer to the format string.</p>

    <p>This address is computed using <strong>RIP-relative addressing</strong>: instead of embedding an absolute address (which would break position-independent executables), the instruction says “whatever address I’m currently at, plus 0xec0.” At link time that offset is calculated so the target is always <code class="language-plaintext highlighter-rouge">0x2008</code> regardless of where the binary gets mapped. <code class="language-plaintext highlighter-rouge">rip</code> is a register - <strong>Register Instruction Pointer</strong>, which points to the next instruction that is to be executed by the CPU.</p>

    <p><code class="language-plaintext highlighter-rouge">QWORD PTR</code> : these words are just denoting that the dereferenced address is 8 bytes (quad-word) and is a pointer.</p>

  </div>
</section>

<section>

  <h2 class="section-label" id="why-there-are-15-arguments-and-where-they-go">Why there are 15 arguments and where they go</h2>

  <div class="description">

    <p>The System V AMD64 ABI lets you pass the first six integer/pointer arguments in registers, in order:</p>

    <p>I need to remember these registers in my mind, so as to setup the correct arguments.</p>

    <div class="highlighter-rouge">
  <pre class="highlight"><code class="language-asm">rdi, rsi, rdx, rcx, r8, r9</code></pre>
</div>

    <p><code class="language-plaintext highlighter-rouge">printf</code> here takes <strong>15 arguments</strong> (one format string plus fourteen values). Six fit in registers; the remaining nine have to go on the stack. The ABI says stack arguments are pushed <strong>right-to-left</strong>, so the last argument gets pushed first and ends up deepest in the stack, while argument 7 (the first stack argument) is pushed last and ends up shallowest — right where <code class="language-plaintext highlighter-rouge">printf</code> can pick it up.</p>

    <ul>
      <li>How did I figure out the 15 arguments? It is just we need to remember what is moved into the registers.</li>
      <li>The first 6 registers that are meant to take up arguments for a function call took the following values as provided in the below table.</li>
      <li>And there were also <code class="language-plaintext highlighter-rouge">push</code> instruction that is copying those values onto the stack, hence growing the stack downwards. Normally, when the registers meant for storing arguments are exhausted, the <code class="language-plaintext highlighter-rouge">printf</code> function reads it from the stack, as long as the number of <code class="language-plaintext highlighter-rouge">formatters</code> in the <code class="language-plaintext highlighter-rouge">format string</code> (first argument) is satisfied.</li>
      <li>But here, the first argument is in the <code class="language-plaintext highlighter-rouge">rdi</code> (register destination index) and that is having a pointer to an address, and relative to <code class="language-plaintext highlighter-rouge">rip</code>, the address is <code class="language-plaintext highlighter-rouge">2008</code>. But in our <code class="language-plaintext highlighter-rouge">objdump</code> output, that address was not shown, because it was in a <code class="language-plaintext highlighter-rouge">.rodata</code> section and we need to use the <code class="language-plaintext highlighter-rouge">-D flag</code> instead of the <code class="language-plaintext highlighter-rouge">-d flag</code>.</li>
    </ul>

    <p><strong>Clearance 3</strong> : Therefore, the format string has 14 format specifiers (formatters) and hence, 5 of them stored in registers and the rest of them <code class="language-plaintext highlighter-rouge">push</code>ed onto the stack.</p>

    <p>Mapping every argument, we just need to write down what is pushed on the stack:</p>

    <table>
      <thead>
        <tr>
          <th>#</th>
          <th>Location</th>
          <th>Value</th>
          <th>Meaning</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>1</td>
          <td><code class="language-plaintext highlighter-rouge">rdi</code></td>
          <td><code class="language-plaintext highlighter-rouge">0x2008</code> pointer</td>
          <td>format string</td>
        </tr>
        <tr>
          <td>2</td>
          <td><code class="language-plaintext highlighter-rouge">rsi</code></td>
          <td><code class="language-plaintext highlighter-rouge">0xa</code></td>
          <td><code class="language-plaintext highlighter-rouge">'\n'</code></td>
        </tr>
        <tr>
          <td>3</td>
          <td><code class="language-plaintext highlighter-rouge">rdx</code></td>
          <td><code class="language-plaintext highlighter-rouge">0xa</code></td>
          <td><code class="language-plaintext highlighter-rouge">'\n'</code></td>
        </tr>
        <tr>
          <td>4</td>
          <td><code class="language-plaintext highlighter-rouge">rcx</code></td>
          <td><code class="language-plaintext highlighter-rouge">0xa</code></td>
          <td><code class="language-plaintext highlighter-rouge">'\n'</code></td>
        </tr>
        <tr>
          <td>5</td>
          <td><code class="language-plaintext highlighter-rouge">r8d</code></td>
          <td><code class="language-plaintext highlighter-rouge">0xa</code></td>
          <td><code class="language-plaintext highlighter-rouge">'\n'</code></td>
        </tr>
        <tr>
          <td>6</td>
          <td><code class="language-plaintext highlighter-rouge">r9d</code></td>
          <td><code class="language-plaintext highlighter-rouge">0x9</code></td>
          <td><code class="language-plaintext highlighter-rouge">'\t'</code></td>
        </tr>
        <tr>
          <td>7</td>
          <td>stack</td>
          <td><code class="language-plaintext highlighter-rouge">0x22</code> = 34</td>
          <td><code class="language-plaintext highlighter-rouge">'"'</code></td>
        </tr>
        <tr>
          <td>8</td>
          <td>stack</td>
          <td><code class="language-plaintext highlighter-rouge">[rbp-0x8]</code></td>
          <td>pointer to <code class="language-plaintext highlighter-rouge">fixed</code> (the string itself)</td>
        </tr>
        <tr>
          <td>9</td>
          <td>stack</td>
          <td><code class="language-plaintext highlighter-rouge">0x22</code> = 34</td>
          <td><code class="language-plaintext highlighter-rouge">'"'</code></td>
        </tr>
        <tr>
          <td>10</td>
          <td>stack</td>
          <td><code class="language-plaintext highlighter-rouge">0xa</code></td>
          <td><code class="language-plaintext highlighter-rouge">'\n'</code></td>
        </tr>
        <tr>
          <td>11</td>
          <td>stack</td>
          <td><code class="language-plaintext highlighter-rouge">0x9</code></td>
          <td><code class="language-plaintext highlighter-rouge">'\t'</code></td>
        </tr>
        <tr>
          <td>12</td>
          <td>stack</td>
          <td><code class="language-plaintext highlighter-rouge">0xa</code></td>
          <td><code class="language-plaintext highlighter-rouge">'\n'</code></td>
        </tr>
        <tr>
          <td>13</td>
          <td>stack</td>
          <td><code class="language-plaintext highlighter-rouge">0x9</code></td>
          <td><code class="language-plaintext highlighter-rouge">'\t'</code></td>
        </tr>
        <tr>
          <td>14</td>
          <td>stack</td>
          <td><code class="language-plaintext highlighter-rouge">0xa</code></td>
          <td><code class="language-plaintext highlighter-rouge">'\n'</code></td>
        </tr>
        <tr>
          <td>15</td>
          <td>stack</td>
          <td><code class="language-plaintext highlighter-rouge">0xa</code></td>
          <td><code class="language-plaintext highlighter-rouge">'\n'</code></td>
        </tr>
      </tbody>
    </table>

    <p>Notice argument 8: <code class="language-plaintext highlighter-rouge">push QWORD PTR [rbp-0x8]</code> — this dereferences the local variable and pushes the <em>pointer value</em> itself. So <code class="language-plaintext highlighter-rouge">printf</code> receives the address of the format string <em>as one of its own arguments</em>. Mm, interesting takeaway. What string will take itself as its format string?</p>

    <p>The <code class="language-plaintext highlighter-rouge">sub rsp, 0x8</code> before the pushes (at <code class="language-plaintext highlighter-rouge">0x1150</code>) is just there to maintain 16-byte alignment as the nine stack arguments are being assembled. After <code class="language-plaintext highlighter-rouge">printf</code> returns, <code class="language-plaintext highlighter-rouge">add rsp, 0x50</code> cleans the whole thing up: <code class="language-plaintext highlighter-rouge">0x50</code> = 80 bytes = 8 (alignment pad) + 9×8 (stack args).</p>

    <p>Here, the last argument should be pushed first onto the stack because the stack is <strong>first in first out</strong> datastructure. Therefore, whatever is pushed at last will be the <code class="language-plaintext highlighter-rouge">printf</code>’s next argument.</p>

    <p>Notice these <code class="language-plaintext highlighter-rouge">push</code> instructions.</p>

    <div class="highlighter-rouge">
<pre class="highlight"><code class="language-asm">
1154:  6a 0a                   push   0xa
1156:  6a 0a                   push   0xa
1158:  6a 09                   push   0x9
115a:  6a 0a                   push   0xa
115c:  6a 09                   push   0x9
115e:  6a 0a                   push   0xa
1160:  6a 22                   push   0x22
1162:  ff 75 f8                push   QWORD PTR [rbp-0x8]
1165:  6a 22                   push   0x22
</code></pre>
</div>

  </div>
</section>

<section>

  <h2 class="section-label" id="decoding-the-format-string-from-raw-bytes">Decoding the format string from raw bytes</h2>

  <div class="description">

    <p>The string lives in the read-only data section starting at <code class="language-plaintext highlighter-rouge">0x2008</code>. <code class="language-plaintext highlighter-rouge">objdump -D</code> disassembles <em>everything</em>, including data sections, so it reads those bytes and prints them as if they were x86 instructions — producing nonsense like:</p>

    <div class="highlighter-rouge">
  <pre class="highlight"><code class="language-asm">2008:  23 69 6e    and  ebp,DWORD PTR [rcx+0x6e]
200b:  63 6c 75 64 movsxd ebp,DWORD PTR [rbp+rsi*2+0x64]</code></pre>
</div>

    <p>Those are not real instructions, reverse engineers call them <em>pseudo instructions</em>. They are character bytes being misread as <em>opcodes</em> (assembly instruction keywords). The actual data is just the ASCII values, (which I just copied that entire section starting from <code class="language-plaintext highlighter-rouge">2008</code> till end of section, put into <strong>gemini</strong> to provide raw bytes mapped into ascii characters):</p>

    <table>
      <thead>
        <tr>
          <th>Hex</th>
          <th>Char</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><code class="language-plaintext highlighter-rouge">23</code></td>
          <td><code class="language-plaintext highlighter-rouge">#</code></td>
        </tr>
        <tr>
          <td><code class="language-plaintext highlighter-rouge">69</code></td>
          <td><code class="language-plaintext highlighter-rouge">i</code></td>
        </tr>
        <tr>
          <td><code class="language-plaintext highlighter-rouge">6e</code></td>
          <td><code class="language-plaintext highlighter-rouge">n</code></td>
        </tr>
        <tr>
          <td><code class="language-plaintext highlighter-rouge">63</code></td>
          <td><code class="language-plaintext highlighter-rouge">c</code></td>
        </tr>
        <tr>
          <td><code class="language-plaintext highlighter-rouge">6c</code></td>
          <td><code class="language-plaintext highlighter-rouge">l</code></td>
        </tr>
        <tr>
          <td><code class="language-plaintext highlighter-rouge">75</code></td>
          <td><code class="language-plaintext highlighter-rouge">u</code></td>
        </tr>
        <tr>
          <td><code class="language-plaintext highlighter-rouge">64</code></td>
          <td><code class="language-plaintext highlighter-rouge">d</code></td>
        </tr>
        <tr>
          <td><code class="language-plaintext highlighter-rouge">65</code></td>
          <td><code class="language-plaintext highlighter-rouge">e</code></td>
        </tr>
        <tr>
          <td><code class="language-plaintext highlighter-rouge">20</code></td>
          <td>` `</td>
        </tr>
        <tr>
          <td><code class="language-plaintext highlighter-rouge">3c</code></td>
          <td><code class="language-plaintext highlighter-rouge">&lt;</code></td>
        </tr>
        <tr>
          <td><code class="language-plaintext highlighter-rouge">73</code></td>
          <td><code class="language-plaintext highlighter-rouge">s</code></td>
        </tr>
        <tr>
          <td>…</td>
          <td>…</td>
        </tr>
      </tbody>
    </table>

    <p>The null terminator (<code class="language-plaintext highlighter-rouge">00</code>) marks the end. You can verify the whole thing instantly with:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>strings elf
</code></pre></div>    </div>

    <p>The full format string is:</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include &amp;lt;stdio.h&amp;gt;%c#include &amp;lt;stdlib.h&amp;gt;%c%cint main(void) {%c%cconst char* fixed = %c%s%c;%c%cprintf(fixed, 10, 10, 10, 10, 9, 34, fixed, 34, 10, 9, 10, 9, 10, 10);%c%creturn EXIT_SUCCESS;%c}%c
</span></code></pre></div>    </div>

    <p>Every <code class="language-plaintext highlighter-rouge">%c</code> gets substituted with a character value from the argument list. With <code class="language-plaintext highlighter-rouge">'\n'</code> (10) and <code class="language-plaintext highlighter-rouge">'\t'</code> (9) in the right slots, the output is properly indented C source. The <code class="language-plaintext highlighter-rouge">%s</code> in the middle gets the pointer to <code class="language-plaintext highlighter-rouge">fixed</code> itself - argument 8 - so the string prints <em>its own contents</em> as the value of the <code class="language-plaintext highlighter-rouge">fixed</code> variable. That is the quine mechanism.</p>

  </div>
</section>

<section>

  <h2 class="section-label" id="the-reconstructed-source">The reconstructed source</h2>

  <div class="description">

    <p>Putting it all together:</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>

  <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">fixed</span> <span class="o">=</span> <span class="s">"#include &amp;lt;stdio.h&amp;gt;%c#include &amp;lt;stdlib.h&amp;gt;%c%cint main(void) {%c%cconst char* fixed = %c%s%c;%c%cprintf(fixed, 10, 10, 10, 10, 9, 34, fixed, 34, 10, 9, 10, 9, 10, 10);%c%creturn EXIT_SUCCESS;%c}%c"</span><span class="p">;</span>

  <span class="n">printf</span><span class="p">(</span><span class="n">fixed</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">34</span><span class="p">,</span> <span class="n">fixed</span><span class="p">,</span> <span class="mi">34</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>

  <span class="k">return</span> <span class="n">EXIT_SUCCESS</span><span class="p">;</span>

<span class="p">}</span>
</code></pre></div>    </div>

    <p>Run it, and it prints itself. That is the whole program.</p>

    <blockquote>
      <p>The string is both the format template <em>and</em> the data being formatted. <code class="language-plaintext highlighter-rouge">%s</code> is the slot where <code class="language-plaintext highlighter-rouge">fixed</code> gets inserted back in — verbatim, quotes included (argument 7 is <code class="language-plaintext highlighter-rouge">"</code>, argument 8 is the pointer, argument 9 is <code class="language-plaintext highlighter-rouge">"</code> again). Everything else is just whitespaces and stuffs I don’t still get yet, weird bytes.</p>
    </blockquote>

  </div>
</section>

<section>

  <h2 class="section-label" id="so-what-is-it-finally">So, what is it finally?</h2>

  <div class="description">

    <p>A few things were noticed during this that weren’t obvious previously, like these:</p>

    <p><strong>Stack argument ordering is counter-intuitive at first.</strong> Arguments beyond the sixth are pushed right-to-left, so argument 15 is on the stack deepest and argument 7 sits on top. Once you know <code class="language-plaintext highlighter-rouge">printf</code> reads them left-to-right from where <code class="language-plaintext highlighter-rouge">rsp</code> points after the call, the ordering should probably make sense to you as it did to me - it mirrors how a function’s stack frame naturally works.</p>

    <p><strong><code class="language-plaintext highlighter-rouge">objdump -d</code> on a data section is actively misleading.</strong> The disassembler does not know where code ends and data begins in a stripped binary unless it has section headers to guide it. Treating <code class="language-plaintext highlighter-rouge">.rodata</code> bytes as opcodes produces syntactically valid but semantically meaningless output. The right move is to extract the bytes at the known address and decode them as ASCII, or just run <code class="language-plaintext highlighter-rouge">strings</code>.</p>

    <p><strong>RIP-relative addressing is the default in PIE binaries.</strong> <code class="language-plaintext highlighter-rouge">lea rax, [rip+0xec0]</code> is not exotic : it is how GCC generates every reference to a global or string literal in a position-independent executable. The offset is baked in at link time and the absolute address resolves at load time.</p>

    <p><strong><code class="language-plaintext highlighter-rouge">-O0</code> output is verbose but readable.</strong> The pointless <code class="language-plaintext highlighter-rouge">mov [rbp-0x8], rax</code> / <code class="language-plaintext highlighter-rouge">mov rax, [rbp-0x8]</code> cycle is a compiler artefact from storing and reloading every value through its stack slot. An optimised build would have eliminated that entirely, making the disassembly shorter but also collapsing the explicit local variable - potentially harder to follow, not easier, but with only a few lines of C code, it would be just a <strong>little</strong> harder.</p>

    <p><strong>And that’s it, this is my first disassembly on a Quine.</strong></p>

  </div>
</section>]]></content><author><name>dream-wa1ker</name></author><category term="reverse-engineering" /><category term="assembly" /><category term="x86-64" /><category term="c" /><category term="quine" /><category term="abi" /><summary type="html"><![CDATA[This is my first reverse engineering work, a RE on a binary file named - elf. Though it was hard for the first time doing it, all I had to do is use objdump on that binary and go through raw assembly. Through this, I get an idea on how all these things work. Note that this is a primitive yet interesting binary.]]></summary></entry><entry><title type="html">Hey Neo, What is Matrix Protocol?</title><link href="https://blog.dream-wa1ker.tech/matrix-decentralised-chat/" rel="alternate" type="text/html" title="Hey Neo, What is Matrix Protocol?" /><published>2026-07-28T00:00:00+00:00</published><updated>2026-07-28T00:00:00+00:00</updated><id>https://blog.dream-wa1ker.tech/matrix-decentralised-chat</id><content type="html" xml:base="https://blog.dream-wa1ker.tech/matrix-decentralised-chat/"><![CDATA[<section>
  <h2 class="section-label" id="what-matrix-actually-is">What Matrix actually is</h2>
  <div class="description">
    <p>Matrix is a specification (not a single app or company) for how independent servers can talk to each other to support chat, voice/video call signaling, and IoT device communication - all without any single company or server being in charge of the whole network. Think of it as similar in spirit to email: anyone can run a mail server, and servers from different providers can still deliver mail to each other. Matrix does the same thing for real-time messaging.</p>

    <p>I got into this matrix stuff when I realized that LinkedIn is a big scam. Matrix is decentralised, that is no central figure owns it. It is kinda TOR, but in surface web - that is you don’t risk yourself from scammers that are in TOR nodes potentially, plus the matrix.org offers its own server, which is one of the biggest matrix servers in use. Another plus - you can even create your own matrix server, just follow its protocol.</p>

    <p>I have read the specification for the matrix version 1.19 which can be found <a href="https://spec.matrix.org/v1.19/">here</a>. I just refined the same in more comprehensible, in my own words.</p>

    <p>So the core idea is a <strong>decentralized publish-subscribe system</strong>: data (mostly JSON objects) gets published into “rooms,” and any server participating in that room receives and stores a copy, keeping everything in sync even though no central authority owns the conversation.</p>
  </div>
</section>

<section>
  <h2 class="section-label" id="the-guiding-design-principles">The guiding design principles</h2>
  <div class="description">
    <ul>
      <li><strong>Practical over pure</strong> - plain JSON over HTTP/REST, not some exotic new protocol</li>
      <li><strong>Simplicity</strong> - minimal moving parts and dependencies</li>
      <li><strong>Full openness</strong> - anyone can run a server and join the network (open federation), and the spec itself is public with no patent restrictions</li>
      <li><strong>User control</strong> - you pick your own server and client software, you control your own privacy, and you know exactly where your data physically lives. Go to matrix.org, and then try matrix - you would get a list of matrix clients like Element, Element X, Element for web, FluffyChat, and several others.</li>
      <li><strong>No central point of failure or control</strong></li>
      <li><strong>Learning from older protocols</strong> - deliberately borrowing good ideas from XMPP, SIP, IRC, SMTP, IMAP, and NNTP while trying to dodge the problems that plagued each of them, and that’s why I think I should use matrix. Moreover, there are no/less API restrictions, so it is easy for me to create matrix bots to send messages, log details, and retrieve them in a private group with only me and my bot.</li>
    </ul>
  </div>
</section>

<section>
  <h2 class="section-label" id="what-you-can-actually-do-with-it-my-opinion">What you can actually do with it (my opinion)</h2>
  <div class="description">
    <p>The spec supports: creating and managing chat rooms with no single owner; keeping room history synced (eventually consistent) across many servers; sending messages with optional end-to-end encryption; a permission system for inviting/kicking/banning members based on power levels; customizable room metadata (name, topic, aliases); user profile data (avatars, display names); account management (register/login/logout); and linking third-party identifiers like email or phone numbers so people can find each other by info they already know, backed by a network of trusted “identity servers” that verify these mappings.</p>

    <p>The long-term goal is for Matrix to be a general-purpose sync layer for <em>any</em> structured data between people, devices, or services - not just chat.</p>
  </div>
</section>

<section>
  <h2 class="section-label" id="the-api-families">The API families</h2>
  <div class="description">
    <ul>
      <li><strong>Client-Server API</strong> - how your chat app talks to your homeserver: this is what I use for my bot management. You first create a bot account in matrix.org and create a private group for you and your bot. The bot’s homeserver is matrix.org, my primary homeserver may or may not be matrix.org - I may use any other server, thanks again to the Server-Server API, that is matrix.org and anything.org can communicate with each other though they are entirely different servers. After creating and inviting the bot to the group (room), I just use the chat to send a message. Client-Server: the bot is the client, and matrix.org is the server for the bot. In the room, the message needs to reach my primary account - so matrix.org and anything.org will follow the Server-Server API to communicate with each other. Then Server-Client: anything.org will communicate with my primary client to make that message visible.</li>
      <li><strong>Server-Server API</strong> - how homeservers talk to each other (this is what “federation” means): server-server is handled by the homeservers themselves, anything that follows the matrix protocol if configured can be added to the federation. So it is just a configuration to write.</li>
      <li><strong>Application Service API</strong> - a privileged API for bots/bridges that need to act as many virtual users at once. This is exclusively designed for bots, but right now, I don’t need it - just me and my bot, so there is no need for virtual users.</li>
      <li><strong>Identity Service API</strong> - for mapping emails/phone numbers to Matrix accounts</li>
      <li><strong>Push Gateway API</strong> - for delivering mobile push notifications</li>
      <li>Plus specs for room versioning and the Olm/Megolm encryption algorithms used for E2EE</li>
    </ul>
  </div>
</section>

<section>
  <h2 class="section-label" id="how-the-architecture-actually-works">How the architecture actually works</h2>
  <div class="description">
    <p>Every user has a <strong>homeserver</strong> - the server that stores their account and message history. When you send a message, here’s the actual path it takes:</p>

    <ol>
      <li>Your client does an HTTP PUT to your own homeserver with the message content</li>
      <li>Your homeserver adds this to its local copy of the room’s history, cryptographically signs it</li>
      <li>Your homeserver forwards it via another HTTP PUT - this time over the <em>Server-Server</em> API - to every other homeserver that has users in that room: that is, if a room has 3 different users with 3 different homeservers, then it would forward it to all three homeservers.</li>
      <li>Each receiving homeserver checks the signature, validates the content is allowed, and adds it to its own local copy</li>
      <li>The other users receive the new message via a long-held GET request their client keeps open to their homeserver (this technique is called long-polling)</li>
    </ol>

    <blockquote>
      <p>It is basically all PUT, POST, GET.</p>
    </blockquote>

    <p>So a message you send doesn’t go directly to the recipient - it goes to your homeserver, gets replicated to their homeserver, and their homeserver hands it to them. No message ever needs a single “master” server to pass through.</p>

    <p>One important tradeoff: Matrix deliberately prioritizes staying <em>available</em> and tolerating network splits over having perfectly consistent data everywhere instantly (this is a direct reference to the CAP theorem - you can’t fully have Consistency, Availability, and Partition-tolerance all at once, and Matrix picks the latter two).</p>
  </div>
</section>

<section>
  <h2 class="section-label" id="users-identified-by-address-like-ids">Users, identified by address-like IDs</h2>
  <div class="description">
    <p>Every account gets a <strong>user ID</strong> shaped like an email address: <code class="language-plaintext highlighter-rouge">@username:servername</code>. The part after the colon just tells you <em>which homeserver</em> issued the account - it doesn’t mean the conversation data lives only on that server. My bot can be like <code class="language-plaintext highlighter-rouge">@mybot:lolcat.org</code>, and primary be like <code class="language-plaintext highlighter-rouge">@myname:somekind.com</code>.</p>
  </div>
</section>

<section>
  <h2 class="section-label" id="devices">Devices</h2>
  <div class="description">
    <p>In Matrix, “device” doesn’t just mean a physical gadget. Every distinct login session - your phone app, your laptop’s browser tab, a second browser on that same laptop - counts as its own separate “device,” each with its own <code class="language-plaintext highlighter-rouge">device_id</code>. This matters primarily for end-to-end encryption: each device gets its own independent set of encryption keys, so you can revoke just one device (e.g., a stolen phone) without logging out everywhere else. Whether a device is long-lived or gets thrown away depends on the app - a website might create a fresh device every time you log in, while a mobile app might keep reusing the same one across sessions.</p>

    <blockquote>
      <p>Device in this context means - everywhere you are logged in, that is each matrix session is a device. To stabilise that session, you would need a device id. That’s it.</p>
    </blockquote>
  </div>
</section>

<section>
  <h2 class="section-label" id="events">Events</h2>
  <div class="description">
    <p>Every single action in Matrix - sending a message, changing the room name, someone joining - becomes an <strong>event</strong>, which is just a JSON object with a <code class="language-plaintext highlighter-rouge">type</code> field describing what kind of event it is. Built-in event types defined by the spec always start with <code class="language-plaintext highlighter-rouge">m.</code> (like <code class="language-plaintext highlighter-rouge">m.room.message</code>); custom application-specific event types must use reverse-domain naming (like <code class="language-plaintext highlighter-rouge">com.example.game.score</code>) to avoid clashing with other apps’ custom types.</p>

    <p>An important security note baked into the design: event content coming from the network should always be treated as <strong>untrusted input</strong>. A client or server must validate the shape of an event before trusting any of its fields, since there’s no absolute guarantee every expected field will actually be present or of the right type.</p>
  </div>
</section>

<section>
  <h2 class="section-label" id="event-graphs">Event graphs</h2>
  <div class="description">
    <p>Rather than a simple linear timeline, each room’s history is stored as a <strong>directed acyclic graph (DAG)</strong> - every event points back to the event(s) that came immediately before it from that server’s perspective. Usually that’s just one prior event, but if two homeservers send messages at almost the same moment, you can get a temporary fork with two parents pointing at the same predecessor, which then merges back together as new events reference both branches.</p>

    <p>To keep a sense of chronological order without needing a single global clock, every event carries a <strong>depth</strong> number - strictly larger than any of its parents’ depth values. This lets any server figure out relative ordering just by walking the graph, even under network delays. The very first event in any room has a depth of 1. This has something to do with graph theory stuffs, but I am not going in depth into this rabbit hole - for now, this is enough to get started with the API.</p>
  </div>
</section>

<section>
  <h2 class="section-label" id="rooms-or-groups">Rooms (or groups)</h2>
  <div class="description">
    <p>A room is identified by an opaque ID shaped like <code class="language-plaintext highlighter-rouge">!randomstring:servername</code>. That domain suffix is only there to prevent ID collisions globally - it does <strong>not</strong> mean the room is physically hosted on that one server. In federation, a room’s data is actually replicated across every homeserver that has a member in it (remember - it is replicated).</p>

    <p>Room data splits into two categories:</p>

    <ul>
      <li><strong>Message events</strong> - one-off, transient activity: a chat message, a call-setup signal, a file share. Say it is just like the messages sent in WhatsApp, like files sent, files received, etc in a group chat.</li>
      <li><strong>State events</strong> - durable, current facts about the room: its name, topic, member list, which servers are participating. State works like a key-value table, where each entry’s key is a combination of an event type and a “state key,” and newer state events simply overwrite older ones for that same key. Say it is just like a user viewing the group info.</li>
    </ul>

    <p>If two servers create conflicting state changes at nearly the same time (a race condition), Matrix runs a <strong>state resolution algorithm</strong> to deterministically decide which version wins - every server, regardless of the order it received events in, ends up agreeing on the same outcome.</p>

    <p>Each event is cryptographically signed by the server that created it, and that signature covers the event’s parent links, type, depth, and content hash - so tampering is detectable. Servers propagate new events to each other directly (a full-mesh pattern, meaning every server in a room can talk to every other one), and can also request older history (“backfill”) from peers if they’re missing parts of it.</p>
  </div>
</section>

<section>
  <h2 class="section-label" id="room-aliases">Room aliases</h2>
  <div class="description">
    <p>It is better to be read as <code class="language-plaintext highlighter-rouge">#roomname</code> rather than <code class="language-plaintext highlighter-rouge">!oijup24UIOh</code>, and that is why we have this.</p>

    <p>Since room IDs are opaque strings, Matrix also supports <strong>aliases</strong> shaped like <code class="language-plaintext highlighter-rouge">#name:servername</code> - these are the human-readable names you’d actually see or type, like a bookmark. An alias simply points to an underlying room ID, and that mapping isn’t permanent - it can be repointed to a different room ID later. Because of that, clients are expected to resolve an alias to a room ID once and then keep using that ID going forward, rather than re-resolving on every request. Looking up an alias also tells you which servers are known to participate in that room, which is useful info for actually joining it.</p>
  </div>
</section>

<section>
  <h2 class="section-label" id="identity">Identity</h2>
  <div class="description">
    <p>A Matrix “identity” combines your Matrix user ID with any external identifiers (email, phone number, etc.) you’ve chosen to link to it. Third-party ID servers - a separate, trusted, federated network of “identity servers” - verify that you actually own that email or phone number and then store the verified mapping, so other users can find your Matrix account by searching for your email instead of needing your exact Matrix ID. This is entirely optional - you can use Matrix without ever touching an identity server, you just lose the ability to be found via 3rd-party contact info.</p>
  </div>
</section>

<section>
  <h2 class="section-label" id="profiles-and-private-account-data">Profiles and private account data</h2>
  <div class="description">
    <p>Users can publish public profile info (display name, avatar image URL, contact details) that others can see, and separately store private key-value data tied to their account (client settings, preferences) using a symmetrical but non-public API.</p>
  </div>
</section>

<section>
  <h2 class="section-label" id="matrixs-shared-conventions">Matrix’s shared conventions</h2>
  <div class="description">
    <p><strong>Namespacing:</strong> anything under the <code class="language-plaintext highlighter-rouge">m.</code> prefix is officially defined by the spec itself; anything else (custom event types, custom fields) must use reverse-domain naming to avoid two unrelated apps accidentally colliding on the same identifier.</p>

    <p><strong>Timestamps:</strong> everywhere in the spec, a timestamp means milliseconds since the Unix epoch (Jan 1, 1970 UTC), and leap seconds are deliberately ignored so every day is always treated as exactly 86,400,000 milliseconds - I mean this matches how most programming languages already represent time by default.</p>
  </div>
</section>

<section>
  <h2 class="section-label" id="how-the-spec-itself-is-versioned">How the spec itself is versioned</h2>
  <div class="description">
    <p>Matrix allows you to use simultaneous versions, that is you can use the protocol specifying what version of it you want to use, all with just a single version string in the API path.</p>

    <p>The whole specification carries a single version number like <code class="language-plaintext highlighter-rouge">vX.Y</code>. A change to <code class="language-plaintext highlighter-rouge">X</code> signals something big and breaking (e.g., dropping JSON entirely, changing the cryptographic signing approach). A change to <code class="language-plaintext highlighter-rouge">Y</code> means new features added in a backwards-compatible way. There’s no guarantee that, say, v1.3 stays compatible with v1.1 - only that each step (v1.1 → v1.2) is meant to be safe.</p>

    <p>Individual <strong>endpoints</strong> are versioned separately from the spec as a whole - so <code class="language-plaintext highlighter-rouge">/v3/sync</code> can be superseded by <code class="language-plaintext highlighter-rouge">/v4/sync</code> without touching or breaking <code class="language-plaintext highlighter-rouge">/v3/profile</code>, which keeps working exactly as it did.</p>

    <p><strong>Deprecation works in stages:</strong> a feature first gets marked deprecated (but servers/clients must still support it), then after roughly one spec version of being deprecated, it becomes eligible for full removal in a later version. If your software advertises support for a spec version that included a now-deprecated endpoint, you’re still required to implement it - you only get to drop it once you stop claiming support for that older version.</p>

    <p><strong>Legacy versioning:</strong> before this unified <code class="language-plaintext highlighter-rouge">vX.Y</code> numbering existed, each of the five APIs (Client-Server, Server-Server, Application Service, Identity Service, Push Gateway) was versioned completely independently using an <code class="language-plaintext highlighter-rouge">rX.Y.Z</code> scheme. What’s now called “Matrix 1.0” was never an official spec version number - it’s really shorthand for a specific combination of those older per-API version numbers, alongside room versions 1 through 5.</p>
  </div>
</section>

<section>
  <h2 class="section-label" id="creating-a-python-automation-script">Creating a python automation script</h2>
  <div class="description">
    <p>This is an example of bot script that I wrote using python for sending messages to a chat. Potentially it can be used for logging activities and sending files/photos, etc stuff and messages from a host machine to the room. It is based on a json file structure which has the access token to the bot account and room id to the room. This should kinda look like something like this :</p>

    <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"name"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"lolcat-api"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"bot"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"username"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"some_random_bot"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"homeserver"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"https://yourhomeserver.tld"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"access_token"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"rct_euepJKSII0UUJvcvfIsL1L1Brw5Ehb_asds4"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"device_id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"0b90dB86UU"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"user_id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"@some_random_bot:matrix.org"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"rooms"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"lolcat-api"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nl">"id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"!OEpoYrzABCBiEWqe3l:matrix.org"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"desc"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"A demo for learning matrix API and bot accounts for internet details redirection"</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div>    </div>

    <p>Note that the above json code is just the structure of how the json file should look like, nothing is real there.</p>

    <p>Next we have this python code which will read and parse the json from the <code class="language-plaintext highlighter-rouge">.data.txt</code> file given above, but there is also a variable called CONFIG using which you can change the path of the data.json. For this purpose, we would be using the <code class="language-plaintext highlighter-rouge">httpx</code> module, that is more advanced and capable than the <code class="language-plaintext highlighter-rouge">requests</code> module in python. Here is the code :</p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env python3
</span>
<span class="c1"># import the necessary modules.
</span><span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">uuid</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">mimetypes</span>
<span class="kn">import</span> <span class="nn">httpx</span>

<span class="c1"># set the global config path.
</span><span class="n">CONFIG</span> <span class="o">=</span> <span class="s">".data.json"</span>  <span class="c1"># adjust path if needed
</span>
<span class="c1"># load the config path
</span><span class="k">def</span> <span class="nf">load_config</span><span class="p">(</span><span class="n">path</span><span class="o">=</span><span class="n">CONFIG</span><span class="p">):</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">json</span><span class="p">.</span><span class="n">load</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>

<span class="c1"># get the home server from the json file.
</span><span class="k">def</span> <span class="nf">get_homeserver</span><span class="p">(</span><span class="n">config</span><span class="p">):</span>
    <span class="n">homeserver</span> <span class="o">=</span> <span class="n">config</span><span class="p">[</span><span class="s">"bot"</span><span class="p">][</span><span class="s">"homeserver"</span><span class="p">]</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">homeserver</span><span class="p">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">"http"</span><span class="p">):</span>
        <span class="n">homeserver</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"https://</span><span class="si">{</span><span class="n">homeserver</span><span class="si">}</span><span class="s">"</span>
    <span class="k">return</span> <span class="n">homeserver</span>

<span class="c1"># define a function to send message to the server.
# for understanding what is happening beneath this function, you need to understand the matrix api.
</span><span class="k">def</span> <span class="nf">send_message</span><span class="p">(</span><span class="n">body</span><span class="p">,</span> <span class="n">room_key</span><span class="p">,</span> <span class="n">config</span><span class="p">,</span> <span class="n">html</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="n">homeserver</span> <span class="o">=</span> <span class="n">get_homeserver</span><span class="p">(</span><span class="n">config</span><span class="p">)</span>
    <span class="n">access_token</span> <span class="o">=</span> <span class="n">config</span><span class="p">[</span><span class="s">"bot"</span><span class="p">][</span><span class="s">"access_token"</span><span class="p">]</span>
    <span class="n">room_id</span> <span class="o">=</span> <span class="n">config</span><span class="p">[</span><span class="s">"rooms"</span><span class="p">][</span><span class="n">room_key</span><span class="p">][</span><span class="s">"id"</span><span class="p">]</span>

    <span class="n">txn_id</span> <span class="o">=</span> <span class="n">uuid</span><span class="p">.</span><span class="n">uuid4</span><span class="p">().</span><span class="nb">hex</span>
    <span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">homeserver</span><span class="si">}</span><span class="s">/_matrix/client/v3/rooms/</span><span class="si">{</span><span class="n">room_id</span><span class="si">}</span><span class="s">/send/m.room.message/</span><span class="si">{</span><span class="n">txn_id</span><span class="si">}</span><span class="s">"</span>

    <span class="n">payload</span> <span class="o">=</span> <span class="p">{</span><span class="s">"msgtype"</span><span class="p">:</span> <span class="s">"m.text"</span><span class="p">,</span> <span class="s">"body"</span><span class="p">:</span> <span class="n">body</span><span class="p">}</span>
    <span class="k">if</span> <span class="n">html</span><span class="p">:</span>
        <span class="n">payload</span><span class="p">[</span><span class="s">"format"</span><span class="p">]</span> <span class="o">=</span> <span class="s">"org.matrix.custom.html"</span>
        <span class="n">payload</span><span class="p">[</span><span class="s">"formatted_body"</span><span class="p">]</span> <span class="o">=</span> <span class="n">html</span>

    <span class="n">resp</span> <span class="o">=</span> <span class="n">httpx</span><span class="p">.</span><span class="n">put</span><span class="p">(</span>
        <span class="n">url</span><span class="p">,</span>
        <span class="n">json</span><span class="o">=</span><span class="n">payload</span><span class="p">,</span>
        <span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="s">"Authorization"</span><span class="p">:</span> <span class="sa">f</span><span class="s">"Bearer </span><span class="si">{</span><span class="n">access_token</span><span class="si">}</span><span class="s">"</span><span class="p">},</span>
    <span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="p">.</span><span class="n">is_success</span><span class="p">:</span>
        <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="sa">f</span><span class="s">"Matrix API error </span><span class="si">{</span><span class="n">resp</span><span class="p">.</span><span class="n">status_code</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">resp</span><span class="p">.</span><span class="n">text</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">resp</span><span class="p">.</span><span class="n">json</span><span class="p">()</span>


<span class="k">def</span> <span class="nf">upload_file</span><span class="p">(</span><span class="n">filepath</span><span class="p">,</span> <span class="n">config</span><span class="p">):</span>
    <span class="n">homeserver</span> <span class="o">=</span> <span class="n">get_homeserver</span><span class="p">(</span><span class="n">config</span><span class="p">)</span>
    <span class="n">access_token</span> <span class="o">=</span> <span class="n">config</span><span class="p">[</span><span class="s">"bot"</span><span class="p">][</span><span class="s">"access_token"</span><span class="p">]</span>

    <span class="n">mimetype</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">mimetypes</span><span class="p">.</span><span class="n">guess_type</span><span class="p">(</span><span class="n">filepath</span><span class="p">)</span>
    <span class="n">mimetype</span> <span class="o">=</span> <span class="n">mimetype</span> <span class="ow">or</span> <span class="s">"application/octet-stream"</span>

    <span class="n">filename</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">basename</span><span class="p">(</span><span class="n">filepath</span><span class="p">)</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filepath</span><span class="p">,</span> <span class="s">"rb"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">data</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>

    <span class="n">resp</span> <span class="o">=</span> <span class="n">httpx</span><span class="p">.</span><span class="n">post</span><span class="p">(</span>
        <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">homeserver</span><span class="si">}</span><span class="s">/_matrix/media/v3/upload"</span><span class="p">,</span>
        <span class="n">params</span><span class="o">=</span><span class="p">{</span><span class="s">"filename"</span><span class="p">:</span> <span class="n">filename</span><span class="p">},</span>
        <span class="n">headers</span><span class="o">=</span><span class="p">{</span>
            <span class="s">"Authorization"</span><span class="p">:</span> <span class="sa">f</span><span class="s">"Bearer </span><span class="si">{</span><span class="n">access_token</span><span class="si">}</span><span class="s">"</span><span class="p">,</span>
            <span class="s">"Content-Type"</span><span class="p">:</span> <span class="n">mimetype</span><span class="p">,</span>
        <span class="p">},</span>
        <span class="n">content</span><span class="o">=</span><span class="n">data</span><span class="p">,</span>
    <span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="p">.</span><span class="n">is_success</span><span class="p">:</span>
        <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="sa">f</span><span class="s">"Upload failed </span><span class="si">{</span><span class="n">resp</span><span class="p">.</span><span class="n">status_code</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">resp</span><span class="p">.</span><span class="n">text</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">resp</span><span class="p">.</span><span class="n">json</span><span class="p">()[</span><span class="s">"content_uri"</span><span class="p">],</span> <span class="n">mimetype</span>


<span class="k">def</span> <span class="nf">send_file</span><span class="p">(</span><span class="n">filepath</span><span class="p">,</span> <span class="n">room_key</span><span class="p">,</span> <span class="n">config</span><span class="p">,</span> <span class="n">msgtype</span><span class="o">=</span><span class="s">"m.file"</span><span class="p">):</span>
    <span class="n">homeserver</span> <span class="o">=</span> <span class="n">get_homeserver</span><span class="p">(</span><span class="n">config</span><span class="p">)</span>
    <span class="n">access_token</span> <span class="o">=</span> <span class="n">config</span><span class="p">[</span><span class="s">"bot"</span><span class="p">][</span><span class="s">"access_token"</span><span class="p">]</span>
    <span class="n">room_id</span> <span class="o">=</span> <span class="n">config</span><span class="p">[</span><span class="s">"rooms"</span><span class="p">][</span><span class="n">room_key</span><span class="p">][</span><span class="s">"id"</span><span class="p">]</span>

    <span class="n">mxc_uri</span><span class="p">,</span> <span class="n">mimetype</span> <span class="o">=</span> <span class="n">upload_file</span><span class="p">(</span><span class="n">filepath</span><span class="p">,</span> <span class="n">config</span><span class="p">)</span>
    <span class="n">filename</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">basename</span><span class="p">(</span><span class="n">filepath</span><span class="p">)</span>
    <span class="n">filesize</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">getsize</span><span class="p">(</span><span class="n">filepath</span><span class="p">)</span>

    <span class="n">txn_id</span> <span class="o">=</span> <span class="n">uuid</span><span class="p">.</span><span class="n">uuid4</span><span class="p">().</span><span class="nb">hex</span>
    <span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">homeserver</span><span class="si">}</span><span class="s">/_matrix/client/v3/rooms/</span><span class="si">{</span><span class="n">room_id</span><span class="si">}</span><span class="s">/send/m.room.message/</span><span class="si">{</span><span class="n">txn_id</span><span class="si">}</span><span class="s">"</span>

    <span class="n">payload</span> <span class="o">=</span> <span class="p">{</span>
        <span class="s">"msgtype"</span><span class="p">:</span> <span class="n">msgtype</span><span class="p">,</span>  <span class="c1"># m.file, m.image, m.audio, m.video
</span>        <span class="s">"body"</span><span class="p">:</span> <span class="n">filename</span><span class="p">,</span>
        <span class="s">"url"</span><span class="p">:</span> <span class="n">mxc_uri</span><span class="p">,</span>
        <span class="s">"info"</span><span class="p">:</span> <span class="p">{</span><span class="s">"size"</span><span class="p">:</span> <span class="n">filesize</span><span class="p">,</span> <span class="s">"mimetype"</span><span class="p">:</span> <span class="n">mimetype</span><span class="p">},</span>
    <span class="p">}</span>

    <span class="n">resp</span> <span class="o">=</span> <span class="n">httpx</span><span class="p">.</span><span class="n">put</span><span class="p">(</span>
        <span class="n">url</span><span class="p">,</span>
        <span class="n">json</span><span class="o">=</span><span class="n">payload</span><span class="p">,</span>
        <span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="s">"Authorization"</span><span class="p">:</span> <span class="sa">f</span><span class="s">"Bearer </span><span class="si">{</span><span class="n">access_token</span><span class="si">}</span><span class="s">"</span><span class="p">},</span>
    <span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="p">.</span><span class="n">is_success</span><span class="p">:</span>
        <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="sa">f</span><span class="s">"Matrix API error </span><span class="si">{</span><span class="n">resp</span><span class="p">.</span><span class="n">status_code</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">resp</span><span class="p">.</span><span class="n">text</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">resp</span><span class="p">.</span><span class="n">json</span><span class="p">()</span>


<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">:</span>
        <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span>
            <span class="s">"Usage:</span><span class="se">\n</span><span class="s">"</span>
            <span class="s">'  python send-files-httpx.py msg &lt;room-key&gt; "message text"</span><span class="se">\n</span><span class="s">'</span>
            <span class="s">"  python send-files-httpx.py file &lt;room-key&gt; &lt;filepath&gt; [--type m.image]"</span>
        <span class="p">)</span>

    <span class="n">action</span><span class="p">,</span> <span class="n">room_key</span> <span class="o">=</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
    <span class="n">config</span> <span class="o">=</span> <span class="n">load_config</span><span class="p">()</span>

    <span class="k">if</span> <span class="n">action</span> <span class="o">==</span> <span class="s">"msg"</span><span class="p">:</span>
        <span class="n">message</span> <span class="o">=</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">send_message</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">room_key</span><span class="p">,</span> <span class="n">config</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Sent message to </span><span class="si">{</span><span class="n">room_key</span><span class="si">}</span><span class="s">. Event ID: </span><span class="si">{</span><span class="n">result</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'event_id'</span><span class="p">)</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

    <span class="k">elif</span> <span class="n">action</span> <span class="o">==</span> <span class="s">"file"</span><span class="p">:</span>
        <span class="n">filepath</span> <span class="o">=</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
        <span class="n">msgtype</span> <span class="o">=</span> <span class="s">"m.file"</span>
        <span class="k">if</span> <span class="s">"--type"</span> <span class="ow">in</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">:</span>
            <span class="n">msgtype</span> <span class="o">=</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">.</span><span class="n">index</span><span class="p">(</span><span class="s">"--type"</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">send_file</span><span class="p">(</span><span class="n">filepath</span><span class="p">,</span> <span class="n">room_key</span><span class="p">,</span> <span class="n">config</span><span class="p">,</span> <span class="n">msgtype</span><span class="o">=</span><span class="n">msgtype</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Sent file to </span><span class="si">{</span><span class="n">room_key</span><span class="si">}</span><span class="s">. Event ID: </span><span class="si">{</span><span class="n">result</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'event_id'</span><span class="p">)</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

    <span class="k">else</span><span class="p">:</span>
        <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="sa">f</span><span class="s">"Unknown action '</span><span class="si">{</span><span class="n">action</span><span class="si">}</span><span class="s">'. Use 'msg' or 'file'."</span><span class="p">)</span>


<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>

<span class="c1"># usage for this is :
# python3 send-files-httpx.py &lt;msg-type:msg|file&gt; &lt;message|path/to/file&gt; --type &lt;if image, m.image&gt;
</span></code></pre></div>    </div>

    <p><strong>How to actually use this script to automate the messaging, sending files and messages?</strong></p>

    <p>All we need is just two matrix accounts. (preferable) or even one matrix account (making your primary account act as bot). The difference between the two is that : the room is created by the bot account in first case and the primary account is invited to the room. The latter one, you just create a room and invite no one. You act as a bot and the script sends the message on behalf of you.</p>

    <p><strong>Step 1 :</strong> Create a primary matrix account in your preferred matrix server. Then procceed creating the bot account in case you don’t want to leak your primary account’s access token.</p>

    <p><strong>Step 2 :</strong> Figure out your access token. You can do it by just curling to a matrix API endpoint (this entire blog post will give you some kinda help). You can follow this oneliner -</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Run in Terminal/CLI</span>
curl <span class="nt">-X</span> POST https://yourserver.tld/_matrix/client/v3/login <span class="se">\</span>
     <span class="nt">-H</span> <span class="s2">"Content-Type: application/json"</span> <span class="se">\</span>
     <span class="nt">-d</span> <span class="s1">'{
           "type": "m.login.password",
           "identifier": {"type": "m.id.user", "user": "your_bot_username"},
            "password": "your_bot_passwd"
         }'</span>
</code></pre></div>    </div>

    <p><strong>Step 3 :</strong> Replace the contents of the <code class="language-plaintext highlighter-rouge">.data.json</code> file from the results from your curl. You would need to create a room and get its room id. Replace the dummy id in the file with your original room id. Invite your primary account to the room.</p>

    <p><strong>Step 4 :</strong> Run the python script and you are good to go. See the last comment for usage.</p>

    <blockquote>
      <p>I have not yet published to code to github. I need to document it and explain it, and do some advanced stuffs like defaulting, falling back and learn more of matrix APIs for doing automation and bots. See the official spec given below for more details.</p>
    </blockquote>
  </div>
</section>]]></content><author><name>dream-wa1ker</name></author><category term="matrix" /><category term="federation" /><category term="protocol" /><summary type="html"><![CDATA[This is my first blog post, that is about creating a bot group chat in matrix federation used for automating messages, logging, sending files and messages from a victim to a host, providing an overview of matrix protocol and its specifications.]]></summary></entry></feed>