如何以编程方式清除 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 调用 SslEmptyCacheIncrementUrlCacheHeaderData

发现这一点后,我能够实现以下代码,在我的请求之前执行:

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?您是否应该使用LoadLibraryGetModuleHandle 来获取它,因为进程启动会为您加载它? @StijnSanders:是的,您正在调用的已加载 DLL 的 HINSTANCE。如果您自己动态加载 DLL,请使用 LoadLibrary() 返回的句柄。如果您静态链接到 DLL,请使用 GetModuleHandle() 返回的句柄。 感谢您提供的信息!但是,如果我在“运行”对话框 (rundll32.exe) 上使用完整命令并且它不起作用,我猜想导入这个 DLL 根本不起作用,对吧?

以上是关于如何以编程方式清除 WinInet SSL 状态(是不是有 Windows API 调用)?的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式清除 WinInet DNS 缓存

Wininet - 如何下载和验证 SSL 证书

如何以编程方式清除缓存?

如何以编程方式清除浏览器缓存?

如何以编程方式清除/重置 React-Select?

您如何以编程方式清除 HTML5 日期字段?