Краш при использовании системы лицензирования
Краш при использовании системы лицензирования
Минимизировал и прикрепил пример на котором это воспроизводится, библиотека собрана под Linux
Конфиг дефолтный, за исключением включённой системы лицензирования и использованием скрипта https://github.com/CertainLach/vmprotec ... script.lua (TL;DR: на функции начинающиеся с vmprotect_ применяет опции согласно их названию, и удаляет их из экспортов)
Библиотека экспортирует одну функцию - do_the_thing
Функция принимает буфер, первый байт = 4, остальные - лицензионный ключ для системы лицензирования и завершающий \0
При получении лицензионного ключа функция его активирует, делает SetSerialNumber, и если ошибок не было (их логгирует) дёргает функцию защищённую лицензией (lockToKey)
Если передать буфер у которого первый байт = 13, то оно сразу вызывает функцию защищённую лицензией
До применения vmprotect (Запуск с VMProtectSDK заглушками) код успешно работает, если ему передать \x04activationcode\0, то он выведет
```
Op 4
activate license
set serial
call lock by key function
called
```
Падений нет
После применения vmprotect при передаче правильного кода лицензии (\x04aaaa-aaaa-aaaa-aaaa\0) - код получает серийник, но падает на вызове функции под защитой
```
Op 4
activate license
set serial
call lock by key function
terminated by signal SIGSEGV (Address boundary error)
```
Если же не вызывая активацию попробовать вызвать код под лицензией (Аргумент \x0d), то
```
Op 13
# И тут появляется окно zenity с ошибкой
```
Обычные покрытые функции работают правильно (do_the_thing помечена как ultra), падения происходят только на lockByKey.
Конфиг дефолтный, за исключением включённой системы лицензирования и использованием скрипта https://github.com/CertainLach/vmprotec ... script.lua (TL;DR: на функции начинающиеся с vmprotect_ применяет опции согласно их названию, и удаляет их из экспортов)
Библиотека экспортирует одну функцию - do_the_thing
Функция принимает буфер, первый байт = 4, остальные - лицензионный ключ для системы лицензирования и завершающий \0
При получении лицензионного ключа функция его активирует, делает SetSerialNumber, и если ошибок не было (их логгирует) дёргает функцию защищённую лицензией (lockToKey)
Если передать буфер у которого первый байт = 13, то оно сразу вызывает функцию защищённую лицензией
До применения vmprotect (Запуск с VMProtectSDK заглушками) код успешно работает, если ему передать \x04activationcode\0, то он выведет
```
Op 4
activate license
set serial
call lock by key function
called
```
Падений нет
После применения vmprotect при передаче правильного кода лицензии (\x04aaaa-aaaa-aaaa-aaaa\0) - код получает серийник, но падает на вызове функции под защитой
```
Op 4
activate license
set serial
call lock by key function
terminated by signal SIGSEGV (Address boundary error)
```
Если же не вызывая активацию попробовать вызвать код под лицензией (Аргумент \x0d), то
```
Op 13
# И тут появляется окно zenity с ошибкой
```
Обычные покрытые функции работают правильно (do_the_thing помечена как ultra), падения происходят только на lockByKey.
Re: Краш при использовании системы лицензирования
Пример не прикрепляется на форум: https://send.0la.ch/download/530f3a2b3d ... RtF9vvwSZg
Re: Краш при использовании системы лицензирования
Этот код удаляет элемент в том числе и из вектора "exports" и вы проскакиваете следующий item после delete:
Нужно бегать по вектору в обратном направлении.
P.S. В вашем примере нет бинарника, который вызывает вашу SO.
Code: Select all
for i = 1, exports:count() do
if exports:item(i):address() == fn:address() then
bprint("And removing from exports")
exports:delete(i)
break
end
end
P.S. В вашем примере нет бинарника, который вызывает вашу SO.
Re: Краш при использовании системы лицензирования
Похоже что в этом репродюсере проблема действительно с этимЭтот код удаляет элемент в том числе и из вектора "exports" и вы проскакиваете следующий item после delete:
К сожалению в реальном коде это работает несколько иначе, и там функций изначально в .dynsym нет; Значит там другая проблема, переделаю репродюсер.
Однако судя по всему, ElfExports:delete() сейчас не работает, поскольку даже с исправленным скриптом библиотека на выходе падает:
https://github.com/CertainLach/vmprotec ... script.lua
Если экспорты не удалять, то выхлоп работает
Пытался их удалить в нескольких разных хуках, не только в OnBeforeSaveFile, символы из .dynsym успешно исчезают
Код для вызова библиотеки:
Code: Select all
#include <string.h>
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char* argv[]) {
char* libname = argc >= 2 ? argv[1] : "repro.so";
char* action = argc >= 3 ? argv[2] : "";
printf("Loading library %s\n", libname);
void* lib = dlopen(libname, RTLD_NOW);
if (!lib) {
printf("Failed to load lib: %s\n", dlerror());
return 1;
}
printf("Getting export\n");
void* (*do_the_thing)(char*) = dlsym(lib, "do_the_thing");
if (!do_the_thing) {
printf("Failed to find symbol: %s\n", dlerror());
return 1;
}
if (strcmp(action, "activate") == 0) {
if (argc < 4) {
printf("Usage: [lib] activate [code]");
return 1;
}
char* code = argv[3];
char* req = malloc(1 + strlen(code) + 1);
req[0] = 4;
strcpy(req + 1, code);
printf("Activating with code \"%s\"\n", code);
uint16_t* status = do_the_thing(req);
if (status == NULL || *status != 0) {
printf("Activation failed with status %x\n", *status);
return 1;
}
} else if (strcmp(action, "call_locked") == 0) {
char req[1];
req[0] = 13;
printf("Calling locked function\n");
uint16_t* status = do_the_thing(req);
} else {
printf("Unknown action\n");
return 1;
}
printf("Success\n");
return 0;
}
gcc main.c -o main && ./main ./repro.so activate activationcode
Вызов функции с lock by key без активации
gcc main.c -o main && ./main ./repro.so call_locked
Re: Краш при использовании системы лицензирования
Вопрос был не про то, что это является причиной креша, а в том, что ваш код LUA работает неправильно и пропускает один из элементов в exports после delete.
В любом случае ваш функционал можно сделать намного проще, т.к. у exports есть itemByAddress:
Code: Select all
bprint("And queuing for export removal")
local export = file:exports():itemByAddress(fn:address())
if (export) then
bprint("Deleting export " .. export:name() .. " (" .. address:tostring() .. ")")
export:destroy()
end
deent()
Re: Краш при использовании системы лицензирования
Это я понял, в последней версии скрипта это исправленоВопрос был не про то, что это является причиной креша, а в том, что ваш код LUA работает неправильно и пропускает один из элементов в exports после delete.
Однако что исправленный вариант
Code: Select all
for i = exports:count(), 1, -1 do
local export = exports:item(i)
local address = export:address();
if tableHas(toDelete, address) then
bprint("Deleting export " .. export:name() .. " (" .. address:tostring() .. ")")
exports:delete(i)
end
end
Code: Select all
for _, address in ipairs(toDelete) do
local export = exports:itemByAddress(address)
if export then
bprint("Deleting export " .. export:name() .. " (" .. address:tostring() .. ")")
export:destroy()
end
end
Re: Краш при использовании системы лицензирования
Скрипт к падению не имеет никакого отношения. Он у вас просто неправильно работал и все.
Re: Краш при использовании системы лицензирования
Code: Select all
К сожалению в реальном коде это работает несколько иначе
Версия с названиями функций (та что публичная, https://github.com/CertainLach/vmprotect) устроена проще, но в ней для красоты желательно срезать экспорты
Code: Select all
Он у вас просто неправильно работал и все.
Он обходит таблицу exports каждый раз когда нужно удалить экспорт, и как только экспорт найден и удалён - делает break, т.е после удаления не будет проверяться элемент i+1
Я вижу проблему только если бы там было
Code: Select all
for i = 1, exports:count() do
local export = exports:item(i)
local address = export:address();
if tableHas(toDelete, address) then
bprint("Deleting export " .. export:name() .. " (" .. address:tostring() .. ")")
exports:delete(i)
end
end
Re: Краш при использовании системы лицензирования
Да, с break внутри цикла ошибки нет.
Re: Краш при использовании системы лицензирования
Проверяйте 2374 билд.
Re: Краш при использовании системы лицензирования
Спасибо, на репродюсере помогло
Но к сожалению на реальном коде оно всё ещё падает
Приблизил репродюсер к реальному, на нём падает; апи библиотеки аналогичное, послал в ПМ
Но к сожалению на реальном коде оно всё ещё падает
Приблизил репродюсер к реальному, на нём падает; апи библиотеки аналогичное, послал в ПМ
Re: Краш при использовании системы лицензирования
У вас do_the_thing работает через символ "vmprotect_ultra_do_the_thing_inner_186237384678405675810701436432396487933_ptr", который вы удаляете вместе с экспортом:
Code: Select all
.text:000000000007DDC0 public do_the_thing
.text:000000000007DDC0 do_the_thing proc near ; DATA XREF: LOAD:00000000000007F8↑o
.text:000000000007DDC0 ; __unwind {
.text:000000000007DDC0 jmp cs:vmprotect_ultra_do_the_thing_inner_186237384678405675810701436432396487933_ptr
.text:000000000007DDC0 ; } // starts at 7DDC0
.text:000000000007DDC0 do_the_thing endp
Re: Краш при использовании системы лицензирования
Блин, действительно, спасибо.
Надо выкинуть из библиотеки использование экспортов, и по нормальному названию матчить, проблема лишь в том что оно mangled, и vmprotect не может названия обработать
Сделал так, + через FFI подключил demangler, и решил кучу проблем
Было бы однако неплохо если бы сам vmprotect научился это делать. Я так понимаю используемая сейчас библиотека притворяется что умеет demangling Rust символов, однако зачастую у неё ничего не выходит (везде mangled названия)
В Rust дефолтная (legacy) схема mangling не стабильная, а v0 схему нужно включать явно, и её никто не поддерживает
Единственный правильный demangler - https://github.com/rust-lang/rustc-demangle
Надо выкинуть из библиотеки использование экспортов, и по нормальному названию матчить, проблема лишь в том что оно mangled, и vmprotect не может названия обработать
Сделал так, + через FFI подключил demangler, и решил кучу проблем
Было бы однако неплохо если бы сам vmprotect научился это делать. Я так понимаю используемая сейчас библиотека притворяется что умеет demangling Rust символов, однако зачастую у неё ничего не выходит (везде mangled названия)
В Rust дефолтная (legacy) схема mangling не стабильная, а v0 схему нужно включать явно, и её никто не поддерживает
Единственный правильный demangler - https://github.com/rust-lang/rustc-demangle
Code: Select all
local rustc_demangle_lib = vmprotect.openLib("/path/to/librustc_demangle.so")
if not rustc_demangle_lib then
error("failed to open librustc_demangle")
end
local rustc_demangle = rustc_demangle_lib:getFunction("rustc_demangle", "int", "string", "pointer", "size_t")
local c_lib = vmprotect.openLib("/path/to/libc.so.6")
if not c_lib then
error("failed to open libc")
end
local malloc = c_lib:getFunction("malloc", "pointer", "size_t")
local free = c_lib:getFunction("malloc", "void", "pointer")
local strdup = c_lib:getFunction("strdup", "string", "pointer")
function demangle(identifier)
local demangle_buf = malloc(4096)
local res_code = rustc_demangle(identifier, demangle_buf, 4096)
local res = nil
if res_code == 0 then
-- Buffer is too small, or the string is not a valid rust identifier
goto free
end
-- I think memory leak occurs here?.. Haven't found a good way to convert pointer to string in vmprotect lua api, any identity function would work
res = strdup(demangle_buf)
::free::
free(demangle_buf)
return res
end
if demangle("_RNvCskwGfYPst2Cb_3foo16example_function") ~= "foo::example_function" then
error("demangler is not working properly")
end
Re: Краш при использовании системы лицензирования
У вас сейчас там вообще нет никаких символов кроме экспорта.Было бы однако неплохо если бы сам vmprotect научился это делать. Я так понимаю используемая сейчас библиотека притворяется что умеет demangling Rust символов, однако зачастую у неё ничего не выходит (везде mangled названия)
Re: Краш при использовании системы лицензирования
Code: Select all
У вас сейчас там вообще нет никаких символов кроме экспорта.
Сейчас flow в vmprotect rust sdk - функция с маркером
Code: Select all
#[protect(ultra)]
fn add(a: u32, b: u32) -> u32 {
a + b
}
Code: Select all
#[inline(always)]
fn add(a: u32, b: u32) -> u32 {
#[inline(never)]
#[no_mangle]
fn vmprotect_ultra_add_0123456789(a: u32, b: u32) {
a + b
}
vmprotect_ultra_add_0123456789(a, b)
}
Code: Select all
#[no_mangle]
Я собрал бинарь без strip, и убрал
Code: Select all
#[no_mangle]
С таким кодом нужно дополнительно парсить названия
Code: Select all
local name, protinfo = name:match("^(.+)::vmprotect_(.+)::h" .. string.rep("[0-9]", 16) .. "$")