How to delete self (executable file) in Windows?

package main

import "os"

func main() {
    err := os.Remove(os.Args[1])
    if err != nil {
        panic(err)
    }
}

Compile this

GOOS=windows GOARCH=386 go build test.go

Then run on wine

Z:\tmp>test.exe test.exe
fixme:process:SetProcessPriorityBoost (0xffffffff,1): stub
panic: remove test.exe: Access denied.

goroutine 1 [running]:
panic(0x462c40, 0x5b3f9ca0)
    /usr/local/go/src/runtime/panic.go:500 +0x331
main.main()
    /tmp/test.go:8 +0x70

Z:\tmp>fixme:console:CONSOLE_DefaultHandler Terminating process 8 on event 0

I think "ok, it's wine" and run in Win XP on VirtualBox. But that's error in Windows return.

//Sorry for my english.

Upvotes: 1

Views: 2980

Answers (2)

Carson
Carson

Reputation: 8078

For windows you can use system API: shell32.dll.ShellExecuteW. It's running at another process, so even if your main program has terminated, it will continue to run. Therefore, you only need to call it to delete the program before the program exits. To ensure that the delete command is called after the program has terminated, you can wait for a period of time before deleting it (using start-sleep).

Example

Start-Sleep 2; del "C:\xxx.exe"

package main

import (
    "fmt"
    "log"
    "os"
    "syscall"
    "unicode/utf16"
    "unsafe"
)

func main() {
    defer func() { // delete exe
        shell32dll := syscall.NewLazyDLL("Shell32.dll")
        shellExecuteWProc := shell32dll.NewProc("ShellExecuteW")

        const deleteExeAfterNSec = 2
        const swHide = 0
        const swShow = 1
        log.Println(os.Args[0]) // os.Args[0] is the path of the executable file itself
        _, _, _ = syscall.SyscallN(shellExecuteWProc.Addr(),
            uintptr(0), // hwnd
            uintptr(unsafe.Pointer(&(utf16.Encode([]rune("runas" + "\x00")))[0])),
            uintptr(unsafe.Pointer(&(utf16.Encode([]rune("powershell" + "\x00")))[0])),
            uintptr(unsafe.Pointer(&(utf16.Encode([]rune(fmt.Sprintf("Start-Sleep %d;del %q;", deleteExeAfterNSec, os.Args[0]) + "\x00")))[0])), 
            uintptr(unsafe.Pointer(&(utf16.Encode([]rune("" + "\x00"))) [0])), // wkDir
            uintptr(swHide), // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
        )
        log.Println("done")
    }()
}

powershell for multiple command use ; to split

command1 ; command2 ; command3

Start-Sleep 3; del "C:\xxx.exe"

Upvotes: 0

Nilou Marandi
Nilou Marandi

Reputation: 21

Using CreateProcess function, as can be written in Go by using syscall package:

package main

import (
    "fmt"
    "syscall"
    "os"
)

func main() {
    // write your code here 
    // <----
    fmt.Println("Blah Blah Blah")
    // ---->
    var sI syscall.StartupInfo
    var pI syscall.ProcessInformation
    argv := syscall.StringToUTF16Ptr(os.Getenv("windir")+"\\system32\\cmd.exe /C del "+os.Args[0])
    err := syscall.CreateProcess(
        nil,
        argv,
        nil,
        nil,
        true,
        0,
        nil,
        nil,
        &sI,
        &pI)
    if err != nil {
        fmt.Printf("Return: %d\n", err)
    }
}

Upvotes: 2

Related Questions