C语言在
unix
下可以通过直接覆写argv的方式隐藏参数,但是在windows下由于win32 api的限制,获取到的参数是一串连续的字符串,在C语言的main
函数调用之前已经由C标准库实现了分割,导致直接修改argv并不能实现隐藏参数的目的。
但是,我们可以利用
golang
封装的syscall.GetCommandLine()
直接拿到该处内存的切片,从而可以方便地进行修改。当然,C语言通过系统调用同样也可以实现这点。
感谢@wdvxdr1123对本方法在可行性方面提出的建议
直接使用
如果您不关心实现,为方便起见,本方法已经封装成了package,使用也很简单,只需要像下面这样写即可。
import para "github.com/fumiama/go-hide-param"
// This will hide os.Args[index]
para.Hide(index)
实现代码
//go:build windows
// +build windows
package gohideparam
import (
"os"
"syscall"
"unsafe"
)
// Slice is the runtime representation of a slice.
// It cannot be used safely or portably and its representation may
// change in a later release.
//
// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
// data it references will not be garbage collected.
type Slice struct {
Data unsafe.Pointer
Len int
Cap int
}
// readNextArg splits command line string cmd into next
// argument and command line remainder.
func readNextArg(cmd *[]uint16, is2erase bool) {
var inquote bool
var nslash int
for ; len(*cmd) > 0; (*cmd) = (*cmd)[1:] {
switch (*cmd)[0] {
case uint16(' '), uint16('\t'):
if !inquote {
return
}
case uint16('"'):
if nslash%2 == 0 {
// use "Prior to 2008" rule from
// http://daviddeley.com/autohotkey/parameters/parameters.htm
// section 5.2 to deal with double double quotes
if inquote && len(*cmd) > 1 && (*cmd)[1] == uint16('"') {
*cmd = (*cmd)[1:]
}
inquote = !inquote
}
nslash = 0
continue
case uint16('\\'):
nslash++
if is2erase {
(*cmd)[0] = uint16('*')
}
continue
default:
if is2erase {
(*cmd)[0] = uint16('*')
}
}
nslash = 0
}
}
func eraseCommandLine(cmd *[]uint16, pos uint) {
var p uint
for len(*cmd) > 0 && p <= pos {
if (*cmd)[0] == uint16(' ') || (*cmd)[0] == uint16('\t') {
(*cmd) = (*cmd)[1:]
continue
}
readNextArg(cmd, p == pos)
p++
}
}
func utf16PtrToSlice(p *uint16) []uint16 {
if p == nil {
return nil
}
// Find NUL terminator.
end := unsafe.Pointer(p)
n := 0
for *(*uint16)(end) != 0 {
end = unsafe.Pointer(uintptr(end) + unsafe.Sizeof(*p))
n++
}
// Turn *uint16 into []uint16.
var s []uint16
hdr := (*Slice)(unsafe.Pointer(&s))
hdr.Data = unsafe.Pointer(p)
hdr.Cap = n
hdr.Len = n
return s
}
func Hide(position int) {
if position > 0 && position < len(os.Args) {
cmd := utf16PtrToSlice(syscall.GetCommandLine())
eraseCommandLine(&cmd, uint(position))
}
}