Можно ли как-то получить код функции в рантайме? Хочу сделать что-то типа облачных вычислений. Код (Text): int foo() { return 5 + 5; } int main() { int res = remotexec(foo); } Я думал узнать размер функции, а потом просто получить машинный код, далее как-нибудь его распарсить на принимающем сервере, но комплияторы обычно оптимизируют (общий пролог делают и тд), может есть какие-то средства в Windows API для этого?
Даже не обязательно делать это на голом СИ. Может ли DSL как-то помочь в этом, например с переводом в LLVM IR? Главное, чтобы потом была обратная интеграция с СИ, чтобы отправить код по сокету.
Нет, это фантастика. Сами исходные коды и надо передавать по сети если уж нужно неизвестно что заранее на сервере считать, главное троянов не хапнуть.
Это какой-то новый уровень написания эксплоитоориентированных приложений - исполнять присланный кем-то код на сервере.
короче получилось так: механизм SEH сует информацию о функциях в NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION] у PE32+ достать можно через RtlCaptureContext + RtlLookupFunctionEntry Код (Text): #include <windows.h> #include <dbghelp.h> #include <stdio.h> void printFunctionBytes(DWORD64 imgBase, DWORD64 beginAddr, DWORD64 endAddr) { printf("Function bytes from 0x%llX to 0x%llX:\n", beginAddr + imgBase, endAddr + imgBase); for (DWORD64 addr = beginAddr; addr < endAddr; addr++) { unsigned char byte; if (ReadProcessMemory(GetCurrentProcess(), (LPVOID)(imgBase + addr), &byte, 1, NULL)) { printf("%02X ", byte); } if ((addr - beginAddr + 1) % 16 == 0) { printf("\n"); } } printf("\n"); } int foo(int x, int y, int* size) { CONTEXT con = { 0 }; RtlCaptureContext(&con); DWORD64 ImgBase = 0; RUNTIME_FUNCTION* pRTFn = RtlLookupFunctionEntry(con.Rip, &ImgBase, NULL); size_t nFnSz = 0; if (pRTFn) { // Выводим начало функции printf("Function start address (by API): 0x%p\n", ImgBase + pRTFn->BeginAddress); nFnSz = pRTFn->EndAddress - pRTFn->BeginAddress; // Выводим байты функции printFunctionBytes(ImgBase, pRTFn->BeginAddress, pRTFn->EndAddress); } else { printf("Function entry not found.\n"); } *size = (int)nFnSz; return x + y; } int main() { int size = 0; int result = foo(5, 10, &size); printf("Size of the function: %d\n", size); printf("ptr foo %p\n", foo); printf("Result of foo: %d\n", result); return 0; } правда в функции придется таскать портянку, но ее можно будет исполнить два раза, первый для получения инфы, а второй для результата кстати почему-то значения ImgBase + pRTFn->BeginAddress и printf("ptr foo %p\n", foo); не совпадают
да, это не проблема, если код задавать в виде строки или файла, задача именно обеспечить маршалинг и данных и кода, а для клиента это будет обычный вызов ф-ции обернутой в макрос или другую ф-цию. как в питоне например сначала Код (Text): import pickle import socket def remote_function(a, b): return a + b func_data = pickle.dumps(remote_function) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect(('localhost', 12345)) s.sendall(func_data) потом Код (Text): import pickle import socket with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind(('localhost', 12345)) s.listen(1) conn, addr = s.accept() with conn: data = conn.recv(1024) func = pickle.loads(data) result = func(5, 10) print(f'Result from remote function: {result}')
Для чего знать длину процедуры ? Процедуру как строку нельзя скопировать. Процедура содержит данные, смещения/адреса их, части процедуры разнесены в памяти, в общем это сложный обьект в памяти и описывается cfg. Все манипуляции нужно выполнять с модулем, а не пытаться его разобрать на части. Это между прочим весьма сложная задача и не без статистики(код от данных отличить), а значит не может быть решена без ошибок.
У бинарного кода гранулярность в одну инструкцию, соотв. нужно пройти декодером длин по коду, обрабатывая при этом развилки в флоу типо условных ветвлений. Исследование как то показало, что сишный компилер может процедуры обьединять в целях оптимизации, те между ними возможны ветвления.
Есть же DCOM, запускаем на одном компе клиента, а на другом сервер и через RPC вызываем функцию. Все это нужно правильно настроить, но в конечном итоге все сведется к созданию ActiveX объекта на удаленной машине, маршалинг интерфейсной ссылки в свой поток и вызов через Proxy/Stub маршалинг обычного метода. Вот я делал, даже из vbs будет доступно.
Спасибо, посмотрю, хоть там и черт ногу сломит. Но при таком подходе реализация функции все равно на сервере ведь будет? В моем понимании RPC это когда функция хранится в таблице на сервере, с клиента отправляется запрос к серверу - сервер ищет функцию в таблице и если она там есть, то он вызывает ее.
да.. с яп где есть байт код ваще проблем никаких не возникает. изначально задание было написать такое на джаве, но я подумал возможно ли на СИ такое.. видимо без написания вирт. машины все таки не обойтись, механизм рефлексии необходим.
Конечно. К серверу отправляется запрос вместе с параметрами, там отрабатывает функция и результат возвращается клиенту. Очевидные плюсы COM в том что все Automation типы поддерживают маршалинг (скалярные типы, строки, массивы, COM объекты) из коробки, а также что сервер может находится хоть на другой машине, хоть в другом процессе, хоть в своем процессе, а также нет проблем с кроссбитностью. --- Сообщение объединено, 15 янв 2025 --- mantissa, вообще если нужен байткод, то в системе по дефолту есть MSVBVM60 в которой есть интерпретатор байткода, но это полный андок. Я разбирался в свое время - если захотеть то можно захостить эту ВМ у себя и выполнять какой-либо байткод. Плюсы в том что там из коробки работает COM, WINAPI и скорость достаточно высокая.
Именно такие места и нужны, где механизм непонятен, не прозрачен и тп, там и ищут уязвимости. Смотреть на идеальный код, на который никакую атаку не провести не интересно