Debug to file param added

This commit is contained in:
Print3M
2025-08-23 11:21:14 +02:00
parent 590b32dc01
commit 89528c3023
9 changed files with 86 additions and 52 deletions
+2 -1
View File
@@ -2,6 +2,7 @@
"files.associations": {
"*.cpp.template": "cpp",
"*.sh.template": "shellscript",
"functional": "cpp"
"functional": "cpp",
"*.template": "cpp"
}
}
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+2 -2
View File
@@ -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
View File
@@ -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 == "" {
+37 -14
View File
@@ -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
+4 -2
View File
@@ -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:
+3 -3
View File
@@ -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: