To enable analysis of samples using user32.dll, support for KiFastSystemCall of ntdll is needed in binee.
Roughly, this is what happens when a program invokes a function of user32.dll, say ShowCursor(FALSE).
- The sample binary pushes 1 argument to the stack and invokes
ShowCursor of user32.dll.
- The
ShowCursor function of user32.dll pushes a simple call routine ID (e.g. the ID of ShowCursor is 0x40 on XP) and the argument of ShowCursor and then invokes NtUserCallOneParam.
- The
NtUserCallOneParam function assigns arguments to the corresponding registers and invokes KiFastSystemCall of ntdll, through an indirect call to 0x7FFE0300 (i.e. mov edx, 7FFE0300h; call dword ptr [edx])
- The
KiFastSystemCall function of ntdll assigns arguments to the corresponding registers and performs a call to sysenter.
- Now, the system call performs the simple routine of
user32.dll as indicated by the given ID.
Using binee to analyze a simple program using ShowCursor currently results an premature abort of the analysis, as binee cannot resolve the indirect call to 0x7ffe0300 (which should resolve to KiFastSystemCall of ntdll).
A minimal test case is provided below.
$ ~/Desktop/binee/binee -v -d -c win.yaml c.exe
[1] 0x00401000: push 0
[1] 0x00401002: call 0x12
[1] 0x00401014: jmp dword ptr [0x402008]
[1] 0x20566a6e: **user32.dll:ShowCursor**() = 0xb0010000
[1] 0x20566a6e: mov edi, edi
[1] 0x20566a70: push ebp
[1] 0x20566a71: mov ebp, esp
[1] 0x20566a73: push 0x40
[1] 0x20566a75: push dword ptr [ebp + 8]
[1] 0x20566a78: call 0xfffe8a36
[1] 0x2054f4ae: mov eax, 0x1143
[1] 0x2054f4b3: mov edx, 0x7ffe0300
[1] 0x2054f4b8: call dword ptr [edx]
# Note: analysis is prematurely aborted here. It should continue to analyze, in this case the call to ExitProcess
Contents of c.asm:
extern _ShowCursor@4
extern _ExitProcess@4
global _WinMain@12
[section .text]
_WinMain@12:
push 0
call _ShowCursor@4
push 123
call _ExitProcess@4
Build instructions:
# assemble c.asm into 32-bit PE object file.
$ nasm -f win32 -o c.obj c.asm
# link object file with kernel32.lib to create executable
$ wine ~/VS6/VC98/Bin/LINK.EXE /OUT:c.exe /ENTRY:WinMain@12 /subsystem:windows /machine:i386 /LIBPATH:${HOME}/VS6/VC98/LIB /nologo c.obj kernel32.lib user32.lib
# run binary to check result of GetLastError
$ wine c.exe ; echo $?
123
c.exe attachment: c.tar.gz
User code:
push 0
call _ShowCursor@4
ShowCursor of user32.dll as presented in IDA:
.text:7E42FA6E ; int __stdcall ShowCursor(BOOL bShow)
.text:7E42FA6E public _ShowCursor@4
.text:7E42FA6E _ShowCursor@4 proc near ; DATA XREF: .text:off_7E413928↑o
.text:7E42FA6E
.text:7E42FA6E bShow = dword ptr 8
.text:7E42FA6E
.text:7E42FA6E mov edi, edi
.text:7E42FA70 push ebp
.text:7E42FA71 mov ebp, esp
.text:7E42FA73 push 40h ; '@'
.text:7E42FA75 push [ebp+bShow]
.text:7E42FA78 call _NtUserCallOneParam@8 ; NtUserCallOneParam(x,x)
.text:7E42FA7D pop ebp
.text:7E42FA7E retn 4
.text:7E42FA7E _ShowCursor@4 endp
Code of NtUserCallOneParam as presented in IDA:
.text:7E4184AE ; __stdcall NtUserCallOneParam(x, x)
.text:7E4184AE _NtUserCallOneParam@8 proc near ; CODE XREF: ReleaseDC(x,x)+1C↓p
.text:7E4184AE ; RealMsgWaitForMultipleObjectsEx(x,x,x,x,x)+72↓p ...
.text:7E4184AE mov eax, 1143h
.text:7E4184B3 mov edx, 7FFE0300h
.text:7E4184B8 call dword ptr [edx]
.text:7E4184BA retn 8
.text:7E4184BA _NtUserCallOneParam@8 endp
Code of KiFastSystemCall as presented in IDA:
.text:7C90E4F0 ; Exported entry 41. KiFastSystemCall
.text:7C90E4F0
.text:7C90E4F0 ; =============== S U B R O U T I N E =======================================
.text:7C90E4F0
.text:7C90E4F0
.text:7C90E4F0 ; _DWORD __stdcall KiFastSystemCall()
.text:7C90E4F0 public _KiFastSystemCall@0
.text:7C90E4F0 _KiFastSystemCall@0 proc near ; DATA XREF: .text:off_7C903428↑o
.text:7C90E4F0 mov edx, esp
.text:7C90E4F2 sysenter
.text:7C90E4F2 _KiFastSystemCall@0 endp
.text:7C90E4F2
.text:7C90E4F4 ; Exported entry 42. KiFastSystemCallRet
.text:7C90E4F4
.text:7C90E4F4 ; =============== S U B R O U T I N E =======================================
.text:7C90E4F4
.text:7C90E4F4
.text:7C90E4F4 ; _DWORD __stdcall KiFastSystemCallRet()
.text:7C90E4F4 public _KiFastSystemCallRet@0
.text:7C90E4F4 _KiFastSystemCallRet@0 proc near ; DATA XREF: .text:off_7C903428↑o
.text:7C90E4F4 retn
.text:7C90E4F4 _KiFastSystemCallRet@0 endp
References:
Edit: a related by orthogonal issue to this would be that an error should be reported by binee to indicate premature abort of analysis, so the analyzee can make an informed decision as to how to proceed (and not be under the false pretense that analysis completed successfully).
To enable analysis of samples using
user32.dll, support forKiFastSystemCallofntdllis needed inbinee.Roughly, this is what happens when a program invokes a function of
user32.dll, sayShowCursor(FALSE).ShowCursorofuser32.dll.ShowCursorfunction ofuser32.dllpushes a simple call routine ID (e.g. the ID ofShowCursoris0x40on XP) and the argument ofShowCursorand then invokesNtUserCallOneParam.NtUserCallOneParamfunction assigns arguments to the corresponding registers and invokesKiFastSystemCallofntdll, through an indirect call to0x7FFE0300(i.e.mov edx, 7FFE0300h; call dword ptr [edx])KiFastSystemCallfunction ofntdllassigns arguments to the corresponding registers and performs a call tosysenter.user32.dllas indicated by the given ID.Using
bineeto analyze a simple program usingShowCursorcurrently results an premature abort of the analysis, asbineecannot resolve the indirect call to0x7ffe0300(which should resolve toKiFastSystemCallofntdll).A minimal test case is provided below.
Contents of
c.asm:Build instructions:
c.exeattachment: c.tar.gzUser code:
ShowCursorofuser32.dllas presented in IDA:Code of
NtUserCallOneParamas presented in IDA:Code of
KiFastSystemCallas presented in IDA:References:
Edit: a related by orthogonal issue to this would be that an error should be reported by
bineeto indicate premature abort of analysis, so the analyzee can make an informed decision as to how to proceed (and not be under the false pretense that analysis completed successfully).