Hoy vengo con una nueva libreria que he programado para C/C++, ésta tiene la función
primeramente de demostrar algunos conceptos de Hooking, por ahora solo sirven
para el mismo proceso de la aplicación en la que se ejecuta, con el objetivo de redireccionar
funciones, optimizar lagunas de memoria, y alguna cosa más.

En un futuro se expandirá junto con otro mix de funciones y hooks/inyecciones remotos,
por ahora solo demostraré los siguientes conceptos que puede hacer la libreria:
[+] Hookear una función para saltar a otra.
[+] Unhook para restaurar la función.
[+] Desensamblar por completo una función y leerla en opcodes.
[+] Obtener el tamaño exacto de una función.
[+] NOPear una función (Detecta RET, es decir que puede salir sin errores ni violaciones de acceso).
[+] Escribir en una dirección de memoria exacta 1 o tantos valores como se quiera(operaciones peligrosas).


Ésta libreria esta hecha 100% por mi, no contiene rips, ya que su objetivo es comprender y realizar
primeramente las características antes descritas, para luego poder adaptarlo a otro nivel.

NOTA:En internet encontré mucho código generico, y muchos rips pero no he visto a nadie implementar éste metodo ni tampoco en conceptos, supongo que muchos empiezan con inyecciones remotas sin saber primeramente como funciona los hooks, saltos, sobreescritura de memoria etc...
Código:
#include <windows.h>

#ifndef __NVK_OPS__
    #define NOP()__asm__ volatile("nop;");
    #define SaveMemoryContext(FADDRESS, SAVE_LABEL) \
        BYTE SAVE_LABEL[0x6]; \
        SaveMemoryContextEx(FADDRESS, SAVE_LABEL);

    int SizeMemoryAddress(int* FAddress);
    void ReadDisassembleMemory(int *FAddress, BYTE *PByteBuffer);
    void HookMemoryAddress(int *FAddress, int *HijackAddr);
    void SaveMemoryContextEx(int *FAddress, BYTE SaveBuffer[]);
    void UnhookMemoryAddress(int* FAddress, BYTE UnhookBytes[]);
    void PoolNOPAddress(int *FAddress);
    void WriteMemory(int *FAddress, int BeginPointer, BYTE writeByte[]);

#endif // __NVK_OPS__

int SizeMemoryAddress(int* FAddress)
{
    BYTE *TotalBytes;
    for(int readBytes=0;;readBytes++)
    {
        TotalBytes= (BYTE *)malloc(readBytes +sizeof(BYTE));
        MoveMemory((BYTE *)&TotalBytes[readBytes], (void *)FAddress+readBytes, 0x1);
        if(TotalBytes[readBytes]==0xc3)
            return(readBytes);
    }
    free(TotalBytes);

    return 0;
}

void ReadDisassembleMemory(int *FAddress, BYTE *PByteBuffer)
{
    for(int readBytes=0;;readBytes++)
    {
        MoveMemory((BYTE *)&PByteBuffer[readBytes], (void *)FAddress+readBytes, 0x1);
        if(PByteBuffer[readBytes]==0xc3)
            break;
    }
}

void HookMemoryAddress(int *FAddress, int *HijackAddr)
{
    DWORD lpflOldProtect;
    BYTE jmp[] = {
        0xe9,                       // JMP
        0x00, 0x00, 0x00, 0x00,     // Futura direccion de la funcion a saltar.
        0xc3                        // RETN
    };

    int funcSize= SizeMemoryAddress((int *)FAddress);
    DWORD jmp_size= ((DWORD)HijackAddr - (DWORD)FAddress); // tecnica de hijack clasica.
    jmp_size -= 0x05;

    if(VirtualProtect((void *)FAddress, funcSize, PAGE_EXECUTE_READWRITE, &lpflOldProtect))
    {
        CopyMemory(&jmp[1], (DWORD *)&jmp_size, 0x04); //for(int d=0; d<sizeof(jmp); d++)printf("jmp buffer: 0x%x \t+%d \n", jmp[d], d);
        MoveMemory((DWORD *)FAddress, (BYTE *)jmp , sizeof(jmp) );
    }
}

void SaveMemoryContextEx(int *FAddress, BYTE SaveBuffer[])
{
    BYTE UnhookBytes [] =
    {
        // Re-configurar stack frame.
        0x55,               /// - PUSH EBP
        0x89, 0xE5,         /// - MOV EBP,ESP
        0x00, 0x00, 0x00
    };
    BYTE saveOriginalFunc[6];

    CopyMemory((BYTE *)&saveOriginalFunc, (DWORD *)FAddress, sizeof(saveOriginalFunc)); // 004016b9
    MoveMemory((BYTE *)&UnhookBytes[3], (BYTE *)&saveOriginalFunc[3] , 3); // - 3 bytes despues del stack frame.
    CopyMemory((BYTE *)SaveBuffer, (BYTE *)UnhookBytes, sizeof(UnhookBytes)); //for(int x=0; x<6; x++) printf("-0x%x\n", UnhookBytes[x]); // Para debug.
}

void UnhookMemoryAddress(int* FAddress, BYTE UnhookBytes[])
{
    __asm__
    (
        "sub $0x18, %%esp;"
        "movl $0x6, 0x8(%%esp);" // longitud 6
        //"mov 0xc(%%ebp), %%eax;"

        "mov %%eax, 0x4(%%esp);"
        "mov 0x8(%%ebp), %%eax;"
        "mov %%eax, (%%esp);"
        "call _memmove;"
        "leave;"
        "ret;"

        ::"a"((BYTE *)&UnhookBytes[0])
    );
}

void PoolNOPAddress(int *FAddress)
{
    DWORD lpflOldProtect;
    int funcSize= SizeMemoryAddress((int *)FAddress);
    BYTE NOPS[funcSize];

    memset(&NOPS, 0x90, sizeof(NOPS)); // llenar el array de nops
    if(VirtualProtect((void *)FAddress, funcSize, PAGE_EXECUTE_READWRITE, &lpflOldProtect))
        MoveMemory((DWORD *)FAddress, (BYTE *)NOPS, sizeof(NOPS));
}

void WriteMemory(int *FAddress, int BeginPointer, BYTE writeByte[])
{
    DWORD lpflOldProtect;
    int funcSize= SizeMemoryAddress((int *)FAddress);
    int align_size_array= (sizeof(writeByte)/sizeof(writeByte[0]))-0x1;

    if(VirtualProtect((void *)FAddress, funcSize, PAGE_EXECUTE_READWRITE, &lpflOldProtect))
    {
        if(align_size_array>1)
            MoveMemory((DWORD *)FAddress + BeginPointer, (BYTE *)writeByte , align_size_array );
        else
            *(DWORD *)(FAddress + BeginPointer)= *(BYTE *)writeByte;
    }
}
Algunos ejemplos:

Hookear función
// Funcion a hookear.
int xprintf()
{
    printf("[!]Funcion original.\n");
    return 0;
}

// Funcion sobreescrita.
int xwrite()
{
    for(int x=0; x<3; x++)
        printf("[+]Funcion hookeada!\n");
}

// Hook
int main()
{
	printf("Direccion funcion original -> 0x%p\n\n", & xprintf);
	
    xprintf();

    HookMemoryAddress((int *)&xprintf, (int*)&xwrite);

    xprintf();
}
Imagen


Hook y Unhook
printf("Direccion funcion original -> 0x%p\n\n", & xprintf);

    SaveMemoryContext((int*)&xprintf, SaveBuffer);

    xprintf();

    HookMemoryAddress((int *)&xprintf, (int*)&xwrite);

    xprintf();

    UnhookMemoryAddress((int *)&xprintf, SaveBuffer);

    xprintf();
Imagen


Desensamblar la función.
printf("Direccion funcion original -> 0x%p\n\n", & xprintf);
	// Tamaño de la funcion.
    int funcSize= SizeMemoryAddress((int *)xprintf);
    BYTE disBuf[funcSize];

    printf("Tam de la funcion: %d\n", funcSize);
	
	// Desensamblado de la funcion y lectura en bucle.
    ReadDisassembleMemory((int *)&xprintf , disBuf);
    for (int bytes=0; bytes<=funcSize; bytes++)
        printf("-0x%x\n", disBuf[bytes]);
Imagen


Escribir una zona de memoria.
// Escribir un byte NOP(ampersand obligatorio).
    BYTE writeBuff = 0x90;
    WriteMemory((int *)&xprintf, 0, (BYTE *)&writeBuff);

// Escribir varios bytes.
	// Escribir 3 nops iniciando en la posicion 3 de la funcion(no ampersand, pero si en un array).
	BYTE writeBuff[]= {0x90, 0x90, 0x90};
    WriteMemory((int *)&xprintf, 3, (BYTE *)writeBuff);
Imagen


Nopear toda la función hasta el RET(se autodetecta)
printf("Direccion funcion a nopear -> 0x%p\n\n", & xprintf);
PoolNOPAddress((int *)&xprintf);
Imagen


eso es todo por ahora
Todo esto me suena a chino, pero si algún día empiezo a estudiar C++ sé que todo esto será una lectura obligatoria.

De todos modos, muchas gracias maestro.
Estaremos atentos , gracias compadre por el material e por su tiempo

Saludos

Indetectables RAT v.0.9.5

@Indetectables Team
Gracias a todos por sus comentarios, ojalá les haya servido... tal vez para un futuro escriba un artículo lo más detalladamente posible sobre hooks y alguna que otra cosa mas.
saludos!
Me encantan tus trabajos, no se de donde sacas tanta sabiduria en esto pero ya le gustaria a mas de uno hacer estos trabajos tan admirables, haber si algun dia me pongo con esto ya que nunca me e puesto a fondo con el hooking. pero me interesa mucho el tema, y no es solo el trabajo que has hecho si no tu orgullo como coder lo llevas ante todo y lo haces desde 0, como deberian de hacerlo muchos, un ejemplo a seguir un saludo maquina
PD:
NvK escribió:eso es todo por ahora
ya quiero ver la siguiente parte
Abolición para el torneo del toro de la vega. Death to the murderers of bulls.
Saludos colega, bueno quería decir primero que siempre antes de interiorizarme en un tema(sea cual sea), primero estudio sus bases, luego ensayo programando código para entender su funcionamiento(y también aquí es donde depuro), y luego de comprender y asimilar conceptos trato de crear mi propia versión.
En general siempre me las veo tras un debugger para entender que hago realmente y como lo hago. Con ésto no quería sonar orgulloso como dices, nunca fui una persona creída ni con complejos de superioridad, soy ambicioso en lo que hago por las horas de estudio que le dedico y los resultados que trato de obtener.
Pero siempre ayudo a las personas que realmente veo que tienen voluntad de aprender(y no a los ripers que piden todo un código hecho), ya que todos empezamos de abajo y si muchas veces no lo hago es por que tuve malas experiencias con gente que me a robado código.
Un saludo y hasta la próxima.
Bueno no era mi intencion decirte creido, orgullo puede sonar a eso pero no siempre tiene por que ser asi, yo me referia a tener orgullo de hacerlo desde 0 todo, como haces tu y como hago yo y otros muchos, lo que yo llamo orgullo de coder, y si, tambien se le puede llamar ambicion
Se lo que sientes cuando as ayudado a alguien y despues te han defraudado de esa manera, yo e ayudado a muchos aqui y despues me an dejado de hablar o me han mandado a cagar algo incomprensible y que nunca entendere y por eso no ayudo a los nuevos como hacia antes, pero bueno como no soy de caer en la misma trampa ya no e vuelto a ayudar a gente que empieza asta que no conozca yo bien como es esa persona.Respecto a lo ultimo, hay mucho ripper por hay que quiere aparentar lo que no es, asta que al final acavan siendo cazados, un saludo crack y sigue asi
Abolición para el torneo del toro de la vega. Death to the murderers of bulls.
strup escribió:Bueno no era mi intencion decirte creido, orgullo puede sonar a eso pero no siempre tiene por que ser asi, yo me referia a tener orgullo de hacerlo desde 0 todo, como haces tu y como hago yo y otros muchos, lo que yo llamo orgullo de coder, y si, tambien se le puede llamar ambicion
Se lo que sientes cuando as ayudado a alguien y despues te han defraudado de esa manera, yo e ayudado a muchos aqui y despues me an dejado de hablar o me han mandado a cagar algo incomprensible y que nunca entendere y por eso no ayudo a los nuevos como hacia antes, pero bueno como no soy de caer en la misma trampa ya no e vuelto a ayudar a gente que empieza asta que no conozca yo bien como es esa persona.Respecto a lo ultimo, hay mucho ripper por hay que quiere aparentar lo que no es, asta que al final acavan siendo cazados, un saludo crack y sigue asi
No hay problema, es que hay veces las cosas pueden sonar con doble sentido, y si, los rippers caen por si solos la mentira tarde o temprano se descubre, saludos compa

PD: Haber si le sigues dando a haskell,junto con sanko y se hacen un tuto. Me encanta ese lenguaje pero últimamente ando escaso de tiempo, quisiera saber más de el
NvK escribió: PD: Haber si le sigues dando a haskell,junto con sanko y se hacen un tuto. Me encanta ese lenguaje pero últimamente ando escaso de tiempo, quisiera saber más de el
Claro bro es un lenguaje muy interesante en cuanto me lea el libro que aun me queda el doble hare algun tuto o algo xD haber si Sanko sigue dandole xD, ahora mismo ando practicando con las lambdas y haciendome mis propios ejercicios xDD, estoy convencido de que el lenguaje te viciara a mi de hecho me encanto y no me despegado desde entonces,
un saludo crack
Abolición para el torneo del toro de la vega. Death to the murderers of bulls.
Responder

Volver a “Fuentes”