NTSTATUS GetExeImageSize(LPWSTR ExeFullPath, PULONG SizeOfImage) { ULONG Size; NTSTATUS Status; NtFileDisk file; IMAGE_DOS_HEADER DosHeader; IMAGE_NT_HEADERS NtHeader; PIMAGE_OPTIONAL_HEADER OptionalHeader; PIMAGE_SECTION_HEADER SectionHeader; Status = file.Open(ExeFullPath); if (!NT_SUCCESS(Status)) return Status; Status = file.Read(&DosHeader, sizeof(DosHeader)); if (!NT_SUCCESS(Status)) return Status; if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) return STATUS_INVALID_IMAGE_WIN_32; Status = file.Seek(DosHeader.e_lfanew, FILE_BEGIN); if (!NT_SUCCESS(Status)) return Status; Status = file.Read(&NtHeader, sizeof(NtHeader) - sizeof(NtHeader.OptionalHeader)); if (!NT_SUCCESS(Status)) return Status; if (NtHeader.Signature != IMAGE_NT_SIGNATURE) return STATUS_INVALID_IMAGE_WIN_32; if (NtHeader.FileHeader.SizeOfOptionalHeader > FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, SizeOfImage) + RTL_FIELD_SIZE(IMAGE_OPTIONAL_HEADER, SizeOfImage)) { OptionalHeader = (PIMAGE_OPTIONAL_HEADER)AllocStack(NtHeader.FileHeader.SizeOfOptionalHeader); Status = file.Read(OptionalHeader, NtHeader.FileHeader.SizeOfOptionalHeader); if (!NT_SUCCESS(Status)) return Status; *SizeOfImage = OptionalHeader->SizeOfImage; return STATUS_SUCCESS; } SectionHeader = (PIMAGE_SECTION_HEADER)AllocStack(NtHeader.FileHeader.NumberOfSections * sizeof(*SectionHeader)); Status = file.Read(SectionHeader, NtHeader.FileHeader.NumberOfSections * sizeof(*SectionHeader)); if (!NT_SUCCESS(Status)) return Status; Size = 0; for (ULONG NumberOfSections = NtHeader.FileHeader.NumberOfSections; NumberOfSections; --NumberOfSections) { Size += SectionHeader->Misc.VirtualSize; ++SectionHeader; } Size += ROUND_UP(file.GetCurrentPos(), MEMORY_PAGE_SIZE); *SizeOfImage = Size; return STATUS_SUCCESS; }
void WriteLog(PCWSTR Format, ...) { #if ENABLE_LOG NtFileDisk log; WCHAR Buffer[0xFF0]; log.CreateIfNotExist(L"log.txt"); if (log.GetSize32() == 0) { ULONG BOM = BOM_UTF16_LE; log.Write(&BOM, 2); } log.Seek(0, FILE_END); log.Write(Buffer, vswprintf(Buffer, Format, (va_list)(&Format + 1)) * 2); log.Write(L"\r\n", 4); #endif }
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; }
UPK_STATUS NitroPlus:: Pack( PCWSTR InputPath, PCWSTR OutputFile /* = NULL */, PLARGE_INTEGER PackedFiles /* = NULL */, ULONG Flags /* = 0 */ ) { UNREFERENCED_PARAMETER(OutputFile); UNREFERENCED_PARAMETER(Flags); ULONG PathLength, Length, Hash, Offset; ULONG Size, CompressedSize, FileBufferSize, CompresseBufferSize; WCHAR FilePath[MAX_NTPATH]; PVOID NpaEntryBase, FileBuffer, CompresseBuffer; PBYTE NpaEntryBuffer; PWSTR FileName; NTSTATUS Status; LARGE_INTEGER FileCount, PackedFileCount; NITRO_PLUS_ENTRY *BaseEntry, *Entry; NITRO_PLUS_NPA_HEADER Header; NITRO_PLUS_NPA_ETNRY *Info; NtFileDisk File; if (PackedFiles == NULL) PackedFiles = &PackedFileCount; PackedFiles->QuadPart = 0; if (!EnumDirectoryFiles( (PVOID *)&BaseEntry, L"*.*", sizeof(*BaseEntry), InputPath, &FileCount, (EnumDirectoryFilesCallBackRoutine)QueryFileList, 0, EDF_SUBDIR) ) { return STATUS_UNSUCCESSFUL; } FileBufferSize = 0; CompresseBufferSize = 0; FileBuffer = NULL; CompresseBuffer = NULL; *(PULONG)&Header.Signature = NPA_HEADER_MAGIC; Header.Version = NPA_GCLX_VERSION; Header.EntryCount = FileCount.LowPart; Header.FileCount = FileCount.LowPart; Header.DirectoryCount = 0; Header.IsCompressed = TRUE; Header.IsEncrypted = TRUE; RtlRandom(&Header.Hash[0]); RtlRandom(&Header.Hash[1]); PathLength = StrLengthW(InputPath); if (OutputFile != NULL) { Status = m_File.Create(OutputFile); } else { FileName = FilePath + PathLength; CopyMemory(FilePath, InputPath, PathLength * sizeof(*FilePath)); if (FileName[-1] == '\\') --FileName; *(PULONG64)FileName = TAG4W('.npa'); FileName[4] = 0; Status = m_File.Create(FilePath); } if (!NT_SUCCESS(Status)) goto RETURN_POINT; PathLength += InputPath[PathLength - 1] != '\\'; NpaEntryBase = AllocateMemory(sizeof(*BaseEntry) * FileCount.LowPart); if (NpaEntryBase == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto RETURN_POINT; } NpaEntryBuffer = (PBYTE)NpaEntryBase; Entry = BaseEntry; for (ULONG Index = 0, Count = FileCount.LowPart; Count; ++Index, --Count) { Length = StrLengthW(Entry->FileName) - PathLength; Length = WideCharToMultiByte( CP_SHIFTJIS, 0, Entry->FileName + PathLength, Length, (PSTR)NpaEntryBuffer + 4, INT_MAX, NULL, NULL ); // Nt_UnicodeToAnsi((PSTR)NpaEntryBuffer + 4, INT_MAX, Entry->FileName + PathLength, Length, &Length); *(PULONG)NpaEntryBuffer = Length; NpaEntryBuffer += 4; Entry->DecryptLength = Length; Entry->Seed = HashBuffer(NpaEntryBuffer, Length); EncryptName(NpaEntryBuffer, Length, Index, &Header); NpaEntryBuffer += Length; NpaEntryBuffer += sizeof(*Info); ++Entry; } Header.EntrySize = PtrOffset(NpaEntryBuffer, NpaEntryBase); Hash = Header.Hash[0] * Header.Hash[1]; NpaEntryBuffer = (PBYTE)NpaEntryBase; Entry = BaseEntry; Offset = 0; m_File.Seek(Header.EntrySize + sizeof(Header), FILE_BEGIN); for (ULONG Index = 0, Count = FileCount.LowPart; Count; ++Index, --Count) { Status = File.Open(Entry->FileName); if (!NT_SUCCESS(Status)) break; Size = File.GetSize32(); if (FileBufferSize < Size) { FileBufferSize = Size; FileBuffer = ReAllocateMemory(FileBuffer, FileBufferSize); if (FileBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } } Status = File.Read(FileBuffer, Size); if (!NT_SUCCESS(Status)) break; CompressedSize = Size * 4; if (CompresseBufferSize < CompressedSize) { CompresseBufferSize = CompressedSize; CompresseBuffer = ReAllocateMemory(CompresseBuffer, CompresseBufferSize); if (CompresseBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } } CompressedSize = CompresseBufferSize; Status = compress2(CompresseBuffer, &CompressedSize, FileBuffer, Size, Z_BEST_COMPRESSION); if (Status != Z_OK) { Status = STATUS_UNSUCCESSFUL; break; } EncryptData( CompresseBuffer, MY_MIN(CompressedSize, Entry->DecryptLength + 0x1000), (Hash + Entry->Seed) * Size ); NpaEntryBuffer += *(PULONG)NpaEntryBuffer + 4; Info = (NITRO_PLUS_NPA_ETNRY *)NpaEntryBuffer; NpaEntryBuffer += sizeof(*Info); Info->FileType = NP_FILE_TYPE_FILE; Info->CompressedSize = CompressedSize; Info->Offset = Offset; Info->OriginalSize = Size; Info->DirectoryIndex = 0; Status = m_File.Write(CompresseBuffer, CompressedSize); if (!NT_SUCCESS(Status)) break; Offset += CompressedSize; ++Entry; } if (!NT_SUCCESS(Status)) goto RETURN_POINT; m_File.Seek(0, FILE_BEGIN); Status = m_File.Write(&Header, sizeof(Header)); if (!NT_SUCCESS(Status)) goto RETURN_POINT; Status = m_File.Write(NpaEntryBase, Header.EntrySize); if (!NT_SUCCESS(Status)) goto RETURN_POINT; PackedFiles->QuadPart = FileCount.QuadPart; RETURN_POINT: FreeMemory(FileBuffer); EnumDirectoryFilesFree(BaseEntry); return Status; }