HeavensGate.cpp
/*
Original: https://github.com/terrorisst/Malware/tree/master/Heavens%20Gate
Edited by: Blau
Date: 21/03/2017
*/
#include <Windows.h>
#include <stdio.h>
#include "HeavensGate.hpp"
#pragma warning(disable: 4409)
__declspec(naked) void* memcpy64(unsigned long long Dst, unsigned long long Src, unsigned long len)
{
__asm
{
push ebp
mov ebp, esp
push esi
push edi
X64_Start()
EMIT(0x67) EMIT(0x48) EMIT(0x8B) EMIT(0x75) EMIT(0x10) //mov rsi, qword ptr[ebp+16]
EMIT(0x67) EMIT(0x48) EMIT(0x8B) EMIT(0x7D) EMIT(0x08) //mov rdi, qword ptr[ebp+8]
EMIT(0x67) EMIT(0x8B) EMIT(0x4D) EMIT(0x18) //mov ecx, dword ptr [ebp+24]
EMIT(0x8a) EMIT(0x06) //mov al, byte ptr[rsi]
EMIT(0x88) EMIT(0x07) //mov byte ptr[rdi], al
EMIT(0x48) EMIT(0xFF) EMIT(0xC6) //inc rsi
EMIT(0x48) EMIT(0xFF) EMIT(0xC7) //inc rdi
EMIT(0xE2) EMIT(0xF4) //loop e (mov al, byte ptr[rsi])
X64_End()
pop edi
pop esi
mov esp, ebp
pop ebp
ret
}
}
__declspec(naked) void GetPEB64(PEB64* out)
{
__asm
{
push ebp
mov ebp, esp
sub esp, 8
X64_Start()
EMIT(0x65) EMIT(0x48) EMIT(0x8B) EMIT(0x04) EMIT(0x25) EMIT(0x60) EMIT(0x00) EMIT(0X00) EMIT(0X00) //mov rax, gs:[0x60]
EMIT(0x50) //push rax
EMIT(0x67) EMIT(0x8F) EMIT(0x45) EMIT(0xF8) //pop qword ptr[ebp-8]
X64_End()
push 32 //dword
push[ebp - 0x04] //qword
push[ebp - 0x08]
push 0
push[ebp + 0x08] //qword
call memcpy64
add esp, 20
mov esp, ebp
pop ebp
ret
}
}
unsigned long long GetModuleHandle64(wchar_t* ModuleName)
{
unsigned long long Current = 0;
unsigned long long ulModule = 0;
wchar_t szBuffer[512] = { 0 };
PEB64 Peb64 = { 0 };
LDR64 Ldr64 = { 0 };
LDR_DATA_TABLE_ENTRY64 LdrEntry64 = { 0 };
GetPEB64(&Peb64);
if (Peb64.ImageBaseAddress == (unsigned long long)GetModuleHandle(0)/*GetImageBase()*/)
{
memcpy64((unsigned long long)&Ldr64, Peb64.Ldr, sizeof(LDR64));
memcpy64((unsigned long long)&LdrEntry64, Ldr64.InLoadOrderModuleList.Flink, sizeof(LDR_DATA_TABLE_ENTRY64));
do
{
Current = LdrEntry64.InLoadOrderLinks.Flink;
if (Current == Peb64.Ldr + 0x10)
break;
memcpy64((unsigned long long)&LdrEntry64, LdrEntry64.InLoadOrderLinks.Flink, sizeof(LDR_DATA_TABLE_ENTRY64));
memcpy64((unsigned long long)szBuffer, LdrEntry64.BaseDllName.Buffer, LdrEntry64.BaseDllName.Length);
//if (!m_memcmp(ModuleName, szBuffer, LdrEntry64.BaseDllName.Length))
if (!memcmp(ModuleName, szBuffer, LdrEntry64.BaseDllName.Length))
{
ulModule = LdrEntry64.DllBase;
break;
}
} while (1);
}
return ulModule;
}
unsigned long long GetNextArgument(unsigned long * ulCurrentArg, unsigned long ulArgCount, unsigned long long *pulArgs)
{
unsigned long long NextArg = 0;
if (*ulCurrentArg < ulArgCount)
{
NextArg = pulArgs[(*ulCurrentArg)++];
}
return NextArg;
}
unsigned long CallFunction64(unsigned long long ulAddress, unsigned long ulOrdinal, unsigned long long * pulArgs, unsigned long ulArgCount, unsigned char ucType)
{
unsigned long ulNtStatus = 0;
unsigned long long StackArguments = 0;
unsigned long long StackCount = 0;
unsigned long ulCurrentArg = 0;
unsigned long long Arg1 = GetNextArgument(&ulCurrentArg, ulArgCount, pulArgs);
unsigned long long Arg2 = GetNextArgument(&ulCurrentArg, ulArgCount, pulArgs);
unsigned long long Arg3 = GetNextArgument(&ulCurrentArg, ulArgCount, pulArgs);
unsigned long long Arg4 = GetNextArgument(&ulCurrentArg, ulArgCount, pulArgs);
if (ulArgCount > 4)
{
StackArguments = (unsigned long long)&pulArgs[3];
StackCount = ulArgCount - 4;
}
__asm
{
push edi
push esi
X64_Start()
push Arg1
EMIT(0x59) //pop rcx
push Arg2
EMIT(0x5A) //pop rdx
push Arg3
EMIT(0x41) EMIT(0x58) //pop r8
push Arg4
EMIT(0x41) EMIT(0x59) //pop r9
push StackArguments
EMIT(0x5F) //pop rdi
push StackCount
EMIT(0x5E) //pop rsi
test esi, esi
jz Procedure
LoadStack :
push[edi + (esi * 8)]
sub esi, 1
jnz LoadStack
Procedure :
push ucType
EMIT(0x58)
cmp eax, 0
jne SysCall
push ulAddress
EMIT(0x58)
sub esp, 32
call eax
add esp, 32
jmp StackCleanup
SysCall :
push Arg1
EMIT(0x41) EMIT(0x5A) //pop r10
mov eax, ulOrdinal
sub esp, 40
EMIT(0x0F) EMIT(0x05) //syscall
add esp, 40
StackCleanup:
push StackCount
EMIT(0x5E)
test esi, esi
jz End
Cleanup :
pop edi
sub esi, 1
jnz Cleanup
End :
mov ulNtStatus, eax
X64_End()
pop esi
pop edi
}
return ulNtStatus;
}
__declspec(naked) unsigned long strlen64(unsigned long long Dst)
{
__asm
{
push ebp
mov ebp, esp
xor ecx, ecx
X64_Start()
EMIT(0x67) EMIT(0x48) EMIT(0x8b) EMIT(0x45) EMIT(0x08) //mov rax, qword ptr[ebp+8]
Calculate:
EMIT(0x80) EMIT(0x38) EMIT(0x00) //cmp byte ptr[rax], 00
je Done
EMIT(0x48) EMIT(0x83) EMIT(0xC0) EMIT(0x01) //add rax, 1
add ecx, 1
jmp Calculate
Done :
mov eax, ecx
X64_End()
mov esp, ebp
pop ebp
ret
}
}
unsigned long long GetProcAddress64(unsigned long long ulModule, char *szFunction)
{
unsigned long long ulFunction = 0;
IMAGE_DOS_HEADER DosHeader = { 0 };
IMAGE_NT_HEADERS64 NtHeaders = { 0 };
memcpy64((unsigned long long)&DosHeader, ulModule, sizeof(IMAGE_DOS_HEADER));
memcpy64((unsigned long long)&NtHeaders, ulModule + DosHeader.e_lfanew, sizeof(IMAGE_NT_HEADERS64));
if (NtHeaders.Signature == IMAGE_NT_SIGNATURE)
{
char szName[256] = { 0 };
IMAGE_EXPORT_DIRECTORY Exports = { 0 };
unsigned long ulVA = NtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
unsigned long ulSize = NtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
unsigned long i = 0;
memcpy64((unsigned long long)&Exports, ulModule + ulVA, sizeof(IMAGE_EXPORT_DIRECTORY));
for (i; i < Exports.NumberOfNames; i++)
{
unsigned long long ulNameOffset = 0;
memcpy64((unsigned long long)&ulNameOffset, Exports.AddressOfNames + ulModule + (i * 4), sizeof(unsigned long));
ulNameOffset += ulModule;
memcpy64((unsigned long long)szName, ulNameOffset, strlen64(ulNameOffset));
if (!memcmp(szFunction, szName, strlen(szFunction)))
{
unsigned long long ulAddressOffset = 0;
unsigned long long ulOrdinalOffset = 0;
memcpy64((unsigned long long)&ulOrdinalOffset, (Exports.AddressOfNameOrdinals + ulModule + (i * 2)), sizeof(unsigned short));
memcpy64((unsigned long long)&ulAddressOffset, (Exports.AddressOfFunctions + ulModule + (ulOrdinalOffset * 4)), sizeof(unsigned long));
if (ulAddressOffset > ulVA && ulAddressOffset < (ulVA + ulSize))
{
ulFunction = 0;
break;
}
ulFunction = (ulAddressOffset + ulModule);
break;
}
}
}
return ulFunction;
}
unsigned long SysCall64(unsigned long ulOrdinal, unsigned long long * pulArgs, unsigned long ulArgCount)
{
unsigned long ulNtStatus = 0;
unsigned long long StackArguments = 0;
unsigned long long StackCount = 0;
unsigned long ulCurrentArg = 0;
unsigned long long Arg1 = GetNextArgument(&ulCurrentArg, ulArgCount, pulArgs);
unsigned long long Arg2 = GetNextArgument(&ulCurrentArg, ulArgCount, pulArgs);
unsigned long long Arg3 = GetNextArgument(&ulCurrentArg, ulArgCount, pulArgs);
unsigned long long Arg4 = GetNextArgument(&ulCurrentArg, ulArgCount, pulArgs);
if (ulArgCount > 4)
{
StackArguments = (unsigned long long)&pulArgs[3];
StackCount = ulArgCount - 4;
}
__asm
{
push edi
push esi
X64_Start()
push Arg1
EMIT(0x59) //pop rcx
push Arg2
EMIT(0x5A) //pop rdx
push Arg3
EMIT(0x41) EMIT(0x58) //pop r8
push Arg4
EMIT(0x41) EMIT(0x59) //pop r9
push StackArguments
EMIT(0x5F) //pop rdi
push StackCount
EMIT(0x5E) //pop rsi
sub esp, 40 //Stack frame spilling registers
mov eax, esi
imul eax, 8
sub esp, eax //Rest of arguments
test esi, esi
jz SysCall
LoadStack :
EMIT(0x67) EMIT(0x48) EMIT(0x8B) EMIT(0x0C) EMIT(0xF7) //mov rcx, qword ptr[edi + (esi*8)]
EMIT(0x67) EMIT(0x48) EMIT(0x89) EMIT(0x4C) EMIT(0xF4) EMIT(0x20) //mov qword ptr [esp+(esi*8)+32], rcx
sub esi, 1
jnz LoadStack
SysCall :
push Arg1
EMIT(0x41) EMIT(0x5A) //pop r10
mov eax, ulOrdinal
EMIT(0x0F) EMIT(0x05) //syscall
push StackCount
EMIT(0x5E) //pop rsi
mov ulNtStatus, eax
mov eax, esi
imul eax, 8
add esp, eax
add esp, 40
//End:
X64_End()
pop esi
pop edi
}
return ulNtStatus;
}
template <typename T, typename... A>
T Call64(wchar_t* Library, char* Function, A ... args) {
DWORD64 Arguments[sizeof...(args)] = { DWORD64(args)... };
unsigned long long ulFunctionPointer = GetProcAddress64(GetModuleHandle64(Library), Function);
if (!ulFunctionPointer) {
printf("Error! Cannot get pointer to funciton '%ls!%s'\n", Library, Function);
return NULL;
}
T tReturn = (T)CallFunction64(ulFunctionPointer, 0, Arguments, sizeof...(args), 0);
return tReturn;
}
int main()
{
printf("[#] Heaven's Gate - START\n");
STARTUPINFOW StartupInfo = { 0 };
PROCESS_INFORMATION ProcessInfo;
BOOL bCreate = CreateProcess(L"C:/Windows/System32/notepad.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo);
if (!bCreate) {
printf("[-] Cannot create process. Error code: %d\n", GetLastError());
return 1;
}
else {
printf("[+] Process created with PID %d\n", ProcessInfo.dwProcessId);
Sleep(1000);
LONG lStatus = Call64<LONG>(L"ntdll.dll", "NtTerminateProcess", ProcessInfo.hProcess);
if (lStatus != ERROR_SUCCESS) {
printf("[-] Error calling 'NtTerminateProcess' (x64). Error code: %d, NtStatus = 0x%08X\n", GetLastError(), lStatus);
CloseHandle(ProcessInfo.hProcess);
}
}
printf("[#] Heaven's Gate - END\n");
return 0;
}
#pragma once
#define EMIT(a) __asm __emit (a)
#define X64_Start_with_CS(_cs) \
{ \
EMIT(0x6A) EMIT(_cs) /* push _cs */ \
EMIT(0xE8) EMIT(0) EMIT(0) EMIT(0) EMIT(0) /* call $+5 */ \
EMIT(0x83) EMIT(4) EMIT(0x24) EMIT(5) /* add dword [esp], 5 */ \
EMIT(0xCB) /* retf */ \
}
#define X64_End_with_CS(_cs) \
{ \
EMIT(0xE8) EMIT(0) EMIT(0) EMIT(0) EMIT(0) /* call $+5 */ \
EMIT(0xC7) EMIT(0x44) EMIT(0x24) EMIT(4) EMIT(_cs) EMIT(0) EMIT(0) EMIT(0) /* mov dword [rsp + 4], _cs */ \
EMIT(0x83) EMIT(4) EMIT(0x24) EMIT(0xD) /* add dword [rsp], 0xD */ \
EMIT(0xCB) /* retf */ \
}
#define X64_Start() X64_Start_with_CS(0x33)
#define X64_End() X64_End_with_CS(0x23)
typedef struct _LDR64
{
unsigned long Length;
unsigned long Initialized;
unsigned long long ssHandle;
LIST_ENTRY64 InLoadOrderModuleList;
LIST_ENTRY64 InMemoryOrderModuleList;
LIST_ENTRY64 InInitializationOrderModuleList;
}LDR64;
typedef struct _PEB64
{
unsigned char InheritedAddressSpace;
unsigned char ReadImageFileExecOptions;
unsigned char BeingDebugged;
unsigned long ImageUsesLargePages : 1;
unsigned long IsProtectedProcess : 1;
unsigned long IsLegacyProcess : 1;
unsigned long IsImageDynamicallyRelocated : 1;
unsigned long SpareBits : 4;
unsigned long long Mutant;
unsigned long long ImageBaseAddress;
unsigned long long Ldr;
}PEB64;
typedef struct _LSA_UNICODE_STRING64 {
USHORT Length;
USHORT MaximumLength;
DWORD64 Buffer;
} UNICODE_STRING64, *PUNICODE_STRING64;
typedef struct _LDR_DATA_TABLE_ENTRY64
{
LIST_ENTRY64 InLoadOrderLinks;
LIST_ENTRY64 InMemoryOrderLinks;
LIST_ENTRY64 InInitializationOrderLinks;
DWORD64 DllBase;
DWORD64 EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING64 FullDllName;
UNICODE_STRING64 BaseDllName;
ULONG Flags;
WORD LoadCount;
} LDR_DATA_TABLE_ENTRY64;
Lo he probado con Visual Studio 2015 Profesional y compila y funciona de maravilla.
[Enlace externo eliminado para invitados]