En Colombia, el auge del comercio electrónico y las ventas por redes sociales ha impulsado a miles de pequeños negocios a digitalizarse rápidamente. Desde tiendas de ropa hasta ventas de productos artesanales, muchas micro y pequeñas empresas manejan catálogos, pagos y atención al cliente vía páginas web, Facebook, Instagram y WhatsApp.
Sin embargo, esta rápida digitalización trae consigo un incremento exponencial en fraudes digitales, ataques cibernéticos y suplantación de identidad que pueden afectar directamente las ventas y la confianza de los clientes.
¿Cuáles son los fraudes digitales más comunes que afectan a pequeños negocios online en Colombia?
Suplantación de cuentas de WhatsApp Business o perfiles en Instagram Los estafadores crean cuentas idénticas a las de la tienda para solicitar pagos anticipados por productos falsos o engañar clientes con ofertas inexistentes.
Phishing y páginas web falsas Se crean sitios web que imitan el negocio original para capturar datos bancarios o personales de los clientes.
Ataques a plataformas de pago Robos de credenciales o manipulación de pasarelas de pago que generan cobros indebidos o anulaciones fraudulentas.
Robo o filtración de bases de datos de clientes Incluye nombres, direcciones, teléfonos y detalles de compra, que luego pueden ser vendidos o usados para campañas de spam y estafas.
Ataques de denegación de servicio (DDoS) Que hacen caer el sitio web en momentos claves de ventas, causando pérdidas económicas.
Inserción de código malicioso (malware) en el sitio web Que puede redirigir a los visitantes a sitios peligrosos o infectar dispositivos de clientes.
¿Qué pasos debe tomar un pequeño negocio si detecta un fraude digital o ataque en su página web o redes sociales?
Aislar los sistemas afectados y cambiar todas las contraseñas Incluye no solo la página web, sino también las cuentas de redes sociales, correo electrónico y plataformas de pago.
Contactar al proveedor de hosting y plataformas sociales Para solicitar soporte y bloqueo de cuentas falsas o acceso no autorizado.
Recopilar evidencias Capturas de pantalla, correos sospechosos, mensajes de clientes afectados, y registros de acceso para facilitar investigaciones.
Solicitar apoyo profesional en informática forense Esto permite identificar la causa, la extensión del daño y las acciones para evitar nuevas brechas. Más en https://ihack.red/informatica-forense/
Informar a los clientes con transparencia Comunicarles qué sucedió, qué datos pudieron verse comprometidos y qué medidas se están tomando para protegerlos.
Denunciar el incidente ante la Fiscalía Para que se inicie un proceso legal contra los responsables.
¿Cómo prevenir fraudes digitales y ataques en pequeños negocios online?
Implementar certificados SSL para asegurar la conexión en la página web.
Mantener actualizados todos los plugins, temas y sistemas de gestión web.
Usar sistemas de pago confiables y verificables.
Configurar autenticación de dos factores en todas las cuentas digitales.
Capacitar al equipo en identificación de correos y mensajes maliciosos.
Realizar respaldos periódicos y seguros de toda la información crítica.
¿Por qué invertir en ciberseguridad es vital para un pequeño negocio online?
Porque la confianza es la base de la relación con el cliente. Un incidente de seguridad puede:
Disminuir la reputación y las ventas.
Generar pérdidas económicas directas y multas legales.
Crear desconfianza en los canales digitales.
Llevar a la suspensión temporal o definitiva del negocio online.
En ciudades como Bogotá, Medellín, Cali y otras capitales regionales, los pequeños negocios que invierten en protección digital han logrado no solo prevenir ataques sino aumentar su competitividad y confianza del cliente.
Si quieres blindar tu pequeño negocio online y proteger tu reputación, iHack.red está listo para ayudarte con estrategias, tecnologías y acompañamiento especializado.
En Colombia, el uso de la banca en línea y las aplicaciones móviles para realizar transacciones financieras ha crecido exponencialmente en los últimos años. Tanto personas naturales como empresas usan estas plataformas para pagos, transferencias y manejo de cuentas bancarias. Sin embargo, este crecimiento también ha traído un aumento en fraudes digitales, ataques y robos de identidad que pueden afectar gravemente las finanzas y la confianza en los servicios digitales.
Los fraudes en banca digital son uno de los delitos cibernéticos que más impacto tienen en usuarios colombianos, especialmente en ciudades como Bogotá, Medellín, Cali y Barranquilla, donde la adopción de tecnología financiera (FinTech) es alta.
¿Cuáles son los fraudes digitales más comunes en banca en línea y apps móviles?
Phishing financiero Correos, SMS o mensajes en redes sociales que simulan ser del banco, solicitando datos sensibles o códigos de seguridad.
Sim swapping (clonación de SIM) Robo del número telefónico para interceptar códigos de autenticación de doble factor y acceder a cuentas.
Malware y troyanos bancarios Software malicioso instalado en dispositivos que registra teclas o intercepta información bancaria.
Ataques de ingeniería social Engaños para convencer al usuario de entregar claves, tokens o información confidencial.
Falsos sitios web y apps fraudulentas Que imitan a bancos o servicios financieros para robar datos o dinero.
Transferencias no autorizadas Mediante el acceso remoto o vulnerabilidades en sistemas.
¿Qué hacer si detectas una transacción sospechosa o un posible fraude?
Contactar inmediatamente a la entidad bancaria Para bloquear la cuenta o transacciones y reportar el incidente.
No responder a mensajes sospechosos ni proporcionar datos personales o códigos.
Denunciar ante las autoridades colombianas y la Superintendencia Financiera.
Consultoría en implementación de autenticación segura y cifrado.
Respuesta inmediata y análisis forense ante incidentes financieros digitales.
¿Por qué es esencial protegerse contra fraudes financieros digitales en Colombia?
Porque las pérdidas económicas directas y la exposición de información sensible pueden impactar no solo a personas sino también a pequeñas, medianas y grandes empresas, afectando su operación y reputación.
En ciudades como Bogotá, Medellín y Cali, la ciberseguridad financiera es una prioridad para garantizar confianza y continuidad en los negocios y servicios personales.
Si deseas proteger tus transacciones financieras y evitar fraudes digitales, iHack.red tiene la experiencia y tecnología para blindar tus operaciones.
En Colombia, miles de freelancers, diseñadores gráficos, community managers, coaches, terapeutas y pequeños comerciantes usan diariamente WhatsApp e Instagram como canales principales para ofrecer sus servicios y productos. Estas plataformas son accesibles, directas y económicas, pero también son un terreno fértil para ciberdelincuentes que buscan suplantar identidades, robar dinero o información sensible.
La vulnerabilidad no está en la herramienta, sino en la falta de medidas de seguridad y conocimiento sobre los riesgos digitales reales que enfrentan.
¿Por qué los freelancers son blancos fáciles para fraudes digitales?
No suelen tener áreas de TI ni asesoría profesional en seguridad.
Usan sus celulares personales para todo, sin protección avanzada.
Manejan pagos y contratos digitales sin sistemas formales o cifrados.
A veces aceptan solicitudes de amistad, mensajes o enlaces sin verificar.
Trabajan con clientes nuevos y desconocidos, lo que abre puertas a engaños.
No cuentan con respaldo de datos ni planes de contingencia ante ataques.
En ciudades como Bogotá, Medellín, Cali, e incluso en zonas rurales con conectividad, se reportan ataques crecientes como:
Suplantación de cuentas de WhatsApp Business para pedir anticipos falsos.
Phishing vía Instagram con mensajes que llevan a páginas falsas para robar credenciales.
Robo o clonación del número telefónico (SIM swapping).
Instalación de malware mediante archivos recibidos de clientes.
Extorsión y amenazas tras hackeo de cuentas.
¿Qué hacer si un freelancer descubre que su WhatsApp o Instagram fue hackeado?
No borrar ni modificar nada inmediatamente Preservar los mensajes, pruebas de pagos o chats ayuda a rastrear al atacante.
Contactar soporte de la plataforma para reportar el hackeo Instagram y WhatsApp tienen procesos para recuperar cuentas, pero pueden ser largos y confusos. En iHack.red apoyamos con asesoría para acelerar este proceso.
Denunciar ante las autoridades colombianas La Fiscalía tiene unidades especializadas en delitos informáticos, pero requieren evidencia técnica.
Solicitar una investigación forense digital Un perito puede identificar cómo entraron, qué información se comprometió y cómo protegerte en el futuro. Más en https://ihack.red/informatica-forense/
Avisar a tus clientes y contactos que tu cuenta fue vulnerada Para que no caigan en posibles fraudes hechos con tu identidad.
¿Cómo prevenir estos ataques siendo freelancer?
Activa la verificación en dos pasos en WhatsApp e Instagram con apps de autenticación, no con SMS.
Usa contraseñas fuertes y únicas para todas tus cuentas.
No abras enlaces o archivos de remitentes desconocidos o sospechosos.
Realiza respaldos periódicos de tus conversaciones y contenidos importantes.
Evita usar redes Wi-Fi públicas sin protección (VPN).
Mantén actualizado tu sistema operativo y aplicaciones.
No compartas datos sensibles ni pagos fuera de plataformas seguras.
¿Qué servicios ofrece iHack.red para freelancers que quieren proteger su negocio digital?
Auditoría de seguridad digital personalizada Revisamos tus perfiles, dispositivos y accesos para identificar riesgos.
Pentesting para tus redes sociales y correos Simulamos ataques para mostrar vulnerabilidades y te ayudamos a corregirlas. Más en https://ihack.red/fortaleza-digital/
Capacitación en prevención de fraudes digitales Para que entiendas qué técnicas usan los atacantes y cómo evitar caer.
Respuesta rápida y forense digital ante incidentes Te acompañamos en la recuperación y denunciación legal si sufres un ataque.
Protocolos y recomendaciones para proteger tus datos y los de tus clientes.
¿Por qué es importante para un freelancer contar con apoyo profesional en ciberseguridad?
Porque la pérdida o robo de una cuenta puede significar:
Pérdida de ingresos al no poder atender clientes.
Daño a la reputación profesional.
Robo de información confidencial de clientes.
Extorsiones o fraudes que comprometen tu negocio.
En Colombia, la ciberseguridad para freelancers es una necesidad urgente y un factor diferencial para competir con confianza.
Si eres freelancer y quieres blindar tu presencia digital, iHack.red tiene las soluciones y experiencia para apoyarte. Contáctanos y protégete con expertos.
En esta ocasión estaremos viendo diferentes herramientas que nos facilitarán la tarea de realizar reversing a programas en Go
¿Por qué es más complicado realizar reversing a programas en GO?
Son varios los factores que dificultan la tarea a los reversers cuando se trata de realizar reversing a los programas en Go como por ejemplo Los programas en GO están enlazados estáticamente (Statically-Linked) es decir que este tendrá incluidos todas las dependencias necesarias para que este funcione. Esto aumenta el tamaño de los mismos, y si abonado a esto no se tienen los símbolos será aún más complicado entender la relación y funcionamiento de las diferentes funciones y podríamos estar analizando código irrelevante para nuestro análisis (código interno de Go). Cuando realizamos reversing a archivos Go sin símbolos no tenemos información tal como los nombres de las variables y funciones con lo que nos dificulta la tarea de entender el propósito de las diferentes funciones y variables además de perdernos fácilmente en las funciones agregadas por Go.
Otra cosa particular de los programas en Go es que las strings no están null terminated en lugar están colocadas pegadas unas con las otras y cuando una función requiere una string se le pasa el puntero y el tamaño de la misma.
En Go Seguir los argumentos y los valores de retorno es más difícil que en programas por ejemplo de c o c++
Realizando pruebas en Go
En esta parte procederemos a compilar un programa en Go y nos dispondremos a analizar el desensamblado con el objetivo de resaltar las diferencias de los programas en Go con otros lenguajes e ilustrar las dificultades que podemos tener a la hora de analizar los mismos
El código que estaremos analizando es el siguiente
package main
import "fmt"
func main() {
var a int
var b int
var res int
fmt.Println("Ingrese el primer numero : ")
fmt.Scan(&a)
fmt.Println("Ingrese el segundo numero : ")
fmt.Scan(&b)
res = suma(a, b)
fmt.Println("La suma es : ", res)
}
func suma(a, b int) int {
return a + b
}
Como podemos ver es un sencillo programa que pide dos números e imprime el resultado de la suma de los dos números, procedamos a ver el desensamblado del programa compilado con símbolos
Como vemos en la imagen la función carece del prólogo clásico de las funciones en c o c++ en lugar de eso tiene una comparación y un salto a llamar a runtime_morestack. De esta manera inicializan la mayoría de las funciones en GO en caso de ser necesario allocara más stack en runtime. El código que a nosotros nos concierne es el código escrito por el usuario así que esto lo podemos pasar por alto
Llama a runtime_newobject al parecer para allocar espacio para nuestros dos enteros
Luego llama a fmt_Fprintln pero el paso de argumentos no es tan claro como lo es en otros lenguajes. Coloca en una parte del stack “Ingrese el primer numero”, en ebx tiene os_Stdout en rax tiene File io writer. Pero depurando nos damos cuenta que lo que hace es imprimir “ingrese el primer numero”
Luego llama a fmt_Fscan en rax tiene file io reader, en rbx tiene os_Stdin y en determinada posición del stack coloca var_70 que es uno de nuestras variables enteras creadas con runtime_newobject y si depuramos nos damos cuenta que escribe en var_70 el numero leído con fmt_Fscan
Imprime ingrese el segundo numero
Lee nuestro segundo numero y lo almacena en var_78
Los suma
Y por último imprime el resultado de la suma
Como nos hemos dado cuenta en este ejemplo es que muchas veces seguir las variables, argumentos y valores de retorno en go puede llegar a ser más complicado que en otros lenguajes, pero podemos ayudarnos de la documentación de go la cual es bastante completa y asistirnos de la depuración
Análisis de programas en Go sin símbolos
En esta parte procederemos a compilar el ejemplo anterior pero esta vez sin símbolos y veremos una herramienta que nos ayudara en el análisis de programas Go cuando estos carecen de símbolos.
Abramos el ejemplo en ida
Como podemos ver en la imagen tenemos 1128 funciones y ninguna tiene nombre o alguna pista si es interna de go o creada por el usuario. Si empezamos a realizar el reversing así va a ser demasiado tedioso.
Gracias a AlphaGolang de sentinel labs esto no tiene que ser así. AlphaGolang es una serie de scripts para idapython que te permiten entre otras cosas recuperar la información de los símbolos, veamos esta serie de scripts en acción
Recrear la tabla pcln
La tabla pcln es una tabla que contiene información sobre las funciones del programa incluyendo los nombres. El primer script lo que hace es recrear dicha tabla
Aquí tenemos los segmentos del programa ejemplo antes de ejecutar el primer script
Ejecutamos el primer script
Y este es el resultado el script crea un segmento que contiene la información de esta tabla
2. Descubrimiento de funciones y renombrado
El siguiente script lo que hace es renombrar las funciones del programa
Estas son las funciones antes de ejecutar el segundo script
Y este es el resultado luego de ejecutar el script. Como vemos ha renombrado la gran mayoría de funciones ahorrándonos un gran trabajo sin embargo no todas fueron renombradas
3. El tercer script organiza las funciones en carpetas, pero por una razón la cual desconozco no funciona en mi maquina
4. El cuarto script arreglas las referencias a las strings
5. El quinto y ultimo script comenta en todas las llamadas a newobject el tipo de objeto
Conclusión
La ingeniería inversa de programas en go puede llegar a tener una mayor dificultad que la ingeniería inversa a otros lenguajes, pero existen Scripts y herramientas que hacen que el proceso de reversing sea mas llevadero
Hola amigos en esta ocasión estaremos hablando de la ingeniería inversa, aprenderemos que es, resolveremos las dudas más comunes y aprenderemos que es lo necesario para iniciarse en este arte
¿Qué es el reversing?
El reversing o la ingeniería inversa es el proceso de tomar un producto final y obtener información sobre su funcionamiento y\o como fue realizado, existen varios tipos de reversing como, por ejemplo, reversing de hardware, software, mecánico etc. en este artículo nos enfocaremos en la ingeniería inversa de software
¿Para qué se usa el reversing?
El reversing de software se utiliza en muchas áreas diversas, como por ejemplo en análisis de malware, para conocer el funcionamiento y las acciones llevadas a cabo por el mismo con el objetivo de crear las medidas de protección necesarias. También es utilizado en el área de detección de vulnerabilidades, en esta se utiliza la ingeniería inversa para identificar el código con fallas de seguridad y crear exploits que aprovechan esas vulnerabilidades descubiertas. Otros usos que se le pueden dar al reversing son, recuperar código perdido, extender funcionalidades, descifrar algoritmos criptográficos, descifrar protocolos, y también es utilizado en el cracking de software para retirar las medidas de protección del software, y retirar las limitaciones
¿Es el reversing Legal?
El reversing es legal si el producto sometido a ingeniería inversa fue obtenido de manera legal y se es el propietario del mismo, aunque esto puede variar dependiendo de la legislación del país. también es legal realizar ingeniería inversa de malware.
Realizar reversing a determinado software con el objetivo de quitarle las medidas de seguridad y limitaciones para poder usarlo “Full”, es ilegal, a esto se le conoce como cracking
¿Cómo iniciarse en reversing?
Para iniciarse en reversing es muy útil tener una base de programación, aunque esto no debe ser impedimento para empezar, se puede aprender los conceptos de programación conforme se avanza, es necesario conocer las instrucciones más comunes del código ensamblador para la arquitectura objetivo, si se realiza reversing de códigos interpretados es necesario conocer esos lenguajes. Algo muy importante es la práctica, para practicar de manera legal se pueden utilizar crackmes que son programas destinados para aprender técnicas de ingeniería inversa, existen muchos crackmes y de muchos niveles desde principiante hasta algunos muy avanzados.
También existen cursos y comunidades como Crackslatinos que es una gran comunidad donde siempre están dispuestos a darte una mano
¿Cuáles son las herramientas?
A la hora de realizar reversing nos podemos ayudar de muchas herramientas que nos asistirán en el proceso de ingeniería inversa, entre esas herramientas tenemos Desensambladores, decompiladores, debuggers, editores hexadecimales, y otras herramientas útiles que nos asisten en la labor
Desensambladores
Los desensambladores son programas que se encargan de traducir el código maquina a código ensamblador
Debuggers
Los debuggers o depuradores son programas en los cuales podemos ver paso a paso las instrucciones del programa (muchas veces en ensamblador), podemos parar en cualquier punto del programa, editar el flujo de ejecución del programa, editar las instrucciones entre un abanico de posibilidades, sin duda una de las herramientas esenciales a la hora de hacer reversing
Decompiladores
Los decompiladores son herramientas que a partir de un código compilado realizan el proceso de convertir el código maquina a seudocódigo C, este proceso no es perfecto y nunca se recupera el código original sino una aproximación
Editores Hexadecimales
Los editores hexadecimales son programas que nos permiten editar archivos binarios
Detectores de packers
Este tipo de herramientas nos muestran si el programa se encuentra protegido por un packer y que packer información que será de mucha utilidad
Algunas herramientas frecuentemente utilizadas
En este apartado veremos una lista de herramientas frecuentemente utilizadas y su objetivo
IDA
The interactive disassembler es una herramienta super completa para realizar tanto análisis estático como dinámico, esta cuenta con desensamblador, decompilador, debugger, sumado a la capacidad de renombrar variables, crear estructuras crear scripts para automatizar procesos y muchas otras cosas que nos facilitan el análisis. Esta herramienta cuenta tanto con versión gratuita (IDA freeware), como versión de pago
x64dbg
x64dbg es un debugger que soporta debugging tanto de x64 con x32, esta herramienta soporta también un lenguaje de scripting similar al ensamblador
Process Explorer
Esta herramienta que hace parte de sysinternal suite es una herramienta que nos permite ver los procesos en ejecución e información adicional como los handles, las dlls procesos hijos entre otra información
Process Monitor
Esta herramienta también de sysinternal suite nos permite monitorizar las acciones realizadas por un proceso como por ejemplo esta herramienta registrará si el proceso manipula el registro, si crea o modifica archivos entre otras acciones, esta cuenta con una serie de filtros que nos ayudan a encontrar más fácilmente información especifica
WireShark
Esta herramienta la cual es un packet analyzer nos permite capturar los paquetes enviados y recibidos y nos permite filtrar y ver la información de cada paquete
HxD
HxD es un editor hexadecimal bastante usado este nos permite modificar archivos binarios
CFF explorer
Esta herramienta nos permite ver y editar el contenido de archivos portable ejecutable, que es el formato de archivo de los ejecutables de Microsoft Windows
RegShot
Esta herramienta te permite tomar un snapshot del estado actual del registro y uno después de haber ejecutado el software analizado con el objetivo de ver qué cambios sufrió el registro
Palabras Finales
La ingeniería inversa de software es un área que requiere practica y dedicación para dominarla. Pero una vez aprendidas las bases el proceso es más llevadero
Cuando nosotros escribimos nuestro código fuente en un lenguaje de alto nivel este al ser compilado es traducido a código maquina el cual es ejecutado por el procesador. Cuando realizamos ingeniería inversa tomamos un ejecutable ya compilado y realizamos el desensamblado del mismo para proceder con el análisis.
¿Qué es desensamblar?
Desensamblar es el proceso de traducir el código de máquina de un programa en lenguaje ensamblador. Es decir, el proceso de convertir el código de máquina en una representación legible por humanos, que es más fácil de entender y analizar que el código de máquina. Un desensamblador toma el archivo ejecutable del programa y lo analiza para identificar las instrucciones de código de máquina y su correspondiente representación en lenguaje ensamblador. El resultado es un archivo de texto legible por humanos que muestra el código ensamblador del programa. Es importante destacar que el proceso de desensamblar no siempre produce un código ensamblador idéntico al código fuente original, ya que el código de máquina puede ser optimizado y reordenado por el compilador durante la compilación. Por lo tanto, el código ensamblador producido por el desensamblador puede requerir cierta interpretación y análisis para comprender completamente su funcionamiento.
¿Qué es el lenguaje ensamblador?
El ensamblador (también conocido como «Assembly» en inglés) es un lenguaje de programación de bajo nivel utilizado para escribir programas que operan directamente en la arquitectura de una computadora. El ensamblador utiliza una sintaxis que está muy cerca del lenguaje de máquina, lo que permite al programador escribir instrucciones que se traducen directamente en códigos de máquina ejecutables por el procesador.
Antes de ver las instrucciones en ensamblador debemos conocer lo que son los registros, Los registros del procesador son pequeñas áreas de almacenamiento en la CPU que se utilizan para realizar operaciones aritméticas y lógicas, y para almacenar temporalmente datos y direcciones de memoria. Existen varios registros entre los cuales destacamos: registros de propósito general, registros de coma flotante y registros de propósito especifico.
Registros de propósito General (GPR)
Los registros de propósito general son utilizados para almacenar temporalmente datos y direcciones de memoria. Algunos de estos cumplen propósitos específicos en determinadas instrucciones. Entre los registros de propósito general para la arquitectura de 64 bits tenemos los registros RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP y los registros desde el R8 al R15
Registros de punto Flotante
Los registros de punto flotante son utilizados para realizar operaciones matemáticas con números de punto flotante en la arquitectura de 64 bits tenemos los registros de la serie XMM, YMM y ZMM
Registros de Propósito Especifico
Entre los registros de propósito especifico tenemos los registros RFLAGS y RIP. El registro RIP es utilizado para contener la dirección de la próxima instrucción que se va a ejecutar y el registro RFLAGS es utilizado para contener el estado de la CPU y contiene diferentes banderas que indican el resultado de las operaciones entre otras cosas
Si por ejemplo el resultado de una resta nos da cero el registro RFLAGS colocara la bandera que indica que el resultado es cero (Zero Flag) a 1 indicando que el resultado de la operación anterior fue cero. O si por ejemplo el resultado de la resta da un numero negativo la bandera del registro RFLAGS que indica que el resultado es un numero negativo (Sign Flag) será colocada a 1 en caso contrario es decir el resultado dio un numero positivo la bandera que indica que el resultado es negativo será colocada a 0
Instrucciones en ensamblador
Las instrucciones del lenguaje ensamblador son el conjunto de instrucciones que son interpretadas directamente por el procesador estas las podemos clasificar en, instrucciones de movimiento de datos, instrucciones de comparación, instrucciones aritméticas, instrucciones de control de flujo, instrucciones de llamada y retorno, instrucciones de manejo de pila, instrucciones lógicas y de desplazamiento de bits
instrucciones de movimiento de datos
Las instrucciones de movimiento de datos nos permiten mover desde la fuente al destino estas pueden ser de movimiento incondicional o movimiento condicional
Instrucciones de movimiento incondicional
Las instrucciones de movimiento incondicional son instrucciones que se encargan de mover datos desde la fuente al destino incondicionalmente es decir que no tienen en cuenta los FLAGS o banderas antes de mover entre estas instrucciones tenemos LEA, MOV y XCHG
MOV
La instrucción MOV nos permite mover datos desde fuente a destino en caso de que la fuente se encuentre entre corchetes (por ejemplo, modo de direccionamiento indirecto) se calculará la dirección y se moverá el contenido de la dirección a la fuente
sintaxis
mov destino, origen
ejemplo
mov eax, 1 ; mueve el valor 1 al registro EAX
mov ebx, eax ; mueve el valor de EAX a EBX
mov [memoria], eax ; mueve el valor de EAX a la dirección de memoria indicada
mov al, [ebx] ; mueve el byte almacenado en la dirección apuntada por EBX al registro AL
mov dword ptr [eax], 0 ; mueve el valor 0 a la dirección de memoria indicada por el registro EAX
LEA
La instrucción Lea (Load effective Address) es una instrucción utilizada para calcular la dirección efectiva, esta instrucción va a calcular la dirección del segundo operando (el operando fuente) y lo va a almacenar en el primer operando (destino) es decir calculará la dirección contenida entre corchetes y moverá la dirección no el contenido de la dirección
sintaxis
lea registro, dirección_de_memoria
ejemplo
lea ebx, [memoria] ; carga la dirección de memoria en EBX
lea eax, [ebx+4] ; carga la dirección de memoria desplazada por 4 bytes de la dirección almacenada en EBX en EAX
lea edx, [ebx+eax*2] ; carga la dirección de memoria desplazada por el doble del valor almacenado en EAX desde la dirección almacenada en EBX en EDX
XCHG
Exchange Esta instrucción intercambia los contenidos de registros/memoria con registros
sintaxis
xchg destino, origen
ejemplo
xchg eax, ebx ; intercambia el contenido de los registros EAX y EBX
MOVSX
La instrucción MOVSX (move sign extended) es una instrucción que mueve desde una fuente más pequeña a un destino más grande y el espacio sobrante lo rellena con el bit de signo de la fuente
sintaxis
movsx registro_destino, origen
ejemplo
movsx eax, byte ptr [memoria] ; mueve el byte almacenado en la dirección de memoria indicada a EAX y lo extiende a 32 bits
movsx ebx, word ptr [memoria] ; mueve la palabra almacenada en la dirección de memoria indicada a EBX y lo extiende a 32 bits
movsx edx, al ; extiende el valor del registro AL (8 bits) a 32 bits y lo mueve a EDX
MOVZX
La instrucción MOVZX (move zero extended) es una instrucción que mueve desde una fuente más pequeña (la cual puede ser un Word o byte) a un destino más grande y el espacio sobrante lo rellena con ceros
sintaxis
movzx registro_destino, origen
ejemplo
movzx eax, byte ptr [memoria] ; mueve el byte almacenado en la dirección de memoria indicada a EAX y lo extiende a 32 bits con ceros movzx ebx, word ptr [memoria] ; mueve la palabra almacenada en la dirección de memoria indicada a EBX y lo extiende a 32 bits con ceros movzx edx, al ; extiende el valor del registro AL (8 bits) a 32 bits con ceros y lo mueve a EDX
Instrucciones de movimiento condicional
Las instrucciones de movimiento condicional son instrucciones que verifican las banderas de estado o flags antes de mover en caso de que la condición necesaria para el movimiento no se cumpla es decir las banderas que esta verifica no están seteadas el movimiento no se realizará
instrucciones de comparación
las instrucciones de comparación realizan la comparación de dos operandos sin modificar ninguno de ellos, pero actualizando las banderas de estado dependiendo del resultado de la comparación entre las instrucciones de comparación tenemos TEST y CMP
TEST
La instrucción test realiza la operación AND entre el primer y segundo operando sin alterar ninguno, pero modificando las banderas de estado dependiendo del resultado de la operación AND
sintaxis
test destino, origen
ejemplo
test eax, ebx ; realiza la operación AND lógica entre EAX y EBX y establece las banderas según el resultado test al, 0xFF ; realiza la operación AND lógica entre el registro AL y el valor hexadecimal 0xFF, estableciendo las banderas según el resultado test [memoria], 0x10 ; realiza la operación AND lógica entre el valor almacenado en la dirección de memoria indicada y el valor hexadecimal 0x10, estableciendo las banderas según el resultado
CMP
La instrucción CMP (Compare) realiza una resta entre el primer y segundo operando (operando1-operando2) actualiza las banderas de estado y no modifica ninguno de los operandos
sintaxis
cmp operando1, operando2
ejemplo
cmp eax, ebx ; compara los valores de los registros EAX y EBX y establece las banderas según el resultado cmp al, 0xFF ; compara el valor del registro AL con el valor hexadecimal 0xFF y establece las banderas según el resultado cmp [memoria], ebx ; compara el valor almacenado en la dirección de memoria indicada con el valor del registro EBX y establece las banderas según el resultado
instrucciones aritméticas
las instrucciones aritméticas como su nombre lo indica nos permiten realizar operaciones aritméticas tales como la suma, resta, multiplicación o división
ADD
La instrucción ADD suma el operando fuente más el operando de destino y el resultado de la suma queda almacenado en el operando de destino
sintaxis
add destino, origen
ejemplo
add eax, ebx ; suma el valor del registro EBX al valor del registro EAX y almacena el resultado en EAX add [memoria], eax ; suma el valor del registro EAX al valor almacenado en la dirección de memoria indicada y almacena el resultado en esa dirección de memoria add al, 0x10 ; suma el valor hexadecimal 0x10 al valor del registro AL y almacena el resultado en AL
SUB
La instrucción SUB le resta al operando de destino la fuente (destino-fuente) y el resultado de la resta es almacenado en el operando de destino
sintaxis
sub destino, origen
ejemplo
sub eax, ebx ; resta el valor del registro EBX del valor del registro EAX y almacena el resultado en EAX sub [memoria], eax ; resta el valor del registro EAX del valor almacenado en la dirección de memoria indicada y almacena el resultado en esa dirección de memoria sub al, 0x10 ; resta el valor hexadecimal 0x10 del valor del registro AL y almacena el resultado en AL
MUL
Esta instrucción realiza la multiplicación sin signo del operando con el registro RAX y el resultado de la multiplicación es almacenado en RDX:RAX (la parte alta en RDX y la parte baja en RAX)
sintaxis
mul operando
ejemplo
mul eax ; multiplica el valor del registro EAX por el valor del registro EAX y almacena los 32 bits más significativos del resultado en EDX y los 32 bits menos significativos en EAX mul ebx ; multiplica el valor del registro EBX por el valor del registro EAX y almacena los 32 bits más significativos del resultado en EDX y los 32 bits menos significativos en EAX mul dword [memoria] ; multiplica el valor almacenado en la dirección de memoria indicada por el valor del registro EAX y almacena los 32 bits más significativos del resultado en EDX y los 32 bits menos significativos en EAX
IMUL
La instrucción IMUL realiza la multiplicación de números con signo y esta puede tener uno dos o tres operandos cuando esta tiene un operando se comporta similar a MUL pero en este caso multiplicando con signo el registro RAX por el operando y el resultado se almacena en el registro RDX:RAX. Con dos operandos multiplica la fuente por el destino y el resultado se almacena en la fuente. Con tres operandos multiplica el segundo operando con el tercer operando el cual debe ser una constante y el resultado lo almacena en el primer operando
imul eax, ebx ; multiplica el valor del registro EBX por el valor del registro EAX y almacena el resultado en EAX imul ecx, dword [memoria] ; multiplica el valor almacenado en la dirección de memoria indicada por el valor del registro ECX y almacena el resultado en ECX imul rax, rbx ; multiplica el valor del registro RBX por el valor del registro RAX y almacena el resultado en RAX
DIV
Esta instrucción realiza la división de números sin signo de los registros RDX:RAX (dividendo) entre el operando (divisor), el resultado es almacenado en el registro RAX y el residuo en el registro RDX
sintaxis
div operando
ejemplo
div ebx ; divide el valor del registro EDX:EAX (valor de 64 bits) por el valor del registro EBX y almacena el cociente en EAX y el resto en EDX div dword [memoria] ; divide el valor almacenado en la dirección de memoria indicada por el valor del registro EAX y almacena el cociente en EAX y el resto en EDX
IDIV
Esta instrucción realiza la división con signo de los registros RDX:RAX (dividendo) entre el operando (divisor), el resultado es almacenado en el registro RAX y el residuo en el registro RDX
sintaxis
idiv operando
ejemplo
idiv ebx ; divide el valor del registro EDX:EAX (valor de 64 bits) por el valor del registro EBX y almacena el cociente en EAX y el resto en EDX idiv dword [memoria] ; divide el valor almacenado en la dirección de memoria indicada por el valor del registro EAX y almacena el cociente en EAX y el resto en EDX
instrucciones de control de flujo
estas instrucciones nos permiten alterar el flujo del programa entre estas instrucciones tenemos las instrucciones de salto incondicional y salto condicional
instrucciones de salto incondicional
JMP
La instrucción JMP salta a la dirección de memoria especificada por el operando incondicionalmente es decir salta sin tener en cuenta las banderas o FLAGS
sintaxis
jmp destino
ejemplo
etiqueta: ; instrucciones jmp etiqueta ; salta de vuelta a la etiqueta ; más instrucciones
Instrucciones de salto condicional
Las instrucciones de salto condicional verifican determinadas banderas y si la condición se satisface es decir las banderas que chequea están seteadas salta a la dirección indicada por el operando, en caso contrario (la condición no se satisface) la instrucción no salta
instrucciones de llamada y retorno
las instrucciones de llamada y retorno nos permiten entrar y retornar de las funciones
CALL
La instrucción CALL salta a la dirección apuntada por el operando, pero antes coloca en el stack la dirección de retorno es decir la dirección siguiente a donde fue ejecutada
sintaxis
call subrutina
ejemplo
subrutina:
; instrucciones
ret ; retorna de la subrutina
call subrutina ; llama a la subrutina indicada y salta a la dirección de memoria donde comienza la subrutina
RET
La instrucción RET saltará a la dirección de retorno es decir la dirección colocada en el stack por la instrucción CALL
sintaxis
ret
ejemplo
subrutina:
; instrucciones
ret ; retorna de la subrutina
call subrutina ; llama a la subrutina indicada y salta a la dirección de memoria donde comienza la subrutina
instrucciones de manejo de pila
las instrucciones de manejo de pila nos permiten colocar y retirar valores de la pila o stack
PUSH
La instrucción PUSH coloca valores en el stack
sintaxis
push operando
ejemplo
push eax ; coloca el valor del registro eax en la pila push 10 ; coloca el valor 10 en la pila push dword [memoria] ; coloca el valor almacenado en la dirección de memoria "memoria" en la pila
POP
La instrucción POP retira valores del stack
sintaxis
pop destino
ejemplo
pop eax ; saca el valor de la cima de la pila y lo coloca en el registro eax pop dword [memoria] ; saca el valor de la cima de la pila y lo coloca en la dirección de memoria "memoria"
instrucciones lógicas
Las instrucciones Lógicas nos permiten realizar operaciones lógicas entre las cuales tenemos AND, OR, NOT, XOR
AND
La instrucción AND nos permite realizar la operación lógica AND entre el operando destino y fuente y el resultado de esta operación es almacenado en el operando de destino
sintaxis
and destino, origen
ejemplo
and eax, ebx ; realiza la operación lógica "AND" entre los valores de los registros eax y ebx, y almacena el resultado en eax and dword [memoria], 0xFF ; realiza la operación lógica "AND" entre el valor almacenado en la dirección de memoria "memoria" y la constante 0xFF, y almacena el resultado en la misma dirección de memoria
OR
La instrucción OR nos permite realizar la operación lógica OR entre el operando destino y fuente y el resultado de esta operación es almacenado en el operando de destino
sintaxis
or destino, origen
ejemplo
or eax, ebx ; realiza la operación lógica "OR" entre los valores de los registros eax y ebx, y almacena el resultado en eax or dword [memoria], 0x7F ; realiza la operación lógica "OR" entre el valor almacenado en la dirección de memoria "memoria" y la constante 0x7F, y almacena el resultado en la misma dirección de memoria
NOT
Esta instrucción realiza la negación del operando
sintaxis
not destino
ejemplo
not eax ; realiza la operación lógica "NOT" en el valor del registro eax, y almacena el resultado en eax not byte [memoria] ; realiza la operación lógica "NOT" en el valor almacenado en la dirección de memoria "memoria", y almacena el resultado en la misma dirección de memoria
XOR
La instrucción XOR nos permite realizar la operación lógica XOR entre el operando destino y fuente y el resultado de esta operación es almacenado en el operando de destino. Un uso frecuente de esta operación es colocar un registro a cero.
sintaxis
xor destino, origen
ejemplo
xor eax, eax ; coloca el registro eax a cero
xor eax, ebx ; realiza la operación lógica "XOR" entre los valores de los registros eax y ebx, y almacena el resultado en eax
xor byte [memoria], 0xff ; realiza la operación lógica "XOR" entre el valor almacenado en la dirección de memoria "memoria" y el valor 0xff, y almacena el resultado en la misma dirección de memoria
instrucciones de desplazamiento de bits
Las instrucciones de desplazamiento de bits como su nombre lo indica son utilizadas para desplazar bits, un uso muy frecuente es para manejar valores de campos de bits o para multiplicar o dividir entre potencias de 2
SHL y SAL
Las instrucciones SHL (Shift logical Left) y SAL (Shift artitmenical Left) desplazan os bits hacia la izquierda el número de veces indicado por la fuente, rellenando los nuevos lugares con ceros
sintaxis
shl destino, fuente
sal destino, fuente
ejemplo
mov eax, 0x00000001 ; mueve el valor hexadecimal 0x00000001 al registro eax shl eax, 1 ; desplaza los bits en eax un bit a la izquierda mov ebx, 0xffff0000 ; mueve el valor hexadecimal 0xffff0000 al registro ebx sal ebx, 4 ; desplaza los bits en ebx cuatro bits a la izquierda, realizando un desplazamiento aritmético
desplazar hacia la izquierda equivale a multiplicar por una potencia de dos
SHR
La instrucción SHR (Shift logical Right) desplaza los bits hacia la derecha el número de veces indicado por la fuente, rellenando los nuevos lugares con ceros
sintaxis
shr destino, fuente
ejemplo
mov eax, 0x12345678 ; coloca el valor 0x12345678 en eax shr eax, 4 ; desplaza 4 bits a la derecha
SAR
La instrucción SAR (Shift Aritmetical Right) desplaza los bits hacia la derecha el número de veces indicado por la fuente y rellena los nuevos lugares con el bit de signo que tenía el destino
sintaxis
sar destino, fuente
ejemplo
mov eax, 0xFFFF0000 ; coloca el valor 0xFFFF0000 en eax
sar eax, 16 ; desplaza 16 bits a la derecha
desplazar hacia la derecha equivale a dividir entre una potencia de dos
ROR y ROL
Las instrucciones ROR (Rotate right) y ROL (Rotate left) realizan una rotación de bits a la derecha e izquierda respectivamente
sintaxis
ror destino, fuente
rol destino, fuente
ejemplo
mov eax, 0x0F0F0F0F ; coloca el valor 0x0F0F0F0F en eax ror eax, 8 ; rota los bits de eax 8 posiciones a la derecha mov eax, 0x0F0F0F0F ; coloca el valor 0x0F0F0F0F en eax rol eax, 8 ; rota los bits de eax 8 posiciones a la izquierda
Sean todos bienvenidos una vez más a este espacio, en esta ocasión estaremos explorando LangChain y estaremos viendo algunos conceptos y un ejemplo practico de su uso
¿Qué es LangChain?
LangChain es un open source framework para construir aplicaciones con LLM (Large languge models), esta permite enlazar LLM con otras fuentes de datos y permite al Modelo interactuar con su entorno
Ventajas de usar LangChain
LangChain ofrece varios componentes tales como, prompt template, models, chains, indexes, agents, que permiten generar aplicaciones mas complejas con LLM de una manera más fácil a continuación conoceremos algunos de estos componentes.
Models
Los modelos nos permiten conectar con Modelos como por ejemplo GPT4. hay dos tipos de modelos los cuales son Language models (Modelos de lenguaje) y Text Embedding Models
Language models (Modelos de lenguaje)
Los modelos de lenguaje nos permiten interactuar con modelos de lenguaje, así como su nombre indica, estos están subdivididos en dos subtipos LLM los cuales toman texto y retornan texto y ChatModels los cuales toman mensajes de chat y retornan mensajes de chat
Text Embedding Models
Esta clase de modelos toma texto como entrada y retorna un Embedding, la cual es una representación numérica de dicho texto
Prompts
Prompt se refiere al texto o a la entrada de nuestro modelo LangChain esta entrada puede ser construida por varios componentes LangChain ofrece PromptTemplate que son los responsables de construir las prompt estos permiten entre otras cosas crear prompts con determinado formato
from langchain.prompts import PromptTemplate, ChatPromptTemplate
string_prompt = PromptTemplate.from_template("tell me a joke about {subject}")
chat_prompt = ChatPromptTemplate.from_template("tell me a joke about {subject}")
string_prompt_value = string_prompt.format_prompt(subject="soccer")
chat_prompt_value = chat_prompt.format_prompt(subject="soccer")
Indexes
El uso más común que se le da a los indexes es extraer información relevante para los LLM los principales indexes están centrados alrededor de vector databases. LangChain cuenta con funcionalidades tales como Document loaders que permiten la carga de documentos, Text splitters que permiten dividir estos documentos en trozos más pequeños, vector stores el cual almacena documentos y sus embeddings asociados y retrievers que obtienen información relevante la cual puede ser combinada con LLM
Chains
Las cadenas nos permiten combinar múltiples componentes para crear aplicaciones. Tenemos cadenas que nos permiten por ejemplo responder preguntas, hacer resúmenes entre otras además podemos crear nuestras propias cadenas
Agents
Los agentes permiten a los LLM interactuar con su entorno por ejemplo podemos crear un agente que le permita al modelo realizar búsquedas por internet
Ejemplo de uso LangChain
A continuación, vamos a hacer un ejemplo de cómo podemos utilizar LangChain de manera práctica, lo que estaremos haciendo es tomar un documento PDF el cual va a ser la fuente de conocimientos externa, y procederemos a hacer preguntas a la IA y le estaremos pasando el documento como contexto
explicación de nuestro Código
El primer paso es importar todas las librerías necesarias
# -*- coding: utf-8 -*-
from transformers import GPT2TokenizerFast
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS
from langchain.chains.question_answering import load_qa_chain
from langchain.llms import OpenAI
import textract
Luego de importar las librerías tomamos nuestro PDF y le extraemos el texto con la función process
# convertimos el pdf a texto
doc = textract.process(r'C:\Users\HP\Desktop\chat_GPT\datos\Virus_Informaticos.pdf')
para que esta función funcione correctamente en nuestro Windows debemos tener instalado poppler y la ruta del mismo agregado al Path.
Lo siguiente que hacemos es guardar el texto que extraemos del PDF en un documento de texto y lo leemos
# guardamos el texto y reabrimos
with open('texto.txt', 'w', encoding="utf-8") as f:
f.write(doc.decode('utf-8'))
with open('texto.txt', 'r', encoding="utf-8") as f:
text = f.read()
luego creamos una función para contar los tokens esta función la pasaremos como argumento a nuestro text splitter que será el encargado de dividir nuestro texto en trozos
# creamos una funcion para contar los tokens
tokenizer = GPT2TokenizerFast.from_pretrained("gpt2")
def count_tokens(text: str) -> int:
return len(tokenizer.encode(text))
después de esto creamos nuestra base de datos de vectores, para hacer esto primero obtenemos nuestro modelo para crear los embeddings y creamos la base de datos pasándole los chunks y el modelo de embedding a FAISS.from_documents
# obtenemos el embedding model
embeddings = OpenAIEmbeddings()
# creamos la database de vectores
db = FAISS.from_documents(chunks, embeddings)
luego de esto lo que hacemos es pedirle al usuario que realice una pregunta y obtenemos los fragmentos relacionados con la pregunta que hizo el usuario gracias a un similarity search
# realizamos la busqueda por similaridad
query = input("realiza tu pregunta: ")
docs = db.similarity_search(query)
por último, creamos nuestra cadena Question answering que nos permite hacer preguntas y obtener respuestas, esta cadena la obtenemos con la función load_qa_chain que recibe como argumentos el modelo y el tipo de cadena, en este caso el tipo de cadena es stuff, este tipo de cadenas se recibe nuestros docs obtenidos con el similarity search como contexto
# creamos un QA chain que nos permite hacer preguntas en base a nuestros documentos
chain = load_qa_chain(OpenAI(temperature=0), chain_type="stuff")
print(chain.run(input_documents=docs, question=query))
al ejecutar nuestro código podemos ver la respuesta que nos da el modelo
Esta información es basada en nuestro documento PDF
Conclusión
Hemos visto como usar LangChain y lo poderoso que es este framework, LangChain tiene funcionalidades ya definidas y la posibilidad de implementar o agregarle nuevas funcionalidades lo que lo hace ideal para crear aplicaciones con LLM
Debugging o depuración es el proceso de encontrar bugs o errores en el programa, en este identificamos y aislamos las causas del error. Este puede llevase a cabo de diferentes maneras entre las cuales tenemos software testing, revisión del código o mediante herramientas como debuggers
¿Qué es un debugger?
Un debugger es una herramienta que nos permite depurar un programa en estos podemos ver instrucción por instrucción, alterar el flujo de ejecución, ver los valores de las distintas variables y editarlos, colocar puntos de interrupción o breakpoints. Los depuradores nos permiten ver cómo se comporta el programa mientras es ejecutado
Conociendo las partes de un debugger
En esta parte procederemos a conocer las diferentes partes que puede tener un debugger tomando como ejemplo un debugger muy utilizado llamado x64dbg, el objetivo de esta parte es familiarizarse no solo con este depurador sino entender las diferentes partes para tener un conocimiento general que nos puede servir para cualquier depurador. Algo a tener en cuenta es que algunas de las cosas incluidas en un depurador quizás no estén incluidas en otro, pero hay elementos que son comunes de depurador a depurador
Este es nuestro depurador, lo primero que haremos será cargar un archivo ejecutable para depurarlo, para hacer esto presionamos archivo->abrir
Entre las otras opciones que tenemos están vincular que nos permite depurar un proceso que se encuentra corriendo actualmente, cambiar el comando empleado que nos permite pasarle argumentos al proceso
Una vez cargado nuestro programa en el depurador este para por defecto en el breakpoint del sistema y nos rellenara las diferentes partes con distinta información que procederemos a aclararlos a continuación
Desensamblado
En esta parte se nos muestra el código ensamblador de nuestro ejecutable, en esta parte podemos ver las instrucciones que el programa va ejecutando, podemos colocar breakpoints en la dirección que queramos y también podemos alterar el flujo de ejecución del mismo
Registros
En esta parte podemos ver y modificar los valores de los diferentes registros incluyendo las banderas de estado
Variables Locales
En esta parte nos muestra las variables locales de la función que estamos depurando actualmente y también nos da la opción de seleccionar la convención de llamada de la función
Aclaraciones
En esta parte se nos mostraran aclaraciones como por ejemplo el contenido de un puntero
Volcado de memoria
En esta parte tenemos el volcado de memoria es decir el contenido de la memoria, esta parte la usamos cuando queremos ver el contenido de cierta zona de memoria
Stack
En esta parte tenemos el contenido del stack, que como sabemos es la zona destinada para guardar nuestras variables locales, argumentos, registros salvados entre otra información
En la pestaña breakpoints tenemos todos los breakpoints o puntos de interrupción que hemos colocado, por defecto el depurador nos coloca un breakpoint en el entry point del programa y nos aclara que parará una sola vez
En la pestaña mapa de memoria podemos ver las diferentes secciones del ejecutable, su dirección de inicio y final, así como también las secciones de las diferentes dlls, memoria reservada dinámicamente y los permisos de estas
En la pestaña pila de llamadas tenemos la pila de llamadas es decir las funciones que han sido llamadas para llegar a la función actual, de primero tenemos la función actual y bajando tenemos los callers
Una vez familiarizados con el debugger procederemos a aprender a como depurar nuestros programas, para esto debemos aprender a como tracear, también debemos aprender a colocar puntos de interrupción y los diferentes puntos de interrupción que tenemos a nuestra disposición, además debemos aprender a buscar referencias y otra información que nos puede ser de utilidad.
Con el objetivo de ilustrar esto procederemos a realizar el análisis del crackme de cruehead, en este articulo no veremos la solución del mismo solo lo tomaremos como ejemplo para aprender a usar nuestro depurador
El primer paso será abrir nuestro crackme en el depurador y una vez abierto nos parará por defecto en el breakpoint del sistema
si queremos cambiar este comportamiento lo podemos hacer en opciones->preferencias y en la pestaña eventos podemos seleccionar solamente el breakpoint en el punto de entrada o entry point, esto hará que el programa pare en el entry point
Resaltado en la imagen superior tenemos los comandos que nos permiten, reiniciar el programa, detenerlo, correrlo, pausarlo y tracearlo, procederemos a explicar cada uno a continuación
Reiniciar
Reinicia el proceso que está siendo depurado actualmente
Detener
Detiene el proceso que está siendo depurado actualmente
Ejecutar
Ejecuta el programa hasta que este finaliza o encuentra un breakpoint
Pausar
Pausa la ejecución del programa
Step into
Ejecuta la instrucción entrando a cada uno de los calls
Step over
Ejecuta la instrucción sin entrar a los calls, los calls se ejecutan por completo, pero no se muestra el código dentro de estos
Trace Into y Trace Over
Inicializar el traceado que lo que hace es ejecutar las instrucciones recordándolas y se detiene cuando se cumple determinada condición
Ejecutar hasta el retorno
Ejecuta el contenido de la función actual hasta que llega al fin de esta (el retorno)
Ejecutar hasta el código de usuario
Ejecuta todo el código del sistema y se detiene cuando llega nuevamente al código de usuario
Breakpoints
Los breakpoints o puntos de interrupción los utilizamos cuando queremos parar en determinada instrucción o código que nos interesa, existen varios tipos de breakpoints como lo son de memoria, de hardware y software
Memory Breakpoints
Los breakpoints de memoria nos permiten detener la ejecución del programa cuando se accede a determinada zona de memoria estos pueden parar en acceso ya sea para lectura o escritura, solo en lectura, solo en escritura o en ejecución
Hardware Breakpoints
Los hardware breakpoints son llevados a cabo mediante registros de depuración en el procesador podemos colocar un máximo de 4 breakpoints de este tipo y las condiciones de estos pueden ser de en acceso, en lectura, escritura o ejecución
Software Breakpoints
Este tipo de breakpoint lo colocamos cuando queremos parar en determinada instrucción, cuando colocamos este tipo de breakpoint el depurador cambia la instrucción por un int3 que hace que el programa se detenga ahí pero estos pueden llegar a ser detectados por el programa fácilmente, los breakpoints de software paran en ejecución pero x64dbg soporta breakpoints por software condicionales un ejemplo de esto puede ser parar si determinado registro tiene determinado valor como por ejemplo eax==0x1234
Retomando a el ejemplo del crackme lo primero que hacemos será correr el mismo en el debugger e intentar buscar referencias a cadenas que puedan ser de nuestro interés o también podemos parar en el momento en que se lee nuestro username y serial
Una vez abierto presionamos register
nos abre esta ventanita que nos pide nombre de usuario y serial coloquemos username y 12345
Nos abre esta ventanita que nos indica que fue invalido, tratemos de ver si encontramos referencias a esta string en el debugger y analizar el código en busca de la comparación que decide cuando mostrar o no esta ventanita
Presionamos en el área del desensamblado clic derecho buscar en->módulo actual->referencias a cadena
Vemos que tuvimos suerte y encontramos dos referencias a la cadena “no luck there, mate!” coloquemos un breakpoint en ambas direcciones
Ahí colocamos nuestros breakpoints en las dos referencias, y nos damos cuenta que en una de las referencias esta muy cerca una referencia a la cadena que puede ser nuestro chico bueno, nos ayudamos con un plugin llamado xAnalyzer, una vez instalado el plugin de a cuerdo a las instrucciones de github
Damos clic derecho xAnalyzer analyze module
Este plugin hace un gran trabajo resaltándonos el inicio de las funciones ciclos y demás, vemos que nuestra referencia a nuestra string “no luck there, mate!” es usada por un mensaje box en una función que empieza en 0x401362 y si nos fijamos en la otra referencia
Está dentro de otra función que empieza en 0x40137e esta función hace determinadas comparaciones y ciclos y si no le gusta nos manda al chico malo, ahora busquemos referencias a el código que llama a estas funciones, lo primero que haremos es en el inicio de cada una de estas funciones (me refiero a las funciones que llaman a nuestra cadena)
Posicionados en la dirección que queremos encontrar referencias damos clic derecho->encontrar referencias a-> dirección seleccionada
Nos dirigimos a la dirección y colocamos un breakpoint
Una vez hecho esto con las dos referencias reiniciamos nuestro programa
Colocamos un username y un serial y al dar ok se detiene en nuestro breakpoint
Una vez detenidos podemos ver que va a pasar nuestro username y nuestro serial a dos funciones, la función en la que le pasa el username es la función que realizaba unas comparaciones y bucles y si algo no le gustaba nos mostraba el mensaje de chico malo, al salir de estas funciones en la dirección 0x401241 realiza una comparación que si eax es igual a ebx llama a la función 0x40134d que si nos fijamos cual es
Nos damos cuenta que es la función que nos manda el cartel de felicitaciones, así que lo que haremos es forzar el salto para que siempre nos mande al cartel de felicitaciones a esto se le conoce como parchear
Posicionados sobre el salto decisivo damos clic derecho->ensamblar o presionamos espacio
Cambiaremos el je (salta si es igual) por un jmp (salta siempre)
Nos quedará así ahora presionamos aceptar, ahora para que los cambios se guarden presionamos clic derecho->parches
En la ventana que se nos abre le damos a aplicar el parche
Nos abrirá el explorador de archivos
Guardamos la versión modificada con un nombre cualquiera y procedemos a probarla
Abrimos la versión modificada y colocamos un username y serial cualquiera
Y vemos que al presionar ok ¡nos muestra el mensaje de felicitaciones!
Esto concluye nuestro articulo de hoy en el cual en el nos familiarizamos con el depurador y hemos aprendido como depurar un programa e incluso a modificarlo
Bienvenidos una vez mas a este espacio, en esta ocasión estaremos creando un Bot de telegram al cual le estaremos integrando chatgpt.
Este será un sencillo ejemplo de cómo integrar el api de OpenAI con el api de Telegram
Como primer paso debemos crear un api key de OpenAI para poder interactuar con la misma, para hacer esto nos dirigimos a https://platform.openai.com/account/api-keys y creamos nuestra key presionando el botón
Le asignamos un nombre y presionamos créate secret key
Una vez presionado el botón OpenAI nos advierte que debemos guardar la key en un lugar seguro y por razones de seguridad no seremos capaces de ver la key nuevamente así que debemos copiar la key y guardarla tal como nos recomienda OpenAI
Una vez creada nuestra key de OpenAI nos dirigimos a Bot Father y creamos nuestro Bot siguiendo las instrucciones y guardamos el token de nuestro Bot
Una vez hecho esto ya estamos listos para empezar con nuestro Bot
Lo primero que debemos hacer es importar los módulos necesarios para nuestro código
el modulo json lo utilizamos para leer el contenido del archivo de configuración, el modulo aiogram es utilizado para interactuar con el api de Telegram y el modulo openai es utilizado para interactuar con el api de OpenAI
yo he creado un archivo de configuración json en el cual almaceno la key de OpenAI y el token de nuestro Bot, esto puede hacerse de esta forma o también puede hacerse almacenando las keys en variables de entorno
Lo siguiente que debemos hacer es leer nuestras keys del archivo de configuración json esto lo hacemos abriendo nuestro archivo con open y json.load() y almacenamos nuestras keys en las variables telegram_token y opeanai_key
# leemos las keys
with open("config.json") as cfg:
data=json.load(cfg)
telegram_token=data["telegram_token"]
openai_key=data["openai_key"]
lo siguiente que hacemos es asignar nuestra key de OpenAI y creamos la instancia del Bot
# Asignamos la key OpenAi
openai.api_key= openai_key
# Creamos La instancia del bot
bot=Bot(token=telegram_token)
Lo siguiente es instanciar nuestro dispatcher el cual es un componente de la biblioteca aiogram que es utilizado para manejar y enrutar mensajes entrantes en un Bot de Telegram. este recibe los mensajes y los dirige a las funciones de manejo adecuadas para su procesamiento.
El dispatcher se encarga de registrar y administrar los controladores de mensajes para diferentes tipos de eventos, tales como mensajes de texto, comandos, actualizaciones de chat entre otros. Puede asociar funciones especificas a estos eventos y ejecutarlas cuando se produzcan
Algunas funciones importantes del Dispatcher incluyen:
register_message_handler(): Permite registrar una función para manejar mensajes de texto entrantes. Se puede especificar opcionalmente una condición para filtrar los mensajes basados en su contenido o atributos.
register_callback_query_handler(): Permite registrar una función para manejar consultas de botones en línea. Estas consultas se generan cuando un usuario interactúa con un botón en línea adjunto a un mensaje.
register_inline_handler(): Permite registrar una función para manejar consultas en línea. Estas consultas se generan cuando un usuario escribe el nombre del Bot seguido de un comando o consulta especial en el campo de entrada de un chat.
register_errors_handler(): Permite registrar una función para manejar errores que ocurren durante la ejecución del Bot. Esto puede ser útil para manejar excepciones y tomar medidas adecuadas en caso de errores.
En este caso nosotros estaremos usando el decorador message_handler para asociar funciones a mensajes.
@disp.message_handler(commands=["start", "help"])
async def bienvenido(message: types.Message):
await message.reply("bienvenido a este bot, preguntame lo que quieras!")
lo que hemos hecho en el código de arriba es crear una función decorada llamada bienvenido la cual se ejecutará cuando se reciba un mensaje que contenga alguno de los comandos especificados en la lista (start o help), esta responderá con el mensaje “bienvenido a este Bot, preguntame lo que quieras!»
Luego creamos otra función la cual manejara cualquier otro mensaje que no sea un comando
esta función utiliza el api de OpenAI para generar una respuesta al mensaje recibido utilizando el modelo text-davinci-003 la respuesta generada se envía como respuesta al mensaje enviado
por último, iniciamos nuestro dispatcher con executor.start_polling(disp)
if __name__ == "__main__":
executor.start_polling(disp)
al ejecutar nuestro código e interactuar con nuestro Bot de telegram
Vemos que nuestro Bot interactúa con nosotros correctamente
Conclusión
En esta ocasión hemos aprendido como crear nuestros bots de telegram y como interactuar con ellos utilizando el api de OpenAI, también hemos visto como utilizar aiogram para crear nuestros bots de una forma más fácil
Una base de datos accesible públicamente perteneciente a DeepSeek permitió el control total sobre las operaciones de la base de datos, incluyendo el acceso a datos internos. La exposición incluyó más de un millón de registros con información altamente sensible.
31 de enero de 2025 Lectura de 3 minutos
Wiz Research ha identificado una base de datos ClickHouse expuesta
El equipo de Wiz Research identificó una base de datos ClickHouse de DeepSeek accesible públicamente, lo que permitía el control total sobre las operaciones de la base de datos y el acceso a datos internos.
La exposición incluía más de un millón de registros, con información como historial de chats, claves secretas, detalles del backend y otros datos altamente sensibles.
Tras descubrir el problema, el equipo de Wiz Research notificó de inmediato a DeepSeek, que procedió a asegurar la base de datos rápidamente.
En esta publicación, detallaremos nuestro descubrimiento y analizaremos las implicaciones para la industria.
Resumen ejecutivo
DeepSeek, una startup china de inteligencia artificial, ha ganado atención en los medios gracias a sus innovadores modelos de IA, en particular el modelo de razonamiento DeepSeek-R1. Este modelo rivaliza con OpenAI o1 en rendimiento, destacando por su eficiencia y menor costo.
Dado el crecimiento de DeepSeek en la industria de la IA, el equipo de Wiz Research decidió evaluar su postura de seguridad externa.
Hallazgo clave: En pocos minutos, identificamos una base de datos ClickHouse completamente abierta y sin autenticación, accesible en:
oauth2callback.deepseek.com:9000
dev.deepseek.com:9000
Datos expuestos:
Historial de chats
Datos internos del backend
Claves API
Registros operativos
Riesgo crítico: La base de datos permitía acceso sin autenticación, lo que facilitaba el control total sobre los datos y la posibilidad de escalamiento de privilegios dentro del entorno de DeepSeek.
Análisis detallado de la exposición
El equipo de Wiz Research comenzó su evaluación con un mapeo de los dominios públicos de DeepSeek, identificando alrededor de 30 subdominios expuestos.
Sin embargo, al explorar puertos más allá de los estándares HTTP (80/443), encontramos puertos abiertos inusuales (8123 y 9000) en los siguientes hosts:
http://oauth2callback.deepseek.com:8123
http://dev.deepseek.com:8123
http://oauth2callback.deepseek.com:9000
http://dev.deepseek.com:9000
Resultado: Estos puertos llevaban a una base de datos ClickHouse accesible sin autenticación, lo que planteaba un grave riesgo de seguridad.
Método de acceso: Aprovechando la interfaz HTTP de ClickHouse, accedimos a la ruta /play, lo que permitía ejecutar consultas SQL directamente desde un navegador.
Con una simple consulta SHOW TABLES;, obtuvimos una lista completa de bases de datos disponibles.
Datos expuestos en la tabla «log_stream»
Entre todas las bases de datos, una en particular llamó la atención: log_stream, que contenía más de un millón de registros sensibles.
Columnas clave:
timestamp: Registros desde el 6 de enero de 2025.
span_name: Referencias a los endpoints internos de la API de DeepSeek.
string.values: Registros en texto plano, incluyendo historial de chats, claves API y metadatos operativos.
_service: Indica qué servicio de DeepSeek generó los registros.
_source: Expone el origen de las solicitudes, revelando historial de chats, claves API, estructuras de directorios y metadatos del chatbot.
Riesgo crítico:
Un atacante podía extraer mensajes de chat en texto plano.
Posible exfiltración de contraseñas y archivos locales mediante consultas avanzadas como SELECT * FROM file('filename'), dependiendo de la configuración de ClickHouse.
Nota: No ejecutamos consultas intrusivas más allá de la enumeración inicial para mantener prácticas de investigación ética.
Lecciones clave y riesgos para la industria
La rápida adopción de IA sin medidas de seguridad adecuadas es un riesgo creciente. Este incidente demuestra que los mayores peligros en seguridad de IA provienen de exposiciones accidentales, no necesariamente de amenazas avanzadas.
Riesgos clave:
Muchas startups de IA priorizan la innovación sin proteger adecuadamente sus infraestructuras.
Bases de datos expuestas pueden revelar información confidencial sin necesidad de un ataque sofisticado.
Las medidas de seguridad en IA deben fortalecerse de inmediato.
Recomendaciones:
Implementar autenticación en todas las bases de datos accesibles en línea.
Auditar regularmente la seguridad de la infraestructura.
Involucrar equipos de seguridad en el desarrollo de IA para evitar exposiciones accidentales.
Conclusión
La inteligencia artificial está creciendo a un ritmo sin precedentes, pero la seguridad no ha seguido el mismo ritmo.
El caso de DeepSeek demuestra que muchas startups de IA han evolucionado sin implementar protocolos de seguridad adecuados.
La industria debe adoptar medidas de seguridad tan estrictas como las aplicadas en servicios de computación en la nube.