最近同事在Jenkins上构建产品时偶尔出现签名工具(signtool)一直不返回结果,造成编译被Block。编译团队的同事查了两三天,尝试了各种解决方案都没有解决,于是找到我来定位原因。
查问题的思路很简单,在出问题后,首先到构建机器上抓一个signtool的dump,分析堆栈查看主线程目前的状态。但是任务管理器抓的dump存在一些问题,无法解析出主线程的堆栈。因此尝试使用procexp查看堆栈。
procexp看过以后,问题很明显。主线程的堆栈中出现了 user32!DialogBoxParamW,这表示signtool触发了一个模态对话框并且因为没有人操作对话框,因此signtool就卡住了。
但是问题又来了,signtool目前运行在session 0下,也就是在控制台session中,作为普通的用户登录是无法访问session 0的用户对象,所以无法知道弹出的对话框是什么内容。解决的办法也很简单,既然我们有dump,那么通过 dps 主线程堆栈就能大概还原出主线程的堆栈,也就能找到 user32!DialogBoxParamW 调用的参数。
不出所料,手工恢复了堆栈后,可以清晰地看出user32!DialogBoxParamW 的参数,其中第二个参数 0x65。
INT_PTR DialogBoxParamW(
[in, optional] HINSTANCE hInstance,
[in] LPCWSTR lpTemplateName,
[in, optional] HWND hWndParent,
[in, optional] DLGPROC lpDialogFunc,
[in] LPARAM dwInitParam
);
[in] lpTemplateName
Type: LPCTSTR
The dialog box template. This parameter is either the pointer to a null-terminated character string that specifies the name of the dialog box template or an integer value that specifies the resource identifier of the dialog box template. If the parameter specifies a resource identifier, its high-order word must be zero and its low-order word must contain the identifier. You can use the MAKEINTRESOURCE macro to create this value.
从MSDN的描述可以看出,第二个参数标识对话框模板的名字,它也可以是一个资源ID。因为对应的实参是0x65,因此其肯定是资源的ID。那么接下来我们就要找到对应ID对应的资源。
从堆栈的图中我们可以看出出问题的模块是 VenafiCsp.dll。从构建机器上找到对应的dll后,将其随意拖到某个PE分析工具中,查看0x65对应的ID,直接可以到对话框的标题与内容。
对话框的提示已经很明显了,编译团队的同事根据提示查找解决的办法,案件侦破到此结束。