[Tutorial] Programado un viewbot en pascal usando APIS

Iniciado por WarZ0n3, 3 Agosto 2013, 18:50 PM

0 Miembros y 1 Visitante están viendo este tema.

WarZ0n3

Lo prometido es deuda, hace un tiempo había echo un pequeño Viewbot, y al parecer a la gente le ha gustado, hoy les traigo algunas de las técnicas para programarlo lo más eficiente posible.. claro que lo haremos con las APIS WinInet, Winsock y más...


===============================

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 (pascal) [Seleccionar]
// 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 (pascal) [Seleccionar]
// 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 (pascal) [Seleccionar]
// Esta directiva impide a pascal que se sobrecarguen rutinas, ya definidas en los headers de C++
// ejemplo: {$EXTERNALSYM <VARIABLE_O_FUNCIÓN>}

Creando la función:
Código (pascal) [Seleccionar]
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 (pascal) [Seleccionar]
hInet:= InternetOpen('USER AGENT: ROBOT', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
Básicamente inicializa el uso de las funciones de Wininet.
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 (cpp) [Seleccionar]
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 (pascal) [Seleccionar]
hUrl:= InternetOpenUrl(hInet, pChar(HTTP+url), nil, INTERNET_FLAG_NO_COOKIES, INTERNET_FLAG_RELOAD,INTERNET_SERVICE_HTTP);
Usada para el acceso a internet (también puede usarse para el protocolo FTP). Y el HTTP+url,
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 (cpp) [Seleccionar]
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
);

Y nos retorna un NULL si la conexión ha fallado. Otra cosa es que podríamos haber usado InternetConnect,
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 (pascal) [Seleccionar]
InternetCloseHandle(hInet); InternetCloseHandle(hUrl);
Cierra el/los manejadores de internet... mas información aquí: http://msdn.microsoft.com/en-us/library/windows/desktop/aa384350&#38;#40;v=vs.85&#38;#41;.aspx
(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 (pascal) [Seleccionar]
hInet,
 hUrl        : Pointer;

Si lo hacen así recomiendo usar FreeMemory(hInet), etc...

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 (pascal) [Seleccionar]
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) [Seleccionar]
<?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)
$abre_visitas fopen($contador"r");
// Leemos el contenido del archivo
$total fread($abre_visitasfilesize($contador));
// Cerramos el archivo
fclose($abre_visitas);

// Abrimos nuevamente el archivo
$abre_visitas fopen($contador"w");
// Sumamos 1 nueva visita
$total $total 1;

// Y reemplazamos por la nueva cantidad de visitas 
$grabar_visitas fwrite($abre_visitas$total);
// Cerramos la conexión al archivo
fclose($abre_visitas);

// 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.
$abre_datosfopen($info"a+");
// lo escribimos (PHP_EOL es un salto de linea).
$grabar_datos fwrite($abre_datosPHP_EOL ."Tu ip es: ".$ip.PHP_EOL ."Tu navegador es: ".$user_agent);
fclose($abre_datos);
?>


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 (pascal) [Seleccionar]
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 (pascal) [Seleccionar]
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 (pascal) [Seleccionar]
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 (pascal) [Seleccionar]
iHash: sera la longitud de la variable "BuffHash" que como vimos anteriormente es la que contiene nuestro diccionario.
Código (pascal) [Seleccionar]
PbuffHash: Sera de tipo Char y contendrá como dato nustro hash.
Código (pascal) [Seleccionar]
Randomize: es un procedimiento(procedure), NO! una función.
y básicamente genera números al azar en conjunción con la función Ramdom, que ya veremos.
Código (pascal) [Seleccionar]
PBuffHash:= BuffHash[Random(Length(BuffHash))];
Acá lo que estamos haciendo es decirle a PbuffHash, que almacene nuestro diccionario,
que es de tipo char(por esto te comentaba que ambas variables deben ser de tipo Char).
Código (pascal) [Seleccionar]
Random();
es una función que genera números al azar y
Código (pascal) [Seleccionar]
length(BuffHash);
repito de nuevo, sera la longitud de nuestro diccionario en la que se generara el hash.
Código (pascal) [Seleccionar]
asm
     @@StartUp:
       DEC(iHash);
end;

