Wednesday, September 21, 2011

Hardware breakpoints

In addition to. Spent some time trying to recollect how to set the hw breakpoints.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <signal.h>
#include <wait.h>

typedef enum {
    BREAK_ON_EXEC    = 0x00,
    BREAK_ON_WRITE    = 0x01,
    BREAK_ON_RW    = 0x03,
} BreakFlags;

typedef enum {
    LEN_1 = 0x00,
    LEN_2 = 0x01,
    LEN_4 = 0x03,
} DataLength;

typedef struct {
    int    dr0_local:1;
    int    dr0_global:1;
    int    dr1_local:1;
    int    dr1_global:1;
    int    dr2_local:1;
    int    dr2_global:1;
    int    dr3_local:1;
    int    dr3_global:1;
    int    exact_local:1;
    int    exact_global:1;
    int    reserved:6;
    BreakFlags    dr0_break:2;
    DataLength    dr0_len:2;
    BreakFlags    dr1_break:2;
    DataLength    dr1_len:2;
    BreakFlags    dr2_break:2;
    DataLength    dr2_len:2;
    BreakFlags    dr3_break:2;
    DataLength    dr3_len:2;
} DR7;

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

int set_bp(int pid, uint32_t addr)
{
    uintptr_t dr0 = (uintptr_t)addr;
    DR7 dr7 = {0};
    dr7.dr0_local    = 1;
    dr7.dr0_break    = BREAK_ON_EXEC;
    dr7.dr0_len    = 0;
    return     ptrace(PTRACE_POKEUSER, pid, offsetof(struct user, u_debugreg[0]), dr0) ||
        ptrace(PTRACE_POKEUSER, pid, offsetof(struct user, u_debugreg[6]), 0) ||
        ptrace(PTRACE_POKEUSER, pid, offsetof(struct user, u_debugreg[7]), dr7);
}

void action(void)
{
    printf("Let's rock!\n");
}

void tracer(void)
{
    int pid, status;
    struct user_regs_struct regs;
    if ((pid = fork()) == -1)
        return;
    if (pid == 0) {
        ptrace(PTRACE_TRACEME, 0, 0, 0);
        kill(getpid(), SIGINT);
    } else {
        int first = 0;
        uint32_t next_bp = (uint32_t)action;
        for (;;) {
            wait(&status);
            if (WIFEXITED(status))
                break;
            ptrace(PTRACE_GETREGS, pid, 0, &regs);
            if (regs.eip != next_bp) {
                puts("Setting BP");
                set_bp(pid, next_bp);
            } else {
                printf("Reached BP @ %08x\n", regs.eip);
                set_bp(pid, 0);
            }
            ptrace(PTRACE_CONT, pid, 0, 0);
        }
        exit(0);
    }
}

int main(int argc, char **argv)
{
    tracer();
    action();
}

No comments:

Post a Comment