简体   繁体   中英

How to access binary before msbuild packs it to single file

I'm using ConfuserEx to obfuscate my app, but it requires whole .dll binary file.
So, is there a way to obfuscate it using cli and then pack it to single file, or
access binary before compressing it to single file, so i can obfuscate it

I tried to do exclude main binary by ExcludeFromSingleFile , but it didn't work

My .crproj file

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>exe</OutputType>
        <AssemblyName>jay-$(RuntimeIdentifier)</AssemblyName>
        <PublishSingleFile>true</PublishSingleFile>
        <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
        <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
        <TargetFramework>net5.0</TargetFramework>
    </PropertyGroup>

    <ItemGroup>
        <Content Update="$(AssemblyName).dll">
            <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
            <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
        </Content>
    </ItemGroup>

    <ItemGroup>
      <PackageReference Include="CloudFlareUtilities" Version="1.3.0" />
      <PackageReference Include="Colorful.Console" Version="1.2.15" />
      <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
      <PackageReference Include="YamlDotNet" Version="9.1.4" />
    </ItemGroup>

</Project>

You need to add it as a post-build event, for example:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>exe</OutputType>
        <AssemblyName>jay-$(RuntimeIdentifier)</AssemblyName>
        <PublishSingleFile>true</PublishSingleFile>
        <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
        <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
        <TargetFramework>net5.0</TargetFramework>
    </PropertyGroup>

    <!-- runs: TheAppToPassItTo.exe "<path to dll>" -->
    <Target Name="PostBuild" AfterTargets="PostBuildEvent">
      <Exec Command="TheAppToPassItTo.exe &quot;$(TargetPath)&quot;" />
    </Target>

    <ItemGroup>
      <PackageReference Include="CloudFlareUtilities" Version="1.3.0" />
      <PackageReference Include="Colorful.Console" Version="1.2.15" />
      <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
      <PackageReference Include="YamlDotNet" Version="9.1.4" />
    </ItemGroup>

</Project>

Edited To Add

So, it turns out that the new "single file" executable option doesn't build it's executable from the bin directory, but from the obj directory. This has to be a simple oversight from the .NET team. There are many times where you'd want to modify your executable code before packing it up. What you are asking for is not unreasonable.

We can accomplish this by implementing a kludge until this gets rectified. We will still use the "post-build" job, but we are going to do some string replacement to build the correct path to the executable you want to modify.

This is the new script:

@ECHO off
SET tp=$(TargetPath)
SET tp=%tp:\bin\=\obj\% 
ECHO Target file to modify: %tp%
YourObfuscatorEngine.exe "%tp%"

This will get the target path, in my case it is:

D:\Repositories\Source\ConsoleApp2\ConsoleApp2\bin\Release\netcoreapp3.1\win-x64\ConsoleApp2.dll

Then we do a string replace. We replace \bin\ with \obj\ . The path will then be:

D:\Repositories\Source\ConsoleApp2\ConsoleApp2\obj\Release\netcoreapp3.1\win-x64\ConsoleApp2.dll

Now when you call your obfuscator engine, it will modify the correct file.

Please keep in mind that if you turn on the PublishReadyToRun option, your path will change to:

D:\Repositories\Source\ConsoleApp2\ConsoleApp2\obj\Release\netcoreapp3.1\win-x64\R2R\ConsoleApp2.dll

Which will make this a tad more complicated. So just keep that in mind if you decide you want to do this.

At the end of the day, your post-build script will look like this:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>exe</OutputType>
        <AssemblyName>jay-$(RuntimeIdentifier)</AssemblyName>
        <PublishSingleFile>true</PublishSingleFile>
        <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
        <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
        <TargetFramework>net5.0</TargetFramework>
    </PropertyGroup>

  <Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Command="@ECHO off&#xD;&#xA;SET tp=$(TargetPath)&#xD;&#xA;SET tp=%25tp:\bin\=\obj\%25 &#xD;&#xA;ECHO Target file to modify: %25tp%25&#xD;&#xA;YourObfuscatorEngine.exe &quot;%25tp%25&quot;" />
  </Target>

    <ItemGroup>
      <PackageReference Include="CloudFlareUtilities" Version="1.3.0" />
      <PackageReference Include="Colorful.Console" Version="1.2.15" />
      <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
      <PackageReference Include="YamlDotNet" Version="9.1.4" />
    </ItemGroup>

</Project>

if you only need to modify the file on publish, I suggest hooking into the publish pipeline:

<Target Name="ObfuscateAssembly" BeforeTargets="PrepareForPublish">
  <Exec Command="some.exe %(IntermediateAssembly.FullPath)" />
</Target>

In case a larger process is needed, eg for this sample all dependencies need to be present for the obfuscator to work on all assemblies, an extended method of hooking into the build process would be after ComputeResolvedFilesToPublishList where the SDK figures out what files are needed to publish.

Here's the full example where the obfuscator works on all the assemblies in a directory:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <PublishReadyToRun>True</PublishReadyToRun>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
    <SelfContained>False</SelfContained>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
  </ItemGroup>

  <Target Name="CalculateObfuscationInputs" DependsOnTargets="_ComputeAssembliesToPostprocessOnPublish">
    <PropertyGroup>
      <ObfuscationDir>$(IntermediateOutputPath)obfuscation\</ObfuscationDir>
    </PropertyGroup>
    <ItemGroup>
      <AssembliesToObfuscate Include="@(ResolvedFileToPublish->WithMetadataValue('PostprocessAssembly', 'true'))" />
      <AssembliesToObfuscateTemporaryLocation Include="@(AssembliesToObfuscate->'$(ObfuscationDir)%(Filename)%(Extension)')" />
      <_PdbsToObfuscateInput Include="@(AssembliesToObfuscate->'%(RelativeDir)%(Filename).pdb')" />
      <PdbsToObfuscate Include="@(_PdbsToObfuscateInput)" RelativePath="%(_PdbsToObfuscateInput.Identity)" Condition="Exists(%(_PdbsToObfuscateInput.Identity))" />
      <PdbsToObfuscateTemporaryLocation Include="@(PdbsToObfuscate->'$(ObfuscationDir)%(Filename)%(Extension)')" />
    </ItemGroup>
    <MakeDir Directories="$(ObfuscationDir)" />
  </Target>

  <Target Name="PrepareForObfuscation" Inputs="@(AssembliesToObfuscate);@(PdbsToObfuscate)" Outputs="@(AssembliesToObfuscateTemporaryLocation);@(PdbsToObfuscateTemporaryLocation)">
    <Copy SourceFiles="@(AssembliesToObfuscate);@(PdbsToObfuscate)" DestinationFiles="@(AssembliesToObfuscateTemporaryLocation);@(PdbsToObfuscateTemporaryLocation)" SkipUnchangedFiles="True" />
  </Target>

  <Target Name="ObfuscateAssembly" AfterTargets="ComputeResolvedFilesToPublishList" DependsOnTargets="CalculateObfuscationInputs;PrepareForObfuscation">
    <Exec Command="some-obfuscator.exe $(ObfuscationDir)" />
    <ItemGroup>
      <ResolvedFileToPublish Remove="@(AssembliesToObfuscate);@(PdbsToObfuscate)" />
      <ResolvedFileToPublish Include="@(AssembliesToObfuscateTemporaryLocation);@(PdbsToObfuscateTemporaryLocation)" />
    </ItemGroup>
  </Target>

</Project>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM