Как я могу определить функцию во время выполнения в c - PullRequest
2 голосов
/ 18 февраля 2020

Я пытаюсь определить и вызвать функцию во время выполнения с языком c в процессоре arm (cortex a72). чтобы сделать это, я реализовал код, подобный приведенному ниже:

#include <stdio.h>
#include <sys/mman.h>

char* ibuf;
int   pbuf = 0;
#define ADD_BYTE(val) do{ibuf[pbuf] = val; pbuf++;} while(0)
void (*routine)(void);

void MakeRoutineSimpleFunc(void)
{
    //nop
    ADD_BYTE(0x00);
    ADD_BYTE(0xf0);
    ADD_BYTE(0x20);
    ADD_BYTE(0xe3);

    //bx lr
    ADD_BYTE(0x1e);
    ADD_BYTE(0xff);
    ADD_BYTE(0x2f);
    ADD_BYTE(0xe1);
}

int main(void)
{
    ibuf = (char*)mmap(NULL, 4 * 1024, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
    MakeRoutineSimpleFunc();
    routine = (void(*)())(ibuf);
    routine();
}

, как вы можете видеть, в приведенном выше коде сначала я выделяю область исполняемой памяти и назначаю адрес этого ibuf, затем я помещаю некоторые простая инструкция в ibuf ("nop" и "bx lr", что означает возврат в руку), а затем я пытаюсь вызвать эту функцию через указатель функции.

но когда я хочу вызвать функцию через указатель функции i получил ошибку "ошибка сегментации". Кстати, когда я пытаюсь запустить приложение с отладчиком GDB, программа запускается без ошибок.

есть что-то, что я пропустил в приведенном выше коде, что вызывает "ошибку сегментации"?

Я хочу добавить , когда я добавляю вышеприведенные инструкции ("nop" и "bx lr", что означает возврат в руку) во время компиляции к функции, подобной приведенной ниже, функция работает без ошибок.

void f2(void)
{
    __asm__ volatile (".byte 0x00, 0xf0, 0x20, 0xe3");
    __asm__ volatile (".byte 0x1e, 0xff, 0x2f, 0xe1");
}

EDIT1: in Чтобы проверить правильность функции времени выполнения, я удалил пролог и эпилог f2 с помощью дизассемблера Гидры, поэтому ассемблерный код f2 выглядит так:

**************************************************************
FUNCTION                     
**************************************************************
undefined FUN_0000083c()
undefined         r0:1           <RETURN>
undefined4        Stack[-0x4]:4  local_4
FUN_0000083c                                    XREF[1]: FUN_00000868:000008a4(c)  
        0000083c 00 f0 20 e3     nop
        00000840 00 f0 20 e3     nop
        00000844 00 f0 20 e3     nop
        00000848 00 f0 20 e3     nop
        0000084c 00 f0 20 e3     nop
        00000850 00 f0 20 e3     nop
        00000854 1e ff 2f e1     bx         lr
        00000858 00 f0 20 e3     nop
        0000085c 00 f0 20 e3     nop
        00000860 00 f0 20 e3     nop
        00000864 00 f0 20 e3     nop

, а также снова работает без проблем.

EDIT2: кое-что, что я хочу добавить, может быть полезно для решения проблемы, как я видел в ассемблере, компилятор вызывает функцию «рутина» с инструкцией «blx r3», в то время как он вызывает другие функции с именем символа «bl» «». как я знаю, blx может изменить состояние процессора с ARM на большой палец или наоборот. может ли эта точка вызвать проблему?

EDIT3: дизассемблирование основной функции выглядит примерно так:

**************************************************************
FUNCTION
**************************************************************
int __stdcall main(void)
int               r0:4           <RETURN>
undefined4        Stack[-0xc]:4  local_c                                 XREF[1]:     00010d44(W)  
undefined4        Stack[-0x10]:4 local_10                                XREF[1]:     00010d4c(W)  
                             main                                            XREF[4]:     Entry Point(*), 
                                                                                          _start:00010394(*), 000103a8(*), 
                                                                                          .debug_frame::000000a0(*)  
        00010d34 00 48 2d e9     stmdb      sp!,{ r11 lr }
        00010d38 04 b0 8d e2     add        r11,sp,#0x4
        00010d3c 08 d0 4d e2     sub        sp,sp,#0x8
        00010d40 00 30 a0 e3     mov        r3,#0x0
        00010d44 04 30 8d e5     str        r3,[sp,#local_c]
        00010d48 00 30 e0 e3     mvn        r3,#0x0
        00010d4c 00 30 8d e5     str        r3,[sp,#0x0]=>local_10
        00010d50 22 30 a0 e3     mov        r3,#0x22
        00010d54 07 20 a0 e3     mov        r2,#0x7
        00010d58 01 1a a0 e3     mov        r1,#0x1000
        00010d5c 00 00 a0 e3     mov        r0,#0x0
        00010d60 7d fd ff eb     bl         mmap                                         
        00010d64 00 20 a0 e1     cpy        r2,r0
        00010d68 50 30 9f e5     ldr        r3,[->ibuf]                                      
        00010d6c 00 20 83 e5     str        r2,[r3,#0x0]=>ibuf
        00010d70 48 30 9f e5     ldr        r3,[->ibuf]
        00010d74 00 30 93 e5     ldr        r3,[r3,#0x0]=>ibuf
        00010d78 03 10 a0 e1     cpy        r1,r3
        00010d7c 40 00 9f e5     ldr        r0=>s_ibuf:_%x_00010e40,[PTR_s_ibuf:_%x_00010d
        00010d80 69 fd ff eb     bl         printf
        00010d84 ae fe ff eb     bl         MakeRoutineSimpleFunc
        00010d88 30 30 9f e5     ldr        r3,[->ibuf]
        00010d8c 00 30 93 e5     ldr        r3,[r3,#0x0]=>ibuf
        00010d90 03 20 a0 e1     cpy        r2,r3
        00010d94 2c 30 9f e5     ldr        r3,[->routine]
        00010d98 00 20 83 e5     str        r2,[r3,#0x0]=>routine
        00010d9c 24 30 9f e5     ldr        r3,[->routine]
        00010da0 00 30 93 e5     ldr        r3,[r3,#0x0]=>routine
        00010da4 33 ff 2f e1     blx        r3
        00010da8 1c 00 9f e5     ldr        r0=>DAT_00010e4c,
        00010dac 61 fd ff eb     bl         puts
        00010db0 00 30 a0 e3     mov        r3,#0x0
        00010db4 03 00 a0 e1     cpy        r0,r3
        00010db8 04 d0 4b e2     sub        sp,r11,#0x4
        00010dbc 00 88 bd e8     ldmia      sp!,{ r11 pc }

, как вы можете видеть, подпрограмма вызывается с инструкцией "blx r3" по адресу "00010da4 ». а также я напечатал адрес ibuf, это было "0xb6ff8000".

1 Ответ

2 голосов
/ 18 февраля 2020

Я думаю, вы можете ввести коды операций непосредственно в строку «двоичный код» и выполнить код, используя ((void*)STRING)(). Тем не менее, вы также можете прочитать о том, как g cc реализует батуты, потому что именно так g cc генерирует код, который создает код в стеке и запускает его выполнение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...