Beispiel #1
0
        public void LoadFromFile(string filePath, FileStream fileStream)
        {
            FilePath    = filePath;
            FileName    = Path.GetFileNameWithoutExtension(FilePath);
            FilePointer = 0;

            // Get file size
            RealFileSize    = fileStream.Length;
            VirtualFileSize = RealFileSize;

            // Read header to determine where the data starts & so we can read all of the headers
            DwPackHeader header = new DwPackHeader();

            fileStream.Read(SpanHelper.AsSpan <DwPackHeader, byte>(ref header));

            // Read the rest of the header data
            var length = sizeof(DwPackHeader) + (sizeof(DwPackEntry) * header.FileCount);
            var buffer = (byte *)Marshal.AllocHGlobal(length);

            fileStream.Seek(0, SeekOrigin.Begin);
            fileStream.Read(new Span <byte>(buffer, length));
            Native = new DwPackPtr(buffer);

            for (int i = 0; i < Native.Header->FileCount; i++)
            {
                var entry = new VirtualDwPackEntry(mLogger, this, Native.Entries + i, i);
                Entries.Add(entry);
                mMapper.Map(DataBaseOffset + entry.Native->DataOffset, entry.Native->CompressedSize, true);
            }
        }
 private void LoadEntries()
 {
     for (int i = 0; i < Native.Header->FileCount; i++)
     {
         var entry = new VirtualDwPackEntry(mLogger, this, Native.Entries + i);
         Entries.Add(entry);
         mMapper.Map(DataBaseOffset + entry.Native->DataOffset, entry.Native->CompressedSize, true);
     }
 }
        private NtStatus ReadFile(IntPtr handle, IntPtr hEvent, IntPtr *apcRoutine, IntPtr *apcContext,
                                  ref Native.IO_STATUS_BLOCK ioStatus, byte *buffer, uint length, LARGE_INTEGER *byteOffset, IntPtr key,
                                  VirtualDwPack pack, long offset, long effOffset)
        {
            // File data read
            NtStatus result = NtStatus.Success;

            for (int i = 0; i < pack.Entries.Count; i++)
            {
                var entry      = pack.Entries[i];
                var dataOffset = (pack.Native.Data + entry.Native->DataOffset) - pack.Native.Ptr;
                if (effOffset < dataOffset || effOffset >= (dataOffset + entry.Native->CompressedSize))
                {
                    continue;
                }

                var fileDataOffset = effOffset - dataOffset;
                var readEndOffset  = fileDataOffset + length;
                if (readEndOffset > entry.Native->CompressedSize)
                {
                    continue;
                }

                // Make sure the file has been redirected
                // This is done as late as possible to improve startup times
                if (!entry.IsRedirected)
                {
                    mLogger.Info($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Data access Offset: 0x{effOffset:X8} Length: 0x{length:X8}");
                    result = mHooks.NtReadFileHook.OriginalFunction(handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key);
                }
                else
                {
                    mLogger.Info($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Data access Offset: 0x{effOffset:X8} Length: 0x{length:X8} redirected to {entry.RedirectedFilePath}");
                    result = NtStatus.Success;

                    if (fileDataOffset < 0)
                    {
                        mLogger.Error($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Offset is before start of data!!!");
                    }
                    else if (fileDataOffset > entry.RedirectedFileSize)
                    {
                        mLogger.Error($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Offset is after end of data!!!");
                    }

                    mLogger.Debug($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Reading 0x{length:X8} bytes from redirected file at offset 0x{fileDataOffset:X8}");

                    // Get cached file stream if the file was previously opened or open a new file
                    Stream redirectedStream;
                    if (mCachedFile == entry)
                    {
                        redirectedStream = mCachedFileStream;
                    }
                    else
                    {
                        mCachedFileStream?.Close();
                        mCachedFile       = entry;
                        mCachedFileStream = redirectedStream = entry.OpenRead();
                    }

                    // Read from redirected file into the buffer
                    try
                    {
                        redirectedStream.Seek(fileDataOffset, SeekOrigin.Begin);
                        var readBytes = redirectedStream.Read(new Span <byte>(( void * )buffer, ( int )length));
                        SetBytesRead(handle, ( int )offset, ( int )length, ref ioStatus);

                        if (readBytes != length)
                        {
                            mLogger.Error($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) File read length doesnt match requested read length!! Expected 0x{length:X8}, Actual 0x{readBytes:X8}");
                        }

                        mLogger.Debug($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Wrote redirected file to buffer");
                    }
                    catch (Exception e)
                    {
                        mLogger.Debug($"{pack.FileName} Hnd: {handle} Idx: {i} {entry.Native->Path} Unhandled exception thrown during reading {entry.RedirectedFilePath}: {e}");
                    }
                }

                // Return early, we're done here
                return(result);
            }

            mLogger.Error($"{pack.FileName} Hnd: {handle} Unhandled file data read request!! Offset: 0x{effOffset:X8} Length: 0x{length:X8}");
            return(mHooks.NtReadFileHook.OriginalFunction(handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key));
        }