Parse WebCacheV01.dat in C#

3k Views Asked by At

I'm looking to parse the WebCacheV01.dat file using C# to find the last file location for upload in an Internet browser.

%LocalAppData%\Microsoft\Windows\WebCache\WebCacheV01.dat

I using the Managed Esent nuget package.

  • Esent.Isam
  • Esent.Interop

When I try and run the below code it fails at:

Api.JetGetDatabaseFileInfo(filePath, out pageSize, JET_DbInfo.PageSize);

Or if I use

Api.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.CircularLog, 1, null);

at

Api.JetAttachDatabase(sesid, filePath, AttachDatabaseGrbit.ReadOnly);

I get the following error:

An unhandled exception of type 'Microsoft.Isam.Esent.Interop.EsentFileAccessDeniedException' occurred in Esent.Interop.dll

Additional information: Cannot access file, the file is locked or in use


string localAppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
string filePathExtra = @"\Microsoft\Windows\WebCache\WebCacheV01.dat";
string filePath = string.Format("{0}{1}", localAppDataPath, filePathExtra);

JET_INSTANCE instance;
JET_SESID sesid;
JET_DBID dbid;
JET_TABLEID tableid;
String connect = "";

JET_SNP snp;
JET_SNT snt;
object data;
int numInstance = 0;
JET_INSTANCE_INFO [] instances;
int pageSize;

JET_COLUMNDEF columndef = new JET_COLUMNDEF();
JET_COLUMNID columnid;

Api.JetCreateInstance(out instance, "instance");
Api.JetGetDatabaseFileInfo(filePath, out pageSize, JET_DbInfo.PageSize);
Api.JetSetSystemParameter(JET_INSTANCE.Nil, JET_SESID.Nil, JET_param.DatabasePageSize, pageSize, null);
//Api.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.CircularLog, 1, null);

Api.JetInit(ref instance);
Api.JetBeginSession(instance, out sesid, null, null);

//Do stuff in db

Api.JetEndSession(sesid, EndSessionGrbit.None);
Api.JetTerm(instance);

Is it not possible to read this without making modifications?


Viewer

http://www.nirsoft.net/utils/ese_database_view.html

Python

https://jon.glass/attempts-to-parse-webcachev01-dat/

3

There are 3 best solutions below

0
On

I'm thinking about using the 'Recent Items' folder as when you select a file to upload an entry is written here:

C:\Users\USER\AppData\Roaming\Microsoft\Windows\Recent

string recent = (Environment.GetFolderPath(Environment.SpecialFolder.Recent));
0
On

I was not able to get Adam's answer to work. What worked for me was making a copy with AlphaVSS (a .NET class library that has a managed API for the Volume Shadow Copy Service). The file was in "Dirty Shutdown" state, so I additionally wrote this to handle the exception it threw when I opened it:

catch (EsentErrorException ex)
{   // Usually after the database is copied, it's in Dirty Shutdown state
    // This can be verified by running "esentutl.exe /Mh WebCacheV01.dat"
    logger.Info(ex.Message);
    switch (ex.Error)
    {
        case JET_err.SecondaryIndexCorrupted:
            logger.Info("Secondary Index Corrupted detected, exiting...");
            Api.JetTerm2(instance, TermGrbit.Complete);
            return false;
        case JET_err.DatabaseDirtyShutdown:
            logger.Info("Dirty shutdown detected, attempting to recover...");
            try
            {
                Api.JetTerm2(instance, TermGrbit.Complete);
                Process.Start("esentutl.exe", "/p /o " + newPath);
                Thread.Sleep(5000);
                Api.JetInit(ref instance);
                Api.JetBeginSession(instance, out sessionId, null, null);
                Api.JetAttachDatabase(sessionId, newPath, AttachDatabaseGrbit.None);
            }
            catch (Exception e2)
            {
                logger.Info("Could not recover database " + newPath + ", will try opening it one last time. If that doesn't work, try using other esentutl commands", e2);
            }
            break;
    }
}
0
On

Issue:

The file is probably in use.

Solution:

