Etiquetas

C (31) Cpp (28) Linux (14) asm (8) Telegram (5) bot (5) libreria (5) Algoritmo (3) Errores comunes (3) python (3) Opengl (2) kali (2) Android (1) Snippet (1) nano (1) recursividad (1)

domingo, 21 de junio de 2026

[C]Bruteforce Recursivo vs Iterativo


/*Me encontré este post en elhacker y lo comparto con uds... no es de mi autoría Hay casos en que es más conveniente usar la recursividad para solucionar un problema. Hay que cambiar system("PAUSE") y los scanf"*/

//////////////////////////////////////
/*BruteForce Iterativo en Lenguaje C*/
//////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]){
int contadores[50]={0}, len=0, cant=0, i=0;
char caracteres[200]={0}, pass[50]={0};
printf ("Ingrese los caracteres a usar para la contrasena: \n");
scanf ("%s", caracteres);
printf ("Ingrese la longitud de la contraseña: \n");
scanf ("%i", &len);
cant = strlen (caracteres);
/*contadores = (int *) malloc (sizeof (int) * (len+1) );
pass = (char *) malloc (len+1);*/
for (i=0 ; i<len;i++){
pass[i] = caracteres[0];contadores[i] = 0;}
contadores[i] = 0;pass [i] = '\0';
while (!contadores[len]){
printf ("%s\n", pass);
for (i=0;contadores[i]==cant-1;i++)
pass[i] = caracteres [contadores[i] = 0];
pass[i] = caracteres [++contadores[i]];}
/*free (contadores);free (pass);*/
system("PAUSE");return 0;} //end of main
vs Recursivo

//////////////////////////////////////
/*BruteForce Recursivo en Lenguaje C
*///////////////////////////////////////
#include <stdio.h>
#include <string.h>
void brute_force (char caracteres[], int cant, int pos, char *password){
if(pos==-1){printf ("%s\n", password);return;}
for(int i=0;i password[pos]=caracteres[i];
brute_force (caracteres, cant, pos-1, password);}
return;}

int main(int argc, char *argv[]){
char caracteres[256]={0}, *password=NULL;int longitud=0, cantidad=0;
double tiempo=0;time_t t1, t2;
printf ("Ingrese los caracteres a usar: ");
scanf ("%s", caracteres);
cantidad = strlen(caracteres); printf ("Ingrese la longitud maxima de la contraseña: "); scanf ("%i", &longitud); password = (char*) malloc (longitud*sizeof(char)); time (&t1);password[longitud]= '\0'; brute_force (caracteres, cantidad, longitud-1, password); time (&t2);tiempo = difftime (t2, t1); printf ("\tTiempo: %7.2f\n\n", tiempo); free (password); //importante:liberar memoria system("PAUSE");return 0;}

martes, 11 de marzo de 2025

Intro al Reversing

Ingeniería Inversa Definición por pancake aka trufae
 La ingeniería inversa sirve para obtener información de un producto, cómo ha sido construido o cómo funciona por dentro. 
 El objetivo de la ingeniería inversa es obtener información o un diseño a partir de un producto accesible al público, con el fin de determinar de qué está hecho, qué lo hace funcionar y cómo fue fabricado. 
Hoy en día los productos más comúnmente sometidos a ingeniería inversa son los programas. Sirve para: 
 Clasificar Malware 
Liberar drivers/hardware 
Analizar vulnerabilidades 
Hacker crackmes/ctf (Capture the Flag) 
Contabilidad con software Espionaje industrial 
 ¿Qué tipos de ejecutables existen? 
¿Todos se depuran de la misma forma? 
¿Por qué los ejecutables tienen un encabezado? 
¿Qué información hay en ese encabezado (header en inglés)? 
¿Cómo se analiza un virus y qué modifica? 
¿Cómo se modifica un programa? 
¿Cómo puedo depurar mi programa para buscar errores? 
Una vez que he aprendido a depurar, ¿cómo puedo mejorar la protección de mi software? Del Código Máquina al Lenguaje Ensamblador Cuando nos encontramos frente a una variante de algún código malicioso en un sistema y nos disponemos a analizarlo tenemos el archivo binario y debemos utilizar un desensamblador para generar el código en assembler con el objetivo de analizarlo. 
Ensamblador (assembler) es en realidad una clase de lenguaje de programación. Cada variante de ensamblador corresponde a una familia particular de microprocesadores tales como x86, x64, SPARC, PowerPC, MIPS o ARM. Dentro de todas estas familias la más habitual dentro las arquitecturas de procesadores es la x86, aunque con el pasar de los años vemos más y más procesadores x64. 

 Data: La sección de datos de un programa hace referencia a una región específica de memoria. Contiene lo que se conoce como las variables estáticas que no cambian con la ejecución del programa. También en esta sección se encuentran las variables globales, que están disponibles desde cualquier parte del programa. 

Code: En esta región de memoria se almacena el código que se ejecuta del programa donde se alojan todas las instrucciones que se van a ejecutar. 

Heap: El heap es una región de memoria que se utiliza para alocar nuevos valores durante la ejecución del programa como así también para eliminarlos una vez que se dejaron de utilizar. El heap es una memoría dinámica y su contenido varía a medida que se ejecuta el programa 

Stack (Pila): La pila se utiliza para alojar las variables locales, parámetros y valores de retorno de una función como así también contiene las direcciones de retorno entre una llamada a una función y otra, siendo muy útil para controlar el flujo de ejecución del programa. Cualquier software se ejecuta de forma secuencial, es decir una instrucción detrás de otra, la siguiente instrucción a ejecutar se almacena en un registro llamado IP, mediante programación se puede desviar esa ejecución hacia funciones que realicen tareas concretas, el programa en un principio ejecutará el flujo normal hasta que llega a una llamada a una función, en ese momento guarda en RAM el registro IP, ejecuta la función y retorna al flujo principal del programa porque fué capaz de leer el valor almacenado en RAM del registro IP.
Registros
Un registro es, de forma simplificada, un pequeño almacén en la CPU y es, evidentemente, la forma más rápida que tiene la CPU de acceder a datos.
En la arquitectura x86 de Intel existen ocho registros de propósito general: EAX, EDX, ECX, ESI, EDI, EBP, ESP y EBX (cambiar E por R en arquitecturas de 64 bits).
Son utilizados para facilitar la tarea en el procesado de las instrucciones, cómo para almacenar datos que se utilizaran posteriormente por las mismas.
El registro EAX (RAX)
El registro EDX (RDX)
El registro ECX (RCX)
Los registros ESI (XSI) y EDI (RDI)
Los registros ESP (RSP) y EBP (RBP)
El registro EBX (RBX)
Registro especial EIP (RIP)
Estos son alguno de los registros básicos que existen:
-EAX (Accumulator register): Utilizado tanto para realizar cálculos, cómo para el almacenamiento de valores de retorno en "calls".
-EDX (Data register): Extensión de EAX, utilizada para el almacenamiento de datos en cálculos más complejos.
-ECX (Count register): Utilizado en funciones que necesiten de contadores, como por ejemplo bucles.
-EBX (Base register): Se suele utilizar para apuntar a datos situados en la memoria.
-ESI (Source index): Utilizado para la lectura de datos.
-EDI (Destination index): Utilizado para la escritura de datos.
-ESP (Stack pointer): Apunta a la cima de la pila “stack”.
-EBP (Base pointer: Apunta a la base de la pila “stack”.

Instrucciones -Son acciones predefinidas en el lenguaje ensamblador. Algunas de las más habituales de ver son:
-PUSH: Guarda el valor en la pila.
-POP: Recupera valor de la pila.
-MOV (dst, src): Copia el operador “src” en el operador “dst”.
-LEA (reg, src): Copia una dirección de memoria en el registro destino (ej: EAX).
-ADD (o1, o2): Suma los dos operadores y los almacena en el operador uno.
-SUB (o1, o2): Resta el valor del segundo operador sobre el primero y lo almacena en el primer operador.
-INC: Incrementa en 1 el valor del operador indicado.
-DEC: Decrementa en 1 el valor del operador indicado.
-AND: El resultado es 1 si los dos operadores son iguales, y 0 en cualquier otro caso.
-OR: El resultado es 1 si uno o los dos operadores es 1, y 0 en cualquier otro caso.
-CMP: Compara dos operadores.
-JMP Salta a la dirección indicada.
-CALL: Llama/Salta a la dirección/función indicada.
-NOP: Not Operation.

Estructura de la pila (Stack)
La pila es una estructura FILO (First In, Last Out) donde los argumentos son apilados en la cima de la misma cuando se invoca una función y retirados cuando la función finaliza. El registro ESP se usa para seguir la pista a la parte más alta del marco de la pila y el registro EBP para seguirle la pista a la parte baja (aunque ya vimos que ciertos compiladores pueden decidir no usar ebp para eso). 
 La PILA o Stack es un conjunto de direcciones de memoria encargadas de almacena información de llamadas a funciones, variables locales, direcciones de retorno a funciones anteriores, entre otras tareas. La PILA es dinámica, por lo que va cambiando su tamaño dependiendo de la función a la cual se encuentre asociada, dispone de una estructura “First In, Last Out”, por lo que lo último que entra será lo primero en salir, delimitada siempre por su cima (ESP) y por su base (EBP).
Puntos de Interrupción (Breakpoints)
La habilidad de parar un proceso que está siendo depurado se consigue mediante el fijado de puntos de interrupción o breakpoints. Al parar el proceso podemos inspeccionar el valor de las variables, los argumentos de la pila, y las direcciones de memoria sin que el proceso modifique estos valores hasta que no se lo indicas de esa forma al depurador. Los puntos de interrupción son la herramienta principal proporcionada por los depuradores. Los puntos de interrupción le permiten interrumpir la ejecución del programa en un lugar específico. Hay dos tipos de puntos de interrupción:
Puntos de interrupción de software
Puntos de interrupción de hardware
Es muy difícil realizar ingeniería inversa de software sin puntos de interrupción. Las tácticas populares de ingeniería anti-reversa se basan en la detección de puntos de interrupción, proporcionando una serie de métodos anti-depuración correspondientes.
Cómo omitir una verificación de punto de interrupción de software
No existe un enfoque universal para evitar una verificación de punto de interrupción de software. Para evitar esta protección, debes encontrar el código que calcula la suma de verificación y sustituir el valor devuelto con una constante, así como los valores de todas las variables que almacenan sumas de verificación de funciones.
Puntos de interrupción de hardware
DR0-DR3 – breakpoint registers -“Debug Address Registers” or “Address-Breakpoint Registers”
DR4 - DR5 – reserved - “Reserved Debug Registers”
DR6 – debug status - "Debug Status Register”
DR7 – debug control -“Debug Control Register”

SEH (Structured Exception Handling)
El manejo estructurado de excepciones es un mecanismo proporcionado por el sistema operativo a una aplicación que le permite recibir notificaciones sobre situaciones excepcionales como la división por cero, la referencia a un puntero inexistente o la ejecución de una instrucción restringida. Este mecanismo le permite manejar excepciones dentro de una aplicación, sin la participación del sistema operativo. Si no se maneja una excepción, dará como resultado la finalización anormal del programa. Los desarrolladores suelen ubicar punteros a SEH en la pila, que se denominan marcos SEH. La dirección de trama SEH actual se encuentra en el desplazamiento 0 en relación con el selector FS (o el selector GS para los sistemas x64).
VEH (Vectored Exception Handler)
VEH se introdujo en Windows XP y es una variación de SEH. VEH y SEH no dependen el uno del otro y funcionan simultáneamente. Cuando se agrega un nuevo "manejador" VEH, la cadena SEH no se ve afectada ya que la lista de manejadores VEH se almacena en la variable no exportada ntdll! LdrpVectorHandlerList. Los mecanismos VEH y SEH son bastante similares, la única diferencia es que las funciones documentadas se utilizan para configurar y eliminar un controlador VEH.
Exploiting sobre Linux-x86
La porción de RAM utilizada por un programa cuando se llama a una función es comunmente llamada pila o stack, debemos tener en cuenta que la pila crece de arriba a abajo, como podemos ver hay una parte de la ram que almacena la copia del registro IP(EIP) en el momento de realizar la llamada a la función, en el programa no se tiene en cuenta que el dato introducido sea de una longitud concreta, se realiza la copia a ciegas a la variable nombre, aprovechando este descuido podemos hacer crecer la variable nombre hasta llegar a ocupar la dirección de retorno EIP haciendo así que el software termine retornando a otra posición de memoria y no la que se guardó al realizar la llamada a la función func.
¿Qué es una Shellcode?
Una shellcode no es mas que el conjunto de opcodes (instrucciones en hexadecimal) que ejecutará el procesador para realizar un acción en concreto, las shellcodes suelen estar escritas en ensamblador ya que nos permite un control total sobre el proceso de ejecución además de un tamaño inferior de la shellcode.

Definición Buffer
Un espacio de memoria de cierto tamaño que se reserva para guardar datos, y manejar los mismos.
Un ejemplo básico es una lata de 20 litros que tengo vacía para guardar allí un contenido, el mismo podrá ser menor o igual a 20 litros, el cual es el tamaño máximo que puedo guardar en este buffer de 20 litros, si quisiera guardar más en un solo depósito debería buscar la forma de tener un buffer más grande, sino, al tratar de guardar por ejemplo 40 litros en una lata de 20 litros se desbordaría. Un buffer overflow ocurre cuando un programa informático excede el uso de cantidad de memoria reservado para ello , escribiendo en el bloque de memoria contiguo.
En verdad, un buffer overflow se produce en una aplicación informática cuando no cuenta con los chequeos de seguridad necesarios en su código de programación, como por ejemplo medir la cantidad de datos que se copiara a un buffer y que no exceda el tamaño del mismo.
Los tipos más comunes de buffer overflows son los stack buffer overflows y los heap buffer overflows. Bueno aqui vemos la definición de buffer overflow, y en nuestro ejemplo anterior si trato de guardar 40 litros en una lata de 20 litros se desbordara como vimos, ese desborde que se produce es el buffer overflow, o sea el desbordamiento de mi depósito al sobrepasar la máxima capacidad del mismo.
Stack y heap overflow
Ahora una idea acerca de la diferencia entre stack y heap: STACK : El stack se utiliza para guardar las variables locales de una función que sólo necesitan durar tanto como la ejecución de la función. En la mayoría de los lenguajes de programación es fundamental que sepamos en tiempo de compilación qué tan grande es una variable si queremos almacenarla en el stack. HEAP: El heap se utiliza para reservar memoria dinámica, cuya vida útil no se sabe muy bien por adelantado, pero se espera que duren un tiempo. Si no sabemos su tamaño o el mismo se decide en tiempo de ejecución se deberá calcular y reservar en el heap.
Stack Buffer Overflow
In software, a stack buffer overflow occurs when a program writes to a memory address on the program's call stack outside of the intended data structure; usually a fixed length buffer.
Es decir, la vulnerabilidad Stack Buffer Overflow ocurre cuando una aplicación no controla correctamente el número de bytes que son almacenados en una dirección de memoria previamente reservada, de forma que la cantidad de bytes que se van a almacenar son superiores a los reservados. Nuestro principal objetivo es llegar a sobrescribir la dirección de retorno (almacenada en la PILA) con un valor que apunte a nuestra shellcode.
-Registro EIP (Extended Instruction Pointer): Este registro apunta a la siguiente dirección de memoria que el procesador va a ejecutar.
-Instrucción RETN: Es la instrucción encargada de recoger el valor de ESP y almacenarlo en el registro EIP, de este modo el valor de ESP será la próxima dirección de memoria que el procesador va a ejecutar.
-Dirección de retorno: Es el valor exacto que nos indica la dirección de memoria donde habíamos dejado la aplicación ante de entrar en una subfunción, para así cuando esta termine volver a la posición exacta donde nos quedamos. Este valor se encontrará almacenado en la siguiente dirección de memoria del EBP de la subfunción.

Anti-sandboxing y Anti-debugging
Debuggers como OllyDbg, WindDbg, Radare o IDA ya sabréis que se requieren conocimientos sobre lenguaje ensamblador y estructuras internas de ficheros.
Una técnica anti-debugging muy fácil de implementar, pero también muy fácil de evadir, es la función “IsDebuggerPresent”.
PEB (Process Environment Block)
Los códigos de espagueti y basura hacen que las herramientas de análisis comunes sean ineficaces
El primer problema de ofuscación que requiere una solución es la eliminación de las instrucciones basura y el "código de espagueti", que es una técnica que pretende confundir los programas de desamblado El código de espagueti hace que el programa fluya de forma difícil de leer al agregar saltos continuos de código, de ahí el nombre.
Este problema no es nuevo, y en situaciones comunes se conocen complementos de reversing que pueden ayudar en esta tarea. Sin embargo, a veces no podemos encontrar un buen complemento de desensamblador interactivo (IDA) que pueda normalizar el flujo de código.

VM detection
hardware IDs are VmBus in case of HyperV VEN_15AD in case of VMware Debugger detection IsDebuggerPresent ThreadHideFromDebugger ProcessDebugPort ProcessDebugObjectHandle ProcessDebugFlags CheckRemoteDebuggerPresent NtQueryInformationProcess ProcessBasicInformation Fuente:elhacker.net

miércoles, 5 de junio de 2024

No encontrar las librerías .h en linux

Las librerías que usa gcc y g++ (y creo que clang) están en /usr/include/ ...a veces el comando locate no encuentra las librerías.

viernes, 31 de mayo de 2024

Los 11 fallos más comunes en Lenguaje C

(1)Mezclar enteros signed y unsigned.
(2)Sobrepasando límites de un arreglo.
(3)Perdiendo la condición base de una funcion recursiva.
(4)Usando constantes de caracteres en vez de literales de cadena y viceversa.
(5)Literales de tipo float son por defecto de tipo double.
(6)Olvidando liberar la memoria.
(7)Añadiendo un semicolon a #define.
(8)No ser cuidadoso con el semicolon.
(9)Erroneamente escribir = o ==.
(10)Copiando demasiado.
(11)Las macros son solo reeemplazo de cadenas.
1.- Mezclar enteros signed y unsigned en operaciones aritmeticas
#include stdio.h
int main(void){
unsigned int a = 1000;signed int b = -1;
if (a > b) puts("a is more than b");
else puts("a is less or equal than b");
return 0;}
Como 1000 es mayor que -1 uno esperaría que a es mayor que b. Antes de hacer la comparación, b es convertida a unsigned int. Cuando es convertido a unsigned int toma el valor máximo de unsigned int... el cual es mayor que 1000. Por esto se puede apreciar que a > b es una falso.
2.- Sobrepasando los límites de un arreglo.

Los arreglos siempre empiezan en 0 y terminan en la longitud del arreglo - 1.
#include stdio.h
int main(){
int x = 0;int myArray[5] = {1,2,3,4,5};
for(x=1; x<=5; x++){printf("%d\t",myArray[x]);}
printf("\n");return 0;} //Output: 2 3 4 5 GarbageValue
La forma correcta:
#include stdio.h
int main(){
int x = 0;int myArray[5] = {1,2,3,4,5};
for(x=0; x<5; x++){printf("%d\t",myArray[x]);}
printf("\n");return 0;} //Output: 1 2 3 4 5
Entonces, hay que conocer el límite de nuestros arreglos porque osino podemos corromper el buffer o provocar un fallo de segmentacion por acceder a un área de memoria distinta.
3.- Perdiendo la condición base en una función recursiva.
Calcular la factorización de un número es un ejemplo clásico de recursividad:
#include stdio.h
int factorial(int n){return n * factorial(n - 1);}

int main(){
printf("Factorial %d = %d\n", 3, factorial(3));return 0;}
//Typical output: Segmentation fault
El problema con esta función es que va a estar en un ciclo infinito, lo que causará fallo de segmentación. Necesita una condición base para detener la recursividad. La forma correcta:
#include stdio.h
int factorial(int n){
// Base Condition, very crucial in designing the recursive functions.
if (n == 1){return 1;}else{return n * factorial(n - 1);}}

int main(){
printf("Factorial %d = %d\n", 3, factorial(3));return 0;}
//Esta función va a terminar tan pronto alcance 1.
//Output : Factorial 3 = 6
Reglas a seguir:
1 Iniciar el algoritmo.
Las funciones recursivas necesitan con frecuencia un valor inicial con el que empezar. Esto es acompañado sea por un parametro de la función o una función puerta que no es recursiva pero pone los valores iniciales para la recursión.

2 Revisar para ver si los valores actuales que se están procesando coinciden con el caso base.Si es asi, entonces procesa y devuelve un valor


3 Redefine la respuesta en terminos de un problema pequeño o simple subproblema o subproblemas.

4 Ejecuta el algoritmo en un subproblema.
5 Combina los resultados en la formulación de la respuesta.
6 Retorna los resultados.

4.- Usando constantes de caracteres en vez de literales de cadena y viceversa.

En lenguaje C, las cadenas de caracteres y literales de cadena son cosas distintas. 'a' ..esto es una cadena de caracter. Una cadena de caracter es de tipo entero que tiene asignado un número para ese caracter. "asdf"... es un literal de caracteres. Un literal de caracteres un arreglo inmodificable cuyos elementos son de tipo char. "asdf" tiene 5 caracteres, porque el caracter final es un \0. Este caracter final es conocido como carácter nulo. {a,s,d,f,\0}.
//ejemplo 1: una cadena de caracteres es usada donde debería ir una literal de cadena. Esto da un comportamiento indefinido.
#include stdio.h
int main(void){
const char *hello = 'hello, world'; /* bad */puts(hello);return 0;}
//ejemplo 2:
un literal de cadena se usa donde se debería usar una cadena de caracteres. El resultado es una cosa sin sentido.
#include stdio.h
int main(void) { char c = "a"; /* bad */ printf("%c\n", c); return 0;}
En ambos casos el compilador se va a quejar de la mezcla. Si no pasa esto, necesita usar más advertencias para la compilación, o derechamente usar un mejor compilador.

5.- Literales de tipo float son por defecto de tipo double.

Hay que tener cuidado al inicializar una variable float a valores literales o compararlas con estos. Esto es debido a que literales float de valor 0.1 por lo regular son de tipo double. Este tipo de cosas nos puede conducir a sorpresas:

#include stdio.h

int main(){
float n = 0.1; if (n > 0.1) printf("Wierd\n");return 0;}
// Prints "Wierd" when n is float
n fue inicializada y redondeada por precisión, resultando en 0.10000000149011612. Entonces, n es vuelto a convertir en double para ser comparado con el valor literal 0.1 (lo cual es igual a 0.10000000000000001) lo que da una discordancia. Mezclar variables float con literales dobles puede resultar en pobre desempeño en plataformas donde no hay soporte de hardware para doble precisión.

6.- Olvidando liberar la memoria.

Uno siempre debe recordar liberar la memoria alojada, sea una función hecha por tí o por una función de librería llamada por tu función.
#include stdlib.h #include stdio.h

int main(void){
char *line = NULL;size_t size = 0;
/* memory implicitly allocated in getline */
getline(&line, &size, stdin);
/* uncomment the line below to correct the code */
/* free(line); */return 0;}
Es un error inocente en este ejemplo específico,porque cuando un proceso termina,la mayoría de los sistemas operativos libera la memoria alojada en vez de tí.
7.- Añadiendo un semicolon a #define

Muchas veces me pasó a mí!!! Es fácil confundirse con el preprocesador de C, y tratarlo como parte del lenguaje. Pero es un error, porque el preprocesador es sólo un mecanismo de reemplazo de texto.
// WRONG
#define MAX 100; int arr[MAX]={0};
//lo cual se traduce como
int arr[100]={0}; //Que se traduce como error de sintaxis.

8.- Ser cuidadoso con el semicolon
//Esto: if (x > a); a = x;
//Significa esto:
if (x > a) {} a = x;
Aveces, perder un semicolon puede provocar problemas inesperados:
if (i < 0) return day = date[0]; hour = date[1]; minute = date[2];
/*El semicolon antes de return está perdido, por lo que day =date[0]; va a ser regresado. El compilador lee hasta que encuentra ; como el fin de línea.*/

9.- Erroneamente escribir = en vez de ==.
El = es para asignar.
El == es para COMPARAR.
A veces hacemos:
/* assign y to x */ if (x = y) {/* logic */}
//cuando lo que uno queria era:
/* compare if x is equal to y */ if (x == y) {/* logic */}

//lo cual es equivalente a:
/* compare if x is equal to y */ if (x == y) != 0{/* logic */}

10.- Copiando demasiado.
char buf[8]={0}; /* tiny buffer, easy to overflow */
printf("What is your name?\n");
scanf("%s", buf); /* WRONG */
scanf("%7s", buf); /* RIGHT */
Si uno pone más caracteres que los requeridos por scanf, van a empezar a sobreescribirse zonas de memorias aledañas al buffer. Esto puede derivar en comportamiento indefinido. Los hackers maliciosos con frecuencia usan esto para sobreeescribir la dirección de return, y cambiar la dirección por la del código malicioso creado por este.
11.- Las Macros son solo reemplazo de cadenas
#include stdio.h
#define SQUARE(x) x*x
//este es el error.
int main(void){
printf("%d\n", SQUARE(1+2));return 0;}
Esperarías que este código devolviese 9, pero devolverá 5 porque la macro será expandida a 1+2*1+2. Para evadir este problema debe encerrar entre () las fichas para evadir este problema.
#include stdio.h
#define SQUARE(x) ((x)*(x))
int main(void){
printf("%d\n", SQUARE(1+2));return 0;}

TextView and EditText en Android

crear un archivo .xml con esto: LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> /LinearLayout> ........Encerrar LinearLayout entre <> (no me deja poner el código xml) y escribir esto en un archivo .xml: LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> /LinearLayout> TextView and EditText in Android

Diferencias entre const int y int const

Una respuesta simple: leer hacia atrás. Los punteros como sabréis son variables especiales que apuntan a otras variables, y las constantes son variables que no cambian durante la ejecución de un programa. int * ptr = ptr es un puntero hacia int. int const * ptr = ptr es un puntero hacia constante int. int * const ptr = ptr es un puntero constante hacia int. const int * const ptr = ptr es una constante puntero a una constante int. const int * ptr es igual a int const * ptr const int * const ptr es igual a int const * const ptr véase que lo que cambia es lo que esta antes de *ptr o *const ptr. int ** ptr = is a pointer to pointer(p2p) to int. Un puntero que apunta hacia otro puntero. int ** const ptr = ptr es un puntero constante de un puntero hacia int. int * const * ptr = ptr es un puntero a una constante puntero hacia int. int const **ptr = ptr es un puntero de un puntero hacia una constante int. int * const * const ptr = ptr es un puntero constante de otro puntero constante hacia int. ¿Como saber si const se refiere al puntero o lo apuntado? Si está del lado derecho del asterico, entonces se refiere a lo apuntado. Si está del lado izquierdo del asterico, del puntero. Fuente: What is the difference between const int and int const.

miércoles, 22 de mayo de 2024

Colores c.nanorc

## Syntax highlighting for C and C++ files. syntax c "\.([ch](pp|xx)?|C|cc|c\+\+|cu|H|hh|ii?)$" header "-\*-.*\" # Labels. color brightmagenta "^[[:blank:]]*[A-Z_a-z][0-9A-Z_a-z]*:[[:blank:]]*$" color normal ":[[:blank:]]*$" # Types and related keywords. color green "\<(auto|bool|char|const|double|enum|extern|float|inline|int|long|restrict|short|signed|sizeof|static|struct|typedef|union|unsigned|void)\>" color green "\<([[:lower:]][[:lower:]_]*|(u_?)?int(8|16|32|64))_t\>" color green "\<(_(Alignas|Alignof|Atomic|Bool|Complex|Generic|Imaginary|Noreturn|Static_assert|Thread_local))\>" color green "\<(class|explicit|friend|mutable|namespace|override|private|protected|public|register|template|this|typename|using|virtual|volatile)\>" # Flow control. color brightyellow "\<(if|else|for|while|do|switch|case|default)\>" color brightyellow "\<(try|throw|catch|operator|new|delete)\>" color magenta "\<(break|continue|goto|return)\>" # Single-quoted stuff (characters, backslash escapes, hex and octal byte codes). color brightmagenta "'([^'\]|\\(["'\abfnrtv]|x[[:xdigit:]]{1,2}|[0-3]?[0-7]{1,2}))'" # GCC builtins. color cyan "__attribute__[[:blank:]]*\(\([^)]*\)\)|__(aligned|asm|builtin|hidden|inline|packed|restrict|section|typeof|weak)__" # Strings and names of included files. color brightyellow ""([^"]|\\")*"|#[[:blank:]]*include[[:blank:]]*<[^>]+>" # Preprocessor directives. color brightcyan start="^[[:blank:]]*#[[:blank:]]*(if(n?def)?|elif|warning|error|pragma)\>" end="(\`|[^\])$" color brightcyan "^[[:blank:]]*#[[:blank:]]*((define|else|endif|include(_next)?|line|undef)\>|$)" # Comments. color brightblue "//.*" color brightblue start="/\*" end="\*/" # Reminders. color brightwhite,yellow "\<(FIXME|TODO|XXX)\>" # Trailing whitespace. color ,green "[[:space:]]+$"