7 Commits
17 changed files with 239 additions and 85 deletions
+63
View File
@@ -0,0 +1,63 @@
name: Create Release
on:
workflow_dispatch:
push:
tags:
- "v*.*.*"
env:
SOLUTION_FILE_PATH: .
BUILD_CONFIGURATION: Release
BUILD_OUTPUT_PATH: Build
permissions:
contents: write
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.CODECEPTICON_TOKEN }}
- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@v2
- name: Restore NuGet packages
working-directory: ${{env.GITHUB_WORKSPACE}}
run: nuget restore ${{env.SOLUTION_FILE_PATH}}
- name: Build
working-directory: ${{env.GITHUB_WORKSPACE}}
run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} /p:OutputPath=../${{env.BUILD_OUTPUT_PATH}} ${{env.SOLUTION_FILE_PATH}}
- name: Delete .config file
run: Remove-Item -Path ${{env.BUILD_OUTPUT_PATH}}/Codecepticon.exe.config
- name: Set release filename
run: echo "RELEASE_FILENAME=Codecepticon-${{ github.ref_name }}.zip" >> $env:GITHUB_ENV
- name: Compress release
run: Compress-Archive -Path ${{env.BUILD_OUTPUT_PATH}}/* -Destination ${{ env.RELEASE_FILENAME }}
- name: Get file hash
run: |
$hash = Get-FileHash -Algorithm SHA256 ${{ env.RELEASE_FILENAME }} | select -exp Hash
echo "FILE_HASH=$hash" >> $env:GITHUB_ENV
- name: Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: ${{ env.RELEASE_FILENAME }}
name: Codecepticon-${{ github.ref_name }}
body: |
Archive SHA256: `${{ env.FILE_HASH }}`
For more details see `CHANGELOG.md`.
token: ${{ secrets.CODECEPTICON_TOKEN }}
+12
View File
@@ -1,5 +1,17 @@
# Codecepticon Changelog
## v1.2.3
* `[Update]` Update copyright & links, added workflows to repo.
## v1.2.2
* `[Update]` Removed `BouncyCastle` dependency, now certificates are generated using native .NET functionality.
## v1.2.1
* `[New]` C#: Added support for renaming Structs.
## v1.2.0
* `[Update]` Removed the `signtool.exe` dependency and are now natively signing executables. The code was taken & customised from https://github.com/Danielku15/SigningServer, under MIT License - original author is Danielku15.
+10 -11
View File
@@ -9,38 +9,38 @@
<LangVersion>9.0</LangVersion>
<PackageId>Codecepticon</PackageId>
<Title>Codecepticon</Title>
<Version>1.2.0</Version>
<Version>1.2.3</Version>
<Authors>Pavel Tsakalidis</Authors>
<Company>Accenture Security</Company>
<Company></Company>
<Product>Codecepticon</Product>
<Description>Offensive Security Code Obfuscator</Description>
<PackageProjectUrl>https://github.com/Accenture/Codecepticon</PackageProjectUrl>
<PackageProjectUrl>https://github.com/sadreck/Codecepticon</PackageProjectUrl>
<AssemblyVersion></AssemblyVersion>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>full</DebugType>
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebugType>full</DebugType>
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<DebugType>full</DebugType>
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>full</DebugType>
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebugType>full</DebugType>
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<DebugType>full</DebugType>
<DebugType>none</DebugType>
</PropertyGroup>
<ItemGroup>
@@ -57,7 +57,6 @@
<ItemGroup>
<PackageReference Include="Antlr4.Runtime.Standard" Version="4.9.2" />
<PackageReference Include="BouncyCastle" Version="1.8.9" />
<PackageReference Include="Microsoft.Build" Version="17.3.1" ExcludeAssets="runtime" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.5.3" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
@@ -65,7 +64,7 @@
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="3.9.0" />
<PackageReference Include="Microsoft.PowerShell.5.1.ReferenceAssemblies" Version="1.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.Collections.Immutable" Version="6.0.0" />
<PackageReference Include="System.Collections.Immutable" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
+4
View File
@@ -8,8 +8,11 @@ Usage: Codecepticon.exe --module [csharp|cs] [OPTIONS]...
--build Whether to build the project upon completion.
--build-path [path] Path to a directory where the solution will be compiled to. Only works with --build.
--profile [name] Name of an application-specific profile to use. Supported profiles are:
- certify
- rubeus
- seatbelt
- sharpchrome
- sharpdpapi
- sharphound
- sharpview
@@ -22,6 +25,7 @@ Usage: Codecepticon.exe --module [csharp|cs] [OPTIONS]...
- p Properties
- a Parameters
- v Variables
- s Structs
- o Command Line
%%_SHARED_%%
+2 -2
View File
@@ -1,2 +1,2 @@
Codecepticon v%%_VERSION_%% [ Accenture Security ]
- For more information visit https://github.com/Accenture/Codecepticon
Codecepticon v%%_VERSION_%% [ Pavel Tsakalidis ]
- For more information visit https://github.com/sadreck/Codecepticon
@@ -112,6 +112,7 @@ namespace Codecepticon.Modules.CSharp
Logger.Verbose($"\tProperties:\t{DataCollector.AllProperties.Count}");
Logger.Verbose($"\tParameters:\t{DataCollector.AllParameters.Count}");
Logger.Verbose($"\tVariables:\t{DataCollector.AllVariables.Count}");
Logger.Verbose($"\tStructs:\t{DataCollector.AllStructs.Count}");
Logger.Info("Generating mappings...");
if (await GenerateMappings() == false)
@@ -190,6 +191,7 @@ namespace Codecepticon.Modules.CSharp
await DataCollector.CollectProperties(solution, project.Name, document.Name);
await DataCollector.CollectVariables(solution, project.Name, document.Name);
await DataCollector.CollectParameters(solution, project.Name, document.Name);
await DataCollector.CollectStructs(solution, project.Name, document.Name);
}
}
@@ -320,6 +322,21 @@ namespace Codecepticon.Modules.CSharp
}
}
if (CommandLineData.CSharp.Rename.Structs)
{
Logger.Verbose("Creating mappings for structs");
foreach (string name in DataCollector.AllStructs)
{
newName = await GenerateName(CommandLineData.Global.NameGenerator, DataCollector.IsMappingUnique);
if (newName.Length == 0)
{
return false;
}
DataCollector.Mapping.Structs.Add(name, newName);
}
}
return true;
}
@@ -587,6 +604,28 @@ namespace Codecepticon.Modules.CSharp
}
}
if (CommandLineData.CSharp.Rename.Structs)
{
Logger.Info($"Renaming {DataCollector.Mapping.Structs.Count} structs...", CommandLineData.Global.Project.Debug);
c = 0;
foreach (Document document in project.Documents)
{
if (CommandLineData.Global.Project.Debug)
{
Logger.Debug($"Renaming structs in document {document.FilePath}");
}
else if (++c % step == 0)
{
Logger.Verbose(".", false, false);
}
solution = await dataRenamer.RenameStructs(solution, project.Name, document.Name);
}
if (!CommandLineData.Global.Project.Debug)
{
Logger.Info("", true, false);
}
}
Logger.Debug($"Setting ProjectGuid to {{{CommandLineData.Global.Project.Guid.ToString().ToUpper()}}}");
VisualStudioManager.SetProjectConfiguration(solution, new Dictionary<string, string>
{
@@ -129,6 +129,9 @@ namespace Codecepticon.Modules.CSharp.CommandLine
case "o":
CommandLineData.CSharp.Rename.CommandLine = true;
break;
case "s":
CommandLineData.CSharp.Rename.Structs = true;
break;
}
}
break;
@@ -145,6 +148,7 @@ namespace Codecepticon.Modules.CSharp.CommandLine
CommandLineData.CSharp.Rename.Variables = value;
CommandLineData.CSharp.Rename.Parameters = value;
CommandLineData.CSharp.Rename.CommandLine = value;
CommandLineData.CSharp.Rename.Structs = value;
}
}
}
+28 -1
View File
@@ -23,6 +23,7 @@ namespace Codecepticon.Modules.CSharp
public static List<string> AllProperties = new List<string>();
public static List<string> AllVariables = new List<string>();
public static List<string> AllParameters = new List<string>();
public static List<string> AllStructs = new List<string>();
public struct CommandLine
{
@@ -41,6 +42,7 @@ namespace Codecepticon.Modules.CSharp
public Dictionary<string, string> Properties;
public Dictionary<string, string> Variables;
public Dictionary<string, string> Parameters;
public Dictionary<string, string> Structs;
public Dictionary<string, CommandLine> CommandLine;
}
@@ -52,7 +54,8 @@ namespace Codecepticon.Modules.CSharp
Enums = new Dictionary<string, string>(),
Properties = new Dictionary<string, string>(),
Variables = new Dictionary<string, string>(),
Parameters = new Dictionary<string, string>()
Parameters = new Dictionary<string, string>(),
Structs = new Dictionary<string, string>(),
};
public static bool IsMappingUnique(string name)
@@ -93,6 +96,12 @@ namespace Codecepticon.Modules.CSharp
return false;
}
item = Mapping.Structs.FirstOrDefault(s => s.Value == name).Key;
if (item != null)
{
return false;
}
item = Mapping.Parameters.FirstOrDefault(s => s.Value == name).Key;
return item == null;
}
@@ -195,6 +204,24 @@ namespace Codecepticon.Modules.CSharp
}
}
public static async Task CollectStructs(Solution solution, string projectName, string documentName)
{
Document document = VisualStudioManager.GetDocumentByName(solution, projectName, documentName);
SyntaxTree syntaxTree = await document.GetSyntaxTreeAsync();
var structs = syntaxTree.GetRoot().DescendantNodes().OfType<StructDeclarationSyntax>();
foreach (var s in structs)
{
string name = s.Identifier.ToString();
if (AllStructs.Contains(name))
{
continue;
}
AllStructs.Add(name);
}
}
public static async Task CollectProperties(Solution solution, string projectName, string documentName)
{
Document document = VisualStudioManager.GetDocumentByName(solution, projectName, documentName);
@@ -190,5 +190,26 @@ namespace Codecepticon.Modules.CSharp
return solution;
}
public async Task<Solution> RenameStructs(Solution solution, string projectName, string documentName)
{
Document document = VisualStudioManager.GetDocumentByName(solution, projectName, documentName);
SyntaxTree syntaxTree = await document.GetSyntaxTreeAsync();
var structs = syntaxTree.GetRoot().DescendantNodes().OfType<StructDeclarationSyntax>();
foreach (var s in structs)
{
string name = s.Identifier.ToString();
if (!DataCollector.Mapping.Structs.ContainsKey(name))
{
Logger.Debug($"Struct does not exist in mapping: {name}");
continue;
}
solution = await RenameCode<StructDeclarationSyntax>(solution, projectName, documentName, name, DataCollector.Mapping.Structs[name]);
}
return solution;
}
}
}
+6
View File
@@ -23,6 +23,7 @@ namespace Codecepticon.Modules.CSharp
["properties"] = "",
["variables"] = "",
["parameters"] = "",
["structs"] = "",
["cmdline"] = "",
};
@@ -61,6 +62,11 @@ namespace Codecepticon.Modules.CSharp
data["parameters"] = ConcatData(DataCollector.Mapping.Parameters);
}
if (CommandLineData.CSharp.Rename.Structs)
{
data["structs"] = ConcatData(DataCollector.Mapping.Structs);
}
if (CommandLineData.CSharp.Rename.CommandLine)
{
data["cmdline"] = DataCollector.ConcatCommandLineData(DataCollector.Mapping.CommandLine);
+1
View File
@@ -67,6 +67,7 @@ namespace Codecepticon.CommandLine
public bool Variables;
public bool Parameters;
public bool CommandLine;
public bool Structs;
}
public struct RewriteTemplateStruct
+35 -67
View File
@@ -1,101 +1,69 @@
using Codecepticon.Utils;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace Codecepticon.Modules.Sign
{
class CertificateManager
{
private const string SignatureAlgorithm = "SHA256WithRSA";
private const int KeyLength = 2048;
public bool GenerateCertificate(string Subject, string Issuer, DateTime NotBefore, DateTime NotAfter, string Password, string PfxOutput)
{
// https://mcse.cloud/create-a-self-signed-certificate-with-bouncy-castle-and-c/
Logger.Debug("Initialising random generators and certificate generators...");
SecureRandom secureRandom = new SecureRandom(new CryptoApiRandomGenerator());
// https://stackoverflow.com/a/48210587/2445959
RSA keyPair = RSA.Create(KeyLength);
X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();
Logger.Verbose("Generating issuer certificate...");
Logger.Verbose("Issuer is " + Issuer);
X509Certificate2 certificateIssuer = GenerateIssuerCertificate(Issuer, NotBefore, NotAfter);
// Create and set serial number.
Logger.Verbose("Setting up certificate properties...");
BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), secureRandom);
certificateGenerator.SetSerialNumber(serialNumber);
Logger.Info("Generating signing certificate...");
Logger.Verbose("Subject is " + Subject);
CertificateRequest certRequest = new(Subject, keyPair, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
certRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
//certRequest.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new Oid("1.3.6.1.5.5.7.3.8") }, true));
certRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(certRequest.PublicKey, false));
X509Certificate2 cert = certRequest.Create(certificateIssuer, NotBefore, NotAfter, new byte[] { 1, 2, 3, 4 });
Logger.Debug("Creating Subject: " + Subject);
X509Name subjectDN = new X509Name(true, Subject);
certificateGenerator.SetSubjectDN(subjectDN);
// Add the private key back to the certificate.
X509Certificate2 certificate = cert.CopyWithPrivateKey(keyPair);
Logger.Debug("Creating Issuer: " + Issuer);
X509Name issuerDN = new X509Name(true, Issuer);
certificateGenerator.SetIssuerDN(issuerDN);
Logger.Debug("Setting NotBefore: " + NotBefore);
certificateGenerator.SetNotBefore(NotBefore);
Logger.Debug("Setting NotAfter: " + NotAfter);
certificateGenerator.SetNotAfter(NotAfter);
KeyGenerationParameters keyGeneration = new KeyGenerationParameters(secureRandom, KeyLength);
// Create RSA key.
Logger.Verbose("Generating RSA keypair...");
RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGeneration);
AsymmetricCipherKeyPair keyPair = keyPairGenerator.GenerateKeyPair();
// Add the public/private keys to the certificate generator.
Logger.Debug("Setting public key...");
certificateGenerator.SetPublicKey(keyPair.Public);
ISignatureFactory signatureFactory = new Asn1SignatureFactory(SignatureAlgorithm, keyPair.Private, secureRandom);
X509Certificate certificate = certificateGenerator.Generate(signatureFactory);
Logger.Debug("Creating keystore...");
Pkcs12Store keyStore = new Pkcs12Store();
X509CertificateEntry certificateEntry = new X509CertificateEntry(certificate);
keyStore.SetCertificateEntry(certificate.SubjectDN.ToString(), certificateEntry);
keyStore.SetKeyEntry(certificate.SubjectDN.ToString(), new AsymmetricKeyEntry(keyPair.Private), new[] { certificateEntry });
// Convert to .NET Certificate.
Logger.Debug("Converting to a .NET certificate...");
MemoryStream stream = new MemoryStream();
keyStore.Save(stream, Password.ToCharArray(), secureRandom);
System.Security.Cryptography.X509Certificates.X509Certificate2 netCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(stream.ToArray(), Password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.PersistKeySet | System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable);
Logger.Verbose("Writing certificate to " + PfxOutput);
File.WriteAllBytes(PfxOutput, netCertificate.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pfx, Password));
Logger.Info("Exporting certificate to file...");
File.WriteAllBytes(PfxOutput, certificate.Export(X509ContentType.Pfx, Password));
return true;
}
private X509Certificate2 GenerateIssuerCertificate(string Issuer, DateTime NotBefore, DateTime NotAfter)
{
RSA keyPair = RSA.Create(KeyLength);
CertificateRequest issuerRequest = new(Issuer, keyPair, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
issuerRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true));
issuerRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(issuerRequest.PublicKey, false));
return issuerRequest.CreateSelfSigned(NotBefore, NotAfter);
}
public bool CheckPfxPassword(string pfxFile, string password)
{
try
{
Pkcs12Store keyStore = new Pkcs12Store(File.OpenRead(pfxFile), password.ToCharArray());
} catch (Exception e)
X509Certificate2 certificate = new(pfxFile, password);
}
catch (Exception e)
{
return false;
}
return true;
}
public System.Security.Cryptography.X509Certificates.X509Certificate GetCertificateFromFile(string signedFile)
public X509Certificate GetCertificateFromFile(string signedFile)
{
return System.Security.Cryptography.X509Certificates.X509Certificate2.CreateFromSignedFile(signedFile);
return X509Certificate.CreateFromSignedFile(signedFile);
}
}
}
+1
View File
@@ -84,6 +84,7 @@
"properties": "%properties%",
"variables": "%variables%",
"parameters": "%parameters%",
"structs": "%structs%",
"cmdline": "%cmdline%"
}
</script>
+6
View File
@@ -267,6 +267,12 @@
<label class="form-check-label" for="csharp-rename-variables">Variables</label>
</div>
<!-- Structs -->
<div class="form-check form-switch">
<input class="csharp-rename-item form-check-input" type="checkbox" data-argument="s" id="csharp-rename-structs">
<label class="form-check-label" for="csharp-rename-structs">Structs</label>
</div>
<!-- Command Line -->
<div class="form-check form-switch">
<input class="csharp-rename-item form-check-input" type="checkbox" data-argument="o" id="csharp-rename-commandline">
+2 -1
View File
@@ -1,6 +1,7 @@
MIT License
Copyright (c) 2022 Accenture Security
Copyright (c) 2022 - 02/2024 Accenture Security
Copyright (c) 03/2024 - Present - Pavel Tsakalidis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+4 -3
View File
@@ -1,4 +1,4 @@
# Codecepticon ![version](https://img.shields.io/github/v/tag/Accenture/Codecepticon?label=version&style=flat-square)
# Codecepticon ![version](https://img.shields.io/github/v/tag/sadreck/Codecepticon?label=version&style=flat-square)
## Table of Contents
@@ -53,7 +53,7 @@ Codecepticon allows you to obfuscate and rewrite code, but also provides feature
### Open and Compile
Open Codecepticon, wait until all NuGet packages are downloaded and then build the solution.
Open Codecepticon, wait until all NuGet packages are downloaded and then build the solution. You can also download a pre-compiled `Release`.
## Using Codecepticon
@@ -119,7 +119,7 @@ Therefore it is **critical** to always test your result in a local environment f
### Sign Executables
It is also possible to use Codecepticon to digitally sign executable files (your compiled output). Codecepticon can both generate a signing certificate for you, and also use it (or any other you may provide) to sign your target file. Please note that for this functionality you will need Microsoft's [SignTool](https://learn.microsoft.com/en-us/windows/win32/seccrypto/signtool) - although it should be automatically installed when you install Visual Studio 2022.
It is also possible to use Codecepticon to digitally sign executable files (your compiled output). Codecepticon can both generate a signing certificate for you, and also use it (or any other you may provide) to sign your target file.
## FAQ
@@ -168,3 +168,4 @@ Whether it's a typo, a bug, or a new feature, Codecepticon is very open to contr
* https://github.com/MagicMau/ProceduralNameGenerator
* https://github.com/uwol/proleap-vb6-parser
* https://github.com/dwyl/english-words
* https://github.com/Danielku15/SigningServer
+1
View File
@@ -173,6 +173,7 @@ The level of customisation supported by the C# module is:
* Properties
* Parameters
* Variables
* Structs
* Command Line _(only for targets that have a pre-existing Profile - like SharpHound, Rubeus, etc)_
This means that it is possible to choose which identifiers should be obfuscated.