Skip to content

Commit

Permalink
Merge pull request #147 from sunnamed434/dev
Browse files Browse the repository at this point in the history
Bump new version 0.20.0
  • Loading branch information
sunnamed434 committed Oct 21, 2023
2 parents d7e7887 + dda551c commit 3cd079b
Show file tree
Hide file tree
Showing 48 changed files with 220 additions and 14 deletions.
13 changes: 13 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: "2"

build:
os: "ubuntu-22.04"
tools:
python: "3.10"

python:
install:
- requirements: docs/requirements.txt

sphinx:
configuration: docs/source/conf.py
6 changes: 5 additions & 1 deletion BitMono.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CLI/@EntryIndexedValue">CLI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=JS/@EntryIndexedValue">JS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NET/@EntryIndexedValue">NET</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PE/@EntryIndexedValue">PE</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Decryptor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Ldasm/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Ldasm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=mprotect/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nops/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=renamer/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

| Versions: |
|-------------------------------|
| [0.20.0-alpha](#0200-alpha35) |
| [0.19.0-alpha](#0190-alpha34) |
| [0.18.0-alpha](#0180-alpha33) |
| [0.16.2-alpha](#0162-alpha31) |
Expand All @@ -31,6 +32,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

---

## 0.20.0-alpha.35
2023-10-21

### Added
- BillionNops protection.
- Information about BillionNops in docs.
- XML docs for RuntimeMonikerMonoAttribute.

### Fixed
- Annoying EndOfStreamException being thrown in AssemblyResolver when file doesn't exists or this is lib/file that at the end of the stream.
- Not being properly compiled docs.
- DotNetHook VirtualProtect will not work on linux [#37](https://github.com/sunnamed434/BitMono/issues/37)

## 0.19.0-alpha.34
2023-10-12

Expand Down
7 changes: 2 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ BitMono is a free open-source C# obfuscator that in most cases works **only** wi
alt="Before and after obfuscation preview by BitMono 2">
</p>

<p align="center">
<img src="https://raw.githubusercontent.com/sunnamed434/BitMono/main/resources/images/preview/GUI.png"
alt="GUI">
</p>

<p align="center">
<img src="https://raw.githubusercontent.com/sunnamed434/BitMono/main/resources/images/preview/CLI.png"
alt="CLI">
Expand Down Expand Up @@ -79,6 +74,7 @@ Read the **[docs][bitmono_docs]** to read protection, functionality, and more.
* AntiDecompiler
* BitDateTimeStamp
* BitMono
* BillionNops

## Usage

Expand Down Expand Up @@ -150,6 +146,7 @@ Mono is supported obviously (some protections don't support Mono), however if yo
| .NET (Core) | 6.0 |
| .NET Framework | 462 |
| netstandard | 2.0 |
| netstandard | 2.1 |

Credits
-------
Expand Down
20 changes: 20 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
35 changes: 35 additions & 0 deletions docs/make.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@ECHO OFF

pushd %~dp0

REM Command file for Sphinx documentation

if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build

if "%1" == "" goto help

%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)

%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end

:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%

:end
popd
2 changes: 2 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
sphinx==7.1.2
sphinx-rtd-theme==1.3.0rc1
File renamed without changes.
35 changes: 35 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Configuration file for the Sphinx documentation builder.

# -- Project information

project = 'BitMono'
copyright = '2023, BitMono'
author = 'sunnamed434'

release = '0.1'
version = '0.1.0'

# -- General configuration

extensions = [
'sphinx.ext.duration',
'sphinx.ext.doctest',
'sphinx.ext.autodoc',
'sphinx.ext.autosummary',
'sphinx.ext.intersphinx',
]

intersphinx_mapping = {
'python': ('https://docs.python.org/3/', None),
'sphinx': ('https://www.sphinx-doc.org/en/master/', None),
}
intersphinx_disabled_domains = ['std']

templates_path = ['_templates']

# -- Options for HTML output

html_theme = 'sphinx_rtd_theme'

# -- Options for EPUB output
epub_show_urls = 'footnote'
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions docs/index.rst → docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Table of Contents:
protections/stringsencryption
protections/unmanagedstring
protections/nonamespaces
protections/billionnops


.. toctree::
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
19 changes: 19 additions & 0 deletions docs/source/protections/billionnops.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
BillionNops
===========

History
-------

You might already know this protection because it's so popular and well known in many obfuscators, it is very simple protection but can cause a lot of headaches.

How it works?
-------------

Protection adds a new dummy method in the Module and then adds 100.000 nop instructions, and ret at the end.

As a result when someone will try to analyze this method will cause a crashed dnSpy, and it will lead a reverse engineer install old dnSpy or use a IDE/VS Code/LinqPad with installed AsmResolver or dnlib to remove this method.

Cons
----

Be careful because this protection will increase a file size a lot, and a bigger file size will cause more questions by users, most of us when see a big file size think that this file is obfuscated.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion props/SharedProjectProps.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/sunnamed434/BitMono</PackageProjectUrl>
<PackageOwners>sunnamed434</PackageOwners>
<BitMonoVersion>0.18.0-alpha.33</BitMonoVersion>
<BitMonoVersion>0.19.1-alpha.35</BitMonoVersion>
<PackageVersion>$(BitMonoVersion)</PackageVersion>
<Version>$(BitMonoVersion)</Version>
<InformationalVersion>$(BitMonoVersion)</InformationalVersion>
Expand Down
1 change: 0 additions & 1 deletion src/BitMono.Core/Attributes/RuntimeMonikerAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ namespace BitMono.Core.Attributes;
/// If you don't see any of the attributes then it works everywhere, also, users will get a message via <see cref="GetMessage"/></remarks>
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public abstract class RuntimeMonikerAttribute : Attribute
{
protected RuntimeMonikerAttribute(string name)
Expand Down
5 changes: 5 additions & 0 deletions src/BitMono.Core/Attributes/RuntimeMonikerMonoAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
namespace BitMono.Core.Attributes;

/// <summary>
/// Represents a mechanism that specifies the runtime moniker of the protection as a <b>Mono</b>.
/// <remarks>i.e if you see this attribute on protection then only specified attributes are the supported runtime monikers for the protection.
/// If you don't see any of the attributes then it works everywhere, also, users will get a message via <see cref="RuntimeMonikerAttribute.GetMessage"/></remarks>
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class RuntimeMonikerMonoAttribute : RuntimeMonikerAttribute
{
Expand Down
4 changes: 4 additions & 0 deletions src/BitMono.Core/Resolvers/AssemblyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public static AssemblyResolve Resolve(IEnumerable<byte[]> dependenciesData, Star
{
// ignored
}
catch (EndOfStreamException)
{
// ignored
}
}

if (resolved == false)
Expand Down
6 changes: 5 additions & 1 deletion src/BitMono.Host/protections.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
"Name": "AntiDebugBreakpoints",
"Enabled": false
},
{
"Name": "BillionNops",
"Enabled": false
},
{
"Name": "StringsEncryption",
"Enabled": false
Expand Down Expand Up @@ -58,7 +62,7 @@
},
{
"Name": "BitMono",
"Enabled": true
"Enabled": false
}
]
}
29 changes: 29 additions & 0 deletions src/BitMono.Protections/BillionNops.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace BitMono.Protections;

[UsedImplicitly]
public class BillionNops : Protection
{
private readonly Renamer _renamer;

public BillionNops(Renamer renamer, IServiceProvider serviceProvider) : base(serviceProvider)
{
_renamer = renamer;
}

public override Task ExecuteAsync()
{
var module = Context.Module;
var moduleType = module.GetOrCreateModuleType();
var factory = module.CorLibTypeFactory;
var method = new MethodDefinition(_renamer.RenameUnsafely(), MethodAttributes.Public | MethodAttributes.Static,
MethodSignature.CreateStatic(factory.Void));
moduleType.Methods.Add(method);
var body = method.CilMethodBody = new CilMethodBody(method);
for (var i = 0; i < 100000; i++)
{
body.Instructions.Insert(0, new CilInstruction(CilOpCodes.Nop));
}
body.Instructions.Add(new CilInstruction(CilOpCodes.Ret));
return Task.CompletedTask;
}
}
35 changes: 30 additions & 5 deletions src/BitMono.Runtime/Hooking.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,33 @@ internal static void RedirectStub(int from, int to)
var fromPtr = fromMethodHandle.GetFunctionPointer();
var toPtr = toMethodHandle.GetFunctionPointer();

VirtualProtect(fromPtr, (IntPtr)5, 0x40, out uint oldProtect);
if (Environment.OSVersion.Platform is PlatformID.Unix or PlatformID.MacOSX)
{
const int PROT_EXEC = 0x04;
const int PROT_READ = 0x01;
const int PROT_WRITE = 0x02;

mprotect(fromPtr, 5, PROT_READ | PROT_WRITE);

if (IntPtr.Size == 8)
MakeHook(fromPtr, toPtr);

mprotect(fromPtr, 5, PROT_READ | PROT_EXEC);
}
else
{
VirtualProtect(fromPtr, (IntPtr)5, 0x40, out var oldProtect);

MakeHook(fromPtr, toPtr);

VirtualProtect(fromPtr, (IntPtr)5, oldProtect, out _);
}
}

private static void MakeHook(IntPtr fromPtr, IntPtr toPtr)
{
const int x64BitProcess = 8;
const int x32BitProcess = 4;
if (IntPtr.Size == x64BitProcess)
{
Marshal.WriteByte(fromPtr, 0, 0x49);
Marshal.WriteByte(fromPtr, 1, 0xBB);
Expand All @@ -23,16 +47,17 @@ internal static void RedirectStub(int from, int to)
Marshal.WriteByte(fromPtr, 11, 0xFF);
Marshal.WriteByte(fromPtr, 12, 0xE3);
}
else if (IntPtr.Size == 4)
else if (IntPtr.Size == x32BitProcess)
{
Marshal.WriteByte(fromPtr, 0, 0xE9);
Marshal.WriteInt32(fromPtr, 1, toPtr.ToInt32() - fromPtr.ToInt32() - 5);
Marshal.WriteByte(fromPtr, 5, 0xC3);
}

VirtualProtect(fromPtr, (IntPtr)5, oldProtect, out _);
}

[DllImport("libc.so.6", EntryPoint = nameof(mprotect))]
internal static extern int mprotect(IntPtr start, ulong len, int prot);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, EntryPoint = nameof(VirtualProtect))]
internal static extern bool VirtualProtect(IntPtr address, IntPtr size, uint newProtect, out uint oldProtect);
}

0 comments on commit 3cd079b

Please sign in to comment.