如何以编程方式清除 WinInet SSL 状态(是不是有 Windows API 调用)?
Posted
技术标签:
【中文标题】如何以编程方式清除 WinInet SSL 状态(是不是有 Windows API 调用)?【英文标题】:How to clear WinInet SSL state programmatically (is there a Windows API call)?如何以编程方式清除 WinInet SSL 状态(是否有 Windows API 调用)? 【发布时间】:2018-02-26 04:46:46 【问题描述】:我需要使用 Delphi 中的 API 函数来模拟与“Internet 选项”对话框(“内容”选项卡)中的“清除 SSL 状态”按钮相同的行为。
我的意图是将此与 WinInet 一起使用以建立后续独立的 SSL 连接。如果没有这个,两个 WinInet 连接共享相同的 SSL 状态,例如,阻止我更正错误的 SSL 证书密码。
两次连接尝试之间没有清除 SSL 状态,第一次返回“密码错误”,然后我更正密码并重试,但第二次尝试返回“安全通道支持错误”。
【问题讨论】:
对于那些投票结束我的问题的人,请仔细阅读。这是一个简单的问题,就像 Stack Overflow 上的任何其他问题一样。这不是题外话。我需要知道如何以编程方式执行上述按钮的相同行为,因为我找不到任何有用的参考。 【参考方案1】:终于!我成功了!
我使用出色的API Monitor 来监控整个 Internet 选项对话框,并且我设法发现了“清除 SSL 状态”按钮的作用。它仅按顺序执行两个 API 调用 SslEmptyCache 和 IncrementUrlCacheHeaderData。
发现这一点后,我能够实现以下代码,在我的请求之前执行:
type
TSslEmptyCache = function (pszTargetName: LPSTR; dwFlags: DWORD): BOOL; WINAPI;
TIncrementUrlCacheHeaderData = function (nIdx: DWORD; lpdwData: LPDWORD): BOOL; WINAPI;
var
SchannelDLLHandle, WinInetHandle: HMODULE;
SslEmptyCache: TSslEmptyCache;
IncrementUrlCacheHeaderData: TIncrementUrlCacheHeaderData;
SchannelDLLHandle := LoadLibrary('schannel.dll');
WinInetHandle := LoadLibrary('wininet.dll');
if (SchannelDLLHandle > 0) and (WinInetHandle > 0) then
try
SslEmptyCache := GetProcAddress(SchannelDLLHandle,'SslEmptyCacheW');
IncrementUrlCacheHeaderData := GetProcAddress(WinInetHandle,'IncrementUrlCacheHeaderData');
if Assigned(SslEmptyCache) and Assigned(IncrementUrlCacheHeaderData) then
begin
SslEmptyCache(nil,0);
IncrementUrlCacheHeaderData(14,@buffer);
end;
finally
FreeLibrary(SchannelDLLHandle);
FreeLibrary(WinInetHandle);
end;
当然,这是一个伪代码,但它是完整的;)
SslEmptyCache 函数在 MSDN 上有文档,但 IncrementUrlCacheHeaderData 函数没有,所以我不得不研究一下,发现第二个参数必须是 PDWORD,当函数返回时,它会接收一个增量数,即在不同进程(不同应用程序)的调用之间持久化。
有关更多信息,您可以访问this article,我将在其中解释我的所有传奇。文字是葡萄牙语,但该网站有一个很好的翻译工具。
感谢大家的帮助
【讨论】:
支持这项研究,并支持 API Monitor 的链接!【参考方案2】:“清除 SSL 状态”按钮仅执行以下未记录的命令行命令:
"C:\Windows\system32\rundll32.exe" "C:\Windows\system32\WININET.dll",DispatchAPICall 3
使用CreateProcess()
在您的 Delphi 代码中执行相同的命令。
【讨论】:
你好,我看到了这种方法,但我真的需要一个真正的 API 调用来实现这一点。有没有办法直接调用 DispatchAPICall ?我没有找到任何关于它的文档 @CarlosFeitozaFilho “我真的需要一个真正的 API 调用来实现这一目标” - 没有。 “有没有办法直接调用 DispatchAPICall?” - 当然,只需 call it the same way rundll32.exe does。 直接调用DispatchAPICall()
不行吗?或者它根本不起作用,即使你通过 rundll32 调用它?如果它在 rundll32 中有效,但在您的 Delphi 代码中无效,那么您的代码没有正确调用它。
没有一个工作:/相同的初始行为继续。我在这里有一些想法。如果他们有效,我会与你分享
和this one一样吗?然后也许它会与 TWebBrowser 实例的 execCommand('ClearAuthenticationCache')
一起工作【参考方案3】:
你是对的:如果rundll可以做到,你可以通过编程来做到:
//somewhere in an interface section:
procedure DispatchAPICall(h: HWND; hinst: HINST; lpszCmdLine: PAnsiChar; nCmdShow: integer); stdcall;
//somewhere in the implementation section:
function DispatchAPICall; external 'wininet.dll';
//somewhere in your code:
DispatchAPICall(GetDesktopWindow(), GetModuleHandle('wininet.dll'), '3', SW_NORMAL);
【讨论】:
对不起,但不幸的是我使用了完全相同的代码。我实际上复制/粘贴了您的代码,即使如此 SSL 状态也没有被清除。 +1 这个答案,因为你对我的要求很严格(“Windows API 调用”)。谢谢!DispatchAPICall()
的声明错误。根据rundll32 documentation,它必须是procedure
而不是function
,并且lpszCmdLine
需要是PAnsiChar
而不是PChar
(在D2009+ 中是PWideChar
),例如:@987654330 @ 另外,hinst
必须是 DLL 的 HINST
,而不是 EXE。由于您是静态链接,因此您可以使用 GetModuleHandle('wininet.dll')
到该句柄。
特定DLL的HINSTANCE
?您是否应该使用LoadLibrary
或GetModuleHandle
来获取它,因为进程启动会为您加载它?
@StijnSanders:是的,您正在调用的已加载 DLL 的 HINSTANCE
。如果您自己动态加载 DLL,请使用 LoadLibrary()
返回的句柄。如果您静态链接到 DLL,请使用 GetModuleHandle()
返回的句柄。
感谢您提供的信息!但是,如果我在“运行”对话框 (rundll32.exe) 上使用完整命令并且它不起作用,我猜想导入这个 DLL 根本不起作用,对吧?以上是关于如何以编程方式清除 WinInet SSL 状态(是不是有 Windows API 调用)?的主要内容,如果未能解决你的问题,请参考以下文章