in order to free the locked file, please stop the Schedule Task -\Microsoft\Windows\Wininet\CacheTask.

The Code

    public override IEnumerable<string> GetBrowsingHistoryUrls(FileInfo fileInfo)
            {
                var fileName = fileInfo.FullName;
                var results = new List<string>();
                try
                {
                    int pageSize;
                    Api.JetGetDatabaseFileInfo(fileName, out pageSize, JET_DbInfo.PageSize);
                    SystemParameters.DatabasePageSize = pageSize;

                    using (var instance = new Instance("Browsing History"))
                    {
                        var param = new InstanceParameters(instance);
                        param.Recovery = false;
                        instance.Init();
                        using (var session = new Session(instance))
                        {
                            Api.JetAttachDatabase(session, fileName, AttachDatabaseGrbit.ReadOnly);
                            JET_DBID dbid;
                            Api.JetOpenDatabase(session, fileName, null, out dbid, OpenDatabaseGrbit.ReadOnly);

                            using (var tableContainers = new Table(session, dbid, "Containers", OpenTableGrbit.ReadOnly))
                            {
                                IDictionary<string, JET_COLUMNID> containerColumns = Api.GetColumnDictionary(session, tableContainers);

                                if (Api.TryMoveFirst(session, tableContainers))
                                {
                                    do
                                    {
                                        var retrieveColumnAsInt32 = Api.RetrieveColumnAsInt32(session, tableContainers, columnIds["ContainerId"]);
                                        if (retrieveColumnAsInt32 != null)
                                        {
                                            var containerId = (int)retrieveColumnAsInt32;
                                            using (var table = new Table(session, dbid, "Container_" + containerId, OpenTableGrbit.ReadOnly))
                                            {
                                                var tableColumns = Api.GetColumnDictionary(session, table);
                                                if (Api.TryMoveFirst(session, table))
                                                {
                                                    do
                                                    {

                                                        var url = Api.RetrieveColumnAsString(
                                                            session,
                                                            table,
                                                            tableColumns["Url"],
                                                            Encoding.Unicode);

                                                        var downloadedFileName = Api.RetrieveColumnAsString(
                                                        session,
                                                        table,
                                                        columnIds2["Filename"]);

                                                        if(string.IsNullOrEmpty(downloadedFileName))  // check for download history only.
                                                             continue;

                                                        // Order by access Time to find the last uploaded file.                                                     
                                                        var accessedTime = Api.RetrieveColumnAsInt64(
                                                        session,
                                                        table,
                                                        columnIds2["AccessedTime"]);
                                                        var lastVisitTime = accessedTime.HasValue ? DateTime.FromFileTimeUtc(accessedTime.Value) : DateTime.MinValue;


                                                        results.Add(url);

                                                    }
                                                    while (Api.TryMoveNext(session, table.JetTableid));
                                                }
                                            }
                                        }
                                    } while (Api.TryMoveNext(session, tableContainers));
                                }
                            }
                        }
                    }

                }
                catch (Exception ex)
                {
                    // log goes here....
                }

                return results;
            }

Utils

Task Scheduler Wrapper

You can use Microsoft.Win32.TaskScheduler.TaskService Wrapper to stop it using c#, just add this Nuget package [nuget]:https://taskscheduler.codeplex.com/

Usage

public static FileInfo CopyLockedFileRtl(DirectoryInfo directory, FileInfo fileInfo, string remoteEndPoint)
        {
            FileInfo copiedFileInfo = null;
            using (var ts = new TaskService(string.Format(@"\\{0}", remoteEndPoint)))
            {
                var task = ts.GetTask(@"\Microsoft\Windows\Wininet\CacheTask");
                task.Stop();
                task.Enabled = false;
                var byteArray = FileHelper.ReadOnlyAllBytes(fileInfo);
                var filePath = Path.Combine(directory.FullName, "unlockedfile.dat");
                File.WriteAllBytes(filePath, byteArray);
                copiedFileInfo = new FileInfo(filePath);
                task.Enabled = true;
                task.Run();
                task.Dispose();
            }

            return copiedFileInfo;
        }