carbonblack / binee

Binee: binary emulation environment
GNU General Public License v2.0
502 stars 73 forks source link

ntdll,user32: Add support for ntdll.KiFastSystemCall sysenter wrapper, as needed by NtUserCallOneParam and NtUserCallTwoParam of user32.dll #45

Open mewmew opened 4 years ago

mewmew commented 4 years ago

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).

  1. The sample binary pushes 1 argument to the stack and invokes ShowCursor of user32.dll.
  2. 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.
  3. 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])
  4. The KiFastSystemCall function of ntdll assigns arguments to the corresponding registers and performs a call to sysenter.
  5. 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).

mewmew commented 4 years ago

7FFE0300h is supposed to point to SharedUserData!SystemCallStub

From http://www.nynaeve.net/?p=131

0:000> u ntdll!NtClose
ntdll!ZwClose:
mov     eax,30h
mov     edx,offset SharedUserData!SystemCallStub
call    dword ptr [edx]
ret     4

Edit: another link on the topic, SystemCallStub is removed in Windows 8 it seems: https://www.malwaretech.com/2015/07/windows-10-system-call-stub-changes.html