Recordemos que siempre el código en ensamblador se ejecuta mas rápido, y así de alguna manera estamos pre-optimizando nuestro código.

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 (pascal) [Seleccionar]
@@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 (pascal) [Seleccionar]
Repeat y until (iHash<ZERO);
Repite nuestro código(generando char por char en PbuffHash) hasta que se cumpla una condición,
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 (pascal) [Seleccionar]
Result:= Result+PBuffHash;
¿Recuerdan lo de los Results que les había explicado?, pues es tiempo de darles uso,
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 (pascal) [Seleccionar]
ZeroMemory(Addr(iHash), SizeOf(iHash));
Esta función es el equivalente a FillChar y es muy útil para limpiar una variable en memoria(también para incializarla en $00000000),
en realidad si hubiera inicializado otro tipo de array (ya sea de punteros especialmente),
haría algo como
Código (pascal) [Seleccionar]
ZeroMemory(HandlerArrayOPuntero, SizeOf(HandlerArrayOPuntero))
pero lo del Addr,  es para limpiar fuera de la memoria nuestra variable, ademas es Addr quien contiene la dirección.

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 (pascal) [Seleccionar]
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 (pascal) [Seleccionar]
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 (pascal) [Seleccionar]
NHash:= Pchar(RandomHashes(Hashes));
Entonces Nhash contendrá nuestro hash generado en la longitud de 22 y lo pondremos en InternetOpen para que cambie nuestro USER-AGENT,
terminemos el código(por ahora).
Entonces si todo va bien te debería quedar de la siguiente manera:
Código (pascal) [Seleccionar]
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.

Y listo!, hora de probar nuestro robot:

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 (pascal) [Seleccionar]
/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.

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
var Init : BOOL = True, lo dejaremos para mas adelante, ya que esto inicializar el loop en true.
Código (pascal) [Seleccionar]
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 (pascal) [Seleccionar]
if GetasyncKeyState(F5KEY)<>ZERO then begin  Init:= false; ...
GetasyncKeyState es un función de windows, el cual nos permitirá registrar lo que escribamos,
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 (cpp) [Seleccionar]
SHORT WINAPI GetAsyncKeyState(
 int vKey
);

para mas información consultalo aquí: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646293(v=vs.85).aspx

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 (pascal) [Seleccionar]
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 (pascal) [Seleccionar]
const: INADDRSIZE = $0000000A;
Acuérdense, esto va en constantes(fuera de la función),
y el valor es el que tendrá nuestro Array "A" en hexa es el equivalente a 10 en decimal.
Código (pascal) [Seleccionar]
aIn_addr = array [0..INADDRSIZE] of pInAddr;
Esto va en constantes(dentro de la función), pInAddr es un puntero de ^TinAddr que ha su vez termina en "in_addr"
Código (pascal) [Seleccionar]
pIn_addr      = ^aIn_addr;
Puntero a "aIn_addr" nuestro array.
Código (pascal) [Seleccionar]
Hostent : PhostEnt;
Es el "result"(recuerde que explique esto anteriormente) de la función "gethostbyname" por
medio de stdcall.
Código (pascal) [Seleccionar]
HostAddr : pIn_addr;
Puntero a "pIn_addr" que a su vez es un puntero de "aIn_addr" que contiene otro array de punteros
(puede sonar confuso..)
Código (pascal) [Seleccionar]
WSData : WsaData; y WSAStartup($1, WSData);
Para ello nos vamos a la bendita msdn, los parámetros son los siguientes:
Código (cpp) [Seleccionar]
int WSAStartup(
 WORD wVersionRequested, // Versión de sockets que se usaran
 LPWSADATA lpWSAData // Puntero a WsaData el que definimos en las variables
);

Mas información puede encontrarse aquí: http://msdn.microsoft.com/en-us/library/windows/desktop/ms742213(v=vs.85).aspx
Código (pascal) [Seleccionar]
Hostent:= GetHostByName( PChar(ParamStr(1)) );
Ya había mencionado que PhostEnt era el resultado de esta función, así
que obviamente al definirla la usaremos, (paramstr 1 es el sitio web que
visitemos ej:www.youtube.com)
Código (pascal) [Seleccionar]
HostAddr:= pIn_addr(Hostent^.h_addr_list);
Y no podía faltar el puntero de puntero de punteros...
Ejemplo:
Código (pascal) [Seleccionar]
function GetHostByName(name: PChar): PHostEnt; stdcall;
Para entender esta función debemos recurrir de nuevo a la msdn, luego daré un ejemplo
Entonces los parámetros son los siguientes:
Código (cpp) [Seleccionar]
struct hostent* FAR gethostbyname(
 const char *name // Puntero al nombre del host a traducir a IP
);

Código (pascal) [Seleccionar]
h_addr_list;
lista de direcciones IP para el servidor pasado como parametro.
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 (pascal) [Seleccionar]
Result:= inet_ntoa(HostAddr^[ZERO]^);
Otra vez por la msdn: http://msdn.microsoft.com/en-us/library/windows/desktop/ms738564(v=vs.85).aspx

De todos modos lo explicare, esta función convierte una dirección de red de tipo Ipv4 en un ASCII
Ejemplo:
Código (cpp) [Seleccionar]
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 (pascal) [Seleccionar]
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 (pascal) [Seleccionar]
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 (pascal) [Seleccionar]
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 (pascal) [Seleccionar]
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!.