mirror of
https://github.com/Print3M/DllShimmer
synced 2026-06-06 16:34:32 +00:00
README improvements, new release
This commit is contained in:
@@ -47,7 +47,7 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh release delete 1.0.5 --cleanup-tag --yes || echo "No release or tag found for 1.0.5"
|
||||
gh release delete 1.1.0 --cleanup-tag --yes || echo "No release or tag found for 1.1.0"
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
@@ -55,13 +55,13 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: 1.0.5
|
||||
release_name: DllShimmer 1.0.5
|
||||
tag_name: 1.1.0
|
||||
release_name: DllShimmer 1.1.0
|
||||
body: |
|
||||
DllShimmer Weaponize DLL hijacking easily. Backdoor any function in any DLL.
|
||||
|
||||
- [x] GitHub Actions workflow improvements
|
||||
- [x] Windows build improvements
|
||||
- [x] Dynamic linking is now cached (both LoadLibraryA and GetProcAddress). Performance improved.
|
||||
- [x] Better debug log format: timestamp added.
|
||||
- [x] New parameter: `--debug-file`. Save debug logs to file.
|
||||
- [x] README updated.
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
|
||||
@@ -71,10 +71,14 @@ Default: DllShimmer always uses dynamic linking with the `LoadLibraryA()` and `G
|
||||
|
||||
**`--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.
|
||||
Save debug logs to a file. Logs are written to a file on an ongoing basis while the program is running. If selected, logs are not printed to STDOUT.
|
||||
|
||||
Default: DllShimmer always writes debug logs to STDOUT.
|
||||
|
||||
Example debug output:
|
||||
|
||||

|
||||
|
||||
## Limitations
|
||||
|
||||
- Only x86-64 / AMD64 architecture is supported.
|
||||
@@ -84,6 +88,12 @@ Default: DllShimmer always writes debug logs to STDOUT.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Before you start troubleshooting:
|
||||
|
||||
1. Read "Limitations".
|
||||
2. Make sure you don't use static linking (`--static`). It's easier to debug with dynamic linking (default).
|
||||
3. Save debug output to file (`--debug-file`).
|
||||
|
||||
### _In the generated `.cpp` file, I don't see all the exported functions from the original DLL._
|
||||
|
||||
Functions defined in the original DLL as “forwarded” are not included in the `.cpp` file. However, they are visible in the `.def` file. They will also be exported after compilation, exactly as in the original DLL.
|
||||
|
||||
@@ -8,27 +8,31 @@
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <time.h>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
|
||||
#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 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
|
||||
|
||||
typedef T (*FuncPtr)(PARAMS);
|
||||
|
||||
typedef struct {
|
||||
FILE *dbgOut;
|
||||
HMODULE module;
|
||||
std::unordered_map<std::string, FuncPtr> functions;
|
||||
} Ctx;
|
||||
|
||||
Ctx CTX = {.dbgOut = NULL };
|
||||
Ctx gCtx = { .dbgOut = NULL, .module = NULL };
|
||||
|
||||
void initDbg() {
|
||||
if (CTX.dbgOut != NULL) return;
|
||||
if (gCtx.dbgOut != NULL) return;
|
||||
|
||||
{{- if gt (len .DebugFile) 0 }}
|
||||
|
||||
CTX.dbgOut = fopen("{{.DebugFile}}", "w");
|
||||
if (!CTX.dbgOut) {
|
||||
gCtx.dbgOut = fopen("{{.DebugFile}}", "w");
|
||||
if (!gCtx.dbgOut) {
|
||||
MessageBoxA(
|
||||
NULL,
|
||||
"fopen({{.DebugFile}}) failed",
|
||||
@@ -39,43 +43,39 @@ void initDbg() {
|
||||
|
||||
{{- else }}
|
||||
|
||||
CTX.dbgOut = stdout;
|
||||
gCtx.dbgOut = stdout;
|
||||
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
char TIME_BUF[9]; // "HH:MM:SS" + null
|
||||
char gTimeBuf[9]; // "HH:MM:SS" + null
|
||||
|
||||
char *getCurrentTime() {
|
||||
time_t t = time(NULL);
|
||||
struct tm lt;
|
||||
localtime_s(<, &t);
|
||||
|
||||
strftime(TIME_BUF, sizeof(TIME_BUF), "%H:%M:%S", <);
|
||||
strftime(gTimeBuf, sizeof(gTimeBuf), "%H:%M:%S", <);
|
||||
|
||||
return TIME_BUF;
|
||||
return gTimeBuf;
|
||||
}
|
||||
|
||||
void dbgf(const char *fmt, ...) {
|
||||
if (CTX.dbgOut == NULL) {
|
||||
if (gCtx.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);
|
||||
fprintf(gCtx.dbgOut, "[DBG] {{.DllName}} | %s | ", getCurrentTime());
|
||||
vfprintf(gCtx.dbgOut, fmt, ap);
|
||||
fprintf(gCtx.dbgOut, "\n");
|
||||
fflush(gCtx.dbgOut);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void InitCache() {
|
||||
|
||||
}
|
||||
|
||||
void dbgCurrentDirectory() {
|
||||
char buf[MAX_PATH];
|
||||
DWORD len = GetCurrentDirectoryA(MAX_PATH, buf);
|
||||
@@ -87,20 +87,35 @@ void dbgCurrentDirectory() {
|
||||
dbgf("\tCurrent directory: '%s'", buf);
|
||||
}
|
||||
|
||||
|
||||
FuncPtr getProxyFunc(const char *funcName) {
|
||||
HMODULE hModule = LoadLibraryA("{{.Original}}");
|
||||
if (hModule == NULL) {
|
||||
dbgf("LoadLibraryA({{.Original}}) failed");
|
||||
dbgf("\tError code: %lu", GetLastError());
|
||||
dbgCurrentDirectory();
|
||||
// Module pointer is cached
|
||||
if (gCtx.module == NULL) {
|
||||
gCtx.module = LoadLibraryA("{{.Original}}");
|
||||
if (gCtx.module == NULL) {
|
||||
dbgf("LoadLibraryA({{.Original}}) failed");
|
||||
dbgf("\tError code: %lu", GetLastError());
|
||||
dbgCurrentDirectory();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
FuncPtr pFunc = (FuncPtr)GetProcAddress(hModule, funcName);
|
||||
std::string strFuncName(funcName);
|
||||
|
||||
// Function pointer is cached
|
||||
if (gCtx.functions.find(strFuncName) != gCtx.functions.end()) {
|
||||
return gCtx.functions[strFuncName];
|
||||
}
|
||||
|
||||
FuncPtr pFunc = (FuncPtr)GetProcAddress(gCtx.module, funcName);
|
||||
if (pFunc == NULL) {
|
||||
dbgf("GetProcAddress(%s, {{.Original}}) failed", funcName);
|
||||
dbgf("\tError code: %lu", GetLastError());
|
||||
}
|
||||
|
||||
gCtx.functions[strFuncName] = pFunc;
|
||||
|
||||
return pFunc;
|
||||
}
|
||||
|
||||
@@ -108,5 +123,3 @@ FuncPtr getProxyFunc(const char *funcName) {
|
||||
(CreateMutexA(NULL, TRUE, name) && GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
|
||||
#define PROXY_FUNCTION(funcName) getProxyFunc(funcName)(ARGS);
|
||||
|
||||
// TODO: Cache LoadLibraryA() and GetProcAddress() result
|
||||
|
||||
Reference in New Issue
Block a user