Valid HTML 4.01 Transitional Valid CSS Valid SVG 1.0

Me, myself & IT

Write, Read and Execute NTFS Alternate Data Streams

Purpose
Background Information
Demonstration

Purpose

Background Information

The MSKB article 105763 provides an introduction to NTFS alternate data streams.

Demonstration

Perform the following 20 simple steps to build a DLL, a console and a Windows application solely within NTFS alternate data streams and execute them.
  1. Start the command prompt of the Windows SDK in an arbitrary, preferable empty directory, then create an (empty) file or subdirectory, for example streams, there:

    IF DEFINED STREAMS (MKDIR streams) ELSE (COPY NUL: streams)
            1 file(s) copied.
  2. Write the hexadecimal dump of a 16-bit DOS program that prints its copyright message on standard output to an alternate data stream, for example .txt, of the file or subdirectory created in step 1.:

    IF EXIST streams @(
    ECHO 4d 5a 90 00 01 00 00 00 04 00 00 00 ff ff 00 00 e0 00 00 00 43 00 00 00
    ECHO 40 00 00 00 00 00 00 00 00 00 00 00 19 57 04 27 00 00 00 00 00 00 00 00
    ECHO 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28 43 29 6f 70 79 72 69
    ECHO 67 68 74 20 32 30 30 34 2d 32 30 32 36 2c 20 53 74 65 66 61 6e 20 4b 61
    ECHO 6e 74 68 61 6b 20 3c 73 74 65 66 61 6e 2e 6b 61 6e 74 68 61 6b 40 6e 65
    ECHO 78 67 6f 2e 64 65 3e 0d 0a 07 24 0e 1f 33 d2 b4 09 cd 21 b8 01 4c cd 21) 1>streams:.txt
    Note: the MSKB article 65122 documents the IMAGE_DOS_HEADER structure contained in the first 64 bytes; it is followed by the 67 ASCII characters (C)opyright 2004-2026, Stefan Kanthak <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>\r\n\a$ and the real mode machine code.

    Note: the command lines can be copied and pasted as block into a Command Processor window.

  3. Decode the 16-bit DOS program to another alternate data stream, for example .dos, of the file or subdirectory created in step 1.:

    CERTUTIL.EXE /DecodeHex streams:.txt streams:.dos
    Input Length = 438
    Output Length = 144
    CertUtil: -decodehex command completed successfully.
  4. Execute the 16-bit DOS program created in step 3.:

    .\streams:.dos
    The syntax of the command is incorrect.
    Oops¹: except for input and output redirection, and except for its internal Dir and Mklink commands, the Command Processor Cmd.exe fails to support alternate data streams!
  5. Write a JScript that prints its pathname on standard output to the alternate data stream .js of the file or subdirectory created in step 1. and execute it with the Windows Script Host console application:

    1>streams:.js ECHO WScript.Echo(WScript.ScriptFullName)
    CSCRIPT.EXE streams:.js
    Microsoft (R) Windows Script Host, Version 5.8
    Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.
    
    C:\Users\Stefan\Desktop\streams:.js
  6. Write a VBScript that executes the 16-bit DOS program decoded in step 3. and prints its standard output to the alternate data stream .vbs of the file or subdirectory created in step 1. and execute it with the Windows Script Host console application:

    1>streams:.vbs ECHO WScript.Echo WScript.CreateObject("WScript.Shell").Exec("%CD%\streams:.dos").StdOut.ReadAll()
    CSCRIPT.EXE streams:.vbs
    32-bit editions of Windows execute the 16-bit DOS program:
    Microsoft (R) Windows Script Host, Version 5.8
    Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.
    
    (C)opyright 2004-2026, Stefan Kanthak <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>

    [Screen shot of message box from module loader on Windows 7] 64-bit editions of Windows don’t support 16-bit DOS programs and display the message box shown to the right:

    C:\Users\Stefan\Desktop\streams:.vbs(1, 1) WshShell.Exec: This version of C:\Users\Stefan\Desktop\streams:.dos is not compatible with the version of Windows you're running. Check your computer's system information to see whether you need an x86 (32-bit) or x64 (64-bit) version of the program, and then contact the software publisher.

  7. Write an ANSI C source code to the alternate data stream .c of the file or subdirectory created in step 1.:

    1>streams:.c ECHO unsigned _DllMainCRTStartup(void *module, unsigned reason, void *context) { return 0; }
  8. Compile and link the source code from the alternate data stream .c written in step 7.:

    SET CL=/Fa /Gz /LD /W4 /Zl
    SET LINK=/MANIFEST /MAP /NODEFAULTLIB /STUB:streams:.dos
    CL.EXE streams:.c
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    streams:.c
    
    Microsoft (R) Incremental Linker Version 10.00.40219.386
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /MANIFEST /MAP /NODEFAULTLIB /STUB:streams:.dos
    /out:streams:.dll
    /dll
    /implib:streams:.lib
    streams:.obj
    Note: the Visual C compiler writes its output to one or more alternate data streams of the file or subdirectory from which it reads the alternate data stream with the (first) source, then the linker reads object file and DOS stub from and writes its output to one or more alternate data streams of the same file or subdirectory.
  9. List the alternate data streams of the (still empty) file or subdirectory created in step 1.:

    DIR /R streams
     Volume in drive C has no label.
     Volume Serial Number is 1957-0427
    
     Directory of C:\Users\Stefan\Desktop
    
    04/27/2012  08:15 PM                 0 streams
                                       619 streams:.asm:$DATA
                                        89 streams:.c:$DATA
                                     1.024 streams:.dll:$DATA
                                       381 streams:.dll.manifest:$DATA
                                       144 streams:.dos:$DATA
                                        38 streams:.js:$DATA
                                       577 streams:.map:$DATA
                                       469 streams:.obj:$DATA
                                       438 streams:.txt:$DATA
                                       114 streams:.vbs:$DATA
                   1 File(s)              0 bytes
                   0 Dir(s)    9,876,543,210 bytes free
  10. Execute the DLL built in step 8. via the Windows host process (Rundll32) application:

    [Screen shot of error message box from 'Windows host process (Rundll32)' on Windows 7]

    RUNDLL32.EXE "%CD%\streams:.dll",#0
    Note: the error message box is expected – the _DllMainCRTStartup() function intentionally returns 0 alias FALSE to let the Win32 functions LoadLibrary() and LoadLibraryEx() fail with Win32 error code 1114 alias ERROR_DLL_INIT_FAILED.
  11. Write another ANSI C source code to the alternate data stream .c of the file or subdirectory created in step 1.:

    1>streams:.c ECHO unsigned mainCRTStartup(void) { return 'NTFS'; }
  12. Compile and link the source code from the alternate data stream .c overwritten in step 11.:

    SET CL=/Gd /W4 /Zl
    SET LINK=/ENTRY:mainCRTStartup /NODEFAULTLIB /STUB:streams:.dos /SUBSYSTEM:CONSOLE
    CL.EXE streams:.c
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    streams:.c
    
    Microsoft (R) Incremental Linker Version 10.00.40219.386
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /ENTRY:mainCRTStartup /NODEFAULTLIB /STUB:streams:.dos /SUBSYSTEM:CONSOLE
    /out:streams:.exe
    streams:.obj
  13. Write a VBScript that executes the Win32 console application built in step 12. and prints its exit code to the alternate data stream .vbs of the file or subdirectory created in step 1. and execute it with the Windows Script Host console application:

    IF EXIST streams @(
    ECHO With WScript.CreateObject("WScript.Shell"^).Exec("%CD%\streams:.exe"^)
    ECHO     Do
    ECHO         WScript.Sleep(99^)
    ECHO     Loop Until .Status = 1
    ECHO     WScript.Echo Hex(.ExitCode^)
    ECHO End With) 1>streams:.vbs
    CSCRIPT.EXE streams:.vbs
    Microsoft (R) Windows Script Host, Version 5.8
    Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.
    
    4E544653
  14. Write an intentionally invalid external manifest for the Win32 console application built in step 12. to the alternate data stream .exe.manifest of the file or subdirectory created in step 1.:

    1>streams:.exe.manifest ECHO ^<?xml version='1.0' encoding='US-ASCII' standalone='yes' ?^>
  15. Execute the Win32 console application built in step 12. via the VBScript overwritten in step 13. again:

    CSCRIPT.EXE streams:.vbs
    Microsoft (R) Windows Script Host, Version 5.8
    Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.
    
    C:\Users\Stefan\Desktop\streams:.vbs(1, 1) WshShell.Exec: The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log or use the command-line sxstrace.exe tool for more detail.
    Oops²: Windows’ module loader honors external manifests for executable image files stored in alternate data streams!
  16. Write another external manifest for the Win32 console application built in step 12. to the alternate data stream .exe.manifest of the file or subdirectory created in step 1.:

    IF EXIST streams @(
    ECHO ^<?xml version='1.0' encoding='UTF-8' standalone='yes' ?^>
    ECHO ^<assembly manifestVersion='1.0' xmlns='urn:schemas-microsoft-com:asm.v1'^>
    ECHO     ^<file loadFrom='%CD%\streams:.dll' name='kernel32.dll' /^>
    ECHO ^</assembly^>) 1>streams:.exe.manifest
  17. Execute the Win32 console application built in step 12. via the VBScript overwritten in step 13. once more:

    [Screen shot of error message box from module loader on Windows 7]

    CSCRIPT.EXE streams:.vbs
    Microsoft (R) Windows Script Host, Version 5.8
    Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.
    
    C0000139
    OUCH: Windows’ module loader displays the error message box for NTSTATUS 0xC000007A alias STATUS_PROCEDURE_NOT_FOUND shown to the right – it loads multiple unreferenced DLLs with the Win32 console application built without dependencies in step 12. and fails with NTSTATUS 0xC0000139 alias STATUS_ENTRYPOINT_NOT_FOUND since the (external) manifest overwritten in step 16. redirects kernel32.dll to the alternate data stream that contains the DLL built in step 8. without exports and imports!
  18. Write yet another ANSI C source code to the alternate data stream .c of the file or subdirectory created in step 1.:

    1>streams:.c ECHO void wWinMainCRTStartup(void) { ExitProcess(MessageBox(HWND_DESKTOP, GetCommandLine(), __LPREFIX(__FUNCTION__), MB_OK) ? ERROR_SUCCESS : GetLastError()); }
  19. Compile and link the source code from the alternate data stream .c overwritten in step 18.:

    SET CL=/DSTRICT /DUNICODE /DWIN32_LEAN_AND_MEAN /FIwindows.h /Gd /W4 /we4013 /Zl
    SET LINK=/ENTRY:wWinMainCRTStartup /FIXED /MANIFEST /NODEFAULTLIB /STUB:streams:.dos /SUBSYSTEM:WINDOWS
    CL.EXE streams:.c kernel32.lib user32.lib
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    streams:.c
    
    Microsoft (R) Incremental Linker Version 10.00.40219.386
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /ENTRY:wWinMainCRTStartup /FIXED /MANIFEST /NODEFAULTLIB /STUB:streams:.dos /SUBSYSTEM:WINDOWS
    /out:streams:.exe
    kernel32.lib
    user32.lib
    streams:.obj
  20. Execute the Windows application built in step 19. via the WMI Commandline Utility console application:

    [Screen shot of message box on Windows 7]

    WMIC.EXE PROCESS CALL CREATE "%CD%\streams:.exe"
    Executing (Win32_Process)->Create()
    Method execution successful.
    Out Parameters:
    instance of __PARAMETERS
    {
    	ProcessId = 9876;
    	ReturnValue = 0;
    };
