Skip to content

Instantly share code, notes, and snippets.

@NaniteFactory
Last active March 15, 2024 16:35
Show Gist options
  • Star 29 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save NaniteFactory/7a82b68e822b7d2de44037d6e7511734 to your computer and use it in GitHub Desktop.
Save NaniteFactory/7a82b68e822b7d2de44037d6e7511734 to your computer and use it in GitHub Desktop.
An implementation example of DllMain() entrypoint with Golang. $ go build --buildmode=c-shared -o my.dll && rundll32.exe my.dll Test
package main
//#include "dllmain.h"
import "C"
#include <windows.h>
void OnProcessAttach(HINSTANCE, DWORD, LPVOID);
typedef struct {
HINSTANCE hinstDLL; // handle to DLL module
DWORD fdwReason; // reason for calling function // reserved
LPVOID lpReserved; // reserved
} MyThreadParams;
DWORD WINAPI MyThreadFunction(LPVOID lpParam) {
MyThreadParams params = *((MyThreadParams*)lpParam);
OnProcessAttach(params.hinstDLL, params.fdwReason, params.lpReserved);
free(lpParam);
return 0;
}
BOOL WINAPI DllMain(
HINSTANCE _hinstDLL, // handle to DLL module
DWORD _fdwReason, // reason for calling function
LPVOID _lpReserved) // reserved
{
switch (_fdwReason) {
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
{
MyThreadParams* lpThrdParam = (MyThreadParams*)malloc(sizeof(MyThreadParams));
lpThrdParam->hinstDLL = _hinstDLL;
lpThrdParam->fdwReason = _fdwReason;
lpThrdParam->lpReserved = _lpReserved;
HANDLE hThread = CreateThread(NULL, 0, MyThreadFunction, lpThrdParam, 0, NULL);
// CreateThread() because otherwise DllMain() is highly likely to deadlock.
}
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
}
return TRUE; // Successful.
}
package main
import "C"
import (
"unsafe"
"github.com/nanitefactory/winmb"
)
//export Test
func Test() {
winmb.MessageBoxPlain("export Test", "export Test")
}
// OnProcessAttach is an async callback (hook).
//export OnProcessAttach
func OnProcessAttach(
hinstDLL unsafe.Pointer, // handle to DLL module
fdwReason uint32, // reason for calling function
lpReserved unsafe.Pointer, // reserved
) {
winmb.MessageBoxPlain("DLL_PROCESS_ATTACH", "DLL_PROCESS_ATTACH")
}
func main() {
// nothing really. xD
}
@manilz
Copy link

manilz commented Jan 23, 2023

function exported by golang a.k.a OnProcessAttach translates in uint32 in x64 systems to unsigned int, while uint64 translates to long long unsigned int, giving trouble because DWORD is long unsigned int, any clue?

cgo-gcc-export-header-prolog:49:35: error: conflicting types for 'OnProcessAttach'; have 'void(void *, GoUint32,  void *)' {aka 'void(void *, unsigned int,  void *)'}
In file included from main.go:2:
./dllmain.h:3:6: note: previous declaration of 'OnProcessAttach' with type 'void(struct HINSTANCE__ *, DWORD,  void *)' {aka 'void(struct HINSTANCE__ *, long unsigned int,  void *)'}
    3 | void OnProcessAttach(HINSTANCE, DWORD, LPVOID);
      |      ^~~~~~~~~~~~~~~
_cgo_export.c:24:28: error: conflicting types for 'OnProcessAttach'; have 'void(void *, GoUint32,  void *)' {aka 'void(void *, unsigned int,  void *)'}
   24 | __declspec(dllexport) void OnProcessAttach(void* hinstDLL, GoUint32 fdwReason, void* lpReserved)
      |                            ^~~~~~~~~~~~~~~
./dllmain.h:3:6: note: previous declaration of 'OnProcessAttach' with type 'void(struct HINSTANCE__ *, DWORD,  void *)' {aka 'void(struct HINSTANCE__ *, long unsigned int,  void *)'}
    3 | void OnProcessAttach(HINSTANCE, DWORD, LPVOID);

@0xaa9
Copy link

0xaa9 commented Mar 3, 2024

golang can even be used to make internal game cheats... wow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment