===============================
0)¿Por que Pascal?.
1)Introducción.
2)Conocimientos previos.
3)Desarrollando con la libreria WinInet.
4)Hablando de “Return” y “Result” en Pascal.
5)Probando nuestro robot por primera vez.
6)Convirtiendo nuestra PC en un servidor web de pruebas.
7)Creando un contador de visitas en PHP y algo más...
8)Hashes mixtos para nuestra maquina.
9)Un vistazo a la programación monolítica.
10)Limpiando variables en memoria(Apartado de optimizacion 1º parte).
11) Probando nuestro viewbot por 2º vez.
12) Usando el API Winsock para obtener Ips.
13)Finalizando.
14) Probando nuestro viewbot por 3º vez!.
15)Usando StripReloc para hacer el ejecutable mas pequeño y su relación con .reloc(Apartado de optimizacion 2º parte).
16)Mirando en LordPe la sección .reloc.
17)Viendo el Stack y el Heap con WinDbg.
18)Despedida.
===============================
0)¿Por que Pascal?:
Porque es un lenguaje muy potente, sin dudarlo a la altura de C++, que lo supera en algunos aspectos y como comentario personal,
se puede decir que en pascal se han programado grandes troyanos y/o herramientas de hacking.
Pascal tanto como C, lamentablemente son tomados por los novatos de la programación como “lenguajes de alto nivel”,
pero esto es completamente falso, ambos son LENGUAJES DE PROPOSITO GENERAL,
esto quiere decir que podemos programar tanto a alto nivel, como a medio nivel, o bajo nivel(asm y mas, incluso se pueden hacer drivers).
Por ejemplo, el FPC compila 10% mas rapido que el GCC,
pueden encontrar mas información acerca de este lenguaje aquí: http://es.wikipedia.org/wiki/Pascal_(lenguaje_de_programaci%C3%B3n)
1)Introduccion:
Antes de comenzar con el tutorial les pido que si deciden distribuir este material,
mencionen al autor por respeto y por que seria(en mi opinión) la forma mas sumisa de darme las gracias si te ha servido,
mi nombre es WarZ0n3 y me puedes encontrar en el los foros de http://foro.elhacker.net o http://www.indetectables.net.
El uso de Wininet no esta muy documentado, no he encontrado demasiada información al respecto,
y es un hecho que gran parte de los códigos que se pueden encontrar en la red fueron hechos como ejemplos,
por lo que realmente pasare a decir que lo aquí explicado, se comentara lo mas posible. Ademas el uso de robots,
spamers publicitario etc.. no es un tema nuevo(aunque nunca vi un tutorial de como programar uno),
por esto se me ocurrió hablar sobre este tema, pero cuando se saben usar APIS como winsock, wininet, etc..
sea en C++ o pascal y usando tu sentido común podrás desarrollar un viewer,
lo suficientemente poderoso y profesional para el mercado.
Pero RECUERDEN que este es un tutorial para aquellos iniciados en el tema de las APIS. Así que basta de rodeos y a empezar.
2)Conocimientos previos:
Si no sabes usar APIS, o eres un iniciado en pascal, no debes preocuparte, ya que este tutorial
se enfoca en las personas que recién empiezan.
No sondeare sobre como desensamblar código para hacer las funciones en asm puro
y se ejecuten mas rápido (esto por si lo ven en códigos futuros míos), tal vez para otro tutorial,
eso puede aprenderse en shellcoding (de hecho así lo aprendí yo).
3)Desarrollando con la librería WinInet:
Wininet es una dll que puedes encontrar en System32 de tu windows, y es la encargada de las funciones de internet.
La importancia de usarla es que, como toda API, se pueden hacer cosas muy profesionales arbitrariamente hablando, también tomar en cuenta la optimización de código, y que siempre es mejor usar apis, en vez de componentes externos o indys. No tengo nada contra de estos, incluso hay veces que debo recurrir a ellos.
Lo primero sera agregarla en USES para poder usarla, y para ello abrimos delphi 7 nos vamos a
file->new->other y elejimos console application.
Ahora crearemos una función la cual se encargara de hacer peticiones a una pagina que nosotros le pasemos como argumento:
Código
// Uses: Requerimientos para usar la librería wininet y otras funciones de las que nos provee pascal uses WinInet, Windows, SysUtils; // aplicación de tipo consola {$APPTYPE CONSOLE} // directiva del compilador usada para añadir un símbolo especifico en la cabecera de C++ generada {$HPPEMIT '#include <wininet.h>'} // otro ejemplo {$HPPEMIT 'struct myVar'}, obviamente generada desde la cabecera de C++ // constantes que usaremos como parámetros en las funciones de wininet (* recordemos que podemos usar valores hexadecimal para las definiciones, de echo muchas se proveen de esta forma (por lo que yo recomiendo mucho esto), también tengan presente que deben ser 8 dígitos (1 octeto), si no saben hexa usen la calculadora de windows en modo científico. NOTA RAPIDA: en pascal los valores hexadecimales son definidos con el simbolo $ adelante *) const INTERNET_OPEN_TYPE_PRECONFIG = $00000000; (* Usa la configuracion del registro(por defecto) *) {$EXTERNALSYM INTERNET_OPEN_TYPE_PRECONFIG} INTERNET_OPEN_TYPE_DIRECT = $00000001; (* Acceso directo a la red *) {$EXTERNALSYM INTERNET_OPEN_TYPE_DIRECT} INTERNET_OPEN_TYPE_PROXY = $00000003; (* Acceso via proxy *) {$EXTERNALSYM INTERNET_OPEN_TYPE_PROXY} INTERNET_FLAGS_MASK = INTERNET_FLAG_RELOAD or INTERNET_FLAG_NO_COOKIES; {$EXTERNALSYM INTERNET_FLAGS_MASK} ZERO = $00000000; HTTP = 'http://';
En pascal existen 3 tipos de comentarios:
Código
// comentario 1(inline) {comentario 2 equivalente a /**/ en c++} (* comentario 3 equivalente a /**/ en c++ *)
NOTA: No es lo mismo hacer {} que {$}, cuando hacemos esto {$} en realidad hablamos de directivas del compilador,
si saben c++ deberían entender a que me refiero. #define ...
Código
Creando la función:
// Esta directiva impide a pascal que se sobrecarguen rutinas, ya definidas en los headers de C++ // ejemplo: {$EXTERNALSYM <VARIABLE_O_FUNCIÓN>}
Código
function RequestInternet(url:string): BOOL; var hInet, hUrl : hInternet; begin hInet:= InternetOpen('USER AGENT: ROBOT', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, ZERO); if assigned(hInet) then begin hUrl:= InternetOpenUrl(hInet, pChar(HTTP+url), nil, INTERNET_FLAG_NO_COOKIES, INTERNET_FLAG_RELOAD,INTERNET_SERVICE_HTTP); if assigned(hUrl) then begin Result:= true; end else begin Result:= false; end; end; InternetCloseHandle(hInet); InternetCloseHandle(hUrl); end;
“if assigned”: esta función chequea si la referencia no es de tipo nula (NIL), si lo es retorna FALSE y si no es nula retorna TRUE
ej: if assigned(Puntero) then begin … <codigo> … end;
Código
Básicamente inicializa el uso de las funciones de Wininet.
hInet:= InternetOpen('USER AGENT: ROBOT', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
Pueden encontrar mas información al respecto en : http://msdn.microsoft.com/en-us/library/windows/desktop/aa385096(v=vs.85).aspx
msdn nos dice que los parámetros son:
Código
HINTERNET InternetOpen( LPCTSTR lpszAgent, // USER-AGENT del protocolo HTTP (luego lo cambiaremos) DWORD dwAccessType, // Tipo de acceso, es este caso el pre-configurado. LPCTSTR lpszProxyName, // Usados para proxys LPCTSTR lpszProxyBypass, DWORD dwFlags );
Código
Usada para el acceso a internet (también puede usarse para el protocolo FTP). Y el HTTP+url,
hUrl:= InternetOpenUrl(hInet, pChar(HTTP+url), nil, INTERNET_FLAG_NO_COOKIES, INTERNET_FLAG_RELOAD,INTERNET_SERVICE_HTTP);
es el definido en las constantes mas el parámetro de la función.
Los demás parámetros según la msdn:
Código
Y nos retorna un NULL si la conexión ha fallado. Otra cosa es que podríamos haber usado InternetConnect,
HINTERNET InternetOpenUrl( HINTERNET hInternet, // Handler a OpenInternet(que inicializamos previamente) LPCTSTR lpszUrl, // Url pasada como argumento (ej: http://www.youtube.com&#38;#41; LPCTSTR lpszHeaders, // tipo de lectura en HTTP, FTP, o HTPPS (son soportados) DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext );
no entrare en detalles, tal ves para otra entrega y otro tipo de spamer,
pero me limitare a decir que esto puede ser en caso de querer logearnos automáticamente(con autentificación ) a un sitio web,
y seria cuestión de saltarse los captchas, si es que los tiene, por esto solo utilizaremos “openurl”,
ya que solo queremos generar visitas y nada más.
Código
Cierra el/los manejadores de internet... mas información aquí: http://msdn.microsoft.com/en-us/library/windows/desktop/aa384350&#40;v=vs.85&#41;.aspx
InternetCloseHandle(hInet); InternetCloseHandle(hUrl);
(Recordemos siempre liberar memoria, cerrando handlers correctamente, y variables (mas si son de tipo puntero).
NOTA: Hinternet según wininet.pas son de tipo punteros, así que podríamos haber echo lo mismo de la
siguiente forma:
Código
Si lo hacen así recomiendo usar FreeMemory(hInet), etc...
hInet, hUrl : Pointer;
4)Hablando de return y result en Pascal:
En pascal no hay return como tal, pero alternativamente nos valemos de Result,
el cual se crea (automáticamente) cuando se inicia la función en memoria,
este contiene el resultado de dicha función y puede ser usada a lo largo del programa.
Para este ejemplo se uso un booleano que nos devuelve true si la sesión fue exitosa y false si no lo fue.
Entonces el código hasta el momento nos debe quedar así:
Código
program rweb; uses WinInet, Windows, SysUtils; {$APPTYPE CONSOLE} {$HPPEMIT '#include <wininet.h>'} const INTERNET_OPEN_TYPE_PRECONFIG = $00000000; (* Usa la configuracion del registro(por defecto) *) {$EXTERNALSYM INTERNET_OPEN_TYPE_PRECONFIG} INTERNET_OPEN_TYPE_DIRECT = $00000001; (* Acceso directo a la red *) {$EXTERNALSYM INTERNET_OPEN_TYPE_DIRECT} INTERNET_OPEN_TYPE_PROXY = $00000003; (* Acceso via proxy *) {$EXTERNALSYM INTERNET_OPEN_TYPE_PROXY} INTERNET_FLAGS_MASK = INTERNET_FLAG_RELOAD or INTERNET_FLAG_NO_COOKIES; {$EXTERNALSYM INTERNET_FLAGS_MASK} ZERO = $00000000; HTTP = 'http://'; function RequestInternet(url:string): BOOL; var hInet, hUrl : hInternet; begin hInet:= InternetOpen('USER AGENT: ROBOT', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, ZERO); if assigned(hInet) then begin hUrl:= InternetOpenUrl(hInet, pChar(HTTP+url), nil, INTERNET_FLAG_NO_COOKIES, INTERNET_FLAG_RELOAD,INTERNET_SERVICE_HTTP); if assigned(hUrl) then begin Result:= true; end else begin Result:= false; end; end; InternetCloseHandle(hInet); InternetCloseHandle(hUrl); end; // inicializamos el programa con la funcion begin if RequestInternet( string(ParamStr(1)) ) then begin writeLn('Sesion exitosa'); end else begin writeLn('Ha surgido un problema en la conexion...'); end; end.
Dentro de begin y end. (no end;), se inicia el programa, y el end. (con punto) remarca la finalización del código.
ParamStr(1) es el argumentos de la aplicación (el que le pasaremos como parámetro cuando la ejecutemos).
Osease rweb 'pagina a visitar'.
5)Probando nuestro robot por primera vez:
Simple y eficaz, luego agregaremos más características, como user agents hasheados en una variable random,
que dará como resultado user-agents falsos, pero por ahora el código esta bien y es necesario probarlo antes de continuar.
Entonces naveguemos hasta el directorio de nuestro projecto y hagan lo que se muestra en la imagen (yo copie mi rweb.exe en C:/ )
Como vemos en el primer ejemplo “rweb localhost”(por si no ves la imagen),
nos indica que la sesión fue exitosa (ya que tengo xampp corriendo).
Y en el segundo ejemplo vemos “ha surgido un problema en la conexión” ya que visitamos una web no existente,
el http:// adelante no lo agregamos por que en nuestro código previo ya lo habíamos hecho.
6) Convirtiendo nuestra PC en un servidor web de pruebas:
Si no sabes que es xampp, wampp, etc.. te recomiendo que te pases por aca: http://es.wikipedia.org/wiki/XAMPP
no entraremos en este tema, por que es irrelevante, ya que este es un tutorial sobre desarrollo de viewbots,
pero básicamente esto convierte tu maquina en un servidor web (y es necesario para hacer las pruebas locales),
lo puedes descargar de acá: http://www.apachefriends.org/es/xampp.html y para instalarlo
te dejo esta guía: http://vagabundia.blogspot.com/2012/07/como-instalar-xampp-en-windows.html
Eso sera suficiente para entrar en “localhost” o lo que es lo mismo “127.0.0.1” .
7)Creando un contador de visitas en PHP y algo más... :
En el ejemplo anterior vimos que nuestro pequeño bot funciona, y hasta nos avisa que la sesión fue exitosa,
¿pero realmente como sabemos que así fue?, y mas importante aun, como podemos tener un control de ello,
antes de adelantarnos a agregar mas en nuestro código haremos un simple contador de visitas en PHP
y ademas haremos que nos diga nuestra IP y USER-AGENT(navegador), también lo guardaremos en un archivo .txt .
NOTA RAPIDA: en Xampp la carpeta para entrar al index y agregar nuestra pagina es
C:/xampp/htdocs en otros servicios es probable encontrar la carpeta en /www .
Código en PHP (crea un archivo con la extensión .php que se llame contador y guardala en htdocs):
Código
<?php // Encargada de capturar la ip (o ip remota en el caso de que sea en la web). $ip=$_SERVER['REMOTE_ADDR']; // Captura el navegador. $user_agent=$_SERVER['HTTP_USER_AGENT']; echo "Tu ip real es: ".$ip; echo "<br>Y tu navegador es: ".$user_agent; // Archivo en donde se acumulará el numero de visitas $contador = "contador.txt"; // Archivo en donde se guardara tu ip y navegador. $info = "ips.txt"; // Abrimos el archivo para solamente leerlo (r de read) // Leemos el contenido del archivo // Cerramos el archivo // Abrimos nuevamente el archivo // Sumamos 1 nueva visita $total = $total + 1; // Y reemplazamos por la nueva cantidad de visitas // Cerramos la conexión al archivo // Imprimimos el total de visitas dándole un formato echo "<br><br><i>Total de visitas: ".$total; // abrimos el segundo archivo donde ira la ip y navegador. // lo escribimos (PHP_EOL es un salto de linea). $grabar_datos = fwrite($abre_datos, PHP_EOL ."Tu ip es: ".$ip.PHP_EOL ."Tu navegador es: ".$user_agent); ?>
Como vemos el código es bastante básico, pero la idea no es mala y con esto bastara para saber
el navegador con el que se loguea nuestro bot y cuantas veces lo hace.
Haremos otra visita, pero esta ves al “contador.php”
En la imagen podemos observar el total de visitas, 5 que hice comúnmente, y la numero 6 del bot,
vamos a la carpeta xampp/htdocs y veamos los ficheros formados y que contienen.
Muy bien, tenemos “contador.txt” con el numero 6, y “ips.txt” con los navegadores visitados y la ip,
en la imagen podemos observar que el ultimo (el remarcado con azul) dice:
Tu navegador es: USER-AGENT: ROBOT
Exelente! Esto quiere decir que nuestro pequeño bot dio resultado. ¿Recuerdan esto?:
Código
hInet:= InternetOpen('USER AGENT: ROBOT', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, ZERO);
Pues hay lo tienen!.
8)Hashes mixtos para nuestra maquina:
Nuestro próximo objetivo es hacer hashes que se generen automáticamente, y con una llamado de “Ramdom” se creen al azar,
crearemos una nueva función llamada RandomHashes arriba de RequestInternet, entonces nuestro código sera el siguiente:
Código
const: BUFFSIZE = $00000041; // 65d function RandomHashes(LenDict:integer):string; const BuffHash : Array[0..BUFFSIZE] of Char= ( 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '=', '?', '-' );
Creamos 2 constantes, la primera llamada BUFFSIZE fuera de la función, que tendrá la longitud de nuestro diccionario ,
y la segunda constante(dentro de la función) tendrá nuestro diccionario de letras que se generaran al azar.
NOTA: $00000041(hex) en decimal es 65, osea que nuestro diccionario tiene 66 de longitud real (por que el array se inicializa
en zero y también es contado como lugar).
Ahora lo que haremos sera generar el hash, y lo imprimiremos en pantalla,
esto es para asegurarnos de que la función esta haciendo su trabajo correctamente.
Código
var iHash : Integer; PBuffHash : Char; repeat iHash:= Length(BuffHash)-LenDict; repeat Randomize; PBuffHash:= BuffHash[Random(Length(BuffHash))]; asm @@StartUp: DEC(iHash); end; Result:= Result+PBuffHash; until (iHash<ZERO); Result:= Result; ZeroMemory(Addr(iHash), SizeOf(iHash)); ZeroMemory(Addr(PBuffHash), SizeOf(PBuffHash));
Tranquilos que esto es muy fácil, solo hay que desmenuzar el código y analizarlo con tranquilidad.
Código
iHash: sera la longitud de la variable “BuffHash” que como vimos anteriormente es la que contiene nuestro diccionario.
Código
PbuffHash: Sera de tipo Char y contendrá como dato nustro hash.
Código
y básicamente genera números al azar en conjunción con la función Ramdom, que ya veremos.
Randomize: es un procedimiento(procedure), NO! una función.
Código
Acá lo que estamos haciendo es decirle a PbuffHash, que almacene nuestro diccionario,
PBuffHash:= BuffHash[Random(Length(BuffHash))];
que es de tipo char(por esto te comentaba que ambas variables deben ser de tipo Char).
Código
es una función que genera números al azar y
Random();
Código
repito de nuevo, sera la longitud de nuestro diccionario en la que se generara el hash.
length(BuffHash);
Código
Recordemos que siempre el código en ensamblador se ejecuta mas rápido, y así de alguna manera estamos pre-optimizando nuestro código.
asm @@StartUp: DEC(iHash); end;
9)Un vistazo a la programación monolítica:
Aquellos que sean programadores de la vieja escuela sabrán que antes no existía la programación estructurada como tal,
por lo que se hacía con labels, o etiquetas, por esto usar gotos es una mala manera de programar aun que en algunos casos
no queda remedio...
Código
@@Startup: Sera nuestra etiqueta de comienzo algo así como una referencia en el código, y DEC lo que hace es decrementar en 1 la variable pasada como argumento, mas adelante explicare por que.
Código
Repite nuestro código(generando char por char en PbuffHash) hasta que se cumpla una condición,
Repeat y until (iHash<ZERO);
por ejemplo lo que vimos anteriormente es que estamos decrementando
iHash(contenedor de la longitud de nuestro diccionario) en 1,
osea que nuestro until se dejara de ejecutar cuando este llegue a zero, y la variable que le pase “ZERO” es la constante definida anteriormente.
Código
¿Recuerdan lo de los Results que les había explicado?, pues es tiempo de darles uso,
Result:= Result+PBuffHash;
y aquí lo que hacemos es sumar el valor en cada repetición, en este caso “PbuffHash” el cual es nuestro hash generandose.
Ahora le decimos a que sea igual al resultado ya generado, osease Result:= Result;
10)Limpiando variables en memoria:
Código
Esta función es el equivalente a FillChar y es muy útil para limpiar una variable en memoria(también para incializarla en $00000000),
ZeroMemory(Addr(iHash), SizeOf(iHash));
en realidad si hubiera inicializado otro tipo de array (ya sea de punteros especialmente),
haría algo como
Código
pero lo del Addr, es para limpiar fuera de la memoria nuestra variable, ademas es Addr quien contiene la dirección.
ZeroMemory(HandlerArrayOPuntero, SizeOf(HandlerArrayOPuntero))
Y para terminar la explicación, nuestra función recibe un parámetro “LenDict” de tipo integro,
esta será la longitud total que queremos que tenga nuestro diccionario,
habíamos dicho que 66 en decimal, pero la verdad que es un valor MUY largo para nuestro bot,
entonces lo restaremos en nuestra función prorroga.
Probemos la funcion (en begin comente lo anterior hecho para la pruebita):
Código
begin (* if RequestInternet( string(ParamStr(1)), 40) then begin writeLn(#13#10+'Sesion exitosa'); end else begin writeLn(#13#10+'Ha surgido un problema en la conexion...'); end; *) WriteLn('Hash formado: ', RandomHashes(45)); Sleep($500); end.
Pueden observar que le pasamos el número 45 osea 66-45=21, pero la longitud total es 22 por que inicializamos el array en 0.
Y ahora es tiempo de tocar RequestInternet, es tan facil como agregar nuestra nueva función:
Código
function RequestInternet(url:string; Hashes: integer): BOOL; var hInet, hUrl : hInternet; NHash : Pchar; // Creamos otra variable begin NHash:= Pchar(RandomHashes(Hashes)); // Llamamos nuestra función generadora de hashes hInet:= InternetOpen(NHash, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, ZERO); if assigned(hInet) then begin hUrl:= InternetOpenUrl(hInet, pChar(HTTP+url), nil, INTERNET_FLAG_NO_COOKIES, INTERNET_FLAG_RELOAD,INTERNET_SERVICE_HTTP); if assigned(hUrl) then begin Result:= true; WriteLn('Hash generado: '+NHash); end // mostramos el hash generado. else begin Result:= false; end; end; InternetCloseHandle(hInet); InternetCloseHandle(hUrl); FreeMemory(NHash); // liberamos nuestra variable de tipo puntero. End;
Código
Entonces Nhash contendrá nuestro hash generado en la longitud de 22 y lo pondremos en InternetOpen para que cambie nuestro USER-AGENT,
NHash:= Pchar(RandomHashes(Hashes));
terminemos el código(por ahora).
Entonces si todo va bien te debería quedar de la siguiente manera:
Código
Y listo!, hora de probar nuestro robot:
program rweb; uses WinInet, Windows, SysUtils; {$APPTYPE CONSOLE} {$HPPEMIT '#include <wininet.h>'} const INTERNET_OPEN_TYPE_PRECONFIG = $00000000; (* Usa la configuracion del registro(por defecto) *) {$EXTERNALSYM INTERNET_OPEN_TYPE_PRECONFIG} INTERNET_OPEN_TYPE_DIRECT = $00000001; (* Acceso directo a la red *) {$EXTERNALSYM INTERNET_OPEN_TYPE_DIRECT} INTERNET_OPEN_TYPE_PROXY = $00000003; (* Acceso via proxy *) {$EXTERNALSYM INTERNET_OPEN_TYPE_PROXY} INTERNET_FLAGS_MASK = INTERNET_FLAG_RELOAD or INTERNET_FLAG_NO_COOKIES; {$EXTERNALSYM INTERNET_FLAGS_MASK} ZERO = $00000000; BUFFSIZE = $00000041; // 66d HTTP = 'http://'; function RandomHashes(LenDict:integer):string; const BuffHash : Array[0..BUFFSIZE] of Char= ( 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '=', '?', '-' ); var iHash : Integer; PBuffHash : Char; begin iHash:= Length(BuffHash)-LenDict; repeat Randomize; PBuffHash:= BuffHash[Random(Length(BuffHash))]; asm @@StartUp: DEC(iHash); end; Result:= Result+PBuffHash; until (iHash<ZERO); Result:= Result; ZeroMemory(Addr(iHash), SizeOf(iHash)); ZeroMemory(Addr(PBuffHash), SizeOf(PBuffHash)); end; function RequestInternet(url:string; Hashes: integer): BOOL; var hInet, hUrl : hInternet; NHash : PChar; begin NHash:= PChar(RandomHashes(Hashes)); hInet:= InternetOpen(NHash, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, ZERO); if assigned(hInet) then begin hUrl:= InternetOpenUrl(hInet, pChar(HTTP+url), nil, INTERNET_FLAG_NO_COOKIES, INTERNET_FLAG_RELOAD,INTERNET_SERVICE_HTTP); if assigned(hUrl) then begin Result:= true; WriteLn('Hash generado: '+NHash); end else begin Result:= false; end; end; InternetCloseHandle(hInet); InternetCloseHandle(hUrl); FreeMemory(NHash); end; begin if RequestInternet( string(ParamStr(1)), 40) then begin writeLn(#13#10+'Sesion exitosa'); end else begin writeLn(#13#10+'Ha surgido un problema en la conexion...'); end; Sleep($500); end.
11) Probando nuestro viewbot por 2º vez:
Parámetro : rweb localhost/contador.php
¿Que tal he? Va tomando color.
Vamos a automatizarlo para que mientras visite nuestro sitio deseado, nosotros no tengamos que hacer nadas mas que
esperar viéndonos un capitulo de los simpson mientras comemos helado.
Agregamos los siguiente:
Código
Aun mas fácil!, en constante definimos “F5KEY” el cual es un valor hexa de 74 osea traducido en decimal 116 que es la tecla F5
/en const: F5KEY = $00000074; // 116decimal = F5 var Init : BOOL = True; begin while Init do begin WriteLn('Apreta (F5) para salir de Rbot. '); if RequestInternet( string(ParamStr(1)), 40) then begin writeLn(#13#10+'Sesion exitosa!'); end else begin writeLn(#13#10+'Ha surgido un problema en la conexion...'); end; if GetasyncKeyState(F5KEY)<>ZERO then begin Init:= false; WriteLn(#13#10+'Opcion salida por el usuario.'); end; end; Sleep($500); end.
var Init : BOOL = True, lo dejaremos para mas adelante, ya que esto inicializar el loop en true.
Código
while Init do begin: el bucle while permanecerá repitiéndose mientras sea True de otro modo se rompe y salimos de la aplicación .
Código
GetasyncKeyState es un función de windows, el cual nos permitirá registrar lo que escribamos,
if GetasyncKeyState(F5KEY)<>ZERO then begin Init:= false; ...
es muy intuitiva y fácil(también usada para keyloggers, aunque nada como hooks).
Como parámetro recibe la tecla presionada, osease F5 que es la que usaremos para salir, y <>
ZERO nos dice que mientras sea distinto a zero no igualara Init a False lo que pondrá fin a nuestro bucle.
El parámetro según la msdn:
Código
para mas información consultalo aquí: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646293(v=vs.85).aspx
SHORT WINAPI GetAsyncKeyState( int vKey );
12) Usando el API Winsock para obtener IPs:
Bueno este paso es opcional, pero lo recomiendo mucho, ya que ayudara a entender(un poco) la librería WinSock,
tal ves mas adelante(en otro tuto), hablaremos de ello y enseñare a como usarla, incluso si se quiere programar un troyano,
yo por mi parte la aprendía a usar con este objetivo, y hace poco había echo un troyano con tal funciones,
aun que le queda mucho por optimizar, pero ya, dejemos lo ahí...
Crearemos otra función llamada GetIp, la cual nos dirá la IP del servidor pasado como paramentro,
Entonces el código es el siguiente (vamos que queda poquísimo y es fácil):
Código
const: INADDRSIZE = $0000000A; var: IRobot : Integer = 0; WSData : WsaData; function GetIP(): PChar; type aIn_addr = array [0..INADDRSIZE] of pInAddr; pIn_addr = ^aIn_addr; var Hostent : PHostEnt; HostAddr : pIn_addr; begin WSAStartup($1, WSData); Hostent:= GetHostBYName( PChar(ParamStr(1)) ); HostAddr:= pIn_addr(Hostent^.h_addr_list); Result:= inet_ntoa(HostAddr^[ZERO]^); FreeMemory(HostAddr); WSACleanUp; end;
Código
Acuérdense, esto va en constantes(fuera de la función),
const: INADDRSIZE = $0000000A;
y el valor es el que tendrá nuestro Array “A” en hexa es el equivalente a 10 en decimal.
Código
Esto va en constantes(dentro de la función), pInAddr es un puntero de ^TinAddr que ha su vez termina en “in_addr”
aIn_addr = array [0..INADDRSIZE] of pInAddr;
Código
Puntero a “aIn_addr” nuestro array.
pIn_addr = ^aIn_addr;
Código
Es el “result”(recuerde que explique esto anteriormente) de la función “gethostbyname” por
Hostent : PhostEnt;
medio de stdcall.
Código
Puntero a “pIn_addr” que a su vez es un puntero de “aIn_addr” que contiene otro array de punteros
HostAddr : pIn_addr;
(puede sonar confuso..)
Código
Para ello nos vamos a la bendita msdn, los parámetros son los siguientes:
WSData : WsaData; y WSAStartup($1, WSData);
Código
Mas información puede encontrarse aquí: http://msdn.microsoft.com/en-us/library/windows/desktop/ms742213(v=vs.85).aspx
int WSAStartup( WORD wVersionRequested, // Versión de sockets que se usaran LPWSADATA lpWSAData // Puntero a WsaData el que definimos en las variables );
Código
Ya había mencionado que PhostEnt era el resultado de esta función, así
Hostent:= GetHostByName( PChar(ParamStr(1)) );
que obviamente al definirla la usaremos, (paramstr 1 es el sitio web que
visitemos ej:www.youtube.com)
Código
Y no podía faltar el puntero de puntero de punteros...
HostAddr:= pIn_addr(Hostent^.h_addr_list);
Ejemplo:
Código
Para entender esta función debemos recurrir de nuevo a la msdn, luego daré un ejemplo
function GetHostByName(name: PChar): PHostEnt; stdcall;
Entonces los parámetros son los siguientes:
Código
struct hostent* FAR gethostbyname( const char *name // Puntero al nombre del host a traducir a IP );
Código
lista de direcciones IP para el servidor pasado como parametro.
h_addr_list;
Mas info en: http://msdn.microsoft.com/en-us/library/windows/desktop/ms738524(v=vs.85).aspx
Si quieren saber mas sobre gethostbyname y gethostbyaddr: http://beej.us/guide/bgnet/output/html/multipage/gethostbynameman.html
Por ahora no es necesario que lo comprendan un 100%, pero seria bueno, ahora lo que sigue es:
Código
Otra vez por la msdn: http://msdn.microsoft.com/en-us/library/windows/desktop/ms738564(v=vs.85).aspx
Result:= inet_ntoa(HostAddr^[ZERO]^);
De todos modos lo explicare, esta función convierte una dirección de red de tipo Ipv4 en un ASCII
Ejemplo:
Código
char* FAR inet_ntoa( struct in_addr in // Representa un dirección de internet );
Y como no un record. Aquí lo pondré mas claro, nada como un ejemplo(de Winsock.pas):
Código
PInAddr = ^TInAddr; {$EXTERNALSYM in_addr} in_addr = record case integer of 0: (S_un_b: SunB); 1: (S_un_w: SunW); 2: (S_addr: u_long); end; TInAddr = in_addr; // Puntero a in_addr. FreeMemory(HostAddr); // Libera el array de punteros WSACleanUp; // Limpia el socket.
13)Finalizando:
Y para finalizar nuestra primer entrega(y espero que no sea la ultima), eso sí, si a la gente le gusta.
Haremos un pequeño timer para que el tiempo en visitar una pagina no sea demasiado grande,
recordemos que el bucle while se genera muy rapido,
y con tan solo decirles que ejecutado así nada mas en menos de 30 segundos hice casi 100 visitas a mi pagina y esto
puede ser realmente muy molesto (y obvio), por esto ademas veremos cuantas visitas hacemos en un rango de X segundos:
Agregaremos lo siguiente al begin principal:
Código
agrega en constantes HASHKEY = $00000028; // 40 decimal begin WriteLn('Apreta (F5) para salir de Rbot. '); while Init do begin if RequestInternet( string(ParamStr(1)), HASHKEY, StrToInt(ParamStr(2))) then begin asm @@StartUp: Inc(IRobot) end; writeLn( '[Servidor visitado]: ', ParamStr(1), #13#10+'[Ip]: ', PChar(GetIP()), #13#10+'[Numero de veces]: ', IRobot, #13#10+'Sesion exitosa!'+#13#10 +'============================' ); end else begin writeLn(#13#10+'Ha surgido un problema en la conexion...'); end; if GetasyncKeyState(F5KEY)<>ZERO then begin Init:= false; WriteLn(#13#10+'Opcion salida por el usuario.'); end; end; ZeroMemory(Addr(IRobot), sizeof(IRobot)); end.
Bien, HASHKEY es 40 en decimal, que sera la longitud del hash que restaremos(con 66 el total de nuestro diccionario en la función RandomHashes),
y Como 3º parámetro recibirá los segundos que tardara en hacer la repetición, por ultimo retocaremos la función RequestInternet.
Código
function RequestInternet(url:string; Hashes, Secs: integer): BOOL; // Secs: segundos pasados var hInet, hUrl : hInternet; NHash : PChar; begin NHash:= PChar(RandomHashes(Hashes)); hInet:= InternetOpen(NHash, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, ZERO); if assigned(hInet) then begin hUrl:= InternetOpenUrl(hInet, pChar(HTTP+url), nil, INTERNET_FLAG_NO_COOKIES, INTERNET_FLAG_RELOAD,INTERNET_SERVICE_HTTP); if assigned(hUrl) then begin Result:= true; WriteLn('Hash generado: '+NHash); end else begin Result:= false; end; end; Sleep(Secs*1000); // Delay del tiempo en hacer la repetición InternetCloseHandle(hInet); InternetCloseHandle(hUrl); FreeMemory(NHash); end;
TERMINAMOS!!! Entonces el código final te debería quedar así..
Código
program rweb; uses WinInet, WinSock, Windows, SysUtils; {$APPTYPE CONSOLE} {$HPPEMIT '#include <wininet.h>'} const INTERNET_OPEN_TYPE_PRECONFIG = $00000000; (* Usa la configuracion del registro(por defecto) *) {$EXTERNALSYM INTERNET_OPEN_TYPE_PRECONFIG} INTERNET_OPEN_TYPE_DIRECT = $00000001; (* Acceso directo a la red *) {$EXTERNALSYM INTERNET_OPEN_TYPE_DIRECT} INTERNET_OPEN_TYPE_PROXY = $00000003; (* Acceso via proxy *) {$EXTERNALSYM INTERNET_OPEN_TYPE_PROXY} INTERNET_FLAGS_MASK = INTERNET_FLAG_RELOAD or INTERNET_FLAG_NO_COOKIES; {$EXTERNALSYM INTERNET_FLAGS_MASK} ZERO = $00000000; BUFFSIZE = $00000041; // 65d F5KEY = $00000074; // 116d (F5) HASHKEY = $00000028; // 40d INADDRSIZE = $0000000A; // 10d HTTP = 'http://'; var Init : BOOL = True; IRobot : Integer = 0; WSData : WsaData; function RandomHashes(LenDict:integer):string; const BuffHash : Array[0..BUFFSIZE] of Char= ( 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '=', '?', '-' ); var iHash : Integer; PBuffHash : Char; begin iHash:= Length(BuffHash)-LenDict; repeat Randomize; PBuffHash:= BuffHash[Random(Length(BuffHash))]; asm @@StartUp: DEC(iHash); end; Result:= Result+PBuffHash; until (iHash<ZERO); Result:= Result; ZeroMemory(Addr(iHash), SizeOf(iHash)); ZeroMemory(Addr(PBuffHash), SizeOf(PBuffHash)); end; function RequestInternet(url:string; Hashes, Secs: integer): BOOL; var hInet, hUrl : hInternet; NHash : PChar; begin NHash:= PChar(RandomHashes(Hashes)); hInet:= InternetOpen(NHash, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, ZERO); if assigned(hInet) then begin hUrl:= InternetOpenUrl(hInet, pChar(HTTP+url), nil, INTERNET_FLAG_NO_COOKIES, INTERNET_FLAG_RELOAD,INTERNET_SERVICE_HTTP); if assigned(hUrl) then begin Result:= true; WriteLn('Hash generado: '+NHash); end else begin Result:= false; end; end; Sleep(Secs*1000); InternetCloseHandle(hInet); InternetCloseHandle(hUrl); FreeMemory(NHash); end; function GetIP(): PChar; type aIn_addr = array [0..INADDRSIZE] of pInAddr; pIn_addr = ^aIn_addr; var Hostent : PHostEnt; HostAddr : pIn_addr; begin WSAStartup($1, WSData); Hostent:= GetHostBYName( PChar(ParamStr(1)) ); HostAddr:= pIn_addr(Hostent^.h_addr_list); Result:= inet_ntoa(HostAddr^[ZERO]^); FreeMemory(HostAddr); WSACleanUp; end; begin {$O+} // Directiva para optimización WriteLn('Apreta (F5) para salir de Rweb. '); while Init do begin if RequestInternet( string(ParamStr(1)), HASHKEY, StrToInt(ParamStr(2))) then begin asm @@StartUp: Inc(IRobot) end; writeLn( '[Servidor visitado]: ', ParamStr(1), #13#10+'[Ip]: ', PChar(GetIP()), #13#10+'[Numero de veces]: ', IRobot, #13#10+'Sesion exitosa!'+#13#10 +'============================' ); end else begin writeLn(#13#10+'Ha surgido un problema en la conexion...'); end; if GetasyncKeyState(F5KEY)<>ZERO then begin Init:= false; WriteLn(#13#10+'Opcion salida por el usuario.'); end; end; ZeroMemory(Addr(IRobot), sizeof(IRobot)); {$0-} end.
14)Probando nuestro viewbot por 3º vez!:
Hora de probarlo!!!.
Y como ven los argumentos usados son: <sitio_web> <intervalo en tiempo>
Nota: Para aumentar un vídeo en especifico debes usar la url del sitio mas el enlancé,
Ej: http://www.youtube.com/mi_video_a_aumentar
Claro, youtube cuenta una vez por IP, como algunos sitios pero a no preocuparse que en la próxima entrega veremos
como soluciónar ese problema, y lo mismo de siempre, si comentan y les gusta, si no, no hay problema...
15)Usando StripReloc para hacer el ejecutable mas pequeño y su relación con .reloc:
StripReloc se encarga de eliminar una parte de la sección que windows agrega por defecto a los PE(Portable ejecutable) “.reloc”,
(no toda), sino aquella que los compiladores como delphi 7 agregan y
son inútiles, de esta manera reduce el ejecutable moderadamente.
puedes encontrar mas documentación acerca de estas cabeceras acá: http://es.wikipedia.org/wiki/Portable_Executable
tambien pueden encontrar StripReloc en el siguiente link: http://www.jrsoftware.org/striprlc.php
Para usarlo debemos descargarnos el .zip de la pagina que les pase. Una vez descomprimido,
obtendremos un .exe llamado “StripReloc”.
Naveguemos hasta la ruta del exe, y los parámetros son: “StripReloc <EXE_A_REDUCIR>”
La reducción ha sido considerable, veamoslo:
16)Mirando en LordPe la sección .reloc:
¿Y si miramos en el LordPe?:
Repito!, esto no quita la sección, solo remueve lo innecesario que generan los compiladores
17)Viendo el Stack y el Heap con WinDbg(este paso solo es demostrativo):
Por ultimo usare windbg para ver el stack y los heaps asignados, es una aplicación pequeña pero es algo que siempre tengo en cuenta,
tómenlo como un detalle de mi parte:
18)Despedida:
Y bueno gente, se despide WarZ0n3, espero que les haya servido y aprendido algo acerca del mundo de las APIS,
y lo poderosas que son, junto con la imaginación se puede hacer cualquier cosa,
también vimos como reducir un ejecutable, y optimizar código liberando variables en memoria y pequeño
uso de asm.
Ahora usando tu criterio y si has estudiado e investigado al respecto ya podrás hacer tu propio viewbot,
y mandármelo por PM o publicarlo en el foro dándome las gracias.
Saludos!.