mirror of
https://github.com/Print3M/DllShimmer
synced 2026-06-06 16:34:32 +00:00
Debug to file param added
This commit is contained in:
Vendored
+2
-1
@@ -2,6 +2,7 @@
|
||||
"files.associations": {
|
||||
"*.cpp.template": "cpp",
|
||||
"*.sh.template": "shellscript",
|
||||
"functional": "cpp"
|
||||
"functional": "cpp",
|
||||
"*.template": "cpp"
|
||||
}
|
||||
}
|
||||
@@ -103,4 +103,3 @@ In case of static linking, we really only have one option:
|
||||
|
||||
- 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?)
|
||||
- Maybe move boilerplate code into header file?
|
||||
|
||||
+17
-12
@@ -8,11 +8,12 @@ import (
|
||||
)
|
||||
|
||||
type CliFlags struct {
|
||||
Input string
|
||||
Output string
|
||||
OriginalPath string
|
||||
Mutex bool
|
||||
Static bool
|
||||
Input string
|
||||
Output string
|
||||
Original string
|
||||
Mutex bool
|
||||
Static bool
|
||||
DebugFile string
|
||||
}
|
||||
|
||||
func IsValidDllName(filename string) bool {
|
||||
@@ -41,8 +42,11 @@ func ParseCli() *CliFlags {
|
||||
flag.StringVar(&flags.Output, "o", "", "")
|
||||
flag.StringVar(&flags.Output, "output", "", "")
|
||||
|
||||
flag.StringVar(&flags.OriginalPath, "x", "", "")
|
||||
flag.StringVar(&flags.OriginalPath, "original-path", "", "")
|
||||
flag.StringVar(&flags.Original, "x", "", "")
|
||||
flag.StringVar(&flags.Original, "original", "", "")
|
||||
|
||||
flag.StringVar(&flags.DebugFile, "d", "", "")
|
||||
flag.StringVar(&flags.DebugFile, "debug-file", "", "")
|
||||
|
||||
flag.BoolVar(&flags.Mutex, "m", false, "")
|
||||
flag.BoolVar(&flags.Mutex, "mutex", false, "")
|
||||
@@ -54,10 +58,11 @@ func ParseCli() *CliFlags {
|
||||
fmt.Println()
|
||||
fmt.Println("Usage:")
|
||||
fmt.Println()
|
||||
fmt.Printf(" %-26s %s\n", "-i, --input <file>", "Input DLL file (required)")
|
||||
fmt.Printf(" %-26s %s\n", "-o, --output <dir>", "Output directory (required)")
|
||||
fmt.Printf(" %-26s %s\n", "-x, --original-path <path>", "Path to original DLL on target (required)")
|
||||
fmt.Printf(" %-26s %s\n", "-i, --input <path>", "Input DLL file (required)")
|
||||
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", " --static", "Static linking to original DLL via IAT (default: false)")
|
||||
fmt.Printf(" %-26s %s\n", "-h, --help", "Show this help")
|
||||
fmt.Println()
|
||||
@@ -71,12 +76,12 @@ func ParseCli() *CliFlags {
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if flags.Input == "" || flags.Output == "" || flags.OriginalPath == "" {
|
||||
if flags.Input == "" || flags.Output == "" || flags.Original == "" {
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if flags.Static && !IsValidDllName(flags.OriginalPath) {
|
||||
if flags.Static && !IsValidDllName(flags.Original) {
|
||||
fmt.Fprintf(os.Stderr, "[!] Invalid '-x' parameter value:\n")
|
||||
fmt.Fprintf(os.Stderr, "In case of static linking enabled '-x' parameter must be valid Windows DLL file name with no path information. E.g. kernel32.dll, user32.dll.")
|
||||
os.Exit(1)
|
||||
|
||||
+3
-3
@@ -15,15 +15,15 @@ type ExportedFunction struct {
|
||||
|
||||
type Dll struct {
|
||||
Name string
|
||||
OriginalPath string
|
||||
Original string
|
||||
ExportedFunctions []ExportedFunction
|
||||
}
|
||||
|
||||
func ParseDll(path string, originalPath string) *Dll {
|
||||
func ParseDll(path string, original string) *Dll {
|
||||
var dll Dll
|
||||
|
||||
dll.Name = filepath.Base(path)
|
||||
dll.OriginalPath = originalPath
|
||||
dll.Original = original
|
||||
|
||||
pe, err := peparser.New(path, &peparser.Options{})
|
||||
if err != nil {
|
||||
|
||||
@@ -18,12 +18,12 @@ func main() {
|
||||
cli.PrintBanner()
|
||||
|
||||
out := output.Output{
|
||||
Dll: dll.ParseDll(flags.Input, flags.OriginalPath),
|
||||
Dll: dll.ParseDll(flags.Input, flags.Original),
|
||||
OutputDir: filepath.Clean(flags.Output),
|
||||
TemplatesFS: &templatesFS,
|
||||
}
|
||||
|
||||
out.CreateCodeFiles(flags.Mutex, flags.Static)
|
||||
out.CreateCodeFiles(flags.Mutex, flags.DebugFile, flags.Static)
|
||||
out.CreateDefFile()
|
||||
out.CreateCompileScript(flags.Static)
|
||||
|
||||
|
||||
+18
-14
@@ -44,10 +44,12 @@ func (o *Output) GetLibFileName() string {
|
||||
}
|
||||
|
||||
type CodeFileParams struct {
|
||||
Functions []dll.ExportedFunction
|
||||
OriginalPath string
|
||||
Mutex bool
|
||||
DllName string
|
||||
Functions []dll.ExportedFunction
|
||||
Original string
|
||||
Mutex bool
|
||||
DllName string
|
||||
DebugFile string
|
||||
IsStaticLinked bool
|
||||
}
|
||||
|
||||
func (o *Output) GetTemplate(filename string) *template.Template {
|
||||
@@ -60,21 +62,23 @@ func (o *Output) GetTemplate(filename string) *template.Template {
|
||||
return template.Must(template.New("new").Parse(string(content)))
|
||||
}
|
||||
|
||||
func (o *Output) CreateCodeFiles(mutex bool, isStaticLinked bool) {
|
||||
func (o *Output) CreateCodeFiles(mutex bool, debugFile string, isStaticLinked bool) {
|
||||
params := CodeFileParams{
|
||||
Functions: o.Dll.ExportedFunctions,
|
||||
OriginalPath: sanitizePathForInjection(o.Dll.OriginalPath),
|
||||
Mutex: mutex,
|
||||
DllName: o.Dll.Name,
|
||||
Functions: o.Dll.ExportedFunctions,
|
||||
Original: sanitizePathForInjection(o.Dll.Original),
|
||||
Mutex: mutex,
|
||||
DllName: o.Dll.Name,
|
||||
DebugFile: sanitizePathForInjection(debugFile),
|
||||
IsStaticLinked: isStaticLinked,
|
||||
}
|
||||
|
||||
o.createCppCodeFile(params, isStaticLinked)
|
||||
o.createCppCodeFile(params)
|
||||
o.createHdrCodeFile(params)
|
||||
}
|
||||
|
||||
func (o *Output) createCppCodeFile(params CodeFileParams, isStaticLinked bool) {
|
||||
func (o *Output) createCppCodeFile(params CodeFileParams) {
|
||||
templateFile := "dynamic-shim.cpp.template"
|
||||
if isStaticLinked {
|
||||
if params.IsStaticLinked {
|
||||
templateFile = "static-shim.cpp.template"
|
||||
}
|
||||
|
||||
@@ -113,8 +117,8 @@ func (o *Output) CreateDefFile() {
|
||||
func (o *Output) CreateLibFile() {
|
||||
var def def.DefFile
|
||||
|
||||
// In case of static linking OriginalPath is DLL name itself
|
||||
def.DllName = o.Dll.OriginalPath
|
||||
// In case of static linking Original is DLL name itself
|
||||
def.DllName = o.Dll.Original
|
||||
|
||||
for _, function := range o.Dll.ExportedFunctions {
|
||||
if function.Forwarder == "" {
|
||||
|
||||
@@ -5,49 +5,72 @@
|
||||
// | (auto generated) |
|
||||
// #------------------------------------------------------------------#
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.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 struct {
|
||||
FILE *dbgOut;
|
||||
} Ctx;
|
||||
|
||||
Ctx CTX;
|
||||
|
||||
void InitCTX() {
|
||||
{{- if gt (len .DebugFile) 0 }}
|
||||
|
||||
CTX.dbgOut = fopen("{{.DebugFile}}", "w");
|
||||
if (!CTX.dbgOut) {
|
||||
// TODO: Change to message box
|
||||
perror("fopen");
|
||||
}
|
||||
|
||||
{{- else }}
|
||||
|
||||
CTX.dbgOut = stdout;
|
||||
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
typedef T (*FuncPtr)(PARAMS);
|
||||
|
||||
|
||||
void PrintCurrentDirectory() {
|
||||
void LogCurrentDirectory() {
|
||||
char buf[MAX_PATH];
|
||||
DWORD len = GetCurrentDirectoryA(MAX_PATH, buf);
|
||||
if (len == 0 || len >= MAX_PATH) {
|
||||
printf("\tGetCurrentDirectoryA failed\n");
|
||||
logf("\tGetCurrentDirectoryA failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\tCurrent directory: '%s'\n", buf);
|
||||
logf("\tCurrent directory: '%s'\n", buf);
|
||||
}
|
||||
|
||||
|
||||
FuncPtr getProxyFunc(const char *funcName) {
|
||||
HMODULE hModule = LoadLibraryA("{{.OriginalPath}}");
|
||||
HMODULE hModule = LoadLibraryA("{{.Original}}");
|
||||
if (hModule == NULL) {
|
||||
printf("[!] {{.DllName}}: LoadLibraryA({{.OriginalPath}}) failed\n");
|
||||
printf("\tError code: %lu\n", GetLastError());
|
||||
PrintCurrentDirectory();
|
||||
logf("[!] {{.DllName}}: LoadLibraryA({{.Original}}) failed\n");
|
||||
logf("\tError code: %lu\n", GetLastError());
|
||||
LogCurrentDirectory();
|
||||
}
|
||||
|
||||
FuncPtr pFunc = (FuncPtr)GetProcAddress(hModule, funcName);
|
||||
if (pFunc == NULL) {
|
||||
printf("[!] {{.DllName}}: GetProcAddress(%s, {{.OriginalPath}}) failed\n",
|
||||
logf("[!] {{.DllName}}: GetProcAddress(%s, {{.Original}}) failed\n",
|
||||
funcName);
|
||||
printf("\tError code: %lu\n", GetLastError());
|
||||
logf("\tError code: %lu\n", GetLastError());
|
||||
}
|
||||
|
||||
return pFunc;
|
||||
}
|
||||
|
||||
|
||||
#define MUTEX(name) \
|
||||
(CreateMutexA(NULL, TRUE, name) && GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
|
||||
#define PROXY_FUNCTION(funcName) getProxyFunc(funcName)(ARGS);
|
||||
#define PROXY_FUNCTION(funcName) getProxyFunc(funcName)(ARGS);
|
||||
|
||||
// TODO: Cache LoadLibraryA() and GetProcAddress() result
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
#include <stdio.h>
|
||||
|
||||
{{- range $i, $v := .Functions }}
|
||||
|
||||
{{- if eq (len $v.Forwarder) 0 }}
|
||||
|
||||
extern "C" UINT64 {{$v.Name}}Fwd(PARAMS) {
|
||||
#ifdef DEBUG
|
||||
printf("[+] {{$r.DllName}}: {{$v.Name}} called\n");
|
||||
logf("[+] {{$r.DllName}}: {{$v.Name}} called\n");
|
||||
#endif
|
||||
{{ if $r.Mutex }}
|
||||
if (MUTEX("Global\\{{$v.Name}}__{{$i}}")) {
|
||||
@@ -26,6 +27,7 @@ extern "C" UINT64 {{$v.Name}}Fwd(PARAMS) {
|
||||
}
|
||||
|
||||
{{- end }}
|
||||
|
||||
{{- end }}
|
||||
|
||||
|
||||
@@ -34,7 +36,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
|
||||
switch (fdwReason) {
|
||||
case DLL_PROCESS_ATTACH: {
|
||||
#ifdef DEBUG
|
||||
printf("[+] {{.DllName}}: DLL_PROCESS_ATTACH event\n");
|
||||
logf("[+] {{.DllName}}: DLL_PROCESS_ATTACH event\n");
|
||||
#endif
|
||||
}
|
||||
case DLL_THREAD_ATTACH:
|
||||
|
||||
@@ -32,7 +32,7 @@ extern "C" __declspec(dllimport) UINT64 {{$v.Name}}(PARAMS);
|
||||
|
||||
extern "C" UINT64 {{$v.Name}}Fwd(PARAMS) {
|
||||
#ifdef DEBUG
|
||||
printf("[+] {{$r.DllName}}: {{$v.Name}} called\n");
|
||||
logf("[+] {{$r.DllName}}: {{$v.Name}} called\n");
|
||||
#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
|
||||
printf("[+] {{.DllName}}: DLL_PROCESS_ATTACH event\n");
|
||||
PrintCurrentDirectory();
|
||||
logf("[+] {{.DllName}}: DLL_PROCESS_ATTACH event\n");
|
||||
LogCurrentDirectory();
|
||||
#endif
|
||||
}
|
||||
case DLL_THREAD_ATTACH:
|
||||
|
||||
Reference in New Issue
Block a user