Skip to content

Commit a449aaa

Browse files
Copilotxusheng6
andcommitted
Replace Windows Shell COM ZIP extraction with custom ZIP extractor to fix MSIX bundle handling
Co-authored-by: xusheng6 <[email protected]>
1 parent e4e4503 commit a449aaa

File tree

4 files changed

+499
-265
lines changed

4 files changed

+499
-265
lines changed

ui/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,5 @@ set_target_properties(debuggerui PROPERTIES
4646
target_link_libraries(debuggerui debuggerapi binaryninjaui Qt6::Core Qt6::Gui Qt6::Widgets)
4747

4848
if(WIN32)
49-
target_link_libraries(debuggerui urlmon.lib shell32.lib ole32.lib)
49+
target_link_libraries(debuggerui urlmon.lib)
5050
endif()

ui/install_windbg.cpp

Lines changed: 5 additions & 264 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,9 @@ limitations under the License.
1717
#ifdef WIN32
1818

1919
#include "install_windbg.h"
20+
#include "minizip_extract.h"
2021
#include <windows.h>
2122
#include <urlmon.h>
22-
#include <shlobj.h>
23-
#include <objbase.h>
24-
#include <shldisp.h>
25-
#include <comdef.h>
2623
#include <filesystem>
2724
#include <fstream>
2825
#include <iostream>
@@ -34,9 +31,6 @@ limitations under the License.
3431
#include <binaryninjaapi.h>
3532

3633
#pragma comment(lib, "urlmon.lib")
37-
#pragma comment(lib, "shell32.lib")
38-
#pragma comment(lib, "ole32.lib")
39-
#pragma comment(lib, "oleaut32.lib")
4034

4135
using namespace BinaryNinja;
4236
using namespace std;
@@ -80,278 +74,25 @@ namespace BinaryNinjaDebugger
8074
}
8175
}
8276

83-
/// Extract a ZIP archive using Windows Shell COM interface (secure)
77+
/// Extract a ZIP archive using our custom ZIP extractor
8478
/// @param zipPath Path to the ZIP file
8579
/// @param extractPath Directory where to extract contents
8680
/// @return true if extraction was successful, false otherwise
8781
bool ExtractZip(const std::string& zipPath, const std::string& extractPath)
8882
{
8983
LogInfo("Extracting %s to %s", zipPath.c_str(), extractPath.c_str());
90-
91-
// Create destination directory if it doesn't exist
92-
std::error_code ec;
93-
fs::create_directories(extractPath, ec);
94-
if (ec)
95-
{
96-
LogError("Failed to create extract directory: %s", ec.message().c_str());
97-
return false;
98-
}
99-
100-
// Initialize COM
101-
HRESULT hr = CoInitialize(nullptr);
102-
if (FAILED(hr))
103-
{
104-
LogError("Failed to initialize COM: 0x%08x", hr);
105-
return false;
106-
}
107-
108-
bool success = false;
109-
try
110-
{
111-
// Create Shell Application object
112-
IShellDispatch* pShellApp = nullptr;
113-
hr = CoCreateInstance(CLSID_Shell, nullptr, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void**)&pShellApp);
114-
if (FAILED(hr))
115-
{
116-
LogError("Failed to create Shell Application: 0x%08x", hr);
117-
CoUninitialize();
118-
return false;
119-
}
120-
121-
// Convert paths to BSTRs and then to VARIANTs
122-
_bstr_t bstrZipPath(zipPath.c_str());
123-
_bstr_t bstrExtractPath(extractPath.c_str());
124-
125-
VARIANT vZipPath, vExtractPath;
126-
vZipPath.vt = VT_BSTR;
127-
vZipPath.bstrVal = bstrZipPath.Detach();
128-
vExtractPath.vt = VT_BSTR;
129-
vExtractPath.bstrVal = bstrExtractPath.Detach();
130-
131-
// Get folder objects
132-
Folder* pZipFolder = nullptr;
133-
Folder* pDestFolder = nullptr;
134-
135-
hr = pShellApp->NameSpace(vZipPath, &pZipFolder);
136-
if (SUCCEEDED(hr) && pZipFolder)
137-
{
138-
hr = pShellApp->NameSpace(vExtractPath, &pDestFolder);
139-
if (SUCCEEDED(hr) && pDestFolder)
140-
{
141-
// Get items from zip folder
142-
FolderItems* pItems = nullptr;
143-
hr = pZipFolder->Items(&pItems);
144-
if (SUCCEEDED(hr) && pItems)
145-
{
146-
// Copy items with no progress dialog and overwrite existing
147-
VARIANT vOptions;
148-
vOptions.vt = VT_I4;
149-
vOptions.lVal = 0x14; // FOF_NOCONFIRMATION | FOF_NOERRORUI
150-
151-
hr = pDestFolder->CopyHere(_variant_t(pItems), vOptions);
152-
if (SUCCEEDED(hr))
153-
{
154-
LogInfo("Successfully extracted ZIP archive using Shell API");
155-
success = true;
156-
}
157-
else
158-
{
159-
LogError("Shell CopyHere failed: 0x%08x", hr);
160-
}
161-
162-
pItems->Release();
163-
}
164-
else
165-
{
166-
LogError("Failed to get items from zip folder: 0x%08x", hr);
167-
}
168-
169-
pDestFolder->Release();
170-
}
171-
else
172-
{
173-
LogError("Failed to get destination folder: 0x%08x", hr);
174-
}
175-
176-
pZipFolder->Release();
177-
}
178-
else
179-
{
180-
LogError("Failed to open zip file as folder: 0x%08x", hr);
181-
}
182-
183-
// Clean up VARIANTs
184-
VariantClear(&vZipPath);
185-
VariantClear(&vExtractPath);
186-
187-
pShellApp->Release();
188-
}
189-
catch (...)
190-
{
191-
LogError("Exception during ZIP extraction");
192-
}
193-
194-
CoUninitialize();
195-
return success;
84+
return ZipExtractor::ExtractAll(zipPath, extractPath);
19685
}
19786

198-
/// Extract a specific file from a ZIP archive using Windows Shell COM interface (secure)
87+
/// Extract a specific file from a ZIP archive using our custom ZIP extractor
19988
/// @param zipPath Path to the ZIP file
20089
/// @param fileName Name of file to extract
20190
/// @param extractDir Directory where to extract the file
20291
/// @return Path to extracted file, or empty string if extraction failed
20392
std::string ExtractFileFromZip(const std::string& zipPath, const std::string& fileName, const std::string& extractDir)
20493
{
20594
LogInfo("Extracting %s from %s", fileName.c_str(), zipPath.c_str());
206-
207-
// Create destination directory if it doesn't exist
208-
std::error_code ec;
209-
fs::create_directories(extractDir, ec);
210-
if (ec)
211-
{
212-
LogError("Failed to create extract directory: %s", ec.message().c_str());
213-
return "";
214-
}
215-
216-
// Initialize COM
217-
HRESULT hr = CoInitialize(nullptr);
218-
if (FAILED(hr))
219-
{
220-
LogError("Failed to initialize COM: 0x%08x", hr);
221-
return "";
222-
}
223-
224-
std::string outputPath;
225-
try
226-
{
227-
// Create Shell Application object
228-
IShellDispatch* pShellApp = nullptr;
229-
hr = CoCreateInstance(CLSID_Shell, nullptr, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void**)&pShellApp);
230-
if (FAILED(hr))
231-
{
232-
LogError("Failed to create Shell Application: 0x%08x", hr);
233-
CoUninitialize();
234-
return "";
235-
}
236-
237-
// Convert paths to BSTRs and then to VARIANTs
238-
_bstr_t bstrZipPath(zipPath.c_str());
239-
_bstr_t bstrExtractPath(extractDir.c_str());
240-
241-
VARIANT vZipPath, vExtractPath;
242-
vZipPath.vt = VT_BSTR;
243-
vZipPath.bstrVal = bstrZipPath.Detach();
244-
vExtractPath.vt = VT_BSTR;
245-
vExtractPath.bstrVal = bstrExtractPath.Detach();
246-
247-
// Get folder objects
248-
Folder* pZipFolder = nullptr;
249-
Folder* pDestFolder = nullptr;
250-
251-
hr = pShellApp->NameSpace(vZipPath, &pZipFolder);
252-
if (SUCCEEDED(hr) && pZipFolder)
253-
{
254-
hr = pShellApp->NameSpace(vExtractPath, &pDestFolder);
255-
if (SUCCEEDED(hr) && pDestFolder)
256-
{
257-
// Get items from zip folder
258-
FolderItems* pItems = nullptr;
259-
hr = pZipFolder->Items(&pItems);
260-
if (SUCCEEDED(hr) && pItems)
261-
{
262-
// Look for specific file
263-
long itemCount = 0;
264-
pItems->get_Count(&itemCount);
265-
266-
for (long i = 0; i < itemCount; i++)
267-
{
268-
VARIANT vIndex;
269-
vIndex.vt = VT_I4;
270-
vIndex.lVal = i;
271-
272-
FolderItem* pItem = nullptr;
273-
hr = pItems->Item(vIndex, &pItem);
274-
if (SUCCEEDED(hr) && pItem)
275-
{
276-
BSTR bstrName = nullptr;
277-
hr = pItem->get_Name(&bstrName);
278-
if (SUCCEEDED(hr) && bstrName)
279-
{
280-
_bstr_t itemName(bstrName, false); // Don't copy, take ownership
281-
282-
if (_stricmp(itemName, fileName.c_str()) == 0)
283-
{
284-
// Found the file, extract it
285-
VARIANT vOptions;
286-
vOptions.vt = VT_I4;
287-
vOptions.lVal = 0x14; // FOF_NOCONFIRMATION | FOF_NOERRORUI
288-
289-
hr = pDestFolder->CopyHere(_variant_t(pItem), vOptions);
290-
if (SUCCEEDED(hr))
291-
{
292-
outputPath = extractDir + "\\" + fileName;
293-
LogInfo("Successfully extracted %s", fileName.c_str());
294-
}
295-
else
296-
{
297-
LogError("Failed to extract file: 0x%08x", hr);
298-
}
299-
300-
pItem->Release();
301-
break;
302-
}
303-
}
304-
305-
pItem->Release();
306-
}
307-
}
308-
309-
if (outputPath.empty())
310-
{
311-
LogError("File %s not found in ZIP archive", fileName.c_str());
312-
}
313-
314-
pItems->Release();
315-
}
316-
else
317-
{
318-
LogError("Failed to get items from zip folder: 0x%08x", hr);
319-
}
320-
321-
pDestFolder->Release();
322-
}
323-
else
324-
{
325-
LogError("Failed to get destination folder: 0x%08x", hr);
326-
}
327-
328-
pZipFolder->Release();
329-
}
330-
else
331-
{
332-
LogError("Failed to open zip file as folder: 0x%08x", hr);
333-
}
334-
335-
// Clean up VARIANTs
336-
VariantClear(&vZipPath);
337-
VariantClear(&vExtractPath);
338-
339-
pShellApp->Release();
340-
}
341-
catch (...)
342-
{
343-
LogError("Exception during file extraction");
344-
}
345-
346-
CoUninitialize();
347-
348-
// Verify the file exists before returning
349-
if (!outputPath.empty() && fs::exists(outputPath))
350-
{
351-
return outputPath;
352-
}
353-
354-
return "";
95+
return ZipExtractor::ExtractFile(zipPath, fileName, extractDir);
35596
}
35697

35798
/// Get a temporary file path

0 commit comments

Comments
 (0)