commit ae3c87bc0626a59a4244eb59aa572bceba2b25bb Author: Egor00f Date: Wed Dec 17 12:35:34 2025 +0500 create it покачто не умеет открывать зависимости других библиотек diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..219f1ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.a +*.o +*.dll +*.kex diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..08bd6eb --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,23 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/include", + "/home/autobuild/tools/win32/include", + "/home/autobuild/tools/win32/lib/gcc/mingw32/5.4.0/include", + "${workspaceFolder}/../kolibrios/contrib/C_Layer/INCLUDE" + ], + "defines": [], + "compilerPath": "/home/autobuild/tools/win32/bin/kos32-gcc", + "compilerArgs": [ + "-nostdinc -fno-builtin -fno-ident -fomit-frame-pointer -DMISSING_SYSCALL_NAMES -U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 -std=c11" + ], + "cStandard": "c11", + "cppStandard": "c++11", + "intelliSenseMode": "linux-gcc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..04dd796 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,32 @@ +{ + "editor.insertSpaces": false, + "cSpell.words": [ + "dlfcn", + "dlloader", + "dlopen", + "ksys" + ], + "files.associations": { + "ksys.h": "c", + "cstdio": "cpp", + "exception": "cpp", + "optional": "cpp", + "random": "cpp", + "new": "cpp", + "type_traits": "cpp", + "array": "cpp", + "*.tcc": "cpp", + "string": "cpp", + "iomanip": "cpp", + "istream": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "algorithm": "cpp", + "cmath": "cpp", + "kolibri_libini.h": "c", + "dlfcn.h": "c", + "list": "c", + "format": "c", + "thread": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ee460f8 --- /dev/null +++ b/Makefile @@ -0,0 +1,82 @@ +NAME=dlopen + +CC=kos32-gcc +LD=kos32-ld +STRIP=kos32-strip +OBJCOPY=kos32-objcopy + + +MYCFLAGS = +MYLDFLAGS = +DEBUG_INFO=0 + +CFLAGS= -O2 -Wall -Iinclude -std=c11 -DDEBUG_INFO=$(DEBUG_INFO) $(MYCFLAGS) $(SYSCFLAGS) +AR= kos32-ar rcu +RANLIB= ranlib +RM= rm -f +LIBS= $(MYLIBS) $(SYSLIBS) + + +STATIC_NAME=$(NAME).a + +DLL_NAME=$(NAME).dll +DLL_IMPL=$(DLL_NAME).a + +ALL_A= $(STATIC_NAME) +ALL_DLL=$(DLL_NAME) $(DLL_IMPL) + +ALL_TESTS= test.kex + +ALL_BIN=$(ALL_A) $(ALL_DLL) $(ALL_TESTS) + + +######### + +ifeq ($(OS),Windows_NT) + TOOLCHAIN_PATH=C:/MinGW/msys/1.0/home/autobuild/tools/win32 +else + TOOLCHAIN_PATH=/home/autobuild/tools/win32 +endif + +SYSCFLAGS= -nostdinc -fno-builtin -fno-ident -fomit-frame-pointer \ + -U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 \ + -I$(TOOLCHAIN_PATH)/lib/gcc/mingw32/5.4.0/include -I$(TOOLCHAIN_PATH)/lib/gcc/mingw32/5.4.0/include-fixed -I$(TOOLCHAIN_PATH)/include +SYSLDFLAGS=--image-base 0 -Tapp-dynamic.lds +SYSLIBS=-nostdlib -L$(TOOLCHAIN_PATH)/mingw32/lib -lgcc -lc.dll -ldll + +######### + +OBJECTS = src/dlopen.o src/loader.o src/sha256.o +#../kolibrios/contrib/C_Layer/OBJ/loadlibini.obj + +default: $(ALL_BIN) + + + +$(STATIC_NAME): $(OBJECTS) + $(AR) $@ $? + +$(DLL_NAME): $(OBJECTS) + $(LD) -shared -T dll.lds --entry _DllStartup -o $@ $^ --out-implib $(DLL_IMPL) $(LIBS) + +$(DLL_IMPL): $(DLL_NAME) + + +test.kex: tests/test.o dlopen.a + $(LD) -o $@ $(SYSLDFLAGS) $(MYLDFLAGS) $^ $(LIBS) + $(STRIP) -S $@ + $(OBJCOPY) $@ -O binary + + +clean: + rm -f $(OBJECTS) $(ALL_BIN) + +# deps + +tests/test.o: tests/test.c include/dlfcn.h src/loader.h + +src/dlopen.o: src/dlopen.c include/dlfcn.h +src/loader.o: src/loader.c src/loader.h src/sha256.h +src/loader.h: src/pe.h +src/sha256.o: src/sha256.c src/sha256.h + diff --git a/README.md b/README.md new file mode 100644 index 0000000..3d9187a --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# DLopen for kolibriOS + +Умеет загружать `dll` и `obj`, расшаривать `dll`. + +Загрузчик `PE` основан на том, что в newlib. Использует [Функцию 68, подфункцию 22](https://git.kolibrios.org/KolibriOS/kolibrios/src/commit/c17d1a57a313968946d166ac25d8a0d117f85a94/kernel/trunk/docs/sysfuncr.txt#L3497) для расшаривания diff --git a/include/dlfcn.h b/include/dlfcn.h new file mode 100644 index 0000000..fdcc932 --- /dev/null +++ b/include/dlfcn.h @@ -0,0 +1,78 @@ +#ifndef _DLFCN_H +#define _DLFCN_H 1 + +#include + +enum DLOPEN_FLAGS +{ + /* + Perform lazy binding. Resolve symbols only as the code + that references them is executed. If the symbol is never + referenced, then it is never resolved. (Lazy binding is + performed only for function references; references to + variables are always immediately bound when the shared + object is loaded.). + */ + RTLD_LAZY, + + /* + If this value is specified, or the environment variable + LD_BIND_NOW is set to a nonempty string, all undefined + symbols in the shared object are resolved before dlopen() + returns. If this cannot be done, an error is returned. + + Zero or more of the following values may also be ORed in flags: + */ + RTLD_NOW, + + /* + The symbols defined by this shared object will be made + available for symbol resolution of subsequently loaded + shared objects. + */ + RTLD_GLOBAL, + + /* + This is the converse of RTLD_GLOBAL, and the default if + neither flag is specified. Symbols defined in this shared + object are not made available to resolve references in + subsequently loaded shared objects. + */ + RTLD_LOCAL, + + /* + Do not unload the shared object during dlclose(). + Consequently, the object's static and global variables are + not reinitialized if the object is reloaded with dlopen() + at a later time. + */ + RTLD_NODELETE, + + /* + Don't load the shared object. This can be used to test if + the object is already resident (dlopen() returns NULL if it + is not, or the object's handle if it is resident). This + flag can also be used to promote the flags on a shared + object that is already loaded. For example, a shared + object that was previously loaded with RTLD_LOCAL can be + reopened with RTLD_NOLOAD | RTLD_GLOBAL. + */ + RTLD_NOLOAD, + + /* + Place the lookup scope of the symbols in this shared object + ahead of the global scope. This means that a self- + contained object will use its own symbols in preference to + global symbols with the same name contained in objects that + have already been loaded. + */ + RTLD_DEEPBIND +}; + +void *dlopen(const char *filename, int flag); +const char *dlerror(void); +void *dlsym(void *handle, char *symbol); +int dlclose(void *handle); + + +#endif // _DLFCN_H diff --git a/src/dlopen.c b/src/dlopen.c new file mode 100644 index 0000000..40d2caf --- /dev/null +++ b/src/dlopen.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include "loader.h" + +enum TYPE +{ + OBJ, + DLL +}; + +struct dll +{ + enum TYPE t; + uint8_t flags; + void *h; +}; + +void *dlopen(const char *filename, int flag) +{ + struct dll *dll = _ksys_alloc(sizeof(dll)); + dll->flags = flag; + + char *e = strrchr(filename, '.') + 1; + if (strcmp(e, "dll") == 0) + { + printf("load dll: %s\n", filename); + dll->t = DLL; + dll->h = load_PE_dll(filename); + } + else if (strcmp(e, "obj") == 0) + { + printf("load obj: %s\n", filename); + dll->t = OBJ; + dll->h = _ksys_dlopen(filename); + } + else + { + _ksys_free(dll); + return NULL; + } + + return dll; +} + +const char *dlerror(void) +{ + return dll_err; +} + +void *dlsym(void *handle, char *symbol) +{ + void *f = NULL; + switch (((struct dll *)handle)->t) + { + case DLL: + f = get_pe_proc(((struct dll *)handle)->h, symbol); + break; + case OBJ: + f = _ksys_dlsym(((struct dll *)handle)->h, symbol); + break; + default: + break; + } + + return f; +} + +int dlclose(void *handle) +{ + if (((struct dll *)handle)->flags == RTLD_NODELETE) + { + switch (((struct dll *)handle)->t) + { + case DLL: + + break; + case OBJ: + _ksys_free(((struct dll *)handle)->h); + break; + default: + break; + } + } +} diff --git a/src/loader.c b/src/loader.c new file mode 100644 index 0000000..5a7eeac --- /dev/null +++ b/src/loader.c @@ -0,0 +1,580 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "loader.h" +#include "sha256.h" + +#define unlikely(x) __builtin_expect(!!(x), 0) + +char *dll_err; + +#define DBG_OUT(format, ...) printf(format, __VA_ARGS__) +#define _DBG_ERR(format, ...) sprintf(dll_err, format, __VA_ARGS__); +#if DEBUG_INFO +#define DBG_ERR(format, ...) _DBG_ERR(format, __VA_ARGS__) DBG_OUT(format, __VA_ARGS__); +#define DBG(format, ...) DBG_OUT(format, __VA_ARGS__) +#else +#define DBG_ERR(format, ...) _DBG_ERR(format, __VA_ARGS__) +#define DBG(format, ...) +#endif + +static inline int IsPowerOf2(uint32_t val) +{ + if (val == 0) + return 0; + return (val & (val - 1)) == 0; +} + +int validate_pe(void *raw, size_t raw_size, int is_exec) +{ + PIMAGE_DOS_HEADER dos; + PIMAGE_NT_HEADERS32 nt; + + dos = (PIMAGE_DOS_HEADER)raw; + + if (!raw || raw_size < sizeof(IMAGE_DOS_HEADER)) + return 0; + + if (dos->e_magic != IMAGE_DOS_SIGNATURE || dos->e_lfanew <= 0) + return 0; + + nt = MakePtr(PIMAGE_NT_HEADERS32, dos, dos->e_lfanew); + + if ((uint32_t)nt < (uint32_t)raw) + return 0; + + if (nt->Signature != IMAGE_NT_SIGNATURE) + return 0; + + if (nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) + return 0; + + if (is_exec && (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)) + return 0; + + if (nt->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) + return 0; + + if (is_exec && nt->OptionalHeader.ImageBase != 0) + return 0; + + if (nt->OptionalHeader.SectionAlignment < 4096) + { + if (nt->OptionalHeader.FileAlignment != nt->OptionalHeader.SectionAlignment) + return 0; + } + else if (nt->OptionalHeader.SectionAlignment < nt->OptionalHeader.FileAlignment) + return 0; + + if (!IsPowerOf2(nt->OptionalHeader.SectionAlignment) || + !IsPowerOf2(nt->OptionalHeader.FileAlignment)) + return 0; + + if (nt->FileHeader.NumberOfSections > 96) + return 0; + + return 1; +} + +static inline void sec_copy(void *dst, void *src, size_t len) +{ + __asm__ __volatile__( + "shrl $2, %%ecx \n\t" + "rep movsl" + : + : "c"(len), "S"(src), "D"(dst) + : "cc"); + __asm__ __volatile__( + "" ::: "ecx", "esi", "edi"); +}; + +static const char *fixName(const char *path) +{ + size_t l = strlen(path); + if (l < 31) + { + return path; + } + else // кароч кринж попытка впихнуть большой путь в маленькую строку + { // в теории должно работать, если в пути <= 15 папок и впринципе они даже будут уникальными + char *ret = _ksys_alloc(32); + + sha256_string(path, ret); + + return ret; + } +} + +static void *create_image(void *raw, const char *path) +{ + PIMAGE_DOS_HEADER dos; + PIMAGE_NT_HEADERS32 nt; + PIMAGE_SECTION_HEADER img_sec; + + void *img_base; + uint32_t sec_align; + int i; + + dos = (PIMAGE_DOS_HEADER)raw; + nt = MakePtr(PIMAGE_NT_HEADERS32, dos, dos->e_lfanew); + + char *Name = (char *)fixName(path); + + int err = _ksys_shm_open(Name, KSYS_SHM_CREATE, nt->OptionalHeader.SizeOfImage, (char **)&img_base); + + DBG("shm err: %d\n", err); + + if (err == 10 || err == nt->OptionalHeader.SizeOfImage /* этого в доках нет, но экспирементально подтверждается */) + { + DBG("shm err: %d\n", _ksys_shm_open(Name, KSYS_SHM_OPEN, nt->OptionalHeader.SizeOfImage, (char **)&img_base)); + } + else if (unlikely(img_base != NULL)) + { + + sec_copy(img_base, raw, nt->OptionalHeader.SizeOfHeaders); + + img_sec = MakePtr(PIMAGE_SECTION_HEADER, nt, sizeof(IMAGE_NT_HEADERS32)); + + sec_align = nt->OptionalHeader.SectionAlignment; + + for (i = 0; i < nt->FileHeader.NumberOfSections; i++) + { + void *src_ptr; + void *dest_ptr; + size_t sec_size; + + if (img_sec->SizeOfRawData && img_sec->PointerToRawData) + { + src_ptr = MakePtr(void *, raw, img_sec->PointerToRawData); + dest_ptr = MakePtr(void *, img_base, img_sec->VirtualAddress); + sec_copy(dest_ptr, src_ptr, img_sec->SizeOfRawData); + }; + + img_sec++; + }; + + if (nt->OptionalHeader.DataDirectory[5].Size) + { + PIMAGE_BASE_RELOCATION reloc; + + uint32_t delta = (uint32_t)img_base - nt->OptionalHeader.ImageBase; + + reloc = MakePtr(PIMAGE_BASE_RELOCATION, img_base, + nt->OptionalHeader.DataDirectory[5].VirtualAddress); + + while (reloc->SizeOfBlock != 0) + { + uint32_t cnt; + uint16_t *entry; + uint16_t reltype; + uint32_t offs; + + cnt = (reloc->SizeOfBlock - sizeof(*reloc)) / sizeof(uint16_t); + entry = MakePtr(uint16_t *, reloc, sizeof(*reloc)); + + for (i = 0; i < cnt; i++) + { + uint16_t *p16; + uint32_t *p32; + + reltype = (*entry & 0xF000) >> 12; + offs = (*entry & 0x0FFF) + reloc->VirtualAddress; + switch (reltype) + { + case 1: + p16 = MakePtr(uint16_t *, img_base, offs); + *p16 += (uint16_t)(delta >> 16); + break; + case 2: + p16 = MakePtr(uint16_t *, img_base, offs); + *p16 += (uint16_t)delta; + break; + case 3: + p32 = MakePtr(uint32_t *, img_base, offs); + *p32 += delta; + } + entry++; + } + reloc = MakePtr(PIMAGE_BASE_RELOCATION, reloc, reloc->SizeOfBlock); + } + }; + } + + return img_base; +}; + +static int link_image(void *img_base, PIMAGE_IMPORT_DESCRIPTOR imp) +{ + static jmp_buf loader_env; + static int recursion = -1; + int warn = 0; + + recursion++; + if (!recursion) + { + if (unlikely(setjmp(loader_env) != 0)) + { + recursion = -1; + return 0; + }; + }; + + while (imp->Name) + { + PIMAGE_DOS_HEADER expdos; + PIMAGE_NT_HEADERS32 expnt; + PIMAGE_EXPORT_DIRECTORY exp; + PIMAGE_THUNK_DATA32 thunk; + + void **iat; + char *libname; + uint32_t *exp_functions; + uint16_t *exp_ordinals; + char **exp_names; + + const module_t *api; + + libname = MakePtr(char *, imp->Name, img_base); + + DBG("import from %s\n", libname); + + api = load_PE_dll(libname); + if (unlikely(api == NULL)) + { + DBG(dll_err, "library %s not found\n", libname); + longjmp(loader_env, 1); + } + + iat = MakePtr(void **, imp->FirstThunk, img_base); + + if (imp->OriginalFirstThunk != 0) + { + thunk = MakePtr(PIMAGE_THUNK_DATA32, imp->OriginalFirstThunk, img_base); + } + else + { + thunk = MakePtr(PIMAGE_THUNK_DATA32, imp->FirstThunk, img_base); + }; + + exp = api->img_exp; + + exp_functions = MakePtr(uint32_t *, exp->AddressOfFunctions, api->start); + exp_ordinals = MakePtr(uint16_t *, exp->AddressOfNameOrdinals, api->start); + exp_names = MakePtr(char **, exp->AddressOfNames, api->start); + + while (thunk->u1.AddressOfData != 0) + { + PIMAGE_IMPORT_BY_NAME imp_name; + + if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) + { + // ordinal = (*func_list) & 0x7fffffff; + // *ImportAddressList = LdrGetExportByOrdinal(ImportedModule->DllBase, Ordinal); + // if ((*ImportAddressList) == NULL) + // { + // DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullDllName); + // RtlpRaiseImportNotFound(NULL, Ordinal, &ImportedModule->FullDllName); + // return STATUS_ENTRYPOINT_NOT_FOUND; + // } + } + else + { + char *export_name; + uint16_t ordinal; + void *function; + uint32_t minn; + uint32_t maxn; + + imp_name = MakePtr(PIMAGE_IMPORT_BY_NAME, + thunk->u1.AddressOfData, img_base); + *iat = NULL; + + DBG("import %s", imp_name->Name); + + if (imp_name->Hint < exp->NumberOfNames) + { + export_name = MakePtr(char *, exp_names[imp_name->Hint], + api->start); + if (strcmp(imp_name->Name, export_name) == 0) + { + ordinal = exp_ordinals[imp_name->Hint]; + function = MakePtr(void *, exp_functions[ordinal], api->start); + if ((uint32_t)function >= (uint32_t)exp) + { + printf("forward %s\n", function); + warn = 1; + } + else + { + DBG(" \t\tat %x\n", function); + *iat = function; + }; + thunk++; // Advance to next thunk + iat++; + continue; + }; + }; + + minn = 0; + maxn = exp->NumberOfNames - 1; + while (minn <= maxn) + { + int mid; + int res; + + mid = (minn + maxn) / 2; + + export_name = MakePtr(char *, exp_names[mid], api->start); + + res = strcmp(export_name, imp_name->Name); + if (res == 0) + { + ordinal = exp_ordinals[mid]; + function = MakePtr(void *, exp_functions[ordinal], api->start); + + if ((uint32_t)function >= (uint32_t)exp) + { + DBG("forward %s\n", function); + warn = 1; + } + else + { + DBG(" \t\tat %x\n", function); + *iat = function; + }; + break; + } + else if (minn == maxn) + { + DBG_ERR("unresolved %s\n", imp_name->Name); + warn = 1; + break; + } + else if (res > 0) + { + maxn = mid - 1; + } + else + { + minn = mid + 1; + } + }; + }; + thunk++; // Advance to next thunk + iat++; + } + imp++; // advance to next IMAGE_IMPORT_DESCRIPTOR + }; + + recursion--; + + if (!warn) + return 1; + else + return 0; +} + +static void *get_entry_point(void *raw) +{ + PIMAGE_DOS_HEADER dos; + PIMAGE_NT_HEADERS32 nt; + + dos = (PIMAGE_DOS_HEADER)raw; + nt = MakePtr(PIMAGE_NT_HEADERS32, dos, dos->e_lfanew); + + return MakePtr(void *, raw, nt->OptionalHeader.AddressOfEntryPoint); +}; + +static void *load_lib_internal(const char *path) +{ + PIMAGE_DOS_HEADER dos; + PIMAGE_NT_HEADERS32 nt; + PIMAGE_EXPORT_DIRECTORY exp; + + ksys_ufile_t uf; + void *raw_img; + size_t raw_size; + void *img_base = NULL; + + uf = _ksys_load_file(path); + raw_img = uf.data; + raw_size = uf.size; + + if (raw_img == NULL) + { + DBG_ERR("fail load file: %s", path); + return NULL; + } + + if (validate_pe(raw_img, raw_size, 0) == 0) // абасрамс + { + DBG_ERR("invalide module %s\n", path); + } + else + { + img_base = create_image(raw_img, path); + if (unlikely(img_base == NULL)) + { + DBG_ERR("cannot create image %s\n", path); + } + } + + _ksys_free(raw_img); + + return img_base; +} + +void *get_pe_proc(void *handle, const char *proc_name) +{ + module_t *module = handle; + PIMAGE_DOS_HEADER expdos; + PIMAGE_NT_HEADERS32 expnt; + PIMAGE_EXPORT_DIRECTORY exp; + + uint32_t *exp_functions; + uint16_t *exp_ordinals; + char **exp_names; + + int minn, maxn; + char *export_name; + uint16_t ordinal; + void *function = NULL; + + exp = module->img_exp; + + exp_functions = MakePtr(uint32_t *, exp->AddressOfFunctions, module->start); + exp_ordinals = MakePtr(uint16_t *, exp->AddressOfNameOrdinals, module->start); + exp_names = MakePtr(char **, exp->AddressOfNames, module->start); + + minn = 0; + maxn = exp->NumberOfNames - 1; + while (minn <= maxn) + { + int mid; + int res; + + mid = (minn + maxn) / 2; + + export_name = MakePtr(char *, exp_names[mid], module->start); + + res = strcmp(export_name, proc_name); + if (res == 0) + { + ordinal = exp_ordinals[mid]; + function = MakePtr(void *, exp_functions[ordinal], module->start); + + if ((uint32_t)function >= (uint32_t)exp) + { + DBG("forward %s\n", function); + } + else + { + DBG(" \t\tat %x\n", function); + }; + break; + } + else if (minn == maxn) + { + DBG("unresolved %s\n", proc_name); + break; + } + else if (res > 0) + { + maxn = mid - 1; + } + else + { + minn = mid + 1; + } + }; + + return function; +} + +void *load_PE_dll(const char *name) +{ + PIMAGE_DOS_HEADER dos; + PIMAGE_NT_HEADERS32 nt; + PIMAGE_EXPORT_DIRECTORY exp; + + module_t *module, *mod; + dll_path_t *dllpath; + const char *path = name; + int len; + char *libname, *tmp; + void *img_base; + + img_base = load_lib_internal(path); + + if (unlikely(img_base == NULL)) + { + DBG_ERR("dll_err, unable to load %s\n", name); + return 0; + }; + + module = malloc(sizeof(module_t)); + + if (unlikely(module == NULL)) + { + DBG_ERR("%s epic fail: no enough memory\n", __FUNCTION__); + goto err1; + } + + module->img_name = strdup(libname); + module->img_path = strdup(path); + module->start = img_base; + module->entry = get_entry_point(img_base); + module->refcount = 1; + + dos = (PIMAGE_DOS_HEADER)img_base; + nt = MakePtr(PIMAGE_NT_HEADERS32, dos, dos->e_lfanew); + exp = MakePtr(PIMAGE_EXPORT_DIRECTORY, img_base, + nt->OptionalHeader.DataDirectory[0].VirtualAddress); + + module->end = MakePtr(char *, img_base, nt->OptionalHeader.SizeOfImage); + + module->img_hdr = nt; + module->img_sec = MakePtr(PIMAGE_SECTION_HEADER, nt, sizeof(IMAGE_NT_HEADERS32)); + module->img_exp = MakePtr(PIMAGE_EXPORT_DIRECTORY, img_base, + nt->OptionalHeader.DataDirectory[0].VirtualAddress); + + if (nt->OptionalHeader.DataDirectory[1].Size) + { + PIMAGE_IMPORT_DESCRIPTOR imp; + int (*dll_startup)(module_t *mod, uint32_t reason); + + imp = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, img_base, + nt->OptionalHeader.DataDirectory[1].VirtualAddress); + + if (link_image(img_base, imp) == 0) + goto err2; + + dll_startup = get_pe_proc(module, "DllStartup"); + if (dll_startup) + { + if (0 == dll_startup(module, 1)) + goto err2; + } + }; + +#ifdef DEBUG_INFO + printf("module %s %p - %p\n", name, module->start, module->end); +#endif + return module; + +err2: + free(module->img_name); + free(module->img_path); + free(module); +err1: + _ksys_free(img_base); + return NULL; +}; diff --git a/src/loader.h b/src/loader.h new file mode 100644 index 0000000..585ed2a --- /dev/null +++ b/src/loader.h @@ -0,0 +1,39 @@ +#ifndef __LOADER_H__ +#define __LOADER_H__ + +#include "pe.h" + +extern char *dll_err; + +void *get_pe_proc(void *handle, const char *proc_name); +void *load_PE_dll(const char *name); + +extern char *__appenv; +extern int __appenv_size; + +typedef struct tag_module module_t; + +struct tag_module +{ + char *img_name; + char *img_path; + + uint32_t refcount; + + char *start; + char *end; + + void *entry; + + PIMAGE_NT_HEADERS32 img_hdr; + PIMAGE_SECTION_HEADER img_sec; + PIMAGE_EXPORT_DIRECTORY img_exp; +}; + +typedef struct +{ + char *path; + int path_len; +} dll_path_t; + +#endif // __LOADER_H__ \ No newline at end of file diff --git a/src/pe.h b/src/pe.h new file mode 100644 index 0000000..da9a7c4 --- /dev/null +++ b/src/pe.h @@ -0,0 +1,187 @@ + +typedef unsigned short WORD; +typedef unsigned int DWORD; +typedef unsigned int LONG; +typedef unsigned char BYTE; + +#define IMAGE_DOS_SIGNATURE 0x5A4D +#define IMAGE_NT_SIGNATURE 0x00004550 +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b + +#pragma pack(push, 2) +typedef struct _IMAGE_DOS_HEADER +{ + WORD e_magic; + WORD e_cblp; + WORD e_cp; + WORD e_crlc; + WORD e_cparhdr; + WORD e_minalloc; + WORD e_maxalloc; + WORD e_ss; + WORD e_sp; + WORD e_csum; + WORD e_ip; + WORD e_cs; + WORD e_lfarlc; + WORD e_ovno; + WORD e_res[4]; + WORD e_oemid; + WORD e_oeminfo; + WORD e_res2[10]; + LONG e_lfanew; +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; +#pragma pack(pop) + +#pragma pack(push, 4) +typedef struct _IMAGE_FILE_HEADER +{ + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +#define IMAGE_FILE_DLL 0x2000 + +#define IMAGE_FILE_MACHINE_I386 0x014c /* Intel 386 or later processors \ + and compatible processors */ +typedef struct _IMAGE_DATA_DIRECTORY +{ + DWORD VirtualAddress; + DWORD Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +typedef struct _IMAGE_OPTIONAL_HEADER +{ + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; + +#pragma pack(pop) + +#pragma pack(push, 4) +typedef struct _IMAGE_NT_HEADERS +{ + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER OptionalHeader; +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; + +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct _IMAGE_SECTION_HEADER +{ + BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; + union + { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; +#pragma pack(pop) + +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +#pragma pack(push, 4) +typedef struct _IMAGE_BASE_RELOCATION +{ + DWORD VirtualAddress; + DWORD SizeOfBlock; +} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION; +#pragma pack(pop) + +typedef struct _IMAGE_IMPORT_DESCRIPTOR +{ + union + { + DWORD Characteristics; + DWORD OriginalFirstThunk; + }; + DWORD TimeDateStamp; + DWORD ForwarderChain; + DWORD Name; + DWORD FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; + +typedef struct _IMAGE_THUNK_DATA32 +{ + union + { + DWORD ForwarderString; + DWORD Function; + DWORD Ordinal; + DWORD AddressOfData; + } u1; +} IMAGE_THUNK_DATA32, *PIMAGE_THUNK_DATA32; + +typedef struct _IMAGE_IMPORT_BY_NAME +{ + WORD Hint; + BYTE Name[1]; +} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; + +#define IMAGE_ORDINAL_FLAG 0x80000000 + +typedef struct _IMAGE_EXPORT_DIRECTORY +{ + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; + DWORD AddressOfNames; + DWORD AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + +#define MakePtr(cast, ptr, addValue) (cast)((uint32_t)(ptr) + (uint32_t)(addValue)) diff --git a/src/sha256.c b/src/sha256.c new file mode 100644 index 0000000..5169fec --- /dev/null +++ b/src/sha256.c @@ -0,0 +1,188 @@ + +#include "sha256.h" +#include // Для memcpy, memset +#include // Для snprintf в bytes_to_hex + +// --- Внутренние макросы и константы SHA-256 --- + +// Ротации +#define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) + +// Логические функции +#define Ch(x, y, z) (((x) & (y)) ^ (~(x) & (z))) +#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define SIGMA0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define SIGMA1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define sigma0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ ((x) >> 3)) +#define sigma1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ ((x) >> 10)) + +// Начальные значения хеша (H0-H7) +static const uint32_t H_INIT[8] = { + 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, + 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL}; + +// Константы раундов (K0-K63) +static const uint32_t K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL}; + +// --- Вспомогательные функции --- + +// Обработка одного 64-байтового блока +static void sha256_transform(uint32_t H[8], const uint8_t block[64]) +{ + uint32_t W[64]; + uint32_t a, b, c, d, e, f, g, h; + uint32_t t1, t2; + int i; + + // 1. Преобразование 16 32-битных слов из блока (big-endian) + for (i = 0; i < 16; i++) + { + W[i] = (uint32_t)block[i * 4] << 24 | + (uint32_t)block[i * 4 + 1] << 16 | + (uint32_t)block[i * 4 + 2] << 8 | + (uint32_t)block[i * 4 + 3]; + } + + // 2. Расширение до 64 слов + for (i = 16; i < 64; i++) + { + W[i] = sigma1(W[i - 2]) + W[i - 7] + sigma0(W[i - 15]) + W[i - 16]; + } + + // 3. Инициализация рабочих переменных + a = H[0]; + b = H[1]; + c = H[2]; + d = H[3]; + e = H[4]; + f = H[5]; + g = H[6]; + h = H[7]; + + // 4. Основной цикл (64 раунда) + for (i = 0; i < 64; i++) + { + t1 = h + SIGMA1(e) + Ch(e, f, g) + K[i] + W[i]; + t2 = SIGMA0(a) + Maj(a, b, c); + + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + // 5. Добавление результатов к текущему хешу + H[0] += a; + H[1] += b; + H[2] += c; + H[3] += d; + H[4] += e; + H[5] += f; + H[6] += g; + H[7] += h; +} + +// --- API функции --- + +void sha256_init(SHA256_CTX *ctx) +{ + memcpy(ctx->H, H_INIT, sizeof(H_INIT)); + ctx->buffer_len = 0; + ctx->total_len_bits = 0; +} + +void sha256_update(SHA256_CTX *ctx, const uint8_t *data, size_t len) +{ + size_t i; + + ctx->total_len_bits += len * 8; // Обновляем общую длину в битах + + while (len > 0) + { + size_t copy_len = 64 - ctx->buffer_len; // Сколько байт нужно для заполнения буфера + if (copy_len > len) + { + copy_len = len; + } + + memcpy(ctx->buffer + ctx->buffer_len, data, copy_len); + ctx->buffer_len += copy_len; + data += copy_len; + len -= copy_len; + + if (ctx->buffer_len == 64) + { + sha256_transform(ctx->H, ctx->buffer); + ctx->buffer_len = 0; + } + } +} + +void sha256_final(SHA256_CTX *ctx, uint8_t digest[32]) +{ + // 1. Добавление "1" бита + ctx->buffer[ctx->buffer_len++] = 0x80; + + // 2. Добавление нулей, пока не останется 8 байтов для длины + if (ctx->buffer_len > 56) + { + // Если места не хватает, заполняем текущий блок нулями и обрабатываем его + memset(ctx->buffer + ctx->buffer_len, 0x00, 64 - ctx->buffer_len); + sha256_transform(ctx->H, ctx->buffer); + ctx->buffer_len = 0; + } + // Заполняем оставшуюся часть буфера нулями до 56 байтов + memset(ctx->buffer + ctx->buffer_len, 0x00, 56 - ctx->buffer_len); + + // 3. Добавление длины сообщения в битах (big-endian, 64-бит) + // Длина уже в ctx->total_len_bits + ctx->buffer[56] = (uint8_t)(ctx->total_len_bits >> 56); + ctx->buffer[57] = (uint8_t)(ctx->total_len_bits >> 48); + ctx->buffer[58] = (uint8_t)(ctx->total_len_bits >> 40); + ctx->buffer[59] = (uint8_t)(ctx->total_len_bits >> 32); + ctx->buffer[60] = (uint8_t)(ctx->total_len_bits >> 24); + ctx->buffer[61] = (uint8_t)(ctx->total_len_bits >> 16); + ctx->buffer[62] = (uint8_t)(ctx->total_len_bits >> 8); + ctx->buffer[63] = (uint8_t)(ctx->total_len_bits); + + // 4. Обработка последнего блока + sha256_transform(ctx->H, ctx->buffer); + + // 5. Копирование финального хеша в digest (big-endian) + for (int i = 0; i < 8; i++) + { + digest[i * 4] = (uint8_t)(ctx->H[i] >> 24); + digest[i * 4 + 1] = (uint8_t)(ctx->H[i] >> 16); + digest[i * 4 + 2] = (uint8_t)(ctx->H[i] >> 8); + digest[i * 4 + 3] = (uint8_t)(ctx->H[i]); + } +} + +void sha256_string(const char *input_string, uint8_t digest[32]) +{ + SHA256_CTX ctx; + sha256_init(&ctx); + sha256_update(&ctx, (const uint8_t *)input_string, strlen(input_string)); + sha256_final(&ctx, digest); +} + +void bytes_to_hex(const uint8_t *bytes, size_t len, char *hex_string) +{ + for (size_t i = 0; i < len; i++) + { + sprintf(hex_string + (i * 2), "%02x", bytes[i]); + } + hex_string[len * 2] = '\0'; // Завершаем строку +} diff --git a/src/sha256.h b/src/sha256.h new file mode 100644 index 0000000..2792f2e --- /dev/null +++ b/src/sha256.h @@ -0,0 +1,30 @@ +#ifndef SHA256_H +#define SHA256_H + +#include // Для size_t +#include // Для uint8_t, uint32_t, uint64_t + +// Контекст для пошагового хеширования +typedef struct { + uint8_t buffer[64]; // Буфер для неполного 64-байтового блока + uint32_t buffer_len; // Длина данных в буфере + uint64_t total_len_bits; // Общая длина входных данных в битах + uint32_t H[8]; // Текущие значения хеша (H0-H7) +} SHA256_CTX; + +// Инициализирует контекст SHA256 +void sha256_init(SHA256_CTX *ctx); + +// Обновляет хеш-значение данными +void sha256_update(SHA256_CTX *ctx, const uint8_t *data, size_t len); + +// Завершает хеширование и получает 32-байтовый дайджест +void sha256_final(SHA256_CTX *ctx, uint8_t digest[32]); + +// Вспомогательная функция для хеширования всей строки сразу +void sha256_string(const char *input_string, uint8_t digest[32]); + +// Вспомогательная функция для преобразования байтов в шестнадцатеричную строку +void bytes_to_hex(const uint8_t *bytes, size_t len, char *hex_string); + +#endif // SHA256_H diff --git a/tests/test.c b/tests/test.c new file mode 100644 index 0000000..667c012 --- /dev/null +++ b/tests/test.c @@ -0,0 +1,36 @@ +#include +#include +#include + +int main() +{ + char path[256]; + char fName[256]; + const char *error; + + printf("dll: "); + scanf("%s", &path); + + void *handle = dlopen(path, RTLD_LAZY); + if (!handle) + { + fprintf(stderr, "Error: %s\n", dlerror()); + exit(1); + } + + printf("fName:"); + scanf("%s", fName); + + void (*f)() = dlsym(handle, fName); + if ((error = dlerror()) != NULL) + { + fprintf(stderr, "Error: %s\n", error); + exit(1); + } + else + { + printf("OK\n"); + } + + return 0; +} \ No newline at end of file