🚀 Building a Low-Level ICMP Sniffer in x64 Assembly (Raw Sockets)
Introduction
In the realm of network security and packet analysis, tools like Python (Scapy) or C are the usual go-tos. However, when we want to strip away all abstraction layers from the OS network stack and talk directly to the processor, resources become incredibly scarce. Finding modern, zero-dependency networking tools written in x64 Assembly on the internet is almost impossible today.
In this post, we will explore the architecture and design decisions behind my x64 Assembly-based ICMP Sniffer project, completely rejecting standard C libraries (libc) and relying purely on direct Linux system calls (syscalls).
The Concept: Why Assembly?
Our goal isn't just to catch ICMP (ping) packets on the network. We want to manually manage memory, register allocations, and data type conversions (integer-to-string) at the CPU cycle level. This approach provides a flawless foundation for understanding how hardware behaves during malware analysis and low-level exploit development.
How Does It Work? (Technical Deep Dive)
The architecture of the tool is divided into three main phases:
1. The Raw Socket Foundation
To capture raw, unprocessed packets passing through the network interface card (NIC), the application uses sys_socket (syscall 41) with AF_INET and SOCK_RAW parameters. Our target here is strictly the IPPROTO_ICMP protocol. This tells the operating system to filter out all TCP/UDP traffic and hand us only the ICMP packets.
2. Packet Interception and Header Stripping
Incoming packets are read into a memory buffer using sys_recvfrom. Since we are using Raw Sockets, the data arrives in its absolute raw form. To reach the actual payload, we must manually bypass the protocol headers:
IPv4 Header: 20 Bytes
ICMP Header: 8 Bytes
Therefore, by utilizing the lea rsi, [sniffed_data + 28] instruction in our Assembly code, we strip away this 28-byte "noise" and dive straight into the heart of the data.
3. The Custom Integer-to-ASCII Engine This is the most complex and educational part of the project. The captured IP address (e.g., 192.168.1.29) resides in memory as raw binary (hexadecimal). To print this to the terminal, we must convert it into a human-readable ASCII string.
Since we aren't using any external printf or itoa functions, I designed the engine as follows:
Each octet (8-bit IP segment) fetched from the network address is divided by 10 using the
divinstruction.We mathematically add 48 (
0x30) to the remainders to convert them into ASCII characters.These converted characters are written into a 16-byte memory buffer in reverse order (from end to start).
Using logical brakes via conditional jumps (
je,jg), dot (.) characters are strategically inserted only between the octets to prevent malformed strings.
Conclusion and Source Code
This tool proves how we can filter not just the "existence" of ICMP packets, but the actual payloads hidden inside them (like data exfiltration or command & control traffic) at the kernel level. Writing our own string conversion engine using nothing but Linux Syscalls, without relying on any external libraries, has been a fantastic exercise in pushing the limits of low-level system programming.
For security researchers, Blue Team members, and exploit development enthusiasts who want to test the tool or review the code, the full source is available on my GitHub profile:
🔗 GitHub Repo: JM00NJ/asm-icmp-sniffer
(⚠️ Disclaimer: This project was developed solely for educational and ethical cybersecurity research purposes. Unauthorized interception of network traffic is illegal.)