• [Tutorial] Programado un Viewbot en pascal usando APIS

 #420447  por WarZ0n3
 03 Ago 2013, 15:48
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 WinInet, Winsock y más...


============[Temarios]============

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í: [ Debe registrarse para ver este enlace ]

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 [ Debe registrarse para ver este enlace ] o [ Debe registrarse para ver este enlace ].

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:
// 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:
// 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 ...
// 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:
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 TRUE y si no retorna FALSE
ej: if assigned(Puntero) then begin … <codigo> … end;
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 : [ Debe registrarse para ver este enlace ]

msdn nos dice que los parámetros son:
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
);
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:
HINTERNET InternetOpenUrl(
  HINTERNET hInternet, // Handler a OpenInternet(que inicializamos previamente)
  LPCTSTR lpszUrl, // Url pasada como argumento (ej: http://www.youtube.com&#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.
InternetCloseHandle(hInet); InternetCloseHandle(hUrl);
Cierra el/los manejadores de internet... mas información aquí: [ Debe registrarse para ver este enlace ]
(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:
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í:
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: [ Debe registrarse para ver este enlace ]
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á: [ Debe registrarse para ver este enlace ] y para instalarlo
te dejo esta guía: [ Debe registrarse para ver este enlace ]
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):
<?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_visitas, filesize($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_datos= fopen($info, "a+");
// 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);
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?:
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:
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.
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.
iHash: sera la longitud de la variable “BuffHash” que como vimos anteriormente es la que contiene nuestro diccionario.
PbuffHash: Sera de tipo Char y contendrá como dato nustro hash.
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.
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).
Random();
es una función que genera números al azar y
length(BuffHash);
repito de nuevo, sera la longitud de nuestro diccionario en la que se generara el hash.
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...
@@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.
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.
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:
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
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):
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:
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;
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:
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:
// 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.
while Init do begin: el bucle while permanecerá repitiéndose mientras sea True de otro modo se rompe y salimos de la aplicación .
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:
SHORT WINAPI GetAsyncKeyState(
  int vKey
);
para mas información consultalo aquí: [ Debe registrarse para ver este enlace ]

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):
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;
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.
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”
pIn_addr      = ^aIn_addr;
Puntero a “aIn_addr” nuestro array.
Hostent : PhostEnt;
Es el “result”(recuerde que explique esto anteriormente) de la función “gethostbyname” por
medio de stdcall.
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..)
WSData : WsaData; y WSAStartup($1, WSData);
Para ello nos vamos a la bendita msdn, los parámetros son los siguientes:
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í: [ Debe registrarse para ver este enlace ]
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:[ Debe registrarse para ver este enlace ])
HostAddr:= pIn_addr(Hostent^.h_addr_list);
Y no podía faltar el puntero de puntero de punteros...
Ejemplo:
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:
struct hostent* FAR gethostbyname(
  const char *name // Puntero al nombre del host a traducir a IP
);
h_addr_list;
lista de direcciones IP para el servidor pasado como parametro.
Mas info en: [ Debe registrarse para ver este enlace ]

Si quieren saber mas sobre gethostbyname y gethostbyaddr: [ Debe registrarse para ver este enlace ]

Por ahora no es necesario que lo comprendan un 100%, pero seria bueno, ahora lo que sigue es:
Result:= inet_ntoa(HostAddr^[ZERO]^);
Otra vez por la msdn: [ Debe registrarse para ver este enlace ]

De todos modos lo explicare, esta función convierte una dirección de red de tipo Ipv4 en un ASCII
Ejemplo:
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):
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:
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.
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í..
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: [ Debe registrarse para ver este enlace ]

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á: [ Debe registrarse para ver este enlace ]
tambien pueden encontrar StripReloc en el siguiente link: [ Debe registrarse para ver este enlace ]
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 el tu propio viewbot,
y mandármelo por PM o publicarlo en el foro dándome las gracias.
Saludos!.
 #420471  por WarZ0n3
 03 Ago 2013, 20:13
Perdon por el doble post pero es que era tanto que escribir y explicar que tuve ciertos errores(por mera confusión) por ejemplo me acabo de dar cuenta que puse:
“if assigned”: esta función chequea si la referencia no es de tipo nula (NIL), si lo es retorna TRUE y si no retorna FALSE
(Esta mal).
En realidad es:
“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
 #420592  por WarZ0n3
 04 Ago 2013, 23:10
Pink escribió:Excelente el tutorial gracias por compartirlo.

PD:la seccion .reloc no es inútil.

Si quieres bajar el peso llama a las API de forma dinámica.


saludos
Gracias a ti, por tomarte el tiempo en leer... ojala te haya servido de algo
No quise decir que la sección .reloc es inútil, solo trataba de explicar que lo inutil es lo que
agregan los compiladores, tal vez fui poco explicativo, y lo de llamarlo de forma dinamica,
claro pero este tutorial es para los iniciados en programación con Apis.
Saludos
PD: Tal vez para otro hablemos de eso
 #420802  por Pink
 06 Ago 2013, 22:31
Aquí les dejo un ejemplo en fasm no es la gran cosa. es un ejemplo de novato. (ando aprendiendo)



saludos


PD: los que pidieron tuto no se asomaron mas :S
 #424456  por orlando9427
 12 Sep 2013, 02:49
Doddy escribió:una pregunta , me podes decir cual es la diferencia en hacerlo a tu modo y usar idhttp para hacer las peticiones en unas lineas.
Mayor peso al ejecutable y tienes que manejar excepciones, con APIs no te salta mensajes de error.
 #424458  por WarZ0n3
 12 Sep 2013, 03:10
Perdon por no responder antes esta semana estuve muy ocupado.
Orlando gracias por aclarar el tema, yo voy a agregar algo más (como comentario personal),
programar con APIS es muy conveniente ya que te permite "movilizarte" de una manera mas profesional,
y además teniendo en cuenta la optimización de código y como bien dijo orlando la portabilidad, ademas
de el control de flujo, de punteros, etc...
con APIS puedes hacer "casi" lo que sea, aun que hay veces que no es suficiente y se debe usar ASM
por esto para mi, es la mejor manera de programar .

PD: Pregunta personal a los usuarios que comentaron este post(y a cualquiera que lo haya leído),
¿Les ha servido de algo el tuto? tengo la sensacion que no hay mucho feedback al respecto,
no se si me explique mal o no fue suficiente. Me gustaria que me contestaran, gracias a todos.
 #424489  por Pink
 12 Sep 2013, 13:36
@WarZ0n3
Me parece que el tutorial esta muy muy bueno, y muy buena base para los que comenzamos en la parte de conexiones app & web, A mi me sirvió mucho.
saludos
 #424509  por M3
 12 Sep 2013, 19:26
Descuidate hermano, esta re-bueno el material capo , sirve e de mucho , Muchas gracias ,
 #424837  por $DoC
 16 Sep 2013, 23:17
Aunque yo nunca he trabajado con Pascal, el artículo es muy bueno y es de agradecer que nutras el foro con aportes como este y como otros que ya has hecho.

Gracias WarZ0n3, saludos!