код функции в рантайме

Тема в разделе "LANGS.C", создана пользователем mantissa, 14 янв 2025.

  1. mantissa

    mantissa Мембер Команда форума

    Публикаций:
    0
    Регистрация:
    9 сен 2022
    Сообщения:
    167
    Можно ли как-то получить код функции в рантайме? Хочу сделать что-то типа облачных вычислений.

    Код (Text):
    1. int foo() {
    2.     return 5 + 5;
    3. }
    4.  
    5. int main() { int res = remotexec(foo); }
    Я думал узнать размер функции, а потом просто получить машинный код, далее как-нибудь его распарсить на принимающем сервере, но комплияторы обычно оптимизируют (общий пролог делают и тд), может есть какие-то средства в Windows API для этого?
     
  2. mantissa

    mantissa Мембер Команда форума

    Публикаций:
    0
    Регистрация:
    9 сен 2022
    Сообщения:
    167
    Даже не обязательно делать это на голом СИ. Может ли DSL как-то помочь в этом, например с переводом в LLVM IR? Главное, чтобы потом была обратная интеграция с СИ, чтобы отправить код по сокету.
     
  3. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    479
    Нет, это фантастика.
    Сами исходные коды и надо передавать по сети если уж нужно неизвестно что заранее на сервере считать, главное троянов не хапнуть.
     
  4. MaKsIm

    MaKsIm Active Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    120
    Как вариант. Запихать код в библиотеку, передать её, подгрузить динамически и выполнить.
     
  5. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    2.007
    Это какой-то новый уровень написания эксплоитоориентированных приложений - исполнять присланный кем-то код на сервере.
     
  6. mantissa

    mantissa Мембер Команда форума

    Публикаций:
    0
    Регистрация:
    9 сен 2022
    Сообщения:
    167
    короче получилось так: механизм SEH сует информацию о функциях в NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION] у PE32+ достать можно через RtlCaptureContext + RtlLookupFunctionEntry


    Код (Text):
    1. #include <windows.h>
    2. #include <dbghelp.h>
    3. #include <stdio.h>
    4.  
    5. void printFunctionBytes(DWORD64 imgBase, DWORD64 beginAddr, DWORD64 endAddr) {
    6.     printf("Function bytes from 0x%llX to 0x%llX:\n", beginAddr + imgBase, endAddr + imgBase);
    7.     for (DWORD64 addr = beginAddr; addr < endAddr; addr++) {
    8.         unsigned char byte;
    9.         if (ReadProcessMemory(GetCurrentProcess(), (LPVOID)(imgBase + addr), &byte, 1, NULL)) {
    10.             printf("%02X ", byte);
    11.         }
    12.         if ((addr - beginAddr + 1) % 16 == 0) {
    13.             printf("\n");
    14.         }
    15.     }
    16.     printf("\n");
    17. }
    18.  
    19. int foo(int x, int y, int* size) {
    20.     CONTEXT con = { 0 };
    21.     RtlCaptureContext(&con);
    22.  
    23.     DWORD64 ImgBase = 0;
    24.     RUNTIME_FUNCTION* pRTFn = RtlLookupFunctionEntry(con.Rip, &ImgBase, NULL);
    25.     size_t nFnSz = 0;
    26.  
    27.     if (pRTFn) {
    28.         // Выводим начало функции
    29.         printf("Function start address (by API): 0x%p\n", ImgBase + pRTFn->BeginAddress);
    30.         nFnSz = pRTFn->EndAddress - pRTFn->BeginAddress;
    31.  
    32.         // Выводим байты функции
    33.         printFunctionBytes(ImgBase, pRTFn->BeginAddress, pRTFn->EndAddress);
    34.     }
    35.     else {
    36.         printf("Function entry not found.\n");
    37.     }
    38.     *size = (int)nFnSz;
    39.     return x + y;  
    40. }
    41.  
    42. int main() {
    43.     int size = 0;
    44.     int result = foo(5, 10, &size);
    45.     printf("Size of the function: %d\n", size);
    46.     printf("ptr foo %p\n", foo);
    47.     printf("Result of foo: %d\n", result);
    48.     return 0;
    49. }
    50.  
    правда в функции придется таскать портянку, но ее можно будет исполнить два раза, первый для получения инфы, а второй для результата :sarcastic_hand:

    кстати почему-то значения ImgBase + pRTFn->BeginAddress и printf("ptr foo %p\n", foo); не совпадают
     
  7. mantissa

    mantissa Мембер Команда форума

    Публикаций:
    0
    Регистрация:
    9 сен 2022
    Сообщения:
    167
    да, это не проблема, если код задавать в виде строки или файла, задача именно обеспечить маршалинг и данных и кода, а для клиента это будет обычный вызов ф-ции обернутой в макрос или другую ф-цию. как в питоне например

    сначала

    Код (Text):
    1. import pickle
    2. import socket
    3.  
    4. def remote_function(a, b):
    5.     return a + b
    6.  
    7. func_data = pickle.dumps(remote_function)
    8.  
    9. with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    10.     s.connect(('localhost', 12345))
    11.     s.sendall(func_data)
    потом

    Код (Text):
    1. import pickle
    2. import socket
    3. with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    4.     s.bind(('localhost', 12345))
    5.     s.listen(1)
    6.     conn, addr = s.accept()
    7.     with conn:
    8.         data = conn.recv(1024)
    9.         func = pickle.loads(data)
    10.  
    11.         result = func(5, 10)
    12.         print(f'Result from remote function: {result}')
    13.  
     
  8. Ahimov

    Ahimov Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    64
    Для чего знать длину процедуры ?

    Процедуру как строку нельзя скопировать. Процедура содержит данные, смещения/адреса их, части процедуры разнесены в памяти, в общем это сложный обьект в памяти и описывается cfg.

    Все манипуляции нужно выполнять с модулем, а не пытаться его разобрать на части. Это между прочим весьма сложная задача и не без статистики(код от данных отличить), а значит не может быть решена без ошибок.
     
  9. mantissa

    mantissa Мембер Команда форума

    Публикаций:
    0
    Регистрация:
    9 сен 2022
    Сообщения:
    167
    операции в целом проводятся только с чистыми функциями, данные отдельно идут, с ними проблем нет.
     
  10. Ahimov

    Ahimov Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    64
    У бинарного кода гранулярность в одну инструкцию, соотв. нужно пройти декодером длин по коду, обрабатывая при этом развилки в флоу типо условных ветвлений.

    Исследование как то показало, что сишный компилер может процедуры обьединять в целях оптимизации, те между ними возможны ветвления.
     
  11. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    887
    Есть же DCOM, запускаем на одном компе клиента, а на другом сервер и через RPC вызываем функцию. Все это нужно правильно настроить, но в конечном итоге все сведется к созданию ActiveX объекта на удаленной машине, маршалинг интерфейсной ссылки в свой поток и вызов через Proxy/Stub маршалинг обычного метода. Вот я делал, даже из vbs будет доступно.
     
  12. mantissa

    mantissa Мембер Команда форума

    Публикаций:
    0
    Регистрация:
    9 сен 2022
    Сообщения:
    167
    Спасибо, посмотрю, хоть там и черт ногу сломит. Но при таком подходе реализация функции все равно на сервере ведь будет? В моем понимании RPC это когда функция хранится в таблице на сервере, с клиента отправляется запрос к серверу - сервер ищет функцию в таблице и если она там есть, то он вызывает ее.
     
  13. alex_dz

    alex_dz Active Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    484
    mantissa в точности описано как пашет Flask :)
     
  14. mantissa

    mantissa Мембер Команда форума

    Публикаций:
    0
    Регистрация:
    9 сен 2022
    Сообщения:
    167
    да.. с яп где есть байт код ваще проблем никаких не возникает. изначально задание было написать такое на джаве, но я подумал возможно ли на СИ такое.. видимо без написания вирт. машины все таки не обойтись, механизм рефлексии необходим.
     
  15. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    887
    Конечно. К серверу отправляется запрос вместе с параметрами, там отрабатывает функция и результат возвращается клиенту. Очевидные плюсы COM в том что все Automation типы поддерживают маршалинг (скалярные типы, строки, массивы, COM объекты) из коробки, а также что сервер может находится хоть на другой машине, хоть в другом процессе, хоть в своем процессе, а также нет проблем с кроссбитностью.
    --- Сообщение объединено, 15 янв 2025 ---
    mantissa, вообще если нужен байткод, то в системе по дефолту есть MSVBVM60 в которой есть интерпретатор байткода, но это полный андок. Я разбирался в свое время - если захотеть то можно захостить эту ВМ у себя и выполнять какой-либо байткод. Плюсы в том что там из коробки работает COM, WINAPI и скорость достаточно высокая.
     
    mantissa нравится это.
  16. alex_dz

    alex_dz Active Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    484
    а почему не CLR/.NET? полный фул опен сорс
    ВМ машина CIL/IL/etc

    MSVBVM60 - ему уже лет 30+
     
  17. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    887
    С ним (CLR/.NET) не знаком. То что ему 27 лет не делает его плохим.
     
  18. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.764
    Именно такие места и нужны, где механизм непонятен, не прозрачен и тп, там и ищут уязвимости. Смотреть на идеальный код, на который никакую атаку не провести не интересно :nea:
     
    mantissa нравится это.