Update README, better debug handling, timestamp added

This commit is contained in:
Print3M
2025-08-23 13:50:43 +02:00
parent 89528c3023
commit 1c64b0788c
6 changed files with 71 additions and 29 deletions
+2 -1
View File
@@ -3,6 +3,7 @@
"*.cpp.template": "cpp",
"*.sh.template": "shellscript",
"functional": "cpp",
"*.template": "cpp"
"*.template": "cpp",
"cstdarg": "cpp"
}
}
+10 -5
View File
@@ -38,15 +38,15 @@ Example:
Parameters:
**`-i / --input <file>`** [required]
**`-i / --input <path>`** [required]
The original DLL that you want to backdoor.
**`-o / --output <dir>`** [required]
**`-o / --output <path>`** [required]
The path to the directory where DllShimmer will save all generated files.
**`-x / --original-path <path | file>`** [required]
**`-x / --original <path>`** [required]
In case of dynamic linking (default) provide the path where the proxy DLL will find the original DLL on the target system.
@@ -67,7 +67,13 @@ This technique has some serious limitations compared to dynamic linking:
However, static linking may be more stealthy and natural in some scenarios.
By default, DllShimmer always uses dynamic linking with the `LoadLibraryA()` and `GetProcAddress()` functions.
Default: DllShimmer always uses dynamic linking with the `LoadLibraryA()` and `GetProcAddress()` functions.
**`--debug-file <path>`** [optional]
Save debug logs to a file. Logs are written to a file on an ongoing basis while the program is running.
Default: DllShimmer always writes debug logs to STDOUT.
## Limitations
@@ -102,4 +108,3 @@ In case of static linking, we really only have one option:
## TODO
- Cache LoadLibraryA() and GetProcAddress() pointers not to call WinAPI every time (better performance and more stealthy).
- Improve the shim template code (leave as little code in the macro as possible. Is the macro actually required now when we use args/params trick?)
+1 -1
View File
@@ -62,7 +62,7 @@ func ParseCli() *CliFlags {
fmt.Printf(" %-26s %s\n", "-o, --output <path>", "Output directory (required)")
fmt.Printf(" %-26s %s\n", "-x, --original <path>", "Path to original DLL on target (required)")
fmt.Printf(" %-26s %s\n", "-m, --mutex", "Multiple execution prevention (default: false)")
fmt.Printf(" %-26s %s\n", " --debug-file <path>", "Save debug logs to file")
fmt.Printf(" %-26s %s\n", " --debug-file <path>", "Save debug logs to a file (default: stdout)")
fmt.Printf(" %-26s %s\n", " --static", "Static linking to original DLL via IAT (default: false)")
fmt.Printf(" %-26s %s\n", "-h, --help", "Show this help")
fmt.Println()
+51 -15
View File
@@ -7,27 +7,34 @@
#include <stdio.h>
#include <windows.h>
#include <time.h>
#define T UINT64
#define PARAMS \
T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9, T a10, T a11, T a12
#define ARGS a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12
#define logf(...) fprintf(CTX.dbgOut, __VA_ARGS__)
typedef T (*FuncPtr)(PARAMS);
typedef struct {
FILE *dbgOut;
} Ctx;
Ctx CTX;
Ctx CTX = {.dbgOut = NULL };
void initDbg() {
if (CTX.dbgOut != NULL) return;
void InitCTX() {
{{- if gt (len .DebugFile) 0 }}
CTX.dbgOut = fopen("{{.DebugFile}}", "w");
if (!CTX.dbgOut) {
// TODO: Change to message box
perror("fopen");
MessageBoxA(
NULL,
"fopen({{.DebugFile}}) failed",
"DllShimmer",
MB_OK | MB_ICONINFORMATION
);
}
{{- else }}
@@ -37,32 +44,61 @@ void InitCTX() {
{{- end }}
}
typedef T (*FuncPtr)(PARAMS);
char TIME_BUF[9]; // "HH:MM:SS" + null
void LogCurrentDirectory() {
char *getCurrentTime() {
time_t t = time(NULL);
struct tm lt;
localtime_s(&lt, &t);
strftime(TIME_BUF, sizeof(TIME_BUF), "%H:%M:%S", &lt);
return TIME_BUF;
}
void dbgf(const char *fmt, ...) {
if (CTX.dbgOut == NULL) {
initDbg();
}
va_list ap;
va_start(ap, fmt);
fprintf(CTX.dbgOut, "[DBG] {{.DllName}} | %s | ", getCurrentTime());
vfprintf(CTX.dbgOut, fmt, ap);
fprintf(CTX.dbgOut, "\n");
fflush(CTX.dbgOut);
va_end(ap);
}
void InitCache() {
}
void dbgCurrentDirectory() {
char buf[MAX_PATH];
DWORD len = GetCurrentDirectoryA(MAX_PATH, buf);
if (len == 0 || len >= MAX_PATH) {
logf("\tGetCurrentDirectoryA failed\n");
dbgf("GetCurrentDirectoryA failed");
return;
}
logf("\tCurrent directory: '%s'\n", buf);
dbgf("\tCurrent directory: '%s'", buf);
}
FuncPtr getProxyFunc(const char *funcName) {
HMODULE hModule = LoadLibraryA("{{.Original}}");
if (hModule == NULL) {
logf("[!] {{.DllName}}: LoadLibraryA({{.Original}}) failed\n");
logf("\tError code: %lu\n", GetLastError());
LogCurrentDirectory();
dbgf("LoadLibraryA({{.Original}}) failed");
dbgf("\tError code: %lu", GetLastError());
dbgCurrentDirectory();
}
FuncPtr pFunc = (FuncPtr)GetProcAddress(hModule, funcName);
if (pFunc == NULL) {
logf("[!] {{.DllName}}: GetProcAddress(%s, {{.Original}}) failed\n",
funcName);
logf("\tError code: %lu\n", GetLastError());
dbgf("GetProcAddress(%s, {{.Original}}) failed", funcName);
dbgf("\tError code: %lu", GetLastError());
}
return pFunc;
+3 -3
View File
@@ -13,7 +13,7 @@
extern "C" UINT64 {{$v.Name}}Fwd(PARAMS) {
#ifdef DEBUG
logf("[+] {{$r.DllName}}: {{$v.Name}} called\n");
dbgf("{{$v.Name}} called");
#endif
{{ if $r.Mutex }}
if (MUTEX("Global\\{{$v.Name}}__{{$i}}")) {
@@ -32,11 +32,11 @@ extern "C" UINT64 {{$v.Name}}Fwd(PARAMS) {
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
switch (fdwReason) {
case DLL_PROCESS_ATTACH: {
#ifdef DEBUG
logf("[+] {{.DllName}}: DLL_PROCESS_ATTACH event\n");
dbgf("DLL_PROCESS_ATTACH");
#endif
}
case DLL_THREAD_ATTACH:
+4 -4
View File
@@ -10,11 +10,11 @@
// | "DON'T TOUCH" ZONE |
// | (auto generated) |
// #------------------------------------------------------------------#
#include "dllshimmer.h"
{{- range .Functions}}
#define {{.Name}} {{.Name}}Original
{{- end}}
#include "dllshimmer.h"
#include <windows.h>
{{- range .Functions}}
#undef {{.Name}}
@@ -32,7 +32,7 @@ extern "C" __declspec(dllimport) UINT64 {{$v.Name}}(PARAMS);
extern "C" UINT64 {{$v.Name}}Fwd(PARAMS) {
#ifdef DEBUG
logf("[+] {{$r.DllName}}: {{$v.Name}} called\n");
dbgf("{{$v.Name}} called");
#endif
{{ if $r.Mutex }}
if (MUTEX("Global\\{{$v.Name}}__{{$i}}")) {
@@ -54,8 +54,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
switch (fdwReason) {
case DLL_PROCESS_ATTACH: {
#ifdef DEBUG
logf("[+] {{.DllName}}: DLL_PROCESS_ATTACH event\n");
LogCurrentDirectory();
dbgf("DLL_PROCESS_ATTACH event");
dbgCurrentDirectory();
#endif
}
case DLL_THREAD_ATTACH: