2013-11-03 3 views
2

Я хочу получить значение текущего счетчика программы (ПК) внутри обработчика mprotect. Оттуда я хочу увеличить значение ПК с помощью команды «n», чтобы программа пропустила некоторые инструкции. Я хочу сделать все это для Linux версии 3.0.1. Любая помощь в структурах данных, где я могу получить значение ПК и как обновить это значение? Образец кода будет оценен. Заранее спасибо.Как получить текущий счетчик программ внутри обработчика mprotect и обновить его

Моя идея - использовать некоторые задачи при записи адреса памяти. Поэтому моя идея - использовать mprotect для защиты адреса. Когда какой-то код пытается что-то написать по этому адресу памяти, я буду использовать обработчик mprotect для выполнения некоторой операции. После ухода за обработчиком я хочу сделать операцию записи успешной. Поэтому моя идея состояла в том, чтобы сделать адрес памяти незащищенным внутри обработчика, а затем снова выполнить операцию записи. Когда код возвращается из функции обработчика, ПК укажет на оригинальную инструкцию записи, тогда как я хочу, чтобы она указывала на следующую инструкцию. Поэтому я хочу увеличить ПК по одной инструкции, независимо от длины инструкции.

Проверьте следующий поток

MprotectHandler(){ 
    unprotect the memory address on which protection fault arised 
    write it again 
    set PC to the next instruction of original write instruction 
} 

внутри основной функции:

main(){ 
    mprotect a memory address 
    try to write the mprotected address // original write instruction 
    Other instruction // after mprotect handler execution, PC should point here 
} 
+0

Что вы на самом деле пытаетесь достичь? Вы * изменяете * 'mprotect'? Для какой архитектуры это? Набор команд с фиксированной шириной или переменной шириной? Какие инструкции вы пытаетесь пропустить? 'mprotect' - системный вызов ... системный вызов будет возвращаться к процессу после его завершения. –

+0

Я отредактировал мой вопрос. – azizulhakim

ответ

1

Поскольку это утомительно, чтобы вычислить длину инструкции на нескольких CISC процессоров, я рекомендую несколько иной порядок: Вилка с помощью clone(..., CLONE_VM, ...) а также в индикаторе вместо

write it again 
    set PC to the next instruction of original write instruction 

сделать

ptrace(PTRACE_SINGLESTEP, ...) 

- после трассировки ловушки вы можете защитить память снова.

0

Вот пример кода демонстрирует основной принцип:

#include <signal.h> 
#include <stdint.h> 
#include <stdio.h> 
#include <string.h> 
#include <sys/ucontext.h> 

static void 
handler(int signal, siginfo_t* siginfo, void* uap) { 
    printf("Attempt to access memory at address %p\n", siginfo->si_addr); 
    mcontext_t *mctx = &((ucontext_t *)uap)->uc_mcontext; 
    greg_t *rsp = &mctx->gregs[15]; 
    greg_t *rip = &mctx->gregs[16]; 

    // Jump past the bad memory write. 
    *rip = *rip + 7; 
} 

static void 
dobad(uintptr_t *addr) { 
    *addr = 0x998877; 
    printf("I'm a survivor!\n"); 
} 

int 
main(int argc, char *argv[]) { 
    struct sigaction act; 
    memset(&act, 0, sizeof(struct sigaction)); 
    sigemptyset(&act.sa_mask); 
    act.sa_sigaction = handler; 
    act.sa_flags = SA_SIGINFO | SA_ONSTACK; 

    sigaction(SIGSEGV, &act, NULL); 

    // Write to an address we don't have access to. 
    dobad((uintptr_t*)0x1234); 

    return 0; 
} 

Он показывает, как обновить компьютер в ответ на страничную ошибку. В нем отсутствует следующее, которое вам необходимо выполнить:

  • Расширение длины инструкции. Как вы можете видеть, у меня есть hardcoded + 7, который, случается, работает на моем 64-битном Linux, поскольку инструкция, вызывающая ошибку страницы, составляет 7 байт MOV. Как сказал Армали в своем ответе, это утомительная проблема, и вам, вероятно, придется использовать внешнюю библиотеку, такую ​​как libudis86 или что-то в этом роде.
  • mprotect() обработка. У вас есть адрес, вызвавший ошибку страницы в siginfo->si_addr и с использованием этого должно быть тривиально найти адрес страницы mprotected и снять защиту с нее.
Смежные вопросы