Search: Home Bugtraq Vulnerabilities Mailing Lists Security Jobs Tools
      (page 1 of 3 ) next 
Windows Syscall Shellcode
Piotr Bania 2005-08-04

Introduction

This article has been written to show that is possible to write shellcode for Windows operating systems that doesn't use standard API calls at all. Of course, as with every solution, this approach has both advantages and disadvantages. In this paper we will look at such shellcode and also introduce some example usage. IA-32 assembly knowledge is definitely required to fully understand this article.

All shellcode here has been tested on Windows XP SP1. Note that there are variations in the approach depending on the operating system and service pack level, so this will be discussed further as we progress.

Some background

Windows NT-based systems (NT/2000/XP/2003 and beyond) were designed to handle many subsystems, each having its own individual environment. For example, one of NT subsystems is Win32 (for normal Windows applications), another example would be POSIX (Unix) or OS/2. What does it mean? It means that Windows NT could actually run (of course with proper os add-ons) OS/2 and support most of it features. So what changes were made as the OS was developed? To support all of these potential subsystems, Microsoft made unified set of APIs which are called wrappers of each subsystem. In short, all subsystems have all the needed libraries for them to work. For example Win32 apps call the Win32 Subsystem APIs, which in fact call NT APIs (native APIs, or just natives). Natives don't require any subsystem to run.

From native API calls to syscalls

Is this theory true, that shellcode can be written without any standard API calls? Well, for some APIs it is for some it isn't. There are many APIs that do their job without calling native NT APIs and so on. To prove this, let's look at the GetCommandLineA API exported from KERNEL32.DLL.

.text:77E7E358 ; --------------- S U B R O U T I N E -------------------------
.text:77E7E358
.text:77E7E358
.text:77E7E358 ; LPSTR GetCommandLineA(void)
.text:77E7E358 public GetCommandLineA
.text:77E7E358 GetCommandLineA proc near
.text:77E7E358                 mov eax, dword_77ED7614
.text:77E7E35D                 retn
.text:77E7E35D GetCommandLineA endp

This API routine doesn't use any arbitary calls. The only thing it does is the return the pointer to the program command line. But let's now discuss an example that is in line with our theory. What follows is part of the TerminateProcess API's disassembly.

.text:77E616B8 ; BOOL __stdcall TerminateProcess(HANDLE hProcess,UINT uExitCode)
.text:77E616B8 public TerminateProcess
.text:77E616B8 TerminateProcess proc near           ; CODE XREF: ExitProcess+12 j
.text:77E616B8                                      ; sub_77EC3509+DA p
.text:77E616B8
.text:77E616B8 hProcess       =        dword ptr 4
.text:77E616B8 uExitCode      =        dword ptr 8
.text:77E616B8
.text:77E616B8                  cmp [esp+hProcess], 0
.text:77E616BD                  jz short loc_77E616D7
.text:77E616BF                  push [esp+uExitCode]       ; 1st param: Exit code
.text:77E616C3                  push [esp+4+hProcess]      ; 2nd param: Handle of process
.text:77E616C7                  call ds:NtTerminateProcess ; NTDLL!NtTerminateProcess

As you can see, the TerminateProcess API passes arguments and then executes NtTerminateProcess, exported by NTDLL.DLL. The NTDLL.DLL is the native API. In other words, the function which name starts with 'Nt' is called the native API (some of them are also ZwAPIs - just look what exports from the NTDLL library). Let's now look at NtTerminateProcess.

.text:77F5C448 public ZwTerminateProcess
.text:77F5C448 ZwTerminateProcess proc near      ; CODE XREF: sub_77F68F09+D1 p
.text:77F5C448                                   ; RtlAssert2+B6 p
.text:77F5C448 mov eax, 101h                     ; syscall number: NtTerminateProcess
.text:77F5C44D mov edx, 7FFE0300h                ; EDX = 7FFE0300h
.text:77F5C452 call edx                          ; call 7FFE0300h
.text:77F5C454 retn 8
.text:77F5C454 ZwTerminateProcess endp

This native API infact only puts the number of the syscall to eax and calls memory at 7FFE0300h, which is:

7FFE0300      8BD4    MOV EDX,ESP
7FFE0302      0F34    SYSENTER
7FFE0304      C3      RETN

And that shows how the story goes; EDX is now user stack pointer, EAX is the system call to execute. The SYSENTER instruction executes a fast call to a level 0 system routine, which does rest of the job.

Article continued on Page 2 



SecurityFocus accepts Infocus article submissions from members of the security community. Articles are published based on outstanding merit and level of technical detail. Full submission guidelines can be found at http://www.securityfocus.com/static/submissions.html.
    (page 1 of 3 ) next 
Comments Mode:







 

Privacy Statement
Copyright 2005, SecurityFocus