mirror of
https://github.com/Print3M/DllShimmer
synced 2026-06-06 16:34:32 +00:00
Update README, better debug handling, timestamp added
This commit is contained in:
Vendored
+2
-1
@@ -3,6 +3,7 @@
|
||||
"*.cpp.template": "cpp",
|
||||
"*.sh.template": "shellscript",
|
||||
"functional": "cpp",
|
||||
"*.template": "cpp"
|
||||
"*.template": "cpp",
|
||||
"cstdarg": "cpp"
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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(<, &t);
|
||||
|
||||
strftime(TIME_BUF, sizeof(TIME_BUF), "%H:%M:%S", <);
|
||||
|
||||
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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user