LINUX.ORG.RU

Asm + C/C++


0

1

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

Ответ на: комментарий от yoghurt

Если я правильно понимаю, задача перехватить только возврат функции и подменить возвращаемое значение. Подменять полностью функцию не нужно, так что LD_PRELOAD не подходит

Rzhepish
()

системные события.

и

программа на С, в которой вызывается функция, что то делает и возвращает этот результат,

не имеют ничего общего друг с другом.

что можно почитать для этого задания

http://www.google.com/search?q=code+injection

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

не имеют ничего общего друг с другом

Поясни пожалуйста, ведь при вызове например функции по-моему возникает прерывание для сохранения данных в стек, а при возврате - извлечения данных из стека?

energyclab
() автор топика
Ответ на: комментарий от energyclab

Да вы понимаете правильно,

Ну тогда ты «по быстрому» задачу не решишь. У функции может быть несколько точек выхода и тебе придётся это каким-нибудь образом обрабатывать. Например, добавить обёртку над перехватываемой функцией.

Rzhepish
()
Ответ на: комментарий от energyclab

Уу, с такими знаниями тебе нужно начинать с букваря по асму (для твоего таргета).

Rzhepish
()
Ответ на: комментарий от energyclab

Прерывание не происходит, движуха данных с/на стек - опциональна. Гугли книжку по ассемблеру с нуля.

LamerOk ★★★★★
()
Ответ на: комментарий от Rzhepish

так что LD_PRELOAD не подходит

ещё как подходит. Из LD_PRELOAD ты вызываешь оригинальную функцию и дальше делаешь что хочешь с её возвращаемым значением.

true_admin ★★★★★
()
Ответ на: комментарий от energyclab

Кстати я так понимаю LD_PRELOAD это какая то переменная?

Да, переменная окружения.

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

Rzhepish
()
Ответ на: комментарий от energyclab

LD_PRELOAD это какая то переменная

$ man ld.so

anonymous
()
Ответ на: комментарий от Rzhepish

Это был ответ на

Подменять полностью функцию не нужно, так что LD_PRELOAD не подходит

Я не вижу связи между «подменять полностью функцию не нужно» и «LD_PRELOAD не подходит».

По поводу того как подменить функцию внутри бинарника. Простого решения я не нашёл.

true_admin ★★★★★
()

Самый простой вариант это запускать дебаггинг программы, вешать на ret из каждой интересной функции точку останова и подменять регистр с результатом (или как там на целевой архитекруте происходит возврат значения) в момент выхода из функции

kim-roader ★★
()

В современных Линуксах это вроде уже не так просто сделать как в старых ядрах.
http://kerneltrap.org/node/5793

Еще помню отличную статью по FreeBSD kernel, там был пример с подменой сис. вызова. Статья называлася что-то вроде «FreeBSD kernel hacks and tricks», но вот беда, я ее нагуглить не могу. Видимо название немного не так звучало. Может кто знает эту статью?

urxvt ★★★★★
()
Ответ на: комментарий от energyclab

Напиши программу на С, транслируй в asm, прочитай листинг.

kermzyxer
()

Подскажите где что можно почитать для этого задания, времени особо углубляться в это нету поэтому даже самые простые варианты приветствуются

Можно с помощью ptrace сделать. Навскидку - пишется трассировщик c PTRACE_SINGLESTEP, если находится эпилог (ret, например), то выполняем наш побочный код (прямо в трассировщике, ну и его туда можно из so динамически подгружать) и меняем регистры (eax, соответственно).

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Вот так примерно - выполняемая программа:

#include <stdio.h>

int foo(void)
{
    return 42;
}

int main()
{
    printf("call to foo() return %i\n", foo());
    return 0;
}

трассировщик:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/types.h>
#include <sys/wait.h>

#define RET_OPCODE 0x080483cd

int main(void)
{
    pid_t pid = fork();

    if (pid == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        printf("child start...\n");
        execl("./test", "test", NULL);
    } else {
        int status;
        struct user_regs_struct regs;

        wait(&status);

        for(;;) {
            ptrace(PTRACE_SINGLESTEP, pid, 0, 0);

            wait(&status);

            if(WIFEXITED(status))
                break;

            ptrace(PTRACE_GETREGS, pid, NULL, &regs);

            if(regs.eip == RET_OPCODE) {
                printf("changing returned value from %li to ", regs.eax);
                regs.eax = 24;
                printf("%li\n", regs.eax);
                ptrace(PTRACE_SETREGS, pid, NULL, &regs);
                ptrace(PTRACE_CONT, pid, NULL, NULL);
                break;
            }
        }

        wait(&status);

        if(WIFEXITED(status))
            printf("...child stop\n");
    }

    return 0;
}

получается так:

$ gcc -o test test.c
$ gcc -o tracer tracer.c
$ ./test
call to foo() return 42
$ ./tracer
child start...
changing returned value from 42 to 24
call to foo() return 24
...child stop

точно также как и регистры можно менять и любую память процесса. Чтобы менять возвращаемые значения в зависимости от имён функций и их сигнатур нужно немного больше усилий - отслеживать вызов функций (call) и искать в ELF дебажную информацию про соответствующие адреса (как GDB делает).

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

пишется трассировщик c PTRACE_SINGLESTEP

Только это выполняется МЕДЛЕННО :)

quasimoto ★★★★
()

Если будешь делать под окошками, почитай вот это. Довольно толково написано, несколько лет назад мне помогло.

m0rph ★★★★★
()
Ответ на: комментарий от quasimoto

Спасибо за пример, пока я не понимаю как это работает, но буду осваивать, Очень не понятно вот это

#define RET_OPCODE 0x080483cd

откуда такая цифра?

energyclab
() автор топика
Ответ на: комментарий от energyclab

откуда такая цифра?

Да, ввожу в заблуждение - не опкод, а адрес, конечно. Чтобы получить опкод по адресу нужно сделать:

long inst;
...
inst = ptrace(PTRACE_PEEKTEXT, pid, regs.eip, NULL);

и потом использовать что-то вроде

static inline int is_ret_opcode(long inst)
{
    return inst == 0xe58955c3;
}

т.е. нужно делать дизассемблер (смотреть спецификацию опкодов).

quasimoto ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.