<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Low Level on Prepakis Georgios | Kernelstub | Security Researcher</title><link>https://blog.kernelstub.dev/tags/low-level/</link><description>Recent content in Low Level on Prepakis Georgios | Kernelstub | Security Researcher</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Fri, 04 Oct 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.kernelstub.dev/tags/low-level/index.xml" rel="self" type="application/rss+xml"/><item><title>Domain Generation Algorithms and Automatic Domain Registration in C2</title><link>https://blog.kernelstub.dev/posts/domain-generation-algorithms-and-automatic-domain-registration-in-c2/</link><pubDate>Fri, 04 Oct 2024 00:00:00 +0000</pubDate><guid>https://blog.kernelstub.dev/posts/domain-generation-algorithms-and-automatic-domain-registration-in-c2/</guid><description>&lt;h2 id="what-is-a-domain-generation-algorithm-dga"&gt;What Is a Domain Generation Algorithm (DGA)?&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re running a botnet, you have a problem: your infected hosts need a way to phone home, but the moment defenders find your command and control (C2) domain, they blocklist it, sinkhole it, or hand it to a takedown request, and your whole fleet goes dark at once. A single hardcoded IP or domain baked into your malware is a single point of failure, and it&amp;rsquo;s the first thing an incident responder goes looking for when they pull apart a sample in a sandbox.&lt;/p&gt;</description></item><item><title>Custom Linux Kernel Hooks with eBPF</title><link>https://blog.kernelstub.dev/posts/custom-linux-kernel-hooks-with-ebpf/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0000</pubDate><guid>https://blog.kernelstub.dev/posts/custom-linux-kernel-hooks-with-ebpf/</guid><description>&lt;h2 id="understanding-ebpf"&gt;Understanding eBPF&lt;/h2&gt;
&lt;h3 id="what-is-ebpf"&gt;What is eBPF?&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;ve ever wanted to peek inside a running Linux kernel without recompiling it, patching it, or crossing your fingers and loading a sketchy out-of-tree module, eBPF is probably the tool you were looking for. The name is short for &amp;ldquo;extended Berkeley Packet Filter,&amp;rdquo; which is a bit of a historical accident: the original BPF, from the late 1980s, was a tiny virtual machine built to do one job, deciding whether a network packet matched a filter (think &lt;code&gt;tcpdump&lt;/code&gt;). It was small, fast, and deliberately dumb, which made it safe to run inside the kernel.&lt;/p&gt;</description></item><item><title>Introduction to ARM Architecture</title><link>https://blog.kernelstub.dev/posts/introduction-to-arm-architecture/</link><pubDate>Sat, 21 Sep 2024 00:00:00 +0000</pubDate><guid>https://blog.kernelstub.dev/posts/introduction-to-arm-architecture/</guid><description>&lt;p&gt;If you&amp;rsquo;ve spent any time around x86 assembly and then gone to look at ARM, the first thing you probably noticed is how much cleaner it feels. That&amp;rsquo;s not an accident. ARM was designed from day one around a philosophy called RISC (Reduced Instruction Set Computer), which trades a huge, irregular menu of complex instructions for a small set of simple, fast, predictable ones. Instead of one instruction doing five things at once (the CISC way, which is how x86 grew up), ARM prefers to do those five things as five simple instructions, each of which the CPU can execute in a single, predictable cycle. This sounds like it should be slower, and instruction-for-instruction it sometimes is, but it makes the hardware simpler, cheaper to build, and dramatically more power efficient, which is exactly why ARM ended up running basically every phone, tablet, and now a growing share of laptops and servers on the planet.&lt;/p&gt;</description></item><item><title>Introduction to x64 ASM</title><link>https://blog.kernelstub.dev/posts/introduction-to-x64-asm/</link><pubDate>Sat, 21 Sep 2024 00:00:00 +0000</pubDate><guid>https://blog.kernelstub.dev/posts/introduction-to-x64-asm/</guid><description>&lt;h2 id="1-introduction-to-assembly-and-x64-architecture"&gt;1. Introduction to Assembly and x64 Architecture&lt;/h2&gt;
&lt;h3 id="what-is-assembly-language"&gt;What is Assembly Language?&lt;/h3&gt;
&lt;p&gt;Every program you&amp;rsquo;ve ever run, whether it&amp;rsquo;s a shell script, a Python interpreter, or a AAA game engine, eventually gets reduced to a stream of raw binary instructions that a CPU can execute directly. Assembly language is the thin, human-readable layer sitting right on top of that binary stream. Each assembly instruction maps almost one-to-one to a single machine instruction, so when you write &lt;code&gt;mov rax, rbx&lt;/code&gt;, you&amp;rsquo;re really just writing a mnemonic for a specific sequence of bits that tells the processor &amp;ldquo;copy the contents of one register into another.&amp;rdquo; There&amp;rsquo;s no compiler doing clever things behind your back, no garbage collector, no runtime. What you write is (almost) exactly what runs.&lt;/p&gt;</description></item><item><title>Introduction to Windows Syscalls</title><link>https://blog.kernelstub.dev/posts/introduction-to-windows-syscalls/</link><pubDate>Tue, 17 Sep 2024 00:00:00 +0000</pubDate><guid>https://blog.kernelstub.dev/posts/introduction-to-windows-syscalls/</guid><description>&lt;h2 id="what-are-system-calls-really"&gt;What Are System Calls, Really?&lt;/h2&gt;
&lt;p&gt;Every time your program does something that touches the outside world, opening a file, allocating memory, talking to the network, waiting on another thread, it&amp;rsquo;s asking the operating system to do that work on its behalf. Your program doesn&amp;rsquo;t get to poke the disk controller or the network card directly. It can&amp;rsquo;t, by design. The CPU itself enforces this separation through privilege rings: user-mode code (ring 3 on x86/x64) runs with a restricted set of permissions, while the kernel (ring 0) runs with full access to hardware and memory. A system call is the formal, controlled doorway between those two worlds.&lt;/p&gt;</description></item><item><title>Linux Syscalls Table (x86-64)</title><link>https://blog.kernelstub.dev/posts/linux-syscalls-table-x86-64/</link><pubDate>Fri, 13 Sep 2024 00:00:00 +0000</pubDate><guid>https://blog.kernelstub.dev/posts/linux-syscalls-table-x86-64/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;Every time a program on Linux does something that touches the outside world, reading a file, allocating memory, sending a packet, spawning another process, it eventually has to ask the kernel to do it. User space code can&amp;rsquo;t just reach into the kernel&amp;rsquo;s data structures and start editing process tables or filesystem metadata; that would be a security and stability nightmare. Instead, it has to go through a narrow, well-defined door: the system call interface. This post is a reference table for that door on x86-64 Linux, listing every syscall number, its libc-facing name, its man page, and the kernel function that actually handles it once your program&amp;rsquo;s request lands.&lt;/p&gt;</description></item><item><title>Advanced C Programming Best Practices</title><link>https://blog.kernelstub.dev/posts/advanced-c-programming-best-practices/</link><pubDate>Mon, 29 Jul 2024 00:00:00 +0000</pubDate><guid>https://blog.kernelstub.dev/posts/advanced-c-programming-best-practices/</guid><description>&lt;p&gt;C gives you almost nothing for free. There&amp;rsquo;s no garbage collector cleaning up after you, no runtime checking your array bounds, no exception handler catching your mistakes before they corrupt memory. That&amp;rsquo;s exactly why C is still the language of choice for operating systems, embedded firmware, and anything that needs to talk directly to hardware, and it&amp;rsquo;s also exactly why C code has such a long, embarrassing history of security vulnerabilities. The language trusts you completely. Most of &amp;ldquo;best practices in C&amp;rdquo; really boils down to one idea: build habits and guardrails that compensate for the safety net the language refuses to provide.&lt;/p&gt;</description></item><item><title>Hooking `getdents64` to Hide Directories in Linux</title><link>https://blog.kernelstub.dev/posts/hooking-getdents64-to-hide-directories-in-linux/</link><pubDate>Wed, 05 Jun 2024 00:00:00 +0000</pubDate><guid>https://blog.kernelstub.dev/posts/hooking-getdents64-to-hide-directories-in-linux/</guid><description>&lt;h2 id="why-directory-hiding-even-works"&gt;Why Directory Hiding Even Works&lt;/h2&gt;
&lt;p&gt;Every time you run &lt;code&gt;ls&lt;/code&gt; in a terminal, or a graphical file manager draws a folder icon, something has to ask the kernel &amp;ldquo;what&amp;rsquo;s in this directory?&amp;rdquo; On Linux that question gets answered by the &lt;code&gt;getdents64&lt;/code&gt; syscall (the modern replacement for the older &lt;code&gt;getdents&lt;/code&gt;). The C library wraps it up neatly, but underneath, every single directory listing you have ever seen on a Linux box came from a userspace program calling into the kernel and getting back a buffer full of &lt;code&gt;linux_dirent64&lt;/code&gt; structures, one per file or subdirectory.&lt;/p&gt;</description></item></channel></rss>