PVOID NTAPI HookRtlAllocateHeap(HANDLE HeapBase, ULONG Flags, SIZE_T Bytes) { ULONG_PTR Protect, Size; PVOID First, Memory, Second; Size = ROUND_UP(Bytes, MEMORY_PAGE_SIZE) + MEMORY_PAGE_SIZE * 2; Memory = NULL; Nt_AllocateMemory(NtCurrentProcess(), &Memory, Size, PAGE_EXECUTE_READWRITE, MEM_RESERVE); Nt_AllocateMemory(NtCurrentProcess(), &Memory, Size - MEMORY_PAGE_SIZE, PAGE_EXECUTE_READWRITE, MEM_COMMIT); Second = PtrAdd(Memory, Size - MEMORY_PAGE_SIZE); Nt_AllocateMemory(NtCurrentProcess(), &Second, MEMORY_PAGE_SIZE, PAGE_READONLY, MEM_COMMIT); Memory = PtrSub(Second, Bytes); *(PULONG_PTR)PtrSub(Memory, sizeof(PVOID)) = Bytes; return Memory; }
NTSTATUS ModifySelfSizeOfImage(LPWSTR ExeFullPath, LPWSTR CommandLine, ULONG SizeOfImage) { BOOL Result; ULONG Length; PVOID FakeCPInfoBuffer; WCHAR CmdFullPath[MAX_NTPATH]; PWCHAR CmdLineBuffer; NTSTATUS Status; PLDR_MODULE LdrModule; PIMAGE_DOS_HEADER DosHeader; PIMAGE_NT_HEADERS NtHeader; PIMAGE_SECTION_HEADER SectionHeader; FAKE_CREATE_PROCESS_INFO *fcpi; PROCESS_INFORMATION ProcessInformation; CONTEXT Context; NtFileDisk file; UNICODE_STRING ExeNtPath, *ProcessCommandLine; UNREFERENCED_PARAMETER(CommandLine); LdrModule = Nt_FindLdrModuleByName(NULL); DosHeader = (PIMAGE_DOS_HEADER)&__ImageBase; NtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)DosHeader + DosHeader->e_lfanew); fcpi = (FAKE_CREATE_PROCESS_INFO *)AllocStack(0x2000); fcpi->PeHeaderSize = (ULONG_PTR)(IMAGE_FIRST_SECTION(NtHeader) + NtHeader->FileHeader.NumberOfSections) - (ULONG_PTR)DosHeader; Status = file.Open(LdrModule->FullDllName.Buffer); if (!NT_SUCCESS(Status)) return Status; Status = file.Read(fcpi->PeHeader, fcpi->PeHeaderSize); if (!NT_SUCCESS(Status)) return Status; CmdLineBuffer = (PWCHAR)((ULONG_PTR)fcpi->PeHeader + fcpi->PeHeaderSize); fcpi->CommandLine.Buffer = CmdLineBuffer; fcpi->CommandLine.Length = (USHORT)(StrLengthW(ExeFullPath) * sizeof(WCHAR)); ProcessCommandLine = &Nt_CurrentPeb()->ProcessParameters->CommandLine; CopyMemory(CmdLineBuffer, ProcessCommandLine->Buffer, ProcessCommandLine->Length); *(PULONG_PTR)&CmdLineBuffer += ProcessCommandLine->Length; CmdLineBuffer[0] = 0; fcpi->CommandLine.Length = ProcessCommandLine->Length; fcpi->CommandLine.MaximumLength = fcpi->CommandLine.Length + sizeof(WCHAR); ++CmdLineBuffer; CmdLineBuffer = (PWCHAR)ROUND_UP((ULONG_PTR)CmdLineBuffer, 16); RtlDosPathNameToNtPathName_U(LdrModule->FullDllName.Buffer, &ExeNtPath, NULL, NULL); fcpi->ExeNtPath.Buffer = CmdLineBuffer; CopyMemory(CmdLineBuffer, ExeNtPath.Buffer, ExeNtPath.Length); *(PULONG_PTR)&CmdLineBuffer += ExeNtPath.Length; CmdLineBuffer[0] = 0; fcpi->ExeNtPath.Length = ExeNtPath.Length; fcpi->ExeNtPath.MaximumLength = fcpi->ExeNtPath.Length + sizeof(WCHAR); *CmdLineBuffer++ = 0; RtlFreeUnicodeString(&ExeNtPath); DosHeader = (PIMAGE_DOS_HEADER)fcpi->PeHeader; NtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)DosHeader + DosHeader->e_lfanew); SectionHeader = IMAGE_FIRST_SECTION(NtHeader); SectionHeader += NtHeader->FileHeader.NumberOfSections - 1; SizeOfImage -= LdrModule->SizeOfImage; SizeOfImage = ROUND_UP(SizeOfImage, MEMORY_PAGE_SIZE); SectionHeader->Misc.VirtualSize = ROUND_UP(SectionHeader->Misc.VirtualSize, MEMORY_PAGE_SIZE) + SizeOfImage; if (NtHeader->FileHeader.SizeOfOptionalHeader > FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, SizeOfImage) + RTL_FIELD_SIZE(IMAGE_OPTIONAL_HEADER, SizeOfImage)) NtHeader->OptionalHeader.SizeOfImage += SizeOfImage; Length = Nt_GetSystemDirectory(CmdFullPath, countof(CmdFullPath)); StrCopyW(CmdFullPath + Length, L"cmd.exe"); ProcessInformation.hProcess = NtCurrentProcess(); ProcessInformation.hThread = NtCurrentThread(); #if 1 Result = Nt_CreateProcess(NULL, CmdFullPath, NULL, CREATE_SUSPENDED, NULL, &ProcessInformation); if (!Result) return STATUS_UNSUCCESSFUL; #endif FakeCPInfoBuffer = NULL; LOOP_ONCE { ULONG_PTR Offset; Status = NtDuplicateObject( NtCurrentProcess(), NtCurrentProcess(), ProcessInformation.hProcess, &fcpi->ProcessHandle, 0, 0, DUPLICATE_SAME_ACCESS ); if (!NT_SUCCESS(Status)) break; /* Status = NtDuplicateObject( NtCurrentProcess(), file, ProcessInformation.hProcess, &fcpi->FileHandle, 0, 0, DUPLICATE_SAME_ACCESS ); if (!NT_SUCCESS(Status)) break; */ Status = Nt_AllocateMemory(ProcessInformation.hProcess, &FakeCPInfoBuffer, MEMORY_PAGE_SIZE); if (!NT_SUCCESS(Status)) break; fcpi->CreateProcessInternalW = CreateProcessInternalW; fcpi->NtTerminateProcess = NtTerminateProcess; fcpi->LdrShutdownProcess = LdrShutdownProcess; fcpi->NtCreateFile = NtCreateFile; fcpi->NtWriteFile = NtWriteFile; fcpi->NtClose = NtClose; fcpi->NtWaitForSingleObject = NtWaitForSingleObject; fcpi->InitialDirectory.Buffer = NULL; Offset = (ULONG_PTR)FakeCPInfoBuffer - (ULONG_PTR)fcpi; *(PULONG_PTR)&fcpi->CommandLine.Buffer += Offset; *(PULONG_PTR)&fcpi->ExeNtPath.Buffer += Offset; Status = Nt_WriteMemory( ProcessInformation.hProcess, FakeCPInfoBuffer, fcpi, (ULONG_PTR)CmdLineBuffer - (ULONG_PTR)fcpi, &Length ); if (!NT_SUCCESS(Status)) break; Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; Status = NtGetContextThread(ProcessInformation.hThread, &Context); if (!NT_SUCCESS(Status)) break; Context.Eip = (ULONG_PTR)FakeCPInfoBuffer + Length; Context.Eip = ROUND_UP(Context.Eip, 16); Context.Ecx = (ULONG_PTR)FakeCPInfoBuffer; Status = Nt_WriteMemory( ProcessInformation.hProcess, (PVOID)Context.Eip, ModifySizeOfImage, (ULONG_PTR)ModifySizeOfImageEnd - (ULONG_PTR)ModifySizeOfImage, &Length ); if (!NT_SUCCESS(Status)) break; #if 1 Status = NtSetContextThread(ProcessInformation.hThread, &Context); if (!NT_SUCCESS(Status)) break; Status = NtResumeThread(ProcessInformation.hThread, NULL); #else INLINE_ASM jmp Context.Eip; #endif } if (!NT_SUCCESS(Status)) { if (FakeCPInfoBuffer != NULL) Nt_FreeMemory(ProcessInformation.hProcess, FakeCPInfoBuffer); NtTerminateProcess(ProcessInformation.hProcess, 0); } NtClose(ProcessInformation.hProcess); NtClose(ProcessInformation.hThread); return Status; }
NTSTATUS InjectSelfToRemoteProcess(HANDLE hProcess, HANDLE hThread) { NTSTATUS Status; PVOID pvBuffer; DWORD Length; WCHAR szSelfPath[MAX_PATH]; CONTEXT ThreadContext; LARGE_INTEGER TimeOut; INJECT_DLL_CURRENT_THREAD inj; ThreadContext.ContextFlags = CONTEXT_CONTROL; Status = NtGetContextThread(hThread, &ThreadContext); if (!NT_SUCCESS(Status)) { // BaseSetLastNTError(Status); // PrintError(RtlGetLastWin32Error()); return Status; } // PrintConsoleW(L"Eip = %08X\n", ThreadContext.Eip); // getch(); Length = Nt_GetExeDirectory(szSelfPath, countof(szSelfPath)); if (Length == NULL) return STATUS_UNSUCCESSFUL; static WCHAR szDll[] = L"LocaleEmulator.dll"; StrCopyW(szSelfPath + Length, szDll); Length += CONST_STRLEN(szDll); pvBuffer = NULL; Status = Nt_AllocateMemory(hProcess, &pvBuffer, MEMORY_PAGE_SIZE); if (!NT_SUCCESS(Status)) { // BaseSetLastNTError(Status); // PrintError(RtlGetLastWin32Error()); return Status; } Length *= sizeof(WCHAR); inj.pfLdrLoadDll = LdrLoadDll; inj.ReturnAddr = ThreadContext.Eip; inj.ModuleFileName.Length = Length; inj.ModuleFileName.MaximumLength = Length + sizeof(WCHAR); inj.ModuleFileName.Buffer = (LPWSTR)((ULONG_PTR)pvBuffer + sizeof(inj)); Status = STATUS_UNSUCCESSFUL; LOOP_ONCE { Status = Nt_WriteMemory(hProcess, pvBuffer, &inj, sizeof(inj)); if (!NT_SUCCESS(Status)) break; Length += sizeof(WCHAR); Status = Nt_WriteMemory(hProcess, (PVOID)((ULONG_PTR)pvBuffer + sizeof(inj)), szSelfPath, Length); if (!NT_SUCCESS(Status)) break; ThreadContext.Eip = (DWORD)(PBYTE)pvBuffer + sizeof(inj) + Length; Status = Nt_WriteMemory( hProcess, (PVOID)ThreadContext.Eip, LoadExternDll, (ULONG_PTR)_LoadExternDllEnd - (ULONG_PTR)LoadExternDll ); if (!NT_SUCCESS(Status)) break; Status = NtSetContextThread(hThread, &ThreadContext); if (!NT_SUCCESS(Status)) break; Status = NtResumeThread(hThread, NULL); if (!NT_SUCCESS(Status)) break; BaseFormatTimeOut(&TimeOut, 500); for (DWORD TryTimes = 30; TryTimes; --TryTimes) { DWORD Val; Status = Nt_ReadMemory(hProcess, pvBuffer, &Val, sizeof(Val)); if (!NT_SUCCESS(Status)) break; if (Val != 0) { NtDelayExecution(FALSE, &TimeOut); continue; } break; } if (!NT_SUCCESS(Status)) break; NtDelayExecution(FALSE, &TimeOut); Status = NtGetContextThread(hThread, &ThreadContext); if (!NT_SUCCESS(Status)) break; if ((ULONG_PTR)ThreadContext.Eip < (ULONG_PTR)pvBuffer || (ULONG_PTR)ThreadContext.Eip > (ULONG_PTR)pvBuffer + MEMORY_PAGE_SIZE) { Status = STATUS_SUCCESS; } else { Status = STATUS_UNSUCCESSFUL; } } // BaseSetLastNTError(Status); // PrintError(RtlGetLastWin32Error()); // Nt_FreeMemory(hProcess, pvBuffer); return Status; }