Logo
Waseem Akram
HomeAboutResumeBlogContactVU Study MaterialStore
W
Waseem Akram

Cybersecurity expert, web developer, and educator dedicated to sharing knowledge and empowering others in the tech world.

LinkedInGitHubFacebookInstagramYouTubeWhatsApp

Quick Links

  • Home
  • About
  • Services
  • Blog
  • VU Study Material
  • Contact
  • Resume
  • Store
  • Support Me

Contact Info

  • hello@hackerwasii.com
  • +92 313 711 9351
  • Okara, Punjab Pakistan

Newsletter

Subscribe to receive updates on new content, tutorials, and cybersecurity tips.

I respect your privacy. Unsubscribe at any time.

Now Playingon Spotify
© 2025 Waseem Akram. All rights reserved.Made with in Pakistan
Privacy PolicyTerms of ServiceRefund PolicyCookies Policy
Malware DevelopmentPersistenceGolangRed Teaming

Malware Development How to call Windows API from Go

W
Waseem AkramVerified account
Researcher, Pentester, Dev
2024-09-30
4 min read
3,285 views
Featured image for Malware Development How to call Windows API from Go

Introduction

Today we'll see how we can use Golang internal functions from syscall and golang.org/x/sys/windows packages to call Windows API. Other languages like C o C++ are specifically designed for this but Golang is quite different so let's see how to do it.

Explanation

On the next days I'll be uploading all kind of malware development and red team posts but all the code will be... written in Golang That's why you need to understand how we have to use Windows API as it's one of the most important things when writing malware.
In C++ it's pretty easy to do, you just have to import the DLL like this on top of the code and all the internal functions are loaded:

#include windows.h

And for example kernel32.dll is always loaded into every process so you even don't have to do it.
In Golang this is a little bit different but don't worry because with some Windows knowledge you will be able to use it without problems. First of all we have to import
the golang.org/x/sys/windows package, it has some internal functions which allow us to import the DLLs and its functions. We also could do this with the syscall package because the functions even don't change.
Let's start by importing necessary packages

Advertisement

import (
    "fmt"
    "unsafe"
    "golang.org/x/sys/windows"
)

Once we've imported one of the 2 packages let's continue with the DLL:

func main(){
kernel32 := windows.NewLazyDLL("kernel32.dll")
}

The NewLazyDLL function basically loads a DLL and it looks for it first under C:\Windows\System32

As this posts are focused to red team, we will load the MessageBox function, which is in user32.dll, to test with no risks:

Advertisement

func main(){
user32 := windows.NewLazyDLL("user32.dll")
MessageBox := user32.NewProc("MessageBoxW")
}

All the imported functions have the Call() procedure, which receives variables of uintptr type and it always will return 3 values. The first one is the main part of the call, for example OpenProcess() would return a handle to a process, GetProcAddress return a procedure address and so on. For the second value I haven't found any information because it's never used. And the third one is an error type variable like most of the Golang functions which allow users to handle error. If the call shouldn't return any handle or special address it will return an status code which can also be used to check if an error has occurred.

Now to call MessageBox we have to know what arguments should receive, so let's check the Windows documentation here. As we can see the function receives a window handle (0 for no owner window), text to be displayed, message title and some other flags to determine the type of message box, in our case we'll be using a common "Accept" box so the value should be MB_OK msref

Most of the internal Windows values like MB_OK are available to use as a constant variable so we just have to use windows.MB_OK

Advertisement

We also have to do something before calling the function. It's converting the text and title strings into uint16 (note the * as it means it's a pointer), we can do it with another internal function windows.StringToUTF16Ptr() and we'll also use the unsafe package to access the unsafe.Pointer() function which needed to convert _uint16_ to uintptr. The result would be something like this:

uintptr(unsafe.Pointer(windows.StringToUTF16Ptr("example text")))

Now let's put all pieces together to make it work

func main(){
    user32 := windows.NewLazyDLL("user32.dll")
    MessageBox := user32.NewProc("MessageBoxW")
 
    r, _, _ := MessageBox.Call(0, uintptr(unsafe.Pointer(windows.StringToUTF16Ptr("Hello World!"))), uintptr(unsafe.Pointer(windows.StringToUTF16Ptr("Example"))), windows.MB_OK)
}

I recommend you to call the functions with one argument per line so it can be read easily like this:

Advertisement

func main(){
    user32 := windows.NewLazyDLL("user32.dll")
    MessageBox := user32.NewProc("MessageBoxW")
 
    r, _, _ := MessageBox.Call(
        0,
        uintptr(unsafe.Pointer(windows.StringToUTF16Ptr("Hello World!"))),
        uintptr(unsafe.Pointer(windows.StringToUTF16Ptr("Example"))),
        windows.MB_OK,
    )
 
    fmt.Println("Return code:", r)
}

Let's see how it works.

Demo

go build main.go

msgboxbuild And let's execute it:

./main.exe

msg

Advertisement

As we can see... it has worked! A simple message box appeared. This is the first step to start writing malware in Golang, I hope you have enjoyed it and learned something new. If you have any questions or suggestions feel free to ask me.

References

https://github.com/golang/go/wiki/WindowsDLLs
https://anubissec.github.io/How-To-Call-Windows-APIs-In-Golang/#
https://justen.codes/breaking-all-the-rules-using-go-to-call-windows-api-2cbfd8c79724?gi=1337f3df6dc9
https://www.thesubtlety.com/post/getting-started-golang-windows-apis/

Conclusion

As you can see calling Windows API is easy if you know in which DLLs the functions are loaded, like GetCurrentProcess()from kernel32.dll. I hope you've learned a lot from this post.

Source code here - GitHub repository with all the code from this post.

Advertisement

Thanks for reading this post, if you like my work you can support by Become a Patron! Read other posts


Advertisement

Malware DevelopmentPersistenceGolangRed Teaming
W

Waseem AkramVerified account

Researcher, Pentester, Dev

Cybersecurity expert and educator with a passion for sharing knowledge and helping others stay safe online.

Comments

Comments are currently disabled. Please share your thoughts on social media.

Related Articles

Malware Development 5 - Malware analysis evasion via Api Hashing (Golang)
Malware DevelopmentPersistence+2

Malware Development 5 - Malware analysis evasion via Api Hashing (Golang)

Today we’re going to see how real malware protect themselves from being analyzed using a technique called Api Hashing. First of all we should...

2024-11-086 min read
Malware Development 4 - Dump lsass.exe process + AV/EDR evasion (Golang)
Malware DevelopmentPersistence+2

Malware Development 4 - Dump lsass.exe process + AV/EDR evasion (Golang)

Today we’ll dump LSASS.EXE process memory to obtain credentials and we also will be using some evasion techniques. During red team...

2024-10-1714 min read
Malware Development 3 - Persistence via Recycle Bin (Golang)
Malware DevelopmentPersistence+2

Malware Development 3 - Persistence via Recycle Bin (Golang)

Today we’re gonna see an effective technique to mantain access in Windows systems during red team operations just by modifying a registry key...

2024-10-156 min read