elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Trabajando con las ramas de git (tercera parte)


  Mostrar Mensajes
Páginas: 1 2 [3] 4 5 6 7 8 9 10 11
21  Seguridad Informática / Análisis y Diseño de Malware / Re: Introducción basica al maldev en: 19 Diciembre 2023, 16:28 pm
PEB

Cuando en Windows se abre un ejecutable, por ejemplo chrome.exe, este llamará la función CreateProcess del API de win32 lo que le solicita al sistema operativo que cree un proceso y comience la ejecución. A nivel kernel se creará una estructura de datos EPROCESSES. Luego windows aparta memoria virtual e incluye la representación de memoria física en EPROCESS. Entonces el PEB (Process Environment Block [bloque de entorno de proceso]) es una estructura de datos donde Windows guarda información y configuración asociada con un proceso. El PCB (Process Control Block [bloque de control de proceso]) contiene información que le interesa al kernel como el CPU preferido de este proceso. El TCB (Thread Control Block [Bloque de Control de Hilos]) es lo que usa el kernel para determinar que hilo usar y su jerarquía de preferencia, que es lo que hace el kernel a un nivel muy bajo (pero esa es otra historia).

El PEB se accesa para obtener información del proceso y la información asociada a el como las direcciones base de las librerías dinamicas. Miremos el siguiente código:

Código
  1. typedef struct _PEB_LDR_DATA {
  2. ULONG Length;
  3. UCHAR Initialized;
  4. PVOID SsHandle;
  5. LIST_ENTRY InLoadOrderModuleList;
  6. LIST_ENTRY InMemoryOrderModuleList;
  7. LIST_ENTRY InInitializationOrderModuleList;
  8. PVOID EntryInProgress;
  9. } PEB_LDR_DATA, *PPEB_LDR_DATA;
  10.  
  11. typedef struct _UNICODE_STRING32 {
  12. USHORT Length;
  13. USHORT MaximumLength;
  14. PWSTR Buffer;
  15. } UNICODE_STRING32, *PUNICODE_STRING32;
  16.  
  17. typedef struct _PEB32 {
  18.    // ...
  19. } PEB32, *PPEB32;
  20.  
  21. typedef struct _PEB_LDR_DATA32 {
  22.    // ...
  23. } PEB_LDR_DATA32, *PPEB_LDR_DATA32;
  24.  
  25. typedef struct _LDR_DATA_TABLE_ENTRY32 {
  26.    // ...
  27. } LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;
  28.  

Como se puede ver PEB son estructuras robustas. Y las estructuras como _PEB_LDR_DATA32 son versiones simplificadas del PEB como tal. Estas contienen información y las direcciones de los modulos que estan cargados en memoria.

Código
  1. size_t GetModHandle(wchar_t *libName) {
  2. PEB32 *pPEB = (PEB32 *)__readfsdword(0x30); // ds: fs[0x30]
  3. PLIST_ENTRY header = &(pPEB->Ldr->InMemoryOrderModuleList);
  4.  
  5. for (PLIST_ENTRY curr = header->Flink; curr != header; curr = curr->Flink) {
  6. LDR_DATA_TABLE_ENTRY32 *data = CONTAINING_RECORD(
  7. curr, LDR_DATA_TABLE_ENTRY32, InMemoryOrderLinks
  8.  
  9. );
  10. printf("nodo actual: %ls\n", data->BaseDllName.Buffer);
  11. if (StrStrIW(libName, data->BaseDllName.Buffer))
  12. return data->DllBase;
  13. }
  14. return 0;
  15. }
  16.  

Para acceder la dirección base de un modulo que este cargado en memoria se usa la funcion GetModHandle. Dentro de el PEB hay una estructura llamada PEB_LDR_DATA que contiene la información de un modulo cargado en la memoria. Tambien hay una lista enlazada a los modulos de la memoria que se llamada InMemoryModuleOrderList. La funcion GetModHandle antes mencionada cicla por los elementos de esta losta hasta encontrar el modulo especificado por el parámetro libName.

El PEB se puede encontrar en fs (0x30) en el TEB (Thread Environment Block [Bloque de Hilo de Entorno]) para procesadores x86 y en gs (0x60) para procesadores x64.

Despues usaremos la fincion GetFuncDir para obtener la dirección de una funcion de gro de un modulo.

Código
  1. size_t GetFuncDir(size_t baseModulo, char* szFuncName) {
  2.  
  3. // Interpretar tabla de exportación
  4. PIMAGE_DOS_HEADER dosHdr = (PIMAGE_DOS_HEADER)(baseModulo);
  5. PIMAGE_NT_HEADERS ntHdr = (PIMAGE_NT_HEADERS)(baseModulo + dosHdr->e_lfanew);
  6. IMAGE_OPTIONAL_HEADER optHdr = ntHdr->OptionalHeader;
  7. IMAGE_DATA_DIRECTORY dataDir_exportDir = optHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
  8.  
  9. // Interpretar informacion de la funcion
  10.  
  11. PIMAGE_EXPORT_DIRECTORY tablaExp = (PIMAGE_EXPORT_DIRECTORY)(baseModulo + dataDir_exportDir.VirtualAddress);
  12. DWORD* arrFuncs = (DWORD *)(baseModulo + tablaExp->AddressOfFunctions);
  13. DWORD* arrNames = (DWORD *)(baseModulo + tablaExp->AddressOfNames);
  14. WORD* arrNameOrds = (WORD *)(baseModulo + tablaExp->AddressOfNameOrdinals);
  15.  

Esta funcion toma el parámetro baseModulo que es la dirección base del módulo. Despues se fija en la tabla de exportación (tablaExp) para buscar la funcion que tenga de nombre szFuncName. La tabla de exportación es parte de la estructura de datos del modulo lo cual es procesado por el PEB. La tabla de exportación es parte del archivo PE y nos da una manera de acceder las funciones de este externamente:

  • Accesso a el encabezado DOS y el encabezado NT para navegar el encabezado opcional de el archivo PE.
  • Identificar los puntos de exportación usando el indice IMAGE_DIRECTORY_ENTRY_POINT de la lista de directorios de el encabezado opcional.
  • Calcular la dirección de la tabla de exportación que contiene datos de las funciones exportadas del modulo.

Ahora, dentro de un ciclo vamos a comparar el nombre de la funcion exportada sz_CurrApiName con el nombre de la funcion szFuncName. Cuando coincide arrojamos fatos sobre la función.

Código
  1. for (size_t i = 0; i < tablaExp->NumberOfNames; i++) {
  2. char* sz_CurrApiName = (char *)(baseModulo + arrNames[i]);
  3. WORD num_CurrApiOrdinal = arrNameOrds[i] + 1;
  4. if (!stricmp(sz_CurrApiName, szFuncName)) {
  5. printf("[+] Found ordinal %.4x - %s\n", num_CurrApiOrdinal, sz_CurrApiName); //enumeration process
  6. return baseModulo + arrFuncs[ num_CurrApiOrdinal - 1 ];
  7. }
  8. }
  9. return 0;
  10. }
  11.  

Si el nombre de la funcion coincide con el nombre de la funcion deseada arrojamos su dirección. Calculamos la dirección de la funcion haciendo referencia a arrFuncs y al ordinal.

Esto es importante por que sto nos permite realizar una inyección de proceso y cargar una funcion dinamicamente. Ahora tenemos la función main:

Código
  1. int main(int argc, char** argv, char* envp) {
  2.    size_t kernelBase = GetModHandle(L"kernel32.dll");
  3.    printf("[+] GetModHandle(kernel32.dll) = %p\n", kernelBase); // resultado de GetModHandle
  4.  
  5.    size_t ptr_WinExec = (size_t) GetFuncDir(kernelBase, "WinExec");
  6.    printf("[+] GetFuncDir(kernel32.dll, WinExec) = %p\n", ptr_WinExec); // la direcci&#243;n de WinExec
  7.    ((UINT(WINAPI*)(LPCSTR, UINT))ptr_WinExec)("calc", SW_SHOW);
  8.    return 0;
  9. }
  10.  

Aqui usamos la función GetModHandle para encontrar la dirección de kernel32.dll dentro del proceso actual. Usamos el PEB para revisar la lista de modulos cargados por uno que coincida con el nombre kernel32.dll. Teniendo esta, usamos GetFuncDir para encontrar la dirección de WinExec que esta despues de la de kernel32.dll y es por eso que tomamos su dirección como la dirección base. Despues invocamos la funcion WinExec dinamicamente usando la dirección obtenida. Transformamos ptr_WinExac a el tipo adecuado para que sea un puntero de esta funcion. Y luego la invocamos con el argumento "calc" para abrir la calculadora.

Esto muestra como podemos ubicar dinamicamente la funcion WinExec dentro de kernel32.dll y ejecutarla para abrir la calculadora (que obviamente en un escenario de maldev sería otra cosa). Esto es una manera de manipular codigo usando el PEB, localizando y utilizando funciones de los modulos cargados.

Ahora prestemos atención a una linea interesante:

Código:
((UINT(WINAPI*)(LPCSTR, UINT))ptr_WinExec)("calc", SW_SHOW);

Esta es donde se invoca dinamicamente la funcion WinExec. Ahora miremosla mas a fondo.

    • (UINT(WINAPI*)(LPCSTR, UINT))ptr_WinExec Esta cambia el tipo de ptr_WinExex de un puntero normal a uno apropiado para una funcion del API de Windows. Tambien nos encargamos de los parámetros que es un string LPCSTR y un numero UINT.
    • ("calc", SW_SHOW) Son los parámetros antes mencionados. Que simplemente le dicen a WinExec que abra una ventana de "calc" con el modo de display SW_SHOW.

    Lo que sucede es que el codigo inyecta dinamicamente la ejecución que nosotros deseamos a un proceso legitimo. En vez de tener que incluir la funcion WinExec estáticamente, cad que corre la localiza y la ejecuta dinamicamente.

    Esto se usa comúnmente en el malware para no tener que importar ciertas funciones de interés y asi se menos detectables.[/list]
    22  Seguridad Informática / Análisis y Diseño de Malware / Introducción basica al maldev en: 19 Diciembre 2023, 16:28 pm
    Casi no se ven mucho acerca del desarrollo de malware asi que quiero aportsr compartiendo algunas cositas que voy encontrando. Aqui pienso escribir los conceptos basicos del desarrollo de malware usando el WinAPI. Como por ejemplo el cargado dinamico de funciones, accesando El PEB (Process Environment Block [Bloque de entorno de Processos]) y la ejecucion de funciones en el codigo. Además de la obufscacion y encodificacion de la payload usando cosas como XOR o AES para hacerla más difícil de de detectar. Entre otras :3.

    Cargado y Ejecucion Dinámica de una Función[size]

    De ejemplo vamos a empezar con algo simple. La función MessageBoxA que simplemente abre una ventanilla para mostrar un mensaje. Esta función es parte de WinAPI. Nuestro código va a ser simple pero veremos cómo montar funciones dinamicamente. Esto es uno de los principios fundamentales para evadir detección.

    Código
    1. int main(void) {
    2. MessageBoxA(0, "Holi mundo.", "info", 0);
    3. return 0;
    4. }
    5.  

    En Este código estamos llamando la función directamente. Lo que significa que será enlazada estáticamente al momento de la compilación. Esto en resumen significa que su código será incluido en nuestro programa y no se tendrá que cargar al momento de la ejecución.

    Ahora esto es muy fácilmente detectado al momento de análisis así que lo llevaremos otro paso. Observemos el siguiente código:

    Código
    1. int main(void) {
    2. size_t get_MessageBoxA = (size_t)GetProcAddress( LoadLibraryA("USER32.dll"), "MessageBoxA" );
    3. def_MessageBoxA msgbox_a = (def_MessageBoxA) get_MessageBoxA;
    4. msgbox_a(0, "Holi mundos", "info", 0);
    5. return 0;
    6. }
    7.  

    El Codigo hace lo mismo que el anterior la diferencia es que aquí estamos cargando la función dinamicamente mediante GetProcAddress. Esta función (que literalmente se llama "obtén dirección de proceso") en el momento de ejecución irá a USER32.dll y buscará la dirección de MessageBoxA. Para hacer que esto funcione, necesitamos un puntero de función que get_MessageBoxA que coincida con la función MessageBoxA. Usamos está dirección para asignarla al puntero y a travez del puntero accesamos la función.

    El usar punteros nos ayuda a obfuscar la funciones que usamos y hacerle más difícil al análisis estático que es lo que estamos haciendo. Considera el siguiente código que son dos funciones que habren ventanillas con un mensaje. Estas funciones serán importadas de un dll:

    Código
    1. __declspec(dllexport) void func1() { MessageBoxA(0, "", "Uno", 0); }
    2. __declspec(dllexport) void func2() { MessageBoxA(0, "", "Dos", 0); }
    3.  
    4. BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
    5.    if (fdwReason == DLL_PROCESS_ATTACH) {
    6.        // Función gancho para la func1
    7.    }
    8.    return TRUE;
    9. }
    10.  

    Esto parece normal, tenemos dos funciones que son importadas de un dll y cada una abre una ventanilla como lo dije. Pero la cosa aquí es que dentro de DllMain podemos cambiar el comportamiento de func1. Esto para dar una impresión inicial de código benigno y después correr el código sospechoso. La cosa es que esto solo ocurrirá al momento de ejecución haciéndolo muy bueno para evitar detección.

    23  Programación / Programación C/C++ / Re: Desgraciadamente, aún existen proyectos en C, y deben ser mantenidos en: 19 Diciembre 2023, 16:12 pm
    Se me hace muy gracioso cuando los que quieren criticar C en la mayoria de los casos solo terminan mostrando su falta de habilidad. Que a fin de cuentas en eso cae la discusión. Cualquiera que diga que los lenguajes interpretados son mas rapidos lo unico que esta haciendo es mostrar que su forma de programar es tan ineficiente que necesitan que los lleven de la mano. Los lenguajes interpretados por definicion son mas lentos que los compilados y esto aumenta con cada nivel de abstraccion que proporcioné. A fin de cuentas la mayoria de los lenguajes interpretados solo son hechos en C y toda via tienen que montar su run time.

    Es sin necesidad explicar el porque tener un binario ejecutable que pueda correr nativamente en un sistema es un beneficio. Sin mencionar el grado de control que da en terminos de como se utiliza la memoria. Una de las cosas que no me gustan de los lenguajes modernos es que es prácticamente imposible poder optimizar la alocacion de memoria ni limitar el buffer de una lista o string. Simplemente un dia decidieron que era buena idea que estos sean infinitos hasta que crasheen el programa.

    Hablan como si C se invento hace 50 años y no se a vuelto a tocar desde entonces. Incluso hasta la fecha se sigue mejorando y yo personalmente estoy emocionado con la anunciada de C23. Asi que no es como dicen que es cosa del pasado y que esta llegando a la irrelevancia.

    Quisiera ver a uno de esos programadores modernos que critican C hacer algo mas alla de aplicaciones electron y programas de listas de super. Para mi uno de los mejores lenguajes modernos es Rust y admito que ha mejorado muchos aspectos de C. Pero al final del dia sigue siendo C nomas un poco más agradable xd. Obviamente hay casos donde tiene sentido por tiempo y eficiencia usar un lenguaje de scripting por ejemplo cuando voy a hacer un scraper ni loco lo haria en C y uso python o ruby en su lugar. Pero vuelvo estan hechos en C y corren en un sistema operativo también hecho en C.

    Ahora viniendo de alguien que se dedica a las computadoras cuanticas pues obviamente toda la tecnología que conocemos es obsoleta. Pero aun asi hay muchos casos en que C sigue siendo mas util incluso que la computacion cuantica. Y quien no este de acuerdo, ya que tengas un reloj inteligente cuantico o una calculadora cuántica hablamos.

    24  Sistemas Operativos / Unix/Unix-Like / Re: error irresoluble? en: 18 Diciembre 2023, 17:13 pm
    Eso pasa seguido lo puedes solucionar con:

    Código
    1. rm -f /var/lib/dpkg/info/<nombre del paquete>*
    2. apt-get purge <nombre del paquete>
    25  Informática / Tutoriales - Documentación / Re: Nuevo nombre de dominio para la descarga de cursos... en: 18 Diciembre 2023, 08:28 am
    Tomado en cuenta gracias
    26  Programación / Programación C/C++ / Re: Función pedir un a llenar un array en: 17 Diciembre 2023, 05:13 am
    Primero y te lo digo como amigo, tu codigo esta horrible. Hay muchas maneras de hacer lo que buscas pero intentaré mostrarte una forma simple para que agarres práctica. Uno de los primeros problemas al que te vas a enfrentar es que este array es inaccesible a tu funcion principal. Es muy tedioso lidiar con arrays cuando se trata de accesarla atraves de una funcion y si nada mas la vas a modificar una vez (como creo que es tu caso) puedes usar una allocacion dinamica. Solo acuerdate de liberarla cuando termines. Y lo bueno de este codigo es que es facil modificarlo para que funcione cpn diferentes valores. Otra es que para poder validar los números en este caso uso unsigned int para poder solo usar una comparación y no tener que preocuparse por los numeros negativos. Ademas deberias tomar en cuenta que cuando haces algo veces repetidas es mejor usar un ciclo que escribirlo varias veces.

    Código
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3.  
    4. unsigned int *obtenerNumeros();
    5.  
    6. int main() {
    7. unsigned int *numeros = obtenerNumeros();
    8.  
    9. for(int i = 0; i < 10; i++) {
    10. printf("%d\n", numeros[i]);
    11. }
    12.  
    13. free(numeros);
    14.  
    15. }
    16.  
    17. unsigned int *obtenerNumeros() {
    18. unsigned int *ret = malloc(10);
    19. int i = 0;
    20. unsigned int numero;
    21.  
    22. printf("ingresa 10 numeros del 1 al 4\n");
    23.  
    24. do {
    25. scanf("%u", &numero);
    26.  
    27. if(numero > 4) {
    28. printf("%d no es un numero valido, vuelve a intentar\n", numero);
    29. } else {
    30. ret[i] = numero;
    31. i++;
    32. }
    33. } while(i < 10);
    34.  
    35. return ret;
    36. }
    37.  
    27  Programación / Scripting / Re: Perl en 2023 en: 15 Diciembre 2023, 22:29 pm
    A mi me gusta mucho en termino de su efectividad. Incluso me atrevo a decir que me gusta mas que python aunque usar python es mas facil por que alguien mas ya hizo el trabajo duro. Pero me gusta mucho perl en terminos de su libreria estandar es muy completa y obvio su eficiencia al usar expresiones regulares. Aparte no depende tanto de recursos externos y se puede hacer mucho sin preocuparse por la compatibilidad en usarlo en entornos diferentes.

    Yo creo que su mayor limitacion es que el interpretador es demasiado lento ya que se compila en cada ejecución, pero para programas grandes siendo que esto solo sucede una vez no debe ser gran problema. La implementación del precompilado es experimental y no veo que se vaya a implementar pronto. Tambien me gusta que puedo desactivar las advertencias pero especificar cuales no quiero ver en vez de desactivarlas todas por completo. Tambien en terminos de seguridad para mi saca un 8/10 que es muy bueno siendo que los lenguajes viejos suelen ser muy inseguros pero cosas como [img=https://perldoc.perl.org/perlsec]perlsect/img] que es muy interesante. Como por ejemplo su modo teñido que hace que la escalacion de privilegios sea prácticamente imposible incluso si el programa es vulnerable.

    No creo que perl muera gracaias a que cPanel, duckduckgo, ticketmaster entre otros lo usan asi que yo creo que se quedara otro rato.

    En general me gusta perl pero no es el principal le lenguaje que uso. A veces me invento proyectos solo para poderlo usar xd.
    28  Media / Juegos y Consolas / Re: Como crear un emulador? en: 15 Diciembre 2023, 22:11 pm
    De hecho es relativamente facil si sabes lo que estas haciendo. Solo no quieres empezar por querer emular un ps5 xd.

    Yo como un ejercicio de programación eh estado considerando hacer un emulador (o varios no se). Y de lo que eh visto el mejor lugar para empezar es emular un chip-8 y despues pasarte a mime. Esto te dará mucho conocimiento base para que comprendas como funciona la emulacion. Aqui un link: chip-8 que esta en ingles lo se pero es el mejor que eh encontrado yes muy extenso la verdad. Y despues te puedes pasar a la emulación de un gba que es muy interesante tambie.

    En terminos de como funcionan hay dos tipos, los de nivel alto y los de nivel bajo. No entraré en mucho detalle sobre los de nivel alto ya que el concpepto no es muy complicado simplemente das un entorno donde se pueda ejecutar el codigo de la aplicación deseada.

    Primero quisiera dar una distinción entre virtualización y emulacion. En la virtualización por ejemplo en virtualvox o incluso el JVM, le das accesso a los recursos de tu sistema de forma virtualizada para el programa que deseas correr. Osea que le das acceso al programa al hardware real. En caso de una emulacion lo que haces es crear ese hardware de manera logica. Osea que un emulador nivel bajo lo que hace es simular el hardware del sistema que se esta emulando. Esto puede tomar varias forma como incluso mandarle al programa las señales que le mandaria el hardware original. Entonces entre mas chip y mas complejo sea el dispositivo que quieres simular, pues mas complejo seria tu emulador.

    La verdad este es un tema nuevo para mi y espero que te haya ayudado esta información en darte algo de orientación.
    29  Programación / Programación C/C++ / Re: Contador en: 14 Diciembre 2023, 00:46 am
    Supongo que hay mas codigo. Para empezar creo que te falto incluir "while al inicio del ciclo y se me hace un milagro que el compilador no te eeste regañando. Estas usando C17?

    Y aparte contador += 1; esta a fuera del ciclo entonces solo se sumara una vez terminada la ejecucion, no en cada vuelta que es lo que creo que quieres. Solo subelo y asegurate que este andentro de los corchetes de tu ciclo.

    Tambien es mejor cuando incrementas de uno usar operador de incrementacion. Osea contador++.
    30  Programación / Programación General / Re: [CONSULTA] API de Whatsapp en: 12 Diciembre 2023, 05:37 am
    Si quieres automatizar el WA es mejor usar algo que no interactue directamente con el DOM de la aplicación web o con el API. Es muy fácilmente detectado y si suspenden cuentas icluso corres el riesgo de un baneo de dispositivo. Y esto lo dicen los terminos y condiciones. De hecho lo que quieres hacer esta explícitamente prohibido. Usar proxies tambien te puede llevar a que terminen tu cuenta.

    Aqui lo que mejor me funciona es usar un automatizador que sea "por encima" de la aplicación web. Por ejemplo a mi me gusta pyautogui que emula las entradas de teclado y mouse a traves de el sistema operativo y no directamente en la aplicación. Tambien puedes poner retrasos a las entradas para que no se detecte que es un bot.
    Páginas: 1 2 [3] 4 5 6 7 8 9 10 11
    WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines