diff --git a/.gitignore b/.gitignore
index 4a48ed0..418e99b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,5 @@ Release
tests/logging-test.*
*.suo
*.opendb
+*.VC.db
+.vs/*
diff --git a/CAPE/CAPE.c b/CAPE/CAPE.c
index abfa75b..1145a39 100644
--- a/CAPE/CAPE.c
+++ b/CAPE/CAPE.c
@@ -1,6 +1,6 @@
/*
CAPE - Config And Payload Extraction
-Copyright(C) 2015, 2016 Context Information Security. (kevin.oreilly@contextis.com)
+Copyright(C) 2015 - 2018 Context Information Security. (kevin.oreilly@contextis.com)
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
@@ -15,61 +15,422 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see .
*/
+#define _CRT_RAND_S
+#define MD5LEN 16
+
+#define MAX_PRETRAMP_SIZE 320
+#define MAX_TRAMP_SIZE 128
+
+#define BUFSIZE 1024 // For hashing
+#define DUMP_MAX 100
+#define CAPE_OUTPUT_FILE "CapeOutput.bin"
+
+#include
#include
+#include
#include
#include
#include
#include
#include
+#include
+#include
+#include
+#include
#include "CAPE.h"
#include "Debugger.h"
+#include "..\alloc.h"
#include "..\pipe.h"
#include "..\config.h"
#pragma comment(lib, "Shlwapi.lib")
-#define BUFSIZE 1024 // For hashing
-#define MD5LEN 16
+typedef union _UNWIND_CODE {
+ struct {
+ BYTE CodeOffset;
+ BYTE UnwindOp : 4;
+ BYTE OpInfo : 4;
+ };
+ USHORT FrameOffset;
+} UNWIND_CODE;
+
+typedef struct _UNWIND_INFO {
+ BYTE Version : 3;
+ BYTE Flags : 5;
+ BYTE SizeOfProlog;
+ BYTE CountOfCodes;
+ BYTE FrameRegister : 4;
+ BYTE FrameOffset : 4;
+ UNWIND_CODE UnwindCode[20];
+} UNWIND_INFO;
+
+typedef struct _hook_data_t {
+ unsigned char tramp[MAX_TRAMP_SIZE];
+ unsigned char pre_tramp[MAX_PRETRAMP_SIZE];
+ //unsigned char our_handler[128];
+ unsigned char hook_data[32];
+
+ UNWIND_INFO unwind_info;
+} hook_data_t;
+
+typedef struct _hook_t {
+ const wchar_t *library;
+ const char *funcname;
+ void *addr;
+ void *hook_addr;
+ void *new_func;
+ void **old_func;
+ void *alt_func;
+ int allow_hook_recursion;
+ int fully_emulate;
+ unsigned char numargs;
+ int notail;
+ int is_hooked;
+ hook_data_t *hookdata;
+} hook_t;
+
+typedef struct _hook_info_t {
+ int disable_count;
+ hook_t *last_hook;
+ hook_t *current_hook;
+ ULONG_PTR return_address;
+ ULONG_PTR stack_pointer;
+ ULONG_PTR frame_pointer;
+ ULONG_PTR main_caller_retaddr;
+ ULONG_PTR parent_caller_retaddr;
+} hook_info_t;
+
+extern uint32_t path_from_handle(HANDLE handle, wchar_t *path, uint32_t path_buffer_len);
+extern int called_by_hook(void);
+extern int operate_on_backtrace(ULONG_PTR _esp, ULONG_PTR _ebp, void *extra, int(*func)(void *, ULONG_PTR));
+extern unsigned int address_is_in_stack(PVOID Address);
+extern hook_info_t *hook_info();
+extern ULONG_PTR base_of_dll_of_interest;
+extern wchar_t *our_process_path;
+extern wchar_t *our_commandline;
+extern ULONG_PTR g_our_dll_base;
+extern DWORD g_our_dll_size;
extern void DoOutputDebugString(_In_ LPCTSTR lpOutputString, ...);
extern void DoOutputErrorString(_In_ LPCTSTR lpOutputString, ...);
extern void CapeOutputFile(LPCTSTR lpOutputFile);
-extern int ScyllaDumpCurrentProcess(DWORD NewOEP);
-extern int ScyllaDumpProcess(HANDLE hProcess, DWORD_PTR modBase, DWORD NewOEP);
-extern int ScyllaDumpCurrentProcessFixImports(DWORD NewOEP);
+extern int IsPeImageVirtual(LPVOID Buffer);
+extern int ScyllaDumpCurrentProcess(DWORD_PTR NewOEP);
+extern int ScyllaDumpProcess(HANDLE hProcess, DWORD_PTR modBase, DWORD_PTR NewOEP);
+extern int ScyllaDumpCurrentProcessFixImports(DWORD_PTR NewOEP);
+extern int ScyllaDumpProcessFixImports(HANDLE hProcess, DWORD_PTR modBase, DWORD_PTR NewOEP);
+extern int ScyllaDumpPE(DWORD_PTR Buffer);
+extern BOOL CountDepth(LPVOID* ReturnAddress, LPVOID Address);
+extern SIZE_T GetPESize(PVOID Buffer);
+extern LPVOID GetReturnAddress(hook_info_t *hookinfo);
+extern PVOID CallingModule;
+#ifdef CAPE_TRACE
+extern BOOL SetInitialBreakpoints(PVOID ImageBase);
+extern BOOL BreakpointsSet;
+#endif
+
+BOOL ProcessDumped, FilesDumped, ModuleDumped;
+static unsigned int DumpCount;
+
+static __inline ULONG_PTR get_stack_top(void)
+{
+#ifndef _WIN64
+ return __readfsdword(0x04);
+#else
+ return __readgsqword(0x08);
+#endif
+}
+
+static __inline ULONG_PTR get_stack_bottom(void)
+{
+#ifndef _WIN64
+ return __readfsdword(0x08);
+#else
+ return __readgsqword(0x10);
+#endif
+}
+//**************************************************************************************
+BOOL InsideHook(LPVOID* ReturnAddress, LPVOID Address)
+//**************************************************************************************
+{
+ if ((ULONG_PTR)Address >= g_our_dll_base && (ULONG_PTR)Address < (g_our_dll_base + g_our_dll_size))
+ {
+ if (ReturnAddress)
+ *ReturnAddress = Address;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//**************************************************************************************
+BOOL GetCurrentFrame(LPVOID* ReturnAddress, LPVOID Address)
+//**************************************************************************************
+{
+ *ReturnAddress = Address;
+
+ return TRUE;
+}
+
+//**************************************************************************************
+LPVOID GetReturnAddress(hook_info_t *hookinfo)
+//**************************************************************************************
+{
+ LPVOID ReturnAddress = NULL;
+
+ __try
+ {
+ operate_on_backtrace(hookinfo->stack_pointer, hookinfo->frame_pointer, &ReturnAddress, GetCurrentFrame);
+ return ReturnAddress;
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+#ifdef _WIN64
+ DoOutputDebugString("GetReturnAddress: Exception trying to get return address with Rip 0x%p.\n", hookinfo->frame_pointer);
+#else
+ DoOutputDebugString("GetReturnAddress: Exception trying to get return address with base pointer 0x%x.\n", hookinfo->frame_pointer);
+#endif
+ return NULL;
+ }
+}
+
+//**************************************************************************************
+PVOID GetHookCallerBase()
+//**************************************************************************************
+{
+ PVOID ReturnAddress, AllocationBase;
+ hook_info_t *hookinfo = hook_info();
-static HMODULE s_hInst = NULL;
-static WCHAR s_wzDllPath[MAX_PATH];
-CHAR s_szDllPath[MAX_PATH];
+ if (hookinfo->main_caller_retaddr)
+ ReturnAddress = (PVOID)hookinfo->main_caller_retaddr;
+ else if (hookinfo->parent_caller_retaddr)
+ ReturnAddress = (PVOID)hookinfo->parent_caller_retaddr;
+ //else
+ // ReturnAddress = GetReturnAddress(hookinfo);
+
+ if (ReturnAddress)
+ {
+ DWORD ThreadId = GetCurrentThreadId();
+
+ AllocationBase = GetAllocationBase(ReturnAddress);
+ DoOutputDebugString("GetHookCallerBase: thread %d (handle 0x%x), return address 0x%p, allocation base 0x%p.\n", ThreadId, GetThreadHandle(ThreadId), ReturnAddress, AllocationBase);
+
+ if (AllocationBase)
+ {
+ CallingModule = AllocationBase;
+ return CallingModule;
+ // Base-dependent breakpoints can be activated now
+ }
+ }
+ else
+ DoOutputDebugString("GetHookCallerBase: failed to get return address.\n");
+
+ return NULL;
+}
//**************************************************************************************
void PrintHexBytes(__in char* TextBuffer, __in BYTE* HexBuffer, __in unsigned int Count)
//**************************************************************************************
{
unsigned int i;
-
+
if (HexBuffer == NULL)
return;
-
+
for (i=0; iDumpType = DumpType;
+
+ if (DumpType == INJECTION_PE || DumpType == INJECTION_SHELLCODE)
+ {
+ if (!TargetPid)
+ {
+ DoOutputDebugString("SetCapeMetaData: Injection type with no PID - error.\n");
+ return FALSE;
+ }
+
+ if (!hTargetProcess)
+ {
+ DoOutputDebugString("SetCapeMetaData: Injection type with no process handle - error.\n");
+ return FALSE;
+ }
+
+ CapeMetaData->TargetPid = TargetPid;
+
+ if (CapeMetaData->TargetProcess == NULL)
+ {
+ DoOutputDebugString("SetCapeMetaData: failed to allocate memory for target process string.\n");
+ return FALSE;
+ }
+
+ if (CapeMetaData->TargetProcess == NULL && !GetModuleFileNameEx(hTargetProcess, NULL, CapeMetaData->TargetProcess, MAX_PATH))
+ {
+ CapeMetaData->TargetProcess = (char*)malloc(MAX_PATH);
+ DoOutputErrorString("SetCapeMetaData: GetModuleFileNameEx failed on target process, handle 0x%x", hTargetProcess);
+ return FALSE;
+ }
+ }
+ else if (DumpType == EXTRACTION_PE || DumpType == EXTRACTION_SHELLCODE || DumpType == URSNIF_PAYLOAD)
+ {
+ if (!Address)
+ {
+ DoOutputDebugString("SetCapeMetaData: CAPE type with missing PID - error.\n");
+ return FALSE;
+ }
+
+ CapeMetaData->Address = Address;
+ }
+
+ return TRUE;
+}
+
//**************************************************************************************
BOOL MapFile(HANDLE hFile, unsigned char **Buffer, DWORD* FileSize)
//**************************************************************************************
{
LARGE_INTEGER LargeFileSize;
DWORD dwBytesRead;
-
+
if (!GetFileSizeEx(hFile, &LargeFileSize))
{
- DoOutputErrorString("Cannot get file size");
+ DoOutputErrorString("MapFile: Cannot get file size");
return FALSE;
}
@@ -79,24 +440,30 @@ BOOL MapFile(HANDLE hFile, unsigned char **Buffer, DWORD* FileSize)
return FALSE;
}
+ if (LargeFileSize.LowPart == 0)
+ {
+ DoOutputDebugString("MapFile: File is zero in size.");
+ return FALSE;
+ }
+
*FileSize = LargeFileSize.LowPart;
-
+
DoOutputDebugString("File size: 0x%x", *FileSize);
-
+
*Buffer = malloc(*FileSize);
-
+
if (SetFilePointer(hFile, 0, 0, FILE_BEGIN))
{
DoOutputErrorString("MapFile: Failed to set file pointer");
- return FALSE;
+ return FALSE;
}
-
+
if (*Buffer == NULL)
{
DoOutputErrorString("MapFile: Memory allocation error in MapFile");
return FALSE;
}
-
+
if (FALSE == ReadFile(hFile, (LPVOID)*Buffer, *FileSize, &dwBytesRead, NULL))
{
DoOutputErrorString("ReadFile error");
@@ -106,7 +473,7 @@ BOOL MapFile(HANDLE hFile, unsigned char **Buffer, DWORD* FileSize)
if (dwBytesRead > 0 && dwBytesRead < *FileSize)
{
- DoOutputErrorString("MapFile: Unexpected size read in.");
+ DoOutputErrorString("MapFile: Unexpected size read in");
free(Buffer);
return FALSE;
@@ -117,10 +484,75 @@ BOOL MapFile(HANDLE hFile, unsigned char **Buffer, DWORD* FileSize)
free(Buffer);
return FALSE;
}
-
+
return TRUE;
}
+//**************************************************************************************
+char* GetName()
+//**************************************************************************************
+{
+ char *OutputFilename, *FullPathName;
+ SYSTEMTIME Time;
+ DWORD RetVal;
+ unsigned int random;
+
+ FullPathName = (char*) malloc(MAX_PATH);
+
+ if (FullPathName == NULL)
+ {
+ DoOutputErrorString("GetName: Error allocating memory for full path string");
+ return 0;
+ }
+
+ OutputFilename = (char*)malloc(MAX_PATH);
+
+ if (OutputFilename == NULL)
+ {
+ DoOutputErrorString("GetName: failed to allocate memory for file name string");
+ return 0;
+ }
+
+ GetSystemTime(&Time);
+
+ if (rand_s(&random))
+ {
+ DoOutputErrorString("GetName: failed to obtain a random number");
+ return 0;
+ }
+
+ sprintf_s(OutputFilename, MAX_PATH*sizeof(char), "%d_%d%d%d%d%d%d%d%d", GetCurrentProcessId(), abs(random * Time.wMilliseconds), Time.wSecond, Time.wMinute, Time.wHour, Time.wDay, Time.wDayOfWeek, Time.wMonth, Time.wYear);
+
+ // We want to dump CAPE output to the 'analyzer' directory
+ memset(FullPathName, 0, MAX_PATH);
+
+ strncpy_s(FullPathName, MAX_PATH, g_config.analyzer, strlen(g_config.analyzer)+1);
+
+ if (strlen(FullPathName) + strlen("\\CAPE\\") + strlen(OutputFilename) >= MAX_PATH)
+ {
+ DoOutputDebugString("GetName: Error, CAPE destination path too long.");
+ free(OutputFilename);
+ free(FullPathName);
+ return 0;
+ }
+
+ PathAppend(FullPathName, "CAPE");
+
+ RetVal = CreateDirectory(FullPathName, NULL);
+
+ if (RetVal == 0 && GetLastError() != ERROR_ALREADY_EXISTS)
+ {
+ DoOutputDebugString("GetName: Error creating output directory");
+ free(OutputFilename);
+ free(FullPathName);
+ return 0;
+ }
+
+ PathAppend(FullPathName, OutputFilename);
+
+ return FullPathName;
+}
+
//**************************************************************************************
BOOL GetHash(unsigned char* Buffer, unsigned int Size, char* OutputFilenameBuffer)
//**************************************************************************************
@@ -141,14 +573,14 @@ BOOL GetHash(unsigned char* Buffer, unsigned int Size, char* OutputFilenameBuffe
if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
{
- DoOutputErrorString("CryptCreateHash failed");
+ DoOutputErrorString("CryptCreateHash failed");
CryptReleaseContext(hProv, 0);
return 0;
}
if (!CryptHashData(hHash, Buffer, Size, 0))
{
- DoOutputErrorString("CryptHashData failed");
+ DoOutputErrorString("CryptHashData failed");
CryptReleaseContext(hProv, 0);
CryptDestroyHash(hHash);
return 0;
@@ -157,17 +589,17 @@ BOOL GetHash(unsigned char* Buffer, unsigned int Size, char* OutputFilenameBuffe
cbHash = MD5LEN;
if (!CryptGetHashParam(hHash, HP_HASHVAL, MD5Hash, &cbHash, 0))
{
- DoOutputErrorString("CryptGetHashParam failed");
+ DoOutputErrorString("CryptGetHashParam failed");
}
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
-
+
for (i = 0; i < cbHash; i++)
{
PrintHexBytes(OutputFilenameBuffer, MD5Hash, MD5LEN);
}
-
+
return 1;
}
@@ -182,21 +614,25 @@ char* GetHashFromHandle(HANDLE hFile)
char * OutputFilenameBuffer;
if (!MapFile(hFile, &Buffer, &FileSize))
- {
- DoOutputErrorString("MapFile error - check path!");
+ {
+ DoOutputErrorString("MapFile error - check the path is valid and the file has size.");
return 0;
}
-
+
OutputFilenameBuffer = (char*) malloc(MAX_PATH);
if (OutputFilenameBuffer == NULL)
{
- DoOutputErrorString("Error allocating memory for hash string.");
- return 0;
+ DoOutputErrorString("Error allocating memory for hash string");
+ return 0;
+ }
+
+ if (!GetHash(Buffer, FileSize, (char*)OutputFilenameBuffer))
+ {
+ DoOutputErrorString("GetHashFromHandle: GetHash function failed");
+ return 0;
}
-
- GetHash(Buffer, FileSize, (char*)OutputFilenameBuffer);
-
+
DoOutputDebugString("GetHash returned: %s", OutputFilenameBuffer);
// Check if we have a valid DOS and PE header at the beginning of Buffer
@@ -204,7 +640,7 @@ char* GetHashFromHandle(HANDLE hFile)
{
e_lfanew = *(long*)(Buffer+0x3c);
- if ((unsigned int)e_lfanew>PE_HEADER_LIMIT)
+ if ((unsigned int)e_lfanew > PE_HEADER_LIMIT)
{
// This check is possibly not appropriate here
// As long as we've got what's been compressed
@@ -224,12 +660,12 @@ char* GetHashFromHandle(HANDLE hFile)
}
}
}
-
+
CloseHandle(hFile);
-
+
// We don't need the file buffer any more
free(Buffer);
-
+
// We leak the OutputFilenameBuffer
return OutputFilenameBuffer;
}
@@ -239,10 +675,9 @@ int DumpXorPE(LPBYTE Buffer, unsigned int Size)
//**************************************************************************************
{
LONG e_lfanew;
- DWORD NT_Signature, FullKey;
- WORD TestKey;
- unsigned int i, j, k, rotation;
- BYTE* DecryptedBuffer;
+ DWORD NT_Signature;
+ unsigned int i, j, k;
+ BYTE* DecryptedBuffer = NULL;
for (i=0; i<=0xFF; i++)
{
@@ -254,23 +689,23 @@ int DumpXorPE(LPBYTE Buffer, unsigned int Size)
e_lfanew = (LONG)*(DWORD*)(Buffer+0x3c);
DoOutputDebugString("Encrypted e_lfanew: 0x%x", e_lfanew);
-
+
for (j=0; j PE_HEADER_LIMIT)
- {
+ {
DoOutputDebugString("The pointer to the PE header seems a tad large: 0x%x", e_lfanew);
//return FALSE;
}
// let's get the NT signature a.k.a PE header
memcpy(&NT_Signature, Buffer+e_lfanew, 4);
-
+
DoOutputDebugString("Encrypted NT_Signature: 0x%x", NT_Signature);
-
+
// let's try decrypting it with the key
for (k=0; k<4; k++)
*((BYTE*)&NT_Signature+k) = *((BYTE*)&NT_Signature+k)^i;
@@ -281,306 +716,624 @@ int DumpXorPE(LPBYTE Buffer, unsigned int Size)
if (NT_Signature == IMAGE_NT_SIGNATURE)
{
DoOutputDebugString("Xor-encrypted PE detected, about to dump.\n");
-
+
DecryptedBuffer = (BYTE*)malloc(Size);
-
+
if (DecryptedBuffer == NULL)
{
- DoOutputErrorString(TEXT("Error allocating memory for decrypted PE binary."));
+ DoOutputErrorString("Error allocating memory for decrypted PE binary");
return FALSE;
}
-
+
memcpy(DecryptedBuffer, Buffer, Size);
-
+
for (k=0; kAddress = DecryptedBuffer;
+ DumpImageInCurrentProcess(DecryptedBuffer);
+
free(DecryptedBuffer);
- return TRUE;
+ return i;
}
else
{
- DoOutputDebugString("PE signature invalid, looks like a false positive! 1 in 0x10000!!\n");
+ DoOutputDebugString("PE signature invalid, looks like a false positive.\n");
return FALSE;
}
}
}
-#ifndef _WIN64
- for (i=0; i<=0xffff; i++)
- {
- // check for the DOS signature a.k.a MZ header
- if ((*(WORD*)Buffer^(WORD)i) == IMAGE_DOS_SIGNATURE)
- {
- DoOutputDebugString("MZ header found with wordwise XOR key 0x%.2x%.2x\n", *(BYTE*)&i, *((BYTE*)&i+1));
-
- // let's try just the little end of the full lfanew which is almost always the whole value anyway
- e_lfanew = *(WORD*)(Buffer+0x3c);
- // try and decrypt
- e_lfanew = e_lfanew^(WORD)i;
+ // We free can free DecryptedBuffer as it's no longer needed
+ if(DecryptedBuffer)
+ free(DecryptedBuffer);
- if ((unsigned int)e_lfanew > PE_HEADER_LIMIT)
- {
- // even if dword-encrypted,
- // if the little endian word of the dword takes it too far it's over
- DoOutputDebugString("Sadly the pointer to the PE header seems a tad too large: 0x%x", e_lfanew);
- //return FALSE;
- }
+ return FALSE;
+}
- // get PE header
- memcpy(&NT_Signature, Buffer+e_lfanew, 4);
-
- // We need to rotate our key for a non-dword aligned offset
- TestKey = i;
- if (e_lfanew % 2)
- {
- __asm
- {
- mov ax, TestKey
- ror ax, 8
- mov TestKey, ax
- }
- }
-
- // let's try decrypting it with the word key
- for (k=0; k<2; k++)
- *((WORD*)&NT_Signature+k) = *((WORD*)&NT_Signature+k)^TestKey;
-
- // does it check out?
- if (NT_Signature == IMAGE_NT_SIGNATURE)
- {
- DoOutputDebugString("Xor-encrypted PE detected, about to dump.\n");
-
- DecryptedBuffer = (BYTE*)malloc(Size);
-
- if (DecryptedBuffer == NULL)
- {
- DoOutputErrorString(TEXT("Error allocating memory for decrypted PE binary."));
- return FALSE;
- }
-
- memcpy(DecryptedBuffer, Buffer, Size);
-
- for (k=0; ke_lfanew == 0)
{
- DoOutputDebugString("Xor-encrypted PE detected, about to dump.\n");
-
- DecryptedBuffer = (BYTE*)malloc(Size);
-
- if (DecryptedBuffer == NULL)
- {
- DoOutputErrorString(TEXT("Error allocating memory for decrypted PE binary."));
- return FALSE;
- }
-
- memcpy(DecryptedBuffer, Buffer, Size);
-
- for (k=0; k PE_HEADER_LIMIT)
- {
- continue;
- }
-
- memcpy(&NT_Signature, Buffer+full_lfanew, 4);
-
- // We need to rotate our key for a non-dword aligned offset
- FullKey = i + (TestKey<<16);
- for (rotation = 0; rotation<(unsigned int)(full_lfanew % 4); rotation++)
- {
- __asm
- {
- mov eax, FullKey
- ror eax, 8
- mov FullKey, eax
- }
- }
-
- // let's try decrypting it with the key
- if ((NT_Signature ^ FullKey) == IMAGE_NT_SIGNATURE)
+ if ((ULONG)pDosHeader->e_lfanew > Size-p)
{
- DoOutputDebugString("Xor-encrypted PE detected, about to dump.\n");
-
- DecryptedBuffer = (BYTE*)malloc(Size);
-
- if (DecryptedBuffer == NULL)
- {
- DoOutputErrorString(TEXT("Error allocating memory for decrypted PE binary."));
- return FALSE;
- }
-
- memcpy(DecryptedBuffer, Buffer, Size);
-
- for (k=0; ke_lfanew);
+
+ if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
+ {
+ // No 'PE' header
+ continue;
+ }
+
+ if ((pNtHeader->FileHeader.Machine == 0) || (pNtHeader->FileHeader.SizeOfOptionalHeader == 0 || pNtHeader->OptionalHeader.SizeOfHeaders == 0))
+ {
+ // Basic requirements
+ DoOutputDebugString("ScanForPE: Basic requirements failure.\n");
+ continue;
+ }
+
+ if (Offset)
+ {
+ *Offset = (LPVOID)((char*)Buffer+p);
+ }
+
+ DoOutputDebugString("ScanForPE: PE image located at: 0x%x\n", (DWORD_PTR)((char*)Buffer+p));
+
+ return 1;
+ }
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DoOutputDebugString("ScanForPE: Exception occured reading memory address 0x%x\n", (DWORD_PTR)((char*)Buffer+p));
+ return 0;
+ }
+ }
+
+ DoOutputDebugString("ScanForPE: No PE image located at 0x%x.\n", Buffer);
+ return 0;
}
//**************************************************************************************
-int DumpMemory(LPCVOID Buffer, unsigned int Size)
+BOOL TestPERequirements(PIMAGE_NT_HEADERS pNtHeader)
//**************************************************************************************
{
- char *OutputFilename, *FullPathName;
- DWORD RetVal, dwBytesWritten;
- HANDLE hOutputFile;
+ __try
+ {
+ if ((pNtHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) && (pNtHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC))
+ {
+ //DoOutputDebugString("TestPERequirements: OptionalHeader.Magic bad. (0x%x)", (DWORD_PTR)pNtHeader); // extremely noisy
+ return FALSE;
+ }
+ //else
+ // DoOutputDebugString("TestPERequirements: OptionalHeader.Magic ok!: 0x%x (0x%x)", pNtHeader->OptionalHeader.Magic, (DWORD_PTR)pNtHeader);
+
+ // Basic requirements
+ if
+ (
+ pNtHeader->FileHeader.Machine == 0 ||
+ pNtHeader->FileHeader.SizeOfOptionalHeader == 0 ||
+ pNtHeader->OptionalHeader.SizeOfHeaders == 0 //||
+ //pNtHeader->OptionalHeader.FileAlignment == 0
+ )
+ {
+ //DoOutputDebugString("TestPERequirements: Basic requirements failure (0x%x).\n", (DWORD_PTR)pNtHeader); // very noisy
+ return FALSE;
+ }
- OutputFilename = (char*) malloc(MAX_PATH);
- FullPathName = (char*) malloc(MAX_PATH);
+ if (!(pNtHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE))
+ {
+ DoOutputDebugString("TestPERequirements: Characteristics bad. (0x%x)", (DWORD_PTR)pNtHeader);
+ return FALSE;
+ }
- if (OutputFilename == NULL || FullPathName == NULL)
+ if (pNtHeader->FileHeader.SizeOfOptionalHeader & (sizeof (ULONG_PTR) - 1))
+ {
+ DoOutputDebugString("TestPERequirements: SizeOfOptionalHeader bad. (0x%x)", (DWORD_PTR)pNtHeader);
+ return FALSE;
+ }
+
+ if (((pNtHeader->OptionalHeader.FileAlignment-1) & pNtHeader->OptionalHeader.FileAlignment) != 0)
+ {
+ DoOutputDebugString("TestPERequirements: FileAlignment invalid. (0x%x)", (DWORD_PTR)pNtHeader);
+ return FALSE;
+ }
+
+ if (pNtHeader->OptionalHeader.SectionAlignment < pNtHeader->OptionalHeader.FileAlignment)
+ {
+ DoOutputDebugString("TestPERequirements: FileAlignment greater than SectionAlignment.\n (0x%x)", (DWORD_PTR)pNtHeader);
+ return FALSE;
+ }
+
+ // To pass the above tests it should now be safe to assume it's a PE image
+ return TRUE;
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
{
- DoOutputErrorString("DumpMemory: Error allocating memory for strings");
- return 0;
+ DoOutputDebugString("TestPERequirements: Exception occured reading region at 0x%x\n", (DWORD_PTR)(pNtHeader));
+ return FALSE;
}
-
- GetHash((LPVOID)Buffer, Size, (char*)OutputFilename);
-
- DoOutputDebugString("GetHash returned: %s", OutputFilename);
+}
- sprintf_s((OutputFilename+2*MD5LEN), MAX_PATH*sizeof(char)-2*MD5LEN, ".bin");
+//**************************************************************************************
+int IsDisguisedPEHeader(LPVOID Buffer)
+//**************************************************************************************
+{
+ PIMAGE_DOS_HEADER pDosHeader;
+ PIMAGE_NT_HEADERS pNtHeader = NULL;
+ WORD* MachineProbe;
- // We want to dump CAPE output to the 'analyzer' directory
- memset(FullPathName, 0, MAX_PATH);
-
- strncpy_s(FullPathName, MAX_PATH, g_config.analyzer, strlen(g_config.analyzer)+1);
+ __try
+ {
+ pDosHeader = (PIMAGE_DOS_HEADER)Buffer;
- if (strlen(FullPathName) + strlen("\\CAPE\\") + strlen(OutputFilename) >= MAX_PATH)
- {
- DoOutputDebugString("Error, CAPE destination path too long.");
- free(OutputFilename); free(FullPathName);
- return 0;
- }
+ if (pDosHeader->e_lfanew && (ULONG)pDosHeader->e_lfanew < PE_HEADER_LIMIT && ((ULONG)pDosHeader->e_lfanew & 3) == 0)
+ pNtHeader = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + (ULONG)pDosHeader->e_lfanew);
- PathAppend(FullPathName, "CAPE");
+ if (!pDosHeader->e_lfanew)
+ {
+ // In case the header until and including 'PE' has been zeroed
+ MachineProbe = (WORD*)&pDosHeader->e_lfanew;
+ while ((PUCHAR)MachineProbe < (PUCHAR)&pDosHeader + (PE_HEADER_LIMIT - offsetof(IMAGE_DOS_HEADER, e_lfanew)))
+ {
+ if (*MachineProbe == IMAGE_FILE_MACHINE_I386 || *MachineProbe == IMAGE_FILE_MACHINE_AMD64)
+ {
+ pNtHeader = (PIMAGE_NT_HEADERS)((PUCHAR)MachineProbe - 4);
+ break;
+ }
+ MachineProbe += sizeof(WORD);
+ }
+ }
- RetVal = CreateDirectory(FullPathName, NULL);
+ if (pNtHeader && TestPERequirements(pNtHeader))
+ return 1;
- if (RetVal == 0 && GetLastError() != ERROR_ALREADY_EXISTS)
- {
- DoOutputDebugString("Error creating output directory");
- free(OutputFilename); free(FullPathName);
- return 0;
- }
+ // In case the header until and including 'PE' is missing
+ MachineProbe = (WORD*)Buffer;
+ pNtHeader = NULL;
+ while ((PUCHAR)MachineProbe < (PUCHAR)pDosHeader + (PE_HEADER_LIMIT - offsetof(IMAGE_DOS_HEADER, e_lfanew)))
+ {
+ if (*MachineProbe == IMAGE_FILE_MACHINE_I386 || *MachineProbe == IMAGE_FILE_MACHINE_AMD64)
+ {
+ if ((PUCHAR)MachineProbe >= (PUCHAR)pDosHeader + 4)
+ {
+ pNtHeader = (PIMAGE_NT_HEADERS)((PUCHAR)MachineProbe - 4);
+ break;
+ }
+ }
+ MachineProbe += sizeof(WORD);
+ }
+
+ if (pNtHeader && TestPERequirements(pNtHeader))
+ return 1;
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DoOutputDebugString("IsDisguisedPEHeader: Exception occured reading region at 0x%x\n", (DWORD_PTR)(Buffer));
+ return -1;
+ }
+
+ //DoOutputDebugString("IsDisguisedPEHeader: No PE image located\n (0x%x)", (DWORD_PTR)Buffer);
+ return 0;
+}
+
+//**************************************************************************************
+int ScanForDisguisedPE(LPVOID Buffer, SIZE_T Size, LPVOID* Offset)
+//**************************************************************************************
+{
+ SIZE_T p;
+ int RetVal;
+
+ if (Size == 0)
+ {
+ DoOutputDebugString("ScanForDisguisedPE: Error, zero size given\n");
+ return 0;
+ }
+
+ for (p=0; p < Size - PE_HEADER_LIMIT; p++) // we want to stop short of the max look-ahead in IsDisguisedPEHeader
+ {
+ RetVal = IsDisguisedPEHeader((BYTE*)Buffer+p);
+
+ if (!RetVal)
+ continue;
+ else if (RetVal == -1)
+ {
+ DoOutputDebugString("ScanForDisguisedPE: Exception occured scanning buffer at 0x%x\n", (DWORD_PTR)((BYTE*)Buffer+p));
+ return 0;
+ }
+
+ if (Offset)
+ {
+ *Offset = (LPVOID)((BYTE*)Buffer+p);
+ }
+
+ DoOutputDebugString("ScanForDisguisedPE: PE image located at: 0x%x\n", (DWORD_PTR)((BYTE*)Buffer+p));
+
+ return 1;
+ }
+
+ DoOutputDebugString("ScanForDisguisedPE: No PE image located in range 0x%x-0x%x.\n", Buffer, (DWORD_PTR)Buffer + Size);
+ return 0;
+}
+
+//**************************************************************************************
+BOOL DumpPEsInRange(LPVOID Buffer, SIZE_T Size)
+//**************************************************************************************
+{
+ PBYTE PEImage;
+ PIMAGE_DOS_HEADER pDosHeader;
+ PIMAGE_NT_HEADERS pNtHeader = NULL;
+
+ BOOL RetVal = FALSE;
+ LPVOID PEPointer = Buffer;
+
+ DoOutputDebugString("DumpPEsInRange: Scanning range 0x%x - 0x%x.\n", Buffer, (BYTE*)Buffer + Size);
+
+ while (ScanForDisguisedPE(PEPointer, Size - ((DWORD_PTR)PEPointer - (DWORD_PTR)Buffer), &PEPointer))
+ {
+ pDosHeader = (PIMAGE_DOS_HEADER)PEPointer;
+
+ if (*(WORD*)PEPointer != IMAGE_DOS_SIGNATURE || (*(DWORD*)((BYTE*)pDosHeader + pDosHeader->e_lfanew) != IMAGE_NT_SIGNATURE))
+ {
+ DoOutputDebugString("DumpPEsInRange: Disguised PE image (bad MZ and/or PE headers) at 0x%x.\n", PEPointer);
+
+ // We want to fix the PE header in the dump (for e.g. disassembly etc)
+ PEImage = (BYTE*)calloc(Size - ((DWORD_PTR)PEPointer - (DWORD_PTR)Buffer), sizeof(PUCHAR));
+ memcpy(PEImage, PEPointer, Size - ((DWORD_PTR)PEPointer - (DWORD_PTR)Buffer));
+ pDosHeader = (PIMAGE_DOS_HEADER)(PEImage);
+
+ if (!pDosHeader->e_lfanew)
+ {
+ // In case the header until and including 'PE' has been zeroed
+ WORD* MachineProbe = (WORD*)&pDosHeader->e_lfanew;
+ while ((PUCHAR)MachineProbe < (PUCHAR)pDosHeader + (PE_HEADER_LIMIT - offsetof(IMAGE_DOS_HEADER, e_lfanew)))
+ {
+ if (*MachineProbe == IMAGE_FILE_MACHINE_I386 || *MachineProbe == IMAGE_FILE_MACHINE_AMD64)
+ {
+ if ((PUCHAR)MachineProbe > (PUCHAR)pDosHeader + 3)
+ pNtHeader = (PIMAGE_NT_HEADERS)((PUCHAR)MachineProbe - 4);
+ }
+ MachineProbe += sizeof(WORD);
+ }
+
+ if (pNtHeader)
+ pDosHeader->e_lfanew = (LONG)((PUCHAR)pNtHeader - (PUCHAR)pDosHeader);
+ }
+
+ if (!pDosHeader->e_lfanew)
+ {
+ // In case the header until and including 'PE' is missing
+ pNtHeader = NULL;
+ WORD* MachineProbe = (WORD*)pDosHeader;
+ while ((PUCHAR)MachineProbe < (PUCHAR)pDosHeader + (PE_HEADER_LIMIT - offsetof(IMAGE_DOS_HEADER, e_lfanew)))
+ {
+ if (*MachineProbe == IMAGE_FILE_MACHINE_I386 || *MachineProbe == IMAGE_FILE_MACHINE_AMD64)
+ {
+ if ((PUCHAR)MachineProbe >= (PUCHAR)pDosHeader + 4)
+ {
+ pNtHeader = (PIMAGE_NT_HEADERS)((PUCHAR)MachineProbe - 4);
+ //break;
+ }
+ }
+
+ MachineProbe += sizeof(WORD);
+
+ if (pNtHeader && (PUCHAR)pNtHeader == (PUCHAR)pDosHeader && pNtHeader->OptionalHeader.SizeOfHeaders)
+ {
+ SIZE_T HeaderShift = sizeof(IMAGE_DOS_HEADER);
+ memmove(PEImage + HeaderShift, PEImage, pNtHeader->OptionalHeader.SizeOfHeaders - HeaderShift);
+ memset(PEImage, 0, HeaderShift);
+ pDosHeader = (PIMAGE_DOS_HEADER)PEImage;
+ pNtHeader = (PIMAGE_NT_HEADERS)(PEImage + HeaderShift);
+ pDosHeader->e_lfanew = (LONG)((PUCHAR)pNtHeader - (PUCHAR)pDosHeader);
+ DoOutputDebugString("DumpPEsInRange: pNtHeader moved from 0x%x to 0x%x, e_lfanew 0x%x\n", pDosHeader, pNtHeader, pDosHeader->e_lfanew);
+ }
+ }
+ }
+
+ *(WORD*)pDosHeader = IMAGE_DOS_SIGNATURE;
+ *(DWORD*)((PUCHAR)pDosHeader + pDosHeader->e_lfanew) = IMAGE_NT_SIGNATURE;
+
+#ifdef CAPE_INJECTION
+ SetCapeMetaData(INJECTION_PE, 0, NULL, (PVOID)pDosHeader);
+#endif
+
+ if (DumpImageInCurrentProcess((LPVOID)pDosHeader))
+ {
+ DoOutputDebugString("DumpPEsInRange: Dumped PE image from 0x%x.\n", pDosHeader);
+ RetVal = TRUE;
+ }
+ else
+ DoOutputDebugString("DumpPEsInRange: Failed to dump PE image from 0x%x.\n", pDosHeader);
+
+ if (PEImage)
+ free(PEImage);
+ }
+ else
+ {
+ SetCapeMetaData(INJECTION_PE, 0, NULL, (PVOID)PEPointer);
+
+ if (DumpImageInCurrentProcess((LPVOID)PEPointer))
+ {
+ DoOutputDebugString("DumpPEsInRange: Dumped PE image from 0x%x.\n", PEPointer);
+ RetVal = TRUE;
+ }
+ else
+ DoOutputDebugString("DumpPEsInRange: Failed to dump PE image from 0x%x.\n", PEPointer);
+ }
+
+ (BYTE*)PEPointer += PE_HEADER_LIMIT;
+ }
+
+ return RetVal;
+}
+
+//**************************************************************************************
+int DumpMemory(LPVOID Buffer, SIZE_T Size)
+//**************************************************************************************
+{
+ char *FullPathName;
+ DWORD dwBytesWritten;
+ HANDLE hOutputFile;
+ LPVOID BufferCopy;
+
+ FullPathName = GetName();
- PathAppend(FullPathName, OutputFilename);
-
- DoOutputDebugString("DEBUG: FullPathName = %s", FullPathName);
-
hOutputFile = CreateFile(FullPathName, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
-
- DoOutputDebugString("CreateFile returned: 0x%x", hOutputFile);
-
+
if (hOutputFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_EXISTS)
{
- DoOutputDebugString("CAPE output filename exists already: %s", FullPathName);
- free(OutputFilename); free(FullPathName);
+ DoOutputDebugString("DumpMemory: CAPE output filename exists already: %s", FullPathName);
+ free(FullPathName);
return 0;
}
- DoOutputDebugString("Passed file_exists check");
-
if (hOutputFile == INVALID_HANDLE_VALUE)
{
- DoOutputErrorString("Could not create CAPE output file");
- free(OutputFilename); free(FullPathName);
- return 0;
- }
- DoOutputDebugString("Passed invalid_handle check");
-
+ DoOutputErrorString("DumpMemory: Could not create CAPE output file");
+ free(FullPathName);
+ return 0;
+ }
+
dwBytesWritten = 0;
-
- DoOutputDebugString("CAPE output file succssfully created:%s", FullPathName);
- if (FALSE == WriteFile(hOutputFile, Buffer, Size, &dwBytesWritten, NULL))
+ DoOutputDebugString("DumpMemory: CAPE output file successfully created: %s", FullPathName);
+
+ BufferCopy = (LPVOID)((BYTE*)malloc(Size));
+
+ if (BufferCopy == NULL)
+ {
+ DoOutputDebugString("DumpMemory: Failed to allocate memory for buffer copy.\n");
+ return FALSE;
+ }
+
+ __try
+ {
+ memcpy(BufferCopy, Buffer, Size);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DoOutputDebugString("DumpMemory: Exception occured reading memory address 0x%x\n", Buffer);
+ return 0;
+ }
+
+ if (FALSE == WriteFile(hOutputFile, BufferCopy, (DWORD)Size, &dwBytesWritten, NULL))
{
- DoOutputDebugString("WriteFile error on CAPE output file");
- free(OutputFilename); free(FullPathName);
+ DoOutputErrorString("DumpMemory: WriteFile error on CAPE output file");
+ free(FullPathName);
+ free(BufferCopy);
return 0;
}
- DoOutputDebugString("CAPE output filename: %s", FullPathName);
-
CloseHandle(hOutputFile);
-
+
+ CapeMetaData->Address = Buffer;
+ CapeMetaData->Size = Size;
+
CapeOutputFile(FullPathName);
-
+
// We can free the filename buffers
- free(OutputFilename); free(FullPathName);
-
+ free(FullPathName);
+ free(BufferCopy);
+
return 1;
}
//**************************************************************************************
-int DumpCurrentProcessFixImports(DWORD NewEP)
+BOOL DumpRegion(PVOID Address)
+//**************************************************************************************
+{
+ MEMORY_BASIC_INFORMATION MemInfo;
+ PVOID OriginalAllocationBase, OriginalBaseAddress, AddressOfPage;
+ SIZE_T AllocationSize, OriginalRegionSize;
+
+ if (!SystemInfo.dwPageSize)
+ GetSystemInfo(&SystemInfo);
+
+ if (!SystemInfo.dwPageSize)
+ {
+ DoOutputErrorString("DumpRegion: Failed to obtain system page size.\n");
+ return 0;
+ }
+
+ if (!VirtualQuery(Address, &MemInfo, sizeof(MEMORY_BASIC_INFORMATION)))
+ {
+ DoOutputErrorString("DumpRegion: unable to query memory address 0x%x", Address);
+ return 0;
+ }
+
+ OriginalAllocationBase = MemInfo.AllocationBase;
+ OriginalBaseAddress = MemInfo.BaseAddress;
+ OriginalRegionSize = MemInfo.RegionSize;
+ AddressOfPage = OriginalAllocationBase;
+
+ while (MemInfo.AllocationBase == OriginalAllocationBase)
+ {
+ (PUCHAR)AddressOfPage += SystemInfo.dwPageSize;
+
+ if (!VirtualQuery(AddressOfPage, &MemInfo, sizeof(MEMORY_BASIC_INFORMATION)))
+ {
+ DoOutputErrorString("DumpRegion: unable to query memory page 0x%x", AddressOfPage);
+ return 0;
+ }
+ }
+
+ AllocationSize = (SIZE_T)((DWORD_PTR)AddressOfPage - (DWORD_PTR)OriginalAllocationBase);
+
+ SetCapeMetaData(EXTRACTION_SHELLCODE, 0, NULL, (PVOID)OriginalAllocationBase);
+
+ if (DumpMemory(OriginalAllocationBase, AllocationSize))
+ {
+ if (address_is_in_stack(Address))
+ DoOutputDebugString("DumpRegion: Dumped stack region from 0x%p, size 0x%x.\n", OriginalAllocationBase, AllocationSize);
+ else
+ DoOutputDebugString("DumpRegion: Dumped entire allocation from 0x%p, size 0x%x.\n", OriginalAllocationBase, AllocationSize);
+ return TRUE;
+ }
+ else
+ {
+ DoOutputDebugString("DumpRegion: Failed to dump entire allocation from 0x%p size 0x%x.\n", OriginalAllocationBase, AllocationSize);
+
+ SetCapeMetaData(EXTRACTION_SHELLCODE, 0, NULL, (PVOID)OriginalBaseAddress);
+
+ if (DumpMemory(OriginalBaseAddress, OriginalRegionSize))
+ {
+ if (address_is_in_stack(Address))
+ DoOutputDebugString("DumpRegion: Dumped stack region from 0x%p, size 0x%x.\n", OriginalBaseAddress, OriginalRegionSize);
+ else
+ DoOutputDebugString("DumpRegion: Dumped base address 0x%p, size 0x%x.\n", OriginalBaseAddress, OriginalRegionSize);
+ return TRUE;
+ }
+ else
+ {
+ DoOutputDebugString("DumpRegion: Failed to dump base address 0x%p size 0x%x.\n", OriginalBaseAddress, OriginalRegionSize);
+ return FALSE;
+ }
+ }
+}
+
+//**************************************************************************************
+int DumpCurrentProcessFixImports(LPVOID NewEP)
//**************************************************************************************
{
- if (ScyllaDumpCurrentProcessFixImports(NewEP))
+ if (DumpCount < DUMP_MAX && ScyllaDumpCurrentProcessFixImports((DWORD_PTR)NewEP))
{
+ DumpCount++;
return 1;
}
@@ -588,11 +1341,12 @@ int DumpCurrentProcessFixImports(DWORD NewEP)
}
//**************************************************************************************
-int DumpCurrentProcessNewEP(DWORD NewEP)
+int DumpCurrentProcessNewEP(LPVOID NewEP)
//**************************************************************************************
{
- if (ScyllaDumpCurrentProcess(NewEP))
+ if (DumpCount < DUMP_MAX && ScyllaDumpCurrentProcess((DWORD_PTR)NewEP))
{
+ DumpCount++;
return 1;
}
@@ -603,8 +1357,9 @@ int DumpCurrentProcessNewEP(DWORD NewEP)
int DumpCurrentProcess()
//**************************************************************************************
{
- if (ScyllaDumpCurrentProcess(0))
+ if (DumpCount < DUMP_MAX && ScyllaDumpCurrentProcess(0))
{
+ DumpCount++;
return 1;
}
@@ -612,11 +1367,132 @@ int DumpCurrentProcess()
}
//**************************************************************************************
-int DumpProcess(HANDLE hProcess, DWORD_PTR ImageBase)
+int DumpModuleInCurrentProcess(LPVOID ModuleBase)
+//**************************************************************************************
+{
+ PIMAGE_DOS_HEADER pDosHeader;
+
+ if (!IsDisguisedPEHeader(ModuleBase))
+ {
+ DoOutputDebugString("DumpModuleInCurrentProcess: Not a valid image at 0x%p - cannot dump.\n", ModuleBase);
+ return 0;
+ }
+
+ pDosHeader = (PIMAGE_DOS_HEADER)ModuleBase;
+
+ if (*(WORD*)ModuleBase != IMAGE_DOS_SIGNATURE || (*(DWORD*)((BYTE*)pDosHeader + pDosHeader->e_lfanew) != IMAGE_NT_SIGNATURE))
+ {
+ PBYTE PEImage;
+ SIZE_T ImageSize;
+
+ DoOutputDebugString("DumpModuleInCurrentProcess: Disguised PE image (bad MZ and/or PE headers) at 0x%p.\n", ModuleBase);
+
+ // We want to fix the PE header in the dump (for e.g. disassembly etc)
+ ImageSize = GetPESize(ModuleBase);
+ PEImage = (BYTE*)malloc(ImageSize);
+ memcpy(PEImage, ModuleBase, ImageSize);
+ pDosHeader = (PIMAGE_DOS_HEADER)PEImage;
+
+ *(WORD*)PEImage = IMAGE_DOS_SIGNATURE;
+ *(DWORD*)(PEImage + pDosHeader->e_lfanew) = IMAGE_NT_SIGNATURE;
+
+ ModuleBase = PEImage;
+ }
+
+#ifdef CAPE_INJECTION
+ SetCapeMetaData(INJECTION_PE, 0, NULL, (PVOID)ModuleBase);
+#else
+ SetCapeMetaData(EXTRACTION_PE, 0, NULL, (PVOID)ModuleBase);
+#endif
+
+ if (DumpCount < DUMP_MAX && ScyllaDumpProcess(GetCurrentProcess(), (DWORD_PTR)ModuleBase, 0))
+ {
+ DumpCount++;
+ return 1;
+ }
+
+ return 0;
+}
+
+//**************************************************************************************
+int DumpImageInCurrentProcess(LPVOID ImageBase)
+//**************************************************************************************
+{
+ PIMAGE_DOS_HEADER pDosHeader;
+ PIMAGE_NT_HEADERS pNtHeader;
+
+ pDosHeader = (PIMAGE_DOS_HEADER)ImageBase;
+
+ if (DumpCount >= DUMP_MAX)
+ {
+ DoOutputDebugString("DumpImageInCurrentProcess: CAPE dump limit reached.\n");
+ return 0;
+ }
+
+ if (*(WORD*)ImageBase != IMAGE_DOS_SIGNATURE)
+ {
+ DoOutputDebugString("DumpImageInCurrentProcess: No DOS signature in header.\n");
+ return 0;
+ }
+
+ if (!pDosHeader->e_lfanew || pDosHeader->e_lfanew > PE_HEADER_LIMIT)
+ {
+ DoOutputDebugString("DumpImageInCurrentProcess: bad e_lfanew.\n");
+ return 0;
+ }
+
+ pNtHeader = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + (ULONG)pDosHeader->e_lfanew);
+
+ if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
+ {
+ // No 'PE' header
+ DoOutputDebugString("DumpImageInCurrentProcess: Invalid PE signature in header.\n");
+ return 0;
+ }
+
+ if ((pNtHeader->FileHeader.Machine == 0) || (pNtHeader->FileHeader.SizeOfOptionalHeader == 0 || pNtHeader->OptionalHeader.SizeOfHeaders == 0))
+ {
+ // Basic requirements
+ DoOutputDebugString("DumpImageInCurrentProcess: PE image invalid.\n");
+ return 0;
+ }
+
+ if (IsPeImageVirtual(ImageBase) == FALSE)
+ {
+ DoOutputDebugString("DumpImageInCurrentProcess: Attempting to dump 'raw' PE image.\n");
+
+ if (ScyllaDumpPE((DWORD_PTR)ImageBase))
+ {
+ DumpCount++;
+ return 1;
+ }
+ else
+ {
+ // failed to dump pe image
+ DoOutputDebugString("DumpImageInCurrentProcess: Failed to dump 'raw' PE image.\n");
+ return 0;
+ }
+ }
+
+ DoOutputDebugString("DumpImageInCurrentProcess: Attempting to dump virtual PE image.\n");
+
+ if (!ScyllaDumpProcess(GetCurrentProcess(), (DWORD_PTR)ImageBase, 0))
+ {
+ DoOutputDebugString("DumpImageInCurrentProcess: Failed to dump PE as virtual image.\n");
+ return 0;
+ }
+
+ DumpCount++;
+ return 1;
+}
+
+//**************************************************************************************
+int DumpProcess(HANDLE hProcess, LPVOID ImageBase)
//**************************************************************************************
{
- if (ScyllaDumpProcess(hProcess, ImageBase, 0))
+ if (DumpCount < DUMP_MAX && ScyllaDumpProcess(hProcess, (DWORD_PTR)ImageBase, 0))
{
+ DumpCount++;
return 1;
}
@@ -624,26 +1500,93 @@ int DumpProcess(HANDLE hProcess, DWORD_PTR ImageBase)
}
//**************************************************************************************
-int DumpPE(LPCVOID Buffer)
+int DumpPE(LPVOID Buffer)
//**************************************************************************************
{
- if (ScyllaDumpPE((DWORD_PTR)Buffer))
+ SetCapeMetaData(INJECTION_PE, 0, NULL, (PVOID)Buffer);
+
+ if (DumpCount < DUMP_MAX && ScyllaDumpPE((DWORD_PTR)Buffer))
{
- return 1;
+ DumpCount++;
+ return 1;
}
return 0;
}
+//**************************************************************************************
+int RoutineProcessDump()
+//**************************************************************************************
+{
+ PVOID ImageBase, CallerBase = GetHookCallerBase();
+
+ if (base_of_dll_of_interest)
+ ImageBase = (PVOID)base_of_dll_of_interest;
+ else
+ ImageBase = GetModuleHandle(NULL);
+
+ if (g_config.procdump && ProcessDumped == FALSE)
+ {
+ ProcessDumped = TRUE; // this prevents a second call before the first is complete
+ if (g_config.import_reconstruction)
+ ProcessDumped = ScyllaDumpProcessFixImports(GetCurrentProcess(), (DWORD_PTR)ImageBase, 0);
+ else
+ ProcessDumped = ScyllaDumpProcess(GetCurrentProcess(), (DWORD_PTR)ImageBase, 0);
+
+ if (CallerBase && ImageBase != CallerBase && called_by_hook())
+ {
+ DoOutputDebugString("RoutineProcessDump: Terminate caller base (0x%p) different to imagebase (0x%p) - dumping.\n", CallerBase, ImageBase);
+ ScyllaDumpProcess(GetCurrentProcess(), (DWORD_PTR)CallerBase, 0);
+ }
+ }
+
+ return ProcessDumped;
+}
+
void init_CAPE()
{
+ char* CommandLine;
// Initialise CAPE global variables
//
-
-#ifndef _WIN64
- // Start the debugger thread if required
- //launch_debugger();
+#ifndef STANDALONE
+ CapeMetaData = (PCAPEMETADATA)malloc(sizeof(CAPEMETADATA));
+ CapeMetaData->Pid = GetCurrentProcessId();
+ CapeMetaData->ProcessPath = (char*)malloc(MAX_PATH);
+ WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, (LPCWSTR)our_process_path, (int)wcslen(our_process_path)+1, CapeMetaData->ProcessPath, MAX_PATH, NULL, NULL);
+
+ CommandLine = (char*)malloc(MAX_PATH);
+ WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, (LPCWSTR)our_commandline, (int)wcslen(our_commandline)+1, CommandLine, MAX_PATH, NULL, NULL);
+
+ // Specific to Injection package:
+ CapeMetaData->DumpType = INJECTION_SHELLCODE; // default value for now, may be changed to INJECTION_PE
+ CapeMetaData->Address = NULL;
+
+ DumpCount = 0;
+
+ // This flag controls whether a dump is automatically
+ // made at the end of a process' lifetime.
+ // It is normally only set in the base packages,
+ // or upon submission. (This overrides submission.)
+ g_config.procdump = 0;
+
+ // Cuckoo debug output level for development (0=none, 2=max)
+ // g_config.debug = 2;
#endif
-
+
+ // Start the debugger thread if required by package
+ if (DEBUGGER_ENABLED)
+ if (launch_debugger())
+ DoOutputDebugString("Debugger initialised.\n");
+ else
+ DoOutputDebugString("Failed to initialise debugger.\n");
+
+#ifdef _WIN64
+ DoOutputDebugString("CAPE initialised: 64-bit Injection package loaded in process %d at 0x%p, image base 0x%p, stack from 0x%p-0x%p\n", GetCurrentProcessId(), g_our_dll_base, GetModuleHandle(NULL), get_stack_bottom(), get_stack_top());
+#else
+ DoOutputDebugString("CAPE initialised: 32-bit Injection package loaded in process %d at 0x%x, image base 0x%x, stack from 0x%x-0x%x\n", GetCurrentProcessId(), g_our_dll_base, GetModuleHandle(NULL), get_stack_bottom(), get_stack_top());
+#endif
+
+ DoOutputDebugString("Commandline: %s.\n", CommandLine);
+
return;
-}
\ No newline at end of file
+}
diff --git a/CAPE/CAPE.h b/CAPE/CAPE.h
index 50d378b..e086532 100644
--- a/CAPE/CAPE.h
+++ b/CAPE/CAPE.h
@@ -1,12 +1,47 @@
+/*
+CAPE - Config And Payload Extraction
+Copyright(C) 2015-2017 Context Information Security. (kevin.oreilly@contextis.com)
+
+This program is free software : you can redistribute it and / or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.If not, see .
+*/
extern HMODULE s_hInst;
extern WCHAR s_wzDllPath[MAX_PATH];
extern CHAR s_szDllPath[MAX_PATH];
-extern int DumpCurrentProcessNewEP(DWORD NewEP);
-extern int DumpCurrentProcess();
-extern int DumpProcess(HANDLE hProcess, DWORD_PTR ImageBase);
-extern int DumpPE(LPCVOID Buffer);
-extern int ScyllaDumpPE(DWORD_PTR Buffer);
-unsigned int DumpSize;
+
+//Global debugger switch
+#define DEBUGGER_ENABLED 0
+
+PVOID GetHookCallerBase();
+PVOID GetPageAddress(PVOID Address);
+PVOID GetAllocationBase(PVOID Address);
+BOOL TranslatePathFromDeviceToLetter(__in TCHAR *DeviceFilePath, __out TCHAR* DriveLetterFilePath, __inout LPDWORD lpdwBufferSize);
+BOOL DumpPEsInRange(LPVOID Buffer, SIZE_T Size);
+BOOL DumpRegion(PVOID Address);
+int DumpMemory(LPVOID Buffer, SIZE_T Size);
+int DumpCurrentProcessNewEP(LPVOID NewEP);
+int DumpCurrentProcess();
+int DumpProcess(HANDLE hProcess, LPVOID ImageBase);
+int DumpPE(LPVOID Buffer);
+int ScanForNonZero(LPVOID Buffer, SIZE_T Size);
+int ScanPageForNonZero(LPVOID Address);
+int ScanForPE(LPVOID Buffer, SIZE_T Size, LPVOID* Offset);
+int ScanForDisguisedPE(LPVOID Buffer, SIZE_T Size, LPVOID* Offset);
+int IsDisguisedPEHeader(LPVOID Buffer);
+int DumpImageInCurrentProcess(LPVOID ImageBase);
+
+SYSTEM_INFO SystemInfo;
+PVOID CallingModule;
//
// MessageId: STATUS_SUCCESS
@@ -34,3 +69,53 @@ unsigned int DumpSize;
#define DATA 0
#define EXECUTABLE 1
+#define DLL 2
+
+#define PLUGX_SIGNATURE 0x5658 // 'XV'
+
+typedef struct CapeMetadata
+{
+ char* ProcessPath;
+ char* ModulePath;
+ DWORD Pid;
+ DWORD DumpType;
+ char* TargetProcess; // For injection
+ DWORD TargetPid; // "
+ PVOID Address; // For shellcode/modules
+ SIZE_T Size; // "
+} CAPEMETADATA, *PCAPEMETADATA;
+
+struct CapeMetadata *CapeMetaData;
+
+BOOL SetCapeMetaData(DWORD DumpType, DWORD TargetPid, HANDLE hTargetProcess, PVOID Address);
+
+enum {
+ PROCDUMP = 0,
+
+ COMPRESSION = 1,
+
+ INJECTION_PE = 3,
+ INJECTION_SHELLCODE = 4,
+ //INJECTION_RUNPE = 5,
+
+ EXTRACTION_PE = 8,
+ EXTRACTION_SHELLCODE = 9,
+
+ PLUGX_PAYLOAD = 0x10,
+ PLUGX_CONFIG = 0x11,
+
+ EVILGRAB_PAYLOAD = 0x14,
+ EVILGRAB_DATA = 0x15,
+
+ SEDRECO_DATA = 0x20,
+
+ URSNIF_CONFIG = 0x24,
+ URSNIF_PAYLOAD = 0x25,
+
+ CERBER_CONFIG = 0x30,
+ CERBER_PAYLOAD = 0x31,
+
+ DATADUMP = 0x66
+};
+
+HANDLE EvilGrabRegHandle;
diff --git a/CAPE/Debugger.c b/CAPE/Debugger.c
index 874fcd5..a8e3d85 100644
--- a/CAPE/Debugger.c
+++ b/CAPE/Debugger.c
@@ -1,6 +1,6 @@
/*
CAPE - Config And Payload Extraction
-Copyright(C) 2015, 2016 Context Information Security. (kevin.oreilly@contextis.com)
+Copyright(C) 2015 - 2018 Context Information Security. (kevin.oreilly@contextis.com)
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
@@ -15,19 +15,20 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see .
*/
-#ifndef _WIN64
#include
#include
#include
#include
#include
#include "Debugger.h"
+#include "..\alloc.h"
#include "..\config.h"
#include "..\pipe.h"
#define PIPEBUFSIZE 512
// eflags register
+#define FL_ZF 0x00000040 // Zero Flag
#define FL_TF 0x00000100 // Trap flag
#define FL_RF 0x00010000 // Resume flag
@@ -49,7 +50,7 @@ typedef struct _DR7
DWORD PAD1 : 3;
DWORD GD : 1; //General Detect Enable
DWORD PAD2 : 1;
- DWORD Pad3 : 1;
+ DWORD PAD3 : 1;
DWORD RWE0 : 2; //Read/Write/Execute bp0
DWORD LEN0 : 2; //Length bp0
DWORD RWE1 : 2; //Read/Write/Execute bp1
@@ -60,22 +61,36 @@ typedef struct _DR7
DWORD LEN3 : 2; //Length bp3
} DR7, *PDR7;
-#define NUMBER_OF_DEBUG_REGISTERS 4
-#define MAX_DEBUG_REGISTER_DATA_SIZE 4
-#define DEBUG_REGISTER_DATA_SIZES {1, 2, 4}
-#define DEBUG_REGISTER_LENGTH_MASKS {0xFFFFFFFF, 0, 1, 0xFFFFFFFF, 3}
+typedef struct _LSA_UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;
+
+typedef struct _INJECT_STRUCT {
+ ULONG_PTR LdrLoadDllAddress;
+ UNICODE_STRING DllName;
+ HANDLE OutHandle;
+} INJECT_STRUCT, *PINJECT_STRUCT;
DWORD LengthMask[MAX_DEBUG_REGISTER_DATA_SIZE + 1] = DEBUG_REGISTER_LENGTH_MASKS;
DWORD MainThreadId;
struct ThreadBreakpoints *MainThreadBreakpointList;
-LPTOP_LEVEL_EXCEPTION_FILTER OriginalExceptionHandler;
-LONG WINAPI CAPEExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo);
SINGLE_STEP_HANDLER SingleStepHandler;
-DWORD WINAPI PipeThread(LPVOID lpParam);
-DWORD RemoteFuncAddress;
-HANDLE hParentPipe;
+GUARD_PAGE_HANDLER GuardPageHandler;
+HANDLE hCapePipe;
+
+extern SYSTEM_INFO SystemInfo;
+extern ULONG_PTR g_our_dll_base;
+extern DWORD g_our_dll_size;
+extern BOOLEAN is_address_in_ntdll(ULONG_PTR address);
+extern char *convert_address_to_dll_name_and_offset(ULONG_PTR addr, unsigned int *offset);
+extern LONG WINAPI cuckoomon_exception_handler(__in struct _EXCEPTION_POINTERS *ExceptionInfo);
+
+extern BOOL ExtractionGuardPageHandler(struct _EXCEPTION_POINTERS* ExceptionInfo);
+extern PVOID GetPageAddress(PVOID Address);
extern unsigned int address_is_in_stack(DWORD Address);
extern BOOL WoW64fix(void);
extern BOOL WoW64PatchBreakpoint(unsigned int Register);
@@ -85,14 +100,585 @@ extern DWORD MyGetThreadId(HANDLE hThread);
extern void DoOutputDebugString(_In_ LPCTSTR lpOutputString, ...);
extern void DoOutputErrorString(_In_ LPCTSTR lpOutputString, ...);
-LPTOP_LEVEL_EXCEPTION_FILTER OriginalExceptionHandler;
-
-PVOID OEP;
-
void DebugOutputThreadBreakpoints();
-BOOL RestoreExecutionBreakpoint(PCONTEXT Context);
BOOL SetSingleStepMode(PCONTEXT Context, PVOID Handler);
BOOL ClearSingleStepMode(PCONTEXT Context);
+unsigned int TrapIndex;
+
+unsigned int DepthCount;
+extern int operate_on_backtrace(ULONG_PTR _esp, ULONG_PTR _ebp, void *extra, int(*func)(void *, ULONG_PTR));
+
+//**************************************************************************************
+BOOL CountDepth(LPVOID* ReturnAddress, LPVOID Address)
+//**************************************************************************************
+{
+#ifdef _WIN64
+ if (DepthCount == 0 && ReturnAddress && Address)
+#else
+ if (DepthCount == 2 && ReturnAddress && Address)
+#endif
+ {
+ DepthCount = 0;
+ *ReturnAddress = Address;
+ return TRUE;
+ }
+
+ DepthCount++;
+
+ DoOutputDebugString("CountDepth: Address 0x%p, depthcount = %i.\n", Address, DepthCount);
+
+ return FALSE;
+}
+
+//**************************************************************************************
+BOOL IsInTrackedRegions(PVOID Address)
+//**************************************************************************************
+{
+ PTRACKEDREGION CurrentTrackedRegion = TrackedRegionList;
+
+ if (TrackedRegionList == NULL)
+ return FALSE;
+
+ while (CurrentTrackedRegion)
+ {
+ if ((DWORD_PTR)Address >= (DWORD_PTR)CurrentTrackedRegion->BaseAddress && (DWORD_PTR)Address < ((DWORD_PTR)CurrentTrackedRegion->BaseAddress + (DWORD_PTR)CurrentTrackedRegion->RegionSize))
+ return TRUE;
+
+ CurrentTrackedRegion = CurrentTrackedRegion->NextTrackedRegion;
+ }
+
+ return FALSE;
+}
+
+//**************************************************************************************
+PTRACKEDREGION GetTrackedRegion(PVOID Address)
+//**************************************************************************************
+{
+ PTRACKEDREGION CurrentTrackedRegion = TrackedRegionList;
+
+ if (Address == NULL)
+ {
+ DoOutputDebugString("GetTrackedRegion: NULL passed as argument - error.\n");
+ return FALSE;
+ }
+
+ if (TrackedRegionList == NULL)
+ {
+ //DoOutputDebugString("GetTrackedRegion: failed to obtain initial tracked region list.\n");
+ return FALSE;
+ }
+
+ while (CurrentTrackedRegion)
+ {
+ if ((DWORD_PTR)Address >= (DWORD_PTR)CurrentTrackedRegion->BaseAddress && (DWORD_PTR)Address < ((DWORD_PTR)CurrentTrackedRegion->BaseAddress + (DWORD_PTR)CurrentTrackedRegion->RegionSize))
+ {
+ //DoOutputDebugString("GetTrackedRegion: found 0x%x in tracked region at 0x%x.\n", Address, CurrentTrackedRegion->BaseAddress);
+ return CurrentTrackedRegion;
+ }
+
+ CurrentTrackedRegion = CurrentTrackedRegion->NextTrackedRegion;
+ }
+
+ //DoOutputDebugString("GetTrackedRegion: failed to find tracked region in list for address 0x%x.\n", Address);
+
+ return NULL;
+}
+
+//**************************************************************************************
+PTRACKEDREGION CreateTrackedRegion()
+//**************************************************************************************
+{
+ if (TrackedRegionList == NULL)
+ {
+ TrackedRegionList = ((struct TrackedRegion*)malloc(sizeof(struct TrackedRegion)));
+
+ if (TrackedRegionList == NULL)
+ {
+ DoOutputDebugString("CreateTrackedRegion: failed to allocate memory for initial tracked region list.\n");
+ return NULL;
+ }
+
+ memset(TrackedRegionList, 0, sizeof(struct TrackedRegion));
+ }
+
+ return TrackedRegionList;
+}
+
+//**************************************************************************************
+PTRACKEDREGION AddTrackedRegion(PVOID Address, SIZE_T RegionSize, ULONG Protect)
+//**************************************************************************************
+{
+ BOOL PageAlreadyTracked;
+ PTRACKEDREGION CurrentTrackedRegion, PreviousTrackedRegion;
+ unsigned int NumberOfTrackedRegions;
+
+ NumberOfTrackedRegions = 0;
+ PreviousTrackedRegion = NULL;
+
+ if (TrackedRegionList == NULL)
+ CreateTrackedRegion();
+
+ CurrentTrackedRegion = TrackedRegionList;
+
+ while (CurrentTrackedRegion)
+ {
+ if ((DWORD_PTR)Address >= (DWORD_PTR)CurrentTrackedRegion->BaseAddress && (DWORD_PTR)Address < ((DWORD_PTR)CurrentTrackedRegion->BaseAddress + (DWORD_PTR)CurrentTrackedRegion->RegionSize))
+ PageAlreadyTracked = TRUE;
+ else
+ PageAlreadyTracked = FALSE;
+
+ NumberOfTrackedRegions++;
+
+ PreviousTrackedRegion = CurrentTrackedRegion;
+ CurrentTrackedRegion = CurrentTrackedRegion->NextTrackedRegion;
+ }
+
+ if (NumberOfTrackedRegions > 10)
+ DoOutputDebugString("AddTrackedRegion: DEBUG Warning - number of tracked regions %d.\n", NumberOfTrackedRegions);
+
+ if (GetPageAddress(Address) == GetPageAddress(TrackedRegionList))
+ {
+ DoOutputDebugString("AddTrackedRegion: Warning - attempting to track the page (0x%p) containing the tracked region list at 0x%p.\n", Address, TrackedRegionList);
+
+ return NULL;
+ }
+
+ if (PageAlreadyTracked)
+ {
+ DoOutputDebugString("AddTrackedRegion: Region at 0x%p already in list.\n", Address);
+ return NULL;
+ }
+
+ // We haven't found it in the linked list, so create a new one
+ CurrentTrackedRegion = PreviousTrackedRegion;
+
+ CurrentTrackedRegion->NextTrackedRegion = ((struct TrackedRegion*)malloc(sizeof(struct TrackedRegion)));
+
+ if (CurrentTrackedRegion->NextTrackedRegion == NULL)
+ {
+ DoOutputDebugString("AddTrackedRegion: Failed to allocate new tracked region struct.\n");
+ return NULL;
+ }
+
+ memset(CurrentTrackedRegion->NextTrackedRegion, 0, sizeof(struct TrackedRegion));
+
+ if (!VirtualQuery(Address, &CurrentTrackedRegion->MemInfo, sizeof(MEMORY_BASIC_INFORMATION)))
+ {
+ DoOutputErrorString("AddTrackedRegion: unable to query memory region 0x%p", Address);
+ return NULL;
+ }
+
+ CurrentTrackedRegion->BaseAddress = CurrentTrackedRegion->MemInfo.BaseAddress;
+
+ if (Address != CurrentTrackedRegion->BaseAddress)
+ CurrentTrackedRegion->ProtectAddress = Address;
+
+ if ((BYTE*)Address + RegionSize > (BYTE*)CurrentTrackedRegion->BaseAddress + CurrentTrackedRegion->MemInfo.RegionSize)
+ CurrentTrackedRegion->RegionSize = RegionSize;
+ else
+ CurrentTrackedRegion->RegionSize = CurrentTrackedRegion->MemInfo.RegionSize;
+
+ CurrentTrackedRegion->Protect = Protect;
+
+ //DoOutputDebugString("AddTrackedRegion: DEBUG - added region 0x%p to list at 0x%p - 0x%p.\n", Address, TrackedRegionList, (BYTE*)TrackedRegionList + NumberOfTrackedRegions*sizeof(TRACKEDREGION));
+
+ return CurrentTrackedRegion;
+}
+
+//**************************************************************************************
+BOOL DropTrackedRegion(PTRACKEDREGION TrackedRegion)
+//**************************************************************************************
+{
+ PTRACKEDREGION CurrentTrackedRegion, PreviousTrackedRegion;
+
+ if (TrackedRegion == NULL)
+ {
+ DoOutputDebugString("DropTrackedRegion: NULL passed as argument - error.\n");
+ return FALSE;
+ }
+
+ PreviousTrackedRegion = NULL;
+
+ if (TrackedRegionList == NULL)
+ {
+ DoOutputDebugString("DropTrackedRegion: failed to obtain initial tracked region list.\n");
+ return FALSE;
+ }
+
+ CurrentTrackedRegion = TrackedRegionList;
+
+ while (CurrentTrackedRegion)
+ {
+ DoOutputDebugString("DropTrackedRegion: CurrentTrackedRegion 0x%x, BaseAddress 0x%x.\n", CurrentTrackedRegion, CurrentTrackedRegion->BaseAddress);
+
+ if (CurrentTrackedRegion == TrackedRegion)
+ {
+ // Clear any breakpoints in this region
+ ClearBreakpointsInRange(GetCurrentThreadId(), TrackedRegion->BaseAddress, TrackedRegion->RegionSize);
+
+ DoOutputDebugString("DropTrackedRegion: About to unlink.\n");
+ // Unlink this from the list and free the memory
+ if (PreviousTrackedRegion && CurrentTrackedRegion->NextTrackedRegion)
+ {
+ DoOutputDebugString("DropTrackedRegion: removed pages 0x%x-0x%x from tracked region list.\n", TrackedRegion->BaseAddress, (DWORD_PTR)TrackedRegion->BaseAddress + TrackedRegion->RegionSize);
+ PreviousTrackedRegion->NextTrackedRegion = CurrentTrackedRegion->NextTrackedRegion;
+ }
+ else if (PreviousTrackedRegion && CurrentTrackedRegion->NextTrackedRegion == NULL)
+ {
+ DoOutputDebugString("DropTrackedRegion: removed pages 0x%x-0x%x from the end of the tracked region list.\n", TrackedRegion->BaseAddress, (DWORD_PTR)TrackedRegion->BaseAddress + TrackedRegion->RegionSize);
+ PreviousTrackedRegion->NextTrackedRegion = NULL;
+ }
+ else if (!PreviousTrackedRegion)
+ {
+ DoOutputDebugString("DropTrackedRegion: removed pages 0x%x-0x%x from the head of the tracked region list.\n", TrackedRegion->BaseAddress, (DWORD_PTR)TrackedRegion->BaseAddress + TrackedRegion->RegionSize);
+ TrackedRegionList = NULL;
+ }
+
+ DoOutputDebugString("DropTrackedRegion: about to free the memory!\n");
+ free(CurrentTrackedRegion);
+
+ return TRUE;
+ }
+
+ PreviousTrackedRegion = CurrentTrackedRegion;
+ CurrentTrackedRegion = CurrentTrackedRegion->NextTrackedRegion;
+ }
+
+ DoOutputDebugString("DropTrackedRegion: failed to find tracked region in list.\n");
+
+ return FALSE;
+}
+
+//**************************************************************************************
+BOOL ActivateGuardPages(PTRACKEDREGION TrackedRegion)
+//**************************************************************************************
+{
+ DWORD OldProtect;
+ BOOL TrackedRegionFound = FALSE;
+ PTRACKEDREGION CurrentTrackedRegion;
+ PVOID TestAddress;
+
+ SIZE_T MatchingRegionSize;
+
+ if (TrackedRegion == NULL)
+ {
+ DoOutputDebugString("ActivateGuardPages: NULL passed as argument - error.\n");
+ return FALSE;
+ }
+
+ if (TrackedRegionList == NULL)
+ {
+ DoOutputDebugString("ActivateGuardPages: Error - no tracked region list.\n");
+ return FALSE;
+ }
+
+ CurrentTrackedRegion = TrackedRegionList;
+
+ while (CurrentTrackedRegion)
+ {
+ //DoOutputDebugString("TrackedRegion->BaseAddress 0x%x, CurrentTrackedRegion->BaseAddress 0x%x.\n", TrackedRegion->BaseAddress, CurrentTrackedRegion->BaseAddress);
+
+ __try
+ {
+ TestAddress = CurrentTrackedRegion->BaseAddress;
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DoOutputErrorString("ActivateGuardPages: Exception trying to access BaseAddres from tracked region at 0x%x", CurrentTrackedRegion);
+ return FALSE;
+ }
+
+ if (TrackedRegion->BaseAddress == CurrentTrackedRegion->BaseAddress)
+ TrackedRegionFound = TRUE;
+
+ CurrentTrackedRegion = CurrentTrackedRegion->NextTrackedRegion;
+ }
+
+ if (!TrackedRegionFound)
+ {
+ DoOutputDebugString("ActivateGuardPages: failed to locate tracked region(s) in tracked region list.\n");
+ return FALSE;
+ }
+
+ MatchingRegionSize = VirtualQuery(TrackedRegion->BaseAddress, &TrackedRegion->MemInfo, sizeof(MEMORY_BASIC_INFORMATION));
+
+ if (!MatchingRegionSize)
+ {
+ DoOutputErrorString("ActivateGuardPages: failed to query tracked region(s) status in region 0x%x-0x%x", TrackedRegion->BaseAddress, (DWORD_PTR)TrackedRegion->BaseAddress + TrackedRegion->RegionSize);
+ return FALSE;
+ }
+
+ //DoOutputDebugString("ActivateGuardPages: BaseAddress 0x%x, AllocationBase 0x%x, AllocationProtect 0x%x, RegionSize 0x%x, State 0x%x, Protect 0x%x, Type 0x%x\n", TrackedRegion->MemInfo.BaseAddress, TrackedRegion->MemInfo.AllocationBase, TrackedRegion->MemInfo.AllocationProtect, TrackedRegion->MemInfo.RegionSize, TrackedRegion->MemInfo.State, TrackedRegion->MemInfo.Protect, TrackedRegion->MemInfo.Type);
+
+ if (MatchingRegionSize == TrackedRegion->RegionSize && TrackedRegion->MemInfo.Protect & PAGE_GUARD)
+ {
+ DoOutputDebugString("ActivateGuardPages: guard page(s) already set in region 0x%x-0x%x", TrackedRegion->BaseAddress, (DWORD_PTR)TrackedRegion->BaseAddress + TrackedRegion->RegionSize);
+ return FALSE;
+ }
+
+ if (!VirtualProtect(TrackedRegion->BaseAddress, TrackedRegion->RegionSize, TrackedRegion->Protect | PAGE_GUARD, &OldProtect))
+ {
+ DoOutputErrorString("ActivateGuardPages: failed to activate guard page(s) on region 0x%x size 0x%x", TrackedRegion->BaseAddress, TrackedRegion->RegionSize);
+ return FALSE;
+ }
+
+ //DoOutputDebugString("ActivateGuardPages: Activated guard page(s) on region 0x%x size 0x%x", TrackedRegion->BaseAddress, TrackedRegion->RegionSize);
+
+ return TRUE;
+}
+
+//**************************************************************************************
+BOOL ActivateGuardPagesOnProtectedRange(PTRACKEDREGION TrackedRegion)
+//**************************************************************************************
+{
+ DWORD OldProtect;
+ BOOL TrackedRegionFound = FALSE;
+ PTRACKEDREGION CurrentTrackedRegion;
+ DWORD_PTR AddressOfPage;
+ SIZE_T Size;
+ PVOID TestAddress;
+
+ if (TrackedRegion == NULL)
+ {
+ DoOutputDebugString("ActivateGuardPagesOnProtectedRange: NULL passed as argument - error.\n");
+ return FALSE;
+ }
+
+ if (!SystemInfo.dwPageSize)
+ GetSystemInfo(&SystemInfo);
+
+ if (!SystemInfo.dwPageSize)
+ {
+ DoOutputErrorString("ActivateGuardPagesOnProtectedRange: Failed to obtain system page size.\n");
+ return 0;
+ }
+
+ if (TrackedRegionList == NULL)
+ {
+ DoOutputDebugString("ActivateGuardPagesOnProtectedRange: Error - no tracked region list.\n");
+ return FALSE;
+ }
+
+ CurrentTrackedRegion = TrackedRegionList;
+
+ while (CurrentTrackedRegion)
+ {
+ //DoOutputDebugString("TrackedRegion->BaseAddress 0x%x, CurrentTrackedRegion->BaseAddress 0x%x.\n", TrackedRegion->BaseAddress, CurrentTrackedRegion->BaseAddress);
+
+ __try
+ {
+ TestAddress = CurrentTrackedRegion->BaseAddress;
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DoOutputErrorString("ActivateGuardPagesOnProtectedRange: Exception trying to access BaseAddress from tracked region at 0x%x", CurrentTrackedRegion);
+ return FALSE;
+ }
+
+ if (TrackedRegion->BaseAddress == CurrentTrackedRegion->BaseAddress)
+ TrackedRegionFound = TRUE;
+
+ CurrentTrackedRegion = CurrentTrackedRegion->NextTrackedRegion;
+ }
+
+ if (!TrackedRegionFound)
+ {
+ DoOutputDebugString("ActivateGuardPagesOnProtectedRange: failed to locate tracked region(s) in tracked region list.\n");
+ return FALSE;
+ }
+
+ if (!TrackedRegion->ProtectAddress || !TrackedRegion->RegionSize)
+ {
+ DoOutputDebugString("ActivateGuardPagesOnProtectedRange: Protect address or size zero: 0x%x, 0x%x.\n", TrackedRegion->ProtectAddress, TrackedRegion->RegionSize);
+ return FALSE;
+ }
+
+ if (!VirtualQuery(TrackedRegion->BaseAddress, &TrackedRegion->MemInfo, sizeof(MEMORY_BASIC_INFORMATION)))
+ {
+ DoOutputErrorString("ActivateGuardPagesOnProtectedRange: unable to query memory region 0x%x", TrackedRegion->BaseAddress);
+ return FALSE;
+ }
+
+ AddressOfPage = ((DWORD_PTR)TrackedRegion->ProtectAddress/SystemInfo.dwPageSize)*SystemInfo.dwPageSize;
+
+ Size = (BYTE*)TrackedRegion->ProtectAddress + TrackedRegion->RegionSize - (BYTE*)AddressOfPage;
+
+ if (!VirtualProtect((LPVOID)AddressOfPage, Size, TrackedRegion->Protect | PAGE_GUARD, &OldProtect))
+ {
+ DoOutputErrorString("ActivateGuardPagesOnProtectedRange: failed to activate guard page(s) on region 0x%x size 0x%x", AddressOfPage, Size);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//**************************************************************************************
+BOOL DeactivateGuardPages(PTRACKEDREGION TrackedRegion)
+//**************************************************************************************
+{
+ DWORD OldProtect;
+ SIZE_T MatchingRegionSize;
+ BOOL TrackedRegionFound = FALSE;
+ PTRACKEDREGION CurrentTrackedRegion = TrackedRegionList;
+ PVOID TestAddress;
+
+ if (TrackedRegion == NULL)
+ {
+ DoOutputDebugString("DeactivateGuardPages: NULL passed as argument - error.\n");
+ return FALSE;
+ }
+
+ if (TrackedRegionList == NULL)
+ {
+ DoOutputDebugString("DeactivateGuardPages: Error - no tracked region list.\n");
+ return FALSE;
+ }
+
+ //DoOutputDebugString("DeactivateGuardPages: DEBUG - tracked region list 0x%x, BaseAddress 0x%x.\n", CurrentTrackedRegion, CurrentTrackedRegion->BaseAddress);
+
+ while (CurrentTrackedRegion)
+ {
+ __try
+ {
+ TestAddress = CurrentTrackedRegion->BaseAddress;
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DoOutputErrorString("DeactivateGuardPages: Exception trying to access BaseAddres from tracked region at 0x%x", CurrentTrackedRegion);
+ return FALSE;
+ }
+
+ if (TrackedRegion->BaseAddress == CurrentTrackedRegion->BaseAddress)
+ TrackedRegionFound = TRUE;
+
+ CurrentTrackedRegion = CurrentTrackedRegion->NextTrackedRegion;
+ }
+
+ if (!TrackedRegionFound)
+ {
+ DoOutputDebugString("DeactivateGuardPages: failed to locate tracked region(s) in tracked region list.\n");
+ return FALSE;
+ }
+
+ MatchingRegionSize = VirtualQuery(TrackedRegion->BaseAddress, &TrackedRegion->MemInfo, sizeof(MEMORY_BASIC_INFORMATION));
+
+ if (!MatchingRegionSize)
+ {
+ DoOutputErrorString("DeactivateGuardPages: failed to query tracked region(s) status in region 0x%x-0x%x", TrackedRegion->BaseAddress, (DWORD_PTR)TrackedRegion->BaseAddress + TrackedRegion->RegionSize);
+ return FALSE;
+ }
+
+ if (MatchingRegionSize == TrackedRegion->RegionSize && !(TrackedRegion->MemInfo.Protect & PAGE_GUARD))
+ {
+ DoOutputDebugString("DeactivateGuardPages: guard page(s) not set in region 0x%x-0x%x", TrackedRegion->BaseAddress, (DWORD_PTR)TrackedRegion->BaseAddress + TrackedRegion->RegionSize);
+ return FALSE;
+ }
+
+ if (!VirtualProtect(TrackedRegion->BaseAddress, TrackedRegion->RegionSize, TrackedRegion->Protect, &OldProtect))
+ {
+ DoOutputErrorString("DeactivateGuardPages: failed to deactivate guard page(s) on region 0x%x-0x%x", TrackedRegion->BaseAddress, (DWORD_PTR)TrackedRegion->BaseAddress + TrackedRegion->RegionSize);
+ return FALSE;
+ }
+
+ DoOutputDebugString("DeactivateGuardPages: DEBUG: Deactivated guard page(s) on region 0x%x-0x%x", TrackedRegion->BaseAddress, (DWORD_PTR)TrackedRegion->BaseAddress + TrackedRegion->RegionSize);
+
+ return TRUE;
+}
+
+//**************************************************************************************
+BOOL ActivateSurroundingGuardPages(PTRACKEDREGION TrackedRegion)
+//**************************************************************************************
+{
+ DWORD OldProtect, RetVal;
+ DWORD_PTR AddressOfPage, PagePointer;
+ BOOL TrackedRegionFound = FALSE;
+ PTRACKEDREGION CurrentTrackedRegion = TrackedRegionList;
+ PVOID TestAddress;
+
+ if (TrackedRegionList == NULL)
+ {
+ DoOutputDebugString("ActivateSurroundingGuardPages: Error - TrackedRegionList NULL.\n");
+ return 0;
+ }
+
+ if (!SystemInfo.dwPageSize)
+ GetSystemInfo(&SystemInfo);
+
+ if (!SystemInfo.dwPageSize)
+ {
+ DoOutputErrorString("ActivateSurroundingGuardPages: Failed to obtain system page size.\n");
+ return 0;
+ }
+
+ while (CurrentTrackedRegion)
+ {
+ __try
+ {
+ TestAddress = CurrentTrackedRegion->BaseAddress;
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DoOutputErrorString("ActivateSurroundingGuardPages: Exception trying to access BaseAddres from tracked region at 0x%x", CurrentTrackedRegion);
+ return FALSE;
+ }
+
+ if (TrackedRegion->BaseAddress == CurrentTrackedRegion->BaseAddress)
+ TrackedRegionFound = TRUE;
+
+ CurrentTrackedRegion = CurrentTrackedRegion->NextTrackedRegion;
+ }
+
+ if (!TrackedRegionFound)
+ {
+ DoOutputDebugString("ActivateSurroundingGuardPages: Failed to locate tracked region(s) in tracked region list.\n");
+ return FALSE;
+ }
+
+ if (!TrackedRegion->LastAccessAddress)
+ {
+ DoOutputDebugString("ActivateSurroundingGuardPages: Error - Last access address not set.\n");
+ return 0;
+ }
+
+ if ((DWORD_PTR)TrackedRegion->LastAccessAddress < (DWORD_PTR)TrackedRegion->BaseAddress || (DWORD_PTR)TrackedRegion->LastAccessAddress >= ((DWORD_PTR)TrackedRegion->BaseAddress + (DWORD_PTR)TrackedRegion->RegionSize))
+ {
+ DoOutputDebugString("ActivateSurroundingGuardPages: Last access address 0x%x not within tracked region at 0x%x.\n", TrackedRegion->LastAccessAddress, TrackedRegion->BaseAddress);
+ return FALSE;
+ }
+
+ AddressOfPage = ((DWORD_PTR)TrackedRegion->LastAccessAddress/SystemInfo.dwPageSize)*SystemInfo.dwPageSize;
+
+ if (!VirtualQuery(TrackedRegion->BaseAddress, &TrackedRegion->MemInfo, sizeof(MEMORY_BASIC_INFORMATION)))
+ {
+ DoOutputErrorString("ProtectionHandler: unable to query memory region 0x%x", TrackedRegion->BaseAddress);
+ return FALSE;
+ }
+
+ for
+ (
+ PagePointer = ((DWORD_PTR)TrackedRegion->BaseAddress/SystemInfo.dwPageSize)*SystemInfo.dwPageSize;
+ (BYTE*)PagePointer + SystemInfo.dwPageSize < (BYTE*)TrackedRegion->BaseAddress + TrackedRegion->RegionSize;
+ PagePointer += SystemInfo.dwPageSize
+ )
+ {
+ // We skip the initial page if a switch to breakpoints has occurred
+ if (PagePointer == (DWORD_PTR)TrackedRegion->BaseAddress && TrackedRegion->BreakpointsSet)
+ PagePointer += SystemInfo.dwPageSize;
+
+ if (PagePointer != AddressOfPage)
+ {
+ RetVal = VirtualProtect((LPVOID)PagePointer, SystemInfo.dwPageSize, TrackedRegion->Protect | PAGE_GUARD, &OldProtect);
+
+ if (!RetVal)
+ {
+ DoOutputDebugString("ActivateSurroundingGuardPages: Failed to activate page guard on tracked region at 0x%x.\n", PagePointer);
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
//**************************************************************************************
PTHREADBREAKPOINTS GetThreadBreakpoints(DWORD ThreadId)
@@ -115,6 +701,27 @@ PTHREADBREAKPOINTS GetThreadBreakpoints(DWORD ThreadId)
return NULL;
}
+//**************************************************************************************
+HANDLE GetThreadHandle(DWORD ThreadId)
+//**************************************************************************************
+{
+ DWORD CurrentThreadId;
+
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint = MainThreadBreakpointList;
+
+ while (CurrentThreadBreakpoint)
+ {
+ CurrentThreadId = MyGetThreadId(CurrentThreadBreakpoint->ThreadHandle);
+
+ if (CurrentThreadId == ThreadId)
+ return CurrentThreadBreakpoint->ThreadHandle;
+ else
+ CurrentThreadBreakpoint = CurrentThreadBreakpoint->NextThreadBreakpoints;
+ }
+
+ return NULL;
+}
+
//**************************************************************************************
PTHREADBREAKPOINTS CreateThreadBreakpoints(DWORD ThreadId)
//**************************************************************************************
@@ -133,8 +740,10 @@ PTHREADBREAKPOINTS CreateThreadBreakpoints(DWORD ThreadId)
DoOutputDebugString("CreateThreadBreakpoints: failed to allocate memory for initial thread breakpoint list.\n");
return NULL;
}
+
memset(MainThreadBreakpointList, 0, sizeof(struct ThreadBreakpoints));
- MainThreadBreakpointList->ThreadId = MainThreadId;
+
+ MainThreadBreakpointList->ThreadId = MainThreadId;
}
CurrentThreadBreakpoint = MainThreadBreakpointList;
@@ -170,6 +779,7 @@ PTHREADBREAKPOINTS CreateThreadBreakpoints(DWORD ThreadId)
DoOutputDebugString("CreateThreadBreakpoints: Failed to allocate new thread breakpoints.\n");
return NULL;
}
+
memset(CurrentThreadBreakpoint->NextThreadBreakpoints, 0, sizeof(struct ThreadBreakpoints));
CurrentThreadBreakpoint = CurrentThreadBreakpoint->NextThreadBreakpoints;
@@ -196,6 +806,8 @@ PTHREADBREAKPOINTS CreateThreadBreakpoints(DWORD ThreadId)
}
}
+ CurrentThreadBreakpoint->ThreadId = ThreadId;
+
for (Register = 0; Register < NUMBER_OF_DEBUG_REGISTERS; Register++)
{
CurrentThreadBreakpoint->BreakpointInfo[Register].Register = Register;
@@ -205,23 +817,139 @@ PTHREADBREAKPOINTS CreateThreadBreakpoints(DWORD ThreadId)
return CurrentThreadBreakpoint;
}
+//**************************************************************************************
+BOOL InitNewThreadBreakpoints(DWORD ThreadId)
+//**************************************************************************************
+{
+ PTHREADBREAKPOINTS NewThreadBreakpoints;
+
+ if (MainThreadBreakpointList == NULL)
+ {
+ DoOutputDebugString("InitNewThreadBreakpoints: Failed to create thread breakpoints struct.\n");
+ return FALSE;
+ }
+
+ NewThreadBreakpoints = CreateThreadBreakpoints(ThreadId);
+
+ if (NewThreadBreakpoints == NULL)
+ {
+ DoOutputDebugString("InitNewThreadBreakpoints: Cannot create new thread breakpoints.\n");
+ return FALSE;
+ }
+
+ if (NewThreadBreakpoints->ThreadHandle == NULL)
+ {
+ DoOutputDebugString("InitNewThreadBreakpoints error: main thread handle not set.\n");
+ return FALSE;
+ }
+
+ for (unsigned int Register = 0; Register < NUMBER_OF_DEBUG_REGISTERS; Register++)
+ {
+ if (!MainThreadBreakpointList->BreakpointInfo[Register].Address)
+ continue;
+
+ NewThreadBreakpoints->BreakpointInfo[Register] = MainThreadBreakpointList->BreakpointInfo[Register];
+
+ if (!NewThreadBreakpoints->BreakpointInfo[Register].Address)
+ DoOutputDebugString("InitNewThreadBreakpoints error: failed to copy the bleeding breakpoint struct!\n");
+
+ if (NewThreadBreakpoints->BreakpointInfo[Register].Address && !SetThreadBreakpoint(ThreadId, Register, NewThreadBreakpoints->BreakpointInfo[Register].Size, NewThreadBreakpoints->BreakpointInfo[Register].Address, NewThreadBreakpoints->BreakpointInfo[Register].Type, NewThreadBreakpoints->BreakpointInfo[Register].Callback))
+ {
+ DoOutputDebugString("InitNewThreadBreakpoints error: failed to set breakpoint %d for new thread %d.\n", Register, ThreadId);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+//**************************************************************************************
+BOOL GetNextAvailableBreakpoint(DWORD ThreadId, unsigned int* Register)
+//**************************************************************************************
+{
+ DWORD CurrentThreadId;
+ unsigned int i;
+
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint = MainThreadBreakpointList;
+
+ if (CurrentThreadBreakpoint == NULL)
+ {
+ DoOutputDebugString("GetNextAvailableBreakpoint: MainThreadBreakpointList NULL.\n");
+ return FALSE;
+ }
+
+ while (CurrentThreadBreakpoint)
+ {
+ CurrentThreadId = MyGetThreadId(CurrentThreadBreakpoint->ThreadHandle);
+
+ if (CurrentThreadId == ThreadId)
+ {
+ for (i=0; i < NUMBER_OF_DEBUG_REGISTERS; i++)
+ {
+ if (CurrentThreadBreakpoint->BreakpointInfo[i].Address == NULL)
+ {
+ *Register = i;
+ return TRUE;
+ }
+ }
+ }
+
+ CurrentThreadBreakpoint = CurrentThreadBreakpoint->NextThreadBreakpoints;
+ }
+
+ return FALSE;
+}
+
+//**************************************************************************************
+BOOL ContextGetNextAvailableBreakpoint(PCONTEXT Context, unsigned int* Register)
+//**************************************************************************************
+{
+ unsigned int i;
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint;
+
+ CurrentThreadBreakpoint = GetThreadBreakpoints(GetCurrentThreadId());
+
+ if (CurrentThreadBreakpoint == NULL)
+ {
+ DoOutputDebugString("ContextGetNextAvailableBreakpoint: Creating new thread breakpoints for thread %d.\n", GetCurrentThreadId());
+ CurrentThreadBreakpoint = CreateThreadBreakpoints(GetCurrentThreadId());
+ }
+
+ if (CurrentThreadBreakpoint == NULL)
+ {
+ DoOutputDebugString("ContextGetNextAvailableBreakpoint: Cannot create new thread breakpoints - FATAL.\n");
+ return FALSE;
+ }
+
+ for (i=0; i < NUMBER_OF_DEBUG_REGISTERS; i++)
+ {
+ if (CurrentThreadBreakpoint->BreakpointInfo[i].Address == NULL)
+ {
+ *Register = i;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
//**************************************************************************************
void DebugOutputThreadBreakpoints()
//**************************************************************************************
{
unsigned int Register;
- PTHREADBREAKPOINTS CurrentThreadBreakpoints;
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint;
PBREAKPOINTINFO pBreakpointInfo;
- CurrentThreadBreakpoints = GetThreadBreakpoints(GetCurrentThreadId());
+ CurrentThreadBreakpoint = GetThreadBreakpoints(GetCurrentThreadId());
for (Register = 0; Register < NUMBER_OF_DEBUG_REGISTERS; Register++)
{
- pBreakpointInfo = &(CurrentThreadBreakpoints->BreakpointInfo[Register]);
+ pBreakpointInfo = &(CurrentThreadBreakpoint->BreakpointInfo[Register]);
if (pBreakpointInfo == NULL)
{
- DoOutputDebugString("CAPEExceptionFilter: Can't get BreakpointInfo - FATAL.\n");
+ DoOutputDebugString("DebugOutputThreadBreakpoints: Can't get BreakpointInfo - FATAL.\n");
}
DoOutputDebugString("Callback = 0x%x, Address = 0x%x, Size = 0x%x, Register = %i, ThreadHandle = 0x%x, Type = 0x%x\n",
@@ -234,53 +962,87 @@ void DebugOutputThreadBreakpoints()
}
}
+//**************************************************************************************
+void ShowStack(DWORD_PTR StackPointer, unsigned int NumberOfRecords)
+//**************************************************************************************
+{
+ unsigned int i;
+
+ for (i=0; iExceptionRecord->ExceptionCode==EXCEPTION_SINGLE_STEP)
{
BOOL BreakpointFlag;
PBREAKPOINTINFO pBreakpointInfo;
- PTHREADBREAKPOINTS CurrentThreadBreakpoints;
-
- DoOutputDebugString("Entering CAPEExceptionFilter: breakpoint hit: 0x%x\n", ExceptionInfo->ExceptionRecord->ExceptionAddress);
-
- CurrentThreadBreakpoints = GetThreadBreakpoints(GetCurrentThreadId());
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint;
+
+ CurrentThreadBreakpoint = GetThreadBreakpoints(GetCurrentThreadId());
- if (CurrentThreadBreakpoints == NULL)
+ if (CurrentThreadBreakpoint == NULL)
{
DoOutputDebugString("CAPEExceptionFilter: Can't get thread breakpoints - FATAL.\n");
return EXCEPTION_CONTINUE_SEARCH;
- }
-
+ }
+
// Test Dr6 to see if this is a breakpoint
BreakpointFlag = FALSE;
for (bp = 0; bp < NUMBER_OF_DEBUG_REGISTERS; bp++)
{
- if (ExceptionInfo->ContextRecord->Dr6 & (1 << bp))
+ if (ExceptionInfo->ContextRecord->Dr6 & (DWORD_PTR)(1 << bp))
{
BreakpointFlag = TRUE;
}
}
// If not it's a single-step
- if (BreakpointFlag == FALSE)
+ if (!BreakpointFlag)
{
- //if (SingleStepHandler(ExceptionInfo))
- SingleStepHandler(ExceptionInfo);
+ if (SingleStepHandler)
+ SingleStepHandler(ExceptionInfo);
+ else if (TrapIndex)
+ // this is from a 'StepOver' function
+ {
+ DoOutputDebugString("CAPEExceptionFilter: Stepping over execution breakpoint to: 0x%x\n", ExceptionInfo->ExceptionRecord->ExceptionAddress);
+
+ pBreakpointInfo = &(CurrentThreadBreakpoint->BreakpointInfo[TrapIndex-1]);
+
+ ResumeAfterExecutionBreakpoint(ExceptionInfo->ContextRecord, pBreakpointInfo);
+ }
+ else
+ {
+ DoOutputDebugString("CAPEExceptionFilter: Error, unhandled single-step exception at: 0x%x\n", ExceptionInfo->ExceptionRecord->ExceptionAddress);
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
return EXCEPTION_CONTINUE_EXECUTION;
}
+ if (TrapIndex)
+ {
+ DoOutputDebugString("CAPEExceptionFilter: Anomaly detected: Trap index set on non-single-step: %d\n", TrapIndex);
+ }
+
+ DoOutputDebugString("CAPEExceptionFilter: breakpoint hit by instruction at 0x%p\n", ExceptionInfo->ExceptionRecord->ExceptionAddress);
+
for (bp = 0; bp < NUMBER_OF_DEBUG_REGISTERS; bp++)
{
- if (ExceptionInfo->ContextRecord->Dr6 & (1 << bp))
+ if (ExceptionInfo->ContextRecord->Dr6 & (DWORD_PTR)(1 << bp))
{
- pBreakpointInfo = &(CurrentThreadBreakpoints->BreakpointInfo[bp]);
+ pBreakpointInfo = &(CurrentThreadBreakpoint->BreakpointInfo[bp]);
if (pBreakpointInfo == NULL)
{
@@ -290,25 +1052,25 @@ LONG WINAPI CAPEExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
if (pBreakpointInfo->Register == bp)
{
- if (bp == 0 && ((DWORD)pBreakpointInfo->Address != ExceptionInfo->ContextRecord->Dr0))
+ if (bp == 0 && ((DWORD_PTR)pBreakpointInfo->Address != ExceptionInfo->ContextRecord->Dr0))
DoOutputDebugString("CAPEExceptionFilter: Anomaly detected! bp0 address (0x%x) different to BreakpointInfo (0x%x)!\n", ExceptionInfo->ContextRecord->Dr0, pBreakpointInfo->Address);
- if (bp == 1 && ((DWORD)pBreakpointInfo->Address != ExceptionInfo->ContextRecord->Dr1))
+ if (bp == 1 && ((DWORD_PTR)pBreakpointInfo->Address != ExceptionInfo->ContextRecord->Dr1))
DoOutputDebugString("CAPEExceptionFilter: Anomaly detected! bp1 address (0x%x) different to BreakpointInfo (0x%x)!\n", ExceptionInfo->ContextRecord->Dr1, pBreakpointInfo->Address);
- if (bp == 2 && ((DWORD)pBreakpointInfo->Address != ExceptionInfo->ContextRecord->Dr2))
+ if (bp == 2 && ((DWORD_PTR)pBreakpointInfo->Address != ExceptionInfo->ContextRecord->Dr2))
DoOutputDebugString("CAPEExceptionFilter: Anomaly detected! bp2 address (0x%x) different to BreakpointInfo (0x%x)!\n", ExceptionInfo->ContextRecord->Dr2, pBreakpointInfo->Address);
- if (bp == 3 && ((DWORD)pBreakpointInfo->Address != ExceptionInfo->ContextRecord->Dr3))
+ if (bp == 3 && ((DWORD_PTR)pBreakpointInfo->Address != ExceptionInfo->ContextRecord->Dr3))
DoOutputDebugString("CAPEExceptionFilter: Anomaly detected! bp3 address (0x%x) different to BreakpointInfo (0x%x)!\n", ExceptionInfo->ContextRecord->Dr3, pBreakpointInfo->Address);
-
- if (bp == 0 && ((DWORD)pBreakpointInfo->Type != ((PDR7)&(ExceptionInfo->ContextRecord->Dr7))->RWE0))
+#ifndef _WIN64
+ if (bp == 0 && ((DWORD_PTR)pBreakpointInfo->Type != ((PDR7)&(ExceptionInfo->ContextRecord->Dr7))->RWE0))
{
- if (pBreakpointInfo->Type == BP_READWRITE && ((PDR7)&(ExceptionInfo->ContextRecord->Dr7))->RWE0 == BP_WRITE && address_is_in_stack((DWORD)pBreakpointInfo->Address))
+ if (pBreakpointInfo->Type == BP_READWRITE && ((PDR7)&(ExceptionInfo->ContextRecord->Dr7))->RWE0 == BP_WRITE && address_is_in_stack((DWORD_PTR)pBreakpointInfo->Address))
{
DoOutputDebugString("CAPEExceptionFilter: Reinstated BP_READWRITE on breakpoint %d (WoW64 workaround)\n", pBreakpointInfo->Register);
- SetExceptionHardwareBreakpoint(ExceptionInfo->ContextRecord, pBreakpointInfo->Register, pBreakpointInfo->Size, (BYTE*)pBreakpointInfo->Address, pBreakpointInfo->Type, pBreakpointInfo->Callback);
+ ContextSetThreadBreakpoint(ExceptionInfo->ContextRecord, pBreakpointInfo->Register, pBreakpointInfo->Size, (BYTE*)pBreakpointInfo->Address, pBreakpointInfo->Type, pBreakpointInfo->Callback);
}
else
{
@@ -318,11 +1080,11 @@ LONG WINAPI CAPEExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
}
if (bp == 1 && ((DWORD)pBreakpointInfo->Type != ((PDR7)&(ExceptionInfo->ContextRecord->Dr7))->RWE1))
{
- if (pBreakpointInfo->Type == BP_READWRITE && ((PDR7)&(ExceptionInfo->ContextRecord->Dr7))->RWE1 == BP_WRITE && address_is_in_stack((DWORD)pBreakpointInfo->Address))
+ if (pBreakpointInfo->Type == BP_READWRITE && ((PDR7)&(ExceptionInfo->ContextRecord->Dr7))->RWE1 == BP_WRITE && address_is_in_stack((DWORD_PTR)pBreakpointInfo->Address))
{
DoOutputDebugString("CAPEExceptionFilter: Reinstated BP_READWRITE on breakpoint %d (WoW64 workaround)\n", pBreakpointInfo->Register);
- SetExceptionHardwareBreakpoint(ExceptionInfo->ContextRecord, pBreakpointInfo->Register, pBreakpointInfo->Size, (BYTE*)pBreakpointInfo->Address, pBreakpointInfo->Type, pBreakpointInfo->Callback);
+ ContextSetThreadBreakpoint(ExceptionInfo->ContextRecord, pBreakpointInfo->Register, pBreakpointInfo->Size, (BYTE*)pBreakpointInfo->Address, pBreakpointInfo->Type, pBreakpointInfo->Callback);
}
else
{
@@ -332,11 +1094,11 @@ LONG WINAPI CAPEExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
}
if (bp == 2 && ((DWORD)pBreakpointInfo->Type != ((PDR7)&(ExceptionInfo->ContextRecord->Dr7))->RWE2))
{
- if (pBreakpointInfo->Type == BP_READWRITE && ((PDR7)&(ExceptionInfo->ContextRecord->Dr7))->RWE2 == BP_WRITE && address_is_in_stack((DWORD)pBreakpointInfo->Address))
+ if (pBreakpointInfo->Type == BP_READWRITE && ((PDR7)&(ExceptionInfo->ContextRecord->Dr7))->RWE2 == BP_WRITE && address_is_in_stack((DWORD_PTR)pBreakpointInfo->Address))
{
DoOutputDebugString("CAPEExceptionFilter: Reinstated BP_READWRITE on stack breakpoint %d (WoW64 workaround)\n", pBreakpointInfo->Register);
- SetExceptionHardwareBreakpoint(ExceptionInfo->ContextRecord, pBreakpointInfo->Register, pBreakpointInfo->Size, (BYTE*)pBreakpointInfo->Address, pBreakpointInfo->Type, pBreakpointInfo->Callback);
+ ContextSetThreadBreakpoint(ExceptionInfo->ContextRecord, pBreakpointInfo->Register, pBreakpointInfo->Size, (BYTE*)pBreakpointInfo->Address, pBreakpointInfo->Type, pBreakpointInfo->Callback);
}
else
{
@@ -346,11 +1108,11 @@ LONG WINAPI CAPEExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
}
if (bp == 3 && ((DWORD)pBreakpointInfo->Type != ((PDR7)&(ExceptionInfo->ContextRecord->Dr7))->RWE3))
{
- if (pBreakpointInfo->Type == BP_READWRITE && ((PDR7)&(ExceptionInfo->ContextRecord->Dr7))->RWE3 == BP_WRITE && address_is_in_stack((DWORD)pBreakpointInfo->Address))
+ if (pBreakpointInfo->Type == BP_READWRITE && ((PDR7)&(ExceptionInfo->ContextRecord->Dr7))->RWE3 == BP_WRITE && address_is_in_stack((DWORD_PTR)pBreakpointInfo->Address))
{
DoOutputDebugString("CAPEExceptionFilter: Reinstated BP_READWRITE on breakpoint %d (WoW64 workaround)\n", pBreakpointInfo->Register);
- SetExceptionHardwareBreakpoint(ExceptionInfo->ContextRecord, pBreakpointInfo->Register, pBreakpointInfo->Size, (BYTE*)pBreakpointInfo->Address, pBreakpointInfo->Type, pBreakpointInfo->Callback);
+ ContextSetThreadBreakpoint(ExceptionInfo->ContextRecord, pBreakpointInfo->Register, pBreakpointInfo->Size, (BYTE*)pBreakpointInfo->Address, pBreakpointInfo->Type, pBreakpointInfo->Callback);
}
else
{
@@ -358,6 +1120,7 @@ LONG WINAPI CAPEExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
CheckDebugRegisters(0, ExceptionInfo->ContextRecord);
}
}
+#endif // !_WIN64
}
}
}
@@ -375,13 +1138,95 @@ LONG WINAPI CAPEExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
return EXCEPTION_CONTINUE_EXECUTION;
}
-
- // Some other exception occurred. Pass it to next handler
+ // Page guard violations generate STATUS_GUARD_PAGE_VIOLATION
+ else if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION)
+ {
+ if (ExceptionInfo->ExceptionRecord->NumberParameters < 2)
+ {
+ DoOutputDebugString("CAPEExceptionFilter: Guard page exception with missing parameters, passing.\n");
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
+ //DoOutputDebugString("Entering CAPEExceptionFilter: guarded page access at 0x%x by 0x%x\n", ExceptionInfo->ExceptionRecord->ExceptionInformation[1], ExceptionInfo->ExceptionRecord->ExceptionAddress);
+
+ if (TrackedRegion = GetTrackedRegion((PVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[1]))
+ {
+ if (is_address_in_ntdll((ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress))
+ {
+ if (!VirtualProtect((PVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[1], 1, TrackedRegion->Protect | PAGE_GUARD, &OldProtect))
+ {
+ DoOutputDebugString("CAPEExceptionFilter: Failed to re-activate page guard on tracked region around 0x%x touched by ntdll.\n", ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
+ }
+
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ if (GuardPageHandler)
+ {
+ if (GuardPageHandler(ExceptionInfo))
+ return EXCEPTION_CONTINUE_EXECUTION;
+ else
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+ else
+ {
+ DoOutputDebugString("CAPEExceptionFilter: Error, no page guard handler for CAPE guard page exception.\n");
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+ }
+ else
+ {
+ DoOutputDebugString("CAPEExceptionFilter: exception at 0x%x not within CAPE guarded page.\n", ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+ }
+ //else if (ExceptionInfo->ExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C)
+ //{
+ // // This could be useful output
+ // // TODO: find string buffer(s) and send info to DoOutputDebugString
+ // return EXCEPTION_CONTINUE_SEARCH;
+ //}
+ else if (!VECTORED_HANDLER && OriginalExceptionHandler)
+ {
+ if ((ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress >= g_our_dll_base && (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress < (g_our_dll_base + g_our_dll_size))
+ {
+ // This is a CAPE (or Cuckoo) exception
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+
+ // As it's not a bp, and the sample has registered its own handler
+ // we return EXCEPTION_EXECUTE_HANDLER
+ DoOutputDebugString("CAPEExceptionFilter: Non-breakpoint exception caught, passing to sample's handler.\n");
+ SetUnhandledExceptionFilter(OriginalExceptionHandler);
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+ else if (VECTORED_HANDLER && SampleVectoredHandler)
+ {
+ // As it's not a bp and the sample has registered its own handler
+ //DoOutputDebugString("CAPEExceptionFilter: Non-breakpoint exception caught, passing to sample's vectored handler.\n");
+ SampleVectoredHandler(ExceptionInfo);
+ }
+
+ if ((ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress >= g_our_dll_base && (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress < (g_our_dll_base + g_our_dll_size))
+ {
+ // This is a CAPE (or Cuckoo) exception
+ DoOutputDebugString("CAPEExceptionFilter: Exception 0x%x caught at RVA 0x%x in capemon caught accessing 0x%x (expected in memory scans), passing to next handler.\n", ExceptionInfo->ExceptionRecord->ExceptionCode, (BYTE*)ExceptionInfo->ExceptionRecord->ExceptionAddress - g_our_dll_base, ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
+ // Some other exception occurred. Pass it to next handler.
+ //DllRVA = 0;
+ //if (ExceptionInfo->ExceptionRecord->ExceptionAddress)
+ // DllName = convert_address_to_dll_name_and_offset((ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress, &DllRVA);
+ //else
+ // DllName = "unknown";
+ //
+ //DoOutputDebugString("CAPEExceptionFilter: Exception 0x%x caught at 0x%x accessing 0x%x (RVA 0x%x in %s) passing.\n", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress, ExceptionInfo->ExceptionRecord->ExceptionInformation[1], DllRVA, DllName);
return EXCEPTION_CONTINUE_SEARCH;
}
//**************************************************************************************
-BOOL SetExceptionDebugRegister
+BOOL ContextSetDebugRegister
//**************************************************************************************
(
PCONTEXT Context,
@@ -392,38 +1237,41 @@ BOOL SetExceptionDebugRegister
)
{
DWORD Length;
+#ifdef _WIN64
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint;
+#endif
- PDWORD Dr0 = &(Context->Dr0);
- PDWORD Dr1 = &(Context->Dr1);
- PDWORD Dr2 = &(Context->Dr2);
- PDWORD Dr3 = &(Context->Dr3);
- PDR7 Dr7 = (PDR7)&(Context->Dr7);
+ PDWORD_PTR Dr0 = &(Context->Dr0);
+ PDWORD_PTR Dr1 = &(Context->Dr1);
+ PDWORD_PTR Dr2 = &(Context->Dr2);
+ PDWORD_PTR Dr3 = &(Context->Dr3);
+ PDR7 Dr7 = (PDR7)&(Context->Dr7);
if ((unsigned int)Type > 3)
{
- DoOutputDebugString("SetExceptionDebugRegister: %d is an invalid breakpoint type, must be 0-3.\n", Type);
+ DoOutputDebugString("ContextSetDebugRegister: %d is an invalid breakpoint type, must be 0-3.\n", Type);
return FALSE;
}
if (Type == 2)
{
- DoOutputDebugString("SetExceptionDebugRegister: The value 2 is a 'reserved' breakpoint type, ultimately invalid.\n");
+ DoOutputDebugString("ContextSetDebugRegister: The value 2 is a 'reserved' breakpoint type, ultimately invalid.\n");
return FALSE;
}
if (Register < 0 || Register > 3)
{
- DoOutputDebugString("SetExceptionDebugRegister: %d is an invalid register, must be 0-3.\n", Register);
+ DoOutputDebugString("ContextSetDebugRegister: %d is an invalid register, must be 0-3.\n", Register);
return FALSE;
}
if (Size < 0 || Size > 8)
{
- DoOutputDebugString("SetExceptionDebugRegister: %d is an invalid Size, must be 1, 2, 4 or 8.\n", Size);
+ DoOutputDebugString("ContextSetDebugRegister: %d is an invalid Size, must be 1, 2, 4 or 8.\n", Size);
return FALSE;
}
- DoOutputDebugString("Setting breakpoint %i within Context, Size=0x%x, Address=0x%x and Type=0x%x.\n", Register, Size, Address, Type);
+ DoOutputDebugString("ContextSetDebugRegister: Setting breakpoint %i within Context, Size=0x%x, Address=0x%p and Type=0x%x.\n", Register, Size, Address, Type);
Length = LengthMask[Size];
@@ -431,33 +1279,35 @@ BOOL SetExceptionDebugRegister
if (Type == BP_EXEC)
Length = 0;
- if (Type == BP_READWRITE && address_is_in_stack((DWORD)Address))
+#ifndef _WIN64
+ if (Type == BP_READWRITE && address_is_in_stack((DWORD_PTR)Address))
WoW64PatchBreakpoint(Register);
+#endif
if (Register == 0)
{
- *Dr0 = (DWORD)Address;
+ *Dr0 = (DWORD_PTR)Address;
Dr7->LEN0 = Length;
Dr7->RWE0 = Type;
Dr7->L0 = 1;
}
else if (Register == 1)
{
- *Dr1 = (DWORD)Address;
+ *Dr1 = (DWORD_PTR)Address;
Dr7->LEN1 = Length;
Dr7->RWE1 = Type;
Dr7->L1 = 1;
}
else if (Register == 2)
{
- *Dr2 = (DWORD)Address;
+ *Dr2 = (DWORD_PTR)Address;
Dr7->LEN2 = Length;
Dr7->RWE2 = Type;
Dr7->L2 = 1;
}
else if (Register == 3)
{
- *Dr3 = (DWORD)Address;
+ *Dr3 = (DWORD_PTR)Address;
Dr7->LEN3 = Length;
Dr7->RWE3 = Type;
Dr7->L3 = 1;
@@ -465,6 +1315,32 @@ BOOL SetExceptionDebugRegister
Dr7->LE = 1;
Context->Dr6 = 0;
+
+#ifdef _WIN64
+ CurrentThreadBreakpoint = GetThreadBreakpoints(GetCurrentThreadId());
+
+ if (CurrentThreadBreakpoint == NULL)
+ {
+ DoOutputDebugString("ContextSetDebugRegister: No breakpoints found for current thread %d.\n", GetCurrentThreadId());
+ return FALSE;
+ }
+
+ if (CurrentThreadBreakpoint->ThreadHandle == NULL)
+ {
+ DoOutputDebugString("ContextSetDebugRegister: No thread handle found in breakpoints found for current thread %d.\n", GetCurrentThreadId());
+ return FALSE;
+ }
+
+ Context->ContextFlags = CONTEXT_DEBUG_REGISTERS;
+
+ if (!SetThreadContext(CurrentThreadBreakpoint->ThreadHandle, Context))
+ {
+ DoOutputErrorString("ContextSetDebugRegister: SetThreadContext failed");
+ return FALSE;
+ }
+ else
+ DoOutputDebugString("ContextSetDebugRegister: SetThreadContext success.\n");
+#endif
return TRUE;
}
@@ -483,11 +1359,11 @@ BOOL SetDebugRegister
DWORD Length;
CONTEXT Context;
- PDWORD Dr0 = &Context.Dr0;
- PDWORD Dr1 = &Context.Dr1;
- PDWORD Dr2 = &Context.Dr2;
- PDWORD Dr3 = &Context.Dr3;
- PDR7 Dr7 = (PDR7)&(Context.Dr7);
+ PDWORD_PTR Dr0 = &Context.Dr0;
+ PDWORD_PTR Dr1 = &Context.Dr1;
+ PDWORD_PTR Dr2 = &Context.Dr2;
+ PDWORD_PTR Dr3 = &Context.Dr3;
+ PDR7 Dr7 = (PDR7)&(Context.Dr7);
if ((unsigned int)Type > 3)
{
@@ -513,12 +1389,13 @@ BOOL SetDebugRegister
return FALSE;
}
- DoOutputDebugString("Setting breakpoint %i hThread=0x%x, Size=0x%x, Address=0x%x and Type=0x%x.\n", Register, hThread, Size, Address, Type);
+ DoOutputDebugString("SetDebugRegister: Setting breakpoint %i hThread=0x%x, Size=0x%x, Address=0x%p and Type=0x%x.\n", Register, hThread, Size, Address, Type);
Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if (!GetThreadContext(hThread, &Context))
{
+ DoOutputErrorString("SetDebugRegister: GetThreadContext failed (thread handle 0x%x)", hThread);
return FALSE;
}
@@ -528,33 +1405,35 @@ BOOL SetDebugRegister
if (Type == BP_EXEC)
Length = 0;
- if (Type == BP_READWRITE && address_is_in_stack((DWORD)Address))
+#ifndef _WIN64
+ if (Type == BP_READWRITE && address_is_in_stack((DWORD_PTR)Address))
WoW64PatchBreakpoint(Register);
+#endif
if (Register == 0)
{
- *Dr0 = (DWORD)Address;
+ *Dr0 = (DWORD_PTR)Address;
Dr7->LEN0 = Length;
Dr7->RWE0 = Type;
Dr7->L0 = 1;
}
else if (Register == 1)
{
- *Dr1 = (DWORD)Address;
+ *Dr1 = (DWORD_PTR)Address;
Dr7->LEN1 = Length;
Dr7->RWE1 = Type;
Dr7->L1 = 1;
}
else if (Register == 2)
{
- *Dr2 = (DWORD)Address;
+ *Dr2 = (DWORD_PTR)Address;
Dr7->LEN2 = Length;
Dr7->RWE2 = Type;
Dr7->L2 = 1;
}
else if (Register == 3)
{
- *Dr3 = (DWORD)Address;
+ *Dr3 = (DWORD_PTR)Address;
Dr7->LEN3 = Length;
Dr7->RWE3 = Type;
Dr7->L3 = 1;
@@ -566,31 +1445,35 @@ BOOL SetDebugRegister
Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if (!SetThreadContext(hThread, &Context))
- return FALSE;
-
+ {
+ DoOutputErrorString("SetDebugRegister: SetThreadContext failed");
+ return FALSE;
+ }
+
return TRUE;
}
//**************************************************************************************
-BOOL ClearAllDebugRegisters(HANDLE hThread)
+BOOL ContextCheckDebugRegisters(PCONTEXT Context)
//**************************************************************************************
-{
- CONTEXT Context;
- Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
-
- if (!GetThreadContext(hThread, &Context))
- return FALSE;
+{
+ PDR7 Dr7;
+
+ if (!Context)
+ {
+ DoOutputDebugString("CheckDebugRegisters - no context supplied.\n");
+ return FALSE;
+ }
+
+ Dr7 = (PDR7)&(Context->Dr7);
+
+ DoOutputDebugString("Checking breakpoints\n");
+ DoOutputDebugString("Dr0 0x%x, Dr7->LEN0 %i, Dr7->RWE0 %i, Dr7->L0 %i\n", Context->Dr0, Dr7->LEN0, Dr7->RWE0, Dr7->L0);
+ DoOutputDebugString("Dr1 0x%x, Dr7->LEN1 %i, Dr7->RWE1 %i, Dr7->L1 %i\n", Context->Dr1, Dr7->LEN1, Dr7->RWE1, Dr7->L1);
+ DoOutputDebugString("Dr2 0x%x, Dr7->LEN2 %i, Dr7->RWE2 %i, Dr7->L2 %i\n", Context->Dr2, Dr7->LEN2, Dr7->RWE2, Dr7->L2);
+ DoOutputDebugString("Dr3 0x%x, Dr7->LEN3 %i, Dr7->RWE3 %i, Dr7->L3 %i\n", Context->Dr3, Dr7->LEN3, Dr7->RWE3, Dr7->L3);
+ DoOutputDebugString("Dr6 0x%x\n", Context->Dr6);
- Context.Dr0 = 0;
- Context.Dr1 = 0;
- Context.Dr2 = 0;
- Context.Dr3 = 0;
- Context.Dr6 = 0;
- Context.Dr7 = 0;
-
- if (!SetThreadContext(hThread, &Context))
- return FALSE;
-
return TRUE;
}
@@ -599,15 +1482,15 @@ BOOL CheckDebugRegisters(HANDLE hThread, PCONTEXT pContext)
//**************************************************************************************
{
CONTEXT Context;
- PDWORD Dr0 = &Context.Dr0;
- PDWORD Dr1 = &Context.Dr1;
- PDWORD Dr2 = &Context.Dr2;
- PDWORD Dr3 = &Context.Dr3;
- PDR7 Dr7 = (PDR7)&(Context.Dr7);
+ PDWORD_PTR Dr0 = &Context.Dr0;
+ PDWORD_PTR Dr1 = &Context.Dr1;
+ PDWORD_PTR Dr2 = &Context.Dr2;
+ PDWORD_PTR Dr3 = &Context.Dr3;
+ PDR7 Dr7 = (PDR7)&(Context.Dr7);
if (!hThread && !pContext)
{
- DoOutputDebugString("CheckDebugRegisters - no arguments supplied.\n");
+ DoOutputDebugString("CheckDebugRegisters - required arguments missing.\n");
return FALSE;
}
@@ -636,10 +1519,122 @@ BOOL CheckDebugRegisters(HANDLE hThread, PCONTEXT pContext)
}
//**************************************************************************************
-BOOL ClearExceptionHardwareBreakpoint(PCONTEXT Context, PBREAKPOINTINFO pBreakpointInfo)
+BOOL ContextClearAllBreakpoints(PCONTEXT Context)
+//**************************************************************************************
+{
+ unsigned int i;
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint;
+
+ CurrentThreadBreakpoint = GetThreadBreakpoints(GetCurrentThreadId());
+
+ if (CurrentThreadBreakpoint == NULL)
+ {
+ DoOutputDebugString("ContextClearAllBreakpoints: No breakpoints found for current thread %d.\n", GetCurrentThreadId());
+ return FALSE;
+ }
+
+ for (i=0; i < NUMBER_OF_DEBUG_REGISTERS; i++)
+ {
+ CurrentThreadBreakpoint->BreakpointInfo[i].Register = 0;
+ CurrentThreadBreakpoint->BreakpointInfo[i].Size = 0;
+ CurrentThreadBreakpoint->BreakpointInfo[i].Address = NULL;
+ CurrentThreadBreakpoint->BreakpointInfo[i].Type = 0;
+ CurrentThreadBreakpoint->BreakpointInfo[i].Callback = NULL;
+ }
+
+ Context->Dr0 = 0;
+ Context->Dr1 = 0;
+ Context->Dr2 = 0;
+ Context->Dr3 = 0;
+ Context->Dr6 = 0;
+ Context->Dr7 = 0;
+
+#ifdef _WIN64
+ if (CurrentThreadBreakpoint->ThreadHandle == NULL)
+ {
+ DoOutputDebugString("ContextClearAllBreakpoints: No thread handle found in breakpoints found for current thread %d.\n", GetCurrentThreadId());
+ return FALSE;
+ }
+
+ Context->ContextFlags = CONTEXT_DEBUG_REGISTERS;
+
+ if (!SetThreadContext(CurrentThreadBreakpoint->ThreadHandle, Context))
+ {
+ DoOutputErrorString("ContextClearAllBreakpoints: SetThreadContext failed");
+ return FALSE;
+ }
+ else
+ DoOutputDebugString("ContextClearAllBreakpoints: SetThreadContext success.\n");
+#endif
+
+ return TRUE;
+}
+
+//**************************************************************************************
+BOOL ClearAllBreakpoints()
+//**************************************************************************************
+{
+ CONTEXT Context;
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint;
+ unsigned int Register;
+
+ CurrentThreadBreakpoint = MainThreadBreakpointList;
+
+ while (CurrentThreadBreakpoint)
+ {
+ if (!CurrentThreadBreakpoint->ThreadId)
+ {
+ DoOutputDebugString("ClearAllBreakpoints: Error: no thread id for thread breakpoints 0x%x.\n", CurrentThreadBreakpoint);
+ return FALSE;
+ }
+
+ if (!CurrentThreadBreakpoint->ThreadHandle)
+ {
+ DoOutputDebugString("ClearAllBreakpoints: Error no thread handle for thread %d.\n", CurrentThreadBreakpoint->ThreadId);
+ return FALSE;
+ }
+
+ for (Register = 0; Register < NUMBER_OF_DEBUG_REGISTERS; Register++)
+ {
+ CurrentThreadBreakpoint->BreakpointInfo[Register].Register = 0;
+ CurrentThreadBreakpoint->BreakpointInfo[Register].Size = 0;
+ CurrentThreadBreakpoint->BreakpointInfo[Register].Address = NULL;
+ CurrentThreadBreakpoint->BreakpointInfo[Register].Type = 0;
+ CurrentThreadBreakpoint->BreakpointInfo[Register].Callback = NULL;
+ }
+
+ Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+
+ if (!GetThreadContext(CurrentThreadBreakpoint->ThreadHandle, &Context))
+ {
+ DoOutputDebugString("ClearAllBreakpoints: Error getting thread context (thread %d).\n", CurrentThreadBreakpoint->ThreadId);
+ return FALSE;
+ }
+
+ Context.Dr0 = 0;
+ Context.Dr1 = 0;
+ Context.Dr2 = 0;
+ Context.Dr3 = 0;
+ Context.Dr6 = 0;
+ Context.Dr7 = 0;
+
+ if (!SetThreadContext(CurrentThreadBreakpoint->ThreadHandle, &Context))
+ {
+ DoOutputDebugString("ClearAllBreakpoints: Error setting thread context (thread %d).\n", CurrentThreadBreakpoint->ThreadId);
+ return FALSE;
+ }
+
+ CurrentThreadBreakpoint = CurrentThreadBreakpoint->NextThreadBreakpoints;
+ }
+
+ return TRUE;
+}
+
+//**************************************************************************************
+BOOL ContextClearBreakpoint(PCONTEXT Context, PBREAKPOINTINFO pBreakpointInfo)
//**************************************************************************************
{
- PDWORD Dr0, Dr1, Dr2, Dr3;
+ PDWORD_PTR Dr0, Dr1, Dr2, Dr3;
PDR7 Dr7;
if (Context == NULL)
@@ -651,7 +1646,7 @@ BOOL ClearExceptionHardwareBreakpoint(PCONTEXT Context, PBREAKPOINTINFO pBreakpo
Dr3 = &(Context->Dr3);
Dr7 = (PDR7)&(Context->Dr7);
- DoOutputDebugString("Clearing Context breakpoint %i\n", pBreakpointInfo->Register);
+ DoOutputDebugString("ContextClearBreakpoint: Clearing breakpoint %i\n", pBreakpointInfo->Register);
if (pBreakpointInfo->Register == 0)
{
@@ -682,10 +1677,30 @@ BOOL ClearExceptionHardwareBreakpoint(PCONTEXT Context, PBREAKPOINTINFO pBreakpo
Dr7->L3 = 0;
}
- if (pBreakpointInfo->Type == BP_READWRITE && address_is_in_stack((DWORD)pBreakpointInfo->Address))
+#ifndef _WIN64
+ if (pBreakpointInfo->Type == BP_READWRITE && address_is_in_stack((DWORD_PTR)pBreakpointInfo->Address))
WoW64UnpatchBreakpoint(pBreakpointInfo->Register);
+#endif
Context->Dr6 = 0;
+
+#ifdef _WIN64
+ if (pBreakpointInfo->ThreadHandle == NULL)
+ {
+ DoOutputDebugString("ContextClearBreakpoint: No thread handle found in breakpoints found for current thread %d.\n", GetCurrentThreadId());
+ return FALSE;
+ }
+
+ Context->ContextFlags = CONTEXT_DEBUG_REGISTERS;
+
+ if (!SetThreadContext(pBreakpointInfo->ThreadHandle, Context))
+ {
+ DoOutputErrorString("ContextClearBreakpoint: SetThreadContext failed");
+ return FALSE;
+ }
+ else
+ DoOutputDebugString("ContextClearBreakpoint: SetThreadContext success.\n");
+#endif
pBreakpointInfo->Address = 0;
pBreakpointInfo->Size = 0;
@@ -695,6 +1710,54 @@ BOOL ClearExceptionHardwareBreakpoint(PCONTEXT Context, PBREAKPOINTINFO pBreakpo
return TRUE;
}
+//**************************************************************************************
+BOOL ClearBreakpointsInRange(DWORD ThreadId, PVOID BaseAddress, SIZE_T Size)
+//**************************************************************************************
+{
+ unsigned int Register;
+ DWORD CurrentThreadId;
+
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint = MainThreadBreakpointList;
+
+ if (BaseAddress == NULL)
+ {
+ DoOutputDebugString("ClearBreakpointsInRange: No address supplied (may have already been cleared).\n");
+ return FALSE;
+ }
+
+ if (Size == 0)
+ {
+ DoOutputDebugString("ClearBreakpointsInRange: Size supplied is zero.\n");
+ return FALSE;
+ }
+
+ DoOutputDebugString("ClearBreakpointsInRange: Clearing breakpoints in range 0x%x - 0x%x.\n", BaseAddress, (BYTE*)BaseAddress + Size);
+
+ while (CurrentThreadBreakpoint)
+ {
+ CurrentThreadId = MyGetThreadId(CurrentThreadBreakpoint->ThreadHandle);
+
+ if (CurrentThreadId == ThreadId)
+ {
+ for (Register = 0; Register < NUMBER_OF_DEBUG_REGISTERS; Register++)
+ {
+ if ((DWORD_PTR)CurrentThreadBreakpoint->BreakpointInfo[Register].Address >= (DWORD_PTR)BaseAddress
+ && (DWORD_PTR)CurrentThreadBreakpoint->BreakpointInfo[Register].Address < (DWORD_PTR)((BYTE*)BaseAddress + Size))
+ {
+ DoOutputDebugString("ClearBreakpointsInRange: Clearing breakpoint %d address 0x%x.\n", Register, CurrentThreadBreakpoint->BreakpointInfo[Register].Address);
+ ClearBreakpoint(CurrentThreadBreakpoint->ThreadId, Register);
+ }
+ }
+
+ return TRUE;
+ }
+ else
+ CurrentThreadBreakpoint = CurrentThreadBreakpoint->NextThreadBreakpoints;
+ }
+
+ return FALSE;
+}
+
//**************************************************************************************
BOOL SetResumeFlag(PCONTEXT Context)
//**************************************************************************************
@@ -707,16 +1770,40 @@ BOOL SetResumeFlag(PCONTEXT Context)
return TRUE;
}
+//**************************************************************************************
+BOOL SetZeroFlag(PCONTEXT Context)
+//**************************************************************************************
+{
+ if (Context == NULL)
+ return FALSE;
+
+ Context->EFlags |= FL_ZF;
+
+ return TRUE;
+}
+
+//**************************************************************************************
+BOOL ClearZeroFlag(PCONTEXT Context)
+//**************************************************************************************
+{
+ if (Context == NULL)
+ return FALSE;
+
+ Context->EFlags &= ~FL_ZF;
+
+ return TRUE;
+}
+
//**************************************************************************************
BOOL SetSingleStepMode(PCONTEXT Context, PVOID Handler)
//**************************************************************************************
{
if (Context == NULL)
return FALSE;
-
+
// set the trap flag
Context->EFlags |= FL_TF;
-
+
SingleStepHandler = (SINGLE_STEP_HANDLER)Handler;
return TRUE;
@@ -729,14 +1816,132 @@ BOOL ClearSingleStepMode(PCONTEXT Context)
if (Context == NULL)
return FALSE;
- // Clear the trap flag
+ // Clear the trap flag & index
Context->EFlags &= ~FL_TF;
+ TrapIndex = 0;
+
SingleStepHandler = NULL;
return TRUE;
}
+//**************************************************************************************
+BOOL StepOverExecutionBreakpoint(PCONTEXT Context, PBREAKPOINTINFO pBreakpointInfo)
+//**************************************************************************************
+// This function allows us to get past an execution breakpoint while leaving it set. It
+// diaables the breakpoint, sets single-step mode to step over the instruction, whereupon
+// the breakpoint is restored in ResumeAfterExecutionBreakpoint and execution resumed.
+{
+ PDR7 Dr7;
+
+ if (Context == NULL)
+ return FALSE;
+
+ Dr7 = (PDR7)&(Context->Dr7);
+
+ switch(pBreakpointInfo->Register)
+ {
+ case 0:
+ Dr7->L0 = 0;
+ break;
+ case 1:
+ Dr7->L1 = 0;
+ break;
+ case 2:
+ Dr7->L2 = 0;
+ break;
+ case 3:
+ Dr7->L3 = 0;
+ break;
+ }
+
+ // set the trap flag
+ Context->EFlags |= FL_TF;
+
+ // set the 'trap index' so we know which 'register' we're skipping
+ // (off by one to allow 'set'/'unset' to be signified by !0/0)
+ TrapIndex = pBreakpointInfo->Register + 1;
+
+#ifdef _WIN64
+ if (pBreakpointInfo->ThreadHandle == NULL)
+ {
+ DoOutputDebugString("StepOverExecutionBreakpoint: No thread handle found in breakpoints found for current thread %d.\n", GetCurrentThreadId());
+ return FALSE;
+ }
+
+ Context->ContextFlags = CONTEXT_DEBUG_REGISTERS;
+
+ if (!SetThreadContext(pBreakpointInfo->ThreadHandle, Context))
+ {
+ DoOutputErrorString("StepOverExecutionBreakpoint: SetThreadContext failed");
+ return FALSE;
+ }
+#endif
+
+ return TRUE;
+}
+
+//**************************************************************************************
+BOOL ResumeAfterExecutionBreakpoint(PCONTEXT Context, PBREAKPOINTINFO pBreakpointInfo)
+//**************************************************************************************
+{
+ PDR7 Dr7;
+
+ if (Context == NULL)
+ return FALSE;
+
+ Dr7 = (PDR7)&(Context->Dr7);
+
+#ifdef _WIN64
+ if (!pBreakpointInfo)
+ {
+ DoOutputDebugString("ResumeAfterExecutionBreakpoint: pBreakpointInfo NULL.\n");
+ return FALSE;
+ }
+#endif
+
+ switch(TrapIndex-1)
+ {
+ case 0:
+ Dr7->L0 = 1;
+ break;
+ case 1:
+ Dr7->L1 = 1;
+ break;
+ case 2:
+ Dr7->L2 = 1;
+ break;
+ case 3:
+ Dr7->L3 = 1;
+ break;
+ }
+
+ // Clear the trap flag
+ Context->EFlags &= ~FL_TF;
+
+#ifdef _WIN64
+ if (pBreakpointInfo->ThreadHandle == NULL)
+ {
+ DoOutputDebugString("ResumeAfterExecutionBreakpoint: No thread handle found in breakpoints found for current thread %d.\n", GetCurrentThreadId());
+ return FALSE;
+ }
+
+ Context->ContextFlags = CONTEXT_DEBUG_REGISTERS;
+
+ if (!SetThreadContext(pBreakpointInfo->ThreadHandle, Context))
+ {
+ DoOutputErrorString("ResumeAfterExecutionBreakpoint: SetThreadContext failed");
+ return FALSE;
+ }
+#endif
+
+ // clear the 'trap index'
+ TrapIndex = 0;
+
+ return TRUE;
+}
+
//**************************************************************************************
BOOL ClearDebugRegister
//**************************************************************************************
@@ -746,15 +1951,14 @@ BOOL ClearDebugRegister
int Size,
LPVOID Address,
DWORD Type
-)
-{
+){
CONTEXT Context;
BOOL DoCloseHandle = FALSE;
- PDWORD Dr0 = &Context.Dr0;
- PDWORD Dr1 = &Context.Dr1;
- PDWORD Dr2 = &Context.Dr2;
- PDWORD Dr3 = &Context.Dr3;
- PDR7 Dr7 = (PDR7)&(Context.Dr7);
+ PDWORD_PTR Dr0 = &Context.Dr0;
+ PDWORD_PTR Dr1 = &Context.Dr1;
+ PDWORD_PTR Dr2 = &Context.Dr2;
+ PDWORD_PTR Dr3 = &Context.Dr3;
+ PDR7 Dr7 = (PDR7)&(Context.Dr7);
if ((unsigned int)Type > 3)
{
@@ -774,8 +1978,6 @@ BOOL ClearDebugRegister
return FALSE;
}
- DoOutputDebugString("Clearing breakpoint %i\n", Register);
-
Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if (!GetThreadContext(hThread, &Context))
@@ -813,8 +2015,10 @@ BOOL ClearDebugRegister
Dr7->L3 = 0;
}
- if (Type == BP_READWRITE && address_is_in_stack((DWORD)Address))
+#ifndef _WIN64
+ if (Type == BP_READWRITE && address_is_in_stack((DWORD_PTR)Address))
WoW64UnpatchBreakpoint(Register);
+#endif
Context.Dr6 = 0;
@@ -827,24 +2031,60 @@ BOOL ClearDebugRegister
}
if (DoCloseHandle == TRUE)
- CloseHandle(hThread);
+ CloseHandle(hThread);
return TRUE;
}
//**************************************************************************************
-int CheckExceptionDebugRegister(CONTEXT Context, int Register)
+int ContextCheckDebugRegister(CONTEXT Context, int Register)
+//**************************************************************************************
+{
+ PDR7 Dr7;
+
+ if (Register < 0 || Register > 3)
+ {
+ DoOutputDebugString("ContextCheckDebugRegister: %d is an invalid register, must be 0-3.\n", Register);
+ return FALSE;
+ }
+
+ Dr7 = (PDR7)&(Context.Dr7);
+
+ if (Register == 0)
+ return Dr7->L0;
+ else if (Register == 1)
+ return Dr7->L1;
+ else if (Register == 2)
+ return Dr7->L2;
+ else if (Register == 3)
+ return Dr7->L3;
+
+ // should not happen
+ return -1;
+}
+
+//**************************************************************************************
+int CheckDebugRegister(HANDLE hThread, int Register)
//**************************************************************************************
{
+ CONTEXT Context;
PDR7 Dr7;
if (Register < 0 || Register > 3)
{
- DoOutputDebugString("CheckExceptionDebugRegister: %d is an invalid register, must be 0-3.\n", Register);
+ DoOutputDebugString("CheckDebugRegister: %d is an invalid register, must be 0-3.\n", Register);
return FALSE;
}
Dr7 = (PDR7)&(Context.Dr7);
+
+ Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+
+ if (!GetThreadContext(hThread, &Context))
+ {
+ DoOutputDebugString("CheckDebugRegister: GetThreadContext failed - FATAL\n");
+ return FALSE;
+ }
if (Register == 0)
return Dr7->L0;
@@ -859,109 +2099,274 @@ int CheckExceptionDebugRegister(CONTEXT Context, int Register)
return -1;
}
+
+//**************************************************************************************
+BOOL ContextSetBreakpoint(PTHREADBREAKPOINTS ReferenceThreadBreakpoint)
+//**************************************************************************************
+{
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint;
+
+ if (ReferenceThreadBreakpoint == NULL)
+ {
+ DoOutputDebugString("ContextSetBreakpoint: ReferenceThreadBreakpoint NULL.\n");
+ return FALSE;
+ }
+
+ if (MainThreadBreakpointList == NULL)
+ {
+ DoOutputDebugString("ContextSetBreakpoint: MainThreadBreakpointList NULL.\n");
+ return FALSE;
+ }
+
+ CurrentThreadBreakpoint = MainThreadBreakpointList;
+
+ while (CurrentThreadBreakpoint)
+ {
+ if (CurrentThreadBreakpoint != ReferenceThreadBreakpoint)
+ {
+ for (unsigned int i = 0; i < NUMBER_OF_DEBUG_REGISTERS; i++)
+ {
+ if (CurrentThreadBreakpoint->ThreadHandle)
+ CurrentThreadBreakpoint->BreakpointInfo[i].ThreadHandle = CurrentThreadBreakpoint->ThreadHandle;
+ CurrentThreadBreakpoint->BreakpointInfo[i].Register = ReferenceThreadBreakpoint->BreakpointInfo[i].Register;
+ CurrentThreadBreakpoint->BreakpointInfo[i].Size = ReferenceThreadBreakpoint->BreakpointInfo[i].Size;
+ CurrentThreadBreakpoint->BreakpointInfo[i].Address = ReferenceThreadBreakpoint->BreakpointInfo[i].Address;
+ CurrentThreadBreakpoint->BreakpointInfo[i].Type = ReferenceThreadBreakpoint->BreakpointInfo[i].Type;
+ CurrentThreadBreakpoint->BreakpointInfo[i].Callback = ReferenceThreadBreakpoint->BreakpointInfo[i].Callback;
+
+ if (CurrentThreadBreakpoint->BreakpointInfo[i].Address)
+ SetThreadBreakpoint(CurrentThreadBreakpoint->ThreadId, CurrentThreadBreakpoint->BreakpointInfo[i].Register, CurrentThreadBreakpoint->BreakpointInfo[i].Size, CurrentThreadBreakpoint->BreakpointInfo[i].Address, CurrentThreadBreakpoint->BreakpointInfo[i].Type, CurrentThreadBreakpoint->BreakpointInfo[i].Callback);
+ }
+ }
+
+ CurrentThreadBreakpoint = CurrentThreadBreakpoint->NextThreadBreakpoints;
+ }
+
+ return TRUE;
+}
+
+
+//**************************************************************************************
+BOOL ContextSetThreadBreakpoint
+//**************************************************************************************
+(
+ PCONTEXT Context,
+ int Register,
+ int Size,
+ LPVOID Address,
+ DWORD Type,
+ PVOID Callback
+)
+{
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint;
+
+ if (Register > 3 || Register < 0)
+ {
+ DoOutputDebugString("ContextSetThreadBreakpoint: Error - register value %d, can only have value 0-3.\n", Register);
+ return FALSE;
+ }
+
+ if (!ContextSetDebugRegister(Context, Register, Size, Address, Type))
+ {
+ DoOutputDebugString("ContextSetThreadBreakpoint: Call to ContextSetDebugRegister failed.\n");
+ }
+ else
+ {
+ CurrentThreadBreakpoint = GetThreadBreakpoints(GetCurrentThreadId());
+
+ if (CurrentThreadBreakpoint == NULL)
+ {
+ DoOutputDebugString("ContextSetThreadBreakpoint: Error - Failed to acquire thread breakpoints.\n");
+ return FALSE;
+ }
+
+ CurrentThreadBreakpoint->BreakpointInfo[Register].ThreadHandle = CurrentThreadBreakpoint->ThreadHandle;
+ CurrentThreadBreakpoint->BreakpointInfo[Register].Register = Register;
+ CurrentThreadBreakpoint->BreakpointInfo[Register].Size = Size;
+ CurrentThreadBreakpoint->BreakpointInfo[Register].Address = Address;
+ CurrentThreadBreakpoint->BreakpointInfo[Register].Type = Type;
+ CurrentThreadBreakpoint->BreakpointInfo[Register].Callback = Callback;
+ }
+
+#ifdef _WIN64
+ if (CurrentThreadBreakpoint->ThreadHandle == NULL)
+ {
+ DoOutputDebugString("ContextSetThreadBreakpoint: No thread handle found in breakpoints found for current thread %d.\n", GetCurrentThreadId());
+ return FALSE;
+ }
+
+ Context->ContextFlags = CONTEXT_DEBUG_REGISTERS;
+
+ if (!SetThreadContext(CurrentThreadBreakpoint->ThreadHandle, Context))
+ {
+ DoOutputErrorString("ContextSetThreadBreakpoint: SetThreadContext failed");
+ return FALSE;
+ }
+#endif
+
+ return TRUE;
+}
+
+//**************************************************************************************
+BOOL ContextSetNextAvailableBreakpoint
+//**************************************************************************************
+(
+ PCONTEXT Context,
+ unsigned int* Register,
+ int Size,
+ LPVOID Address,
+ DWORD Type,
+ PVOID Callback
+)
+{
+ if (Register)
+ {
+ if (!ContextGetNextAvailableBreakpoint(Context, Register))
+ {
+ DoOutputDebugString("ContextSetNextAvailableBreakpoint: ContextGetNextAvailableBreakpoint failed\n");
+ return FALSE;
+ }
+
+ return ContextSetThreadBreakpoint(Context, *Register, Size, Address, Type, Callback);
+ }
+ else
+ {
+ unsigned int TempRegister;
+
+ if (!ContextGetNextAvailableBreakpoint(Context, &TempRegister))
+ {
+ DoOutputDebugString("ContextSetNextAvailableBreakpoint: ContextGetNextAvailableBreakpoint failed\n");
+ return FALSE;
+ }
+
+ return ContextSetThreadBreakpoint(Context, TempRegister, Size, Address, Type, Callback);
+ }
+}
+
//**************************************************************************************
-int CheckDebugRegister(HANDLE hThread, int Register)
+BOOL ContextUpdateCurrentBreakpoint
//**************************************************************************************
+(
+ PCONTEXT Context,
+ int Size,
+ LPVOID Address,
+ DWORD Type,
+ PVOID Callback
+)
{
- CONTEXT Context;
- PDR7 Dr7;
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint;
+ PBREAKPOINTINFO pBreakpointInfo;
+ unsigned int bp;
- if (Register < 0 || Register > 3)
+ CurrentThreadBreakpoint = GetThreadBreakpoints(GetCurrentThreadId());
+
+ if (CurrentThreadBreakpoint == NULL)
{
- DoOutputDebugString("CheckDebugRegister: %d is an invalid register, must be 0-3.\n", Register);
+ DoOutputDebugString("ContextUpdateCurrentBreakpoint: Error - Failed to acquire thread breakpoints.\n");
return FALSE;
}
- Dr7 = (PDR7)&(Context.Dr7);
-
- Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
-
- if (!GetThreadContext(hThread, &Context))
+ for (bp = 0; bp < NUMBER_OF_DEBUG_REGISTERS; bp++)
{
- DoOutputDebugString("CheckDebugRegister: GetThreadContext failed - FATAL\n");
- return FALSE;
- }
+ if (Context->Dr6 & (DWORD_PTR)(1 << bp))
+ {
+ pBreakpointInfo = &(CurrentThreadBreakpoint->BreakpointInfo[bp]);
+
+ if (pBreakpointInfo == NULL)
+ {
+ DoOutputDebugString("ContextUpdateCurrentBreakpoint: Can't get BreakpointInfo.\n");
+ return FALSE;
+ }
+
+ if (pBreakpointInfo->Register == bp)
+ {
+ if (bp == 0 && ((DWORD_PTR)pBreakpointInfo->Address == Context->Dr0) && ((DWORD)pBreakpointInfo->Type == ((PDR7)&(Context->Dr7))->RWE0))
+ {
+ return ContextSetThreadBreakpoint(Context, 0, Size, Address, Type, Callback);
+ }
- if (Register == 0)
- return Dr7->L0;
- else if (Register == 1)
- return Dr7->L1;
- else if (Register == 2)
- return Dr7->L2;
- else if (Register == 3)
- return Dr7->L3;
-
- // should not happen
- return -1;
+ if (bp == 1 && ((DWORD_PTR)pBreakpointInfo->Address == Context->Dr1) && ((DWORD)pBreakpointInfo->Type == ((PDR7)&(Context->Dr7))->RWE1))
+ {
+ return ContextSetThreadBreakpoint(Context, 1, Size, Address, Type, Callback);
+ }
+
+ if (bp == 2 && ((DWORD_PTR)pBreakpointInfo->Address == Context->Dr2) && ((DWORD)pBreakpointInfo->Type == ((PDR7)&(Context->Dr7))->RWE2))
+ {
+ return ContextSetThreadBreakpoint(Context, 2, Size, Address, Type, Callback);
+ }
+
+ if (bp == 3 && ((DWORD_PTR)pBreakpointInfo->Address == Context->Dr3) && ((DWORD)pBreakpointInfo->Type == ((PDR7)&(Context->Dr7))->RWE3))
+ {
+ return ContextSetThreadBreakpoint(Context, 3, Size, Address, Type, Callback);
+ }
+ }
+ }
+ }
+
+ return FALSE;
}
//**************************************************************************************
-BOOL SetExceptionHardwareBreakpoint
+BOOL ContextClearCurrentBreakpoint
//**************************************************************************************
(
- PCONTEXT Context,
- int Register,
- int Size,
- LPVOID Address,
- DWORD Type,
- PVOID Callback
+ PCONTEXT Context
)
{
PTHREADBREAKPOINTS CurrentThreadBreakpoint;
+ PBREAKPOINTINFO pBreakpointInfo;
+ unsigned int bp;
- if (Register > 3 || Register < 0)
+ CurrentThreadBreakpoint = GetThreadBreakpoints(GetCurrentThreadId());
+
+ if (CurrentThreadBreakpoint == NULL)
{
- DoOutputDebugString("SetExceptionHardwareBreakpoint: Error - register value %d, can only have value 0-3.\n", Register);
+ DoOutputDebugString("ContextUpdateCurrentBreakpoint: Error - Failed to acquire thread breakpoints.\n");
return FALSE;
}
-
- if (SetExceptionDebugRegister(Context, Register, Size, Address, Type) == FALSE)
- {
- DoOutputDebugString("Call to SetExceptionDebugRegister failed.\n");
- }
- else
- {
- DoOutputDebugString("Call to SetExceptionDebugRegister succeeded.\n");
-
- CurrentThreadBreakpoint = GetThreadBreakpoints(GetCurrentThreadId());
-
- if (CurrentThreadBreakpoint == NULL)
+
+ for (bp = 0; bp < NUMBER_OF_DEBUG_REGISTERS; bp++)
+ {
+ if (Context->Dr6 & (DWORD_PTR)(1 << bp))
{
- DoOutputDebugString("Error: Failed to acquire thread breakpoints.\n");
- return FALSE;
+ pBreakpointInfo = &(CurrentThreadBreakpoint->BreakpointInfo[bp]);
+
+ if (pBreakpointInfo == NULL)
+ {
+ DoOutputDebugString("ContextUpdateCurrentBreakpoint: Can't get BreakpointInfo.\n");
+ return FALSE;
+ }
+
+ if (pBreakpointInfo->Register == bp)
+ return ContextClearBreakpoint(Context, pBreakpointInfo);
}
-
- CurrentThreadBreakpoint->BreakpointInfo[Register].Callback = Callback;
- CurrentThreadBreakpoint->BreakpointInfo[Register].Address = Address;
- CurrentThreadBreakpoint->BreakpointInfo[Register].Size = Size;
- CurrentThreadBreakpoint->BreakpointInfo[Register].Type = Type;
- }
-
- return 1;
+ }
+
+ return FALSE;
}
//**************************************************************************************
DWORD WINAPI SetBreakpointThread(LPVOID lpParam)
//**************************************************************************************
{
+ DWORD RetVal;
+
PBREAKPOINTINFO pBreakpointInfo = (PBREAKPOINTINFO)lpParam;
-
+
if (SuspendThread(pBreakpointInfo->ThreadHandle) == 0xFFFFFFFF)
- DoOutputErrorString("SetBreakpointThread: Call to SuspendThread failed");
- else
- DoOutputDebugString("SetBreakpointThread: Current thread suspended.\n");
-
- //debug
- DoOutputDebugString("SetBreakpointThread: ABbout to call SetDebugRegister.\n");
+ DoOutputErrorString("SetBreakpointThread: Call to SuspendThread failed for thread handle 0x%x", pBreakpointInfo->ThreadHandle);
- if (SetDebugRegister(pBreakpointInfo->ThreadHandle, pBreakpointInfo->Register, pBreakpointInfo->Size, pBreakpointInfo->Address, pBreakpointInfo->Type) == FALSE)
- {
- DoOutputErrorString("Call to SetDebugRegister failed");
- }
+ if (!SetDebugRegister(pBreakpointInfo->ThreadHandle, pBreakpointInfo->Register, pBreakpointInfo->Size, pBreakpointInfo->Address, pBreakpointInfo->Type))
+ DoOutputErrorString("SetBreakpointThread: Call to SetDebugRegister failed for thread handle 0x%x", pBreakpointInfo->ThreadHandle);
- DoOutputDebugString("SetBreakpointThread: Breakpoint set, about to resume thread.\n");
-
- ResumeThread(pBreakpointInfo->ThreadHandle);
+ RetVal = ResumeThread(pBreakpointInfo->ThreadHandle);
+
+ if (RetVal == -1)
+ DoOutputErrorString("SetBreakpointThread: ResumeThread failed for thread handle 0x%x", pBreakpointInfo->ThreadHandle);
+ else if (RetVal == 0)
+ DoOutputDebugString("SetBreakpointThread: Error - thread with handle 0x%x was not suspended.\n", pBreakpointInfo->ThreadHandle);
+ else if (g_config.debug)
+ DoOutputDebugString("SetBreakpointThread: Sample thread with handle 0x%x was suspended, now resumed.\n", pBreakpointInfo->ThreadHandle);
return 1;
}
@@ -970,29 +2375,105 @@ DWORD WINAPI SetBreakpointThread(LPVOID lpParam)
DWORD WINAPI ClearBreakpointThread(LPVOID lpParam)
//**************************************************************************************
{
+ DWORD RetVal;
PBREAKPOINTINFO pBreakpointInfo = (PBREAKPOINTINFO)lpParam;
- DoOutputDebugString("Inside ClearBreakpointThread.\n");
-
if (SuspendThread(pBreakpointInfo->ThreadHandle) == 0xFFFFFFFF)
DoOutputErrorString("ClearBreakpointThread: Call to SuspendThread failed");
- else
- DoOutputDebugString("ClearBreakpointThread: Current thread suspended.\n");
- if (ClearDebugRegister(pBreakpointInfo->ThreadHandle, pBreakpointInfo->Register, pBreakpointInfo->Size, pBreakpointInfo->Address, pBreakpointInfo->Type) == FALSE)
+ if (!ClearDebugRegister(pBreakpointInfo->ThreadHandle, pBreakpointInfo->Register, pBreakpointInfo->Size, pBreakpointInfo->Address, pBreakpointInfo->Type))
{
DoOutputDebugString("ClearBreakpointThread: Call to ClearDebugRegister failed.\n");
}
- DoOutputDebugString("ClearBreakpointThread: Breakpoint cleared, about to resume thread.\n");
+ RetVal = ResumeThread(pBreakpointInfo->ThreadHandle);
+ if (RetVal == -1)
+ {
+ DoOutputErrorString("ClearBreakpointThread: ResumeThread failed.\n");
+ }
+ else if (RetVal == 0)
+ {
+ DoOutputDebugString("ClearBreakpointThread: Error - Sample thread was not suspended.\n");
+ }
+ else if (g_config.debug)
+ {
+ DoOutputDebugString("ClearBreakpointThread: Sample thread was suspended, now resumed.\n");
+ }
+
+ DebugOutputThreadBreakpoints();
+
+ return TRUE;
+}
+
+//**************************************************************************************
+BOOL SetBreakpointWithoutThread
+//**************************************************************************************
+(
+ DWORD ThreadId,
+ int Register,
+ int Size,
+ LPVOID Address,
+ DWORD Type,
+ PVOID Callback
+)
+{
+ PBREAKPOINTINFO pBreakpointInfo;
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint;
+ BOOL RetVal;
+
+ if (Register > 3 || Register < 0)
+ {
+ DoOutputDebugString("SetBreakpointWithoutThread: Error - register value %d, can only have value 0-3.\n", Register);
+ return FALSE;
+ }
- ResumeThread(pBreakpointInfo->ThreadHandle);
+ CurrentThreadBreakpoint = GetThreadBreakpoints(ThreadId);
+
+ if (CurrentThreadBreakpoint == NULL)
+ {
+ DoOutputDebugString("SetBreakpointWithoutThread: Creating new thread breakpoints for thread %d.\n", ThreadId);
+ CurrentThreadBreakpoint = CreateThreadBreakpoints(ThreadId);
+ }
+
+ if (CurrentThreadBreakpoint == NULL)
+ {
+ DoOutputDebugString("SetBreakpointWithoutThread: Cannot create new thread breakpoints - FATAL.\n");
+ return FALSE;
+ }
- return 1;
+ pBreakpointInfo = &CurrentThreadBreakpoint->BreakpointInfo[Register];
+
+ if (CurrentThreadBreakpoint->ThreadHandle == NULL)
+ {
+ DoOutputDebugString("SetBreakpointWithoutThread: There is no thread handle in the thread breakpoint - Error.\n");
+ return FALSE;
+ }
+
+ pBreakpointInfo->ThreadHandle = CurrentThreadBreakpoint->ThreadHandle;
+ pBreakpointInfo->Register = Register;
+ pBreakpointInfo->Size = Size;
+ pBreakpointInfo->Address = Address;
+ pBreakpointInfo->Type = Type;
+ pBreakpointInfo->Callback = Callback;
+
+ __try
+ {
+ RetVal = SetDebugRegister(pBreakpointInfo->ThreadHandle, Register, Size, Address, Type);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DoOutputErrorString("SetBreakpointWithoutThread: Exception calling SetDebugRegister");
+ return FALSE;
+ }
+
+ // Debug
+ DoOutputDebugString("SetBreakpointWithoutThread: bp set with register %d\n", Register);
+
+ return TRUE;
}
//**************************************************************************************
-BOOL SetHardwareBreakpoint
+BOOL SetThreadBreakpoint
//**************************************************************************************
(
DWORD ThreadId,
@@ -1003,143 +2484,276 @@ BOOL SetHardwareBreakpoint
PVOID Callback
)
{
+ //if (DisableThreadSuspend)
+ // return SetBreakpointWithoutThread(ThreadId, Register, Size, Address, Type, Callback);
+
PBREAKPOINTINFO pBreakpointInfo;
- PTHREADBREAKPOINTS CurrentThreadBreakpoints;
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint;
HANDLE hSetBreakpointThread;
+ DWORD SetBreakpointThreadId;
+ BOOL RetVal;
if (Register > 3 || Register < 0)
{
- DoOutputDebugString("SetHardwareBreakpoint: Error - register value %d, can only have value 0-3.\n", Register);
+ DoOutputDebugString("SetThreadBreakpoint: Error - register value %d, can only have value 0-3.\n", Register);
return FALSE;
}
- CurrentThreadBreakpoints = GetThreadBreakpoints(ThreadId);
+ CurrentThreadBreakpoint = GetThreadBreakpoints(ThreadId);
- if (CurrentThreadBreakpoints == NULL)
+ if (CurrentThreadBreakpoint == NULL)
{
- DoOutputDebugString("Creating new thread breakpoints for thread 0x%x.\n", ThreadId);
- CurrentThreadBreakpoints = CreateThreadBreakpoints(ThreadId);
+ DoOutputDebugString("SetThreadBreakpoint: Creating new thread breakpoints for thread %d.\n", ThreadId);
+ CurrentThreadBreakpoint = CreateThreadBreakpoints(ThreadId);
}
- if (CurrentThreadBreakpoints == NULL)
+ if (CurrentThreadBreakpoint == NULL)
{
- DoOutputDebugString("Cannot create new thread breakpoints - FATAL.\n");
+ DoOutputDebugString("SetThreadBreakpoint: Cannot create new thread breakpoints - error.\n");
return FALSE;
}
- pBreakpointInfo = &CurrentThreadBreakpoints->BreakpointInfo[Register];
+ pBreakpointInfo = &CurrentThreadBreakpoint->BreakpointInfo[Register];
- if (CurrentThreadBreakpoints->ThreadHandle == NULL)
+ if (CurrentThreadBreakpoint->ThreadHandle == NULL)
{
- DoOutputDebugString("SetHardwareBreakpoint: There is no thread handle in the threadbreakpoint!! FATAL ERROR.\n");
+ DoOutputDebugString("SetThreadBreakpoint: There is no thread handle in the thread breakpoint - Error.\n");
return FALSE;
}
- pBreakpointInfo->ThreadHandle = CurrentThreadBreakpoints->ThreadHandle;
- pBreakpointInfo->Register = Register;
- pBreakpointInfo->Size = Size;
- pBreakpointInfo->Address = Address;
- pBreakpointInfo->Type = Type;
- pBreakpointInfo->Callback = Callback;
-
- OriginalExceptionHandler = SetUnhandledExceptionFilter(CAPEExceptionFilter);
- //AddVectoredContinueHandler(1, CAPEExceptionFilter);
-
- DoOutputDebugString("SetHardwareBreakpoint: about to call SetBreakpointThread\n");
+ pBreakpointInfo->ThreadHandle = CurrentThreadBreakpoint->ThreadHandle;
+ pBreakpointInfo->Register = Register;
+ pBreakpointInfo->Size = Size;
+ pBreakpointInfo->Address = Address;
+ pBreakpointInfo->Type = Type;
+ pBreakpointInfo->Callback = Callback;
+
+ if (VECTORED_HANDLER)
+ {
+ CAPEExceptionFilterHandle = AddVectoredExceptionHandler(1, CAPEExceptionFilter);
+ OriginalExceptionHandler = NULL;
+ }
+ else
+ {
+ OriginalExceptionHandler = SetUnhandledExceptionFilter(CAPEExceptionFilter);
+ CAPEExceptionFilterHandle = NULL;
+ }
+
+ __try
+ {
+ hSetBreakpointThread = CreateThread(NULL, 0, SetBreakpointThread, pBreakpointInfo, 0, &SetBreakpointThreadId);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DoOutputErrorString("SetThreadBreakpoint: An exception was raised creating SetBreakpointThread thread");
+ }
+
+ if (!hSetBreakpointThread)
+ {
+ DoOutputDebugString("SetThreadBreakpoint: Failed to create SetBreakpointThread thread, falling back to SetBreakpointWithoutThread.\n");
+
+ __try
+ {
+ RetVal = SetBreakpointWithoutThread(ThreadId, Register, Size, Address, Type, Callback);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DoOutputErrorString("SetThreadBreakpoint: Error calling SetBreakpointWithoutThread");
+ return FALSE;
+ }
+
+ return RetVal;
+ }
+
+ // We wait for the thread to complete - if this hasn't happened
+ // in under a second, we bail and set without creating a thread
+ RetVal = WaitForSingleObject(hSetBreakpointThread, 1000);
+
+ if (RetVal != WAIT_OBJECT_0)
+ {
+ TerminateThread(hSetBreakpointThread, 0);
+ DoOutputDebugString("SetThreadBreakpoint: SetBreakpointThread timeout, thread killed.\n");
+
+ RetVal = ResumeThread(CurrentThreadBreakpoint->ThreadHandle);
+ if (RetVal == -1)
+ {
+ DoOutputErrorString("SetThreadBreakpoint: ResumeThread failed. About to set breakpoint without thread.\n");
+ }
+ else if (RetVal == 0)
+ {
+ DoOutputDebugString("SetThreadBreakpoint: Sample thread was not suspended. About to set breakpoint without thread.\n");
+ }
+ else
+ {
+ DoOutputDebugString("SetThreadBreakpoint: Sample thread was suspended, now resumed. About to set breakpoint without thread.\n");
+ }
+
+ return SetBreakpointWithoutThread(ThreadId, Register, Size, Address, Type, Callback);
+ }
+
+ DoOutputDebugString("SetThreadBreakpoint: Set bp %d thread id %d type %d at address 0x%p, size %d with Callback 0x%x.\n",
+ Register,
+ ThreadId,
+ Type,
+ Address,
+ Size,
+ Callback
+ );
+
+ CloseHandle(hSetBreakpointThread);
+
+ return TRUE;
+}
- hSetBreakpointThread = CreateThread(
- NULL,
- 0,
- SetBreakpointThread,
- pBreakpointInfo,
- 0,
- &ThreadId);
+//**************************************************************************************
+BOOL SetBreakpoint
+//**************************************************************************************
+(
+ int Register,
+ int Size,
+ LPVOID Address,
+ DWORD Type,
+ PVOID Callback
+)
+{
+ if (MainThreadBreakpointList == NULL)
+ {
+ DoOutputDebugString("SetBreakpoint: MainThreadBreakpointList NULL.\n");
+ return FALSE;
+ }
+
+ PTHREADBREAKPOINTS ThreadBreakpoints = MainThreadBreakpointList;
- if (hSetBreakpointThread == NULL)
+ while (ThreadBreakpoints)
{
- DoOutputDebugString("Failed to create SetBreakpointThread thread\n");
- return 0;
+ if (ThreadBreakpoints->ThreadHandle)
+ ThreadBreakpoints->BreakpointInfo[Register].ThreadHandle = ThreadBreakpoints->ThreadHandle;
+ ThreadBreakpoints->BreakpointInfo[Register].Register = Register;
+ ThreadBreakpoints->BreakpointInfo[Register].Size = Size;
+ ThreadBreakpoints->BreakpointInfo[Register].Address = Address;
+ ThreadBreakpoints->BreakpointInfo[Register].Type = Type;
+ ThreadBreakpoints->BreakpointInfo[Register].Callback = Callback;
+
+ DoOutputDebugString("SetBreakpoint: About to call SetThreadBreakpoint for thread %d.\n", ThreadBreakpoints->ThreadId);
+
+ SetThreadBreakpoint(ThreadBreakpoints->ThreadId, Register, Size, Address, Type, Callback);
+
+ ThreadBreakpoints = ThreadBreakpoints->NextThreadBreakpoints;
}
- DoOutputDebugString("SetHardwareBreakpoint: SetBreakpointThread called, beginning wait\n");
+
+ return TRUE;
+}
- // Wait until thread has terminated
- WaitForSingleObject(hSetBreakpointThread, INFINITE);
+//**************************************************************************************
+BOOL SetThreadBreakpoints(PTHREADBREAKPOINTS ThreadBreakpoints)
+//**************************************************************************************
+{
+ if (!ThreadBreakpoints->ThreadId)
+ {
+ DoOutputErrorString("SetThreadBreakpoints: Error - Thread ID missing from ThreadBreakpoints.\n");
+ return FALSE;
+ }
- CloseHandle(hSetBreakpointThread);
-
- DoOutputDebugString("SetHardwareBreakpoint: Callback = 0x%x, Address = 0x%x, Size = 0x%x, Register = %i, ThreadHandle = 0x%x, Type = 0x%x\n",
- pBreakpointInfo->Callback,
- pBreakpointInfo->Address,
- pBreakpointInfo->Size,
- pBreakpointInfo->Register,
- pBreakpointInfo->ThreadHandle,
- pBreakpointInfo->Type);
-
- return 1;
+ for (unsigned int Register = 0; Register < NUMBER_OF_DEBUG_REGISTERS; Register++)
+ {
+ if (!SetThreadBreakpoint
+ (
+ ThreadBreakpoints->ThreadId,
+ ThreadBreakpoints->BreakpointInfo[Register].Register,
+ ThreadBreakpoints->BreakpointInfo[Register].Size,
+ ThreadBreakpoints->BreakpointInfo[Register].Address,
+ ThreadBreakpoints->BreakpointInfo[Register].Type,
+ ThreadBreakpoints->BreakpointInfo[Register].Callback
+ ))
+ return FALSE;
+ }
+
+ return TRUE;
}
//**************************************************************************************
-BOOL ClearHardwareBreakpoint
+BOOL ClearBreakpoint(DWORD ThreadId, int Register)
//**************************************************************************************
-(
- DWORD ThreadId,
- int Register
-)
{
PBREAKPOINTINFO pBreakpointInfo;
- PTHREADBREAKPOINTS CurrentThreadBreakpoints;
- HANDLE hClearBreakpointThread;
-
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint;
+
if (Register > 3 || Register < 0)
{
- DoOutputDebugString("ClearHardwareBreakpoint: Error - register value %d, can only have value 0-3.\n", Register);
+ DoOutputDebugString("ClearBreakpoint: Error - register value %d, can only have value 0-3.\n", Register);
return FALSE;
}
-
- CurrentThreadBreakpoints = GetThreadBreakpoints(ThreadId);
- if (CurrentThreadBreakpoints == NULL)
+ CurrentThreadBreakpoint = GetThreadBreakpoints(ThreadId);
+
+ if (CurrentThreadBreakpoint == NULL)
{
- DoOutputDebugString("Cannot find thread breakpoints - failed to clear.\n");
- return FALSE;
+ DoOutputDebugString("ClearBreakpoint: Creating new thread breakpoints for thread %d.\n", ThreadId);
+ CurrentThreadBreakpoint = CreateThreadBreakpoints(ThreadId);
}
-
- pBreakpointInfo = &CurrentThreadBreakpoints->BreakpointInfo[Register];
- if (CurrentThreadBreakpoints->ThreadHandle == NULL)
+ if (CurrentThreadBreakpoint == NULL)
{
- DoOutputDebugString("ClearHardwareBreakpoint: There is no thread handle in the threadbreakpoint!! FATAL ERROR.\n");
+ DoOutputDebugString("ClearBreakpoint: Cannot create new thread breakpoints - FATAL.\n");
return FALSE;
}
- else DoOutputDebugString("ClearHardwareBreakpoint: Thread handle 0x%x found in BreakpointInfo struct.\n", CurrentThreadBreakpoints->ThreadHandle);
-
- DoOutputDebugString("About to create ClearBreakpointThread thread\n");
-
- pBreakpointInfo->ThreadHandle = CurrentThreadBreakpoints->ThreadHandle;
+
+ pBreakpointInfo = &CurrentThreadBreakpoint->BreakpointInfo[Register];
- hClearBreakpointThread = CreateThread(NULL, 0, ClearBreakpointThread, pBreakpointInfo, 0, &ThreadId);
-
- if (hClearBreakpointThread == NULL)
+ if (CurrentThreadBreakpoint->ThreadHandle == NULL)
{
- DoOutputDebugString("Failed to create ClearBreakpointThread thread\n");
- return 0;
+ DoOutputDebugString("ClearBreakpoint: There is no thread handle in the thread breakpoint - Error.\n");
+ return FALSE;
}
- DoOutputDebugString("Successfully created ClearBreakpointThread thread\n");
-
- // Wait until thread has terminated.
- WaitForSingleObject(hClearBreakpointThread, INFINITE);
+ if (!ClearDebugRegister(pBreakpointInfo->ThreadHandle, pBreakpointInfo->Register, pBreakpointInfo->Size, pBreakpointInfo->Address, pBreakpointInfo->Type))
+ {
+ DoOutputDebugString("ClearBreakpoint: Call to ClearDebugRegister failed.\n");
+ return FALSE;
+ }
- // Close thread handle and free memory allocations.
- pBreakpointInfo->Register = 0;
+ //pBreakpointInfo->Register = 0;
pBreakpointInfo->Size = 0;
pBreakpointInfo->Address = 0;
pBreakpointInfo->Type = 0;
pBreakpointInfo->Callback = NULL;
- CheckDebugRegisters(pBreakpointInfo->ThreadHandle, 0);
+ return TRUE;
+}
+
+//**************************************************************************************
+BOOL SetNextAvailableBreakpoint
+//**************************************************************************************
+(
+ DWORD ThreadId,
+ unsigned int* Register,
+ int Size,
+ LPVOID Address,
+ DWORD Type,
+ PVOID Callback
+)
+{
+ PTHREADBREAKPOINTS CurrentThreadBreakpoint = GetThreadBreakpoints(ThreadId);
+
+ if (CurrentThreadBreakpoint == NULL)
+ {
+ DoOutputDebugString("SetNextAvailableBreakpoint: Creating new thread breakpoints for thread %d.\n", ThreadId);
+ CurrentThreadBreakpoint = CreateThreadBreakpoints(ThreadId);
+ }
- return 1;
+ if (CurrentThreadBreakpoint == NULL)
+ {
+ DoOutputDebugString("SetNextAvailableBreakpoint: Cannot create new thread breakpoints - FATAL.\n");
+ return FALSE;
+ }
+
+ if (!GetNextAvailableBreakpoint(ThreadId, Register))
+ {
+ DoOutputDebugString("SetNextAvailableBreakpoint: GetNextAvailableBreakpoint failed (breakpoints possibly full).\n");
+ return FALSE;
+ }
+
+ return SetThreadBreakpoint(ThreadId, *Register, Size, Address, Type, Callback);
}
//**************************************************************************************
@@ -1152,7 +2766,7 @@ BOOL InitialiseDebugger(void)
if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &MainThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS) == 0)
{
- DoOutputDebugString("Failed to duplicate thread handle.\n");
+ DoOutputDebugString("InitialiseDebugger: Failed to duplicate thread handle.\n");
return FALSE;
}
@@ -1160,7 +2774,7 @@ BOOL InitialiseDebugger(void)
if (MainThreadBreakpointList == NULL)
{
- DoOutputDebugString("Failed to create thread breakpoints struct.\n");
+ DoOutputDebugString("InitialiseDebugger: Failed to create thread breakpoints struct.\n");
return FALSE;
}
@@ -1170,20 +2784,57 @@ BOOL InitialiseDebugger(void)
return FALSE;
}
- // Initialise any global variables
-
+ // Initialise global variables
+ ChildProcessId = 0;
+ SingleStepHandler = NULL;
+ SampleVectoredHandler = NULL;
+ VECTORED_HANDLER = TRUE;
+
+#ifndef _WIN64
// Ensure wow64 patch is installed if needed
WoW64fix();
+#endif
+
+ // Set up handler to catch breakpoint exceptions
+ if (VECTORED_HANDLER)
+ {
+ CAPEExceptionFilterHandle = AddVectoredExceptionHandler(1, CAPEExceptionFilter);
+ OriginalExceptionHandler = NULL;
+ }
+ else // deprecated alternative via unhandled exception filter
+ {
+ OriginalExceptionHandler = SetUnhandledExceptionFilter(CAPEExceptionFilter);
+ CAPEExceptionFilterHandle = NULL;
+ }
+
+ // Global switch for guard pages
+ GuardPagesDisabled = TRUE;
return TRUE;
}
+//**************************************************************************************
+DWORD_PTR GetNestedStackPointer(void)
+//**************************************************************************************
+{
+ CONTEXT context;
+
+ RtlCaptureContext(&context);
+
+#ifdef _WIN64
+ return (DWORD_PTR)context.Rsp;
+#else
+ return (DWORD_PTR)context.Esp;
+#endif
+}
+
+#ifndef _WIN64
//**************************************************************************************
__declspec (naked dllexport) void DebuggerInit(void)
//**************************************************************************************
{
DWORD StackPointer;
-
+
_asm
{
push ebp
@@ -1194,13 +2845,12 @@ __declspec (naked dllexport) void DebuggerInit(void)
pushad
}
- InitialiseDebugger();
+ if (!InitialiseDebugger())
+ DoOutputDebugString("Debugger initialisation failure!\n");
-// Target specific code
-
-// End of target specific code
-
- DoOutputDebugString("Debugger initialised, about to execute OEP.\n");
+// Package specific code
+// End of package specific code
+ DoOutputDebugString("Debugger initialisation complete, about to execute OEP at 0x%p\n", OEP);
_asm
{
@@ -1209,132 +2859,64 @@ __declspec (naked dllexport) void DebuggerInit(void)
pop ebp
jmp OEP
}
-
}
-
+#else
+#pragma optimize("", off)
//**************************************************************************************
-DWORD WINAPI DebuggerThread(LPVOID lpParam)
+__declspec(dllexport) void DebuggerInit(void)
//**************************************************************************************
-{
- HANDLE hPipe;
- BOOL fSuccess = FALSE, NT5;
- DWORD cbRead, cbToWrite, cbWritten, dwMode;
- PVOID FuncAddress;
+{
+ DWORD_PTR StackPointer;
- char lpszPipename[MAX_PATH];
- OSVERSIONINFO VersionInfo;
+ StackPointer = GetNestedStackPointer() - 8; // this offset has been determined experimentally - TODO: tidy
- DoOutputDebugString("DebuggerThread: About to connect to CAPEpipe.\n");
-
- memset(lpszPipename, 0, MAX_PATH*sizeof(CHAR));
- sprintf_s(lpszPipename, MAX_PATH, "\\\\.\\pipe\\CAPEpipe_%x", GetCurrentProcessId());
- while (1)
- {
- hPipe = CreateFile(
- lpszPipename,
- GENERIC_READ |
- GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL);
+ if (!InitialiseDebugger())
+ DoOutputDebugString("Debugger initialisation failure!\n");
+ else
+ DoOutputDebugString("Debugger initialised, ESP = 0x%x\n", StackPointer);
+
+// Package specific code
+// End of package specific code
- if (hPipe != INVALID_HANDLE_VALUE)
- break;
+ DoOutputDebugString("Debugger initialisation complete, about to execute OEP.\n");
- if (GetLastError() != ERROR_PIPE_BUSY)
- {
- DoOutputErrorString("Could not open pipe");
- return -1;
- }
+ OEP();
+}
+#pragma optimize("", on)
+#endif
- if (!WaitNamedPipe(lpszPipename, 20))
- {
- DoOutputDebugString("Could not open pipe: 20 ms wait timed out.\n");
- return -1;
- }
- }
+BOOL SendDebuggerMessage(PVOID Input)
+{
+ BOOL fSuccess;
+ DWORD cbReplyBytes, cbWritten;
- // The pipe connected; change to message-read mode.
- dwMode = PIPE_READMODE_MESSAGE;
- fSuccess = SetNamedPipeHandleState
- (
- hPipe,
- &dwMode,
- NULL,
- NULL
- );
- if (!fSuccess)
- {
- DoOutputDebugString("SetNamedPipeHandleState failed.\n");
- return -1;
- }
+ cbReplyBytes = sizeof(PVOID);
+
+ if (hCapePipe == NULL)
+ {
+ DoOutputErrorString("SendDebuggerMessage: hCapePipe NULL.");
+ return FALSE;
+ }
- // Send VA of DebuggerInit to loader
- FuncAddress = &DebuggerInit;
-
- cbToWrite = sizeof(PVOID);
-
- fSuccess = WriteFile
- (
- hPipe,
- &FuncAddress,
- cbToWrite,
- &cbWritten,
- NULL
+ // Write the reply to the pipe.
+ fSuccess = WriteFile
+ (
+ hCapePipe, // handle to pipe
+ &Input, // buffer to write from
+ cbReplyBytes, // number of bytes to write
+ &cbWritten, // number of bytes written
+ NULL // not overlapped I/O
);
- if (!fSuccess)
- {
- DoOutputErrorString("WriteFile to pipe failed");
- return -1;
- }
-
- DoOutputDebugString("DebuggerInit VA sent to loader: 0x%x\n", FuncAddress);
-
- fSuccess = ReadFile(
- hPipe,
- &OEP,
- sizeof(DWORD),
- &cbRead,
- NULL);
-
- if (!fSuccess && GetLastError() == ERROR_MORE_DATA)
- {
- DoOutputDebugString("ReadFile on Pipe: ERROR_MORE_DATA\n");
- CloseHandle(hPipe);
- return -1;
- }
-
- if (!fSuccess)
- {
- DoOutputErrorString("ReadFile from pipe failed");
- CloseHandle(hPipe);
- return -1;
- }
-
- DoOutputDebugString("Read OEP from pipe: 0x%x\n", OEP);
-
- //CloseHandle(hPipe);
-
- ZeroMemory(&VersionInfo, sizeof(OSVERSIONINFO));
- VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx(&VersionInfo);
- NT5 = (VersionInfo.dwMajorVersion == 5);
-
- if (NT5)
- {
- DoOutputDebugString("NT5: Leaving debugger thread alive.\n");
- while(1)
- {
- Sleep(500000);
- }
+ if (!fSuccess || cbReplyBytes != cbWritten)
+ {
+ DoOutputErrorString("SendDebuggerMessage: Failed to send message via pipe");
+ return FALSE;
}
- DoOutputDebugString("NT6+: Terminating debugger thread.\n");
+ DoOutputDebugString("SendDebuggerMessage: Sent message via pipe: 0x%x\n", Input);
- return 0;
+ return TRUE;
}
//**************************************************************************************
@@ -1348,23 +2930,24 @@ BOOL DebugNewProcess(unsigned int ProcessId, unsigned int ThreadId, DWORD Creati
DWORD cbBytesRead, cbWritten, cbReplyBytes;
memset(lpszPipename, 0, MAX_PATH*sizeof(CHAR));
+
sprintf_s(lpszPipename, MAX_PATH, "\\\\.\\pipe\\CAPEpipe_%x", ProcessId);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, ProcessId);
if (hProcess == NULL)
{
- DoOutputErrorString("CAPE debug pipe: OpenProcess failed");
+ DoOutputErrorString("DebugNewProcess: OpenProcess failed");
return FALSE;
}
hThread = OpenThread(THREAD_ALL_ACCESS, TRUE, ThreadId);
if (hThread == NULL)
{
- DoOutputErrorString("CAPE debug pipe: OpenThread failed");
+ DoOutputErrorString("DebugNewProcess: OpenThread failed");
return FALSE;
}
- hParentPipe = CreateNamedPipe
+ hCapePipe = CreateNamedPipe
(
lpszPipename,
PIPE_ACCESS_DUPLEX,
@@ -1378,38 +2961,33 @@ BOOL DebugNewProcess(unsigned int ProcessId, unsigned int ThreadId, DWORD Creati
NULL
);
- if (hParentPipe == INVALID_HANDLE_VALUE)
+ if (hCapePipe == INVALID_HANDLE_VALUE)
{
- DoOutputErrorString("CreateNamedPipe failed");
+ DoOutputErrorString("DebugNewProcess: CreateNamedPipe failed");
return FALSE;
}
-#ifndef STANDALONE
- //pipe("PROCESS:%d:%d,%d", 0, ProcessId, 0); // we need CreateRemoteThread injection
- pipe("PROCESS:%d:%d,%d", (CreationFlags & CREATE_SUSPENDED) ? 1 : 0, ProcessId, ThreadId);
- DoOutputDebugString("DebugNewProcess: Announcing new process to Cuckoo.\n");
-#endif
+ DoOutputDebugString("DebugNewProcess: Announcing new process to Cuckoo, pid: %d\n", ProcessId);
+ pipe("DEBUGGER:%d,%d", ProcessId, ThreadId);
- fConnected = ConnectNamedPipe(hParentPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
+ fConnected = ConnectNamedPipe(hCapePipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
fSuccess = FALSE;
cbBytesRead = 0;
if (!fConnected)
{
- DoOutputDebugString("The client could not connect, closing pipe.\n");
-
- CloseHandle(hParentPipe);
-
- return -15;
+ DoOutputDebugString("DebugNewProcess: The client could not connect, closing pipe.\n");
+ CloseHandle(hCapePipe);
+ return FALSE;
}
- DoOutputDebugString("Client connected\n");
+ DoOutputDebugString("DebugNewProcess: Client connected.\n");
fSuccess = ReadFile
(
- hParentPipe,
- &RemoteFuncAddress,
- sizeof(DWORD),
+ hCapePipe,
+ &DebuggerEP,
+ sizeof(DWORD_PTR),
&cbBytesRead,
NULL
);
@@ -1418,36 +2996,40 @@ BOOL DebugNewProcess(unsigned int ProcessId, unsigned int ThreadId, DWORD Creati
{
if (GetLastError() == ERROR_BROKEN_PIPE)
{
- DoOutputErrorString("Client disconnected.");
+ DoOutputErrorString("DebugNewProcess: Client disconnected.");
}
else
{
- DoOutputErrorString("ReadFile failed.");
+ DoOutputErrorString("DebugNewProcess: ReadFile failed.");
}
}
- if (!RemoteFuncAddress)
+ if (!DebuggerEP)
{
- DoOutputErrorString("Successfully read from pipe, however RemoteFuncAddress = 0.");
+ DoOutputErrorString("DebugNewProcess: Successfully read from pipe, however DebuggerEP = 0.");
return FALSE;
}
Context.ContextFlags = CONTEXT_ALL;
if (!GetThreadContext(hThread, &Context))
{
- DoOutputDebugString("GetThreadContext failed - FATAL\n");
+ DoOutputDebugString("DebugNewProcess: GetThreadContext failed - FATAL\n");
return FALSE;
}
+#ifdef _WIN64
+ OEP = (PVOID)Context.Rcx;
+#else
OEP = (PVOID)Context.Eax;
+#endif
cbWritten = 0;
- cbReplyBytes = sizeof(DWORD);
+ cbReplyBytes = sizeof(DWORD_PTR);
- // Write the reply to the pipe.
+ // Send the OEP to the new process
fSuccess = WriteFile
(
- hParentPipe,
+ hCapePipe,
&OEP,
cbReplyBytes,
&cbWritten,
@@ -1455,25 +3037,32 @@ BOOL DebugNewProcess(unsigned int ProcessId, unsigned int ThreadId, DWORD Creati
);
if (!fSuccess || cbReplyBytes != cbWritten)
{
- DoOutputErrorString("Failed to send OEP via pipe.");
+ DoOutputErrorString("DebugNewProcess: Failed to send OEP via pipe.");
return FALSE;
}
- DoOutputDebugString("DebugNewProcess: Sent OEP 0x%x via pipe\n", OEP);
+ DoOutputDebugString("DebugNewProcess: Sent OEP 0x%p via pipe\n", OEP);
Context.ContextFlags = CONTEXT_ALL;
- Context.Eax = RemoteFuncAddress; // eax holds new entry point
+#ifdef _WIN64
+ Context.Rcx = DebuggerEP; // set the new EP to debugger_init
+#else
+ Context.Eax = DebuggerEP;
+#endif
if (!SetThreadContext(hThread, &Context))
{
- DoOutputDebugString("Failed to set new EP\n");
+ DoOutputDebugString("DebugNewProcess: Failed to set new EP\n");
return FALSE;
}
- DoOutputDebugString("Set new EP to DebuggerInit: 0x%x\n", Context.Eax);
+#ifdef _WIN64
+ DoOutputDebugString("DebugNewProcess: Set new EP to DebuggerInit: 0x%x\n", Context.Rcx);
+#else
+ DoOutputDebugString("DebugNewProcess: Set new EP to DebuggerInit: 0x%x\n", Context.Eax);
+#endif
- //CloseHandle(hParentPipe);
CloseHandle(hProcess);
CloseHandle(hThread);
@@ -1481,34 +3070,196 @@ BOOL DebugNewProcess(unsigned int ProcessId, unsigned int ThreadId, DWORD Creati
}
//**************************************************************************************
-int launch_debugger()
+DWORD WINAPI DebuggerLaunch(LPVOID lpParam)
//**************************************************************************************
-{
- DWORD NewThreadId;
- HANDLE hDebuggerThread;
+{
+ HANDLE hPipe;
+ BOOL fSuccess = FALSE, NT5;
+ DWORD cbRead, cbToWrite, cbWritten, dwMode;
+ PVOID FuncAddress;
+
+ char lpszPipename[MAX_PATH];
+ OSVERSIONINFO VersionInfo;
+
+ DoOutputDebugString("DebuggerLaunch: About to connect to CAPEpipe.\n");
+
+ memset(lpszPipename, 0, MAX_PATH*sizeof(CHAR));
+
+ sprintf_s(lpszPipename, MAX_PATH, "\\\\.\\pipe\\CAPEpipe_%x", GetCurrentProcessId());
+
+ while (1)
+ {
+ hPipe = CreateFile(
+ lpszPipename,
+ GENERIC_READ |
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+
+ if (hPipe != INVALID_HANDLE_VALUE)
+ break;
+
+ if (GetLastError() != ERROR_PIPE_BUSY)
+ {
+ DoOutputErrorString("DebuggerLaunch: Could not open pipe");
+ return -1;
+ }
+
+ if (!WaitNamedPipe(lpszPipename, 20))
+ {
+ DoOutputDebugString("DebuggerLaunch: Could not open pipe: 20 ms wait timed out.\n");
+ return -1;
+ }
+ }
+
+ // The pipe connected; change to message-read mode.
+ dwMode = PIPE_READMODE_MESSAGE;
+ fSuccess = SetNamedPipeHandleState
+ (
+ hPipe,
+ &dwMode,
+ NULL,
+ NULL
+ );
+ if (!fSuccess)
+ {
+ DoOutputDebugString("DebuggerLaunch: SetNamedPipeHandleState failed.\n");
+ return -1;
+ }
+
+ // Send VA of DebuggerInit to loader
+ FuncAddress = &DebuggerInit;
+
+ cbToWrite = sizeof(PVOID);
+
+ fSuccess = WriteFile
+ (
+ hPipe,
+ &FuncAddress,
+ cbToWrite,
+ &cbWritten,
+ NULL
+ );
+ if (!fSuccess)
+ {
+ DoOutputErrorString("DebuggerLaunch: WriteFile to pipe failed");
+ return -1;
+ }
- DoOutputDebugString("CAPE: Launching debugger.\n");
+ DoOutputDebugString("DebuggerLaunch: DebuggerInit VA sent to loader: 0x%x\n", FuncAddress);
- hDebuggerThread = CreateThread(
- NULL,
- 0,
- DebuggerThread,
- NULL,
- 0,
- &NewThreadId);
+ fSuccess = ReadFile(
+ hPipe,
+ &OEP,
+ sizeof(DWORD_PTR),
+ &cbRead,
+ NULL);
+
+ if (!fSuccess && GetLastError() == ERROR_MORE_DATA)
+ {
+ DoOutputDebugString("DebuggerLaunch: ReadFile on Pipe: ERROR_MORE_DATA\n");
+ CloseHandle(hPipe);
+ return -1;
+ }
+
+ if (!fSuccess)
+ {
+ DoOutputErrorString("DebuggerLaunch: ReadFile (OEP) from pipe failed");
+ CloseHandle(hPipe);
+ return -1;
+ }
- if (hDebuggerThread == NULL)
+ DoOutputDebugString("DebuggerLaunch: Read OEP from pipe: 0x%p\n", OEP);
+
+ while (1)
{
- DoOutputDebugString("CAPE: Failed to create debug pipe thread.\n");
- return 0;
+ fSuccess = ReadFile(
+ hPipe,
+ &OEP,
+ sizeof(DWORD_PTR),
+ &cbRead,
+ NULL);
+
+ if (!fSuccess && GetLastError() == ERROR_BROKEN_PIPE)
+ {
+ DoOutputDebugString("DebuggerLaunch: Pipe closed, no further updates to OEP\n");
+ CloseHandle(hPipe);
+ break;
+ }
+
+ if (!fSuccess && GetLastError() == ERROR_MORE_DATA)
+ {
+ DoOutputDebugString("DebuggerLaunch: ReadFile on Pipe: ERROR_MORE_DATA\n");
+ CloseHandle(hPipe);
+ return -1;
+ }
+
+ if (!fSuccess)
+ {
+ DoOutputErrorString("DebuggerLaunch: ReadFile from pipe failed");
+ CloseHandle(hPipe);
+ return -1;
+ }
+ else
+ DoOutputDebugString("DebuggerLaunch: Read updated EP from pipe: 0x%p\n", OEP);
}
- else
+
+ ZeroMemory(&VersionInfo, sizeof(OSVERSIONINFO));
+ VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&VersionInfo);
+
+ NT5 = (VersionInfo.dwMajorVersion == 5);
+
+ if (NT5)
{
- DoOutputDebugString("CAPE: Successfully created debug pipe thread.\n");
+ DoOutputDebugString("NT5: Leaving debugger thread alive.\n");
+ while (1)
+ {
+ Sleep(500000);
+ }
}
- CloseHandle(hDebuggerThread);
+ DoOutputDebugString("NT6+: Terminating debugger thread.\n");
- return 1;
+ return 0;
}
-#endif
\ No newline at end of file
+
+//**************************************************************************************
+int launch_debugger()
+//**************************************************************************************
+{
+ if (DEBUGGER_LAUNCHER)
+ {
+ DWORD NewThreadId;
+ HANDLE hDebuggerLaunch;
+
+ hDebuggerLaunch = CreateThread(
+ NULL,
+ 0,
+ DebuggerLaunch,
+ NULL,
+ 0,
+ &NewThreadId);
+
+ if (hDebuggerLaunch == NULL)
+ {
+ DoOutputDebugString("CAPE: Failed to create debugger launch thread.\n");
+ return 0;
+ }
+
+ DoOutputDebugString("CAPE: Launching debugger.\n");
+
+ CloseHandle(hDebuggerLaunch);
+
+ return 1;
+ }
+ else
+ {
+ DebuggerInitialised = InitialiseDebugger();
+
+ return DebuggerInitialised;
+ }
+}
\ No newline at end of file
diff --git a/CAPE/Debugger.h b/CAPE/Debugger.h
index d089e41..88f43fc 100644
--- a/CAPE/Debugger.h
+++ b/CAPE/Debugger.h
@@ -1,10 +1,33 @@
#pragma once
+#pragma once
+
+#define DEBUGGER_LAUNCHER 0
+#define DisableThreadSuspend 0
#define BP_EXEC 0x00
#define BP_WRITE 0x01
#define BP_RESERVED 0x02
#define BP_READWRITE 0x03
+#define NUMBER_OF_DEBUG_REGISTERS 4
+#define MAX_DEBUG_REGISTER_DATA_SIZE 4
+#define DEBUG_REGISTER_DATA_SIZES {1, 2, 4}
+#define DEBUG_REGISTER_LENGTH_MASKS {0xFFFFFFFF, 0, 1, 0xFFFFFFFF, 3}
+
+#define EXECUTABLE_FLAGS (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
+#define WRITABLE_FLAGS (PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_WRITECOMBINE)
+
+#define EXTRACTION_MIN_SIZE 0x1001
+
+#if (NTDDI_VERSION <= NTDDI_WINBLUE)
+typedef struct _EXCEPTION_REGISTRATION_RECORD {
+ struct _EXCEPTION_REGISTRATION_RECORD *Next;
+ PEXCEPTION_ROUTINE Handler;
+} EXCEPTION_REGISTRATION_RECORD;
+
+typedef EXCEPTION_REGISTRATION_RECORD *PEXCEPTION_REGISTRATION_RECORD;
+#endif
+
typedef struct BreakpointInfo
{
HANDLE ThreadHandle;
@@ -17,7 +40,7 @@ typedef struct BreakpointInfo
typedef BOOL (cdecl *BREAKPOINT_HANDLER)(PBREAKPOINTINFO, struct _EXCEPTION_POINTERS*);
-typedef struct ThreadBreakpoints
+typedef struct ThreadBreakpoints
{
DWORD ThreadId;
HANDLE ThreadHandle;
@@ -25,42 +48,129 @@ typedef struct ThreadBreakpoints
struct ThreadBreakpoints *NextThreadBreakpoints;
} THREADBREAKPOINTS, *PTHREADBREAKPOINTS;
+typedef struct TrackedRegion
+{
+ PVOID BaseAddress;
+ PVOID ProtectAddress;
+ SIZE_T RegionSize;
+ ULONG Protect;
+ MEMORY_BASIC_INFORMATION MemInfo;
+ BOOL Committed;
+ PVOID LastAccessAddress;
+ PVOID LastWriteAddress;
+ PVOID LastReadAddress;
+ BOOL WriteDetected;
+ BOOL ReadDetected;
+ PVOID LastAccessBy;
+ PVOID LastWrittenBy;
+ PVOID LastReadBy;
+ BOOL PagesDumped;
+ BOOL CanDump;
+ BOOL Guarded;
+ unsigned int WriteCounter;
+ // under review
+ BOOL WriteBreakpointSet;
+ BOOL PeImageDetected;
+ BOOL AllocationBaseExecBpSet;
+ BOOL AllocationWriteDetected;
+ //
+ PVOID ExecBp;
+ unsigned int ExecBpRegister;
+ PVOID MagicBp;
+ unsigned int MagicBpRegister;
+ BOOL BreakpointsSet;
+ BOOL BreakpointsSaved;
+ struct ThreadBreakpoints *TrackedRegionBreakpoints;
+ struct TrackedRegion *NextTrackedRegion;
+} TRACKEDREGION, *PTRACKEDREGION;
+
+struct TrackedRegion *TrackedRegionList;
+
typedef BOOL (cdecl *SINGLE_STEP_HANDLER)(struct _EXCEPTION_POINTERS*);
+typedef BOOL (cdecl *GUARD_PAGE_HANDLER)(struct _EXCEPTION_POINTERS*);
+typedef BOOL (cdecl *SAMPLE_HANDLER)(struct _EXCEPTION_POINTERS*);
+
+typedef void (WINAPI *PWIN32ENTRY)();
#ifdef __cplusplus
extern "C" {
#endif
-BOOL SetHardwareBreakpoint
-(
- DWORD ThreadId,
- int Register,
- int Size,
- LPVOID Address,
- DWORD Type,
- PVOID Callback
-);
-
-BOOL ClearHardwareBreakpoint(DWORD ThreadId, int Register);
-
-BOOL SetExceptionHardwareBreakpoint
-(
- PCONTEXT Context,
- int Register,
- int Size,
- LPVOID Address,
- DWORD Type,
- PVOID Callback
-);
-
-BOOL ClearExceptionHardwareBreakpoint(PCONTEXT Context, PBREAKPOINTINFO pBreakpointInfo);
+BOOL DebuggerInitialised;
+
+// Global variables for submission options
+void *CAPE_var1, *CAPE_var2, *CAPE_var3, *CAPE_var4;
+PVOID bp0, bp1, bp2, bp3;
+
+LONG WINAPI CAPEExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo);
+PVOID CAPEExceptionFilterHandle;
+SAMPLE_HANDLER SampleVectoredHandler;
+PEXCEPTION_ROUTINE SEH_TopLevelHandler;
+LPTOP_LEVEL_EXCEPTION_FILTER OriginalExceptionHandler;
+BOOL VECTORED_HANDLER;
+BOOL GuardPagesDisabled;
+
+DWORD ChildProcessId;
+DWORD ChildThreadId;
+DWORD_PTR DebuggerEP;
+PWIN32ENTRY OEP;
+
+int launch_debugger(void);
+
+// Set
+BOOL SetBreakpoint(int Register, int Size, LPVOID Address, DWORD Type, PVOID Callback);
+BOOL SetThreadBreakpoint(DWORD ThreadId, int Register, int Size, LPVOID Address, DWORD Type, PVOID Callback);
+BOOL ContextSetThreadBreakpoint(PCONTEXT Context, int Register, int Size, LPVOID Address, DWORD Type, PVOID Callback);
+BOOL ContextSetDebugRegister(PCONTEXT Context, int Register, int Size, LPVOID Address, DWORD Type);
+BOOL SetThreadBreakpoints(PTHREADBREAKPOINTS ThreadBreakpoints);
+BOOL ContextSetBreakpoint(PTHREADBREAKPOINTS ThreadBreakpoints);
+BOOL ContextUpdateCurrentBreakpoint(PCONTEXT Context, int Size, LPVOID Address, DWORD Type, PVOID Callback);
+BOOL SetNextAvailableBreakpoint(DWORD ThreadId, unsigned int* Register, int Size, LPVOID Address, DWORD Type, PVOID Callback);
BOOL SetSingleStepMode(PCONTEXT Context, PVOID Handler);
-BOOL ClearSingleStepMode(PCONTEXT Context);
-BOOL ClearAllDebugRegisters(HANDLE hThread);
+BOOL SetResumeFlag(PCONTEXT Context);
+BOOL SetZeroFlag(PCONTEXT Context);
+BOOL ClearZeroFlag(PCONTEXT Context);
+PTHREADBREAKPOINTS CreateThreadBreakpoints(DWORD ThreadId);
+
+// Get
+BOOL GetNextAvailableBreakpoint(DWORD ThreadId, unsigned int* Register);
+PTHREADBREAKPOINTS GetThreadBreakpoints(DWORD ThreadId);
+BOOL ContextGetNextAvailableBreakpoint(PCONTEXT Context, unsigned int* Register);
+BOOL ContextSetNextAvailableBreakpoint(PCONTEXT Context, unsigned int* Register, int Size, LPVOID Address, DWORD Type, PVOID Callback);
+int CheckDebugRegister(HANDLE hThread, int Register);
BOOL CheckDebugRegisters(HANDLE hThread, PCONTEXT pContext);
+int ContextCheckDebugRegister(CONTEXT Context, int Register);
+BOOL ContextCheckDebugRegisters(PCONTEXT pContext);
+HANDLE GetThreadHandle(DWORD ThreadId);
+
+// Clear
+BOOL ClearBreakpoint(DWORD ThreadId, int Register);
+BOOL ClearBreakpointsInRange(DWORD ThreadId, PVOID BaseAddress, SIZE_T Size);
+BOOL ContextClearBreakpoint(PCONTEXT Context, PBREAKPOINTINFO pBreakpointInfo);
+BOOL ContextClearCurrentBreakpoint(PCONTEXT Context);
+BOOL ContextClearAllBreakpoints(PCONTEXT Context);
+BOOL ClearAllBreakpoints();
+BOOL ClearSingleStepMode(PCONTEXT Context);
+
+// Misc
+BOOL InitNewThreadBreakpoints(DWORD ThreadId);
BOOL InitialiseDebugger(void);
BOOL DebugNewProcess(unsigned int ProcessId, unsigned int ThreadId, DWORD CreationFlags);
-int launch_debugger(void);
+BOOL SendDebuggerMessage(PVOID Input);
+BOOL StepOverExecutionBreakpoint(PCONTEXT Context, PBREAKPOINTINFO pBreakpointInfo);
+BOOL ResumeAfterExecutionBreakpoint(PCONTEXT Context, PBREAKPOINTINFO pBreakpointInfo);
+
+void ShowStack(DWORD_PTR StackPointer, unsigned int NumberOfRecords);
+
+BOOL IsInTrackedRegions(PVOID Address);
+PTRACKEDREGION CreateTrackedRegions();
+PTRACKEDREGION GetTrackedRegion(PVOID Address);
+PTRACKEDREGION AddTrackedRegion(PVOID Address, SIZE_T RegionSize, ULONG Protect);
+BOOL DropTrackedRegion(PTRACKEDREGION TrackedRegion);
+BOOL ActivateGuardPages(PTRACKEDREGION TrackedRegion);
+BOOL ActivateGuardPagesOnProtectedRange(PTRACKEDREGION TrackedRegion);
+BOOL DeactivateGuardPages(PTRACKEDREGION TrackedRegion);
+BOOL ActivateSurroundingGuardPages(PTRACKEDREGION TrackedRegion);
#ifdef __cplusplus
}
diff --git a/CAPE/GetThreadId.c b/CAPE/GetThreadId.c
index 360a104..727bf75 100644
--- a/CAPE/GetThreadId.c
+++ b/CAPE/GetThreadId.c
@@ -117,5 +117,5 @@ DWORD MyGetThreadId
FreeLibrary(hModule);
- return (DWORD)ThreadBasicInfo.ClientId.UniqueThread;
+ return (DWORD)(UINT_PTR)ThreadBasicInfo.ClientId.UniqueThread;
}
diff --git a/CAPE/Injection.c b/CAPE/Injection.c
new file mode 100644
index 0000000..eb5d991
--- /dev/null
+++ b/CAPE/Injection.c
@@ -0,0 +1,1097 @@
+/*
+CAPE - Config And Payload Extraction
+Copyright(C) 2015 - 2018 Context Information Security. (kevin.oreilly@contextis.com)
+
+This program is free software : you can redistribute it and / or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.If not, see .
+*/
+#include
+#include "..\ntapi.h"
+#include
+#include
+#include "..\misc.h"
+#include "..\hooking.h"
+#include "..\log.h"
+#include "Debugger.h"
+#include "CAPE.h"
+#include "Injection.h"
+
+extern _NtMapViewOfSection pNtMapViewOfSection;
+extern _NtUnmapViewOfSection pNtUnmapViewOfSection;
+
+extern void DoOutputDebugString(_In_ LPCTSTR lpOutputString, ...);
+extern void TestDoOutputDebugString(_In_ LPCTSTR lpOutputString, ...);
+extern void DoOutputErrorString(_In_ LPCTSTR lpOutputString, ...);
+extern PVOID get_process_image_base(HANDLE process_handle);
+
+//**************************************************************************************
+PINJECTIONINFO GetInjectionInfo(DWORD ProcessId)
+//**************************************************************************************
+{
+ DWORD CurrentProcessId;
+
+ PINJECTIONINFO CurrentInjectionInfo = InjectionInfoList;
+ while (CurrentInjectionInfo)
+ {
+ CurrentProcessId = CurrentInjectionInfo->ProcessId;
+
+ if (CurrentProcessId == ProcessId)
+ return CurrentInjectionInfo;
+ else
+ CurrentInjectionInfo = CurrentInjectionInfo->NextInjectionInfo;
+ }
+
+ return NULL;
+}
+
+//**************************************************************************************
+PINJECTIONINFO GetInjectionInfoFromHandle(HANDLE ProcessHandle)
+//**************************************************************************************
+{
+ HANDLE CurrentProcessHandle;
+
+ PINJECTIONINFO CurrentInjectionInfo = InjectionInfoList;
+ while (CurrentInjectionInfo)
+ {
+ CurrentProcessHandle = CurrentInjectionInfo->ProcessHandle;
+
+ if (CurrentProcessHandle == ProcessHandle)
+ return CurrentInjectionInfo;
+ else
+ CurrentInjectionInfo = CurrentInjectionInfo->NextInjectionInfo;
+ }
+
+ return NULL;
+}
+
+//**************************************************************************************
+PINJECTIONINFO CreateInjectionInfo(DWORD ProcessId)
+//**************************************************************************************
+{
+ PINJECTIONINFO CurrentInjectionInfo, PreviousInjectionInfo;
+
+ PreviousInjectionInfo = NULL;
+
+ if (InjectionInfoList == NULL)
+ {
+ InjectionInfoList = ((struct InjectionInfo*)malloc(sizeof(struct InjectionInfo)));
+
+ if (InjectionInfoList == NULL)
+ {
+ DoOutputDebugString("CreateInjectionInfo: failed to allocate memory for initial injection info list.\n");
+ return NULL;
+ }
+
+ memset(InjectionInfoList, 0, sizeof(struct InjectionInfo));
+
+ InjectionInfoList->ProcessId = ProcessId;
+ }
+
+ CurrentInjectionInfo = InjectionInfoList;
+
+ while (CurrentInjectionInfo)
+ {
+ if ((CurrentInjectionInfo->ProcessId) == ProcessId)
+ break;
+
+ PreviousInjectionInfo = CurrentInjectionInfo;
+ CurrentInjectionInfo = CurrentInjectionInfo->NextInjectionInfo;
+ }
+
+ if (!CurrentInjectionInfo)
+ {
+ // We haven't found it in the linked list, so create a new one
+ CurrentInjectionInfo = PreviousInjectionInfo;
+
+ CurrentInjectionInfo->NextInjectionInfo = ((struct InjectionInfo*)malloc(sizeof(struct InjectionInfo)));
+
+ if (CurrentInjectionInfo->NextInjectionInfo == NULL)
+ {
+ DoOutputDebugString("CreateInjectionInfo: Failed to allocate new thread breakpoints.\n");
+ return NULL;
+ }
+
+ memset(CurrentInjectionInfo->NextInjectionInfo, 0, sizeof(struct InjectionInfo));
+
+ CurrentInjectionInfo = CurrentInjectionInfo->NextInjectionInfo;
+
+ CurrentInjectionInfo->ProcessId = ProcessId;
+ }
+
+ return CurrentInjectionInfo;
+}
+
+//**************************************************************************************
+BOOL DropInjectionInfo(HANDLE ProcessHandle)
+//**************************************************************************************
+{
+ HANDLE CurrentProcessHandle;
+ PINJECTIONINFO PreviousInjectionInfo, CurrentInjectionInfo = InjectionInfoList;
+
+ PreviousInjectionInfo = NULL;
+
+ while (CurrentInjectionInfo)
+ {
+ CurrentProcessHandle = CurrentInjectionInfo->ProcessHandle;
+
+ if (CurrentProcessHandle == ProcessHandle)
+ {
+ // Unlink this from the list and free the memory
+ if (PreviousInjectionInfo && CurrentInjectionInfo->NextInjectionInfo)
+ {
+ PreviousInjectionInfo->NextInjectionInfo = CurrentInjectionInfo->NextInjectionInfo;
+ DoOutputDebugString("DropInjectionInfo: removed injection info for pid %d.\n", CurrentInjectionInfo->ProcessId);
+ }
+ else if (PreviousInjectionInfo && CurrentInjectionInfo->NextInjectionInfo == NULL)
+ {
+ PreviousInjectionInfo->NextInjectionInfo = NULL;
+ DoOutputDebugString("DropInjectionInfo: removed injection info for pid %d from the end of the section view list.\n", CurrentInjectionInfo->ProcessId);
+ }
+ else if (!PreviousInjectionInfo)
+ {
+ InjectionInfoList = NULL;
+ DoOutputDebugString("DropInjectionInfo: removed the head of the injection info list for pid %d.\n", CurrentInjectionInfo->ProcessId);
+ }
+
+ free(CurrentInjectionInfo);
+
+ return TRUE;
+ }
+
+ PreviousInjectionInfo = CurrentInjectionInfo;
+ CurrentInjectionInfo = CurrentInjectionInfo->NextInjectionInfo;
+ }
+
+ return FALSE;
+}
+
+//**************************************************************************************
+PINJECTIONSECTIONVIEW GetSectionView(HANDLE SectionHandle)
+//**************************************************************************************
+{
+ PINJECTIONSECTIONVIEW CurrentSectionView = SectionViewList;
+
+ while (CurrentSectionView)
+ {
+ wchar_t *SectionName;
+
+ if (CurrentSectionView->SectionHandle == SectionHandle)
+ return CurrentSectionView;
+
+ SectionName = malloc(MAX_UNICODE_PATH * sizeof(wchar_t));
+
+ if (SectionName)
+ {
+ path_from_handle(SectionHandle, SectionViewList->SectionName, MAX_UNICODE_PATH);
+ if ((!wcscmp(CurrentSectionView->SectionName, SectionName)))
+ {
+ DoOutputDebugString("AddSectionView: New section handle for existing named section %ws.\n", SectionHandle, SectionName);
+ free(SectionName);
+ return CurrentSectionView;
+ }
+ free(SectionName);
+ }
+
+ CurrentSectionView = CurrentSectionView->NextSectionView;
+ }
+
+ return NULL;
+}
+
+//**************************************************************************************
+PINJECTIONSECTIONVIEW AddSectionView(HANDLE SectionHandle, PVOID LocalView, SIZE_T ViewSize)
+//**************************************************************************************
+{
+ PINJECTIONSECTIONVIEW CurrentSectionView, PreviousSectionView;
+
+ PreviousSectionView = NULL;
+
+ if (SectionViewList == NULL)
+ {
+ SectionViewList = ((struct InjectionSectionView*)malloc(sizeof(struct InjectionSectionView)));
+
+ if (SectionViewList == NULL)
+ {
+ DoOutputDebugString("AddSectionView: failed to allocate memory for initial section view list.\n");
+ return NULL;
+ }
+
+ memset(SectionViewList, 0, sizeof(struct InjectionSectionView));
+
+ SectionViewList->SectionHandle = SectionHandle;
+ SectionViewList->LocalView = LocalView;
+ SectionViewList->ViewSize = ViewSize;
+ SectionViewList->SectionName = malloc(MAX_UNICODE_PATH * sizeof(wchar_t));
+ if (SectionViewList->SectionName)
+ path_from_handle(SectionHandle, SectionViewList->SectionName, MAX_UNICODE_PATH);
+ }
+
+ CurrentSectionView = SectionViewList;
+
+ while (CurrentSectionView)
+ {
+ wchar_t *SectionName;
+
+ if ((CurrentSectionView->SectionHandle) == SectionHandle)
+ break;
+
+ SectionName = malloc(MAX_UNICODE_PATH * sizeof(wchar_t));
+ if (SectionName)
+ {
+ path_from_handle(SectionHandle, SectionViewList->SectionName, MAX_UNICODE_PATH);
+ if ((!wcscmp(CurrentSectionView->SectionName, SectionName)))
+ {
+ DoOutputDebugString("AddSectionView: New section handle for existing named section %ws.\n", SectionHandle, SectionName);
+ free(SectionName);
+ break;
+ }
+ free(SectionName);
+ }
+
+ PreviousSectionView = CurrentSectionView;
+ CurrentSectionView = CurrentSectionView->NextSectionView;
+ }
+
+ if (!CurrentSectionView)
+ {
+ // We haven't found it in the linked list, so create a new one
+ CurrentSectionView = PreviousSectionView;
+
+ CurrentSectionView->NextSectionView = ((struct InjectionSectionView*)malloc(sizeof(struct InjectionSectionView)));
+
+ if (CurrentSectionView->NextSectionView == NULL)
+ {
+ DoOutputDebugString("CreateSectionView: Failed to allocate new injection sectionview structure.\n");
+ return NULL;
+ }
+
+ memset(CurrentSectionView->NextSectionView, 0, sizeof(struct InjectionSectionView));
+
+ CurrentSectionView = CurrentSectionView->NextSectionView;
+ CurrentSectionView->SectionHandle = SectionHandle;
+ CurrentSectionView->LocalView = LocalView;
+ CurrentSectionView->ViewSize = ViewSize;
+ CurrentSectionView->SectionName = malloc(MAX_UNICODE_PATH * sizeof(wchar_t));
+ path_from_handle(SectionHandle, CurrentSectionView->SectionName, MAX_UNICODE_PATH);
+ }
+
+ return CurrentSectionView;
+}
+
+//**************************************************************************************
+BOOL DropSectionView(PINJECTIONSECTIONVIEW SectionView)
+//**************************************************************************************
+{
+ PINJECTIONSECTIONVIEW CurrentSectionView, PreviousSectionView;
+
+ PreviousSectionView = NULL;
+
+ if (SectionViewList == NULL)
+ {
+ DoOutputDebugString("DropSectionView: failed to obtain initial section view list.\n");
+ return FALSE;
+ }
+
+ CurrentSectionView = SectionViewList;
+
+ while (CurrentSectionView)
+ {
+ if (CurrentSectionView == SectionView)
+ {
+ // Unlink this from the list and free the memory
+ if (PreviousSectionView && CurrentSectionView->NextSectionView)
+ {
+ PreviousSectionView->NextSectionView = CurrentSectionView->NextSectionView;
+ DoOutputDebugString("DropSectionView: removed a view from section view list.\n");
+ }
+ else if (PreviousSectionView && CurrentSectionView->NextSectionView == NULL)
+ {
+ PreviousSectionView->NextSectionView = NULL;
+ DoOutputDebugString("DropSectionView: removed the view from the end of the section view list.\n");
+ }
+ else if (!PreviousSectionView)
+ {
+ SectionViewList = NULL;
+ DoOutputDebugString("DropSectionView: removed the head of the section view list.\n");
+ }
+
+ free(CurrentSectionView);
+
+ return TRUE;
+ }
+
+ PreviousSectionView = CurrentSectionView;
+ CurrentSectionView = CurrentSectionView->NextSectionView;
+ }
+
+ return FALSE;
+}
+
+//**************************************************************************************
+void DumpSectionViewsForPid(DWORD Pid)
+//**************************************************************************************
+{
+ struct InjectionInfo *CurrentInjectionInfo;
+ PINJECTIONSECTIONVIEW CurrentSectionView;
+ DWORD BufferSize = MAX_PATH;
+ LPVOID PEPointer = NULL;
+ BOOL Dumped = FALSE;
+
+ CurrentInjectionInfo = GetInjectionInfo(Pid);
+
+ if (CurrentInjectionInfo == NULL)
+ {
+ DoOutputDebugString("DumpSectionViewsForPid: No injection info for pid %d.\n", Pid);
+ return;
+ }
+
+ CurrentSectionView = SectionViewList;
+
+ while (CurrentSectionView)
+ {
+ if (CurrentSectionView->TargetProcessId == Pid && CurrentSectionView->LocalView)
+ {
+ DoOutputDebugString("DumpSectionViewsForPid: Shared section view found with pid %d, local address 0x%p.\n", Pid);
+
+ PEPointer = CurrentSectionView->LocalView;
+
+ while (ScanForDisguisedPE(PEPointer, CurrentSectionView->ViewSize - ((DWORD_PTR)PEPointer - (DWORD_PTR)CurrentSectionView->LocalView), &PEPointer))
+ {
+ DoOutputDebugString("DumpSectionViewsForPid: Dumping PE image from shared section view, local address 0x%p.\n", PEPointer);
+
+ CapeMetaData->DumpType = INJECTION_PE;
+ CapeMetaData->TargetPid = Pid;
+ CapeMetaData->Address = PEPointer;
+
+ if (DumpImageInCurrentProcess(PEPointer))
+ {
+ DoOutputDebugString("DumpSectionViewsForPid: Dumped PE image from shared section view.\n");
+ Dumped = TRUE;
+ }
+ else
+ DoOutputDebugString("DumpSectionViewsForPid: Failed to dump PE image from shared section view.\n");
+
+ ((BYTE*)PEPointer)++;
+ }
+
+ if (Dumped == FALSE)
+ {
+ DoOutputDebugString("DumpSectionViewsForPid: no PE file found in shared section view, attempting raw dump.\n");
+
+ CapeMetaData->DumpType = INJECTION_SHELLCODE;
+
+ CapeMetaData->TargetPid = Pid;
+
+ if (DumpMemory(CurrentSectionView->LocalView, CurrentSectionView->ViewSize))
+ {
+ DoOutputDebugString("DumpSectionViewsForPid: Dumped shared section view.");
+ Dumped = TRUE;
+ }
+ else
+ DoOutputDebugString("DumpSectionViewsForPid: Failed to dump shared section view.");
+ }
+ }
+
+ //DropSectionView(CurrentSectionView);
+
+ CurrentSectionView = CurrentSectionView->NextSectionView;
+ }
+
+ if (Dumped == FALSE)
+ DoOutputDebugString("DumpSectionViewsForPid: no shared section views found for pid %d.\n", Pid);
+
+ return;
+}
+
+//**************************************************************************************
+void DumpSectionView(PINJECTIONSECTIONVIEW SectionView)
+//**************************************************************************************
+{
+ DWORD BufferSize = MAX_PATH;
+ LPVOID PEPointer = NULL;
+ BOOL Dumped = FALSE;
+
+ if (!SectionView->LocalView)
+ {
+ DoOutputDebugString("DumpSectionView: Section view local view address not set.\n");
+ return;
+ }
+
+ if (!SectionView->TargetProcessId)
+ {
+ DoOutputDebugString("DumpSectionView: Section with local view 0x%p has no target process - error.\n", SectionView->LocalView);
+ return;
+ }
+
+ if (!SectionView->ViewSize)
+ {
+ DoOutputDebugString("DumpSectionView: Section with local view 0x%p has zero commit size - error.\n", SectionView->LocalView);
+ return;
+ }
+
+ Dumped = DumpPEsInRange(SectionView->LocalView, SectionView->ViewSize);
+
+ if (Dumped)
+ DoOutputDebugString("DumpSectionView: Dumped PE image from shared section view with local address 0x%p.\n", SectionView->LocalView);
+ else
+ {
+ DoOutputDebugString("DumpSectionView: no PE file found in shared section view with local address 0x%p, attempting raw dump.\n", SectionView->LocalView);
+
+ CapeMetaData->DumpType = INJECTION_SHELLCODE;
+
+ CapeMetaData->TargetPid = SectionView->TargetProcessId;
+
+ if (DumpMemory(SectionView->LocalView, SectionView->ViewSize))
+ {
+ DoOutputDebugString("DumpSectionView: Dumped shared section view with local address at 0x%p", SectionView->LocalView);
+ Dumped = TRUE;
+ }
+ else
+ DoOutputDebugString("DumpSectionView: Failed to dump shared section view with address view at 0x%p", SectionView->LocalView);
+ }
+
+ if (Dumped == TRUE)
+ DropSectionView(SectionView);
+ else
+ { // This may indicate the view has been unmapped already
+ // Let's try and remap it.
+ SIZE_T ViewSize = 0;
+ PVOID BaseAddress = NULL;
+
+ DoOutputDebugString("DumpSectionView: About to remap section with handle 0x%x, size 0x%x.\n", SectionView->SectionHandle, SectionView->ViewSize);
+
+ NTSTATUS ret = pNtMapViewOfSection(SectionView->SectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, 0, &ViewSize, ViewUnmap, 0, PAGE_READWRITE);
+
+ if (NT_SUCCESS(ret))
+ {
+ Dumped = DumpPEsInRange(BaseAddress, ViewSize);
+
+ if (Dumped)
+ DoOutputDebugString("DumpSectionView: Remapped and dumped section view with handle 0x%x.\n", SectionView->SectionHandle);
+ else
+ {
+ DoOutputDebugString("DumpSectionView: no PE file found in remapped section view with handle 0x%x, attempting raw dump.\n", SectionView->SectionHandle);
+
+ CapeMetaData->DumpType = INJECTION_SHELLCODE;
+
+ CapeMetaData->TargetPid = SectionView->TargetProcessId;
+
+ if (DumpMemory(BaseAddress, ViewSize))
+ {
+ DoOutputDebugString("DumpSectionView: Dumped remapped section view with handle 0x%x.\n", SectionView->SectionHandle);
+ Dumped = TRUE;
+ }
+ else
+ DoOutputDebugString("DumpSectionView: Failed to dump remapped section view with handle 0x%x.\n", SectionView->SectionHandle);
+ }
+
+ pNtUnmapViewOfSection(SectionView->SectionHandle, BaseAddress);
+ }
+ else
+ DoOutputDebugString("DumpSectionView: Failed to remap section with handle 0x%x - error code 0x%x\n", SectionView->SectionHandle, ret);
+ }
+
+ return;
+}
+
+//**************************************************************************************
+void DumpSectionViewsForHandle(HANDLE SectionHandle)
+//**************************************************************************************
+{
+ PINJECTIONSECTIONVIEW CurrentSectionView = SectionViewList;
+
+ while (CurrentSectionView)
+ {
+ wchar_t *SectionName;
+
+ if (CurrentSectionView->SectionHandle == SectionHandle)
+ break;
+
+ SectionName = malloc(MAX_UNICODE_PATH * sizeof(wchar_t));
+
+ if (SectionName)
+ {
+ path_from_handle(SectionHandle, SectionViewList->SectionName, MAX_UNICODE_PATH);
+ if ((!wcscmp(CurrentSectionView->SectionName, SectionName)))
+ {
+ DoOutputDebugString("DumpSectionViewsForHandle: New section handle for existing named section %ws.\n", SectionHandle, SectionName);
+ free(SectionName);
+ break;
+ }
+ free(SectionName);
+ }
+
+ CurrentSectionView = CurrentSectionView->NextSectionView;
+ }
+
+ if (CurrentSectionView && CurrentSectionView->TargetProcessId)
+ {
+ DoOutputDebugString("DumpSectionViewsForHandle: Dumping section view at 0x%p for handle 0x%x (target process %d).\n", CurrentSectionView->LocalView, SectionHandle, CurrentSectionView->TargetProcessId);
+ DumpSectionView(CurrentSectionView);
+ }
+
+ return;
+}
+
+void GetThreadContextHandler(DWORD Pid, LPCONTEXT Context)
+{
+ if (Context && Context->ContextFlags & CONTEXT_CONTROL)
+ {
+ struct InjectionInfo *CurrentInjectionInfo = GetInjectionInfo(Pid);
+#ifdef _WIN64
+ if (CurrentInjectionInfo && CurrentInjectionInfo->ProcessId == Pid)
+ CurrentInjectionInfo->StackPointer = (LPVOID)Context->Rsp;
+#else
+ if (CurrentInjectionInfo && CurrentInjectionInfo->ProcessId == Pid)
+ CurrentInjectionInfo->StackPointer = (LPVOID)Context->Esp;
+#endif
+ }
+}
+
+void SetThreadContextHandler(DWORD Pid, const CONTEXT *Context)
+{
+ if (Context && Context->ContextFlags & CONTEXT_CONTROL)
+ {
+ struct InjectionInfo *CurrentInjectionInfo = GetInjectionInfo(Pid);
+#ifdef _WIN64
+ if (CurrentInjectionInfo && CurrentInjectionInfo->ProcessId == Pid)
+ CurrentInjectionInfo->EntryPoint = Context->Rcx - CurrentInjectionInfo->ImageBase; // rcx holds ep on 64-bit
+
+ if (Context->Rip == (DWORD_PTR)GetProcAddress(GetModuleHandle("ntdll"), "NtMapViewOfSection"))
+ DoOutputDebugString("SetThreadContextHandler: Hollow process entry point set to NtMapViewOfSection (process %d).\n", Pid);
+ else
+ DoOutputDebugString("SetThreadContextHandler: Hollow process entry point reset via NtSetContextThread to 0x%p (process %d).\n", CurrentInjectionInfo->EntryPoint, Pid);
+#else
+ if (CurrentInjectionInfo && CurrentInjectionInfo->ProcessId == Pid)
+ CurrentInjectionInfo->EntryPoint = Context->Eax - CurrentInjectionInfo->ImageBase; // eax holds ep on 32-bit
+
+ if (Context->Eip == (DWORD)GetProcAddress(GetModuleHandle("ntdll"), "NtMapViewOfSection"))
+ DoOutputDebugString("SetThreadContextHandler: Hollow process entry point set to NtMapViewOfSection (process %d).\n", Pid);
+ else
+ DoOutputDebugString("SetThreadContextHandler: Hollow process entry point reset via NtSetContextThread to 0x%p (process %d).\n", CurrentInjectionInfo->EntryPoint, Pid);
+#endif
+ }
+}
+
+void ResumeThreadHandler(DWORD Pid)
+{
+ struct InjectionInfo *CurrentInjectionInfo = GetInjectionInfo(Pid);
+
+ if (!CurrentInjectionInfo)
+ {
+ DoOutputDebugString("ResumeThreadHandler: CurrentInjectionInfo 0x%x (Pid %d).\n", CurrentInjectionInfo, Pid);
+ return;
+ }
+
+ if (CurrentInjectionInfo->ImageBase && CurrentInjectionInfo->WriteDetected && CurrentInjectionInfo->ImageDumped == FALSE)
+ {
+ CapeMetaData->DumpType = INJECTION_PE;
+ CapeMetaData->TargetPid = Pid;
+
+ DoOutputDebugString("ResumeThreadHandler: Dumping hollowed process %d, image base 0x%p.\n", Pid, CurrentInjectionInfo->ImageBase);
+
+ CurrentInjectionInfo->ImageDumped = DumpProcess(CurrentInjectionInfo->ProcessHandle, (PVOID)CurrentInjectionInfo->ImageBase);
+
+ if (CurrentInjectionInfo->ImageDumped)
+ {
+ DoOutputDebugString("ResumeThreadHandler: Dumped PE image from buffer.\n");
+ }
+ else
+ DoOutputDebugString("ResumeThreadHandler: Failed to dump PE image from buffer.\n");
+ }
+
+ DoOutputDebugString("ResumeThreadHandler: Dumping section view for process %d.\n", Pid);
+
+ DumpSectionViewsForPid(Pid);
+}
+
+void CreateProcessHandler(LPWSTR lpApplicationName, LPWSTR lpCommandLine, LPPROCESS_INFORMATION lpProcessInformation)
+{
+ WCHAR TargetProcess[MAX_PATH];
+ struct InjectionInfo *CurrentInjectionInfo;
+
+ // Create 'injection info' struct for the newly created process
+ CurrentInjectionInfo = CreateInjectionInfo(lpProcessInformation->dwProcessId);
+
+ if (CurrentInjectionInfo == NULL)
+ {
+ DoOutputDebugString("CreateProcessHandler: Failed to create injection info for new process %d, ImageBase: 0x%p", lpProcessInformation->dwProcessId, CurrentInjectionInfo->ImageBase);
+ return;
+ }
+
+ CurrentInjectionInfo->ProcessHandle = lpProcessInformation->hProcess;
+ CurrentInjectionInfo->ImageBase = (DWORD_PTR)get_process_image_base(lpProcessInformation->hProcess);
+ CurrentInjectionInfo->EntryPoint = (DWORD_PTR)NULL;
+ CurrentInjectionInfo->ImageDumped = FALSE;
+
+ CapeMetaData->TargetProcess = (char*)malloc(MAX_PATH);
+ memset(TargetProcess, 0, MAX_PATH*sizeof(WCHAR));
+
+ if (lpApplicationName)
+ _snwprintf(TargetProcess, MAX_PATH, L"%s", lpApplicationName);
+ else if (lpCommandLine)
+ {
+ DoOutputDebugString("CreateProcessHandler: using lpCommandLine: %ws.\n", lpCommandLine);
+ if (*lpCommandLine == L'\"')
+ wcsncpy_s(TargetProcess, MAX_PATH, lpCommandLine+1, (rsize_t)((wcschr(lpCommandLine+1, '\"') - lpCommandLine)-1));
+ else
+ {
+ if (wcschr(lpCommandLine, ' '))
+ wcsncpy_s(TargetProcess, MAX_PATH, lpCommandLine, (rsize_t)((wcschr(lpCommandLine, ' ') - lpCommandLine)+1));
+ else
+ wcsncpy_s(TargetProcess, MAX_PATH, lpCommandLine, wcslen(lpCommandLine)+1);
+ }
+ }
+
+ WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, (LPCWSTR)TargetProcess, (int)wcslen(TargetProcess)+1, CapeMetaData->TargetProcess, MAX_PATH, NULL, NULL);
+
+ DoOutputDebugString("CreateProcessHandler: Injection info set for new process %d, ImageBase: 0x%p", CurrentInjectionInfo->ProcessId, CurrentInjectionInfo->ImageBase);
+}
+
+void CreateRemoteThreadHandler(DWORD Pid)
+{
+ struct InjectionInfo *CurrentInjectionInfo = GetInjectionInfo(Pid);
+
+ if (!CurrentInjectionInfo)
+ {
+ DoOutputDebugString("CreateRemoteThreadHandler: CurrentInjectionInfo 0x%x (Pid %d).\n", CurrentInjectionInfo, Pid);
+ return;
+ }
+
+ //if (CurrentInjectionInfo->ImageBase && CurrentInjectionInfo->WriteDetected && CurrentInjectionInfo->ImageDumped == FALSE)
+ if (CurrentInjectionInfo->ImageDumped == FALSE)
+ {
+ CapeMetaData->DumpType = INJECTION_PE;
+ CapeMetaData->TargetPid = Pid;
+
+ DoOutputDebugString("CreateRemoteThreadHandler: Dumping hollowed process %d, image base 0x%p.\n", Pid, CurrentInjectionInfo->ImageBase);
+
+ CurrentInjectionInfo->ImageDumped = DumpProcess(CurrentInjectionInfo->ProcessHandle, (PVOID)CurrentInjectionInfo->ImageBase);
+
+ if (CurrentInjectionInfo->ImageDumped)
+ {
+ DoOutputDebugString("CreateRemoteThreadHandler: Dumped PE image from buffer.\n");
+ }
+ else
+ DoOutputDebugString("CreateRemoteThreadHandler: Failed to dump PE image from buffer.\n");
+ }
+
+ DumpSectionViewsForPid(Pid);
+}
+
+void OpenProcessHandler(HANDLE ProcessHandle, DWORD Pid)
+{
+ struct InjectionInfo *CurrentInjectionInfo;
+ DWORD BufferSize = MAX_PATH;
+ char DevicePath[MAX_PATH];
+ unsigned int PathLength;
+
+ CurrentInjectionInfo = GetInjectionInfo(Pid);
+
+ if (CurrentInjectionInfo == NULL)
+ { // First call for this process, create new info
+ CurrentInjectionInfo = CreateInjectionInfo(Pid);
+
+ DoOutputDebugString("OpenProcessHandler: Injection info created for Pid %d, handle 0x%x.\n", Pid, ProcessHandle);
+
+ if (CurrentInjectionInfo == NULL)
+ {
+ DoOutputDebugString("OpenProcessHandler: Error - cannot create new injection info.\n");
+ }
+ else
+ {
+ CurrentInjectionInfo->ProcessHandle = ProcessHandle;
+ CurrentInjectionInfo->EntryPoint = (DWORD_PTR)NULL;
+ CurrentInjectionInfo->ImageDumped = FALSE;
+ CapeMetaData->TargetProcess = (char*)malloc(BufferSize);
+
+ CurrentInjectionInfo->ImageBase = (DWORD_PTR)get_process_image_base(ProcessHandle);
+
+ if (CurrentInjectionInfo->ImageBase)
+ DoOutputDebugString("OpenProcessHandler: Image base for process %d (handle 0x%x): 0x%p.\n", Pid, ProcessHandle, CurrentInjectionInfo->ImageBase);
+
+ PathLength = GetProcessImageFileName(ProcessHandle, DevicePath, BufferSize);
+
+ if (!PathLength)
+ {
+ DoOutputErrorString("OpenProcessHandler: Error obtaining target process name");
+ _snprintf(CapeMetaData->TargetProcess, BufferSize, "Error obtaining target process name");
+ }
+ else if (!TranslatePathFromDeviceToLetter(DevicePath, CapeMetaData->TargetProcess, &BufferSize))
+ DoOutputErrorString("OpenProcessHandler: Error translating target process path");
+ }
+ }
+ else if (CurrentInjectionInfo->ImageBase == (DWORD_PTR)NULL)
+ {
+ CurrentInjectionInfo->ImageBase = (DWORD_PTR)get_process_image_base(ProcessHandle);
+
+ if (CurrentInjectionInfo->ImageBase)
+ DoOutputDebugString("OpenProcessHandler: Image base for process %d (handle 0x%x): 0x%p.\n", Pid, ProcessHandle, CurrentInjectionInfo->ImageBase);
+ }
+}
+
+void ResumeProcessHandler(HANDLE ProcessHandle, DWORD Pid)
+{
+ struct InjectionInfo *CurrentInjectionInfo;
+
+ CurrentInjectionInfo = GetInjectionInfo(Pid);
+
+ if (CurrentInjectionInfo)
+ {
+ if (CurrentInjectionInfo->ImageBase && CurrentInjectionInfo->WriteDetected && CurrentInjectionInfo->ImageDumped == FALSE)
+ {
+ SetCapeMetaData(INJECTION_PE, Pid, ProcessHandle, NULL);
+
+ DoOutputDebugString("ResumeProcessHandler: Dumping hollowed process %d, image base 0x%p.\n", Pid, CurrentInjectionInfo->ImageBase);
+
+ CurrentInjectionInfo->ImageDumped = DumpProcess(ProcessHandle, (PVOID)CurrentInjectionInfo->ImageBase);
+
+ if (CurrentInjectionInfo->ImageDumped)
+ {
+ DoOutputDebugString("ResumeProcessHandler: Dumped PE image from buffer.\n");
+ }
+ else
+ DoOutputDebugString("ResumeProcessHandler: Failed to dump PE image from buffer.\n");
+ }
+
+ DumpSectionViewsForPid(Pid);
+ }
+}
+
+void MapSectionViewHandler(HANDLE ProcessHandle, HANDLE SectionHandle, PVOID BaseAddress, SIZE_T ViewSize)
+{
+ struct InjectionInfo *CurrentInjectionInfo;
+ PINJECTIONSECTIONVIEW CurrentSectionView;
+ char DevicePath[MAX_PATH];
+ unsigned int PathLength;
+ DWORD BufferSize = MAX_PATH;
+
+ DWORD Pid = pid_from_process_handle(ProcessHandle);
+
+ if (!Pid)
+ {
+ DoOutputErrorString("MapSectionViewHandler: Failed to obtain pid from process handle 0x%x", ProcessHandle);
+ CurrentInjectionInfo = GetInjectionInfoFromHandle(ProcessHandle);
+ Pid = CurrentInjectionInfo->ProcessId;
+ }
+ else
+ CurrentInjectionInfo = GetInjectionInfo(Pid);
+
+ if (!Pid)
+ DoOutputDebugString("MapSectionViewHandler: Failed to find injection info pid from process handle 0x%x.\n", ProcessHandle);
+
+ if (Pid == GetCurrentProcessId())
+ {
+ CurrentSectionView = GetSectionView(SectionHandle);
+
+ if (!CurrentSectionView)
+ {
+ CurrentSectionView = AddSectionView(SectionHandle, BaseAddress, ViewSize);
+ DoOutputDebugString("MapSectionViewHandler: Added section view with handle 0x%x amd local view 0x%p to global list (%ws).\n", SectionHandle, BaseAddress, CurrentSectionView->SectionName);
+ }
+ else
+ {
+ if (CurrentSectionView->LocalView != BaseAddress)
+ {
+ CurrentSectionView->LocalView = BaseAddress;
+ CurrentSectionView->ViewSize = ViewSize;
+ DoOutputDebugString("MapSectionViewHandler: Updated local view to 0x%p for section view with handle 0x%x (%ws).\n", BaseAddress, SectionHandle, CurrentSectionView->SectionName);
+ }
+ }
+ }
+ else if (CurrentInjectionInfo && CurrentInjectionInfo->ProcessId == Pid)
+ {
+ CurrentSectionView = AddSectionView(SectionHandle, BaseAddress, ViewSize);
+
+ if (CurrentSectionView)
+ {
+ CurrentSectionView->TargetProcessId = Pid;
+ DoOutputDebugString("MapSectionViewHandler: Added section view with handle 0x%x to target process %d (%ws).\n", SectionHandle, Pid, CurrentSectionView->SectionName);
+ }
+ else
+ {
+ DoOutputDebugString("MapSectionViewHandler: Error, failed to add section view with handle 0x%x and target process %d (%ws).\n", SectionHandle, Pid, CurrentSectionView->SectionName);
+ }
+ }
+ else if (!CurrentInjectionInfo && Pid != GetCurrentProcessId())
+ {
+ CurrentInjectionInfo = CreateInjectionInfo(Pid);
+
+ if (CurrentInjectionInfo == NULL)
+ {
+ DoOutputDebugString("MapSectionViewHandler: Cannot create new injection info - error.\n");
+ }
+ else
+ {
+ CurrentInjectionInfo->ProcessHandle = ProcessHandle;
+ CurrentInjectionInfo->ProcessId = Pid;
+ CurrentInjectionInfo->EntryPoint = (DWORD_PTR)NULL;
+ CurrentInjectionInfo->ImageDumped = FALSE;
+ CapeMetaData->TargetProcess = (char*)malloc(BufferSize);
+
+ CurrentInjectionInfo->ImageBase = (DWORD_PTR)get_process_image_base(ProcessHandle);
+
+ if (CurrentInjectionInfo->ImageBase)
+ DoOutputDebugString("MapSectionViewHandler: Image base for process %d (handle 0x%x): 0x%p.\n", Pid, ProcessHandle, CurrentInjectionInfo->ImageBase);
+
+ PathLength = GetProcessImageFileName(ProcessHandle, DevicePath, BufferSize);
+
+ if (!PathLength)
+ {
+ DoOutputErrorString("MapSectionViewHandler: Error obtaining target process name");
+ _snprintf(CapeMetaData->TargetProcess, BufferSize, "Error obtaining target process name");
+ }
+ else if (!TranslatePathFromDeviceToLetter(DevicePath, CapeMetaData->TargetProcess, &BufferSize))
+ DoOutputErrorString("MapSectionViewHandler: Error translating target process path");
+
+ CurrentSectionView = AddSectionView(SectionHandle, BaseAddress, ViewSize);
+
+ if (CurrentSectionView)
+ {
+ CurrentSectionView->TargetProcessId = Pid;
+ DoOutputDebugString("MapSectionViewHandler: Added section view with handle 0x%x to target process %d (%ws).\n", SectionHandle, Pid, CurrentSectionView->SectionName);
+ }
+ else
+ DoOutputDebugString("MapSectionViewHandler: Error, failed to add section view with handle 0x%x and target process %d (%ws).\n", SectionHandle, Pid, CurrentSectionView->SectionName);
+ }
+ }
+}
+
+void UnmapSectionViewHandler(PVOID BaseAddress)
+{
+ PINJECTIONSECTIONVIEW CurrentSectionView;
+
+ CurrentSectionView = SectionViewList;
+
+ while (CurrentSectionView)
+ {
+ if (CurrentSectionView->TargetProcessId && CurrentSectionView->LocalView == BaseAddress)
+ {
+ DoOutputDebugString("UnmapSectionViewHandler: Attempt to unmap view at 0x%p, dumping.\n", BaseAddress);
+ CapeMetaData->DumpType = INJECTION_PE;
+ CapeMetaData->TargetPid = CurrentSectionView->TargetProcessId;
+ DumpSectionView(CurrentSectionView);
+ }
+
+ CurrentSectionView = CurrentSectionView->NextSectionView;
+ }
+}
+
+void WriteMemoryHandler(HANDLE ProcessHandle, LPVOID BaseAddress, LPCVOID Buffer, SIZE_T NumberOfBytesWritten)
+{
+ DWORD Pid;
+ struct InjectionInfo *CurrentInjectionInfo;
+ PIMAGE_DOS_HEADER pDosHeader;
+ PIMAGE_NT_HEADERS pNtHeader;
+ char DevicePath[MAX_PATH];
+ unsigned int PathLength;
+ DWORD BufferSize = MAX_PATH;
+
+ Pid = pid_from_process_handle(ProcessHandle);
+
+ CurrentInjectionInfo = GetInjectionInfo(Pid);
+
+ if (NumberOfBytesWritten == 0)
+ return;
+
+ if (!CurrentInjectionInfo && Pid != GetCurrentProcessId())
+ {
+ CurrentInjectionInfo = CreateInjectionInfo(Pid);
+
+ if (CurrentInjectionInfo == NULL)
+ {
+ DoOutputDebugString("WriteMemoryHandler: Cannot create new injection info - error.\n");
+ }
+ else
+ {
+ CurrentInjectionInfo->ProcessHandle = ProcessHandle;
+ CurrentInjectionInfo->ProcessId = Pid;
+ CurrentInjectionInfo->EntryPoint = (DWORD_PTR)NULL;
+ CurrentInjectionInfo->ImageDumped = FALSE;
+ CapeMetaData->TargetProcess = (char*)malloc(BufferSize);
+
+ CurrentInjectionInfo->ImageBase = (DWORD_PTR)get_process_image_base(ProcessHandle);
+
+ if (CurrentInjectionInfo->ImageBase)
+ DoOutputDebugString("WriteMemoryHandler: Image base for process %d (handle 0x%x): 0x%p.\n", Pid, ProcessHandle, CurrentInjectionInfo->ImageBase);
+
+ PathLength = GetProcessImageFileName(ProcessHandle, DevicePath, BufferSize);
+
+ if (!PathLength)
+ {
+ DoOutputErrorString("WriteMemoryHandler: Error obtaining target process name");
+ _snprintf(CapeMetaData->TargetProcess, BufferSize, "Error obtaining target process name");
+ }
+ else if (!TranslatePathFromDeviceToLetter(DevicePath, CapeMetaData->TargetProcess, &BufferSize))
+ DoOutputErrorString("WriteMemoryHandler: Error translating target process path");
+ }
+ }
+
+ if (CurrentInjectionInfo->ProcessId != Pid)
+ return;
+
+ CurrentInjectionInfo->WriteDetected = TRUE;
+
+ // Check if we have a valid DOS and PE header at the beginning of Buffer
+ if (IsDisguisedPEHeader((PVOID)Buffer))
+ {
+ pDosHeader = (PIMAGE_DOS_HEADER)((char*)Buffer);
+
+ pNtHeader = (PIMAGE_NT_HEADERS)((char*)Buffer + pDosHeader->e_lfanew);
+
+ CurrentInjectionInfo->ImageBase = (DWORD_PTR)BaseAddress;
+
+ DoOutputDebugString("WriteMemoryHandler: Executable binary injected into process %d (ImageBase 0x%x)\n", Pid, CurrentInjectionInfo->ImageBase);
+
+ if (CurrentInjectionInfo->ImageDumped == FALSE)
+ {
+ SetCapeMetaData(INJECTION_PE, Pid, ProcessHandle, NULL);
+
+ CurrentInjectionInfo->ImageDumped = DumpImageInCurrentProcess((PVOID)Buffer);
+
+ if (CurrentInjectionInfo->ImageDumped)
+ {
+ CurrentInjectionInfo->BufferBase = (LPVOID)Buffer;
+ CurrentInjectionInfo->BufferSizeOfImage = pNtHeader->OptionalHeader.SizeOfImage;
+ DoOutputDebugString("WriteMemoryHandler: Dumped PE image from buffer at 0x%x, SizeOfImage 0x%x.\n", Buffer, CurrentInjectionInfo->BufferSizeOfImage);
+ }
+ else
+ {
+ DoOutputDebugString("WriteMemoryHandler: Failed to dump PE image from buffer, attempting raw dump.\n");
+
+ CapeMetaData->DumpType = INJECTION_SHELLCODE;
+ CapeMetaData->TargetPid = Pid;
+ if (DumpMemory((LPVOID)Buffer, NumberOfBytesWritten))
+ DoOutputDebugString("WriteMemoryHandler: Dumped malformed PE image from buffer.");
+ else
+ DoOutputDebugString("WriteMemoryHandler: Failed to dump malformed PE image from buffer.");
+ }
+ }
+ }
+ else
+ {
+ if (NumberOfBytesWritten > 0x10) // We assign some lower limit
+ {
+ if (CurrentInjectionInfo->BufferBase && Buffer > CurrentInjectionInfo->BufferBase &&
+ Buffer < (LPVOID)((UINT_PTR)CurrentInjectionInfo->BufferBase + CurrentInjectionInfo->BufferSizeOfImage) && CurrentInjectionInfo->ImageDumped == TRUE)
+ {
+ // Looks like a previously dumped PE image is being written a section at a time to the target process.
+ // We don't want to dump these writes.
+ DoOutputDebugString("WriteMemoryHandler: injection of section of PE image which has already been dumped.\n");
+ }
+ else
+ {
+ DoOutputDebugString("WriteMemoryHandler: shellcode at 0x%p (size 0x%x) injected into process %d.\n", Buffer, NumberOfBytesWritten, Pid);
+
+ // dump injected code/data
+ CapeMetaData->DumpType = INJECTION_SHELLCODE;
+ CapeMetaData->TargetPid = Pid;
+ if (DumpMemory((LPVOID)Buffer, NumberOfBytesWritten))
+ DoOutputDebugString("WriteMemoryHandler: Dumped injected code/data from buffer.");
+ else
+ DoOutputDebugString("WriteMemoryHandler: Failed to dump injected code/data from buffer.");
+ }
+ }
+ }
+}
+
+void DuplicationHandler(HANDLE SourceHandle, HANDLE TargetHandle)
+{
+ struct InjectionInfo *CurrentInjectionInfo;
+ PINJECTIONSECTIONVIEW CurrentSectionView;
+ char DevicePath[MAX_PATH];
+ unsigned int PathLength;
+ DWORD BufferSize = MAX_PATH;
+
+ DWORD Pid = pid_from_process_handle(TargetHandle);
+
+ if (Pid == GetCurrentProcessId())
+ return;
+
+ if (!Pid)
+ {
+ DoOutputErrorString("DuplicationHandler: Failed to obtain pid from target process handle 0x%x", TargetHandle);
+ CurrentInjectionInfo = GetInjectionInfoFromHandle(TargetHandle);
+ Pid = CurrentInjectionInfo->ProcessId;
+ }
+ else
+ CurrentInjectionInfo = GetInjectionInfo(Pid);
+
+ if (!Pid)
+ {
+ DoOutputDebugString("DuplicationHandler: Failed to find pid for target process handle 0x%x in injection info list 0x%x.\n", TargetHandle);
+ return;
+ }
+
+ //if (!CurrentInjectionInfo)
+ //{
+ // DoOutputDebugString("DuplicationHandler: Failed to find injection info for target process %d.\n", Pid);
+ // return;
+ //}
+
+ CurrentSectionView = GetSectionView(SourceHandle);
+
+ if (!CurrentSectionView)
+ {
+ DoOutputDebugString("DuplicationHandler: Failed to find section view with source handle 0x%x.\n", SourceHandle);
+ return;
+ }
+
+ if (CurrentInjectionInfo && CurrentInjectionInfo->ProcessId == Pid)
+ {
+ CurrentSectionView->TargetProcessId = Pid;
+ DoOutputDebugString("DuplicationHandler: Added section view with source handle 0x%x to target process %d (%ws).\n", SourceHandle, Pid, CurrentSectionView->SectionName);
+ }
+ else if (!CurrentInjectionInfo && Pid != GetCurrentProcessId())
+ {
+ CurrentInjectionInfo = CreateInjectionInfo(Pid);
+
+ if (CurrentInjectionInfo == NULL)
+ {
+ DoOutputDebugString("DuplicationHandler: Cannot create new injection info - error.\n");
+ }
+ else
+ {
+ CurrentInjectionInfo->ProcessHandle = SourceHandle;
+ CurrentInjectionInfo->ProcessId = Pid;
+ CurrentInjectionInfo->EntryPoint = (DWORD_PTR)NULL;
+ CurrentInjectionInfo->ImageDumped = FALSE;
+ CapeMetaData->TargetProcess = (char*)malloc(BufferSize);
+
+ CurrentInjectionInfo->ImageBase = (DWORD_PTR)get_process_image_base(SourceHandle);
+
+ if (CurrentInjectionInfo->ImageBase)
+ DoOutputDebugString("DuplicationHandler: Image base for process %d (handle 0x%x): 0x%p.\n", Pid, SourceHandle, CurrentInjectionInfo->ImageBase);
+
+ PathLength = GetProcessImageFileName(SourceHandle, DevicePath, BufferSize);
+
+ if (!PathLength)
+ {
+ DoOutputErrorString("DuplicationHandler: Error obtaining target process name");
+ _snprintf(CapeMetaData->TargetProcess, BufferSize, "Error obtaining target process name");
+ }
+ else if (!TranslatePathFromDeviceToLetter(DevicePath, CapeMetaData->TargetProcess, &BufferSize))
+ DoOutputErrorString("DuplicationHandler: Error translating target process path");
+
+ CurrentSectionView = AddSectionView(SourceHandle, NULL, 0);
+
+ if (CurrentSectionView)
+ {
+ CurrentSectionView->TargetProcessId = Pid;
+ DoOutputDebugString("DuplicationHandler: Added section view with handle 0x%x to target process %d (%ws).\n", SourceHandle, Pid, CurrentSectionView->SectionName);
+ }
+ else
+ DoOutputDebugString("DuplicationHandler: Error, failed to add section view with handle 0x%x and target process %d (%ws).\n", SourceHandle, Pid, CurrentSectionView->SectionName);
+ }
+ }
+}
diff --git a/CAPE/Injection.h b/CAPE/Injection.h
new file mode 100644
index 0000000..94909a8
--- /dev/null
+++ b/CAPE/Injection.h
@@ -0,0 +1,67 @@
+/*
+CAPE - Config And Payload Extraction
+Copyright(C) 2015-2018 Context Information Security. (kevin.oreilly@contextis.com)
+
+This program is free software : you can redistribute it and / or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.If not, see .
+*/
+#define MAX_UNICODE_PATH 32768
+
+void DumpSectionViewsForPid(DWORD Pid);
+void DumpSectionViewsForHandle(HANDLE SectionHandle);
+
+typedef enum _SECTION_INHERIT {
+ ViewShare = 1,
+ ViewUnmap = 2
+} SECTION_INHERIT;
+
+typedef struct InjectionSectionView
+{
+ HANDLE SectionHandle;
+ PVOID LocalView;
+ SIZE_T ViewSize;
+ int TargetProcessId;
+ wchar_t *SectionName;
+ struct InjectionSectionView *NextSectionView;
+} INJECTIONSECTIONVIEW, *PINJECTIONSECTIONVIEW;
+
+PINJECTIONSECTIONVIEW AddSectionView(HANDLE SectionHandle, PVOID LocalView, SIZE_T ViewSize);
+PINJECTIONSECTIONVIEW GetSectionView(HANDLE SectionHandle);
+BOOL DropSectionView(PINJECTIONSECTIONVIEW SectionView);
+void DumpSectionViewsForPid(DWORD Pid);
+void DumpSectionView(PINJECTIONSECTIONVIEW SectionView);
+
+typedef struct InjectionInfo
+{
+ int ProcessId;
+ HANDLE ProcessHandle;
+ DWORD_PTR ImageBase;
+ DWORD_PTR EntryPoint;
+ BOOL WriteDetected;
+ BOOL ImageDumped;
+ LPVOID BufferBase;
+ LPVOID StackPointer;
+ unsigned int BufferSizeOfImage;
+ HANDLE SectionHandle;
+// struct InjectionSectionView *SectionViewList;
+ struct InjectionInfo *NextInjectionInfo;
+} INJECTIONINFO, *PINJECTIONINFO;
+
+struct InjectionInfo *InjectionInfoList;
+
+PINJECTIONINFO GetInjectionInfo(DWORD ProcessId);
+PINJECTIONINFO GetInjectionInfoFromHandle(HANDLE ProcessHandle);
+PINJECTIONINFO CreateInjectionInfo(DWORD ProcessId);
+BOOL DropInjectionInfo(HANDLE ProcessHandle);
+
+struct InjectionSectionView *SectionViewList;
diff --git a/CAPE/Output.c b/CAPE/Output.c
index fb805a4..c6617c5 100644
--- a/CAPE/Output.c
+++ b/CAPE/Output.c
@@ -18,13 +18,19 @@ along with this program.If not, see .
#include
#include
#include
-
+#include "cape.h"
#include "..\pipe.h"
+#include "..\config.h"
+
+#define MAX_INT_STRING_LEN 10 // 4294967294
TCHAR DebugOutput[MAX_PATH];
TCHAR PipeOutput[MAX_PATH];
TCHAR ErrorOutput[MAX_PATH];
+extern struct CapeMetadata *CapeMetaData;
+extern ULONG_PTR base_of_dll_of_interest;
+
//**************************************************************************************
void DoOutputDebugString(_In_ LPCTSTR lpOutputString, ...)
//**************************************************************************************
@@ -34,12 +40,12 @@ void DoOutputDebugString(_In_ LPCTSTR lpOutputString, ...)
va_start(args, lpOutputString);
memset(DebugOutput, 0, MAX_PATH*sizeof(TCHAR));
- _vsntprintf_s(DebugOutput, MAX_PATH, MAX_PATH, lpOutputString, args);
+ _vsntprintf_s(DebugOutput, MAX_PATH, _TRUNCATE, lpOutputString, args);
+#ifdef STANDALONE
OutputDebugString(DebugOutput);
-
+#else
memset(PipeOutput, 0, MAX_PATH*sizeof(TCHAR));
- _sntprintf_s(PipeOutput, MAX_PATH, MAX_PATH, "DEBUG:%s", DebugOutput);
-#ifndef STANDALONE
+ _sntprintf_s(PipeOutput, MAX_PATH, _TRUNCATE, "DEBUG:%s", DebugOutput);
pipe(PipeOutput, strlen(PipeOutput));
#endif
va_end(args);
@@ -68,15 +74,15 @@ void DoOutputErrorString(_In_ LPCTSTR lpOutputString, ...)
NULL);
memset(DebugOutput, 0, MAX_PATH*sizeof(TCHAR));
- _vsntprintf_s(DebugOutput, MAX_PATH, MAX_PATH, lpOutputString, args);
+ _vsntprintf_s(DebugOutput, MAX_PATH, _TRUNCATE, lpOutputString, args);
memset(ErrorOutput, 0, MAX_PATH*sizeof(TCHAR));
- _sntprintf_s(ErrorOutput, MAX_PATH, MAX_PATH, "Error %d (0x%x) - %s: %s", ErrorCode, ErrorCode, DebugOutput, (char*)lpMsgBuf);
+ _sntprintf_s(ErrorOutput, MAX_PATH, _TRUNCATE, "Error %d (0x%x) - %s: %s", ErrorCode, ErrorCode, DebugOutput, (char*)lpMsgBuf);
+#ifdef STANDALONE
OutputDebugString(ErrorOutput);
-
+#else
memset(PipeOutput, 0, MAX_PATH*sizeof(TCHAR));
- _sntprintf_s(PipeOutput, MAX_PATH, MAX_PATH, "DEBUG:%s", ErrorOutput);
-#ifndef STANDALONE
+ _sntprintf_s(PipeOutput, MAX_PATH, _TRUNCATE, "DEBUG:%s", ErrorOutput);
pipe(PipeOutput, strlen(PipeOutput));
#endif
@@ -89,14 +95,141 @@ void DoOutputErrorString(_In_ LPCTSTR lpOutputString, ...)
void CapeOutputFile(_In_ LPCTSTR lpOutputFile)
//**************************************************************************************
{
- memset(DebugOutput, 0, MAX_PATH*sizeof(TCHAR));
- _sntprintf_s(DebugOutput, MAX_PATH, MAX_PATH, "CAPE Output file: %s", lpOutputFile);
- OutputDebugString(DebugOutput);
+ char MetadataPath[MAX_PATH];
+ HANDLE hMetadata;
+ SIZE_T BufferSize;
+ char *Buffer;
+ DWORD dwBytesWritten;
+
+ if (CapeMetaData && CapeMetaData->DumpType == PROCDUMP)
+ {
+ memset(MetadataPath, 0, MAX_PATH * sizeof(TCHAR));
+ _sntprintf_s(MetadataPath, MAX_PATH, MAX_PATH, "%s_info.txt", lpOutputFile);
+ hMetadata = CreateFile(MetadataPath, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (hMetadata == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_EXISTS)
+ {
+ DoOutputDebugString("CAPE metadata filename exists already: %s", MetadataPath);
+ return;
+ }
+
+ if (hMetadata == INVALID_HANDLE_VALUE)
+ {
+ DoOutputErrorString("Could not create CAPE metadata file");
+ return;
+ }
+
+ BufferSize = 3 * (MAX_PATH + MAX_INT_STRING_LEN + 2) + 2; //// max size string can be
+
+ Buffer = malloc(BufferSize);
+
+ // if our file of interest is a dll, we need to update cape module path now
+ if (base_of_dll_of_interest)
+ {
+ if (g_config.file_of_interest == NULL)
+ {
+ DoOutputDebugString("CAPE Error: g_config.file_of_interest is NULL.\n", g_config.file_of_interest);
+ return;
+ }
+
+ CapeMetaData->ModulePath = (char*)malloc(MAX_PATH);
+ WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, (LPCWSTR)g_config.file_of_interest, (int)wcslen(g_config.file_of_interest)+1, CapeMetaData->ModulePath, MAX_PATH, NULL, NULL);
+ }
+ else
+ CapeMetaData->ModulePath = CapeMetaData->ProcessPath;
+
+ // This metadata format is specific to process dumps
+ _snprintf_s(Buffer, BufferSize, BufferSize, "%d\n%d\n%s\n%s\n", CapeMetaData->DumpType, CapeMetaData->Pid, CapeMetaData->ProcessPath, CapeMetaData->ModulePath);
+
+ if (FALSE == WriteFile(hMetadata, Buffer, (DWORD)strlen(Buffer), &dwBytesWritten, NULL))
+ {
+ DoOutputDebugString("WriteFile error on CAPE metadata file %s\n");
+ CloseHandle(hMetadata);
+ free(Buffer);
+ return;
+ }
+
+ CloseHandle(hMetadata);
+
+ memset(DebugOutput, 0, MAX_PATH*sizeof(TCHAR));
+ _sntprintf_s(DebugOutput, MAX_PATH, MAX_PATH, "Process dump output file: %s", lpOutputFile);
+#ifdef STANDALONE
+ OutputDebugString(DebugOutput);
+#else
+ memset(PipeOutput, 0, MAX_PATH*sizeof(TCHAR));
+ _sntprintf_s(PipeOutput, MAX_PATH, MAX_PATH, "FILE_DUMP:%s", lpOutputFile);
+ pipe(PipeOutput, strlen(PipeOutput));
+#endif
- memset(PipeOutput, 0, MAX_PATH*sizeof(TCHAR));
- _sntprintf_s(PipeOutput, MAX_PATH, MAX_PATH, "FILE_CAPE:%s", lpOutputFile);
-#ifndef STANDALONE
- pipe(PipeOutput, strlen(PipeOutput));
+ }
+ else if (CapeMetaData && CapeMetaData->DumpType != PROCDUMP)
+ {
+ memset(MetadataPath, 0, MAX_PATH * sizeof(TCHAR));
+ _sntprintf_s(MetadataPath, MAX_PATH, MAX_PATH, "%s_info.txt", lpOutputFile);
+ hMetadata = CreateFile(MetadataPath, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (hMetadata == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_EXISTS)
+ {
+ DoOutputDebugString("CAPE metadata filename exists already: %s", MetadataPath);
+ return;
+ }
+
+ if (hMetadata == INVALID_HANDLE_VALUE)
+ {
+ DoOutputErrorString("Could not create CAPE metadata file");
+ return;
+ }
+
+ BufferSize = 3 * (MAX_PATH + MAX_INT_STRING_LEN + 2) + 2; //// max size string can be
+
+ Buffer = malloc(BufferSize);
+
+ if (!CapeMetaData->ProcessPath)
+ CapeMetaData->ProcessPath = "Unknown path";
+ CapeMetaData->ModulePath = CapeMetaData->ProcessPath;
+
+ if (CapeMetaData->DumpType == EXTRACTION_PE || CapeMetaData->DumpType == EXTRACTION_SHELLCODE)
+ {
+ // Extraction-specific format
+ _snprintf_s(Buffer, BufferSize, BufferSize, "%d\n%d\n%s\n%s\n0x%p\n", CapeMetaData->DumpType, CapeMetaData->Pid, CapeMetaData->ProcessPath, CapeMetaData->ModulePath, CapeMetaData->Address);
+ }
+ else if (CapeMetaData->DumpType == INJECTION_PE || CapeMetaData->DumpType == INJECTION_SHELLCODE || CapeMetaData->DumpType == EVILGRAB_PAYLOAD || CapeMetaData->DumpType == EVILGRAB_DATA)
+ {
+ if (CapeMetaData->TargetProcess && CapeMetaData->ProcessPath)
+ // Injection-specific format
+ _snprintf_s(Buffer, BufferSize, BufferSize, "%d\n%d\n%s\n%s\n%s\n%d\n", CapeMetaData->DumpType, CapeMetaData->Pid, CapeMetaData->ProcessPath, CapeMetaData->ModulePath, CapeMetaData->TargetProcess, CapeMetaData->TargetPid);
+ }
+ else if (CapeMetaData->DumpType == SEDRECO_DATA)
+ {
+ // Sedreco-specific format where TargetPid is used for config item index #
+ _snprintf_s(Buffer, BufferSize, BufferSize, "%d\n%d\n%s\n%s\n0x%x\n", CapeMetaData->DumpType, CapeMetaData->Pid, CapeMetaData->ProcessPath, CapeMetaData->ModulePath, (DWORD)CapeMetaData->TargetPid);
+ }
+ else
+ if (CapeMetaData->ProcessPath)
+ _snprintf_s(Buffer, BufferSize, BufferSize, "%d\n%d\n%s\n%s\n", CapeMetaData->DumpType, CapeMetaData->Pid, CapeMetaData->ProcessPath, CapeMetaData->ModulePath);
+
+ if (FALSE == WriteFile(hMetadata, Buffer, (DWORD)strlen(Buffer), &dwBytesWritten, NULL))
+ {
+ DoOutputDebugString("WriteFile error on CAPE metadata file %s\n");
+ CloseHandle(hMetadata);
+ free(Buffer);
+ return;
+ }
+
+ CloseHandle(hMetadata);
+
+ memset(DebugOutput, 0, MAX_PATH*sizeof(TCHAR));
+ _sntprintf_s(DebugOutput, MAX_PATH, MAX_PATH, "CAPE Output file: %s", lpOutputFile);
+#ifdef STANDALONE
+ OutputDebugString(DebugOutput);
+#else
+ memset(PipeOutput, 0, MAX_PATH*sizeof(TCHAR));
+ _sntprintf_s(PipeOutput, MAX_PATH, MAX_PATH, "FILE_CAPE:%s", lpOutputFile);
+ pipe(PipeOutput, strlen(PipeOutput));
#endif
+ }
+ else
+ DoOutputDebugString("No CAPE metadata (or wrong type) for file: %s\n", lpOutputFile);
+
return;
-}
\ No newline at end of file
+}
diff --git a/CAPE/Scylla/ApiReader.h b/CAPE/Scylla/ApiReader.h
index 45e67ef..54d1431 100644
--- a/CAPE/Scylla/ApiReader.h
+++ b/CAPE/Scylla/ApiReader.h
@@ -29,6 +29,7 @@ class ApiReader : public ProcessAccessHelp
void addFoundApiToModuleList(DWORD_PTR iatAddress, ApiInfo * apiFound, bool isNewModule, bool isSuspect);
void clearAll();
bool isInvalidMemoryForIat( DWORD_PTR address );
+ void parseModuleWithOwnProcess( ModuleInfo * module );
private:
bool readExportTableAlwaysFromDisk;
void parseIAT(DWORD_PTR addressIAT, BYTE * iatBuffer, SIZE_T size);
@@ -49,7 +50,6 @@ class ApiReader : public ProcessAccessHelp
void findApiByModule(ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi);
bool isModuleLoadedInOwnProcess( ModuleInfo * module );
- void parseModuleWithOwnProcess( ModuleInfo * module );
bool isPeAndExportTableValid(PIMAGE_NT_HEADERS pNtHeader);
void findApiInProcess( ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi );
bool findApiInExportTable(ModuleInfo *module, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi);
diff --git a/CAPE/Scylla/IATReferenceScan.cpp b/CAPE/Scylla/IATReferenceScan.cpp
index 471a21d..7e1690e 100644
--- a/CAPE/Scylla/IATReferenceScan.cpp
+++ b/CAPE/Scylla/IATReferenceScan.cpp
@@ -67,8 +67,6 @@ void IATReferenceScan::startScan(DWORD_PTR imageBase, DWORD imageSize, DWORD_PTR
iatDirectImportList.reserve(50);
}
-
-
DWORD_PTR section = imageBase;
do
@@ -410,7 +408,6 @@ void IATReferenceScan::patchNewIat(DWORD_PTR stdImagebase, DWORD_PTR newIatBaseA
}
}
-
void IATReferenceScan::printDirectImportLog()
{
DoOutputDebugString("------------------------------------------------------------");
@@ -455,7 +452,6 @@ void IATReferenceScan::printDirectImportLog()
DoOutputDebugString("------------------------------------------------------------");
}
-
void IATReferenceScan::findDirectIatReferenceCallJmp( _DInst * instruction )
{
IATReference ref;
@@ -735,5 +731,3 @@ DWORD IATReferenceScan::addAdditionalApisToList()
return newIatSize;
}
-
-
diff --git a/CAPE/Scylla/IATSearch.cpp b/CAPE/Scylla/IATSearch.cpp
index f035fa7..4404f3f 100644
--- a/CAPE/Scylla/IATSearch.cpp
+++ b/CAPE/Scylla/IATSearch.cpp
@@ -51,6 +51,7 @@ bool IATSearch::findIATAdvanced( DWORD_PTR startAddress, DWORD_PTR* addressIAT,
#ifdef DEBUG_COMMENTS
DoOutputDebugString("findAPIAddressInIAT2 :: error reading memory");
#endif
+ delete [] dataBuffer;
return false;
}
@@ -277,6 +278,7 @@ bool IATSearch::findIATStartAndSize(DWORD_PTR address, DWORD_PTR * addressIAT, D
#ifdef DEBUG_COMMENTS
DoOutputDebugString("findIATStartAddress :: error reading memory");
#endif
+ delete [] dataBuffer;
return false;
}
diff --git a/CAPE/Scylla/ImportsHandling.cpp b/CAPE/Scylla/ImportsHandling.cpp
index ba791f0..4724f15 100644
--- a/CAPE/Scylla/ImportsHandling.cpp
+++ b/CAPE/Scylla/ImportsHandling.cpp
@@ -3,12 +3,6 @@
#include "Thunks.h"
#include "Architecture.h"
-#include
-#include
-#include "multitree.h" // CMultiSelectTreeViewCtrl
-
-//#include "resource.h"
-
//#define DEBUG_COMMENTS
extern "C" void DoOutputDebugString(_In_ LPCTSTR lpOutputString, ...);
@@ -59,59 +53,6 @@ ImportsHandling::ImportsHandling()
ImportsHandling::~ImportsHandling()
{
- TreeIcons.Destroy();
-}
-
-bool ImportsHandling::isModule(CTreeItem item)
-{
- return (0 != getModuleThunk(item));
-}
-
-bool ImportsHandling::isImport(CTreeItem item)
-{
- return (0 != getImportThunk(item));
-}
-
-ImportModuleThunk * ImportsHandling::getModuleThunk(CTreeItem item)
-{
- stdext::hash_map::const_iterator it;
- it = itemData.find(item);
- if(it != itemData.end())
- {
- const TreeItemData * data = &it->second;
- if(data->isModule)
- {
- return data->module;
- }
- }
- return NULL;
-}
-
-ImportThunk * ImportsHandling::getImportThunk(CTreeItem item)
-{
- stdext::hash_map::const_iterator it;
- TreeItemData * data = getItemData(item);
- if(data && !data->isModule)
- {
- return data->import;
- }
- return NULL;
-}
-
-void ImportsHandling::setItemData(CTreeItem item, const TreeItemData * data)
-{
- itemData[item] = *data;
-}
-
-ImportsHandling::TreeItemData * ImportsHandling::getItemData(CTreeItem item)
-{
- stdext::hash_map::iterator it;
- it = itemData.find(item);
- if(it != itemData.end())
- {
- return &it->second;
- }
- return NULL;
}
void ImportsHandling::updateCounts()
@@ -144,160 +85,17 @@ void ImportsHandling::updateCounts()
}
}
-/*bool ImportsHandling::addImport(const CHAR * moduleName, const CHAR * name, DWORD_PTR va, DWORD_PTR rva, WORD ordinal, bool valid, bool suspect)
-{
- ImportThunk import;
- ImportModuleThunk * module = 0;
- std::map::iterator iterator1;
-
- if (moduleList.size() > 1)
- {
- iterator1 = moduleList.begin();
- while (iterator1 != moduleList.end())
- {
- if (rva >= iterator1->second.firstThunk)
- {
- iterator1++;
- if (iterator1 == moduleList.end())
- {
- iterator1--;
- module = &(iterator1->second);
- break;
- }
- else if (rva < iterator1->second.firstThunk)
- {
- iterator1--;
- module = &(iterator1->second);
- break;
- }
- }
- }
- }
- else
- {
- iterator1 = moduleList.begin();
- module = &(iterator1->second);
- }
-
- if (!module)
- {
- DoOutputDebugString("ImportsHandling::addFunction module not found rva " PRINTF_DWORD_PTR_FULL, rva);
- return false;
- }
-
- //TODO
- import.suspect = true;
- import.valid = false;
- import.va = va;
- import.rva = rva;
- import.ordinal = ordinal;
-
- strcpy_s(import.moduleName, MAX_PATH, moduleName);
- strcpy_s(import.name, MAX_PATH, name);
-
- module->thunkList.insert(std::pair(import.rva, import));
-
- return true;
-}
-*/
-
-/*
-bool ImportsHandling::addModule(const CHAR * moduleName, DWORD_PTR firstThunk)
-{
- ImportModuleThunk module;
-
- module.firstThunk = firstThunk;
- strcpy_s(module.moduleName, MAX_PATH, moduleName);
-
- moduleList.insert(std::pair(firstThunk,module));
-
- return true;
-}
-
-void ImportsHandling::displayAllImports()
-{
- std::map::iterator it_module;
- std::map::iterator it_import;
-
- //TreeImports.DeleteAllItems();
- itemData.clear();
- //TreeImports.SetImageList(TreeIcons);
-
- it_module = moduleList.begin();
- while (it_module != moduleList.end())
- {
- ImportModuleThunk &moduleThunk = it_module->second;
-
- moduleThunk.key = moduleThunk.firstThunk; // This belongs elsewhere...
- //moduleThunk.hTreeItem = addDllToTreeView(TreeImports, &moduleThunk);
-
- it_import = moduleThunk.thunkList.begin();
- while (it_import != moduleThunk.thunkList.end())
- {
- ImportThunk &importThunk = it_import->second;
-
- importThunk.key = importThunk.rva; // This belongs elsewhere...
- importThunk.hTreeItem = addApiToTreeView(TreeImports, moduleThunk.hTreeItem, &importThunk);
-
- it_import++;
- }
-
- it_module++;
- }
-
- updateCounts();
-}
-*/
-
void ImportsHandling::clearAllImports()
{
- //TreeImports.DeleteAllItems();
- itemData.clear();
moduleList.clear();
updateCounts();
}
-/*
-CTreeItem ImportsHandling::addDllToTreeView(CMultiSelectTreeViewCtrl& idTreeView, ImportModuleThunk * moduleThunk)
-{
- CTreeItem item = idTreeView.InsertItem("", NULL, TVI_ROOT);
-
- item.SetData(itemData.size());
-
- TreeItemData data;
- data.isModule = true;
- data.module = moduleThunk;
-
- setItemData(item, &data);
-
- updateModuleInTreeView(moduleThunk, item);
- return item;
-}
-
-CTreeItem ImportsHandling::addApiToTreeView(CMultiSelectTreeViewCtrl& idTreeView, CTreeItem parentDll, ImportThunk * importThunk)
-{
- CTreeItem item = idTreeView.InsertItem("", parentDll, TVI_LAST);
-
- item.SetData(itemData.size());
-
- TreeItemData data;
- data.isModule = false;
- data.import = importThunk;
-
- setItemData(item, &data);
-
- updateImportInTreeView(importThunk, item);
- return item;
-}
-*/
-
void ImportsHandling::selectImports(bool invalid, bool suspect)
{
std::map::iterator it_module;
std::map::iterator it_import;
- //TreeImports.SelectAllItems(FALSE); //remove selection
-
it_module = moduleList.begin();
while (it_module != moduleList.end())
{
@@ -307,13 +105,6 @@ void ImportsHandling::selectImports(bool invalid, bool suspect)
while (it_import != moduleThunk.thunkList.end())
{
ImportThunk &importThunk = it_import->second;
-
- if ((invalid && !importThunk.valid) || (suspect && importThunk.suspect))
- {
- //TreeImports.SelectItem(importThunk.hTreeItem, TRUE);
- importThunk.hTreeItem.EnsureVisible();
- }
-
it_import++;
}
@@ -321,232 +112,6 @@ void ImportsHandling::selectImports(bool invalid, bool suspect)
}
}
-bool ImportsHandling::invalidateImport(CTreeItem item)
-{
- ImportThunk * import = getImportThunk(item);
- if(import)
- {
- CTreeItem parent = item.GetParent();
- if(!parent.IsNull())
- {
- const ImportModuleThunk * module = getModuleThunk(parent);
- if(module)
- {
- import->invalidate();
-
- updateImportInTreeView(import, import->hTreeItem);
- updateModuleInTreeView(module, module->hTreeItem);
-
- updateCounts();
- return true;
- }
- }
- }
- return false;
-}
-
-bool ImportsHandling::invalidateModule(CTreeItem item)
-{
- ImportModuleThunk * module = getModuleThunk(item);
- if(module)
- {
- std::map::iterator it_import;
-
- it_import = module->thunkList.begin();
- while(it_import != module->thunkList.end())
- {
- ImportThunk * import = &it_import->second;
- import->invalidate();
- updateImportInTreeView(import, import->hTreeItem);
- it_import++;
- }
-
- updateModuleInTreeView(module, module->hTreeItem);
-
- updateCounts();
- return true;
- }
- return false;
-}
-
-bool ImportsHandling::setImport(CTreeItem item, const CHAR * moduleName, const CHAR * apiName, WORD ordinal, WORD hint, bool valid, bool suspect)
-{
- ImportThunk * import = getImportThunk(item);
- if(import)
- {
- CTreeItem parent = item.GetParent();
- if(!parent.IsNull())
- {
- ImportModuleThunk * module = getModuleThunk(parent);
- if(module)
- {
-
- strcpy_s(import->moduleName, moduleName);
- strcpy_s(import->name, apiName);
- import->ordinal = ordinal;
- //import->apiAddressVA = api->va; //??
- import->hint = hint;
- import->valid = valid;
- import->suspect = suspect;
-
- if (module->isValid())
- {
- scanAndFixModuleList();
- //displayAllImports();
- }
- else
- {
- updateImportInTreeView(import, item);
- updateCounts();
- }
- return true;
- }
- }
- }
- return false;
-}
-
-void ImportsHandling::updateImportInTreeView(const ImportThunk * importThunk, CTreeItem item)
-{
- if (importThunk->valid)
- {
- CHAR tempString[300];
-
- if (importThunk->name[0] != 0x00)
- {
- sprintf_s(tempString, "ord: %04X name: %s", importThunk->ordinal, importThunk->name);
- }
- else
- {
- sprintf_s(tempString, "ord: %04X", importThunk->ordinal);
- }
-
- sprintf_s(stringBuffer, " rva: " PRINTF_DWORD_PTR_HALF " mod: %s %s", importThunk->rva, importThunk->moduleName, tempString);
- }
- else
- {
- sprintf_s(stringBuffer, " rva: " PRINTF_DWORD_PTR_HALF " ptr: " PRINTF_DWORD_PTR_FULL, importThunk->rva, importThunk->apiAddressVA);
- }
-
-// item.SetText(stringBuffer);
-// Icon icon = getAppropiateIcon(importThunk);
-// item.SetImage(icon, icon);
-}
-
-void ImportsHandling::updateModuleInTreeView(const ImportModuleThunk * importThunk, CTreeItem item)
-{
- sprintf_s(stringBuffer, "%s (%d) FThunk: " PRINTF_DWORD_PTR_HALF, importThunk->moduleName,importThunk->thunkList.size(), importThunk->firstThunk);
-
- item.SetText(stringBuffer);
- Icon icon = getAppropiateIcon(importThunk->isValid());
- item.SetImage(icon, icon);
-}
-
-ImportsHandling::Icon ImportsHandling::getAppropiateIcon(const ImportThunk * importThunk)
-{
- if(importThunk->valid)
- {
- if(importThunk->suspect)
- {
- return iconWarning;
- }
- else
- {
- return iconCheck;
- }
- }
- else
- {
- return iconError;
- }
-}
-
-ImportsHandling::Icon ImportsHandling::getAppropiateIcon(bool valid)
-{
- if(valid)
- {
- return iconCheck;
- }
- else
- {
- return iconError;
- }
-}
-
-bool ImportsHandling::cutImport(CTreeItem item)
-{
- ImportThunk * import = getImportThunk(item);
- if(import)
- {
- CTreeItem parent = item.GetParent();
- if(!parent.IsNull())
- {
- ImportModuleThunk * module = getModuleThunk(parent);
- if(module)
- {
- itemData.erase(item);
- import->hTreeItem.Delete();
- module->thunkList.erase(import->key);
- import = 0;
-
- if (module->thunkList.empty())
- {
- itemData.erase(parent);
- module->hTreeItem.Delete();
- moduleList.erase(module->key);
- module = 0;
- }
- else
- {
- if (module->isValid() && module->moduleName[0] == L'?')
- {
- //update module name
- strcpy_s(module->moduleName, module->thunkList.begin()->second.moduleName);
- }
-
- module->firstThunk = module->thunkList.begin()->second.rva;
- updateModuleInTreeView(module, module->hTreeItem);
- }
-
- updateCounts();
- return true;
- }
- }
- }
- return false;
-}
-
-bool ImportsHandling::cutModule(CTreeItem item)
-{
- ImportModuleThunk * module = getModuleThunk(item);
- if(module)
- {
- CTreeItem child = item.GetChild();
- while(!child.IsNull())
- {
- itemData.erase(child);
- child = child.GetNextSibling();
- }
- itemData.erase(item);
- module->hTreeItem.Delete();
- moduleList.erase(module->key);
- module = 0;
- updateCounts();
- return true;
- }
- return false;
-}
-
-DWORD_PTR ImportsHandling::getApiAddressByNode(CTreeItem item)
-{
- const ImportThunk * import = getImportThunk(item);
- if(import)
- {
- return import->apiAddressVA;
- }
- return 0;
-}
-
void ImportsHandling::scanAndFixModuleList()
{
CHAR prevModuleName[MAX_PATH] = {0};
@@ -787,29 +352,3 @@ bool ImportsHandling::addFunctionToModuleList(const ImportThunk * apiFound)
module->thunkList[import.key] = import;
return true;
}
-
-void ImportsHandling::expandAllTreeNodes()
-{
- changeExpandStateOfTreeNodes(TVE_EXPAND);
-}
-
-void ImportsHandling::collapseAllTreeNodes()
-{
- changeExpandStateOfTreeNodes(TVE_COLLAPSE);
-}
-
-void ImportsHandling::changeExpandStateOfTreeNodes(UINT flag)
-{
- std::map::iterator it_module;
-
- it_module = moduleList.begin();
- while (it_module != moduleList.end())
- {
- ImportModuleThunk &moduleThunk = it_module->second;
-
- moduleThunk.hTreeItem.Expand(flag);
-
- it_module++;
- }
-}
-
diff --git a/CAPE/Scylla/ImportsHandling.h b/CAPE/Scylla/ImportsHandling.h
index 75299ed..3c1ee9b 100644
--- a/CAPE/Scylla/ImportsHandling.h
+++ b/CAPE/Scylla/ImportsHandling.h
@@ -1,15 +1,9 @@
#pragma once
+#include
#include