diff --git a/2.x/trunk/plugins/OnlineChecks/OnlineChecks.rc b/2.x/trunk/plugins/OnlineChecks/OnlineChecks.rc index 59e8b6845..9a3c22653 100644 --- a/2.x/trunk/plugins/OnlineChecks/OnlineChecks.rc +++ b/2.x/trunk/plugins/OnlineChecks/OnlineChecks.rc @@ -13,39 +13,11 @@ #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources +// English resources -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL #pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - ///////////////////////////////////////////////////////////////////////////// // @@ -91,13 +63,15 @@ END // Dialog // -IDD_PROGRESS DIALOGEX 0, 0, 189, 41 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Uploading" +IDD_PROGRESSDIALOG DIALOGEX 0, 0, 260, 100 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Online Analysis" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - PUSHBUTTON "Cancel",IDCANCEL,132,20,50,14 - LTEXT "Message",IDC_MESSAGE,7,7,175,8 + PUSHBUTTON "Cancel",IDCANCEL,203,79,50,14 + LTEXT "Select a file to upload",IDC_MESSAGE,6,5,246,12 + CONTROL "",IDC_UPLOADPROGRESS,"msctls_progress32",PBS_SMOOTH,7,60,246,11 + CONTROL "Status",IDC_STATUS,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,8,48,245,8 END @@ -107,18 +81,54 @@ END // #ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO +GUIDELINES DESIGNINFO BEGIN - IDD_PROGRESS, DIALOG + IDD_PROGRESSDIALOG, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 182 + RIGHTMARGIN, 253 TOPMARGIN, 7 - BOTTOMMARGIN, 34 + BOTTOMMARGIN, 93 END END #endif // APSTUDIO_INVOKED +#endif // English resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/2.x/trunk/plugins/OnlineChecks/OnlineChecks.vcxproj b/2.x/trunk/plugins/OnlineChecks/OnlineChecks.vcxproj index 0edcd96fc..0c3abdb64 100644 --- a/2.x/trunk/plugins/OnlineChecks/OnlineChecks.vcxproj +++ b/2.x/trunk/plugins/OnlineChecks/OnlineChecks.vcxproj @@ -22,6 +22,7 @@ {79D24223-1122-40A9-BC8F-46A2089FE089} OnlineChecks Win32Proj + OnlineChecks diff --git a/2.x/trunk/plugins/OnlineChecks/main.c b/2.x/trunk/plugins/OnlineChecks/main.c index a37e9db28..23f00ba4e 100644 --- a/2.x/trunk/plugins/OnlineChecks/main.c +++ b/2.x/trunk/plugins/OnlineChecks/main.c @@ -3,6 +3,7 @@ * main program * * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2012 dmex * * This file is part of Process Hacker. * @@ -24,37 +25,63 @@ #include "onlnchk.h" #include "resource.h" -VOID NTAPI LoadCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ); +PPH_PLUGIN PluginInstance; +static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; +static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ModuleMenuInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; VOID NTAPI ShowOptionsCallback( __in_opt PVOID Parameter, __in_opt PVOID Context ); - +VOID NTAPI MainWindowShowingCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ); VOID NTAPI MenuItemCallback( __in_opt PVOID Parameter, __in_opt PVOID Context ); - VOID NTAPI ProcessMenuInitializingCallback( __in_opt PVOID Parameter, __in_opt PVOID Context ); - VOID NTAPI ModuleMenuInitializingCallback( __in_opt PVOID Parameter, __in_opt PVOID Context ); -PPH_PLUGIN PluginInstance; -PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ModuleMenuInitializingCallbackRegistration; +PPH_EMENU_ITEM CreateSendToMenu( + __in PPH_EMENU_ITEM Parent, + __in PWSTR InsertAfter, + __in PPH_STRING FileName + ) +{ + PPH_EMENU_ITEM sendToMenu; + PPH_EMENU_ITEM menuItem; + ULONG insertIndex; + + // Create the Send To menu. + sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Online Analysis", NULL); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, UPLOAD_SERVICE_VIRUSTOTAL, L"Virustotal", FileName), -1); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, UPLOAD_SERVICE_JOTTI, L"Jotti", FileName), -1); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, UPLOAD_SERVICE_CIMA, L"Comodo", FileName), -1); + + menuItem = PhFindEMenuItem(Parent, PH_EMENU_FIND_STARTSWITH, InsertAfter, 0); + + if (menuItem) + insertIndex = PhIndexOfEMenuItem(Parent, menuItem); + else + insertIndex = -1; + + PhInsertEMenuItem(Parent, sendToMenu, insertIndex + 1); + + return sendToMenu; +} + LOGICAL DllMain( __in HINSTANCE Instance, @@ -73,30 +100,30 @@ LOGICAL DllMain( if (!PluginInstance) return FALSE; - info->DisplayName = L"Online Checks"; - info->Author = L"wj32"; - info->Description = L"Allows files to be checked with online services."; + info->DisplayName = L"OnlineChecks"; + info->Author = L"wj32 & dmex"; + info->Description = L""; info->HasOptions = FALSE; - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), ShowOptionsCallback, NULL, &PluginShowOptionsCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMainWindowShowing), + MainWindowShowingCallback, + NULL, + &MainWindowShowingCallbackRegistration ); + PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), MenuItemCallback, NULL, &PluginMenuItemCallbackRegistration ); - PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), ProcessMenuInitializingCallback, @@ -116,14 +143,6 @@ LOGICAL DllMain( return TRUE; } -VOID NTAPI LoadCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ) -{ - // Nothing -} - VOID NTAPI ShowOptionsCallback( __in_opt PVOID Parameter, __in_opt PVOID Context @@ -132,58 +151,64 @@ VOID NTAPI ShowOptionsCallback( // Nothing } +VOID NTAPI MainWindowShowingCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ) +{ + //PhPluginAddMenuItem(PluginInstance, PH_MENU_ITEM_LOCATION_TOOLS, NULL, UPLOAD_SERVICE_VIRUSTOTAL, L"Upload file to VirusTotal", NULL); + //PhPluginAddMenuItem(PluginInstance, PH_MENU_ITEM_LOCATION_TOOLS, NULL, UPLOAD_SERVICE_JOTTI, L"Upload file to JOTTI", NULL); + //PhPluginAddMenuItem(PluginInstance, PH_MENU_ITEM_LOCATION_TOOLS, NULL, UPLOAD_SERVICE_CIMA, L"Upload file to Comodo", NULL); +} + VOID NTAPI MenuItemCallback( __in_opt PVOID Parameter, __in_opt PVOID Context ) { PPH_PLUGIN_MENU_ITEM menuItem = Parameter; - PPH_STRING fileName; switch (menuItem->Id) { - case ID_SENDTO_SERVICE1: - fileName = menuItem->Context; - UploadToOnlineService(menuItem->OwnerWindow, fileName, UPLOAD_SERVICE_VIRUSTOTAL); + case UPLOAD_SERVICE_VIRUSTOTAL: + { + if (menuItem->Context) + { + UploadToOnlineService( + menuItem->OwnerWindow, + menuItem->Context ? menuItem->Context : NULL, + UPLOAD_SERVICE_VIRUSTOTAL + ); + } + } break; - case ID_SENDTO_SERVICE2: - fileName = menuItem->Context; - UploadToOnlineService(menuItem->OwnerWindow, fileName, UPLOAD_SERVICE_JOTTI); + case UPLOAD_SERVICE_JOTTI: + { + if (menuItem->Context) + { + UploadToOnlineService( + menuItem->OwnerWindow, + menuItem->Context ? menuItem->Context : NULL, + UPLOAD_SERVICE_JOTTI + ); + } + } break; - case ID_SENDTO_SERVICE3: - fileName = menuItem->Context; - UploadToOnlineService(menuItem->OwnerWindow, fileName, UPLOAD_SERVICE_CIMA); + case UPLOAD_SERVICE_CIMA: + { + if (menuItem->Context) + { + UploadToOnlineService( + menuItem->OwnerWindow, + menuItem->Context ? menuItem->Context : NULL, + UPLOAD_SERVICE_CIMA + ); + } + } break; } } -PPH_EMENU_ITEM CreateSendToMenu( - __in PPH_EMENU_ITEM Parent, - __in PWSTR InsertAfter, - __in PPH_STRING FileName - ) -{ - PPH_EMENU_ITEM sendToMenu; - PPH_EMENU_ITEM menuItem; - ULONG insertIndex; - - // Create the Send To menu. - sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Send To", NULL); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, ID_SENDTO_SERVICE1, L"virustotal.com", FileName), -1); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, ID_SENDTO_SERVICE2, L"virusscan.jotti.org", FileName), -1); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, ID_SENDTO_SERVICE3, L"camas.comodo.com", FileName), -1); - - menuItem = PhFindEMenuItem(Parent, PH_EMENU_FIND_STARTSWITH, InsertAfter, 0); - - if (menuItem) - insertIndex = PhIndexOfEMenuItem(Parent, menuItem); - else - insertIndex = -1; - - PhInsertEMenuItem(Parent, sendToMenu, insertIndex + 1); - - return sendToMenu; -} VOID NTAPI ProcessMenuInitializingCallback( __in_opt PVOID Parameter, @@ -192,6 +217,8 @@ VOID NTAPI ProcessMenuInitializingCallback( { PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; PPH_PROCESS_ITEM processItem; + ULONG flags; + PPH_EMENU_ITEM miscMenu; PPH_EMENU_ITEM sendToMenu; if (menuInfo->u.Process.NumberOfProcesses == 1) @@ -199,13 +226,17 @@ VOID NTAPI ProcessMenuInitializingCallback( else processItem = NULL; - sendToMenu = CreateSendToMenu(menuInfo->Menu, L"Search Online", processItem ? processItem->FileName : NULL); + flags = 0; // Only enable the Send To menu if there is exactly one process selected and it has a file name. - if (!processItem || !processItem->FileName) + flags = PH_EMENU_DISABLED; + + miscMenu = PhFindEMenuItem(menuInfo->Menu, 0, L"Miscellaneous", 0); + + if (miscMenu) { - sendToMenu->Flags |= PH_EMENU_DISABLED; + sendToMenu = CreateSendToMenu(miscMenu, L"Search Online", processItem ? processItem->FileName : NULL); } } diff --git a/2.x/trunk/plugins/OnlineChecks/onlnchk.h b/2.x/trunk/plugins/OnlineChecks/onlnchk.h index cf3d0625e..40d66345c 100644 --- a/2.x/trunk/plugins/OnlineChecks/onlnchk.h +++ b/2.x/trunk/plugins/OnlineChecks/onlnchk.h @@ -1,6 +1,50 @@ #ifndef ONLNCHK_H #define ONLNCHK_H +#pragma comment(lib, "OleAut32.lib") +#pragma comment(lib, "Winhttp.lib") + +#define COBJMACROS +#include +#include +#include +#include +#include +#include + +#include "sha256.h" +#include "resource.h" + +#define HASH_SHA1 1 +#define HASH_SHA256 2 + +#define UM_LAUNCH_COMMAND (WM_APP + 1) +#define UM_ERROR (WM_APP + 2) + +typedef struct _UPLOAD_CONTEXT +{ + LONG RefCount; + + PPH_STRING FileName; + ULONG Service; + HWND WindowHandle; + HANDLE ThreadHandle; + + PPH_STRING LaunchCommand; + PPH_STRING ErrorMessage; +} UPLOAD_CONTEXT, *PUPLOAD_CONTEXT; + +typedef struct _SERVICE_INFO +{ + ULONG Id; + PWSTR HostName; + INTERNET_PORT HostPort; + ULONG HostFlags; + PWSTR UploadObjectName; + PWSTR FileNameFieldName; +} SERVICE_INFO, *PSERVICE_INFO; + + // main #ifndef MAIN_PRIVATE @@ -9,9 +53,9 @@ extern PPH_PLUGIN PluginInstance; // upload -#define UPLOAD_SERVICE_VIRUSTOTAL 1 -#define UPLOAD_SERVICE_JOTTI 2 -#define UPLOAD_SERVICE_CIMA 3 +#define UPLOAD_SERVICE_VIRUSTOTAL 101 +#define UPLOAD_SERVICE_JOTTI 102 +#define UPLOAD_SERVICE_CIMA 103 VOID UploadToOnlineService( __in HWND hWnd, @@ -19,4 +63,14 @@ VOID UploadToOnlineService( __in ULONG Service ); +INT_PTR CALLBACK UploadDlgProc( + __in HWND hwndDlg, + __in UINT uMsg, + __in WPARAM wParam, + __in LPARAM lParam + ); + + + + #endif diff --git a/2.x/trunk/plugins/OnlineChecks/resource.h b/2.x/trunk/plugins/OnlineChecks/resource.h index 54c2af38d..b77141a90 100644 --- a/2.x/trunk/plugins/OnlineChecks/resource.h +++ b/2.x/trunk/plugins/OnlineChecks/resource.h @@ -2,16 +2,10 @@ // Microsoft Visual C++ generated include file. // Used by OnlineChecks.rc // -#define ID_SENDTO_SERVICE1 101 -#define IDD_PROGRESS 101 -#define ID_SENDTO_SERVICE2 102 -#define ID_SENDTO_SERVICE3 103 -#define ID_SENDTO_SERVICE4 104 -#define ID_SENDTO_SERVICE5 105 -#define ID_SENDTO_SERVICE6 106 -#define ID_SENDTO_SERVICE7 107 -#define ID_SENDTO_SERVICE8 108 +#define IDD_PROGRESSDIALOG 101 #define IDC_MESSAGE 1002 +#define IDC_UPLOADPROGRESS 1003 +#define IDC_STATUS 1004 // Next default values for new objects // @@ -19,7 +13,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_CONTROL_VALUE 1007 #define _APS_NEXT_SYMED_VALUE 109 #endif #endif diff --git a/2.x/trunk/plugins/OnlineChecks/upload.c b/2.x/trunk/plugins/OnlineChecks/upload.c index 86abcb3a2..7727c1368 100644 --- a/2.x/trunk/plugins/OnlineChecks/upload.c +++ b/2.x/trunk/plugins/OnlineChecks/upload.c @@ -3,6 +3,7 @@ * uploader * * Copyright (C) 2010-2012 wj32 + * Copyright (C) 2012 dmex * * This file is part of Process Hacker. * @@ -20,56 +21,45 @@ * along with Process Hacker. If not, see . */ -#include -#include #include "onlnchk.h" -#include "sha256.h" -#include "resource.h" -#define HASH_SHA1 1 -#define HASH_SHA256 2 +static time_t TimeStart = 0; +static time_t TimeTransferred = 0; +static DWORD TotalReadSize = 0; +static DWORD TotalWriteSize = 0; +static DWORD TotalContentSize = 0; -#define UM_LAUNCH_COMMAND (WM_APP + 1) -#define UM_ERROR (WM_APP + 2) - -typedef struct _UPLOAD_CONTEXT +static SERVICE_INFO UploadServiceInfo[] = { - LONG RefCount; - - PPH_STRING FileName; - ULONG Service; - HWND WindowHandle; - PH_QUEUED_LOCK Lock; - HANDLE ThreadHandle; - - PPH_STRING LaunchCommand; - PPH_STRING ErrorMessage; -} UPLOAD_CONTEXT, *PUPLOAD_CONTEXT; - -typedef struct _SERVICE_INFO -{ - ULONG Id; - PWSTR HostName; - ULONG HostPort; - ULONG HostFlags; - PWSTR UploadObjectName; - PSTR FileNameFieldName; -} SERVICE_INFO, *PSERVICE_INFO; - -INT_PTR CALLBACK UploadDlgProc( - __in HWND hwndDlg, - __in UINT uMsg, - __in WPARAM wParam, - __in LPARAM lParam - ); - -SERVICE_INFO UploadServiceInfo[] = -{ - { UPLOAD_SERVICE_VIRUSTOTAL, L"www.virustotal.com", INTERNET_DEFAULT_HTTPS_PORT, INTERNET_FLAG_SECURE, L"???", "file" }, - { UPLOAD_SERVICE_JOTTI, L"virusscan.jotti.org", INTERNET_DEFAULT_HTTP_PORT, 0, L"/processupload.php", "scanfile" }, - { UPLOAD_SERVICE_CIMA, L"camas.comodo.com", INTERNET_DEFAULT_HTTP_PORT, 0, L"/cgi-bin/submit", "file" } + { UPLOAD_SERVICE_VIRUSTOTAL, L"www.virustotal.com", INTERNET_DEFAULT_HTTPS_PORT, WINHTTP_FLAG_SECURE, L"???", L"file" }, + { UPLOAD_SERVICE_JOTTI, L"virusscan.jotti.org", INTERNET_DEFAULT_HTTP_PORT, 0, L"/processupload.php", L"scanfile" }, + { UPLOAD_SERVICE_CIMA, L"camas.comodo.com", INTERNET_DEFAULT_HTTP_PORT, 0, L"/cgi-bin/submit", L"file" } }; +VOID InitializeFont( + __in HWND hwndDlg + ) +{ + LOGFONT lFont = { 0 }; + + // TODO: Cache font handle, it doesn't need to be recreated for each page. + HFONT fHandle = NULL; + + lFont.lfHeight = 20; + lFont.lfWeight = FW_MEDIUM; + lFont.lfQuality = CLEARTYPE_QUALITY | ANTIALIASED_QUALITY; + + wcscat_s( + lFont.lfFaceName, + _countof(lFont.lfFaceName), + L"Segoe UI" + ); + + fHandle = CreateFontIndirectW(&lFont); + + SendMessageW(hwndDlg, WM_SETFONT, (WPARAM)fHandle, FALSE); +} + PUPLOAD_CONTEXT CreateUploadContext( VOID ) @@ -83,12 +73,6 @@ PUPLOAD_CONTEXT CreateUploadContext( return context; } -VOID ReferenceUploadContext( - __inout PUPLOAD_CONTEXT Context - ) -{ - _InterlockedIncrement(&Context->RefCount); -} VOID DereferenceUploadContext( __inout PUPLOAD_CONTEXT Context @@ -119,8 +103,8 @@ VOID UploadToOnlineService( DialogBoxParam( PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_PROGRESS), - hWnd, + MAKEINTRESOURCE(IDD_PROGRESSDIALOG), + NULL, UploadDlgProc, (LPARAM)context ); @@ -151,24 +135,8 @@ static VOID RaiseUploadError( PhSwapReference(&errorMessage, NULL); - PhAcquireQueuedLockExclusive(&Context->Lock); - if (Context->WindowHandle) PostMessage(Context->WindowHandle, UM_ERROR, 0, 0); - - PhReleaseQueuedLockExclusive(&Context->Lock); -} - -static VOID SendLaunchCommand( - __in PUPLOAD_CONTEXT Context - ) -{ - PhAcquireQueuedLockExclusive(&Context->Lock); - - if (Context->WindowHandle) - PostMessage(Context->WindowHandle, UM_LAUNCH_COMMAND, 0, 0); - - PhReleaseQueuedLockExclusive(&Context->Lock); } static PSERVICE_INFO GetUploadServiceInfo( @@ -177,7 +145,7 @@ static PSERVICE_INFO GetUploadServiceInfo( { ULONG i; - for (i = 0; i < sizeof(UploadServiceInfo) / sizeof(SERVICE_INFO); i++) + for (i = 0; i < _countof(UploadServiceInfo); i++) { if (UploadServiceInfo[i].Id == Id) return &UploadServiceInfo[i]; @@ -186,13 +154,13 @@ static PSERVICE_INFO GetUploadServiceInfo( return NULL; } + static BOOLEAN PerformSubRequest( __in PUPLOAD_CONTEXT Context, __in PWSTR HostName, __in PWSTR ObjectName, - __out_bcount(BufferLength) PVOID Buffer, - __in ULONG BufferLength, - __out PULONG ReturnLength + __out_bcount(DataLength) PSTR *Data, + __out_opt PULONG DataLength ) { BOOLEAN result = FALSE; @@ -201,104 +169,134 @@ static BOOLEAN PerformSubRequest( HINTERNET connectHandle = NULL; HINTERNET requestHandle = NULL; + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxycfg = { 0 }; // Create a user agent string. { - PPH_STRING phVersion; - - phVersion = PhGetPhVersion(); + PPH_STRING phVersion = PhGetPhVersion(); userAgent = PhConcatStrings2(L"Process Hacker ", phVersion->Buffer); PhDereferenceObject(phVersion); } + if (!WinHttpGetIEProxyConfigForCurrentUser(&proxycfg)) + { + RaiseUploadError(Context, L"WinHttpGetIEProxyConfigForCurrentUser Failure", GetLastError()); + goto ExitCleanup; + } + // Create the internet handle. - - internetHandle = InternetOpen(userAgent->Buffer, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); - PhDereferenceObject(userAgent); - - if (!internetHandle) + if (!(internetHandle = WinHttpOpen( + userAgent->Buffer, + proxycfg.lpszProxy != NULL ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + proxycfg.lpszProxy, + proxycfg.lpszProxyBypass, + 0 + ))) { RaiseUploadError(Context, L"Unable to initialize internet access", GetLastError()); goto ExitCleanup; } - // Set the timeouts. - { - ULONG timeout = 5 * 60 * 1000; // 5 minutes - - InternetSetOption(internetHandle, INTERNET_OPTION_CONNECT_TIMEOUT, &timeout, sizeof(ULONG)); - InternetSetOption(internetHandle, INTERNET_OPTION_SEND_TIMEOUT, &timeout, sizeof(ULONG)); - InternetSetOption(internetHandle, INTERNET_OPTION_RECEIVE_TIMEOUT, &timeout, sizeof(ULONG)); - InternetSetOption(internetHandle, INTERNET_OPTION_DATA_SEND_TIMEOUT, &timeout, sizeof(ULONG)); - InternetSetOption(internetHandle, INTERNET_OPTION_DATA_RECEIVE_TIMEOUT, &timeout, sizeof(ULONG)); - } + PhDereferenceObject(userAgent); // Connect to the online service. - - connectHandle = InternetConnect( + if (!(connectHandle = WinHttpConnect( internetHandle, HostName, - 80, - NULL, - NULL, - INTERNET_SERVICE_HTTP, - 0, + INTERNET_DEFAULT_HTTP_PORT, 0 - ); - - if (!connectHandle) + ))) { RaiseUploadError(Context, L"Unable to connect to the service", GetLastError()); goto ExitCleanup; } // Create the request. - - { - static PWSTR acceptTypes[2] = { L"*/*", NULL }; - - requestHandle = HttpOpenRequest( - connectHandle, - L"GET", - ObjectName, - L"HTTP/1.1", - L"", - acceptTypes, - INTERNET_FLAG_RELOAD, - 0 - ); - } - - if (!requestHandle) + if (!(requestHandle = WinHttpOpenRequest( + connectHandle, + NULL, // GET + ObjectName, + NULL,// HTTP/1.1 + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + WINHTTP_FLAG_REFRESH + ))) { RaiseUploadError(Context, L"Unable to create the request", GetLastError()); goto ExitCleanup; } // Send the request. - - if (!HttpSendRequest(requestHandle, NULL, 0, NULL, 0)) + if (!WinHttpSendRequest(requestHandle, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) { RaiseUploadError(Context, L"Unable to send the request", GetLastError()); goto ExitCleanup; } - // Handle service-specific actions. - - if (!InternetReadFile(requestHandle, Buffer, BufferLength, ReturnLength)) + // Wait for the send request to complete and recieve the response. + if (!WinHttpReceiveResponse(requestHandle, NULL)) { - RaiseUploadError(Context, L"Unable to complete the request", GetLastError()); + RaiseUploadError(Context, L"Unable to receive the response", GetLastError()); goto ExitCleanup; } + // Handle service-specific actions. + //if (!WinHttpReadData(requestHandle, Buffer, BufferLength, ReturnLength)) + //{ + // RaiseUploadError(Context, L"Unable to complete the request", GetLastError()); + // goto ExitCleanup; + //} + + { + CHAR buffer[512]; + PSTR data; + ULONG allocatedLength; + ULONG dataLength; + ULONG returnLength; + + allocatedLength = sizeof(buffer); + data = PhAllocate(allocatedLength); + dataLength = 0; + + while (WinHttpReadData(requestHandle, buffer, 512, &returnLength)) + { + if (returnLength == 0) + break; + + if (allocatedLength < dataLength + returnLength) + { + allocatedLength *= 2; + data = PhReAllocate(data, allocatedLength); + } + + RtlCopyMemory(data + dataLength, buffer, returnLength); + dataLength += returnLength; + } + + if (allocatedLength < dataLength + 1) + { + allocatedLength++; + data = PhReAllocate(data, allocatedLength); + } + + // Ensure that the buffer is null-terminated. + data[dataLength] = 0; + + *Data = data; + + if (DataLength) + *DataLength = dataLength; + + } + result = TRUE; ExitCleanup: if (requestHandle) - InternetCloseHandle(requestHandle); + WinHttpCloseHandle(requestHandle); if (connectHandle) - InternetCloseHandle(connectHandle); + WinHttpCloseHandle(connectHandle); if (internetHandle) - InternetCloseHandle(internetHandle); + WinHttpCloseHandle(internetHandle); return result; } @@ -386,37 +384,31 @@ static NTSTATUS UploadWorkerThreadStart( __in PVOID Parameter ) { + static ULONG seed = 0; NTSTATUS status; - PUPLOAD_CONTEXT context = Parameter; - PSERVICE_INFO serviceInfo; - PPH_STRING userAgent; - HANDLE fileHandle = NULL; LARGE_INTEGER fileSize64; - ULONG fileSize; - PPH_STRING objectName = NULL; - HINTERNET internetHandle = NULL; - HINTERNET connectHandle = NULL; - HINTERNET requestHandle = NULL; - PPH_STRING boundary = NULL; - PPH_ANSI_STRING boundaryAnsi = NULL; - PH_STRING_BUILDER headers = { 0 }; - PPH_ANSI_STRING baseFileNameAnsi = NULL; - PUCHAR data = NULL; - ULONG dataLength = 0; - ULONG dataCursor = 0; - UCHAR buffer[PAGE_SIZE]; - ULONG bufferSize; - serviceInfo = GetUploadServiceInfo(context->Service); + HANDLE fileHandle = NULL; + HINTERNET internetHandle = NULL, connectHandle = NULL, requestHandle = NULL; + PUPLOAD_CONTEXT context = Parameter; + PSERVICE_INFO serviceInfo = NULL; - if (!serviceInfo) + PPH_STRING userAgent = NULL, objectName = NULL; + PPH_STRING baseFileName = PhGetBaseName(context->FileName); + + // Reset our variables + TimeStart = 0; + TimeTransferred = 0; + TotalContentSize = 0; + TotalReadSize = 0; + + if (!(serviceInfo = GetUploadServiceInfo(context->Service))) { RaiseUploadError(context, L"The service type is invalid", 0); goto ExitCleanup; } // Open the file and check its size. - status = PhCreateFileWin32( &fileHandle, context->FileName->Buffer, @@ -437,10 +429,9 @@ static NTSTATUS UploadWorkerThreadStart( goto ExitCleanup; } - fileSize = fileSize64.LowPart; + TotalContentSize = fileSize64.LowPart; } } - if (!NT_SUCCESS(status)) { RaiseUploadError(context, L"Unable to open the file", RtlNtStatusToDosError(status)); @@ -456,6 +447,8 @@ static NTSTATUS UploadWorkerThreadStart( PPH_STRING subObjectName; PSTR uploadUrl; PSTR quote; + PSTR data; + DWORD length; status = HashFileAndResetPosition(fileHandle, &fileSize64, HASH_SHA256, hash); @@ -468,29 +461,26 @@ static NTSTATUS UploadWorkerThreadStart( hashString = PhBufferToHexString(hash, 32); subObjectName = PhConcatStrings2(L"/file/upload/?sha256=", hashString->Buffer); - if (!PerformSubRequest(context, serviceInfo->HostName, subObjectName->Buffer, buffer, sizeof(buffer) - 1, &bufferSize)) + if (!PerformSubRequest(context, serviceInfo->HostName, subObjectName->Buffer, &data, &length)) { PhDereferenceObject(hashString); PhDereferenceObject(subObjectName); goto ExitCleanup; } - PhDereferenceObject(subObjectName); - - buffer[bufferSize] = 0; - - if (strstr(buffer, "\"file_exists\": true")) - { - // No upload needed; show the results immediately. - context->LaunchCommand = PhFormatString(L"http://www.virustotal.com/file/%s/analysis/", hashString->Buffer); - PhDereferenceObject(hashString); - SendLaunchCommand(context); - goto ExitCleanup; - } + //if (strstr(buffer, "\"file_exists\": true")) + //{ + // // No upload needed; show the results immediately. + // context->LaunchCommand = PhFormatString(L"http://www.virustotal.com/file/%s/analysis/", hashString->Buffer); + // PhDereferenceObject(hashString); + // SendLaunchCommand(context); + // goto ExitCleanup; + //} PhDereferenceObject(hashString); + PhDereferenceObject(subObjectName); - uploadUrl = strstr(buffer, "\"upload_url\": \"https://www.virustotal.com"); + uploadUrl = strstr(data, "\"upload_url\": \"https://www.virustotal.com"); if (!uploadUrl) { @@ -515,8 +505,8 @@ static NTSTATUS UploadWorkerThreadStart( UCHAR hash[20]; PPH_STRING hashString; PPH_STRING subObjectName; - PSTR id; - PSTR quote; + PSTR data; + DWORD length; status = HashFileAndResetPosition(fileHandle, &fileSize64, HASH_SHA1, hash); @@ -529,7 +519,7 @@ static NTSTATUS UploadWorkerThreadStart( hashString = PhBufferToHexString(hash, 20); subObjectName = PhConcatStrings2(L"/nestor/getfileforhash.php?hash=", hashString->Buffer); - if (!PerformSubRequest(context, serviceInfo->HostName, subObjectName->Buffer, buffer, sizeof(buffer) - 1, &bufferSize)) + if (!PerformSubRequest(context, serviceInfo->HostName, subObjectName->Buffer, &data, &length)) { PhDereferenceObject(hashString); PhDereferenceObject(subObjectName); @@ -539,21 +529,19 @@ static NTSTATUS UploadWorkerThreadStart( PhDereferenceObject(hashString); PhDereferenceObject(subObjectName); - buffer[bufferSize] = 0; + //if (id = strstr(data, "\"id\":")) + //{ + // id += 6; + // quote = strchr(id, '"'); - if (id = strstr(buffer, "\"id\":")) - { - id += 6; - quote = strchr(id, '"'); - - if (quote) - { - // No upload needed; show the results immediately. - context->LaunchCommand = PhFormatString(L"http://virusscan.jotti.org/en/scanresult/%.*S", quote - id, id); - SendLaunchCommand(context); - goto ExitCleanup; - } - } + // if (quote) + // { + // // No upload needed; show the results immediately. + // context->LaunchCommand = PhFormatString(L"http://virusscan.jotti.org/en/scanresult/%.*S", quote - id, id); + // SendLaunchCommand(context); + // goto ExitCleanup; + // } + //} objectName = PhCreateString(serviceInfo->UploadObjectName); } @@ -567,358 +555,489 @@ static NTSTATUS UploadWorkerThreadStart( // Create a user agent string. { - PPH_STRING phVersion; - - phVersion = PhGetPhVersion(); + PPH_STRING phVersion = PhGetPhVersion(); userAgent = PhConcatStrings2(L"Process Hacker ", phVersion->Buffer); PhDereferenceObject(phVersion); } - - // Create the internet handle. - - internetHandle = InternetOpen(userAgent->Buffer, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); - PhDereferenceObject(userAgent); - - if (!internetHandle) + + // Get proxy configuration and create winhttp handle. { - RaiseUploadError(context, L"Unable to initialize internet access", GetLastError()); - goto ExitCleanup; - } + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxycfg = { 0 }; - // Set the timeouts. - { - ULONG timeout = 5 * 60 * 1000; // 5 minutes + if (!WinHttpGetIEProxyConfigForCurrentUser(&proxycfg)) + { + RaiseUploadError(context, L"WinHttpGetIEProxyConfigForCurrentUser Failure", GetLastError()); + goto ExitCleanup; + } - InternetSetOption(internetHandle, INTERNET_OPTION_CONNECT_TIMEOUT, &timeout, sizeof(ULONG)); - InternetSetOption(internetHandle, INTERNET_OPTION_SEND_TIMEOUT, &timeout, sizeof(ULONG)); - InternetSetOption(internetHandle, INTERNET_OPTION_RECEIVE_TIMEOUT, &timeout, sizeof(ULONG)); - InternetSetOption(internetHandle, INTERNET_OPTION_DATA_SEND_TIMEOUT, &timeout, sizeof(ULONG)); - InternetSetOption(internetHandle, INTERNET_OPTION_DATA_RECEIVE_TIMEOUT, &timeout, sizeof(ULONG)); + // Create the internet handle. + if (!(internetHandle = WinHttpOpen( + userAgent->Buffer, + proxycfg.lpszProxy != NULL ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + proxycfg.lpszProxy, + proxycfg.lpszProxyBypass, + 0 + ))) + { + RaiseUploadError(context, L"Unable to initialize internet access", GetLastError()); + goto ExitCleanup; + } } // Connect to the online service. - - connectHandle = InternetConnect( + if (!(connectHandle = WinHttpConnect( internetHandle, serviceInfo->HostName, - (INTERNET_PORT)serviceInfo->HostPort, - NULL, - NULL, - INTERNET_SERVICE_HTTP, - 0, + serviceInfo->HostPort, 0 - ); - - if (!connectHandle) + ))) { RaiseUploadError(context, L"Unable to connect to the service", GetLastError()); goto ExitCleanup; } // Create the request. - - { - static PWSTR acceptTypes[2] = { L"*/*", NULL }; - - requestHandle = HttpOpenRequest( - connectHandle, - L"POST", - objectName->Buffer, - L"HTTP/1.1", - L"", - acceptTypes, - INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_AUTO_REDIRECT | serviceInfo->HostFlags, - 0 - ); - } - - if (!requestHandle) + if (!(requestHandle = WinHttpOpenRequest( + connectHandle, + L"POST", + objectName->Buffer, + NULL, // HTTP/1.1 + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + WINHTTP_FLAG_REFRESH | serviceInfo->HostFlags + ))) { RaiseUploadError(context, L"Unable to create the request", GetLastError()); goto ExitCleanup; } - // Create the boundary. - + // Set timeouts and disable http redirection. { - static ULONG seed = 0; + DWORD disable = WINHTTP_DISABLE_REDIRECTS; + ULONG timeout = 5 * 60 * 1000; // 5 minutes - boundary = PhFormatString( + WinHttpSetOption(requestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &disable, sizeof(ULONG)); + WinHttpSetOption(requestHandle, WINHTTP_OPTION_CONNECT_TIMEOUT, &timeout, sizeof(ULONG)); + WinHttpSetOption(requestHandle, WINHTTP_OPTION_SEND_TIMEOUT, &timeout, sizeof(ULONG)); + WinHttpSetOption(requestHandle, WINHTTP_OPTION_RECEIVE_TIMEOUT, &timeout, sizeof(ULONG)); + } + + // Create and POST data. + { + PH_STRING_BUILDER sbRequestHeaders = { 0 }; + PH_STRING_BUILDER sbPostHeader = { 0 }; + PH_STRING_BUILDER sbPostFooter = { 0 }; + + PPH_STRING postBoundary = PhFormatString( L"------------------------%I64u", (ULONG64)RtlRandomEx(&seed) | ((ULONG64)RtlRandomEx(&seed) << 31) ); - boundaryAnsi = PhCreateAnsiStringFromUnicodeEx(boundary->Buffer, boundary->Length); - } - // Create the data. - - { - PSTR contentDispositionPart1 = "Content-Disposition: form-data; name=\""; - PSTR fileNameFieldName; - PSTR contentDispositionPart2 = "\"; filename=\""; - PSTR contentType = "Content-Type: application/octet-stream\r\n\r\n"; - PPH_STRING baseFileName; - IO_STATUS_BLOCK isb; - - baseFileName = PhGetBaseName(context->FileName); - baseFileNameAnsi = PhCreateAnsiStringFromUnicodeEx(baseFileName->Buffer, baseFileName->Length); - PhDereferenceObject(baseFileName); - - fileNameFieldName = serviceInfo->FileNameFieldName; - - dataLength = 2; // -- - dataLength += boundaryAnsi->Length; - dataLength += 2; // \r\n - dataLength += (ULONG)strlen(contentDispositionPart1); - dataLength += (ULONG)strlen(fileNameFieldName); - dataLength += (ULONG)strlen(contentDispositionPart2); - dataLength += baseFileNameAnsi->Length; - dataLength += 3; // \"\r\n - dataLength += (ULONG)strlen(contentType); - dataLength += fileSize; - dataLength += 4; // \r\n-- - dataLength += boundaryAnsi->Length; - dataLength += 6; // --\r\n\r\n - - data = PhAllocatePage(dataLength, NULL); - - if (!data) - { - RaiseUploadError(context, L"Unable to allocate memory", 0); - goto ExitCleanup; - } - - // Boundary - memcpy(&data[dataCursor], "--", 2); - dataCursor += 2; - memcpy(&data[dataCursor], boundaryAnsi->Buffer, boundaryAnsi->Length); - dataCursor += boundaryAnsi->Length; - memcpy(&data[dataCursor], "\r\n", 2); - dataCursor += 2; - - // Content Disposition - memcpy(&data[dataCursor], contentDispositionPart1, strlen(contentDispositionPart1)); - dataCursor += (ULONG)strlen(contentDispositionPart1); - memcpy(&data[dataCursor], fileNameFieldName, strlen(fileNameFieldName)); - dataCursor += (ULONG)strlen(fileNameFieldName); - memcpy(&data[dataCursor], contentDispositionPart2, strlen(contentDispositionPart2)); - dataCursor += (ULONG)strlen(contentDispositionPart2); - memcpy(&data[dataCursor], baseFileNameAnsi->Buffer, baseFileNameAnsi->Length); - dataCursor += baseFileNameAnsi->Length; - memcpy(&data[dataCursor], "\"\r\n", 3); - dataCursor += 3; - - // Content Type - memcpy(&data[dataCursor], contentType, strlen(contentType)); - dataCursor += (ULONG)strlen(contentType); - - // File contents - status = NtReadFile(fileHandle, NULL, NULL, NULL, &isb, &data[dataCursor], fileSize, NULL, NULL); - dataCursor += fileSize; - - if (!NT_SUCCESS(status)) - { - RaiseUploadError(context, L"Unable to read the file", RtlNtStatusToDosError(status)); - goto ExitCleanup; - } - - // Boundary - memcpy(&data[dataCursor], "\r\n--", 4); - dataCursor += 4; - memcpy(&data[dataCursor], boundaryAnsi->Buffer, boundaryAnsi->Length); - dataCursor += boundaryAnsi->Length; - memcpy(&data[dataCursor], "--\r\n\r\n", 6); - dataCursor += 6; - - assert(dataCursor == dataLength); - } - - // Create and add the header. - - { - PhInitializeStringBuilder(&headers, 100); - - PhAppendStringBuilder2( - &headers, - L"Content-Type: multipart/form-data; boundary=" + PhInitializeStringBuilder(&sbRequestHeaders, MAX_PATH); + PhInitializeStringBuilder(&sbPostHeader, MAX_PATH); + PhInitializeStringBuilder(&sbPostFooter, MAX_PATH); + + // build request header string + PhAppendFormatStringBuilder( + &sbRequestHeaders, + L"Content-Type: multipart/form-data; boundary=%s\r\n", + postBoundary->Buffer ); - PhAppendStringBuilder(&headers, boundary); - PhAppendStringBuilder2(&headers, L"\r\n"); - PhAppendFormatStringBuilder(&headers, L"Content-Length: %u\r\n", dataLength); - - HttpAddRequestHeaders( + // POST boundary header + PhAppendFormatStringBuilder( + &sbPostHeader, + L"--%s\r\n", + postBoundary->Buffer + ); + PhAppendFormatStringBuilder( + &sbPostHeader, + L"Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n", + serviceInfo->FileNameFieldName, + baseFileName->Buffer + ); + PhAppendFormatStringBuilder( + &sbPostHeader, + L"Content-Type: application/octet-stream\r\n\r\n" + ); + // POST boundary footer + PhAppendFormatStringBuilder( + &sbPostFooter, + L"\r\n--%s--\r\n\r\n", + postBoundary->Buffer + ); + + // add headers + if (!WinHttpAddRequestHeaders( requestHandle, - headers.String->Buffer, - (ULONG)headers.String->Length, - HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD - ); + sbRequestHeaders.String->Buffer, + -1, + WINHTTP_ADDREQ_FLAG_REPLACE | WINHTTP_ADDREQ_FLAG_ADD + )) + { + RaiseUploadError(context, L"Unable to add request headers", GetLastError()); + goto ExitCleanup; + } + + { + // All until now has been just for this; Calculate the total request length. + ULONG total_length = + (ULONG)wcsnlen(sbPostHeader.String->Buffer, sbPostHeader.String->Length) + + TotalContentSize + + (ULONG)wcsnlen(sbPostFooter.String->Buffer, sbPostFooter.String->Length); + + // Send the request. + if (!WinHttpSendRequest( + requestHandle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + WINHTTP_NO_REQUEST_DATA, + 0, + total_length, + 0 + )) + { + RaiseUploadError(context, L"Unable to send the request", GetLastError()); + goto ExitCleanup; + } + } + + { + DWORD bytesRead = 0; + DWORD bytesWritten = 0; + IO_STATUS_BLOCK isb; + BYTE buffer[512]; + + // Convert to ANSI + PPH_ANSI_STRING ansiPostData = PhCreateAnsiStringFromUnicode(sbPostHeader.String->Buffer); + PPH_ANSI_STRING ansiFooterData = PhCreateAnsiStringFromUnicode(sbPostFooter.String->Buffer); + + // start the clock. + TimeStart = time(NULL); + TimeTransferred = TimeStart; + + // Start our download status timer + SetTimer(context->WindowHandle, 0, 500, NULL); + + // Write the header bytes + WinHttpWriteData( + requestHandle, + ansiPostData->Buffer, + ansiPostData->Length, + &bytesWritten + ); + + assert(ansiPostData->Length == bytesWritten); + + // Write the file bytes + while (NT_SUCCESS(NtReadFile( + fileHandle, + NULL, + NULL, + NULL, + &isb, + &buffer, + 512, + NULL, + NULL + ))) + { + // Check bytes read. + if (isb.Information == 0) + break; + + WinHttpWriteData( + requestHandle, + buffer, + (DWORD)isb.Information, + &bytesWritten + ); + + TotalReadSize += bytesWritten; + ZeroMemory(buffer, 512); + + // Update the GUI progress. + { + WCHAR szDownloaded[1024] = L""; + WCHAR *rtext = L"second"; + time_t time_taken = (time(NULL) - TimeTransferred); + time_t bps = TotalReadSize / (time_taken ? time_taken : 1); + time_t remain = (MulDiv((INT)time_taken, TotalContentSize, TotalReadSize) - time_taken); + + PPH_STRING dlRemaningBytes = PhFormatSize(TotalReadSize, -1); + PPH_STRING dlLength = PhFormatSize(TotalContentSize, -1); + PPH_STRING dlSpeed = PhFormatSize(bps, -1); + + if (remain < 0) + remain = 0; + if (remain >= 60) + { + remain /= 60; + rtext = L"minute"; + if (remain >= 60) + { + remain /= 60; + rtext = L"hour"; + } + } + + wsprintfW( + szDownloaded, + L"%s (%d%%) of %s @ %s/s", + dlRemaningBytes->Buffer, + MulDiv(100, TotalReadSize, TotalContentSize), + dlLength->Buffer, + dlSpeed->Buffer + ); + + if (remain) + { + wsprintfW( + szDownloaded + lstrlenW(szDownloaded), + L" (%d %s%s remaining)", + (DWORD)remain, // Cast and silence code analysis. + rtext, + remain == 1? L"": L"s" + ); + } + + SetWindowText(GetDlgItem(context->WindowHandle, IDC_STATUS), szDownloaded); + + PhDereferenceObject(dlSpeed); + PhDereferenceObject(dlLength); + PhDereferenceObject(dlRemaningBytes); + + // Update the progress bar position + SendDlgItemMessage(context->WindowHandle, IDC_UPLOADPROGRESS, PBM_SETPOS, MulDiv(100, TotalReadSize, TotalContentSize), 0); + } + } + + assert(TotalReadSize == TotalContentSize); + + // Write the footer bytes + WinHttpWriteData( + requestHandle, + ansiFooterData->Buffer, + ansiFooterData->Length, + &bytesWritten + ); + + assert(ansiFooterData->Length == bytesWritten); + + PhReferenceObject(ansiFooterData); + PhReferenceObject(ansiPostData); + } + + PhDereferenceObject(postBoundary); + PhDeleteStringBuilder(&sbPostHeader); + PhDeleteStringBuilder(&sbPostFooter); } - // Send the request. - - if (!HttpSendRequest(requestHandle, NULL, 0, data, dataLength)) + // Wait for the send request to complete and recieve the response. + if (!WinHttpReceiveResponse(requestHandle, NULL)) { - RaiseUploadError(context, L"Unable to send the request", GetLastError()); + RaiseUploadError(context, L"Unable to receive the response", GetLastError()); goto ExitCleanup; } // Handle service-specific actions. - { - ULONG index; + DWORD dwStatusCode = 0; + DWORD dwTemp = sizeof(dwStatusCode); - bufferSize = sizeof(buffer); - index = 0; + WinHttpQueryHeaders( + requestHandle, + WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + NULL, + &dwStatusCode, + &dwTemp, + NULL + ); - switch (context->Service) - { - case UPLOAD_SERVICE_VIRUSTOTAL: + if (dwStatusCode == HTTP_STATUS_OK || dwStatusCode == HTTP_STATUS_REDIRECT) + { + switch (context->Service) { - //HttpQueryInfo(requestHandle, HTTP_QUERY_RAW_HEADERS_CRLF, buffer, &bufferSize, &index); - //PhShowInformation(NULL, L"%.*s", bufferSize, buffer); - - if (!HttpQueryInfo(requestHandle, HTTP_QUERY_LOCATION, buffer, &bufferSize, &index)) + case UPLOAD_SERVICE_VIRUSTOTAL: { - RaiseUploadError(context, L"Unable to complete the request (please try again after a few minutes)", GetLastError()); - goto ExitCleanup; - } + ULONG index = 0; + PBYTE buffer = NULL; + ULONG bufferSize = 0; - if (bufferSize != 0 && *(PWCHAR)buffer == '/') - context->LaunchCommand = PhConcatStrings2(L"http://www.virustotal.com", (PWSTR)buffer); - else - context->LaunchCommand = PhCreateString((PWSTR)buffer); - } - break; - case UPLOAD_SERVICE_JOTTI: - { - PSTR hrefEquals; - PSTR quote; + WinHttpQueryHeaders( + requestHandle, + WINHTTP_QUERY_LOCATION, + WINHTTP_HEADER_NAME_BY_INDEX, + NULL, + &bufferSize, + &index + ); - // This service returns some JavaScript that redirects the user to the new location. - - if (!InternetReadFile(requestHandle, buffer, sizeof(buffer) - 1, &bufferSize)) - { - RaiseUploadError(context, L"Unable to complete the request", GetLastError()); - goto ExitCleanup; - } - - // Make sure the buffer is null-terminated. - buffer[bufferSize] = 0; - - // The JavaScript looks like this: - // top.location.href="..."; - hrefEquals = strstr(buffer, "href=\""); - - if (hrefEquals) - { - hrefEquals += 6; - quote = strchr(hrefEquals, '"'); - - if (quote) + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - context->LaunchCommand = PhFormatString( - L"http://virusscan.jotti.org%.*S", - quote - hrefEquals, - hrefEquals - ); + buffer = malloc(bufferSize); + + // Now, use WinHttpQueryHeaders to retrieve the header. + if (!WinHttpQueryHeaders( + requestHandle, + WINHTTP_QUERY_LOCATION, + WINHTTP_HEADER_NAME_BY_INDEX, + buffer, + &bufferSize, + &index + )) + { + RaiseUploadError(context, L"Unable to complete the request (please try again after a few minutes)", GetLastError()); + goto ExitCleanup; + } + } + + if (bufferSize != 0 && buffer && *(PWCHAR)buffer == '/') + { + context->LaunchCommand = PhConcatStrings2(L"http://www.virustotal.com", (PWSTR)buffer); + } + else + { + context->LaunchCommand = PhCreateString((PWSTR)buffer); + } + + if (buffer) + { + free(buffer); } } - else + break; + case UPLOAD_SERVICE_JOTTI: { - PSTR tooManyFiles; - - tooManyFiles = strstr(buffer, "Too many files"); - - if (tooManyFiles) + PSTR hrefEquals; + PSTR quote; + DWORD bytesRead = 0; + BYTE buffer[512]; + + //This service returns some JavaScript that redirects the user to the new location. + if (!WinHttpReadData(requestHandle, buffer, 512, &bytesRead)) { - RaiseUploadError( - context, - L"Unable to scan the file:\n\n" - L"Too many files have been scanned from this IP in a short period. " - L"Please try again later", - 0 - ); + RaiseUploadError(context, L"Unable to complete the request", GetLastError()); + goto ExitCleanup; + } + + //Make sure the buffer is null-terminated. + buffer[bytesRead] = 0; + /* + The JavaScript looks like this: + top.location.href="...";*/ + hrefEquals = strstr(buffer, "href=\""); + + if (hrefEquals) + { + hrefEquals += 6; + quote = strchr(hrefEquals, '"'); + + if (quote) + { + context->LaunchCommand = PhFormatString( + L"http://virusscan.jotti.org%.*S", + quote - hrefEquals, + hrefEquals + ); + } + } + else + { + PSTR tooManyFiles = strstr(buffer, "Too many files"); + + if (tooManyFiles) + { + RaiseUploadError( + context, + L"Unable to scan the file:\n\n" + L"Too many files have been scanned from this IP in a short period. " + L"Please try again later", + 0 + ); + + goto ExitCleanup; + } + } + + if (!context->LaunchCommand) + { + RaiseUploadError(context, L"Unable to complete the request (please try again after a few minutes)", 0); goto ExitCleanup; } } + break; + case UPLOAD_SERVICE_CIMA: + { + BYTE buffer[512]; + DWORD bytesRead = 0; + PSTR urlEquals; + PSTR quote; - if (!context->LaunchCommand) - { - RaiseUploadError(context, L"Unable to complete the request (please try again after a few minutes)", 0); - goto ExitCleanup; - } - } - break; - case UPLOAD_SERVICE_CIMA: - { - PSTR urlEquals; - PSTR quote; + // This service returns some HTML that redirects the user to the new location. - // This service returns some HTML that redirects the user to the new location. - - if (!InternetReadFile(requestHandle, buffer, sizeof(buffer) - 1, &bufferSize)) - { - RaiseUploadError(context, L"Unable to complete the request", GetLastError()); - goto ExitCleanup; - } - - // Make sure the buffer is null-terminated. - buffer[bufferSize] = 0; - - // The HTML looks like this: - // - urlEquals = strstr(buffer, "url="); - - if (urlEquals) - { - urlEquals += 4; - quote = strchr(urlEquals, '"'); - - if (quote) + if (!WinHttpReadData(requestHandle, buffer, 512, &bytesRead)) { - context->LaunchCommand = PhFormatString( - L"http://camas.comodo.com%.*S", - quote - urlEquals, - urlEquals - ); + RaiseUploadError(context, L"Unable to complete the request", GetLastError()); + goto ExitCleanup; + } + + // Make sure the buffer is null-terminated. + buffer[bytesRead] = 0; + + // The HTML looks like this: + // + urlEquals = strstr(buffer, "url="); + + if (urlEquals) + { + urlEquals += 4; + quote = strchr(urlEquals, '"'); + + if (quote) + { + context->LaunchCommand = PhFormatString( + L"http://camas.comodo.com%.*S", + quote - urlEquals, + urlEquals + ); + } + } + + if (!context->LaunchCommand) + { + RaiseUploadError(context, L"Unable to complete the request (please try again after a few minutes)", 0); + goto ExitCleanup; } } - - if (!context->LaunchCommand) + break; + default: { - RaiseUploadError(context, L"Unable to complete the request (please try again after a few minutes)", 0); + RaiseUploadError(context, L"Unable to complete the request", 0); goto ExitCleanup; } + break; } - break; - default: - { - RaiseUploadError(context, L"Unable to complete the request", 0); - goto ExitCleanup; - } - break; - } - SendLaunchCommand(context); + if (context->WindowHandle) + { + PostMessage(context->WindowHandle, UM_LAUNCH_COMMAND, 0, 0); + } + } + else + { + RaiseUploadError(context, L"Unable to complete the request", 0); + goto ExitCleanup; + } } ExitCleanup: - if (data) - PhFreePage(data); - if (baseFileNameAnsi) - PhDereferenceObject(baseFileNameAnsi); - if (headers.String) - PhDeleteStringBuilder(&headers); - if (boundaryAnsi) - PhDereferenceObject(boundaryAnsi); - if (boundary) - PhDereferenceObject(boundary); + if (requestHandle) - InternetCloseHandle(requestHandle); + WinHttpCloseHandle(requestHandle); if (connectHandle) - InternetCloseHandle(connectHandle); + WinHttpCloseHandle(connectHandle); if (internetHandle) - InternetCloseHandle(internetHandle); + WinHttpCloseHandle(internetHandle); if (objectName) PhDereferenceObject(objectName); if (fileHandle) @@ -958,20 +1077,37 @@ INT_PTR CALLBACK UploadDlgProc( { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetDlgItemText(hwndDlg, IDC_MESSAGE, L"Uploading..."); + _InterlockedIncrement(&context->RefCount); context->WindowHandle = hwndDlg; - ReferenceUploadContext(context); - context->ThreadHandle = PhCreateThread(0, UploadWorkerThreadStart, context); + // Center the update window on PH if visible and not mimimized else center on desktop. + PhCenterWindow(hwndDlg, (IsWindowVisible(GetParent(hwndDlg)) && !IsIconic(GetParent(hwndDlg))) ? GetParent(hwndDlg) : NULL); + + InitializeFont(GetDlgItem(hwndDlg, IDC_MESSAGE)); + + + if (context->FileName) + { + WCHAR szWindowText[MAX_PATH]; + PPH_STRING baseFileName = PhGetBaseName(context->FileName); + swprintf_s( + szWindowText, + _countof(szWindowText), + L"Uploading: %s", + baseFileName->Buffer + ); + + SetDlgItemText(hwndDlg, IDC_MESSAGE, szWindowText); + PhDereferenceObject(baseFileName); + + context->ThreadHandle = PhCreateThread(0, UploadWorkerThreadStart, context); + } } break; case WM_DESTROY: { - PhAcquireQueuedLockExclusive(&context->Lock); context->WindowHandle = NULL; - PhReleaseQueuedLockExclusive(&context->Lock); } break; case WM_COMMAND: @@ -984,6 +1120,25 @@ INT_PTR CALLBACK UploadDlgProc( } } break; + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLORSTATIC: + { + HDC hDC = (HDC)wParam; + HWND hwndChild = (HWND)lParam; + + // Check for our static label and change the color. + if (GetDlgCtrlID(hwndChild) == IDC_MESSAGE) + { + SetTextColor(hDC, RGB(19, 112, 171)); + } + + // Set a transparent background for the control backcolor. + SetBkMode(hDC, TRANSPARENT); + + // set window background color. + return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);; + } case UM_LAUNCH_COMMAND: { PhShellExecute(hwndDlg, context->LaunchCommand->Buffer, NULL);