
// developed by Peter Kleissner

#include "ntddk.h"
#include "windef.h"


/* forward declarations */
NTSTATUS GsDriverEntry(void * ModuleAddress, int (* StonedCallback)(unsigned FunctionNumber, void * Param));
NTSTATUS NotifyDriverLoad(void * ModuleAddress, void * EntryPoint, unsigned SizeOfImage);
NTSTATUS __cdecl HookExAllocatePool(IN UINT32 ReturnEIP, IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes);
NTSTATUS __cdecl HookExAllocatePoolWithTag(IN UINT32 ReturnEIP, IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes, ULONG Tag);
NTSTATUS __cdecl HookExFreePool(IN UINT32 ReturnEIP, IN PVOID P);
NTSTATUS __cdecl InterceptExAllocatePool(IN UINT32 ReturnEIP, IN UINT32 ReturnValueEAX, IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes);
NTSTATUS __cdecl InterceptExAllocatePoolWithTag(IN UINT32 ReturnEIP, IN UINT32 ReturnValueEAX, IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes, ULONG Tag);
NTSTATUS WriteOutFile(void * Address, UINT32 Size, WCHAR * FileName);

/* Stoned Bootkit Framework includes */
#define SbNotifyDriverLoad    0
#define SbInstallWindowsHook  2

#define HookType_Hook         0   // hooking a function = control passed to hook, then original function is called        (before a function is called)
#define HookType_Intercept    1   // intercepting a function = getting function parameters, return value and return eip   (after a function is called)

struct
{
  void * FunctionName;
  void * FunctionHook;
  unsigned Type;
} Hook;

//  HANDLE KernelLogFile;
//  LARGE_INTEGER ByteOffset;


/* the real true driver entry point, name it always GsDriverEntry@8 */

NTSTATUS GsDriverEntry(void * ModuleAddress, int (* StonedCallback)(unsigned FunctionNumber, void * Param))
{
  OBJECT_ATTRIBUTES FileObject;
  IO_STATUS_BLOCK FileIO;
  UNICODE_STRING LogFileName;
//  ByteOffset.QuadPart = 0;

//  DbgPrint("\nWelcome to Stoned 1.0 Sinowal Extractor!\n\n");
  DbgPrint("\nYour PC is now Stoned!  ..again!\n\n");

  // create a log file
  RtlInitUnicodeString(&LogFileName, L"\\??\\C:\\Stoned\\Kernel.log");
  InitializeObjectAttributes(&FileObject, &LogFileName, OBJ_KERNEL_HANDLE, NULL, NULL);
//  ZwCreateFile(&KernelLogFile, FILE_WRITE_DATA, &FileObject, &FileIO, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_SUPERSEDE, FILE_RANDOM_ACCESS, NULL, 0);
//  ZwWriteFile(KernelLogFile, NULL, NULL, NULL, &FileIO, "Starting Sinowal Extractor..\n", sizeof("Starting Sinowal Extractor..\n")-1, &ByteOffset, NULL);
//  ByteOffset.QuadPart += sizeof("Starting Sinowal Extractor..\n")-1;
  
  // register the driver-load notification
  StonedCallback(SbNotifyDriverLoad, &NotifyDriverLoad);
  
  // install hooks
  Hook.FunctionName = "ntoskrnl!ExAllocatePool";
  Hook.FunctionHook = &InterceptExAllocatePool;
  Hook.Type = HookType_Intercept;
  StonedCallback(SbInstallWindowsHook, &Hook);

  Hook.FunctionName = "ntoskrnl!ExAllocatePool";
  Hook.FunctionHook = &HookExAllocatePool;
  Hook.Type = HookType_Hook;
  StonedCallback(SbInstallWindowsHook, &Hook);
  
/*  Hook.FunctionName = "ntoskrnl!ExAllocatePoolWithTag";
  Hook.FunctionHook = &InterceptExAllocatePoolWithTag;
  StonedCallback(SbInstallWindowsHook, &Hook);

  Hook.FunctionName = "ntoskrnl!ExAllocatePoolWithTag";
  Hook.FunctionHook = &HookExAllocatePoolWithTag;
  StonedCallback(SbInstallWindowsHook, &Hook);
*/
  Hook.FunctionName = "ntoskrnl!ExFreePool";
  Hook.FunctionHook = &HookExFreePool;
  StonedCallback(SbInstallWindowsHook, &Hook);
  
  return STATUS_SUCCESS;
}


/* Sinowal extraction variables */
void * SinowalAddress;
unsigned SinowalSize;

int UnpackStatus;
void * SinowalUnpackedAddress;
unsigned SinowalUnpackedSize;


/* called by Stoned when Sinowal is loaded */

NTSTATUS NotifyDriverLoad(void * ModuleAddress, void * EntryPoint, unsigned SizeOfImage)
{
  DbgPrint("Executing Sinowal...\n");
  
  SinowalAddress = ModuleAddress;
  SinowalSize = SizeOfImage;
  UnpackStatus = 0;
  
  return STATUS_SUCCESS;
}


/* hook functions ! */

NTSTATUS __cdecl HookExAllocatePool(IN UINT32 ReturnEIP, IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes)
{
  if (ReturnEIP >= (UINT32)SinowalAddress  &&  ReturnEIP < ((UINT32)SinowalAddress + SinowalSize))
  {
    if (UnpackStatus == 0 && NumberOfBytes > 300000 && NumberOfBytes < 700000)
    {
      UnpackStatus = 1;
      SinowalUnpackedSize = NumberOfBytes;
      DbgPrint(" * Sinowal allocating %u bytes for unpacked driver\n", NumberOfBytes);
    }
    DbgPrint("ExAllocatePool called by Sinowal with Number of Bytes = %u\n", NumberOfBytes);
  }
  else
  {
    DbgPrint("ExAllocatePool called with Number of Bytes = %u\n", /*PoolType, */NumberOfBytes);
  }

  return STATUS_SUCCESS;
}

NTSTATUS __cdecl InterceptExAllocatePool(IN UINT32 ReturnEIP, IN UINT32 ReturnValueEAX, IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes)
{
  if (ReturnEIP >= (UINT32)SinowalAddress  &&  ReturnEIP < ((UINT32)SinowalAddress + SinowalSize))
  DbgPrint("ExAllocatePool intercepted by Sinowal with Address = %08Xh, Number of Bytes = %u\n", ReturnValueEAX, NumberOfBytes);
  else
  DbgPrint("ExAllocatePool intercepted with Address = %08Xh, Number of Bytes = %u\n", ReturnValueEAX, NumberOfBytes);

//  if (ReturnEIP >= (UINT32)SinowalAddress  &&  ReturnEIP < ((UINT32)SinowalAddress + SinowalSize))
  if (UnpackStatus == 1)
  {
    UnpackStatus = 2;
    SinowalUnpackedAddress = (void *)ReturnValueEAX;
//    SinowalUnpackedSize = NumberOfBytes;
    DbgPrint(" * Sinowal will be unpacked to address %08Xh (with size %u) got by ExAllocatePool\n", ReturnValueEAX, SinowalUnpackedSize);
  }

  return STATUS_SUCCESS;
}

NTSTATUS __cdecl HookExFreePool(IN UINT32 ReturnEIP, IN PVOID P)
{
  if (ReturnEIP >= (UINT32)SinowalAddress  &&  ReturnEIP < ((UINT32)SinowalAddress + SinowalSize))
  {
    DbgPrint("ExFreePool called by Sinowal with address = %08Xh\n", P);
  }
  else
  {
    DbgPrint("ExFreePool called with address = %08Xh\n", P);
  }
  
  // write-out (why not)
  if (UnpackStatus == 2)
  {
    UnpackStatus = 3;
    WriteOutFile(SinowalUnpackedAddress, SinowalUnpackedSize, L"\\??\\C:\\Stoned\\Unpacked Sinowal Driver.sys");
  }

  return STATUS_SUCCESS;
}

NTSTATUS __cdecl HookExAllocatePoolWithTag(IN UINT32 ReturnEIP, IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes, ULONG Tag)
{
  DbgPrint("ExAllocatePoolWithTag called with Number of Bytes = %u\n", /*PoolType, */NumberOfBytes/*, Tag*/);

  return STATUS_SUCCESS;
}

NTSTATUS __cdecl InterceptExAllocatePoolWithTag(IN UINT32 ReturnEIP, IN UINT32 ReturnValueEAX, IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes, ULONG Tag)
{
  // Sinowal?
  DbgPrint("ExAllocatePoolWithTag intercepted with Address = %08Xh, Number of Bytes = %u\n", ReturnValueEAX, NumberOfBytes);
  if (ReturnEIP >= (UINT32)SinowalAddress  &&  ReturnEIP < ((UINT32)SinowalAddress + SinowalSize))
  {
    SinowalUnpackedAddress = (void *)ReturnValueEAX;
    SinowalUnpackedSize = NumberOfBytes;
  }

  return STATUS_SUCCESS;
}


/* other helper functions */

NTSTATUS WriteOutFile(void * Address, UINT32 Size, WCHAR * FileName)
{
  HANDLE FileHandle;
  OBJECT_ATTRIBUTES FileObject;
  IO_STATUS_BLOCK FileIO;
  UNICODE_STRING CountedFileName;
  LARGE_INTEGER ByteOffset;

  ByteOffset.QuadPart = 0;

  // create the file
  RtlInitUnicodeString(&CountedFileName, FileName);
  InitializeObjectAttributes(&FileObject, &CountedFileName, OBJ_KERNEL_HANDLE, NULL, NULL);
  ZwCreateFile(&FileHandle, FILE_WRITE_DATA, &FileObject, &FileIO, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, /*FILE_SUPERSEDE*/FILE_CREATE, FILE_RANDOM_ACCESS, NULL, 0);
  
  // write the memory out to the file
  ZwWriteFile(FileHandle, NULL, NULL, NULL, &FileIO, Address, Size, &ByteOffset, NULL);
  
  // close the file, we are not yet Sinowal developers hehe
  ZwClose(FileHandle);

  return STATUS_SUCCESS;
}