Исходник Гайд LuaJIT libtcc | Пишем на C в Lua

Всем прив. Сначала я о том о сём, а в самом низу как установить

Это очередной мини гайд который теперь требует не только хоть какого-то знания-понимания ffi, но теперь еще и C ☠️
Я думаю часто у кого была мысль вот бы С компилер в ffi.cdef, а не просто эти объявления функций
Недавно я опять об этом подумал и решил что хватит
По этому я подружил libtcc (Tiny C Compiler) и luajit. Теперь lua открылась новая суперсила 🙀

Ну и конечно я подправил все это под свои потребности:
  1. Raw string literal. Используя asm вставки в clang и gcc я привык к raw string literal из С++11 потому что это удобно. Оказывается в стандарте С99 и С11 этого нет, ну и в tcc соотвественно этого тоже нет(странно ведь у него много расширений). Ужаснулся и добавил эту возможность. К сожалению опции -masm=intel для tcc нет, по этому только at&t синтаксис асемблера.
  2. __naked функции. tcc любит безопасность, по этому в каждой функции генерит пролог и эпилог для сохранения стека. В задачах когда нужна только asm вставка это немного мешает, по этому я добавил атрибут __naked для функций
  3. В стандартный набор библиотек добавлены хедеры для работы с d3d9 ну и на всякий luajit
  4. 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))
2. Поделиться из С в Lua. В данном примере функцией
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, которая возвращает то что принимает)
До:
1720099750371.png

После:
1720099781952.png


Установка переместить папку libtcc из архива в папку /moonloader/lib/
 

Вложения

  • libtcc.zip
    599.1 KB · Просмотры: 91
Последнее редактирование: