切换到session 0

这是一个小技巧,可以帮助我们从session 1切换到session 0,并且获得system权限。有了system权限,可以做一些admin做不了的事情,具体哪些事情大伙可以自己挖掘。

1
2
切换到session 0: rundll32 winsta.dll WinStationSwitchToServicesSession
切换会原session: rundll32 winsta.dll WinStationRevertFromServicesSession

但是如果直接切换到session 0,会发现一个问题,我们没有桌面程序,所以什么事情也做不了。解决方法也很简单,创建一个explorer就可以了。但是普通方法创建explorer,怎么会不能创建到session 0,于是这里可想而知,我们需要一个服务来创建explorer。专门写一个服务程序未免太麻烦,这里可以使用cmd来快速创建explorer。

1
2
sc create desktop0 binpath= "cmd /c start explorer.exe" type= own type= interact
net start desktop0

虽然cmd不是服务,但是也会被运行起来,只不过不能与服务管理器交互,所以在超时的时候会被结束。不过那个时候已经没关系了,因为explorer已经创建起来了。接下来就可以切换了session 0,用system权限管理电脑了。

Tips

0cchext插件实用命令dttoc

最近给0cchext添加了一个实用的逆向命令,dttoc,这个命令可以把dt命令输出的结构体转化为C的结构,方便我们做逆向还原工作。

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
0:000> !0cchext.dttoc nt!_peb
struct _PEB {
BYTE InheritedAddressSpace;
BYTE ReadImageFileExecOptions;
BYTE BeingDebugged;
union {
BYTE BitField;
struct {
BYTE ImageUsesLargePages:1;
BYTE IsProtectedProcess:1;
BYTE IsImageDynamicallyRelocated:1;
BYTE SkipPatchingUser32Forwarders:1;
BYTE IsPackagedProcess:1;
BYTE IsAppContainer:1;
BYTE IsProtectedProcessLight:1;
BYTE IsLongPathAwareProcess:1;
};
};
VOID* Mutant;
VOID* ImageBaseAddress;
_PEB_LDR_DATA* Ldr;
_RTL_USER_PROCESS_PARAMETERS* ProcessParameters;
VOID* SubSystemData;
VOID* ProcessHeap;
_RTL_CRITICAL_SECTION* FastPebLock;
_SLIST_HEADER* AtlThunkSListPtr;
VOID* IFEOKey;
union {
DWORD CrossProcessFlags;
struct {
DWORD ProcessInJob:1;
DWORD ProcessInitializing:1;
DWORD ProcessUsingVEH:1;
DWORD ProcessUsingVCH:1;
DWORD ProcessUsingFTH:1;
DWORD ReservedBits0:27;
};
};
union {
VOID* KernelCallbackTable;
VOID* UserSharedInfoPtr;
};
DWORD SystemReserved[1];
_SLIST_HEADER* AtlThunkSListPtr32;
VOID* ApiSetMap;
DWORD TlsExpansionCounter;
VOID* TlsBitmap;
DWORD TlsBitmapBits[2];
VOID* ReadOnlySharedMemoryBase;
VOID* SparePvoid0;
VOID** ReadOnlyStaticServerData;
VOID* AnsiCodePageData;
VOID* OemCodePageData;
VOID* UnicodeCaseTableData;
DWORD NumberOfProcessors;
DWORD NtGlobalFlag;
_LARGE_INTEGER CriticalSectionTimeout;
DWORD HeapSegmentReserve;
DWORD HeapSegmentCommit;
DWORD HeapDeCommitTotalFreeThreshold;
DWORD HeapDeCommitFreeBlockThreshold;
DWORD NumberOfHeaps;
DWORD MaximumNumberOfHeaps;
VOID** ProcessHeaps;
VOID* GdiSharedHandleTable;
VOID* ProcessStarterHelper;
DWORD GdiDCAttributeList;
_RTL_CRITICAL_SECTION* LoaderLock;
DWORD OSMajorVersion;
DWORD OSMinorVersion;
WORD OSBuildNumber;
WORD OSCSDVersion;
DWORD OSPlatformId;
DWORD ImageSubsystem;
DWORD ImageSubsystemMajorVersion;
DWORD ImageSubsystemMinorVersion;
DWORD ActiveProcessAffinityMask;
DWORD GdiHandleBuffer[34];
void* PostProcessInitRoutine;
VOID* TlsExpansionBitmap;
DWORD TlsExpansionBitmapBits[32];
DWORD SessionId;
_ULARGE_INTEGER AppCompatFlags;
_ULARGE_INTEGER AppCompatFlagsUser;
VOID* pShimData;
VOID* AppCompatInfo;
_UNICODE_STRING CSDVersion;
_ACTIVATION_CONTEXT_DATA* ActivationContextData;
_ASSEMBLY_STORAGE_MAP* ProcessAssemblyStorageMap;
_ACTIVATION_CONTEXT_DATA* SystemDefaultActivationContextData;
_ASSEMBLY_STORAGE_MAP* SystemAssemblyStorageMap;
DWORD MinimumStackCommit;
_FLS_CALLBACK_INFO* FlsCallback;
_LIST_ENTRY FlsListHead;
VOID* FlsBitmap;
DWORD FlsBitmapBits[4];
DWORD FlsHighIndex;
VOID* WerRegistrationData;
VOID* WerShipAssertPtr;
VOID* pUnused;
VOID* pImageHeaderHash;
union {
DWORD TracingFlags;
struct {
QWORD HeapTracingEnabled:1;
QWORD CritSecTracingEnabled:1;
QWORD LibLoaderTracingEnabled:1;
QWORD SpareTracingBits:29;
};
};
QWORD CsrServerReadOnlySharedMemoryBase;
DWORD TppWorkerpListLock;
_LIST_ENTRY TppWorkerpList;
VOID* WaitOnAddressHashTable[128];
};

Debugging

Delphi异常0EEDFADE

0EEDFADE是Delphi内部异常代码,该异常通常有7个参数,我们用的上的是第二个参数,这个参数指向的是Exception的对象,通过这个对象,我们就可以查出异常的一些信息。

以Delphi XE2为例,Class name的偏移为(不同的版本偏移有所不同):

1
2
x86_vmtClassName = -56(0x38);
x64_vmtClassName = -112(0x70);

我们可以用如下命令获取相关信息:

1
2
x86: da poi(poi(exception_object)-38)+1;du /c 100 poi(exception_object+4)
x64: da poi(poi(exception_object)-70)+1;du /c 100 poi(exception_object+8)

以上命令就能获取异常的类名,而exception_object+sizeof(pointer)则是Exception Message的所在偏移,这是一个unicode string。实际效果如下:

1
2
3
0:002> da poi(poi(003a2800)-38)+1;du /c 100 poi(003a2800 +4)
00b9ec47 "TTransportExceptionUnknown"
00375b8c "ServerTransport.Accept() may not return NULL"

当然,我们也可以设置event filter去截获异常:

1
2
x86: sxe -c "da poi(poi(poi(@ebp+1c))-38)+1;du /c 100 poi(poi(@ebp+1c)+4)" 0EEDFADE
x64: sxe -c "da poi(poi(poi(@rbp+48))-70)+1;du /c 100 poi(poi(@rbp+48)+8)" 0EEDFADE

Debugging

Windows 10设置系统DPI

现在的显示器分辨率越来越高2K,4K甚至5K,而很多程序并不支持这一的高分辨率,所以这些程序在桌面上会显示的很小,好在Windows 8以后的系统中,我们可以设置DPI来放大程序的窗口,如下图所示:

20170309145111

但是,微软并没有把设置DPI的接口文档化。所以我把这个功能逆了一下,还原的代码如下:

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
/*
BOOL ApplyDpiSetting(int val);
val 为DPI要设置的数字,例如0是100%,1是125%,以此类推,注意250%以后是300%。
另外上面的对应关系只是通常情况下的,还有可能有其他对应关系,例如0是300%,-1是250%等等。
具体怎么对应可以通过GetDpiForMonitor函数来获取
*/
typedef struct _SET_DPI {
DISPLAYCONFIG_DEVICE_INFO_HEADER header;
ULONG val;
} SET_DPI;
BOOL ApplyDpiSetting(ULONG val)
{
UINT32 num_of_paths = 0;
UINT32 num_of_modes = 0;
DISPLAYCONFIG_PATH_INFO* display_paths = NULL;
DISPLAYCONFIG_MODE_INFO* display_modes = NULL;
BOOL retval = FALSE;
do
{
if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS,
&num_of_paths,
&num_of_modes) != ERROR_SUCCESS) {
break;
}
display_paths = (DISPLAYCONFIG_PATH_INFO*)calloc((int)num_of_paths, sizeof(DISPLAYCONFIG_PATH_INFO));
display_modes = (DISPLAYCONFIG_MODE_INFO*)calloc((int)num_of_modes, sizeof(DISPLAYCONFIG_MODE_INFO));
if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS,
&num_of_paths,
display_paths,
&num_of_modes,
display_modes,
NULL) != ERROR_SUCCESS) {
break;
}
SET_DPI dpi;
dpi.header.type = (DISPLAYCONFIG_DEVICE_INFO_TYPE)0xFFFFFFFC;
dpi.header.size = sizeof(dpi);
dpi.header.adapterId = display_paths[0].sourceInfo.adapterId;
dpi.header.id = display_paths[0].sourceInfo.id;
dpi.val = val;
if (DisplayConfigSetDeviceInfo((DISPLAYCONFIG_DEVICE_INFO_HEADER*)&dpi) == ERROR_SUCCESS) {
retval = TRUE;
}
} while (0);
if (display_paths) {
free(display_paths);
}
if (display_modes) {
free(display_modes);
}
return retval;
}

Tips

让编译器不推荐(deprecate)使用一个函数

在开发一些公共库函数的时候,我们常常会对函数进行改写,这个时候我们会希望使用者用新的函数。为了提醒使用者,我们可以通过将函数声明为deprecated,这样编译器在编译的时候会抛出一个C4995或者C4996的警告。这个警告我们应该也经常看到过,比如使用strcpy,编译器会提示我们使用strcpy_s。

使用这个编译器特性有两种方法:

  1. __declspec(deprecated)
  2. #pragma deprecated

当然我们还可以给警告自定义消息信息

1
__declspec(deprecated("** this is a deprecated function **")) void func2(int) {}

Tips

PDB 下载工具

前段时间微软的符号服务器特别不稳定,Windbg下载符号文件老是失败,所以就专门写了个pdb的下载工具(pdbdownloader)放到Github上。

P.S. 用WPF写界面确实是很有趣

20170103120319

Tips

快速抛出失败的方法 INT 29H

从Windows8开始,Windows设计了一个新的中断,INT 29H,用来快速的抛出失败。在sdk中,他被声明为 __fastfail:

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
#define FAST_FAIL_LEGACY_GS_VIOLATION 0
#define FAST_FAIL_VTGUARD_CHECK_FAILURE 1
#define FAST_FAIL_STACK_COOKIE_CHECK_FAILURE 2
#define FAST_FAIL_CORRUPT_LIST_ENTRY 3
#define FAST_FAIL_INCORRECT_STACK 4
#define FAST_FAIL_INVALID_ARG 5
#define FAST_FAIL_GS_COOKIE_INIT 6
#define FAST_FAIL_FATAL_APP_EXIT 7
#define FAST_FAIL_RANGE_CHECK_FAILURE 8
#define FAST_FAIL_UNSAFE_REGISTRY_ACCESS 9
#define FAST_FAIL_GUARD_ICALL_CHECK_FAILURE 10
#define FAST_FAIL_GUARD_WRITE_CHECK_FAILURE 11
#define FAST_FAIL_INVALID_FIBER_SWITCH 12
#define FAST_FAIL_INVALID_SET_OF_CONTEXT 13
#define FAST_FAIL_INVALID_REFERENCE_COUNT 14
#define FAST_FAIL_INVALID_JUMP_BUFFER 18
#define FAST_FAIL_MRDATA_MODIFIED 19
#define FAST_FAIL_CERTIFICATION_FAILURE 20
#define FAST_FAIL_INVALID_EXCEPTION_CHAIN 21
#define FAST_FAIL_CRYPTO_LIBRARY 22
#define FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT 23
#define FAST_FAIL_INVALID_IMAGE_BASE 24
#define FAST_FAIL_DLOAD_PROTECTION_FAILURE 25
#define FAST_FAIL_UNSAFE_EXTENSION_CALL 26
#define FAST_FAIL_DEPRECATED_SERVICE_INVOKED 27
#define FAST_FAIL_INVALID_BUFFER_ACCESS 28
#define FAST_FAIL_INVALID_BALANCED_TREE 29
#define FAST_FAIL_INVALID_NEXT_THREAD 30
#define FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED 31 // Telemetry, nonfatal
#define FAST_FAIL_APCS_DISABLED 32
#define FAST_FAIL_INVALID_IDLE_STATE 33
#define FAST_FAIL_MRDATA_PROTECTION_FAILURE 34
#define FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION 35
#define FAST_FAIL_INVALID_FAST_FAIL_CODE 0xFFFFFFFF
#if _MSC_VER >= 1610
DECLSPEC_NORETURN
VOID
__fastfail(
_In_ unsigned int Code
);
#pragma intrinsic(__fastfail)
#endif
/*
// 汇编代码为
mov ecx, code
int 29h
*/

在中断代码执行后,操作系统会根据执行代码的环境来做出不同的处理。
如果fastfail发生在Ring0中,操作系统会抛出一个KERNEL_SECURITY_CHECK_FAILURE (0x139)的蓝屏。如果fastfail发生在Ring3,系统会抛出一个第二次机会的不可继续执行的异常,异常代码为0xC0000409,然后走进我们熟悉的Windows Error Reporting(WER)流程。另外,无论__fastfail发生在R0或者R3,如果有调试器正在调试系统或进程,都将得到一次中断到调试器的机会,这让我们能够看清楚具体发生了什么事情。但是正如我上面所说,这个是一个不可继续执行的异常,所以我们不能在调试器里处理了异常后让程序继续向前跑,当然也不能用try和except去捕获异常。

我觉得__fastfail是个非常不错的设计,它让程序可以快速的进入内核异常处理流程,不需要执行额外的用户层的代码,也不需要额外的内存空间,提高了不可恢复的异常处理的性能,更重要的是,简单快速不依赖内存的执行方式也保证了系统的安全。所以在系统的安全检查失败处理中,大量使用了这个方式,减少被攻击的可能性。

最后,如果INT 29H发生在Windows8以下的系统上,内核里会抛出一个常规的UNEXPECTED_KERNEL_MODE_TRAP的蓝屏,而用户层程序会抛出一个ACCESS VIOLATION的异常。

Debugging

windbg的lua脚本扩展luadbg

2012年的时候,我在blog上写到过开发了一个windbg的lua扩展dbglua,当时觉得windbg的原生脚本语法太奇怪了,而且太不容易使用。现在来看,依旧如此,只不过我已经很熟悉这个原生脚本了。而这个lua扩展反倒是没什么用,因为用起来也不太方便,比如访问结构体。

最近无意之中看了一眼pykd,他用重载.操作符的方式访问符号和结构体深深的吸引了我,感觉非常有趣。而python本身依赖比较多,这也促使我拿起之前的代码看了看,并且决定在github上重新建立这个项目叫做luadbg,这次我决定长期维护这个项目,想到新的功能就往里面写,就像我一直维护的0cchext一样。luadbg除了兼容了老dbglua的函数以外,还添加了几个我觉得很方便的类,主要是用重载.操作符的方式来访问模块和结构体的数据,效果如下图所示:

20161116113129

当然,也可以用!luacmd命令进入input模式,从而一条一条的输入语句来测试正确性。

Debugging

编译时自动增加build number

最近和朋友讨论版本号常用的几种规范,前三位<主版本>.<子版本>.<修正版本>基本上一致,不需要详说。主要区别产生在最后一位,有的是build number,有的是时间日期,还有的是git或者svn的revision。我习惯用build number,每次编译都会增加版本号最后一位的数字。但是手动去修改明显不科学也不可靠,所以给和我有一样习惯的朋友分享一个我早年写的python脚本,无论是自己的工具还是公司的产品我一直都在用这个。

1
用法就是在VS的工程属性Build Event -> Pre Build Event里设置x:\incbuildnum.py $(ProjectDir)$(ProjectName).rc。
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
import re
import os
import sys
import shutil
if os.path.isfile(sys.argv[1] + ".bak"):
os.remove(sys.argv[1] + ".bak")
shutil.copy(sys.argv[1], sys.argv[1] + ".bak")
with open(sys.argv[1], 'r+') as content_file:
content = content_file.read()
m = re.search("VALUE \"FileVersion\", \"(([\\d]+).[ ]*)*([\\d]+)\"", content)
new_ver = str(int(m.group(3)) + 1)
content = re.sub("(VALUE \"FileVersion\", \"([\\d]+.[ ]*)*)[\\d]+\"", "\\g<1>" + new_ver + "\"", content)
m = re.search("FILEVERSION (([\\d]+).[ ]*)*([\\d]+)", content)
new_ver = str(int(m.group(3)) + 1)
content = re.sub("(FILEVERSION ([\\d]+.[ ]*)*)([\\d]+)", "\\g<1>" + new_ver, content)
m = re.search("VALUE \"ProductVersion\", \"(([\\d]+).[ ]*)*([\\d]+)\"", content)
new_ver = str(int(m.group(3)) + 1)
content = re.sub("(VALUE \"ProductVersion\", \"([\\d]+.[ ]*)*)[\\d]+\"", "\\g<1>" + new_ver + "\"", content)
m = re.search("PRODUCTVERSION (([\\d]+).[ ]*)*([\\d]+)", content)
new_ver = str(int(m.group(3)) + 1)
content = re.sub("(PRODUCTVERSION ([\\d]+.[ ]*)*)([\\d]+)", "\\g<1>" + new_ver, content)
content_file.seek(0)
content_file.write(content)
content_file.truncate()
content_file.close()

Tips

验证文件签名

Sysinternal(http://forum.sysinternals.com/howto-verify-the-digital-signature-of-a-file_topic19247.html)上有关于验证签名的代码,不过代码有点问题,他只能验证PE签名,无法验证文件签名,所以我这里稍作了点修改,记录一下

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
BOOL CheckFileTrust(LPCTSTR filename, CString &signer_file)
{
HCATADMIN cat_admin_handle = NULL;
if (!CryptCATAdminAcquireContext(&cat_admin_handle, NULL, 0))
{
return FALSE;
}
HANDLE hFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
CryptCATAdminReleaseContext(cat_admin_handle, 0);
return FALSE;
}
DWORD hash_count = 100;
BYTE hash_data[100];
CryptCATAdminCalcHashFromFileHandle(hFile, &hash_count, hash_data, 0);
CloseHandle(hFile);
LPWSTR member_tag = new WCHAR[hash_count * 2 + 1];
for (DWORD dw = 0; dw < hash_count; ++dw)
{
wsprintfW(&member_tag[dw * 2], L"%02X", hash_data[dw]);
}
WINTRUST_DATA wd = { 0 };
WINTRUST_FILE_INFO wfi = { 0 };
WINTRUST_CATALOG_INFO wci = { 0 };
CATALOG_INFO ci = { 0 };
HCATINFO cat_admin_info = CryptCATAdminEnumCatalogFromHash(cat_admin_handle,
hash_data, hash_count, 0, NULL);
if (NULL == cat_admin_info)
{
wfi.cbStruct = sizeof(WINTRUST_FILE_INFO);
wfi.pcwszFilePath = filename;
wfi.hFile = NULL;
wfi.pgKnownSubject = NULL;
wd.cbStruct = sizeof(WINTRUST_DATA);
wd.dwUnionChoice = WTD_CHOICE_FILE;
wd.pFile = &wfi;
wd.dwUIChoice = WTD_UI_NONE;
wd.fdwRevocationChecks = WTD_REVOKE_NONE;
wd.dwStateAction = WTD_STATEACTION_IGNORE;
wd.dwProvFlags = WTD_SAFER_FLAG;
wd.hWVTStateData = NULL;
wd.pwszURLReference = NULL;
signer_file = filename;
}
else
{
CryptCATCatalogInfoFromContext(cat_admin_info, &ci, 0);
wci.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
wci.pcwszCatalogFilePath = ci.wszCatalogFile;
wci.pcwszMemberFilePath = filename;
wci.pcwszMemberTag = member_tag;
wci.pbCalculatedFileHash = hash_data;
wci.cbCalculatedFileHash = hash_count;
wd.cbStruct = sizeof(WINTRUST_DATA);
wd.dwUnionChoice = WTD_CHOICE_CATALOG;
wd.pCatalog = &wci;
wd.dwUIChoice = WTD_UI_NONE;
wd.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
wd.dwProvFlags = 0;
wd.hWVTStateData = NULL;
wd.pwszURLReference = NULL;
signer_file = ci.wszCatalogFile;
}
GUID action = WINTRUST_ACTION_GENERIC_VERIFY_V2;
HRESULT hr = WinVerifyTrust(NULL, &action, &wd);
BOOL retval = SUCCEEDED(hr);
if (NULL != cat_admin_info) {
CryptCATAdminReleaseCatalogContext(cat_admin_handle, cat_admin_info, 0);
}
CryptCATAdminReleaseContext(cat_admin_handle, 0);
delete[] member_tag;
return retval;
}
BOOL GetCertificateInfo(PCCERT_CONTEXT cert_context, CString &signer_name)
{
LPTSTR name = NULL;
DWORD data;
if (!(data = CertGetNameString(cert_context,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
NULL,
0))) {
return FALSE;
}
// Allocate memory for subject name.
name = (LPTSTR)LocalAlloc(LPTR, data * sizeof(TCHAR));
if (!name) {
return FALSE;
}
// Get subject name.
if (!(CertGetNameString(cert_context,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
name,
data))) {
LocalFree(name);
return FALSE;
}
signer_name = name;
LocalFree(name);
return TRUE;
}
BOOL GetFileSigner(LPCTSTR szFileName, CString &signer_name)
{
HCERTSTORE store_handle = NULL;
HCRYPTMSG msg_handle = NULL;
PCCERT_CONTEXT cert_context = NULL;
BOOL retval = FALSE;
DWORD encoding, content_type, format_type;
PCMSG_SIGNER_INFO signer_info = NULL;
DWORD signer_info_size;
CERT_INFO cert_info;
do
{
// Get message handle and store handle from the signed file.
retval = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
szFileName,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
CERT_QUERY_FORMAT_FLAG_BINARY,
0,
&encoding,
&content_type,
&format_type,
&store_handle,
&msg_handle,
NULL);
if (!retval) {
break;
}
// Get signer information size.
retval = CryptMsgGetParam(msg_handle,
CMSG_SIGNER_INFO_PARAM,
0,
NULL,
&signer_info_size);
if (!retval) {
break;
}
// Allocate memory for signer information.
signer_info = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, signer_info_size);
if (!signer_info) {
break;
}
// Get Signer Information.
retval = CryptMsgGetParam(msg_handle,
CMSG_SIGNER_INFO_PARAM,
0,
(PVOID)signer_info,
&signer_info_size);
if (!retval) {
break;
}
// Search for the signer certificate in the temporary
// certificate store.
cert_info.Issuer = signer_info->Issuer;
cert_info.SerialNumber = signer_info->SerialNumber;
cert_context = CertFindCertificateInStore(store_handle,
ENCODING,
0,
CERT_FIND_SUBJECT_CERT,
(PVOID)&cert_info,
NULL);
if (!cert_context) {
break;
}
retval = GetCertificateInfo(cert_context, signer_name);
} while (0);
if (signer_info != NULL) {
LocalFree(signer_info);
}
if (cert_context != NULL) {
CertFreeCertificateContext(cert_context);
}
if (store_handle != NULL) {
CertCloseStore(store_handle, 0);
}
if (msg_handle != NULL) {
CryptMsgClose(msg_handle);
}
return retval;
}

Tips