I am trying to patch a chunk of memory in Golang. I have the VirtualProtect functionality down and the memory chunk is being changed to RW, but I can't find figure out the Golang functionality for Copying into memory.
I want to emulate this from a Powershell Script:
[System.Runtime.InteropServices.Marshal]::Copy($patch, 0, $targetedAddress, 3)
The Golang code I currently have is below:
var patch = []byte {
0x31, 0xC0, // xor rax, rax
0xC3, // ret
}
var oldfperms uint32
virtualProt(unsafe.Pointer(&patchAddr), unsafe.Sizeof(uintptr(2)), uint32(0x40),
unsafe.Pointer(&oldfperms)) // Modify region for ReadWrite
var r uintptr
for _, b := range patch {
r = (r << 8) | uintptr(b)
}
patch := unsafe.Pointer(uintptr(r)) // Attempting to copy into memory here and I'm stumped
fmt.Println(patch)
var a uint32
virtualProt(unsafe.Pointer(&patchAddr), unsafe.Sizeof(uintptr(2)), oldfperms, unsafe.Pointer(&a)) // Change region back to normal
Nevermind. Found the reference to the Win32 WriteProcessMemory function and used that.
https://pkg.go.dev/github.com/0xrawsec/golang-win32/win32/kernel32#WriteProcessMemory
func WriteProcMem(currProccess uintptr, patchAddr uintptr, patch uintptr) bool {
kern32WriteMem := syscall.NewLazyDLL("kernel32.dll").NewProc("WriteProcessMemory")
_, _, _ = kern32WriteMem.Call(
currProccess,
patchAddr,
patch)
fmt.Println("[+] Patched Memory!")
return true
}
Related
I can get the HICON with ExtractIconW
for example:
package main
import (
"log"
"syscall"
"unsafe"
)
func MakeIntResource(id uintptr) *uint16 {
return (*uint16)(unsafe.Pointer(id))
}
const IDI_QUESTION = 32514
func main() {
user32Dll := syscall.NewLazyDLL("User32.dll")
procLoadIconW := user32Dll.NewProc("LoadIconW")
hIcon, _, _ := syscall.SyscallN(procLoadIconW.Addr(),
0, uintptr(unsafe.Pointer(MakeIntResource(IDI_QUESTION))),
)
log.Println(hIcon)
}
But I don't know what I should do next to save HICON as a file (bitmap format is enough).
A real .ico file usually contains multiple images of different sizes while a HICON is just a single image.
If the goal is to copy the original icon then you must LoadLibraryEx as a datafile and then use the resource functions to first find the RT_GROUP_ICON and once you have that you know the RT_ICON ids and you can extract the sub-images and write your .ico.
If you still think you want to save a HICON, call GetIconInfo to get the image.
There are no low-level Windows functions to write .ico files. You can try GDI+ or WIC or write them yourself. The file format is very close to the resource format (stores a file offset instead of a resource id).
A guide to Windows icon formats starts here...
The following code is an example which writing by go, and it saves one of the resources to a bitmap file.
// Step:
// get HICON
// get ICONINFO from HICON
// get Bitmap from ICONINFO
// save Bitmap to a File
// Note: To make the example look simple, I ignore all possible errors handling.
func Example_saveFileIconAsBitmap() {
user32dll := w32.NewUser32DLL()
kernel32dll := w32.NewKernel32DLL()
gdi32dll := w32.NewGdi32DLL()
var hIcon w32.HICON
{
// Because I already know the iconID(myResourceID) I want, I can load it directly.
// If you want to find the appropriate iconID after searching through RT_GROUP_ICON you can refer to this example:
// https://github.com/CarsonSlovoka/go-pkg/blob/34e5d2c1fc97bf149bf626acaaf8773fe1509d64/v2/w32/kernel32_func_test.go#L331-L353
hmExe := kernel32dll.LoadLibrary("./testdata/exe/writeWithFont.exe") // writeWithFont.exe is in here: https://github.com/CarsonSlovoka/go-pkg/tree/983a2c1/v2/w32/testdata/exe
myResourceID := uintptr(1) // You can use resourceHacker.exe to help you find the ID.
hRes, _ := kernel32dll.FindResource(hmExe,
w32.MakeIntResource(myResourceID),
w32.MakeIntResource(w32.RT_ICON),
)
hMem, _ := kernel32dll.LoadResource(hmExe, hRes)
lpResource := kernel32dll.LockResource(hMem)
hIcon = user32dll.CreateIconFromResourceEx(lpResource,
kernel32dll.MustSizeofResource(hmExe, hRes), true, 0x00030000,
32, 32, // size X, Y
w32.LR_DEFAULTCOLOR,
)
}
var iInfo w32.ICONINFO
{
if !user32dll.GetIconInfo(hIcon, &iInfo) {
return
}
// Remember to release when you are not using the HBITMAP.
defer func() {
_ = gdi32dll.DeleteObject(w32.HGDIOBJ(iInfo.HbmColor))
_ = gdi32dll.DeleteObject(w32.HGDIOBJ(iInfo.HbmMask))
}()
}
bmp := w32.Bitmap{}
{
// Create BITMAP by ICONINFO
gdi32dll.GetObject(w32.HANDLE(iInfo.HbmColor), int32(unsafe.Sizeof(bmp)), uintptr(unsafe.Pointer(&bmp)))
}
// Save Bitmap to a file.
var (
bitmapFileHeader w32.BitmapFileHeader // https://en.wikipedia.org/wiki/BMP_file_format#Bitmap_file_header
bitmapInfoHeader w32.BitmapInfoHeader // https://en.wikipedia.org/wiki/BMP_file_format#DIB_header_(bitmap_information_header)
)
{
bitmapInfoHeader = w32.BitmapInfoHeader{
Size: uint32(unsafe.Sizeof(bitmapInfoHeader)), // 40
Width: bmp.Width, Height: bmp.Height,
Planes: 1,
BitCount: 32,
Compression: w32.BI_RGB,
}
bmpSize := ((bmp.Width*int32(bitmapInfoHeader.BitCount) + 31) / 32) * 4 /* uint32 */ * bmp.Height // see the wiki: https://en.wikipedia.org/wiki/BMP_file_format#Pixel_storage
sizeofDIB := 14 + uint32(unsafe.Sizeof(bitmapInfoHeader)) + uint32(bmpSize)
bitmapFileHeader = w32.BitmapFileHeader{
Type: 0x4D42, // BM. // B: 42, M: 4D // All of the integer values are stored in little-endian format
Size: sizeofDIB, // HEADER + INFO + DATA
OffsetBits: 14 + uint32(unsafe.Sizeof(bitmapInfoHeader)),
}
hdc := user32dll.GetDC(0)
var lpBitmap w32.LPVOID
hDIB, _ := kernel32dll.GlobalAlloc(w32.GHND, w32.SIZE_T(bmpSize))
lpBitmap, _ = kernel32dll.GlobalLock(hDIB)
defer func() {
kernel32dll.GlobalUnlock(hDIB)
kernel32dll.GlobalFree(hDIB)
}()
gdi32dll.GetDIBits(
hdc, iInfo.HbmColor,
0,
w32.UINT(bmp.Height),
lpBitmap, // [out]
&w32.BitmapInfo{Header: bitmapInfoHeader},
w32.DIB_RGB_COLORS,
)
outputBmpPath := "testdata/temp001.bmp"
// Write: FileHeader, DIPHeader, bitmapData
{
f, _ := os.Create(outputBmpPath)
defer func() {
_ = os.Remove(outputBmpPath) // Remove test data. If you want to see the result, delete this line to see the final data.
}()
// FileHeader
_ = binary.Write(f, binary.LittleEndian, bitmapFileHeader)
// DIP Header
_ = binary.Write(f, binary.LittleEndian, bitmapInfoHeader)
// bitmapData
bmpDatas := make([]byte, sizeofDIB)
var offset uint32 = 0
for offset = 0; offset < sizeofDIB; offset += 1 {
curByteAddr := unsafe.Pointer(uintptr(lpBitmap) + uintptr(offset))
bmpDatas[offset] = *(*byte)(curByteAddr)
}
_ = binary.Write(f, binary.LittleEndian, bmpDatas)
_ = f.Close()
}
}
// Output:
}
Above code is part of a third-party library, but no other third-party resources are used.
It is no longer written as a single file because winapi has too many constants, variables, and types, and the declaration of the DLL is also very tedious.
If you are interested, you can download this library back. Its packaging is very simple. If you do not like to use other third parties to capture the relevant variables can be done.
The following pictures will help you understand the meaning of the parameters of MAKEINTRESOURCE more easily.
I'm using golang to call a Dll function like char* fn(), the dll is not written by myself and I cannot change it. Here's my code:
package main
import (
"fmt"
"syscall"
"unsafe"
)
func main() {
dll := syscall.MustLoadDLL("my.dll")
fn := dll.MustFindProc("fn")
r, _, _ := fn.Call()
p := (*byte)(unsafe.Pointer(r))
// define a slice to fill with the p string
data := make([]byte, 0)
// loop until find '\0'
for *p != 0 {
data = append(data, *p) // append 1 byte
r += unsafe.Sizeof(byte(0)) // move r to next byte
p = (*byte)(unsafe.Pointer(r)) // get the byte value
}
name := string(data) // convert to Golang string
fmt.Println(name)
}
I have some questions:
Is there any better way of doing this? There're hundred of dll functions like this, I'll have to write the loop for all functions.
For very-long-string like 100k+ bytes, will append() cause performance issue?
Solved. the unsafe.Pointer(r) causes linter govet shows warning possible misuse of unsafe.Pointer, but the code runs fine, how to avoid this warning? Solution: This can be solved by adding -unsafeptr=false to govet command line, for vim-ale, add let g:ale_go_govet_options = '-unsafeptr=false'.
Casting uintptr as upointer is haram.
You must read the rules:
https://golang.org/pkg/unsafe/#Pointer
But there's hacky way, that shouldn't produce warning:
//go:linkname gostringn runtime.gostringn
func gostringn(p uintptr, l int) string
//go:linkname findnull runtime.findnull
//go:nosplit
func findnull(s uintptr) int
// ....
name := gostringn(r, findnull(r))
Functions takes pointer, but we link them from runtime as uintptr because they have same sizeof.
Might work in theory. But is also frowned upon.
Getting back to your code, as JimB said, you could do it one line with:
name := C.GoString((*C.char)(unsafe.Pointer(r)))
I got the following solution by tracking the os.Args of the go source code, But I am based on go1.17. If you are in another version, you can read the source code to solve it.
func UintPtrToString(r uintptr) string {
p := (*uint16)(unsafe.Pointer(r))
if p == nil {
return ""
}
n, end, add := 0, unsafe.Pointer(p), unsafe.Sizeof(*p)
for *(*uint16)(end) != 0 {
end = unsafe.Add(end, add)
n++
}
return string(utf16.Decode(unsafe.Slice(p, n)))
}
I'm trying to call procedure (without name) from a DLL using the ordinal value.
I can use this DLL in C#, setting the ordinal value to the property EntryPoint of DllImport.
... or you can identify the entry point by its ordinal. Ordinals are prefixed with the # sign, for example, #1. [...]
Example in C#:
[DllImport("dllname.dll", EntryPoint = "#3", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern int DeviceList(ref IntPtr hDeviceList);
When try find the procedure with "#" sign in Go, it shows the the following error:
Failed to find #3 procedure in dllname.dll: The specified procedure could not be found.
I used dumpbin to show the information of the DLL, no function has a name:
Is there a way to find a procedure with its ordinal value (like C#)?
There is a github issue here for this, but it seems not to have been merged as of Go 1.10.3 (the version I am using right now).
Anyway, the github issue links to a changeset with the respective function from which I extracted the code to do what you want here:
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetProcAddress = kernel32.NewProc("GetProcAddress")
)
// GetProcAddressByOrdinal retrieves the address of the exported
// function from module by ordinal.
func GetProcAddressByOrdinal(module syscall.Handle, ordinal uintptr) (uintptr, error) {
r0, _, _ := syscall.Syscall(procGetProcAddress.Addr(), 2, uintptr(module), ordinal, 0)
proc := uintptr(r0)
if proc == 0 {
return 0, syscall.EINVAL
}
return proc, nil
}
For completeness, here is the full example with which I tested this, using the Dependecy Walker I found that the first function in kernel32.dll is AcquireSRWLockExclusive and using the new function it shows that the proc addresses really match.
package main
import (
"fmt"
"syscall"
)
func main() {
dll, err := syscall.LoadDLL("kernel32.dll")
check(err)
want, err := syscall.GetProcAddress(dll.Handle, "AcquireSRWLockExclusive")
check(err)
fmt.Println(want)
first, err := GetProcAddressByOrdinal(dll.Handle, 1)
check(err)
fmt.Println(first)
}
func check(err error) {
if err != nil {
panic(err)
}
}
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetProcAddress = kernel32.NewProc("GetProcAddress")
)
// GetProcAddressByOrdinal retrieves the address of the exported
// function from module by ordinal.
func GetProcAddressByOrdinal(module syscall.Handle, ordinal uintptr) (uintptr, error) {
r0, _, _ := syscall.Syscall(procGetProcAddress.Addr(), 2, uintptr(module), ordinal, 0)
proc := uintptr(r0)
if proc == 0 {
return 0, syscall.EINVAL
}
return proc, nil
}
I'v been trying to play with netapi32.dll, but I'm having mixed results.
The following works as expected
type SERVER_INFO_101 struct {
PlatformID uint32
Name *uint16
VersionMajor uint32
VersionMinor uint32
Type uint32
Comment *uint16
}
func NetServerGetInfo() {
info := &SERVER_INFO_101{}
ret, _, err := procNetServerGetInfo.Call(0, 101, uintptr(unsafe.Pointer(&info)))
if ret != 0 {
log.Fatal(err)
}
spew.Dump(info)
}
However, I'm not sure why info has to have & inside the unsafe.Pointer also.
The following does not work, and I can't seem to find out why. No error codes get thrown. Neither the struct or variables gets filled out.
type SESSION_INFO_10 struct {
Cname *uint16
Username *uint16
Time uint32
IdleTime uint32
}
func NetSessionEnum() {
info := &SESSION_INFO_10{}
var prefmaxlen int32 = -1
var entriesread uint32
var totalentries uint32
var resumehandle uint32
x, y, z := procNetSessionEnum.Call(0, 0, 0, 10, uintptr(unsafe.Pointer(info)), uintptr(prefmaxlen), uintptr(unsafe.Pointer(&entriesread)), uintptr(unsafe.Pointer(&totalentries)), uintptr(unsafe.Pointer(&resumehandle)))
fmt.Println(x, y, z)
fmt.Println(entriesread, totalentries)
spew.Dump(info)
}
…because you're not supposed to pass a pointer to your memory block there—to cite the manual:
This buffer is allocated by the system and must be freed using the NetApiBufferFree function.
The type of that pointer is misleading but you're supposed to pass a pointer to a pointer there, something like this:
func NetSessionEnum() {
var pinfo *SESSION_INFO_10
var prefmaxlen int32 = -1
var entriesread uint32
var totalentries uint32
var resumehandle uint32
x, y, z := procNetSessionEnum.Call(0, 0, 0, 10,
uintptr(unsafe.Pointer(&pinfo)), uintptr(prefmaxlen),
uintptr(unsafe.Pointer(&entriesread)),
uintptr(unsafe.Pointer(&totalentries)),
uintptr(unsafe.Pointer(&resumehandle)))
fmt.Println(x, y, z)
fmt.Println(entriesread, totalentries)
spew.Dump(info)
}
// Now use `*pinfo.Cname` etc
// Don't forget to later call `NetApiBufferFree()` on that pointer.
What happens here:
The variable pinfo is a pointer to a value of type SESSION_INFO_10.
You take the address of the memory block occupied by the value kept in that variable (which is a pointer) and pass it to NetSessionEnum().
That function allocates the buffer by itself and writes its address to the memory block pointed to by the address you have passed to the function.
Since you've passed an address of the pinfo variable, the address of the buffer ends up being written into the variable pinfo.
You then use that address stored in pinfo to access the memory allocated by NetSessionEnum().
That's called "double indirection" and is used in quite many places of Win32 API. Please read the manual page and study the code example it includes.
Update: as it turned out, there were more problems with the original code so I've took time to provide full solution—here is the gist (tested with Go 1.6 amd64 and i386 on Windows XP 32-bit, Windows 2003 R2 64-bit and Windows 8.1 64-bit).
I'm working in Go 1.6 on Windows and trying to export a certificate container to a PFX (the ultimate goal here is to access an exportable private key from the certificate store).
I have opened a memory store and inserted a certificate into the store:
var storedCertCtx *syscall.CertContext
storeHandle, err := syscall.CertOpenStore(syscall.CERT_STORE_PROV_MEMORY, 0, 0, syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, 0)
err = syscall.CertAddCertificateContextToStore(storeHandle, certenum, syscall.CERT_STORE_ADD_ALWAYS, &storedCertCtx)
Now I want to generate a PFX of that store. I have defined a struct for containing the data blob and want to use PFXExportCertStoreEx to get a PFX of the store:
var (
crypt32 = syscall.NewLazyDLL("crypt32.dll")
procPFXExportCertStoreEx = crypt32.NewProc("PFXExportCertStoreEx")
)
type CRYPTOAPI_BLOB struct {
DataSize uint32
Data *byte
}
var pfxBlob CRYPTOAPI_BLOB
err = PfxExportCertStore(storeHandle, &pfxBlob, syscall.StringToUTF16Ptr("MyPassword"), 0, 0)
syscall.Syscall6(procPFXExportCertStoreEx.Addr(), 5,
uintptr(storeHandle), //hStore
uintptr(unsafe.Pointer(&pfxBlob)), //*pPFX
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("password"))), //szPassword
0, //*pvPara
0, //dwFlags
0)
And this half works.
DataSize is populated with what looks like an appropriate value (i.e. if I add more certificates to the store, it grows bigger), however Data is always <nil>.
Seeing as it's meant to be populated with a pointer, I have tried declaring it as *uintptr and uint32 (just to see if anything gets populated), but nothing. The value is always untouched (if I manually put junk data in there, the junk data stays after the syscall is executed).
Have I defined the struct incorrectly? There is precious few examples to go for getting this done in Go, but from what I can see from the numerous C examples, this should be working.
This is the expected behavior.
According to this: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387313(v=vs.85).aspx, the pPFX struct requires a pre-allocated buffer, with the size in the cbData field, which will be updated with the size of the data copied in.
If the call is made with pbData equal to NULL, only the cbData field is updated to reflect the size needed for the output buffer.
JimB's answer is most certainly correct, but I want to add this for followup in case anyone else is going down this path. The actual code that I had to use to get the PFX file into CRYPTOAPI_BLOB was:
var (
crypt32 = syscall.NewLazyDLL("crypt32.dll")
procPFXExportCertStoreEx = crypt32.NewProc("PFXExportCertStoreEx")
procCryptMemAlloc = crypt32.NewProc("CryptMemAlloc")
procCryptMemFree = crypt32.NewProc("CryptMemFree")
)
type CRYPTOAPI_BLOB struct {
cbData uint32
pbData *byte
}
func (b *CRYPTOAPI_BLOB) ToByteArray() []byte {
d := make([]byte, b.cbData)
copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
return d
}
func PfxExportCertStore(storeHandle syscall.Handle, password string, flags uint32) (returnData []byte, err error) {
var pfxBlob CRYPTOAPI_BLOB
r1, _, _ := syscall.Syscall6(procPFXExportCertStoreEx.Addr(), 5,
uintptr(storeHandle), //hStore
uintptr(unsafe.Pointer(&pfxBlob)), //*pPFX
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(password))), //szPassword
0, //*pvPara
uintptr(flags), //dwFlags
0)
r2, _, _ := syscall.Syscall(procCryptMemAlloc.Addr(), 1, uintptr(unsafe.Pointer(&pfxBlob.cbData)), 0, 0)
p := unsafe.Pointer(&r2)
q := (*byte)(p)
pfxBlob.pbData = q
defer syscall.Syscall(procCryptMemFree.Addr(), 1, uintptr(unsafe.Pointer(pfxBlob.pbData)), 0, 0)
r3, _, _ := syscall.Syscall6(procPFXExportCertStoreEx.Addr(), 5,
uintptr(storeHandle), //hStore
uintptr(unsafe.Pointer(&pfxBlob)), //*pPFX
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(password))), //szPassword
0, //*pvPara
uintptr(flags), //dwFlags
0)
returnData = pfxBlob.ToByteArray()
return
}
(I have stripped the error handling to make it easier to read). The first call to PFXExportCertStoreEx just returns the size, and once we have the size we can do a call to PFXExportCertStoreEx to allocate a buffer, and then we pass the same pointer to PFXExportCertStoreEx, but this time it has the allocated buffer, and we get the full PFX file returned.