Search code examples
windowspowershellobfuscationmalware

Why does the dot source operator convert strings into commands


I came across a script that obfuscated its calls using the dot sourcing operator.

$ORMEFyak=.('n'+'ew-obje'+'ct') NeT.WebcLIENt;

This seems to be equivalent to: $var = New-Object Net.WebClient

Running . "help" returns the contents of the help cmdlet.

Why exactly does the dot source operator act like this?


Solution

  • The behavior is not specific to ., the dot-sourcing operator; it equally applies to &, the call operator.

    • Only when you're invoking a script file (*.ps1) (or, less commonly, function or script block) do . and & behave differently: . runs the code directly in the caller's scope, whereas &, which is more typical, runs it in a child scope - see this answer for more information.

    • In the case of New-Object, as a cmdlet, you can technically use them interchangeably (or omit them altogether - see below), but for conceptual clarity it's better to use & unless actual dot-sourcing is required.

    It isn't so much that they convert a string to a command, it is that their purpose is to execute a command given by its name, as a string, among other forms (see below).

    The specific syntax used to provide or construct this name for . or & is incidental, and in your case a string-concatenation expression was used to obscure the name of the command being invoked.

    • However, specifying the name of a command unquoted, verbatim (if syntactically possible) is special in that you can then invoke without an operator - & is then implied; see below for an example.

    Therefore, all of the following variations are equivalent (for the reasons stated above, I'm using &):

    # Bareword (unquoted, verbatim) command name
    # If you don't need dot-sourcing, you can invoke *as-is* - 
    # use of & is implied.
    New-Object regex 'foo?'
    
    # Optionally, use &
    & New-Object regex 'foo?'
    
    # If the command name *needs quoting*, is *(based on) a variable* or
    # *built by an expression*, & is *required*
    $cmd = 'New-Object'
    & $cmd regex 'foo?'
    
    & ('New-' + 'Object') regex 'foo?'
    

    Note that in addition to acting on command names (strings), . and & can also invoke script blocks (e.g. & { New-Object regex 'foo?' }) and command-information objects returned by Get-Command (e.g., & (Get-Command New-Object) regex 'foo?')