Flag: Tornado! Hurricane!

Blogs >> AlexIonescu's Blog

Created: Sunday, May 21 2006 00:06.46 CDT Modified: Sunday, May 21 2006 00:08.00 CDT
Printer Friendly ...
Native Apps: Writing, Building, Testing. Part I: Writing
Author: AlexIonescu # Views: 4531

Today's entry will introduce you to NT Applications which are called "Native", or executing in "native-mode". Without delving into a deep history of NT OS/2 (as it was originally called), NT was developed to support a variety of subsystems (wrappers) which could execute code from various platforms, including, but not limited to, POSIX, OS/2 and Win32. To manage this, the NT Kernel exports a rich set of APIs called the Native API, and subsystem servers wrap their specific APIs around them. For example, CreateFile and fopen both map to NtCreateFile.

So what subsystem does the subsystem manager run in? To avoid a chicken-and-egg problem, NT also supports the so-called native application, which is subsystem independent. Now, all subsystem applications require to register with their subsystem server. Evidently, kernel32 does this for Win32 applications, and it registers with CSRSS, which is the Win32 subsystem server. CSRSS then talks to SMSS, which is the subsystem manager. Therefore, a native app, among a thousand other APIs that are unavailable, also can't use a DLL as basic as kernel32. User32, gdi32 are also out of the question, and, by definition, so is any DLL that depends on those 3. In fact, the loader won't even allow loading of most Win32 DLLs, since their entrypoints won't load. Therefore, a native app is limited to all but one DLL: ntdll.dll, and all the Native and Runtime functions it provides. But hey, if everything in Win32 ultimately calls it (except for GUI stuff), it's good enough for you, right?

Now that you know what a Native Application is, let's talk about some of the advantages:

1) Memory usage and size. Because native applications don't start loading 90 DLLs in memory just because you want to read the registry, memory usage is extremly low, as well as the overal disk size, since all the import tables and other Win32 cruft is missing. You can also (and are recommended to) use an alignment of 32-bytes, which gives you even smaller sizes (at the expense of memory protection).
2) Speed. Native APIs are faster (sometimes much faster) then their Win32 counterparts. Notwithstanding the actual time spent wrapping a Win32 API, many of these include hacks, compatibility options and other lines of code before actually getting to the native call. If you know what you want and want it fast, native is the way to go. Also, because all those 90 DLLs don't have to load, and because kernel32 doesn't need to do LPC registration with CSRSS and then SMSS, startup is immediate and fast.
3) Familiarity and features. As we'll see, Native Applications don't have to have weird entrypoints or painful hacks to do something as simple as reading the command line. In fact, as I'll show later, Native Applications start with the same _main function as a console application, receiving command line arguments and count, as well as environment variables in a simple char* [] array, just like a typical win32 console application would. Features like buffer overflow protection (/GS), Safe SEH (/SAFESEH), hotpatching (/HOTPATCH) and all other features are available, if the application is built properly (again, as I'll show).
4) Richness. The Native API is extremly rich and provides features and functionality beyond what you could have ever achieved in Win32. It's not that Win32 APIs could've done the same in a harder or more complicated way, it's that they simply can't do some operations. Want a simple example? There's no way to remotely inject a section into a process, because MapViewOfFileEx doesn't take a process handle. The Native API does.
5) Security through obsecurity. Certaintly not the kind of thing to advocate for _real_ security, but going native does give some add-on bonuses: people are much less familiar with Native APIs and will have a much harder time figuring out what your code is doing, and, more importantly, it is impossible to debug native applications using a user-mode debugger. Only SoftICE and WinDBG with a remote kernel-connection can do it, which puts lame script kiddies at bay. Again, this is not to say "native code is undebuggable and safe", but it's just more obfuscated and hard to get to.
6) Porting to kernel-mode. Because it only uses Native APIs, which are also available in kernel-mode, a simple native application can easily be ported to a driver with very few changes, isntead of a complete rewrite that a Win32 application would require.
7) Running in subsystem-independent environments. Again, because your native application won't depend on a subsystem, it can run in environments where your applications would normally never run. For example, autochk.exe runs before any subsystem is loaded and is responsible for showing the "press any key to scan your hard disks" message, and scanning your hard disks for errors. Running in this environment allows you to display messages on the boot screen, perform profiling, and a myriad of other advanced features.
8) Consistency. Unlike Win32 APIs which have a normal version, an "Ex" version, and sometimes an "ExWithSomethingElse" version, as well as return either 0, 1, -1 or some random value for success, and either set or forget to use SetLastError when returning an error (if they do at all), Native APIs all follow the same standards. All return NTSTATUS (except when explicitly marked to return a value), which is a descriptive mask and error-code defining the nature of the failure. There are also no "Ex" versions to worry about.

Now let's take a look at some of the disadvantages:
1) Non-trivial learning curve for pure Win32 developers. If you've never used Native API before or done NT kernel-drivers, you will have to learn a whole new set of APIs. Sure, the names are similar, but sometimes the flags are entirely different, and the way values are returned, as well as the object-oriented nature of Native APIs can be confusing at first.
2) Lack of documentation. Although Rtl* functions are pretty well documented, hundreds of them still arne't, including most of the low-level system ones dealing with PE loading, for example. As for the Nt/Zw* functions, apart from what is documented in the DDK/IFS/WDK, you're on your own. Apart from actual coding documentation, there is also no definitive guide on how to properly build one (well, until this blog, that is).
3) Lack of portability. Native Appplications will not work on 9x/Me. Don't ask, don't try, forget about it.
4) Lack of commercial possilbities. As nice as Native Applications are, DO NOT USE NATIVE APIS OR WRITE NATIVE APPLICATIONS IN A COMMERCIAL PRODUCT. Native APIs *CAN* change. Although they generally haven't, this is a possibility that should not be taken lightly. Do NOT gamble with your customers' money.
5) No GUIs or defined input/output methods. There is no "native console". You cannot simply request input from the user and somehow display it on the screen, because methods to do so are not available (the Console API is Win32).

While some of these issues may seem to "suck", there are thankfully solutions, which we will explore in the upcoming parts. 1 is something you will have to work at, while 3/4 can be easily dismissed for hobby/explorative NT coding. As for #2 and #5, we'll attempt to solve this over the course of these posts.

Screenshot of TinyKRNL's Native CLI. Supports keyboard and screen output (as you can see), as well as full directory browsing (a-la-cmd.exe), executing other native applications, displaying the device tree (A command-line device manager) and installing/removing devices, listing system information, listing the current running processes, listing current loaded drivers, and soon, MP3 playing.
http://www.tinykrnl.org/dev_te8.jpg


Blog Comments
Genius Posted: Wednesday, June 23 2010 07:35.25 CDT
Good exploration .



Add New Comment
Comment:









There are 31,314 total registered users.


Recently Created Topics
[help] Unpacking VMP...
Mar/12
Reverse Engineering ...
Jul/06
hi!
Jul/01
let 'IDAPython' impo...
Sep/24
set 'IDAPython' as t...
Sep/24
GuessType return une...
Sep/20
About retrieving the...
Sep/07
How to find specific...
Aug/15
How to get data depe...
Jul/07
Identify RVA data in...
May/06


Recent Forum Posts
Finding the procedur...
rolEYder
Question about debbu...
rolEYder
Identify RVA data in...
sohlow
let 'IDAPython' impo...
sohlow
How to find specific...
hackgreti
Problem with ollydbg
sh3dow
How can I write olly...
sh3dow
New LoadMAP plugin v...
mefisto...
Intel pin in loaded ...
djnemo
OOP_RE tool available?
Bl4ckm4n


Recent Blog Entries
halsten
Mar/14
Breaking IonCUBE VM

oleavr
Oct/24
Anatomy of a code tracer

hasherezade
Sep/24
IAT Patcher - new tool for ...

oleavr
Aug/27
CryptoShark: code tracer ba...

oleavr
Jun/25
Build a debugger in 5 minutes

More ...


Recent Blog Comments
nieo on:
Mar/22
IAT Patcher - new tool for ...

djnemo on:
Nov/17
Kernel debugger vs user mod...

acel on:
Nov/14
Kernel debugger vs user mod...

pedram on:
Dec/21
frida.github.io: scriptable...

capadleman on:
Jun/19
Using NtCreateThreadEx for ...

More ...


Imagery
SoySauce Blueprint
Jun 6, 2008

[+] expand

View Gallery (11) / Submit