Всем прив. Сначала я о том о сём, а в самом низу как установить
Это очередной мини гайд который теперь требует не только хоть какого-то знания-понимания ffi, но теперь еще и C ☠️
Я думаю часто у кого была мысль вот бы С компилер в ffi.cdef, а не просто эти объявления функций
Недавно я опять об этом подумал и решил что хватит
По этому я подружил libtcc (Tiny C Compiler) и luajit. Теперь lua открылась новая суперсила 🙀
Ну и конечно я подправил все это под свои потребности:
Минимальная документация есть в libtcc.h
А полная документация по TCC и libtcc в интернете, ее много(даже chatgpt может помочь)
Я даю простой пример как работать с этим в мунлоадер
Собственно 2 ключевые потребности из этого примера
1. Поделиться данными из Lua в C. В данном примере функцией
2. Поделиться из С в Lua. В данном примере функцией
Полный пример вот:
Установка переместить папку libtcc из архива в папку /moonloader/lib/
Это очередной мини гайд который теперь требует не только хоть какого-то знания-понимания ffi, но теперь еще и C ☠️
Я думаю часто у кого была мысль вот бы С компилер в ffi.cdef, а не просто эти объявления функций
Недавно я опять об этом подумал и решил что хватит
По этому я подружил libtcc (Tiny C Compiler) и luajit. Теперь lua открылась новая суперсила 🙀
Ну и конечно я подправил все это под свои потребности:
- Raw string literal. Используя asm вставки в clang и gcc я привык к raw string literal из С++11 потому что это удобно. Оказывается в стандарте С99 и С11 этого нет, ну и в tcc соотвественно этого тоже нет(странно ведь у него много расширений). Ужаснулся и добавил эту возможность. К сожалению опции -masm=intel для tcc нет, по этому только at&t синтаксис асемблера.
- __naked функции. tcc любит безопасность, по этому в каждой функции генерит пролог и эпилог для сохранения стека. В задачах когда нужна только asm вставка это немного мешает, по этому я добавил атрибут __naked для функций
- В стандартный набор библиотек добавлены хедеры для работы с d3d9 ну и на всякий luajit
- TCCState закрывается сам, этим занимается ffi.gc. В ситуациях когда надо чтобы С код продолжил жить после завершения lua скрипта, нужно отключить это поведение с помощью ffi.gc(s, nil)
Минимальная документация есть в libtcc.h
А полная документация по TCC и libtcc в интернете, ее много(даже chatgpt может помочь)
Я даю простой пример как работать с этим в мунлоадер
Собственно 2 ключевые потребности из этого примера
1. Поделиться данными из Lua в C. В данном примере функцией
Lua:
В С коде объявляем
extern void print(const char*);
И в Lua коде добавляем
s:add_symbol("print", ffi.cast("void(*)(const char*)", function(str)
print("{00BABe}[C]:{FFFFFF}", ffi.string(str))
end))
C++:
В С коде
int add(int a, int b) {
print(R"(kek
"lol"
mda))");
int result;
asm("addl %1, %0" : "=r"(result) : "r"(a), "0"(b));
return result;
}
В Lua коде
local add = s:get_symbol("add", "int(*)(int, int)");
print("add = ", add, "add(22,11) =", add(22,11))
Lua:
local tcc = require("libtcc")
local ffi = require("ffi")
--tcc.cdef хак чтобы vs code включил подсветку кода С
local prog = tcc.cdef[[
#include <windows.h>
#include <winuser.h>
#include <stdio.h>
#include <stdint.h>
#include <lua.h>
#include <d3d9.h>
extern void print(const char*);
void __thiscall CChat__addEntry(intptr_t this, int type, const char* text, const char* prefix, uint32_t tcolor, uint32_t pcolor) {
char buf[256];
_snprintf(buf, sizeof(buf), "this 0x%X | type %d | text{BABE00} %s {FFFFFF} | prefix %s | tc %X | pc %X", this, type, text, prefix, tcolor, pcolor);
print(buf);
}
void swimFixLogic(uintptr_t esp) {
float pCTimer__ms_fTimeStep = *(float*)0xB7CB5C;
float magic = 1.0f / (pCTimer__ms_fTimeStep / (50.0f / 30.0f));
*(float*)(esp + 0x18) *= magic * 15;
*(float*)(esp + 0x1C) *= magic * 15;
*(float*)(esp + 0x20) *= magic * 15;
}
void __naked swimFix() {
asm(R"(
push %eax
push %ecx
push %edx
mov %esp, %eax
add $0xC, %eax
push %eax
call swimFixLogic
add $4, %esp
pop %edx
pop %ecx
pop %eax
fld %st(1)
fmuls (%eax)
fld %st(2)
jmp 0x0068A514
)");
}
void installHook() {
uintptr_t hook_addr = (uintptr_t)GetModuleHandle("samp.dll") + 0x67460;
DWORD oldProt;
VirtualProtect((void*)hook_addr, 5, PAGE_EXECUTE_READWRITE, &oldProt);
*(uint8_t*)hook_addr = 0xE9;
*(uintptr_t*)(hook_addr + 1) = (uintptr_t)&CChat__addEntry - hook_addr - 5;
VirtualProtect((void*)hook_addr, 5, oldProt, NULL);
hook_addr = 0x68A50E;
VirtualProtect((void*)hook_addr, 6, PAGE_EXECUTE_READWRITE, &oldProt);
*(uint8_t*)hook_addr = 0xE9;
*(uintptr_t*)(hook_addr + 1) = (uintptr_t)&swimFix - hook_addr - 5;
*(uint8_t*)(hook_addr + 5) = 0x90;
VirtualProtect((void*)hook_addr, 6, oldProt, NULL);
print("Хуки установлены");
}
int add(int a, int b) {
print(R"(kek
"lol"
mda))");
int result;
asm("addl %1, %0" : "=r"(result) : "r"(a), "0"(b));
return result;
}
]]
local s = tcc.new()
s:compile_string(prog)
s:add_symbol("print", ffi.cast("void(*)(const char*)", function(str)
print("{00BABe}[C]:{FFFFFF}", ffi.string(str))
end))
s:relocate()
local add = s:get_symbol("add", "int(*)(int, int)");
print("add = ", add, "add(22,11) =", add(22,11))
function main()
while not isSampAvailable() do wait(0) end
local installHook = s:get_symbol("installHook", "void(*)()")
installHook()
wait(-1)
end
Пишем tcc.cdef (vs code тригерится на .cdef по этому я добавил функцию cdef, которая возвращает то что принимает)
До:
После:
До:
После:
Установка переместить папку libtcc из архива в папку /moonloader/lib/
Вложения
Последнее редактирование: