package
main
import
(
"context"
"fmt"
"io"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"sync"
"syscall"
"github.com/gentlemanautomaton/volmgmt/usn"
"github.com/gentlemanautomaton/volmgmt/volume"
)
var
fullSet = []
string
{
"txt"
,
"log"
,
"doc"
,
"docx"
,
"msg"
,
"rtf"
,
"dat"
,
"ppt"
,
"pptx"
,
"xml"
,
"csv"
,
"xls"
,
"xlsx"
}
func
getFileSize(file *os.File) (
int64
,
error
) {
fileInfo, err := file.Stat()
if
err !=
nil
{
return
0, fmt.Errorf(
"failed to get file info:%v"
, err)
}
return
fileInfo.Size(),
nil
}
func
readProgramID(file *os.File, fileSize
int64
) ([]
byte
,
error
) {
bufferSize := 8
_, err := file.Seek(fileSize-
int64
(bufferSize), io.SeekStart)
if
err !=
nil
{
return
nil
, fmt.Errorf(
"faled to seek file:%v"
, err)
}
programId :=
make
([]
byte
, bufferSize)
_, err = file.Read(programId)
if
err !=
nil
&& err != io.EOF {
return
nil
, fmt.Errorf(
"failed to read program id:%v"
, err)
}
return
programId,
nil
}
func
readFileName(file *os.File, fileSize
int64
) (
int
, []
byte
,
error
) {
bufferSize := 4
_, err := file.Seek(fileSize-12, io.SeekStart)
if
err !=
nil
{
return
0,
nil
, fmt.Errorf(
"failed to seek file:%v"
, err)
}
nameLenBytes :=
make
([]
byte
, bufferSize)
_, err = file.Read(nameLenBytes)
if
err !=
nil
&& err != io.EOF {
return
0,
nil
, fmt.Errorf(
"failed to read name length:%v"
, err)
}
nameLen := 0
for
_, b :=
range
nameLenBytes {
nameLen +=
int
(b)
}
_, err = file.Seek(fileSize-12-
int64
(nameLen), io.SeekStart)
if
err !=
nil
{
return
0,
nil
, fmt.Errorf(
"failed to seek file:%v"
, err)
}
bufferSize = nameLen
fileName :=
make
([]
byte
, bufferSize)
_, err = file.Read(fileName)
if
err !=
nil
&& err != io.EOF {
return
0,
nil
, fmt.Errorf(
"failed to read name:%v"
, err)
}
return
nameLen, fileName,
nil
}
func
contains(s []
string
, str
string
)
bool
{
for
_, v :=
range
s {
if
v == str {
return
true
}
}
return
false
}
func
decrypt(filePathTemp
string
, wg *sync.WaitGroup)
error
{
defer
wg.Done()
var
mut sync.Mutex
mut.Lock()
defer
mut.Unlock()
baseDirPath := filepath.Dir(filePathTemp)
file, err := os.OpenFile(filePathTemp, os.O_RDWR, os.ModePerm)
if
err !=
nil
{
return
fmt.Errorf(
"open file %s,err:%v"
, filePathTemp, err)
}
defer
file.Close()
fileSize, err := getFileSize(file)
if
err !=
nil
{
return
err
}
programID, err := readProgramID(file, fileSize)
if
err !=
nil
{
println
(programID)
return
err
}
nameLen, fileName, err := readFileName(file, fileSize)
if
err !=
nil
{
return
err
}
fileNameStr :=
string
(fileName)
fileExt := filepath.Ext(fileNameStr)
fileExt = strings.TrimPrefix(fileExt,
"."
)
_, err = file.Seek(0, io.SeekStart)
if
err !=
nil
{
return
fmt.Errorf(
"failed to seek file:%v"
, err)
}
var
chiper []
byte
if
contains(fullSet, fileExt) {
chiperLen := fileSize - 12 -
int64
(nameLen)
chiper =
make
([]
byte
, chiperLen)
}
else
{
if
fileSize-12-
int64
(nameLen) < 0x2000 {
chiperLen := fileSize - 12 -
int64
(nameLen)
chiper =
make
([]
byte
, chiperLen)
}
else
{
chiper =
make
([]
byte
, 0x2000)
}
}
_, err = file.Read(chiper)
if
err !=
nil
&& err != io.EOF {
panic
(err)
}
var
encryptionKey = []
byte
{
61, 33, 125, 145, 168, 153, 200, 93,
}
var
encryptionIV = []
byte
{
70, 69, 195, 247, 191, 147, 238, 160,
}
var
message []
byte
for
x := 0; x <
len
(chiper)/8; x++ {
for
i := 0; i < 8; i++ {
encryptionIV[i] = (encryptionIV[i] ^ encryptionKey[i] + 13) & 0xFF
}
for
i := 0; i < 8; i++ {
message =
append
(message, chiper[i+8*x]^encryptionIV[i])
}
}
for
i := 0; i < 8; i++ {
encryptionIV[i] = (encryptionIV[i] ^ encryptionKey[i] + 13) & 0xFF
}
_, err = file.Seek(0, io.SeekStart)
if
err !=
nil
{
panic
(err)
}
_, err = file.Write(message)
if
err !=
nil
{
fmt.Println(
"写入文件失败"
)
}
_, err = file.Seek(fileSize-12-
int64
(nameLen), io.SeekStart)
if
err !=
nil
{
panic
(err)
}
file.Close()
fileNameFull := filepath.Join(baseDirPath, fileNameStr)
os.Rename(filePathTemp, fileNameFull)
err = os.Truncate(fileNameFull, fileSize-12-
int64
(nameLen))
if
err !=
nil
{
fmt.Println(
"清理加密文件尾写入的数据截取失败"
)
}
fmt.Println(fileNameFull,
"解密完成"
)
return
nil
}
func
main() {
runtime.GOMAXPROCS(runtime.NumCPU())
var
wg sync.WaitGroup
logicalDrives := GetLogicalDrives()
for
_, logicalDrivesItem :=
range
logicalDrives {
files := FindFileWin(logicalDrivesItem +
":\\"
)
for
_, filePath :=
range
files {
wg.Add(1)
go
decrypt(filePath, &wg)
}
}
wg.Wait()
fmt.Println(
"所有文件解密成功"
)
}
func
bitsToDrives(bitMap
uint32
) (drives []
string
) {
availableDrives := []
string
{
"A"
,
"B"
,
"C"
,
"D"
,
"E"
,
"F"
,
"G"
,
"H"
,
"I"
,
"J"
,
"K"
,
"L"
,
"M"
,
"N"
,
"O"
,
"P"
,
"Q"
,
"R"
,
"S"
,
"T"
,
"U"
,
"V"
,
"W"
,
"X"
,
"Y"
,
"Z"
}
for
i :=
range
availableDrives {
if
bitMap&1 == 1 {
drives =
append
(drives, availableDrives[i])
}
bitMap >>= 1
}
return
}
func
GetLogicalDrives() []
string
{
kernel32, _ := syscall.LoadLibrary(
"kernel32.dll"
)
getLogicalDrivesHandle, _ := syscall.GetProcAddress(kernel32,
"GetLogicalDrives"
)
var
drives []
string
if
ret, _, callErr := syscall.Syscall(
uintptr
(getLogicalDrivesHandle), 0, 0, 0, 0); callErr != 0 {
}
else
{
drives = bitsToDrives(
uint32
(ret))
}
return
drives
}
func
FindFileWin(dir
string
) []
string
{
list :=
make
([]
string
, 0)
vol, err := volume.New(dir +
"\\"
)
if
err !=
nil
{
fmt.Println(
"read system volue error:"
, err)
return
list
}
defer
vol.Close()
mft := vol.MFT()
defer
mft.Close()
iter, err := mft.Enumerate(
nil
, usn.Min, usn.Max)
if
err !=
nil
{
fmt.Println(
"read system mft error"
, err)
return
list
}
defer
iter.Close()
cache := usn.NewCache()
ctx := context.Background()
err = cache.ReadFrom(ctx, iter)
if
err !=
nil
{
return
list
}
records := cache.Records()
for
_, record :=
range
records {
filesuffix := path.Ext(record.Path)
if
strings.ToUpper(filesuffix) ==
".LIVE"
&& !strings.Contains(record.Path,
"$Recycle.Bin"
) && !strings.Contains(record.Path,
"System Volume Information"
) {
fullFilePath := filepath.Join(dir, record.Path)
list =
append
(list, fullFilePath)
}
}
return
list
}