├── Injector.cc ├── LICENSE ├── Monitor.ps1 ├── README.md ├── behan.py ├── binaries ├── Captain.dll ├── Injector.exe └── README.md ├── pictures ├── README.md ├── captainhook.png ├── kisspng-peeter-paan-tinker-bell-peter-pan-captain-hook-nev-5b09609a6b65c7.7533439215273412104399.jpg └── monitor.PNG ├── signatures ├── README.md ├── dll_injection.yml ├── macro_execution.yaml ├── mshta.yaml └── regsvr32.yaml └── src ├── Captain.cc ├── CaptainHook.hpp ├── Hooks.hpp ├── Reporting.hpp ├── Utils.hpp └── json.hpp /Injector.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | VOID InjectDll(HANDLE hProcess, LPCSTR lpszDllPath) 5 | { 6 | DWORD dwDllPathLen = strlen(lpszDllPath); 7 | LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, dwDllPathLen, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 8 | 9 | WriteProcessMemory(hProcess, lpBaseAddress, lpszDllPath, dwDllPathLen, NULL); 10 | 11 | HMODULE hModule = GetModuleHandle("kernel32.dll"); 12 | 13 | LPVOID lpStartAddress = GetProcAddress(hModule, "LoadLibraryA"); 14 | 15 | CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpStartAddress, lpBaseAddress, 0, NULL); 16 | } 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | if (argc != 2) 21 | return -1; 22 | 23 | DWORD pid = atoi(argv[1]); 24 | HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 25 | if(hProc == NULL) 26 | return -2; 27 | InjectDll(hProc, "C:\\ProgramData\\Captain\\Captain.dll"); 28 | 29 | return 0; 30 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Tarek Radah 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Monitor.ps1: -------------------------------------------------------------------------------- 1 | 2 | $ignoredProcesses=@("dllhost.exe","SearchProtocolHost.exe","SearchFilterHost.exe","taskhost.exe", "conhost.exe", "firefox.exe"); #these processes will never be suspended 3 | $new_process_check_interval = New-Object System.TimeSpan(0,0,0,0,750); #public TimeSpan (int days, int hours, int minutes, int seconds, int milliseconds); 4 | 5 | 6 | Add-Type -Name Threader -Namespace "" -Member @" 7 | [Flags] 8 | public enum ProcessAccess : uint 9 | { 10 | Terminate = 0x00000001, 11 | CreateThread = 0x00000002, 12 | VMOperation = 0x00000008, 13 | VMRead = 0x00000010, 14 | VMWrite = 0x00000020, 15 | DupHandle = 0x00000040, 16 | SetInformation = 0x00000200, 17 | QueryInformation = 0x00000400, 18 | SuspendResume = 0x00000800, 19 | Synchronize = 0x00100000, 20 | All = 0x001F0FFF 21 | } 22 | 23 | [DllImport("ntdll.dll", EntryPoint = "NtSuspendProcess", SetLastError = true)] 24 | public static extern uint SuspendProcess(IntPtr processHandle); 25 | 26 | [DllImport("ntdll.dll", EntryPoint = "NtResumeProcess", SetLastError = true)] 27 | public static extern uint ResumeProcess(IntPtr processHandle); 28 | 29 | [DllImport("kernel32.dll")] 30 | public static extern IntPtr OpenProcess(ProcessAccess dwDesiredAccess, bool bInheritHandle, uint dwProcessId); 31 | 32 | [DllImport("kernel32.dll", SetLastError=true)] 33 | public static extern bool CloseHandle(IntPtr hObject); 34 | "@ 35 | 36 | 37 | 38 | function Suspend-Process($processID) { 39 | if(($pProc = [Threader]::OpenProcess("SuspendResume", $false, $processID)) -ne [IntPtr]::Zero){ 40 | Write-Host "Trying to suspend process: $processID" 41 | 42 | $result = [Threader]::SuspendProcess($pProc) 43 | if($result -ne 0) { 44 | Write-Error "Failed to suspend. SuspendProcess returned: $result" 45 | return $False 46 | } 47 | [Threader]::CloseHandle($pProc) | out-null; 48 | } else { 49 | Write-Error "Unable to open process. Not elevated? Process doesn't exist anymore?" 50 | return $False 51 | } 52 | return $True 53 | } 54 | 55 | function Resume-Process($processID) { 56 | if(($pProc = [Threader]::OpenProcess("SuspendResume", $false, $processID)) -ne [IntPtr]::Zero){ 57 | Write-Host "Trying to resume process: $processID" 58 | Write-Host "" 59 | $result = [Threader]::ResumeProcess($pProc) 60 | if($result -ne 0) { 61 | Write-Error "Failed to resume. ResumeProcess returned: $result" 62 | } 63 | [Threader]::CloseHandle($pProc) | out-null 64 | } else { 65 | Write-Error "Unable to open process. Process doesn't exist anymore?" 66 | } 67 | } 68 | 69 | $culture = [System.Globalization.CultureInfo]::GetCultureInfo('en-US'); 70 | [System.Threading.Thread]::CurrentThread.CurrentUICulture = $culture; 71 | [System.Threading.Thread]::CurrentThread.CurrentCulture = $culture; 72 | 73 | Write-Host "Monitoring newly spawned processes via WMI..."; 74 | Write-host ""; 75 | 76 | $scope = New-Object System.Management.ManagementScope("\\.\root\cimV2"); 77 | $query = New-Object System.Management.WQLEventQuery("__InstanceCreationEvent",$new_process_check_interval,"TargetInstance ISA 'Win32_Process'" ); 78 | $watcher = New-Object System.Management.ManagementEventWatcher($scope,$query); 79 | 80 | $processSpawnCounter=1; 81 | do 82 | { 83 | $newlyArrivedEvent = $watcher.WaitForNextEvent(); 84 | $e = $newlyArrivedEvent.TargetInstance; 85 | Write-Host "($processSpawnCounter) New process spawned:"; 86 | 87 | $processName=[string]$e.Name; 88 | Write-host "PID:`t`t" $e.ProcessId; 89 | Write-host "Name:`t`t" $processName; 90 | Write-host "PPID:`t`t" $e.ParentProcessID; 91 | 92 | $parent_process=''; 93 | try {$proc=(Get-Process -id $e.ParentProcessID -ea stop); $parent_process=$proc.ProcessName;} catch {$parent_process='unknown';} 94 | Write-host "Parent name:`t" $parent_process; 95 | Write-host "CommandLine:`t" $e.CommandLine; 96 | 97 | if (-not ($ignoredProcesses -match $processName)) 98 | { 99 | if(Suspend-Process -processID $e.ProcessId){ 100 | Write-Host "Process is suspended."; 101 | C:\ProgramData\Captain\Injector.exe $e.ProcessId 102 | Write-Host "Dll Injected !!"; 103 | Resume-Process -processID $e.ProcessId 104 | } 105 | }else{ 106 | Write-Host "Process ignored as per configuration."; 107 | } 108 | 109 | Write-host ""; 110 | $processSpawnCounter += 1; 111 | } while ($true) 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Captain 2 | 3 | 4 | 5 | 6 | [![MIT license](https://badgen.net/badge/license/MIT/blue)](http://opensource.org/licenses/MIT) 7 | 8 | 9 | ## Overview 10 | 11 | Captain is an endpoint monitoring tool that aims at spotting malicious events through API hooking, improving the process of threat hunting analysis . 12 | When a new process is created, Captain will inject a dll into it hooking some Windows API functions. 13 | 14 | ## Captain signatures 15 | 16 | Captain signatures rely on the YAML format to identify malicious events. 17 | With a given set of events generated from the monitor, we can apply a signature to identify malicious behaviours, such as DLL injections, malicious macro executions, Lsass memory dumps, etc. 18 | 19 | A Captain signature represents the API call sequence of a given process along with the passed arguments. 20 | 21 | For example, to look for some LOLBINS abuse : 22 | ```yml 23 | --- 24 | 25 | - name : mshta malware 26 | proc_name : mshta.exe 27 | functions : 28 | - func_name : CreateProcessW 29 | arguments : 30 | lpApplicationName : C:\Windows\system32\cmd.exe 31 | ``` 32 | Or to spot Dll injection attempts : 33 | 34 | ```yml 35 | --- 36 | 37 | - name : DLL Injection 38 | proc_name : 39 | functions : 40 | - func_name : OpenProcess 41 | - func_name : VirtualAllocEx 42 | - func_name : WriteProcessMemory 43 | - func_name : CreateRemoteThread 44 | 45 | 46 | ``` 47 | To spot malicious macro executions : 48 | 49 | ```yml 50 | --- 51 | 52 | - name : MS Word macro execution 53 | proc_name : WINWORD.EXE 54 | functions : 55 | - func_name : CreateProcessW 56 | arguments : 57 | lpApplicationName : C:\Windows\system32\cmd.exe 58 | 59 | ``` 60 | 61 | ## Detection capabilities 62 | Captain is cable of detecting : 63 | 64 | - Code injection 65 | - Memory dump 66 | - Fileless malware 67 | - Macro execution 68 | - wmic and mshta malwares 69 | - etc 70 | 71 | Captain supports sysmon output mode. Using the appropriate script, Captain events could be converted into a sysmon-like output. 72 | 73 | In addition, Captain signatures could also be used to represent IOC, and thus assisting YARA rules. 74 | 75 | Captain supports different modes: 76 | 77 | - Memory injection mode (To spot memory injection) 78 | - Malicious behaviour mode 79 | - IOC mode (Consume resources) 80 | 81 | ## Usage 82 | 83 | To start with, here are Captain components : 84 | 85 | - **Monitor.ps1**: A PowerShell script responsible for monitoring process creations, for each created process, Monitor.ps1 will inject Captain.dll into the process memory using Injector.exe 86 | - **Injector.exe**: A simple program used to inject Captain.dll into processes. 87 | - **Captain.dll**: The dll responsible for hooking Windows API functions and logging events to a JSON file. 88 | - **behan.py**: The behaviour analysing script, written in python, behan.py is used to apply a given signature to a set of events generated by Captain.dll. it will try to explore the events looking for a match of the provided signature. 89 | - **sysconv.py**: A python script to convert Captain events from JSON to an XML, in order to be processed in the same way as sysmon events. 90 | 91 | For now, there is no installation script, but to use Captain, first, you should create a folder in **C:\ProgramData\Captain**, which contain **Captain.dll**, **Monitor.ps1** and **Injector.exe**, then you should start **Montor.ps1** powershell as an Administrator. 92 | 93 | 94 | 95 | Captain will create a subfolder **C:\ProgramData\Captain\Reporting** and store events in JSON format. 96 | 97 | ```JSON 98 | {"event_time":"2/1/2020 15:44:26:142","function":{"func_name":"OpenProcess"},"proc_id":"3568","proc_name":"C:\\Users\\peter\\Documents\\Captain\\Poc.exe"} 99 | {"event_time":"2/1/2020 15:44:26:142","function":{"func_name":"VirtualAlloc"},"proc_id":"3568","proc_name":"C:\\Users\\peter\\Documents\\Captain\\Poc.exe"} 100 | {"event_time":"2/1/2020 15:44:26:142","function":{"func_name":"WriteProcessMemory"},"proc_id":"3568","proc_name":"C:\\Users\\peter\\Documents\\Captain\\Poc.exe"} 101 | {"event_time":"2/1/2020 15:44:26:142","function":{"func_name":"CreateRemoteThread"},"proc_id":"3568","proc_name":"C:\\Users\\peter\\Documents\\Captain\\Poc.exe"} 102 | {"event_time":"2/1/2020 16:9:33:189","function":{"func_name":"OpenProcess"},"proc_id":"4656","proc_name":"C:\\Program Files\\Sublime Text 3\\sublime_text.exe"} 103 | {"event_time":"2/2/2020 22:27:4:135","function":{"arguments":{"lpLibFileName":"kernel32"},"func_name":"LoadLibraryW"},"proc_id":"7624","proc_name":"C:\\Windows\\system32\\cmd.exe"} 104 | {"event_time":"2/2/2020 22:27:18:321","function":{"arguments":{"lpLibFileName":"kernel32"},"func_name":"LoadLibraryW"},"proc_id":"4308","proc_name":"C:\\Windows\\system32\\calc.exe"} 105 | 106 | ``` 107 | 108 | Next, behan.py could be used to hunt for specific behaviour : 109 | 110 | 111 | ``` 112 | shell $ python behan.py -h 113 | Usage: behan.py [options] 114 | 115 | Options: 116 | -h, --help show this help message and exit 117 | -s SIG_FILE, --signature=SIG_FILE 118 | Specify a signature file to apply 119 | -S SIG_DIR, --signatures=SIG_DIR 120 | Specify a directory of signatures to apply 121 | -e EV_FILE, --event=EV_FILE 122 | Specify an event file to analyze 123 | -E EV_DIR, --events=EV_DIR 124 | Specify a directory of events to analyze 125 | 126 | ``` 127 | ``` 128 | shell $ python behan.py -S signatures/ -e events.json 129 | 130 | [+] Malicious event spotted 131 | 132 | Event : mshta malware 133 | Event time : 10/6/2019 15:47:37:533 134 | Processus name : C:\Windows\system32\mshta.exe 135 | Processus ID : 5536 136 | Event function name : CreateProcessW 137 | lpApplicationName : C:\Windows\system32\cmd.exe 138 | lpCommandLine : "C:\Windows\system32\cmd.exe" /q /c chcp 437 & (net session || echo unelevated) 1> C:\Users\peter\AppData\Local\Temp\7c5ff6cb-f678-23e0-59aa-608f777fb707.txt 2>&1 139 | 140 | 141 | 142 | [+] Malicious event spotted 143 | 144 | Event : regsvr32 malware 145 | Event time : 10/7/2019 20:58:0:219 146 | Processus name : C:\Windows\System32\regsvr32.exe 147 | Processus ID : 2476 148 | Event function name : LoadLibraryW 149 | lpLibFileName : scrobj.dll 150 | 151 | ``` 152 | 153 | ## Disclaimer 154 | **Please note that this is an alpha version of Captain which is 155 | still undergoing final testing before its official release. 156 | Please do not use it in a production environment.** 157 | 158 | ## To do : 159 | 160 | * Use Kernel level monitoring for process creation 161 | * Inject DLL from the Kernel using APC 162 | * Protect Captain files using a Kernel Module 163 | ... 164 | -------------------------------------------------------------------------------- /behan.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import os 4 | 5 | from ruamel.yaml import YAML 6 | import optparse 7 | 8 | 9 | class Function: 10 | def __init__(self, name): 11 | self.func_name = name 12 | self.arg_dict = {} 13 | self.match = False 14 | 15 | 16 | class Signature: 17 | def __init__(self, name): 18 | self.sig_name = name 19 | self.proc_name = '' 20 | self.func_list = [] 21 | 22 | 23 | 24 | 25 | class Event: 26 | def __init__(self): 27 | self.event_name = '' 28 | self.proc_name = '' 29 | self.proc_id = 0 30 | self.event_time = '' 31 | self.func_name = '' 32 | self.arg_dict = {} 33 | 34 | def parse_signature(sig_file): 35 | 36 | yaml = YAML() 37 | yaml.allow_duplicate_keys = True 38 | with open(sig_file) as _sig_file: 39 | signature = _sig_file.read() 40 | 41 | sigs = yaml.load(signature) 42 | for sig in sigs: 43 | __sig = Signature(sig['name']) 44 | if 'proc_name' in sig.keys(): 45 | __sig.proc_name = sig['proc_name'] 46 | for func in sig['functions']: 47 | __func = Function(func['func_name']) 48 | for key,value in func['arguments'].items(): 49 | __func.arg_dict[key] = value 50 | __sig.func_list.append(__func) 51 | 52 | return __sig 53 | 54 | 55 | def parse_event(event_str): 56 | 57 | event = Event() 58 | event.event_time = event_str['event_time'] 59 | event.proc_name = event_str['proc_name'] 60 | event.proc_id = event_str['proc_id'] 61 | event.func_name = event_str['function']['func_name'] 62 | for key,value in event_str['function']['arguments'].items(): 63 | event.arg_dict[key] = value 64 | 65 | return event 66 | 67 | 68 | def print_event(event): 69 | 70 | print('Event : ', event.event_name) 71 | print('Event time : ', event.event_time) 72 | print('Processus name : ', event.proc_name) 73 | print('Processus ID : ', event.proc_id) 74 | print('Event function name : ', event.func_name) 75 | for key,value in event.arg_dict.items(): 76 | print('\t', key, ' : ', value) 77 | 78 | def apply_signature(_sig_file, _event_file): 79 | 80 | 81 | signature = parse_signature(_sig_file) 82 | events_json = [json.loads(line) for line in open(_event_file, 'r')] 83 | 84 | if signature.proc_name != None: 85 | for entry in events_json: 86 | event = parse_event(entry) 87 | if event.proc_name.split('\\')[-1].lower() != signature.proc_name.split('\\')[-1].lower(): 88 | events_json.remove(entry) 89 | 90 | valid_events_groups = {} 91 | 92 | 93 | 94 | for func in signature.func_list: 95 | for entry in events_json: 96 | event = parse_event(entry) 97 | event.event_name = signature.sig_name 98 | if(event.func_name == func.func_name) : 99 | for key,value in func.arg_dict.items(): 100 | if value == event.arg_dict[key]: 101 | if event.proc_id in valid_events_groups.keys(): 102 | if event not in valid_events_groups[event.proc_id]: 103 | valid_events_groups[event.proc_id].append(event) 104 | else : 105 | valid_events_groups[event.proc_id] = [] 106 | valid_events_groups[event.proc_id].append(event) 107 | else : 108 | 109 | if event.proc_id in valid_events_groups.keys(): 110 | if event in valid_events_groups[event.proc_id]: 111 | valid_events_groups[event.proc_id].remove(event) 112 | 113 | 114 | match = False 115 | 116 | 117 | clean_valid_events_groups = valid_events_groups.copy() 118 | 119 | 120 | 121 | for key,value in valid_events_groups.items(): 122 | for func in signature.func_list: 123 | match == False 124 | for ev in valid_events_groups[key]: 125 | match = False 126 | if ev.func_name == func.func_name: 127 | match = True 128 | break 129 | 130 | if match == False: 131 | del clean_valid_events_groups[key] 132 | 133 | 134 | for key,value in clean_valid_events_groups.items(): 135 | for ev in value: 136 | print("[+] Malicious event spotted \n") 137 | print_event(ev) 138 | print('\n') 139 | 140 | 141 | if __name__ == '__main__': 142 | 143 | parser = optparse.OptionParser("usage: %prog [options] ") 144 | parser.add_option("-s", "--signature", dest="sig_file", type="string", help="Specify a signature file to apply") 145 | parser.add_option("-S", "--signatures", dest="sig_dir", type="string", help="Specify a directory of signatures to apply") 146 | parser.add_option("-e", "--event", dest="ev_file", type="string", help="Specify an event file to analyze") 147 | parser.add_option("-E", "--events", dest="ev_dir", type="string", help="Specify a directory of events to analyze") 148 | 149 | (options, args) = parser.parse_args() 150 | 151 | if (options.sig_file == None and options.sig_dir == None): 152 | parser.error("please provide at least a signature to apply") 153 | 154 | if (options.ev_file == None and options.ev_dir == None): 155 | parser.error("please provide at least an event file to analyze") 156 | 157 | if(options.sig_dir != None): 158 | if(options.ev_dir != None): 159 | for s_file in os.listdir(options.sig_dir): 160 | for e_file in os.listdir(options.ev_dir): 161 | apply_signature(s_file, e_file) 162 | else: 163 | for s_file in os.listdir(options.sig_dir): 164 | apply_signature(s_file, options.ev_file) 165 | 166 | else: 167 | if(options.ev_dir != None): 168 | for e_file in os.listdir(options.ev_dir): 169 | apply_signature(options.sig_file, e_file) 170 | else: 171 | apply_signature(options.sig_file, options.ev_file) 172 | 173 | 174 | -------------------------------------------------------------------------------- /binaries/Captain.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y3n11/Captain/933070c48d7430e9c22b9ea9c45a45bc1ba82926/binaries/Captain.dll -------------------------------------------------------------------------------- /binaries/Injector.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y3n11/Captain/933070c48d7430e9c22b9ea9c45a45bc1ba82926/binaries/Injector.exe -------------------------------------------------------------------------------- /binaries/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pictures/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pictures/captainhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y3n11/Captain/933070c48d7430e9c22b9ea9c45a45bc1ba82926/pictures/captainhook.png -------------------------------------------------------------------------------- /pictures/kisspng-peeter-paan-tinker-bell-peter-pan-captain-hook-nev-5b09609a6b65c7.7533439215273412104399.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y3n11/Captain/933070c48d7430e9c22b9ea9c45a45bc1ba82926/pictures/kisspng-peeter-paan-tinker-bell-peter-pan-captain-hook-nev-5b09609a6b65c7.7533439215273412104399.jpg -------------------------------------------------------------------------------- /pictures/monitor.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y3n11/Captain/933070c48d7430e9c22b9ea9c45a45bc1ba82926/pictures/monitor.PNG -------------------------------------------------------------------------------- /signatures/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /signatures/dll_injection.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name : DLL Injection 4 | proc_name : 5 | functions : 6 | - func_name : OpenProcess 7 | - func_name : VirtualAllocEx 8 | - func_name : WriteProcessMemory 9 | - func_name : CreateRemoteThread 10 | 11 | -------------------------------------------------------------------------------- /signatures/macro_execution.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name : MS Word macro execution 4 | proc_name : WINWORD.EXE 5 | functions : 6 | - func_name : CreateProcessW 7 | arguments : 8 | lpApplicationName : C:\Windows\system32\cmd.exe 9 | -------------------------------------------------------------------------------- /signatures/mshta.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name : mshta malware 4 | proc_name : mshta.exe 5 | functions : 6 | - func_name : CreateProcessW 7 | arguments : 8 | lpApplicationName : C:\Windows\system32\cmd.exe 9 | -------------------------------------------------------------------------------- /signatures/regsvr32.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name : regsvr32 malware 4 | proc_name : regsvr32.exe 5 | functions : 6 | - func_name : LoadLibraryW 7 | arguments : 8 | lpLibFileName : scrobj.dll 9 | -------------------------------------------------------------------------------- /src/Captain.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Hooks.hpp" 3 | #include "CaptainHook.hpp" 4 | 5 | 6 | VOID EnableHooks() 7 | { 8 | LPBYTE bytes = nullptr; 9 | 10 | std::string psName = Utils::GetCurrentProcessName(); 11 | 12 | 13 | fpCreateProcessW = (pfnCreateProcessW)GetProcAddress(LoadLibraryW(L"kernel32"), "CreateProcessW"); 14 | if (fpCreateProcessW == NULL) 15 | return; 16 | 17 | bytes = CaptainHook::HookFunction((DWORD64)fpCreateProcessW, (DWORD64)HookedCreateProcessW); 18 | g_saved_bytes.insert({"CreateProcessW", bytes}); 19 | 20 | 21 | fpLoadLibraryW = (pfnLoadLibraryW)GetProcAddress(LoadLibraryW(L"kernel32"), "LoadLibraryW"); 22 | if(fpLoadLibraryW == NULL) 23 | return; 24 | 25 | bytes = CaptainHook::HookFunction((DWORD64)fpLoadLibraryW, (DWORD64)HookedLoadLibraryW); 26 | g_saved_bytes.insert({"LoadLibraryW", bytes}); 27 | 28 | fpLoadLibraryA = (pfnLoadLibraryA)GetProcAddress(LoadLibraryW(L"kernel32"), "LoadLibraryA"); 29 | if(fpLoadLibraryW == NULL) 30 | return; 31 | 32 | bytes = CaptainHook::HookFunction((DWORD64)fpLoadLibraryA, (DWORD64)HookedLoadLibraryA); 33 | g_saved_bytes.insert({"LoadLibraryA", bytes}); 34 | 35 | fpLoadLibraryExW = (pfnLoadLibraryExW)GetProcAddress(LoadLibraryW(L"kernel32"), "LoadLibraryExW"); 36 | if(fpLoadLibraryExW == NULL) 37 | return; 38 | 39 | bytes = CaptainHook::HookFunction((DWORD64)fpLoadLibraryExW, (DWORD64)HookedLoadLibraryExW); 40 | g_saved_bytes.insert({"LoadLibraryExW", bytes}); 41 | 42 | fpCreateRemoteThread = (pfnCreateRemoteThread)GetProcAddress(LoadLibraryW(L"kernel32"), "CreateRemoteThread"); 43 | if(fpCreateRemoteThread == NULL) 44 | return; 45 | 46 | bytes = CaptainHook::HookFunction((DWORD64)fpCreateRemoteThread, (DWORD64)HookedCreateRemoteThread); 47 | g_saved_bytes.insert({"CreateRemoteThread", bytes}); 48 | 49 | 50 | fpVirtualAllocEx = (pfnVirtualAllocEx)GetProcAddress(LoadLibraryW(L"kernel32"), "VirtualAllocEx"); 51 | if(fpVirtualAllocEx == NULL) 52 | return; 53 | 54 | bytes = CaptainHook::HookFunction((DWORD64)fpVirtualAllocEx, (DWORD64)HookedVirtualAllocEx); 55 | g_saved_bytes.insert({"VirtualAllocEx", bytes}); 56 | 57 | 58 | fpWriteProcessMemory = (pfnWriteProcessMemory)GetProcAddress(LoadLibraryW(L"kernel32"), "WriteProcessMemory"); 59 | if(fpWriteProcessMemory == NULL) 60 | return; 61 | 62 | bytes = CaptainHook::HookFunction((DWORD64)fpWriteProcessMemory, (DWORD64)HookedWriteProcessMemory); 63 | g_saved_bytes.insert({"WriteProcessMemory", bytes}); 64 | 65 | 66 | fpReadProcessMemory = (pfnReadProcessMemory)GetProcAddress(LoadLibraryW(L"kernel32"), "ReadProcessMemory"); 67 | if(fpReadProcessMemory == NULL) 68 | return; 69 | 70 | bytes = CaptainHook::HookFunction((DWORD64)fpReadProcessMemory, (DWORD64)HookedReadProcessMemory); 71 | g_saved_bytes.insert({"ReadProcessMemory", bytes}); 72 | 73 | if (psName == "C:\\Windows\\Explorer.EXE" || 74 | psName == "C:\\Windows\\explorer.exe") 75 | return; 76 | 77 | fpOpenProcess = (pfnOpenProcess)GetProcAddress(LoadLibraryW(L"kernel32"), "OpenProcess"); 78 | if(fpOpenProcess == NULL) 79 | return; 80 | 81 | bytes = CaptainHook::HookFunction((DWORD64)fpOpenProcess, (DWORD64)HookedOpenProcess); 82 | g_saved_bytes.insert({"OpenProcess", bytes}); 83 | 84 | } 85 | 86 | VOID DisableHooks() 87 | { 88 | std::string psName = Utils::GetCurrentProcessName(); 89 | 90 | CaptainHook::UnHookFunction((DWORD64)fpCreateProcessW, g_saved_bytes.find("CreateProcessW")->second); 91 | CaptainHook::UnHookFunction((DWORD64)fpLoadLibraryW, g_saved_bytes.find("LoadLibraryW")->second); 92 | CaptainHook::UnHookFunction((DWORD64)fpLoadLibraryA, g_saved_bytes.find("LoadLibraryA")->second); 93 | CaptainHook::UnHookFunction((DWORD64)fpLoadLibraryExW, g_saved_bytes.find("LoadLibraryExW")->second); 94 | CaptainHook::UnHookFunction((DWORD64)fpCreateRemoteThread, g_saved_bytes.find("CreateRemoteThread")->second); 95 | CaptainHook::UnHookFunction((DWORD64)fpVirtualAllocEx, g_saved_bytes.find("VirtualAllocEx")->second); 96 | CaptainHook::UnHookFunction((DWORD64)fpWriteProcessMemory, g_saved_bytes.find("WriteProcessMemory")->second); 97 | CaptainHook::UnHookFunction((DWORD64)fpReadProcessMemory, g_saved_bytes.find("ReadProcessMemory")->second); 98 | 99 | if (psName == "C:\\Windows\\Explorer.EXE" || 100 | psName == "C:\\Windows\\explorer.exe") 101 | return; 102 | 103 | 104 | CaptainHook::UnHookFunction((DWORD64)fpOpenProcess, g_saved_bytes.find("OpenProcess")->second); 105 | 106 | } 107 | 108 | 109 | BOOL APIENTRY DllMain(HANDLE hInstance, DWORD fdwReason, LPVOID lpReserved) { 110 | 111 | switch (fdwReason) { 112 | 113 | case DLL_PROCESS_ATTACH: 114 | 115 | Reporting::Init(); 116 | EnableHooks(); 117 | 118 | break; 119 | 120 | case DLL_PROCESS_DETACH: 121 | 122 | DisableHooks(); 123 | 124 | break; 125 | } 126 | 127 | return TRUE; 128 | } 129 | -------------------------------------------------------------------------------- /src/CaptainHook.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _CAPTAINHOOK_ 2 | #define _CAPTAINHOOK_ 3 | 4 | #include 5 | #include 6 | 7 | namespace CaptainHook{ 8 | 9 | template 10 | static T ReadMemory(LPVOID lpAddress) { 11 | return *((T *)lpAddress); 12 | } 13 | 14 | template 15 | static void WriteMemory(LPVOID lpAddress, T value) { 16 | *((T *)lpAddress) = value; 17 | } 18 | 19 | template 20 | T* PointMemory(DWORD address) { 21 | return ((T*)address); 22 | } 23 | 24 | template 25 | static DWORD ProtectMemory(LPVOID lpAddress, SIZE_T size, DWORD flProtect) { 26 | DWORD flOldProtect = 0; 27 | ::VirtualProtect(lpAddress, size, flProtect, &flOldProtect); 28 | 29 | return flOldProtect; 30 | } 31 | 32 | static LPBYTE HookFunction(DWORD64 dwFuncAddress, DWORD64 dwNewAddress){ 33 | 34 | LPBYTE origBytes = new BYTE[16]; //10 35 | 36 | for(INT i = 0; i < 16; i++){ 37 | origBytes[i] = ReadMemory((LPVOID)(dwFuncAddress + i)); 38 | } 39 | 40 | DWORD flOldProtect = ProtectMemory((LPVOID)dwFuncAddress, 16, PAGE_EXECUTE_READWRITE); 41 | 42 | WriteMemory((LPVOID)dwFuncAddress, 0x50); 43 | WriteMemory((LPVOID)(dwFuncAddress + 1), 0x48); 44 | WriteMemory((LPVOID)(dwFuncAddress + 2), 0xb8); 45 | WriteMemory((LPVOID)(dwFuncAddress + 3), dwNewAddress); 46 | WriteMemory((LPVOID)(dwFuncAddress + 11), 0x48); 47 | WriteMemory((LPVOID)(dwFuncAddress + 12), 0x87); 48 | WriteMemory((LPVOID)(dwFuncAddress + 13), 0x04); 49 | WriteMemory((LPVOID)(dwFuncAddress + 14), 0x24); 50 | WriteMemory((LPVOID)(dwFuncAddress + 15), 0xC3); 51 | 52 | 53 | ProtectMemory((LPVOID)dwFuncAddress, 16, flOldProtect); 54 | 55 | return origBytes; 56 | } 57 | 58 | static VOID UnHookFunction(DWORD64 dwFuncAddress, LPBYTE origBytes){ 59 | 60 | DWORD flOldProtect = ProtectMemory((LPVOID)dwFuncAddress, 16, PAGE_EXECUTE_READWRITE); 61 | 62 | for(INT i = 0; i < 16; i++) 63 | WriteMemory((LPVOID)(dwFuncAddress + i), origBytes[i]); 64 | 65 | ProtectMemory((LPVOID)dwFuncAddress, 16, flOldProtect); 66 | } 67 | 68 | } 69 | 70 | 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/Hooks.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _HOOKS_ 2 | #define _HOOKS_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "CaptainHook.hpp" 13 | #include "Reporting.hpp" 14 | #include "Utils.hpp" 15 | 16 | typedef BOOL(WINAPI *pfnCreateProcessW)(LPCWSTR lpApplicationName, 17 | LPTSTR lpCommandLine, 18 | LPSECURITY_ATTRIBUTES lpProcessAttributes, 19 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 20 | BOOL bInheritHandles, 21 | DWORD dwCreationFlags, 22 | LPVOID lpEnvironment, 23 | LPCTSTR lpCurrentDirectory, 24 | LPSTARTUPINFOW lpStartupInfo, 25 | LPPROCESS_INFORMATION lpProcessInformation); 26 | 27 | 28 | typedef HANDLE(WINAPI *pfnCreateFileW)( LPCWSTR lpFileName, 29 | DWORD dwDesiredAccess, 30 | DWORD dwShareMode, 31 | LPSECURITY_ATTRIBUTES lpSecurityAttributes, 32 | DWORD dwCreationDisposition, 33 | DWORD dwFlagsAndAttributes, 34 | HANDLE hTemplateFile); 35 | 36 | typedef BOOL(WINAPI *pfnDeleteFileW)(LPCWSTR path); 37 | typedef HMODULE(WINAPI *pfnLoadLibraryW)(LPCWSTR lpLibFileName); 38 | typedef HMODULE(WINAPI *pfnLoadLibraryA)(LPCSTR lpLibFileName); 39 | 40 | typedef LONG(WINAPI *pfnRegOpenKeyExW)( HKEY hKey, 41 | LPCWSTR lpSubKey, 42 | DWORD ulOptions, 43 | REGSAM samDesired, 44 | PHKEY phkResult ); 45 | 46 | 47 | typedef HMODULE(*pfnLoadLibraryExW)( LPCWSTR lpLibFileName, 48 | HANDLE hFile, 49 | DWORD dwFlags); 50 | 51 | typedef HANDLE(WINAPI *pfnCreateRemoteThread)( HANDLE hProcess, 52 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 53 | SIZE_T dwStackSize, 54 | LPTHREAD_START_ROUTINE lpStartAddress, 55 | LPVOID lpParameter, 56 | DWORD dwCreationFlags, 57 | LPDWORD lpThreadId ); 58 | 59 | 60 | typedef LPVOID (WINAPI * pfnVirtualAllocEx)( HANDLE hProcess, 61 | LPVOID lpAddress, 62 | SIZE_T dwSize, 63 | DWORD flAllocationType, 64 | DWORD flProtect ); 65 | 66 | 67 | typedef BOOL (WINAPI * pfnWriteProcessMemory)( HANDLE hProcess, 68 | LPVOID lpBaseAddress, 69 | LPCVOID lpBuffer, 70 | SIZE_T nSize, 71 | SIZE_T *lpNumberOfBytesWritten); 72 | 73 | 74 | typedef BOOL (WINAPI * pfnReadProcessMemory)( HANDLE hProcess, 75 | LPCVOID lpBaseAddress, 76 | LPVOID lpBuffer, 77 | SIZE_T nSize, 78 | SIZE_T *lpNumberOfBytesRead ); 79 | 80 | typedef HANDLE (WINAPI * pfnOpenProcess)( DWORD dwDesiredAccess, 81 | BOOL bInheritHandle, 82 | DWORD dwProcessId ); 83 | 84 | pfnCreateProcessW fpCreateProcessW; 85 | pfnCreateFileW fpCreateFileW; 86 | pfnDeleteFileW fpDeleteFileW; 87 | pfnLoadLibraryW fpLoadLibraryW; 88 | pfnRegOpenKeyExW fpRegOpenKeyExW; 89 | pfnLoadLibraryA fpLoadLibraryA; 90 | pfnLoadLibraryExW fpLoadLibraryExW; 91 | pfnCreateRemoteThread fpCreateRemoteThread; 92 | pfnVirtualAllocEx fpVirtualAllocEx; 93 | pfnWriteProcessMemory fpWriteProcessMemory; 94 | pfnReadProcessMemory fpReadProcessMemory; 95 | pfnOpenProcess fpOpenProcess; 96 | 97 | 98 | 99 | std::map g_saved_bytes; 100 | 101 | BOOL WINAPI HookedCreateProcessW (LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { 102 | 103 | BYTE bSavedByte; 104 | std::map _args; 105 | 106 | _args.insert(std::pair("lpApplicationName", Utils::WideStringToAscii(lpApplicationName))); 107 | _args.insert(std::pair("lpCommandLine", Utils::WideStringToAscii(lpCommandLine))); 108 | 109 | Reporting::Log("CreateProcessW", _args); 110 | 111 | CaptainHook::UnHookFunction((DWORD64)fpCreateProcessW, g_saved_bytes.find("CreateProcessW")->second); 112 | BOOL b = CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); 113 | g_saved_bytes.find("CreateProcessW")->second = CaptainHook::HookFunction((DWORD64)fpCreateProcessW, (DWORD64)HookedCreateProcessW); 114 | 115 | return b; 116 | } 117 | 118 | 119 | BOOL WINAPI HookedDeleteFileW(LPCWSTR lpFileName){ 120 | 121 | BYTE bSavedByte; 122 | std::map _args; 123 | _args.insert(std::pair("lpFileName", Utils::WideStringToAscii(lpFileName))); 124 | Reporting::Log("DeleteFileW", _args); 125 | 126 | CaptainHook::UnHookFunction((DWORD64)fpDeleteFileW, g_saved_bytes.find("DeleteFileW")->second); 127 | BOOL b = DeleteFileW(lpFileName); 128 | g_saved_bytes.find("DeleteFileW")->second = CaptainHook::HookFunction((DWORD64)fpDeleteFileW, (DWORD64)HookedDeleteFileW); 129 | 130 | return b; 131 | } 132 | 133 | 134 | /*HANDLE WINAPI HookedCreateFileW( LPCWSTR lpFileName, 135 | DWORD dwDesiredAccess, 136 | DWORD dwShareMode, 137 | LPSECURITY_ATTRIBUTES lpSecurityAttributes, 138 | DWORD dwCreationDisposition, 139 | DWORD dwFlagsAndAttributes, 140 | HANDLE hTemplateFile){ 141 | 142 | BYTE bSavedByte; 143 | CaptainHook::UnHookFunction((DWORD64)fpCreateFileW, g_saved_bytes.find("CreateFileW")->second); 144 | 145 | std::map _args; 146 | _args.insert(std::pair("lpFileName", Utils::WideStringToAscii(lpFileName))); 147 | Reporting::Log("CreateFileW", _args); 148 | 149 | HANDLE hFile = CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); 150 | g_saved_bytes.find("CreateFileW")->second = CaptainHook::HookFunction((DWORD64)fpCreateFileW, (DWORD64)HookedCreateFileW); 151 | 152 | return hFile; 153 | 154 | }*/ 155 | 156 | HMODULE WINAPI HookedLoadLibraryW(LPCWSTR lpLibFileName) 157 | { 158 | BYTE bSavedByte; 159 | 160 | 161 | 162 | std::map _args; 163 | _args.insert(std::pair("lpLibFileName", Utils::WideStringToAscii(lpLibFileName))); 164 | Reporting::Log("LoadLibraryW", _args); 165 | 166 | CaptainHook::UnHookFunction((DWORD64)fpLoadLibraryW, g_saved_bytes.find("LoadLibraryW")->second); 167 | HMODULE hModule = LoadLibraryW(lpLibFileName); 168 | 169 | g_saved_bytes.find("LoadLibraryW")->second = CaptainHook::HookFunction((DWORD64)fpLoadLibraryW, (DWORD64)HookedLoadLibraryW); 170 | 171 | return hModule; 172 | 173 | } 174 | 175 | HMODULE HookedLoadLibraryExW( LPCWSTR lpLibFileName, 176 | HANDLE hFile, 177 | DWORD dwFlag) 178 | { 179 | BYTE bSavedByte; 180 | 181 | 182 | std::map _args; 183 | _args.insert(std::pair("lpLibFileName", Utils::WideStringToAscii(lpLibFileName))); 184 | Reporting::Log("LoadLibraryExW", _args); 185 | 186 | CaptainHook::UnHookFunction((DWORD64)fpLoadLibraryExW, g_saved_bytes.find("LoadLibraryExW")->second); 187 | HMODULE hModule = LoadLibraryExW(lpLibFileName, hFile, dwFlag); 188 | 189 | g_saved_bytes.find("LoadLibraryExW")->second = CaptainHook::HookFunction((DWORD64)fpLoadLibraryExW, (DWORD64)HookedLoadLibraryExW); 190 | 191 | return hModule; 192 | 193 | } 194 | 195 | HMODULE WINAPI HookedLoadLibraryA(LPCSTR lpLibFileName) 196 | { 197 | BYTE bSavedByte; 198 | 199 | 200 | std::map _args; 201 | _args.insert(std::pair("lpLibFileName", std::string(lpLibFileName))); 202 | Reporting::Log("LoadLibraryA", _args); 203 | 204 | CaptainHook::UnHookFunction((DWORD64)fpLoadLibraryA, g_saved_bytes.find("LoadLibraryA")->second); 205 | HMODULE hModule = LoadLibraryA(lpLibFileName); 206 | 207 | g_saved_bytes.find("LoadLibraryA")->second = CaptainHook::HookFunction((DWORD64)fpLoadLibraryA, (DWORD64)HookedLoadLibraryA); 208 | 209 | return hModule; 210 | 211 | } 212 | 213 | HANDLE WINAPI HookedCreateRemoteThread( 214 | HANDLE hProcess, 215 | LPSECURITY_ATTRIBUTES lpThreadAttributes, 216 | SIZE_T dwStackSize, 217 | LPTHREAD_START_ROUTINE lpStartAddress, 218 | LPVOID lpParameter, 219 | DWORD dwCreationFlags, 220 | LPDWORD lpThreadId ) 221 | { 222 | BYTE bSavedByte; 223 | 224 | std::map _args; 225 | Reporting::Log("CreateRemoteThread", _args); 226 | 227 | CaptainHook::UnHookFunction((DWORD64)fpCreateRemoteThread, g_saved_bytes.find("CreateRemoteThread")->second); 228 | HANDLE hThread = CreateRemoteThread(hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId); 229 | 230 | g_saved_bytes.find("CreateRemoteThread")->second = CaptainHook::HookFunction((DWORD64)fpCreateRemoteThread, (DWORD64)HookedCreateRemoteThread); 231 | 232 | return hThread; 233 | } 234 | 235 | LPVOID HookedVirtualAllocEx( 236 | HANDLE hProcess, 237 | LPVOID lpAddress, 238 | SIZE_T dwSize, 239 | DWORD flAllocationType, 240 | DWORD flProtect) 241 | { 242 | std::map _args; 243 | Reporting::Log("VirtualAllocEx", _args); 244 | 245 | CaptainHook::UnHookFunction((DWORD64)fpVirtualAllocEx, g_saved_bytes.find("VirtualAllocEx")->second); 246 | LPVOID lpMem = VirtualAllocEx(hProcess, lpAddress, dwSize, flAllocationType, flProtect); 247 | g_saved_bytes.find("VirtualAllocEx")->second = CaptainHook::HookFunction((DWORD64)fpVirtualAllocEx, (DWORD64)HookedVirtualAllocEx); 248 | 249 | return lpMem; 250 | } 251 | 252 | 253 | BOOL HookedWriteProcessMemory( 254 | HANDLE hProcess, 255 | LPVOID lpBaseAddress, 256 | LPCVOID lpBuffer, 257 | SIZE_T nSize, 258 | SIZE_T *lpNumberOfBytesWritten) 259 | { 260 | std::map _args; 261 | Reporting::Log("WriteProcessMemory", _args); 262 | 263 | CaptainHook::UnHookFunction((DWORD64)fpWriteProcessMemory, g_saved_bytes.find("WriteProcessMemory")->second); 264 | BOOL b = WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten); 265 | g_saved_bytes.find("WriteProcessMemory")->second = CaptainHook::HookFunction((DWORD64)fpWriteProcessMemory, (DWORD64)HookedWriteProcessMemory); 266 | 267 | return b; 268 | } 269 | 270 | 271 | 272 | BOOL HookedReadProcessMemory( 273 | HANDLE hProcess, 274 | LPCVOID lpBaseAddress, 275 | LPVOID lpBuffer, 276 | SIZE_T nSize, 277 | SIZE_T *lpNumberOfBytesRead) 278 | { 279 | std::map _args; 280 | Reporting::Log("ReadProcessMemory", _args); 281 | 282 | CaptainHook::UnHookFunction((DWORD64)fpReadProcessMemory, g_saved_bytes.find("ReadProcessMemory")->second); 283 | BOOL b = ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead); 284 | g_saved_bytes.find("ReadProcessMemory")->second = CaptainHook::HookFunction((DWORD64)fpReadProcessMemory, (DWORD64)HookedReadProcessMemory); 285 | 286 | return b; 287 | 288 | } 289 | 290 | 291 | HANDLE HookedOpenProcess( 292 | DWORD dwDesiredAccess, 293 | BOOL bInheritHandle, 294 | DWORD dwProcessId) 295 | { 296 | std::map _args; 297 | Reporting::Log("OpenProcess", _args); 298 | 299 | CaptainHook::UnHookFunction((DWORD64)fpOpenProcess, g_saved_bytes.find("OpenProcess")->second); 300 | HANDLE h = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId); 301 | g_saved_bytes.find("OpenProcess")->second = CaptainHook::HookFunction((DWORD64)fpOpenProcess, (DWORD64)HookedOpenProcess); 302 | 303 | return h; 304 | } 305 | 306 | 307 | /* 308 | 309 | LONG WINAPI HookedRegOpenKeyExW( HKEY hKey, 310 | LPCWSTR lpSubKey, 311 | DWORD ulOptions, 312 | REGSAM samDesired, 313 | PHKEY phkResult) 314 | { 315 | BYTE bSavedByte; 316 | CaptainHook::UnHookFunction((DWORD64)fpCreateFileW, g_saved_bytes.find("CreateFileW")->second); 317 | 318 | std::map _args; 319 | _args.insert(std::pair("lpSubKey", Utils::WideStringToAscii(lpSubKey))); 320 | Reporting::Log("RegOpenKeyExW", _args); 321 | 322 | CaptainHook::UnHookFunction((DWORD64)fpRegOpenKeyExW, g_saved_bytes.find("RegOpenKeyExW")->second); 323 | LONG ret = fpRegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult); 324 | 325 | g_saved_bytes.find("CreateFileW")->second = CaptainHook::HookFunction((DWORD64)fpCreateFileW, (DWORD64)HookedCreateFileW); 326 | g_saved_bytes.find("RegOpenKeyExW")->second = CaptainHook::HookFunction((DWORD64)fpRegOpenKeyExW, (DWORD64)HookedRegOpenKeyExW); 327 | 328 | return ret; 329 | } 330 | 331 | */ 332 | 333 | #endif 334 | -------------------------------------------------------------------------------- /src/Reporting.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _REPORTING_ 2 | #define _REPORTING_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "Utils.hpp" 13 | #include "json.hpp" 14 | 15 | namespace Reporting{ 16 | 17 | 18 | VOID Log(std::string func_name, std::map arguments) 19 | { 20 | nlohmann::json j; 21 | std::ofstream log_file; 22 | 23 | j["event_time"] = Utils::GetCurrentDateTime(); 24 | j["proc_name"] = Utils::GetCurrentProcessName(); 25 | j["proc_id"] = std::to_string(GetCurrentProcessId()); 26 | 27 | j["function"]["func_name"] = func_name; 28 | 29 | for(const auto &p : arguments) 30 | j["function"]["arguments"][p.first] = p.second; 31 | 32 | log_file.open("C:\\ProgramData\\Captain\\Reporting\\events.json", std::ios::out | std::ios::app); 33 | log_file << j << '\n'; 34 | log_file.close(); 35 | } 36 | 37 | VOID Init() 38 | { 39 | 40 | CHAR base_folder[] = "C:\\ProgramData\\Captain\\Reporting"; 41 | if(CreateDirectoryA(base_folder, NULL) 42 | || ERROR_ALREADY_EXISTS == GetLastError()) 43 | { 44 | // 45 | } 46 | } 47 | 48 | } 49 | 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/Utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _UTILS_ 2 | #define _UTILS_ 3 | 4 | #include 5 | 6 | namespace Utils{ 7 | 8 | std::string GetCurrentDateTime() 9 | { 10 | SYSTEMTIME _sys; 11 | GetSystemTime(&_sys); 12 | std::string _datetime = std::to_string(_sys.wMonth) + "/" 13 | + std::to_string(_sys.wDay) + "/" 14 | + std::to_string(_sys.wYear) + " " 15 | + std::to_string(_sys.wHour) + ":" 16 | + std::to_string(_sys.wMinute) + ":" 17 | + std::to_string(_sys.wSecond) + ":" 18 | + std::to_string(_sys.wMilliseconds); 19 | return _datetime; 20 | } 21 | 22 | std::string GetCurrentProcessName() 23 | { 24 | CHAR szExeFileName[MAX_PATH]; 25 | GetModuleFileNameA(NULL, szExeFileName, MAX_PATH); 26 | return std::string(szExeFileName); 27 | } 28 | 29 | std::string WideStringToAscii(std::wstring _wstr) 30 | { 31 | using convert_type = std::codecvt_utf8; 32 | std::wstring_convert converter; 33 | std::string ascii_msg = converter.to_bytes(_wstr); 34 | 35 | return ascii_msg; 36 | } 37 | } 38 | 39 | 40 | #endif --------------------------------------------------------------------------------