Note: a repetition using a subdirectory instead of a file is left as an exercise to the reader.

Contact and Feedback

If you miss anything here, have additions, comments, corrections, criticism or questions, want to give feedback, hints or tipps, report broken links, bugs, deficiencies, errors, inaccuracies, misrepresentations, omissions, shortcomings, vulnerabilities or weaknesses, …: don’t hesitate to contact me and feel free to ask, comment, criticise, flame, notify or report!

Use the X.509 certificate to send S/MIME encrypted mail.

Note: email in weird format and without a proper sender name is likely to be discarded!

I dislike HTML (and even weirder formats too) in email, I prefer to receive plain text.
I also expect to see your full (real) name as sender, not your nickname.
I abhor top posts and expect inline quotes in replies.

Terms and Conditions

By using this site, you signify your agreement to these terms and conditions. If you do not agree to these terms and conditions, do not use this site!

Data Protection Declaration

This web page records no (personal) data and stores no cookies in the web browser.

The web service is operated and provided by

Telekom Deutschland GmbH
Business Center
D-64306 Darmstadt
Germany
<‍hosting‍@‍telekom‍.‍de‍>
+49 800 5252033

The web service provider stores a session cookie in the web browser and records every visit of this web site with the following data in an access log on their server(s):


Copyright © 1995–2026 • Stefan Kanthak • <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>