1

これに関連するさまざまなトピックを見てきましたが、私が抱えているこの特定の問題を見つけることができませんでした。

私が調べたこと: 実行時にコードを実行可能ファイルに挿入する C SIGSEGV Handler & Mprotect Linux プロセスのアドレス空間内のすべてのページを書き込み保護できますか? SIGSEGV をキャッチするシグナルハンドラを作成するには?

ハンドラーで保護を PROT_READ または PROT_WRITE に設定する必要がある場合、SIGSEGV を正常に処理できます。ただし、mmap を使用して命令を挿入しようとしてから、mprotect を使用して PROT_READ のみに設定し、インライン アセンブリを介して命令を実行すると、意図したとおりに SIGSEGV が発生しますが、ハンドラーは元のアドレスを取得できません。信号なので、PROT_READ | に mprotect できません。PROT_EXEC.

例:

void sigHandler(int signum, siginfo_t *info, void *ptr) {

    printf("Received signal number: %d\n", signum);
    printf("Signal originates from process %lu\n",
        (unsigned long)info->si_pid);

    printf("SIGSEGV caused by this address: ? %p\n", info->si_addr);

    char * alignedbaseAddr = (((unsigned int)(info->si_addr)) >> 12) * getPageSize(); 
    printf("Aligning to %p\n", alignedbaseAddr);
    //flip this page to be r+x
    mprotect(alignedbaseAddr, getPageSize(), PROT_READ | PROT_EXEC);
}
void setupSignalHandler() {
    action.sa_sigaction = sigHandler;
    action.sa_flags = SA_SIGINFO;
    sigemptyset(&action.sa_mask);
    sigaction(SIGSEGV, &action, NULL);
}

int main(int argc, char *argv[]) {
    char * baseAddr = (char*)mmap(NULL, getDiskSize(), PROT_READ | PROT_WRITE,    MAP_SHARED, fd, 0);
    if(baseAddr == MAP_FAILED) {
        perror("Unable to mmap.");
    }
    printf("Process address space is %d\n", getDiskSize());
    //no-op filler
    for(int i = 0; i < (getDiskSize()) - 1; i++) {
        baseAddr[i] = 0x90;
    }
    //ret instruction
    baseAddr[i] = 0xc3;

    if( mprotect(baseAddr, getDiskSize(), PROT_READ) == -1) {
        perror("mprotect");
        exit(1);
    }

    printf("Protecting addresses: %p to %p for READ_ONLY\n", baseAddr, baseAddr + getDiskSize() - 1);
    setupSignalHandler();


    __asm__
    (
     "call %%eax;"
     : "=a" (output)
     : "a" (baseAddr)
    );

    printf("Will this ever print?");
    //close fd, and unmap memory
    cleanUp();
    return EXIT_SUCCESS;
}

結果の出力は次のとおりです。

受信シグナル番号: 11
プロセス 0
SIGSEGV からのシグナルは、このアドレスによって発生します: ? (なし)

//そのページを「再保護」できないため、上記の出力は繰り返しループします。

アーキテクチャ: x86 32 ビット OS: Ubuntu 11.04 - Linux バージョン 2.6.38-12-generic (buildd@vernadsky) (gcc バージョン 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4) )

何か案は?上記のロジックは、メモリへの単純な読み取りと書き込みには問題なく機能します。インライン アセンブリとは対照的に、実行時に命令を実行するより良い方法はありますか?

前もって感謝します!

4

1 に答える 1

1

その場合、フォルト アドレスは命令ポインタです。ptr(でインストールされたシグナル ハンドラのSA_SIGINFO) 3 番目の引数を にキャストucontext_tし、適切なレジスタをおそらく (テストされていないコード! )として取得します。

ucontext_t *uc = ptr;
void* faultyip = uc->uc_mcontext.gregs[REG_IP];

詳細については、注意深くお読みください/usr/include/sys/ucontext.h

なぜあなたが尋ねているのか知りたいです!!

于 2011-11-21T06:41:20.697 に答える