mirror of
https://github.com/fortra/No-Consolation
synced 2026-06-06 15:44:28 +00:00
add new option: --inthread
run a PE inline without creating a new thread
This commit is contained in:
@@ -3,7 +3,7 @@ CC_x64 := x86_64-w64-mingw32-gcc
|
||||
CC_x86 := i686-w64-mingw32-gcc
|
||||
STRIP_x64 := x86_64-w64-mingw32-strip
|
||||
STRIP_x86 := i686-w64-mingw32-strip
|
||||
OPTIONS := -Wall -I include
|
||||
OPTIONS := -masm=intel -Wall -I include
|
||||
|
||||
release:
|
||||
$(CC_x64) -c source/entry.c -o dist/$(BOFNAME).x64.o $(OPTIONS)
|
||||
|
||||
+18
-4
@@ -1,7 +1,7 @@
|
||||
|
||||
alias noconsolation
|
||||
{
|
||||
local('$bid $barch $PE $args $path $path_set $name_set $pebytes $x $matchfound $pe_id $local $cmdline $headers $method $use_unicode $timeout $nooutput $alloc_console $close_handles $free_libs $dont_save $list_pes $unload_pe $link_to_peb $dont_unload $load_all_deps $load_all_deps_but $load_deps $search_paths $pepath $pename');
|
||||
local('$bid $barch $PE $args $path $path_set $name_set $pebytes $x $matchfound $pe_id $local $cmdline $headers $method $use_unicode $timeout $timeout_set $nooutput $alloc_console $close_handles $free_libs $dont_save $list_pes $unload_pe $link_to_peb $dont_unload $load_all_deps $load_all_deps_but $load_deps $search_paths $pepath $pename $inthread');
|
||||
|
||||
$bid = $1;
|
||||
$pe_id = 0;
|
||||
@@ -17,6 +17,7 @@ alias noconsolation
|
||||
$method = '';
|
||||
$use_unicode = 0;
|
||||
$timeout = 60;
|
||||
$timeout_set = 0;
|
||||
$nooutput = 0;
|
||||
$alloc_console = 0;
|
||||
$close_handles = 0;
|
||||
@@ -30,6 +31,7 @@ alias noconsolation
|
||||
$load_all_deps_but = '';
|
||||
$load_deps = '';
|
||||
$search_paths = '';
|
||||
$inthread = 0;
|
||||
|
||||
# make sure the beacon is not WoW64
|
||||
$is64 = binfo($bid, "is64");
|
||||
@@ -68,6 +70,7 @@ alias noconsolation
|
||||
berror($1, "Invalid timeout: " . $timeout);
|
||||
return;
|
||||
}
|
||||
$timeout_set = 1;
|
||||
}
|
||||
else if (@_[$i] eq "-k")
|
||||
{
|
||||
@@ -173,6 +176,10 @@ alias noconsolation
|
||||
|
||||
$search_paths = @_[$i];
|
||||
}
|
||||
else if (@_[$i] eq "--inthread" || @_[$i] eq "-it")
|
||||
{
|
||||
$inthread = 1;
|
||||
}
|
||||
else if (-exists @_[$i] || @_[$i] ismatch '^\p{Alpha}:\\\\.*')
|
||||
{
|
||||
$path_set = 1;
|
||||
@@ -233,6 +240,12 @@ alias noconsolation
|
||||
return;
|
||||
}
|
||||
|
||||
if ($timeout_set && $inthread)
|
||||
{
|
||||
berror($bid, "The options --inthread and --timeout are not compatible");
|
||||
return;
|
||||
}
|
||||
|
||||
if ($path_set)
|
||||
{
|
||||
if ($local == 0)
|
||||
@@ -270,7 +283,7 @@ alias noconsolation
|
||||
}
|
||||
}
|
||||
|
||||
runpe($bid, $pename, $pepath, $pebytes, $path, $local, $timeout, $headers, $cmdline, $method, $use_unicode, $nooutput, $alloc_console, $close_handles, $free_libs, $dont_save, $list_pes, $unload_pe, mynick(), tstamp(ticks()), $link_to_peb, $dont_unload, $load_all_deps, $load_all_deps_but, $load_deps, $search_paths);
|
||||
runpe($bid, $pename, $pepath, $pebytes, $path, $local, $timeout, $headers, $cmdline, $method, $use_unicode, $nooutput, $alloc_console, $close_handles, $free_libs, $dont_save, $list_pes, $unload_pe, mynick(), tstamp(ticks()), $link_to_peb, $dont_unload, $load_all_deps, $load_all_deps_but, $load_deps, $search_paths, $inthread);
|
||||
}
|
||||
|
||||
sub runpe{
|
||||
@@ -286,7 +299,7 @@ sub runpe{
|
||||
}
|
||||
|
||||
# Pack the arguments
|
||||
$args = bof_pack($1, "ZzZbziiiZzziiiiiiizzziiizzz", $2 $2, $3, $4, $5, $6, $7, $8, $9, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26);
|
||||
$args = bof_pack($1, "ZzZbziiiZzziiiiiiizzziiizzzi", $2 $2, $3, $4, $5, $6, $7, $8, $9, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27);
|
||||
|
||||
# Execute BOF
|
||||
beacon_inline_execute($1, $data, "go", $args);
|
||||
@@ -298,8 +311,9 @@ beacon_command_register(
|
||||
"
|
||||
Summary: Run an unmanaged EXE/DLL inside Beacon's memory.
|
||||
|
||||
Usage: noconsolation [--local] [--link-to-peb] [--dont-unload] [--timeout 60] [-k] [--method funcname] [-w] [--no-output] [--alloc-console] [--close-handles] [--free-libraries] [--dont-save] [--list-pes] [--unload-pe pename] [--load-all-dependencies] [--load-all-dependencies-but advapi32.dll] [--load-dependencies wininet.dll] [--search-paths C:\\Windows\\Temp\\] /path/to/binary.exe arg1 arg2
|
||||
Usage: noconsolation [--local] [--inthread] [--link-to-peb] [--dont-unload] [--timeout 60] [-k] [--method funcname] [-w] [--no-output] [--alloc-console] [--close-handles] [--free-libraries] [--dont-save] [--list-pes] [--unload-pe pename] [--load-all-dependencies] [--load-all-dependencies-but advapi32.dll] [--load-dependencies wininet.dll] [--search-paths C:\\Windows\\Temp\\] /path/to/binary.exe arg1 arg2
|
||||
--local, -l Optional. The binary should be loaded from the target Windows machine
|
||||
--inthread, -it Optional. Run the PE with the main thread. This might hang your beacon depending on the PE and its arguments.
|
||||
--link-to-peb, -ltp Optional. Load the PE into the PEB
|
||||
--dont-unload, -du Optional. If set, the DLL won't be unloaded.
|
||||
--timeout NUM_SECONDS, -t NUM_SECONDS Optional. The number of seconds you wish to wait for the PE to complete running. Default 60 seconds. Set to 0 to disable
|
||||
|
||||
@@ -8,6 +8,7 @@ This is a Beacon Object File (BOF) that executes unmanaged PEs inline and retrie
|
||||
- Supports 64 and 32 bits
|
||||
- Supports EXEs and DLLs
|
||||
- Does not create new processes
|
||||
- Does not create new threads
|
||||
- Links modules to the PEB
|
||||
- Saves binaries in memory
|
||||
- Supports C++ exceptions (x64 only)
|
||||
@@ -17,8 +18,9 @@ This is a Beacon Object File (BOF) that executes unmanaged PEs inline and retrie
|
||||
```
|
||||
Summary: Run an unmanaged EXE/DLL inside Beacon's memory.
|
||||
|
||||
Usage: noconsolation [--local] [--link-to-peb] [--dont-unload] [--timeout 60] [-k] [--method funcname] [-w] [--no-output] [--alloc-console] [--close-handles] [--free-libraries] [--dont-save] [--list-pes] [--unload-pe pename] [--load-all-dependencies] [--load-all-dependencies-but advapi32.dll] [--load-dependencies wininet.dll] [--search-paths C:\\Windows\\Temp\\] /path/to/binary.exe arg1 arg2
|
||||
Usage: noconsolation [--local] [--inthread] [--link-to-peb] [--dont-unload] [--timeout 60] [-k] [--method funcname] [-w] [--no-output] [--alloc-console] [--close-handles] [--free-libraries] [--dont-save] [--list-pes] [--unload-pe pename] [--load-all-dependencies] [--load-all-dependencies-but advapi32.dll] [--load-dependencies wininet.dll] [--search-paths C:\\Windows\\Temp\\] /path/to/binary.exe arg1 arg2
|
||||
--local, -l Optional. The binary should be loaded from the target Windows machine
|
||||
--inthread, -it Optional. Run the PE with the main thread. This might hang your beacon depending on the PE and its arguments.
|
||||
--link-to-peb, -ltp Optional. Load the PE into the PEB
|
||||
--dont-unload, -du Optional. If set, the DLL won't be unloaded.
|
||||
--timeout NUM_SECONDS, -t NUM_SECONDS Optional. The number of seconds you wish to wait for the PE to complete running. Default 60 seconds. Set to 0 to disable
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
@@ -566,6 +566,47 @@ typedef struct _PEB2
|
||||
ULONG NtGlobalFlag2;
|
||||
} PEB2, *PPEB2;
|
||||
|
||||
typedef struct _NT_TIB2
|
||||
{
|
||||
struct _EXCEPTION_REGISTRATION_RECORD* ExceptionList; //0x0
|
||||
VOID* StackBase; //0x8
|
||||
VOID* StackLimit; //0x10
|
||||
VOID* SubSystemTib; //0x18
|
||||
union
|
||||
{
|
||||
VOID* FiberData; //0x20
|
||||
ULONG Version; //0x20
|
||||
};
|
||||
VOID* ArbitraryUserPointer; //0x28
|
||||
struct _NT_TIB2* Self; //0x30
|
||||
} NT_TIB2, *PNT_TIB2;
|
||||
|
||||
typedef struct _TEB2
|
||||
{
|
||||
struct _NT_TIB2 NtTib; //0x0
|
||||
VOID* EnvironmentPointer; //0x38
|
||||
struct _CLIENT_ID ClientId; //0x40
|
||||
VOID* ActiveRpcHandle; //0x50
|
||||
VOID* ThreadLocalStoragePointer; //0x58
|
||||
struct _PEB* ProcessEnvironmentBlock; //0x60
|
||||
ULONG LastErrorValue; //0x68
|
||||
ULONG CountOfOwnedCriticalSections; //0x6c
|
||||
VOID* CsrClientThread; //0x70
|
||||
VOID* Win32ThreadInfo; //0x78
|
||||
ULONG User32Reserved[26]; //0x80
|
||||
ULONG UserReserved[5]; //0xe8
|
||||
VOID* WOW32Reserved; //0x100
|
||||
ULONG CurrentLocale; //0x108
|
||||
ULONG FpSoftwareStatusRegister; //0x10c
|
||||
VOID* ReservedForDebuggerInstrumentation[16]; //0x110
|
||||
VOID* SystemReserved1[30]; //0x190
|
||||
CHAR PlaceholderCompatibilityMode; //0x280
|
||||
UCHAR PlaceholderHydrationAlwaysExplicit; //0x281
|
||||
CHAR PlaceholderReserved[10]; //0x282
|
||||
ULONG ProxiedProcessId; //0x28c
|
||||
// ...
|
||||
} TEB2, *PTEB2;
|
||||
|
||||
typedef struct _INVERTED_FUNCTION_TABLE_ENTRY
|
||||
{
|
||||
PVOID FunctionTable;
|
||||
@@ -614,6 +655,8 @@ WINBASEAPI NTSTATUS NTAPI NTDLL$RtlUnicodeStringToAnsiString(PANSI_STRING Dest
|
||||
WINBASEAPI NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation, SIZE_T MemoryInformationLength, PSIZE_T ReturnLength);
|
||||
WINBASEAPI NTSTATUS NTAPI NTDLL$NtCreateThreadEx(PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, HANDLE ProcessHandle, PVOID StartRoutine, PVOID Argument, ULONG CreateFlags, SIZE_T ZeroBits, SIZE_T StackSize, SIZE_T MaximumStackSize, PVOID AttributeList);
|
||||
WINBASEAPI SIZE_T NTSYSAPI NTDLL$RtlCompareMemory(VOID *Source1, VOID *Source2, SIZE_T Length);
|
||||
WINBASEAPI NTSTATUS NTAPI NTDLL$NtGetContextThread(HANDLE, PCONTEXT);
|
||||
WINBASEAPI NTSTATUS NTAPI NTDLL$NtSetContextThread(HANDLE, PCONTEXT);
|
||||
|
||||
WINBASEAPI WCHAR* __cdecl MSVCRT$wcscpy(WCHAR *strDestination,const WCHAR *strSource);
|
||||
WINBASEAPI int __cdecl MSVCRT$_stricmp(const char *string1,const char *string2);
|
||||
@@ -649,6 +692,8 @@ WINBASEAPI BOOL WINAPI KERNEL32$FreeLibrary(HANDLE hLibModule);
|
||||
#define NtQueryVirtualMemory NTDLL$NtQueryVirtualMemory
|
||||
#define NtCreateThreadEx NTDLL$NtCreateThreadEx
|
||||
#define RtlCompareMemory NTDLL$RtlCompareMemory
|
||||
#define NtGetContextThread NTDLL$NtGetContextThread
|
||||
#define NtSetContextThread NTDLL$NtSetContextThread
|
||||
|
||||
#define wcscpy MSVCRT$wcscpy
|
||||
#define _stricmp MSVCRT$_stricmp
|
||||
|
||||
+10
-1
@@ -6,7 +6,8 @@
|
||||
#define NC_SAVED_PE_KEY "NoConsolationSavedPeKey"
|
||||
#define NC_PE_INFO_KEY "NoConsolationPeInfoKey"
|
||||
#define NC_LOADED_DLL_KEY "NoConsolationLoadedDllKey"
|
||||
#define NC_MEM_STRUCTS_KEY "NoConsolationMeStructsKey"
|
||||
#define NC_MEM_STRUCTS_KEY "NoConsolationMemStructsKey"
|
||||
#define NC_EXEC_CTX "NoConsolationExecCtxKey"
|
||||
|
||||
#define MIN_XOR_KEY_LENGTH 16
|
||||
|
||||
@@ -100,6 +101,7 @@ typedef struct _LOADED_PE_INFO {
|
||||
BOOL linked;
|
||||
PVOID ldr_entry;
|
||||
BOOL dont_unload;
|
||||
BOOL inthread;
|
||||
} LOADED_PE_INFO, * PLOADED_PE_INFO;
|
||||
|
||||
typedef struct _LIBS_LOADED {
|
||||
@@ -112,3 +114,10 @@ typedef struct _LIB_LOADED {
|
||||
PVOID address;
|
||||
PLOADED_PE_INFO peinfo;
|
||||
} LIB_LOADED, * PLIB_LOADED;
|
||||
|
||||
typedef struct _EXEC_CTX {
|
||||
PVOID Rsp;
|
||||
PVOID Rbp;
|
||||
PVOID Rip;
|
||||
DWORD Tid;
|
||||
} EXEC_CTX, * PEXEC_CTX;
|
||||
|
||||
+2
-2
@@ -41,8 +41,8 @@ ULONG_PTR set_bits(
|
||||
ULONG_PTR newValue);
|
||||
|
||||
VOID clear_breakpoint(
|
||||
CONTEXT* ctx,
|
||||
int index);
|
||||
IN CONTEXT* ctx,
|
||||
IN DWORD index);
|
||||
|
||||
BOOL enable_breakpoint(
|
||||
OUT CONTEXT* ctx,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#endif
|
||||
|
||||
#define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 )
|
||||
#define NtCurrentThread() ( (HANDLE)(LONG_PTR) -2 )
|
||||
|
||||
typedef NTSTATUS(__stdcall* STDCALL)(PLDR_DATA_TABLE_ENTRY);
|
||||
typedef NTSTATUS(__thiscall* THISCALL)(PLDR_DATA_TABLE_ENTRY);
|
||||
@@ -35,6 +36,7 @@ typedef struct _IMAGE_RELOC {
|
||||
} IMAGE_RELOC, *PIMAGE_RELOC;
|
||||
|
||||
typedef BOOL (WINAPI *DllMain_t)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
|
||||
typedef BOOL (WINAPI *Entry_t)(PVOID Param1, PVOID Param2, PVOID Param3);
|
||||
|
||||
// for setting the command line...
|
||||
typedef CHAR** (WINAPI *p_acmdln_t)(VOID);
|
||||
|
||||
@@ -121,6 +121,10 @@ VOID set_std_err_handle(
|
||||
|
||||
HANDLE get_std_in_handle(VOID);
|
||||
|
||||
DWORD get_tid(VOID);
|
||||
|
||||
VOID rtl_exit_user_thread(VOID);
|
||||
|
||||
BOOL create_thread(
|
||||
OUT PHANDLE hThread);
|
||||
|
||||
|
||||
+20
-4
@@ -46,6 +46,7 @@ int go(IN PCHAR Buffer, IN ULONG Length)
|
||||
PLOADED_PE_INFO peinfo = NULL;
|
||||
PLIBS_LOADED libs_loaded = NULL;
|
||||
PMEMORY_STRUCTS mem_structs = NULL;
|
||||
BOOL inthread = FALSE;
|
||||
|
||||
BeaconDataParse(&parser, Buffer, Length);
|
||||
pe_wname = (LPWSTR)BeaconDataExtract(&parser, NULL);
|
||||
@@ -85,6 +86,7 @@ int go(IN PCHAR Buffer, IN ULONG Length)
|
||||
load_deps = load_deps[0] ? load_deps : NULL;
|
||||
search_paths = BeaconDataExtract(&parser, NULL);
|
||||
search_paths = search_paths[0] ? search_paths : NULL;
|
||||
inthread = BeaconDataInt(&parser);
|
||||
|
||||
peinfo = intAlloc(sizeof(LOADED_PE_INFO));
|
||||
|
||||
@@ -108,6 +110,7 @@ int go(IN PCHAR Buffer, IN ULONG Length)
|
||||
peinfo->load_deps = load_deps;
|
||||
peinfo->search_paths = search_paths;
|
||||
peinfo->custom_loaded = TRUE;
|
||||
peinfo->inthread = inthread;
|
||||
|
||||
// save a reference to peinfo
|
||||
BeaconAddValue(NC_PE_INFO_KEY, peinfo);
|
||||
@@ -186,10 +189,17 @@ int go(IN PCHAR Buffer, IN ULONG Length)
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
if (!create_thread(&peinfo->hThread))
|
||||
if (peinfo->inthread)
|
||||
{
|
||||
PRINT_ERR("failed to create thread");
|
||||
goto Cleanup;
|
||||
peinfo->hThread = NtCurrentThread();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!create_thread(&peinfo->hThread))
|
||||
{
|
||||
PRINT_ERR("failed to create thread");
|
||||
goto Cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (!redirect_std_out_err(peinfo))
|
||||
@@ -214,6 +224,12 @@ Cleanup:
|
||||
intFree(pe_bytes);
|
||||
}
|
||||
|
||||
if (peinfo && peinfo->inthread && peinfo->hHwBp1)
|
||||
unset_hwbp(peinfo->hThread, NT_DEVICE_IO_CONTROL_FILE_INDEX);
|
||||
|
||||
if (peinfo && peinfo->inthread && peinfo->hHwBp2)
|
||||
unset_hwbp(peinfo->hThread, CREATE_FILE_INDEX);
|
||||
|
||||
if (peinfo && peinfo->hHwBp1)
|
||||
remove_hwbp_handler(peinfo->hHwBp1);
|
||||
|
||||
@@ -294,7 +310,7 @@ Cleanup:
|
||||
if (peinfo && peinfo->modified_console_reference)
|
||||
*(PHANDLE)peinfo->console_reference_addr = peinfo->original_console_reference;
|
||||
|
||||
if (peinfo && peinfo->hThread)
|
||||
if (peinfo && peinfo->hThread && !peinfo->inthread)
|
||||
{
|
||||
TerminateThread(peinfo->hThread, 0);
|
||||
NtClose(peinfo->hThread);
|
||||
|
||||
+69
-25
@@ -2,6 +2,17 @@
|
||||
#include "hwbp.h"
|
||||
#include "peb.h"
|
||||
|
||||
ULONG_PTR set_bits(
|
||||
IN ULONG_PTR dw,
|
||||
IN int lowBit,
|
||||
IN int bits,
|
||||
IN ULONG_PTR newValue)
|
||||
{
|
||||
ULONG_PTR mask = (1UL << bits) - 1UL;
|
||||
dw = (dw & ~(mask << lowBit)) | (newValue << lowBit);
|
||||
return dw;
|
||||
}
|
||||
|
||||
BOOL enable_breakpoint(
|
||||
OUT CONTEXT* ctx,
|
||||
IN PVOID address,
|
||||
@@ -26,13 +37,38 @@ BOOL enable_breakpoint(
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ctx->Dr7 &= ~(3ull << (16 + 4 * index));
|
||||
ctx->Dr7 &= ~(3ull << (18 + 4 * index));
|
||||
ctx->Dr7 |= 1ull << (2 * index);
|
||||
ctx->Dr7 = set_bits(ctx->Dr7, 16, 16, 0);
|
||||
ctx->Dr7 = set_bits(ctx->Dr7, (index * 2), 1, 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID clear_breakpoint(
|
||||
IN CONTEXT* ctx,
|
||||
IN DWORD index)
|
||||
{
|
||||
// Clear the releveant hardware breakpoint
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
ctx->Dr0 = 0;
|
||||
break;
|
||||
case 1:
|
||||
ctx->Dr1 = 0;
|
||||
break;
|
||||
case 2:
|
||||
ctx->Dr2 = 0;
|
||||
break;
|
||||
case 3:
|
||||
ctx->Dr3 = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ctx->Dr7 = set_bits(ctx->Dr7, (index * 2), 1, 0);
|
||||
ctx->Dr6 = 0;
|
||||
ctx->EFlags = 0;
|
||||
}
|
||||
|
||||
BOOL set_hwbp(
|
||||
IN HANDLE hThread,
|
||||
IN PVOID address,
|
||||
@@ -49,27 +85,12 @@ BOOL set_hwbp(
|
||||
threadCtx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
|
||||
|
||||
PVOID (WINAPI* RtlAddVectoredExceptionHandler) (ULONG, exception_callback) = xGetProcAddress(xGetLibAddress("ntdll", TRUE, NULL), "RtlAddVectoredExceptionHandler", 0);
|
||||
NTSTATUS (NTAPI* NtGetContextThread)(HANDLE, PCONTEXT) = xGetProcAddress(xGetLibAddress("ntdll", TRUE, NULL), "NtGetContextThread", 0);
|
||||
NTSTATUS (NTAPI* NtSetContextThread)(HANDLE, PCONTEXT) = xGetProcAddress(xGetLibAddress("ntdll", TRUE, NULL), "NtSetContextThread", 0);
|
||||
|
||||
if (!RtlAddVectoredExceptionHandler)
|
||||
{
|
||||
api_not_found("RtlAddVectoredExceptionHandler");
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
if (!NtGetContextThread)
|
||||
{
|
||||
api_not_found("NtGetContextThread");
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
if (!NtSetContextThread)
|
||||
{
|
||||
api_not_found("NtSetContextThread");
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
hHwBpHandler = RtlAddVectoredExceptionHandler(1, hwbp_handler);
|
||||
if (!hHwBpHandler)
|
||||
{
|
||||
@@ -110,13 +131,6 @@ VOID remove_hwbp_handler(
|
||||
return;
|
||||
|
||||
ULONG (WINAPI* RtlRemoveVectoredExceptionHandler) (PVOID) = xGetProcAddress(xGetLibAddress("ntdll", TRUE, NULL), "RtlRemoveVectoredExceptionHandler", 0);
|
||||
|
||||
/*
|
||||
* Given that the PE thread always dies,
|
||||
* we do not need to clear the Dr7 register
|
||||
* we simply remove the handler
|
||||
*/
|
||||
|
||||
if (!RtlRemoveVectoredExceptionHandler)
|
||||
{
|
||||
api_not_found("RtlRemoveVectoredExceptionHandler");
|
||||
@@ -128,3 +142,33 @@ VOID remove_hwbp_handler(
|
||||
function_failed("RtlRemoveVectoredExceptionHandler");
|
||||
}
|
||||
}
|
||||
|
||||
VOID unset_hwbp(
|
||||
IN HANDLE hThread,
|
||||
IN UINT32 index)
|
||||
{
|
||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||
CONTEXT threadCtx = { 0 };
|
||||
|
||||
memset(&threadCtx, 0, sizeof(threadCtx));
|
||||
threadCtx.ContextFlags = CONTEXT_ALL;
|
||||
|
||||
status = NtGetContextThread(hThread, &threadCtx);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
syscall_failed("NtGetContextThread", status);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
clear_breakpoint(&threadCtx, index);
|
||||
|
||||
status = NtSetContextThread(hThread, &threadCtx);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
syscall_failed("NtSetContextThread", status);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return;
|
||||
}
|
||||
|
||||
+2
-2
@@ -265,8 +265,8 @@ PVOID handle_import(
|
||||
// if this is an exit-related API, replace it with RtlExitUserThread
|
||||
if (IsExitAPI(api_name))
|
||||
{
|
||||
DPRINT("IAT hooking %s!%s with ntdll!RtlExitUserThread", dll_name ? dll_name : "?", api_name);
|
||||
address = xGetProcAddress(xGetLibAddress("ntdll", TRUE, NULL), "RtlExitUserThread", 0);
|
||||
DPRINT("IAT hooking %s!%s with rtl_exit_user_thread", dll_name ? dll_name : "?", api_name);
|
||||
address = rtl_exit_user_thread;
|
||||
}
|
||||
// some PEs search for exit-related APIs using GetProcAddress
|
||||
else if (peinfo && !peinfo->dont_unload && !peinfo->is_dependency && !_stricmp(api_name, "GetProcAddress"))
|
||||
|
||||
+183
-10
@@ -1,6 +1,117 @@
|
||||
|
||||
#include "runner.h"
|
||||
|
||||
BOOL exec_entrypoint_inthread(
|
||||
IN PVOID EntryPoint,
|
||||
IN PVOID Param1,
|
||||
IN PVOID Param2,
|
||||
IN PVOID Param3)
|
||||
{
|
||||
Entry_t Entry = EntryPoint;
|
||||
PVOID Rsp = NULL;
|
||||
PVOID Rbp = NULL;
|
||||
PEXEC_CTX exec_ctx = NULL;
|
||||
|
||||
// get RSP and RBP
|
||||
#ifdef _WIN64
|
||||
__asm__(
|
||||
"mov rax, rsp \n"
|
||||
"mov rdx, rbp \n"
|
||||
: "=r" (Rbp), // RDX OUT
|
||||
"=r" (Rsp) // RAX OUT
|
||||
:
|
||||
);
|
||||
#else
|
||||
__asm__(
|
||||
"mov eax, esp \n"
|
||||
"mov edx, ebp \n"
|
||||
: "=r" (Rbp), // EDX OUT
|
||||
"=r" (Rbp) // EAX OUT
|
||||
:
|
||||
);
|
||||
#endif
|
||||
|
||||
// save the execution context in the Key/Value store
|
||||
exec_ctx = intAlloc(sizeof(EXEC_CTX));
|
||||
exec_ctx->Rsp = Rsp;
|
||||
exec_ctx->Rbp = Rbp;
|
||||
exec_ctx->Rip = &&return_addr;
|
||||
exec_ctx->Tid = get_tid();
|
||||
BeaconAddValue(NC_EXEC_CTX, exec_ctx);
|
||||
|
||||
// jumping to the entry point... wish me luck!
|
||||
Entry(Param1, Param2, Param3);
|
||||
|
||||
return_addr:
|
||||
DPRINT("Execution context restored"); // :^)
|
||||
|
||||
memset(exec_ctx, 0, sizeof(EXEC_CTX));
|
||||
intFree(exec_ctx);
|
||||
BeaconRemoveValue(NC_EXEC_CTX);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL run_pe_inthread(
|
||||
IN PLOADED_PE_INFO peinfo)
|
||||
{
|
||||
if (peinfo->is_dll)
|
||||
{
|
||||
if (peinfo->method)
|
||||
{
|
||||
DPRINT("Executing %ls!%s", peinfo->pe_wname, peinfo->method);
|
||||
|
||||
if (peinfo->cmdwline || peinfo->cmdline)
|
||||
{
|
||||
if (peinfo->use_unicode)
|
||||
{
|
||||
if (!exec_entrypoint_inthread(peinfo->DllParam, (PVOID)peinfo->cmdwline, NULL, NULL))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!exec_entrypoint_inthread(peinfo->DllParam, (PVOID)peinfo->cmdline, NULL, NULL))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!exec_entrypoint_inthread(peinfo->DllParam, NULL, NULL, NULL))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (peinfo->DllMain)
|
||||
{
|
||||
DPRINT("Executing DllMain(hinstDLL, DLL_PROCESS_ATTACH, NULL)");
|
||||
|
||||
if (!exec_entrypoint_inthread(peinfo->DllMain, peinfo->pe_base, (PVOID)DLL_PROCESS_ATTACH, NULL))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Executing %ls", peinfo->pe_wname);
|
||||
|
||||
if (!exec_entrypoint_inthread(peinfo->EntryPoint, NULL, NULL, NULL))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL set_thread_context(
|
||||
IN HANDLE hThread,
|
||||
IN PVOID Rip,
|
||||
@@ -146,7 +257,7 @@ BOOL resume_thread(
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL read_output(
|
||||
BOOL read_output_from_thread(
|
||||
IN PLOADED_PE_INFO peinfo,
|
||||
OUT PBOOL aborted)
|
||||
{
|
||||
@@ -272,6 +383,53 @@ BOOL read_output(
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL read_output_inthread(
|
||||
IN PLOADED_PE_INFO peinfo)
|
||||
{
|
||||
DWORD output_length = 0;
|
||||
PCHAR recv_buffer = NULL;
|
||||
|
||||
if (peinfo->nooutput)
|
||||
return TRUE;
|
||||
|
||||
recv_buffer = intAlloc(BUFFER_SIZE);
|
||||
if (!recv_buffer)
|
||||
{
|
||||
malloc_failed();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
do {
|
||||
// See if/how much data is available to be read from pipe
|
||||
if (!PeekNamedPipe(peinfo->Handles->hRead, NULL, 0, NULL, &output_length, NULL))
|
||||
{
|
||||
function_failed("PeekNamedPipe");
|
||||
}
|
||||
|
||||
// If there is data to be read, zero out buffer, read data, and send back to CS
|
||||
if (output_length)
|
||||
{
|
||||
memset(recv_buffer, 0, BUFFER_SIZE);
|
||||
|
||||
if (ReadFile((PVOID)peinfo->Handles->hRead, recv_buffer, BUFFER_SIZE - 1, NULL, NULL))
|
||||
{
|
||||
// Send output back
|
||||
PRINT("%s", recv_buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
function_failed("ReadFile");
|
||||
}
|
||||
}
|
||||
} while (output_length);
|
||||
|
||||
// Free results buffer
|
||||
memset(recv_buffer, 0, BUFFER_SIZE);
|
||||
intFree(recv_buffer);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL run_pe(
|
||||
IN PLOADED_PE_INFO peinfo)
|
||||
{
|
||||
@@ -288,19 +446,34 @@ BOOL run_pe(
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!prepare_thread(peinfo))
|
||||
if (peinfo->inthread)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (!run_pe_inthread(peinfo))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!resume_thread(peinfo))
|
||||
{
|
||||
return FALSE;
|
||||
if (!read_output_inthread(peinfo))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!read_output(peinfo, &aborted))
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
if (!prepare_thread(peinfo))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!resume_thread(peinfo))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!read_output_from_thread(peinfo, &aborted))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (peinfo->is_dll && peinfo->DllMain && !aborted && !peinfo->dont_unload)
|
||||
|
||||
@@ -739,6 +739,58 @@ HANDLE get_std_in_handle(VOID)
|
||||
return ProcessParameters->StandardInput;
|
||||
}
|
||||
|
||||
DWORD get_tid(VOID)
|
||||
{
|
||||
return (DWORD)(ULONG_PTR)((PTEB2)NtCurrentTeb())->ClientId.UniqueThread;
|
||||
}
|
||||
|
||||
VOID rtl_exit_user_thread(VOID)
|
||||
{
|
||||
PEXEC_CTX exec_ctx = BeaconGetValue(NC_EXEC_CTX);
|
||||
|
||||
// do we have a execution context saved?
|
||||
if (exec_ctx)
|
||||
{
|
||||
// ensure this is the main thread
|
||||
if (exec_ctx->Tid == get_tid())
|
||||
{
|
||||
// PE has exited, restore the execution context
|
||||
#ifdef _WIN64
|
||||
__asm__(
|
||||
"mov rsp, rax \n"
|
||||
"mov rbp, rdx \n"
|
||||
"jmp rcx \n"
|
||||
: // no outputs
|
||||
: "r" (exec_ctx->Rsp), // RAX IN
|
||||
"r" (exec_ctx->Rbp), // RDX IN
|
||||
"r" (exec_ctx->Rip) // RCX IN
|
||||
);
|
||||
#else
|
||||
__asm__(
|
||||
"mov esp, eax \n"
|
||||
"mov ebp, edx \n"
|
||||
"jmp ecx \n"
|
||||
: // no outputs
|
||||
: "r" (exec_ctx->Rsp), // EAX IN
|
||||
"r" (exec_ctx->Rbp), // EDX IN
|
||||
"r" (exec_ctx->Rip) // ECX IN
|
||||
);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// either there is no execution context saved or this is not the main thread, simply exit
|
||||
VOID ( WINAPI *RtlExitUserThread ) ( NTSTATUS ) = xGetProcAddress(xGetLibAddress("ntdll", TRUE, NULL), "RtlExitUserThread", 0);
|
||||
if (RtlExitUserThread)
|
||||
{
|
||||
return RtlExitUserThread(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
api_not_found("RtlExitUserThread");
|
||||
}
|
||||
}
|
||||
|
||||
BOOL create_thread(
|
||||
OUT PHANDLE hThread)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user