前言
现象描述:Chrome在运行当中会导致Cookies文件被占用,同时不能进行复制等操作。
我们可以通过一段简单的代码复现上述现象
HANDLE hFile = CreateFileA("f:\temp\hello.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
printf("Last Error Code = %dn", GetLastError());
else
printf("File Handle = %pn", hFile);
getchar();
运行程序之后,我们尝试复制hello.txt的时候就会出现相同的问题。
当使用CreateFile创建文件句柄同时没有赋予其他人FILE_SHARE_READ权限时,就会出现文件被占用时无法进行复制删除等操作,这实际上是我们无法创建文件对象的表现,倘若我们拥有共享读或者其他共享权限,我们便能够创建新的文件对象,这一点可以通过ProcessHacker查看。
正文
自以为是的办法
既然如此,我们是否可以通过共用同一个内核文件对象?答案是可以的,只需要调用DuplicateHandle即可
DuplicateHandle的声明
BOOL DuplicateHandle(
[in] HANDLE hSourceProcessHandle,
[in] HANDLE hSourceHandle,
[in] HANDLE hTargetProcessHandle,
[out] LPHANDLE lpTargetHandle,
[in] DWORD dwDesiredAccess,
[in] BOOL bInheritHandle,
[in] DWORD dwOptions
);
假定我们在A进程复制B进程的C对象句柄并保存到D中,那对应的参数含义如下:
hSourceProcessHandle: B进程句柄
hSourceHandle:B进程中C对象句柄
hTargetProcessHandle:A进程句柄
hTargetHadle:A进程中的D,用来保存复制的句柄
dwDesiredAccess 请求新的权限,bInheritHandle 是否可以继承 dwOptions 其他选项,常用DUPLICATE_SAME_ACCESS
DuplicateHandle的作用
可以在当前进程或者两个进程中使用,无论如何他都可以复制某个对象句柄,拥有比之前相同或者更多的权限,同时在当前进程中使用此函数还可以将通过GetCurrentProcess等获得的伪句柄转换为真实的句柄。
据MSDN描述在某些情况下可能无法获得比之前更高的权限,比如当某一个文件对象只有GENERIC_READ权限时,你不能通过此函数同时获得GENERIC_READ|GENERIC_WRITE
关于上述的两个特点可以通过如下代码进行验证
/*
However, in other cases, DuplicateHandle cannot create a handle with more access rights than the original. For example, a file handle created with the GENERIC_READ access right cannot be duplicated so that it has both the GENERIC_READ and GENERIC_WRITE access right.
*/
HANDLE DupFile = NULL;
DuplicateHandle(GetCurrentProcess(), hFile, GetCurrentProcess(), &DupFile, GENERIC_READ | GENERIC_WRITE, FALSE, 0); //failed
if(DupFile)
printf("New File Handle = %pn", DupFile);
/*
If hSourceHandle is a pseudo handle returned by GetCurrentProcess or GetCurrentThread, DuplicateHandle converts it to a real handle to a process or thread, respectively.
*/
HANDLE DupProcess = NULL;
DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &DupProcess, 0, FALSE, DUPLICATE_SAME_ACCESS);
if (DupProcess)
printf("ProcessHandle = %p New Process Handle = %pn", GetCurrentProcess(),DupProcess);
如果我们通过复制cookies文件句柄并获得了与Chrome进程对此一致的权限,理论上我们就可以实现对文件的读写,然后将文件内容读到内存并保存到文件不就可以了吗。
就DuplicateHandle声明而言,我们首先遇到的问题是如何获得cookies文件句柄值?通过ProcessHacker可以很轻易的查看对应的文件及其句柄值
对于代码实现第一步我们可以先通过NtQuerySystemInformation并指定检索类型为SystemHandleInformation获取系统上所有打开句柄的信息
NtQuerySystemInformation(SystemHandleInformation, PSysInfo, SysInfoLen, &RetLen);
第二步遍历所有获得的句柄,并比较句柄所属进程ID是否等于用于网络服务的chrome进程ID,我们可以通过如下命令获得此进程ID,当然也可以用代码实现:)
wmic process Where "CommandLine Like '%network.mojom.NetworkService%' and caption = 'chrome.exe'" get processid /value
比较句柄部分代码
for (DWORD i = 0; i < PSysInfo->NumberOfHandles; i++)
{
PHandleEntry = &(PSysInfo->Handles[i]);
if (PHandleEntry->UniqueProcessId != TargetPid) continue;
......
}
第三步打开进程并获得进程句柄,后面作为DuplicateHandle的第一参数
hProcHandle = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_LIMITED_INFORMATION, FALSE, (DWORD)PHandleEntry->UniqueProcessId);
至此顺利的话,我们就能够复制一份chrome中某个对象的句柄到我们的进程中,但我们仍不能确定这个句柄就是我们想要的,因为进程中打开的句柄实在是太多了。
所以第四步就是利用NtQueryObject来获取句柄的详细信息
NtQueryObject(ObjInfo->Handle, ObjectNameInformation, &ObjInfo->ObjNameInfo, sizeof(ObjInfo->ObjNameInfo), NULL);
有了句柄信息,我们可以获得句柄是否是文件类型,具体是哪个文件,是否是我们要找的cookies文件,如果是的话,我们就执行打开文件,读取文件,写入文件。
那为什么此处没有示例代码:P,因为我发现得到的最终文件并不是数据库(DB)类型的文件,大家都知道的事cookies应该是一个以SQLite format 3开头的数据库格式文件
注:现在想来我并不清楚是不是在读写文件时应该将文件指针指向起始位置,但我也懒得去验证了
又看了看chrome进程打开的所有句柄时,发现cookies还有一个section对象,并且在内存中确实是数据库类型,既然如此不如直接查找所有的section类型的对象再次进行判断,然后将其映射到我们的进程中来,再写入文件?
事实上我可以通过NtQueryObject获得文件类型对象的路径所在,但却获取不到section类型对象的路径,所以我只能采取下策,将所有开头是数据库格式的section都映射过来并写入文件。
映射
NtMapViewOfSection(PObjInfo->Handle, NtCurrentProcess(), &MapFileBaseAddress, 0, 1024, 0, &MapSize, ViewShare, 0, PAGE_READONLY);
比较
MemMem(MapFileBaseAddress, MapSize, "SQLite format 3", 15)
写入
WriteFile(NewFile, MapFileBaseAddress, MapSize, &BytesRead, NULL);
在完整这一通操作之后,我长舒一口气,沉浸在自以为是的喜悦中,直到.....我看到可以利用VSS(Volume Shadow Copy Service)进行文件拷贝时,明明可以使用简单的方法,为什么非得搞这些花里胡哨的东西,而且通用性又不高?太狭隘了,格局完全没有打开
简单且有效的方法
关于VSS已经有足够的文章帖子让大家了解,在这里就不多赘述了,可以参考三好学生之前的一篇文章
如果你仍然觉得太过于麻烦,以管理员运行如下命令即可
C:WINDOWSsystem32esentutl.exe /y .Cookies /vss /d cookies-back
再后来有个小兄弟私信我说可不可以强制结束掉网络相关chrome进程,这样目标不会有感知,同时利用时间差来复制Cookies文件呢?虽然我没试过,但是我觉得理论上应该是可行的
有时候太过于执着某类技术,很容易让人掉进技术陷阱,就类似于太空铅笔的故事,也许解决问题之初就应该想想简单的办法,而非上来就是用“高数”,这样不仅为难了自己,效率还很低下。
引用
https://3gstudent.github.io/%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%95%E4%B8%AD%E7%9A%84Volume-Shadow-Copy
原文始发于微信公众号(无名之):从复制被占用Cookies文件的自我审视
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论