* OnlineChecks: updated VirusTotal and virusscan.jotti.org uploaders

* OnlineChecks: added hash checking

git-svn-id: svn://svn.code.sf.net/p/processhacker/code@4950 21ef857c-d57f-4fe0-8362-d861dc6d29cd
This commit is contained in:
wj32
2012-01-16 02:07:06 +00:00
parent 5667dafb66
commit e905b99eec
9 changed files with 769 additions and 21 deletions
+2
View File
@@ -2,6 +2,8 @@ Process Hacker
2.27
* NEW/IMPROVED:
* Updated OnlineChecks plugin:
* 2012-01-16: Updated VirusTotal uploader and added hash checking
* FIXED:
2.26
+2 -2
View File
@@ -584,10 +584,10 @@ CAPTION "About"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,213,174,50,14
ICON IDI_PROCESSHACKER,IDC_STATIC,16,15,21,20
ICON IDI_PROCESSHACKER,IDC_STATIC,16,15,20,20
LTEXT "Process Hacker",IDC_ABOUT_NAME,45,14,192,8
LTEXT "Licensed under the GNU GPL, v3.",IDC_STATIC,45,27,193,8
LTEXT "Copyright (c) 2008-2011 wj32",IDC_STATIC,15,40,97,8
LTEXT "Copyright (c) 2008-2012 wj32",IDC_STATIC,15,40,97,8
PUSHBUTTON "Diagnostics",IDC_DIAGNOSTICS,160,174,50,14
CONTROL "<a href=""http://sourceforge.net/projects/processhacker"">Process Hacker on SourceForge.net</a>",IDC_LINK_SF,
"SysLink",WS_TABSTOP,7,177,130,11
@@ -1,3 +1,6 @@
1.3
* 2012-01-16: Updated VirusTotal uploader and added hash checking
1.2
* 2011-06-22: Added Comodo Instant Malware Analysis
@@ -53,8 +53,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,2,0,0
PRODUCTVERSION 1,2,0,0
FILEVERSION 1,3,0,0
PRODUCTVERSION 1,3,0,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -71,12 +71,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "wj32"
VALUE "FileDescription", "Online Checks plugin for Process Hacker"
VALUE "FileVersion", "1.2"
VALUE "FileVersion", "1.3"
VALUE "InternalName", "OnlineChecks"
VALUE "LegalCopyright", "Licensed under the GNU GPL, v3."
VALUE "OriginalFilename", "OnlineChecks.dll"
VALUE "ProductName", "Online Checks plugin for Process Hacker"
VALUE "ProductVersion", "1.2"
VALUE "ProductVersion", "1.3"
END
END
BLOCK "VarFileInfo"
@@ -163,11 +163,13 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.c" />
<ClCompile Include="sha256.c" />
<ClCompile Include="upload.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="onlnchk.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="sha256.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="OnlineChecks.rc" />
@@ -21,6 +21,9 @@
<ClCompile Include="upload.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sha256.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="onlnchk.h">
@@ -29,6 +32,9 @@
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="sha256.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="OnlineChecks.rc">
+369
View File
@@ -0,0 +1,369 @@
/*
* FIPS-180-2 compliant SHA-256 implementation
*
* Copyright (C) 2001-2003 Christophe Devine
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string.h>
#include "sha256.h"
#define GET_UINT32(n,b,i) \
{ \
(n) = ( (uint32) (b)[(i) ] << 24 ) \
| ( (uint32) (b)[(i) + 1] << 16 ) \
| ( (uint32) (b)[(i) + 2] << 8 ) \
| ( (uint32) (b)[(i) + 3] ); \
}
#define PUT_UINT32(n,b,i) \
{ \
(b)[(i) ] = (uint8) ( (n) >> 24 ); \
(b)[(i) + 1] = (uint8) ( (n) >> 16 ); \
(b)[(i) + 2] = (uint8) ( (n) >> 8 ); \
(b)[(i) + 3] = (uint8) ( (n) ); \
}
void sha256_starts( sha256_context *ctx )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x6A09E667;
ctx->state[1] = 0xBB67AE85;
ctx->state[2] = 0x3C6EF372;
ctx->state[3] = 0xA54FF53A;
ctx->state[4] = 0x510E527F;
ctx->state[5] = 0x9B05688C;
ctx->state[6] = 0x1F83D9AB;
ctx->state[7] = 0x5BE0CD19;
}
void sha256_process( sha256_context *ctx, uint8 data[64] )
{
uint32 temp1, temp2, W[64];
uint32 A, B, C, D, E, F, G, H;
GET_UINT32( W[0], data, 0 );
GET_UINT32( W[1], data, 4 );
GET_UINT32( W[2], data, 8 );
GET_UINT32( W[3], data, 12 );
GET_UINT32( W[4], data, 16 );
GET_UINT32( W[5], data, 20 );
GET_UINT32( W[6], data, 24 );
GET_UINT32( W[7], data, 28 );
GET_UINT32( W[8], data, 32 );
GET_UINT32( W[9], data, 36 );
GET_UINT32( W[10], data, 40 );
GET_UINT32( W[11], data, 44 );
GET_UINT32( W[12], data, 48 );
GET_UINT32( W[13], data, 52 );
GET_UINT32( W[14], data, 56 );
GET_UINT32( W[15], data, 60 );
#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
#define F0(x,y,z) ((x & y) | (z & (x | y)))
#define F1(x,y,z) (z ^ (x & (y ^ z)))
#define R(t) \
( \
W[t] = S1(W[t - 2]) + W[t - 7] + \
S0(W[t - 15]) + W[t - 16] \
)
#define P(a,b,c,d,e,f,g,h,x,K) \
{ \
temp1 = h + S3(e) + F1(e,f,g) + K + x; \
temp2 = S2(a) + F0(a,b,c); \
d += temp1; h = temp1 + temp2; \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
F = ctx->state[5];
G = ctx->state[6];
H = ctx->state[7];
P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 );
P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 );
P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF );
P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 );
P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B );
P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 );
P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 );
P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 );
P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 );
P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 );
P( G, H, A, B, C, D, E, F, W[10], 0x243185BE );
P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 );
P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 );
P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE );
P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 );
P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 );
P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 );
P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 );
P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 );
P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC );
P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F );
P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA );
P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC );
P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA );
P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 );
P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D );
P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 );
P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 );
P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 );
P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 );
P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 );
P( B, C, D, E, F, G, H, A, R(31), 0x14292967 );
P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 );
P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 );
P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC );
P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 );
P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 );
P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB );
P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E );
P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 );
P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 );
P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B );
P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 );
P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 );
P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 );
P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 );
P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 );
P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 );
P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 );
P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 );
P( G, H, A, B, C, D, E, F, R(50), 0x2748774C );
P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 );
P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 );
P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A );
P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F );
P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 );
P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE );
P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F );
P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 );
P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 );
P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA );
P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB );
P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 );
P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 );
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
ctx->state[4] += E;
ctx->state[5] += F;
ctx->state[6] += G;
ctx->state[7] += H;
}
void sha256_update( sha256_context *ctx, uint8 *input, uint32 length )
{
uint32 left, fill;
if( ! length ) return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += length;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < length )
ctx->total[1]++;
if( left && length >= fill )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, fill );
sha256_process( ctx, ctx->buffer );
length -= fill;
input += fill;
left = 0;
}
while( length >= 64 )
{
sha256_process( ctx, input );
length -= 64;
input += 64;
}
if( length )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, length );
}
}
static uint8 sha256_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
void sha256_finish( sha256_context *ctx, uint8 digest[32] )
{
uint32 last, padn;
uint32 high, low;
uint8 msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32( high, msglen, 0 );
PUT_UINT32( low, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
sha256_update( ctx, sha256_padding, padn );
sha256_update( ctx, msglen, 8 );
PUT_UINT32( ctx->state[0], digest, 0 );
PUT_UINT32( ctx->state[1], digest, 4 );
PUT_UINT32( ctx->state[2], digest, 8 );
PUT_UINT32( ctx->state[3], digest, 12 );
PUT_UINT32( ctx->state[4], digest, 16 );
PUT_UINT32( ctx->state[5], digest, 20 );
PUT_UINT32( ctx->state[6], digest, 24 );
PUT_UINT32( ctx->state[7], digest, 28 );
}
#ifdef TEST
#include <stdlib.h>
#include <stdio.h>
/*
* those are the standard FIPS-180-2 test vectors
*/
static char *msg[] =
{
"abc",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
NULL
};
static char *val[] =
{
"ba7816bf8f01cfea414140de5dae2223" \
"b00361a396177a9cb410ff61f20015ad",
"248d6a61d20638b8e5c026930c3e6039" \
"a33ce45964ff2167f6ecedd419db06c1",
"cdc76e5c9914fb9281a1c7e284d73e67" \
"f1809a48a497200e046d39ccc7112cd0"
};
int main( int argc, char *argv[] )
{
FILE *f;
int i, j;
char output[65];
sha256_context ctx;
unsigned char buf[1000];
unsigned char sha256sum[32];
if( argc < 2 )
{
printf( "\n SHA-256 Validation Tests:\n\n" );
for( i = 0; i < 3; i++ )
{
printf( " Test %d ", i + 1 );
sha256_starts( &ctx );
if( i < 2 )
{
sha256_update( &ctx, (uint8 *) msg[i],
strlen( msg[i] ) );
}
else
{
memset( buf, 'a', 1000 );
for( j = 0; j < 1000; j++ )
{
sha256_update( &ctx, (uint8 *) buf, 1000 );
}
}
sha256_finish( &ctx, sha256sum );
for( j = 0; j < 32; j++ )
{
sprintf( output + j * 2, "%02x", sha256sum[j] );
}
if( memcmp( output, val[i], 64 ) )
{
printf( "failed!\n" );
return( 1 );
}
printf( "passed.\n" );
}
printf( "\n" );
}
else
{
if( ! ( f = fopen( argv[1], "rb" ) ) )
{
perror( "fopen" );
return( 1 );
}
sha256_starts( &ctx );
while( ( i = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
{
sha256_update( &ctx, buf, i );
}
sha256_finish( &ctx, sha256sum );
for( j = 0; j < 32; j++ )
{
printf( "%02x", sha256sum[j] );
}
printf( " %s\n", argv[1] );
}
return( 0 );
}
#endif
+25
View File
@@ -0,0 +1,25 @@
#ifndef _SHA256_H
#define _SHA256_H
#ifndef uint8
#define uint8 unsigned char
#endif
#ifndef uint32
#define uint32 unsigned long int
#endif
typedef struct
{
uint32 total[2];
uint32 state[8];
uint8 buffer[64];
}
sha256_context;
void sha256_starts( sha256_context *ctx );
void sha256_update( sha256_context *ctx, uint8 *input, uint32 length );
void sha256_finish( sha256_context *ctx, uint8 digest[32] );
#endif /* sha256.h */
+356 -15
View File
@@ -2,7 +2,7 @@
* Process Hacker Online Checks -
* uploader
*
* Copyright (C) 2010-2011 wj32
* Copyright (C) 2010-2012 wj32
*
* This file is part of Process Hacker.
*
@@ -23,8 +23,12 @@
#include <phdk.h>
#include <wininet.h>
#include "onlnchk.h"
#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)
@@ -35,6 +39,7 @@ typedef struct _UPLOAD_CONTEXT
PPH_STRING FileName;
ULONG Service;
HWND WindowHandle;
PH_QUEUED_LOCK Lock;
HANDLE ThreadHandle;
PPH_STRING LaunchCommand;
@@ -45,6 +50,8 @@ typedef struct _SERVICE_INFO
{
ULONG Id;
PWSTR HostName;
ULONG HostPort;
ULONG HostFlags;
PWSTR UploadObjectName;
PSTR FileNameFieldName;
} SERVICE_INFO, *PSERVICE_INFO;
@@ -58,9 +65,9 @@ INT_PTR CALLBACK UploadDlgProc(
SERVICE_INFO UploadServiceInfo[] =
{
{ UPLOAD_SERVICE_VIRUSTOTAL, L"www.virustotal.com", L"/file-upload/file_upload", "file" },
{ UPLOAD_SERVICE_JOTTI, L"virusscan.jotti.org", L"/processupload.php", "scanfile" },
{ UPLOAD_SERVICE_CIMA, L"camas.comodo.com", L"/cgi-bin/submit", "file" }
{ 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" }
};
PUPLOAD_CONTEXT CreateUploadContext(
@@ -144,8 +151,24 @@ 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(
@@ -163,6 +186,202 @@ 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
)
{
BOOLEAN result = FALSE;
PPH_STRING userAgent;
HINTERNET internetHandle = NULL;
HINTERNET connectHandle = NULL;
HINTERNET requestHandle = NULL;
// Create a user agent string.
{
PPH_STRING phVersion;
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)
{
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));
}
// Connect to the online service.
connectHandle = InternetConnect(
internetHandle,
HostName,
80,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
0,
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)
{
RaiseUploadError(Context, L"Unable to create the request", GetLastError());
goto ExitCleanup;
}
// Send the request.
if (!HttpSendRequest(requestHandle, NULL, 0, NULL, 0))
{
RaiseUploadError(Context, L"Unable to send the request", GetLastError());
goto ExitCleanup;
}
// Handle service-specific actions.
if (!InternetReadFile(requestHandle, Buffer, BufferLength, ReturnLength))
{
RaiseUploadError(Context, L"Unable to complete the request", GetLastError());
goto ExitCleanup;
}
result = TRUE;
ExitCleanup:
if (requestHandle)
InternetCloseHandle(requestHandle);
if (connectHandle)
InternetCloseHandle(connectHandle);
if (internetHandle)
InternetCloseHandle(internetHandle);
return result;
}
static NTSTATUS HashFileAndResetPosition(
__in HANDLE FileHandle,
__in PLARGE_INTEGER FileSize,
__in ULONG Algorithm,
__out PVOID Hash
)
{
NTSTATUS status;
UCHAR buffer[PAGE_SIZE * 4];
IO_STATUS_BLOCK iosb;
PH_HASH_CONTEXT hashContext;
sha256_context sha256;
ULONG64 bytesRemaining;
FILE_POSITION_INFORMATION positionInfo;
bytesRemaining = FileSize->QuadPart;
switch (Algorithm)
{
case HASH_SHA1:
PhInitializeHash(&hashContext, Sha1HashAlgorithm);
break;
case HASH_SHA256:
sha256_starts(&sha256);
break;
}
while (bytesRemaining)
{
status = NtReadFile(
FileHandle,
NULL,
NULL,
NULL,
&iosb,
buffer,
sizeof(buffer),
NULL,
NULL
);
if (!NT_SUCCESS(status))
break;
switch (Algorithm)
{
case HASH_SHA1:
PhUpdateHash(&hashContext, buffer, (ULONG)iosb.Information);
break;
case HASH_SHA256:
sha256_update(&sha256, (PUCHAR)buffer, (ULONG)iosb.Information);
break;
}
bytesRemaining -= (ULONG)iosb.Information;
}
if (status == STATUS_END_OF_FILE)
status = STATUS_SUCCESS;
if (NT_SUCCESS(status))
{
switch (Algorithm)
{
case HASH_SHA1:
PhFinalHash(&hashContext, Hash, 20, NULL);
break;
case HASH_SHA256:
sha256_finish(&sha256, Hash);
break;
}
positionInfo.CurrentByteOffset.QuadPart = 0;
status = NtSetInformationFile(FileHandle, &iosb, &positionInfo, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation);
}
return status;
}
static NTSTATUS UploadWorkerThreadStart(
__in PVOID Parameter
)
@@ -172,17 +391,21 @@ static NTSTATUS UploadWorkerThreadStart(
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;
PPH_ANSI_STRING baseFileNameAnsi = NULL;
PUCHAR data = NULL;
ULONG dataLength = 0;
ULONG dataCursor = 0;
UCHAR buffer[PAGE_SIZE];
ULONG bufferSize;
serviceInfo = GetUploadServiceInfo(context->Service);
@@ -206,8 +429,6 @@ static NTSTATUS UploadWorkerThreadStart(
if (NT_SUCCESS(status))
{
LARGE_INTEGER fileSize64;
if (NT_SUCCESS(status = PhGetFileSize(fileHandle, &fileSize64)))
{
if (fileSize64.QuadPart > 20 * 1024 * 1024) // 20 MB
@@ -226,6 +447,124 @@ static NTSTATUS UploadWorkerThreadStart(
goto ExitCleanup;
}
switch (context->Service)
{
case UPLOAD_SERVICE_VIRUSTOTAL:
{
UCHAR hash[32];
PPH_STRING hashString;
PPH_STRING subObjectName;
PSTR uploadUrl;
PSTR quote;
status = HashFileAndResetPosition(fileHandle, &fileSize64, HASH_SHA256, hash);
if (!NT_SUCCESS(status))
{
RaiseUploadError(context, L"Unable to hash the file", RtlNtStatusToDosError(status));
goto ExitCleanup;
}
hashString = PhBufferToHexString(hash, 32);
subObjectName = PhConcatStrings2(L"/file/upload/?sha256=", hashString->Buffer);
if (!PerformSubRequest(context, serviceInfo->HostName, subObjectName->Buffer, buffer, sizeof(buffer) - 1, &bufferSize))
{
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;
}
PhDereferenceObject(hashString);
uploadUrl = strstr(buffer, "\"upload_url\": \"https://www.virustotal.com");
if (!uploadUrl)
{
RaiseUploadError(context, L"Unable to complete the request (no upload URL provided)", 0);
goto ExitCleanup;
}
uploadUrl += 41;
quote = strchr(uploadUrl, '"');
if (!quote)
{
RaiseUploadError(context, L"Unable to complete the request (invalid upload URL)", 0);
goto ExitCleanup;
}
objectName = PhCreateStringFromAnsiEx(uploadUrl, quote - uploadUrl);
}
break;
case UPLOAD_SERVICE_JOTTI:
{
UCHAR hash[20];
PPH_STRING hashString;
PPH_STRING subObjectName;
PSTR id;
PSTR quote;
status = HashFileAndResetPosition(fileHandle, &fileSize64, HASH_SHA1, hash);
if (!NT_SUCCESS(status))
{
RaiseUploadError(context, L"Unable to hash the file", RtlNtStatusToDosError(status));
goto ExitCleanup;
}
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))
{
PhDereferenceObject(hashString);
PhDereferenceObject(subObjectName);
goto ExitCleanup;
}
PhDereferenceObject(hashString);
PhDereferenceObject(subObjectName);
buffer[bufferSize] = 0;
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;
}
}
objectName = PhCreateString(serviceInfo->UploadObjectName);
}
break;
default:
{
objectName = PhCreateString(serviceInfo->UploadObjectName);
}
break;
}
// Create a user agent string.
{
PPH_STRING phVersion;
@@ -262,7 +601,7 @@ static NTSTATUS UploadWorkerThreadStart(
connectHandle = InternetConnect(
internetHandle,
serviceInfo->HostName,
80,
serviceInfo->HostPort,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
@@ -284,11 +623,11 @@ static NTSTATUS UploadWorkerThreadStart(
requestHandle = HttpOpenRequest(
connectHandle,
L"POST",
serviceInfo->UploadObjectName,
objectName->Buffer,
L"HTTP/1.1",
L"",
acceptTypes,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_AUTO_REDIRECT,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_AUTO_REDIRECT | serviceInfo->HostFlags,
0
);
}
@@ -426,8 +765,6 @@ static NTSTATUS UploadWorkerThreadStart(
// Handle service-specific actions.
{
UCHAR buffer[PAGE_SIZE];
ULONG bufferSize;
ULONG index;
bufferSize = sizeof(buffer);
@@ -475,7 +812,7 @@ static NTSTATUS UploadWorkerThreadStart(
if (hrefEquals)
{
hrefEquals += 6;
quote = strchr(hrefEquals, '\"');
quote = strchr(hrefEquals, '"');
if (quote)
{
@@ -535,7 +872,7 @@ static NTSTATUS UploadWorkerThreadStart(
if (urlEquals)
{
urlEquals += 4;
quote = strchr(urlEquals, '\"');
quote = strchr(urlEquals, '"');
if (quote)
{
@@ -562,7 +899,7 @@ static NTSTATUS UploadWorkerThreadStart(
break;
}
PostMessage(context->WindowHandle, UM_LAUNCH_COMMAND, 0, 0);
SendLaunchCommand(context);
}
ExitCleanup:
@@ -582,6 +919,8 @@ ExitCleanup:
InternetCloseHandle(connectHandle);
if (internetHandle)
InternetCloseHandle(internetHandle);
if (objectName)
PhDereferenceObject(objectName);
if (fileHandle)
NtClose(fileHandle);
@@ -630,7 +969,9 @@ INT_PTR CALLBACK UploadDlgProc(
break;
case WM_DESTROY:
{
PhAcquireQueuedLockExclusive(&context->Lock);
context->WindowHandle = NULL;
PhReleaseQueuedLockExclusive(&context->Lock);
}
break;
case WM_COMMAND: