Author: Fernando

  • Prog2Svc – A jobless service

    Nowadays, although contradictory it may seem, creating a service does not require much work. A few clicks on a Visual Studio 2005 Wizard and just it, we will have an application capable of providing ATL COM interfaces and which is indeed a Windows service. In this post, I will talk about a little tool that I’m offering as a toast to those who have the patience to read this Blog.

    At the first company I worked for as a programmer, about 11 years ago, I was responsible for maintaining Provectus’s software’s data collector communication network. At first, an MFC program was responsible for interacting with the driver that controls the SS140 board, which was the interface that the PC had to be part of this data collector network. Once the program had stabilized, we modified the software to make it a Windows service.

    But what is a Service?

    A service is an executable module, which is registered to be executed on the system even if nobody logs on to Windows. Today, many applications and Windows components are implemented as services. A service is not only a common executable registered to get started automatically. A service must provide an interface CallBack routines for the system, in order to respond to commands that start, stop and stay of execution. This interface is not a COM interface as some of you might have guessed. Take a look at the StartServiceCtrlDispatcher function to get an idea of the interface type I am referring to. This is just one of the necessary functions to build a service. Take a walk by reference for details on how to implement a service from the scratch. Services typically run on system account, but it may optionally use a given user account. More details about services, on the MSDN site.

    Back to the ’90s, then we needed to make the Supervisor, one of our major programs at Provectus work as a service. Supervisor was a giant program built in Visual Basic 4.0. It was responsible for receiving commands from collector network, and regarding to them, execute Stored Procedures in SQL Server. Visual Basic 4.0 didn’t implement the AddressOf operator, which appeared only in version 5.0. This operator can be used to obtain the pointer to functions written in VB. This allowed such programs registering CallBack routines in the system. Anyway, with this operator, a few pounds of patience and a gun over your head, you could build a service in Visual Basic. We thought about the possibility of rewriting the entire Supervisor in C, so we could then turn it into a service. But luckily someone had an outbreak of sanity and said:

    “Why do not you write an empty service that simply calls the Supervisor?”

    Yeah, this really works perfectly! This need of having a program behaving as a service is more common than you think, especially when we are talking about business environments. It didn’t take long to some tools that made this possible appear, but nothing prevents me from having my own version.

    Prog2Svc program is a service that does right that. Running this program without any parameters, you will receive the message below, which tells what the possible parameters are to be used.

    Thus, to register the Windows calculator as a service, we use the following command line. Remember that this is an operation that requires administrative rights, so in the case of Windows Vista, this command should be run from a Command Prompt that was started as an administrator.

    Prog2Svc -add Calculadora c:\Windows\System32\calc.exe

    After the message of success has been shown, you can already see your new service through the Windows Service Manager. To access the service manager, type “services.msc” without the quotes in the Run… window.

    You can start your service either using service manager or using the good old command “net start calculadora” in the Run… window.

    When we start the service, we have no sign that it is really working. That’s because calc.exe was executed on another Desktop, but we can confirm its execution using Process Explorer.

    The additional -interactive parameter can make your new service interaction with the Desktop. Note: Windows Vista deserves special attention here. The -auto parameter sets the service automatic to start when the system is turned on. Finally, the –silent parameter makes the installation being silently done. That is, no success or error message will be displayed. Note: In this case, the success or failure can be verified by the Prog2Svc exit code. Another possibility is the use of environment variables in application path that will run. See this example more completely.

    Prog2Svc -add -silent -auto BlocoDeNotas %SystemRoot%\System32\notepad.exe

    Removing the service is very simple. See example below. Note that to remove services, we can also count on the silent mode.

    Prog2Svc -remove Calculadora
    Prog2Svc -remove -silent BlocoDeNotas

    How does pseudo-service finishes?

    When we ask to stop the service, Prog2Svc program receives a notification via CallBack routine. In that time, we could do a flying kick in the process’s chest, but this wouldn’t be good manners. A routine identifies the process created main window and sends a WM_CLOSE message to this window. After that, 30 seconds are expected for the process to have the opportunity to finish their tasks and deallocate system resources. If this time expires and the process is still running, well, it’s like my friend Thiago always says: “Only violence builds” and the process will be dropped out via TerminateProcess().

    If you cannot still imagine how this tool might be useful, think you could create a service that runs the Command Prompt, and thus, you will have a shell running on system account. This would help you to test and find out what you could do with this account privilege.

    Prog2Svc -add -interactive SysCmd %SystemRoot%\System32\cmd.exe

    To install this program, just put a copy of this executable at the System32 directory. Technically, you could put it into any directory, but remember that the folder where it will be should be accessible by a system account. So, do not put it into directories like “My Documents” or any other personal folder.

    As we know that the Internet is not the safest place to get an executable, make sure the program you are downloading has a valid signature.

    Have fun!

    • Version: 1.0.1.0
    • Windows: 2000, XP, 2003, Vista

    Prog2Svc.exe – x86 (58.7 KB)
    Prog2Svc.exe – x64 (59.2 KB)
    Prog2Svc.exe – IA64 (113 KB)

  • Step into Kernel (SoftIce)

    Finally back from vacation. It has been nearly six years that I did not take vacations. Traveling, visiting new places and just relaxing were my main tasks during these last 20 days. Back to work, I’ve just arrived at the company and I was amazed by it. I could not believe they sent that old one away. We exchanged glances and obviously I got butterflies in my stomach. I got close enough to be able to smell it. I looked up and down. Simply perfect and it was an injustice to leave it alone. It didn’t take long and it was under my control. I had to prove everything it had to offer. After all, there were so many choices: Coffee, cappuccino, chocolate, tea with or without sugar. But it was all an illusion. “Oh my… that’s was a horrible coffee.” My friends, appearances can be deceiving. How can so beautiful machine make so bad coffee? I confess I miss the old machine. I didn’t mean that coffee was not so good, because the coffee was really horrible! Now I’m looking for alternative ways to keep my addiction. Perhaps there are caffeine patches to sell out there.

    Don’t worry, this will no longer be an “Off Topic” post about changing coffee machines and the impact caused by them. In this post, which I had started last year and have just finished it now, I’ll take the steps needed to use SoftICE system debugger.

    I still was new in SCUA and I was developing a GINA for our security product. For those who do not know, Gina is one small screen that appears during the Logon in NT platform. GINA is a DLL that is loaded by winlogon.exe process, which has the function of making the user’s interface to perform the login in the computer. The Msgina.dll GINA is the original one, but we can build our own GINA to provide alternative ways of authentication. A practical example of this is the product True Finger sold by SCUA. This product changes the system’s GINA, so that, with a biometric sensor help, it makes the system ask for the user’s fingerprint to logon the system. Debug GINA requires a few atypical steps, since to test it is necessary to do Logon, Logoff and things like that. You can also debug it using the Visual Studio Remote Debug, but at that time, debugging GINA was the need I had to learn how to use SoftICE.

    There were two development teams, one for Kernel drivers and the other for applications. I still worked on application staff when in a meeting area, the team introduced me to SoftICE as an alternative to solve the problems about Kernel Debug I was facing. I was using techniques such as log files and MessageBox to debug GINA. You can imagine the MessageBox with the typical messages as “I called the X routine”, “Returning from Y routine.” After I learned how to use SoftICE, it solved many things for me. Specially since other Ginas had to be developed and as, the time passed by, I started to develop kernel drivers.

    Most of the application team had a panicked about using SoftICE. A situation very similar to that described in my previous post. They said: “Oh no, using SoftICE is too complicated. I will continue with the MessageBox. If I cannot solve this, then I will use a Kernel Debugger.” I think it was just about getting used to it, SoftICE is not a rocket science and nor difficult to use. I found it amusing when one part of the team was caught trying to solve a particular problem, that kind of strange bug that nobody could find. I went around and asked: “Why don’t you just use SoftICE?”, “No, no, I guess it is not necessary.” they said. Later I also was called to help tracing the problem, and in most of the time I could, I’d picked up the problem that they’d chased for days in half an hour of Debug. I’m not saying I’m super Debug genius, or that they were technically incompetent. I’m saying that it is only a matter of using the right tool. You could dig a tunnel with a teaspoon, but with a shovel things would be much easier.

    SoftICE is part of a development package called Driver Studio, which was sold by Compuware. For those who still do not know, Compuware has discontinued SoftICE and we cannot count on a version of this tool for Windows Vista. With SoftICE is possible to debug the kernel using only one machine, but the product still has the resources to do remote debug via serial ports or network adapters. Thus, they are also adopted the names Host for the machine that does the Debug and Target for the machine that will suffer the Debug (Similar to WinDbg). Here we will adopt the Host name for identifying the machine where we have the compiler and the installation type Host SoftICE. We will not do any remote debug on this post.

    Very briefly, we can say that SoftICE works as it follows. At the Host machine, it is necessary to create a symbol file known as NMS. This file is copied along with the driver to be tested to the Target machine. In it, we load the symbols and start debugging the driver. We will describe these steps in more details next.

    Installing the Host Machine

    Installing SoftICE on the development machine is necessary for us to generate the NMS file. Don’t worry; you will not test your driver on your development machine. At least not while you’re sane. During the setup process, you will pass through the typical setup screens until you reach the screen shown above where you select installation type you want. Because we use only installation Host portion, select that option and skip to the next screen. Select only the option “SoftICE Host Components”, so that it appears on screen as below. The remainder of this process is next, next…

    Installing the Target Machine

    We will use the test machine in a way that it is not necessary to have two machines to do the debug, and so we will explore this feature that is usually used. To do this, select the “Full Instalation” in the first screen, then select only “SoftICE Host Components” items and “SoftICE Target Components” as it is shown below.

    In this case, at the end of the register and file copy process, we will have to set some debugger properties. The first group of settings refers to initialization. We will select the Manual startup at this moment. All these settings can be changed after the product is installed. The setup screen should be as shown below.

    The next group will be about general settings. In this item, we will change the field “Initialization” to stay with the configuration shown below. These are commands that are executed when the debugger is started. Each command is separated by a semicolon. These commands will make the following changes:

    • LINES 60; Change the total amount of lines to 60
    • WC 30; Change code window size to 30 lines
    • WL 10; Change local variable window size to 10 lines
    • X; And finally, the command that starts the system normal execution

    The lack of “X” command will cause the system to become paralyzed at debugger startup time. This gives us the opportunity to put initial breakpoints and later we will be able to continue with the system execution by pressing F5, which is the hot-key for “X” command.

    Now let’s set the video configuration. Right now you can ask me: “What do you mean by video configuration? Doesn’t Windows implement an abstraction layer called GDI?”

    SoftICE is a system Kernel debugger. GDI is part of the system. How would you debug a video driver if the debugger itself utilizes this driver? The debugger should influence the debugged system as little as possible. It is for this reason that WinDbg need a serial cable and another whole machine to make the Kernel Debug possible. Similarly, SoftICE, once loaded, cannot use any system resource. This includes video drivers, disk, keyboard, mouse and so on. For the SoftICE being able to have a place in the video while debugging the system, it accesses the video memory directly and draws manually its entire interface. That’s why we have to configure the video.

    This configuration can be chosen between two main options. The first is the “Universal Video Driver”, where the interface will appear in a window. This “window” is actually the result of writing in video memory that gives the impression of a window. This is not the type of window you’re used to seeing and drag with the mouse or even suffer the action of ALT + TAB. Remember, when SoftICE displays its user interface, the whole system is frozen. The other option is “Full screen”, where SoftICE switches the video to text mode to display its interface.

    If you are installing SoftICE on a virtual machine, some steps are required:

    • Do not install tools such as video acceleration like VmTools.
    • Use the standard VGA driver in Windows and configure it so that, it is 640×480 with 16 colors. (Disgusting but necessary)
    • Select the “Full Screen” option in SoftICE.

    If these steps are not followed, the machine will freeze when asked, but the debugger screen will not appear. Assuming that we are installing on a real machine, select the video option as shown below.

    The remaining is next, next…

    Generating the NMS File

    On the Host machine, after compiling your driver (if you still don’t know how to do it, read this other post), you must now run the application “SoftICE Symbol Loader” that was already installed. This application does the symbol translation and generates the NMS file. Select Open… from the File menu and point out the driver you will debug. Once opened, the program must place the driver loaded name at the window title. I have numbered the three buttons you need for this operation.

    • Make sure that the second button is pressed. This will make any driver source code be appended to the resulting NMS.
    • Also make sure that the “3” button is released. This will prevent the program for asking for sources that it cannot find.
    • Click on “1” button that will do the symbol translation and the program will generate NMS file at the local directory.

    Starting SoftICE

    After installing your driver as usual in the Target machine, we will be ready to start the Debug of our driver. Remember that both our sample driver and SoftICE are configured to start manually. To start SoftICE, you can click the “Start SoftICE” icon that was installed in your Start menu or simply run the command “net start ntice” in the “Run…” window. To make sure that the debugger has loaded, press CTRL + D so that the system freezes and the screen is shown as the one below.

    No, this is not a CRASH DUMP of your video card that has just exploded. Gentlemen, I am pleased to introduce you the SoftICE. Now can you understand the application staff panic? Don’t worry, it’s ugly but it doesn’t bite you. Pressing F5, the system returns to normal execution.

    Now we have to load the NMS file into the debugger. This is easily done simply by double-clicking the NMA file. This file can be in any directory on the machine. The only time that this file is used is when you load it in the debugger. To verify whether the file was successfully loaded by SoftICE, use the “table” command that lists all loaded symbol tables. Several tables can be loaded simultaneously, but only one is active at a time. The “file *” command lists all files of a given table. To open a specific file, enter the file name in front of the command. See example below.

    With the file already opened in the code window, press ALT + C to put the cursor into the source code. If this key sequence is not working, press ESC and then ALT + C. Note that you can only walk with the cursor up and down. Attempts to move the cursor sideways causes the command window to gain focus again. Place the cursor on the line you want to insert the breakpoint and press F9. At this time, the line was highlighted as shown in the picture below.

    Now let’s press F5 to let the system return to normal operation. At the moment the driver starts, our breakpoint will interrupt this action and the SoftICE interface will be displayed. The highlighted line shows what the next instruction to be executed. Pressing ALT + L, the local variables window gains focus. You can navigate among the variables by moving the cursor up and down. Press ENTER key on the structures that begin with “+”, so that they are expanded. The image below shows register window and then, the local variable window.

    I will leave a small table of commands here, but the full reference is in “SoftICE Command Reference” PDF file.

    • F5 : Run
    • F9 : Breakpoint
    • F8 : Step into
    • F10 : Step over
    • F12 : Step out
    • F7 : Run to cursor
    • WL : Local variable window
    • WW : Watch window
    • WD : Memory window
    • F3 : Swap among C source/Assembly/Mixed

    Obviously there are numerous details and technical use, but let’s leave that to the documentations that coming with the product.

    Wow, what a long post! You thought it would be easy, didn’t you? Until the next time …

  • Wow!! DDKBuild out of Vista

    About a year ago, I was reading the Windows Internals when I came in the chapter about Wow64, so I thought to myself: “Oh my… That’s a sort of thing that will bring us some issues.”

    This week I’ve installed a Vista x64 copy on my computer to do some tests and I attempted to anticipate the problems I would have when it would be released. I almost had no problems. Actually, I had to configure some shortcuts to certain programs with compatibility mode set to Windows XP SP2. This is because these programs showed the message: “This program is not compatible with Windows 6.0”

    After installing the Visual Studio 2005, DDK do Windows 2003 Server and DDKBuild, everything was working fine. A project was created, compiled and debugged in Visual Studio without problems. I also compiled a DDK example from the command line and also everything was OK. But at the time I was compiling one of the examples that I’ve already made available at the site using DDKBuild, I got the following error message:

    'ddkbuild' is not recognized as an internal or external command

    Executing the DDKBuild in a command prompt, it worked fine, but same error was always showing at the Visual Studio. After pooling out some hair, I tried to open the file DDKBuild.cmd from Visual Studio, that is, by selecting Open… from File menu and so on. When I got into the System32 directory, I saw that the file I was looking for was not there as it should be, at least, not for Visual Studio.

    It took some time, but the penny dropped. Visual Studio is a 32 bit process and fell in the Wow64 (Windows-on-Windows 64) rules for File System redirection. For those who do not know, to maintain compatibility with the past, 64-bit platforms still use the directory C: \Windows\System32 folder to put the system DLLs, even though they were 64-bits.

    But what happens with 32-bit system DLLs? Thirty-two bit processes still need to load these DLLs. When a 32-bit process tries to access the C:\Windows\System32 directory, the access is redirected by Wow64 to C:\Windows\SysWow64 (C:\Windows\System32\SysWow64 For Windows XP x64). Accesses to the registry are also reflected from 32 bits to 64 bits and vice versa. Please, refer to the MSDN site for Wow64 details.

    Once the penny has dropped, it is ridiculous to solve the problem. Simply put a copy of DDKBuild.cmd in the C:\Windows\SysWow64 and everyone will live happily ever after.

  • Walter Oney for Managers

    The fact of writing a little unusual program has some consequences. Some of your friends at work, those ones who sometimes sit beside you, do not understand what you are doing (and vice versa). Others are seen whispering: “Look out! Is that guy the one who programs drivers.” This difficulty other people have to understand what we write, ends up also affecting the managers, directors and so on. Not that they were guilty of this. After all, if they were interested in the technical area at this point, probably they would not be managers, directors or whatever they are. This is not a rule, but at least it worked in companies where I have worked for; the minority of my superiors understood those problem complexities that ended up delaying a product release.

    The worst case is when your manager thinks it’s simple to solve things. After all, when he programmed in COBOL, there was no problem he could not solve and you would probably be acting as a lazy guy or simply as a superstar for being able to solve blue screen problems. I particularly think it is beautiful when they ask: “But didn’t you already solve this blue screen problem?”, as there was only one problem what would result in a blue screen.

    Well, so I think the recognized authority’s opinion on this could have some influence over those people’s opinions. In the first chapter of his book Programming The Microsoft Windows Driver Model (2nd Edition), Walter Oney gives some tips on how a company could consider driver development to obtain results closer to the expected. I have separated some sections that it follows below.

    “The sad truth is that WDM driver programming is pretty hard, and only experienced (and expensive!) programmers are capable of doing it well.”

    “Driver programming should start as soon as there is a reasonably firm specification for how the hardware will work. You should expect to modify the specification in light of unpleasant discoveries during driver development…”

    “You should also expect driver programming to last longer and cost more that you initially imagine. All software is subject to time and cost overruns. Additional overruns in this kind of programming stem from communication difficulties between the hardware and software people, from ambiguity in specifications and in the DDK documentation…”

    “Pay attention early on to how end users will install the driver software. Most vendors of add-on hardware prefer to ship a custom installation program on a CD-ROM, and writting the installer is a lengthy process that can consume en experienced programmer for several weeks…”

    “Your driver executable will also probably include the text of messages in a special multilingual message resource, and it would be a good idea to have a trained writer compose that text. (I’m not saying your driver developer can’t do this, but he or she may not be the best choice.)”

    “Finally, don’t treat your drivers as unimportant details. Having a good driver with a smooth installation is at least as important as the exterior appearance of the product… So a myopic decision to short-fund driver development could easily have a dramatic, negative effect on your bottom line for years to come. This advice is especially important for hardware manufacturers in developing countries, where managers have a tendency to look for every possible way to cut costs. I suggest that driver development is one place where cost-based decision making is inappropriate.”

    Perhaps they will never read this, but for sure it will help us take a deep breath and continue programming. Now, you back to work because you are not getting paid for surfing the Internet! (This is also great) … 😀

  • Step into Kernel (Serial)

    I earned my first computer when I was 13 years-old, but seven years later, when I started my internship, I discovered that it was possible to debug programs that I used to write. Until then, my debug methods were always things like printing the variable value on screen. All right, in that time I didn’t use to develop complex programs enough to be stuck; over the time, I think I got used to working without the luxury as break-points and so on.

    When I was introduced to a debugger, I even paid attention to it. I thought to myself: I can just put a printf and I’ll be OK. I don’t need all this stuff. At that time, we used the CodeView, a 16-bit debugger that runs on DOS which is displayed on the picture below.

    It didn’t take long for me starting to depend on the debugger doing the simplest things, like brushing my teeth, for example. In fact, some situations, such as writing code for data collectors, writing firmware for hardware that has no display, situations in which we could not count on a serial port to see what was happening with the software, and the unforgettable situation where I had placed an oscilloscope on a particular processor pin to catch our software life signs, so, situations that we would give an arm to have a simple break-point made me realize that the debugger is really necessary.

    The funny thing is that nowadays, in college, most students in my class don’t know how to debug software. I’ve tried to explain to my friends the tremendous advantage of using a debugger, but they end up having the same reaction I had years ago: “No way, Fernando, this is too complicated. Just by looking at the source code we end up finding the mistake”. So, that’s fine for me.

    Well, we’re here to debug or to talk? Let us debug the driver generated by the traditional post Getting Started. This time we’ll do according to the tradition. We will need two machines, a Null Modem serial cable and last but not least, a copy of WinDbg. No, not worth reading this sentence again, you didn’t take it wrongly; you’ll really need two machines. I don’t know why some people have a certain resistance to believe in this. Well, I think we have overcome that phase and we can continue with the post.

    If you do not have a copy of WinDbg, you can download it for free from the Windows Debugging Tools page at Microsoft site.

    Let’s take this picture borrowed from the Windbg Help, which shows how we should set computers to do Kernel debug.

    The machine named HOST is where WinDbg will run. This machine is, in most cases, the machine where the driver was developed. Let’s assume that this is the machine where the driver was developed and defer the details about how to set the symbol and source directory to another post. The machine named TARGET is where our driver is loaded by the system. The TARGET machine’s operating system don’t necessarily need to be Checked Build nor it is necessary to install any additional kit to the operating system. All you need is your driver and a serial port. All of the Windows NT platform (Windows NT, Windows 2000, Windows XP, Windows 2003 Server and Windows Vista) already bring their native debugger since its installation. Actually, this is a great feature in the use of WinDbg. Imagine that kind of problem that manifests itself on the client machine. You will not want to install anything aggressive or even that will change the scenario that would make the problem not manifest itself anymore. Believe me, this is not so rare as it seems to be. In these cases, simply enable the Debug mode on the TAGET computer and we’re done.

    To enable the Debug mode in the TARGET machine, we need to edit some initialization parameters that are in the Boot.ini file located in the system root folder. This file has its attributes as system file, hidden file and also read-only. You may need to configure Windows Explorer to view these files. Using Windows Explorer, go to the root folder, remove the read-only property from the Boot.ini file, then open this file using a text editor like Notepad, for example. The contents of this file is similar to that shown below.

    At Operating Systems section you will need to duplicate the referenced system line you will want to debug. Add to its end the /debugport=com1 /baudrate=115200 parameters that will configure the Debug mode. The first parameter selects the COM port being used, while the second selects communication speed. The serial protocol is not the fastest communication way between machines HOST and TARGET and in some cases is annoying having to wait for interactions between WinDbg and debugee system. There are other media that can be used if your computer does not have an available serial port or if you wish more speed and comfort during the Debug. See more details in the post Serial Killers.

    The final result of our Boot.ini file should be something like shown below. I’ll skip the lines beginning that describe the operating system for better visualization putting “…” in their places.

    [boot loader]
    timeout=30
    default=multi(0)disk(0)rdisk(0)partition(2)\WINDOWS
    [operating systems]
    multi(0)... /NoExecute=OptIn
    multi(0)... /NoExecute=OptIn /debugport=com1 /baudrate=115200

    After making these changes, you can save the file and restore the original file attributes on it. In Windows XP and Windows 2003, the same described steps above could be done with the help of a tool named Bootcfg.exe. In Windows Vista, the process is quite different and I will describe it in a future post.

    Back on the HOST machine, start WinDbg and select Kernel Debug… from the File menu. You should see a window that sets the communication way. Make it so in a compatible way with what was set in the Boot.ini on the TARGET machine. In this case, we are using COM1 serial port and baud rate of 115200. Clicking on OK will make WinDbg opening the serial port on the HOST machine and it will wait until the TARGET machine be ready. At this point, we get the following messages in WinDbg command window .

    While the HOST machine waits, make sure your driver is installed on the TARGET machine and restart it. After that, when system is starting, the system loader is displaying the options found in the Boot.ini edited by you. Select the option which appears [debugger enabled] as shown below.

    After selecting this option, the machines HOST and TARGET should connect each other and the Command window would show a text similar to that shown below.

    Microsoft (R) Windows Debugger  Version 6.6.0007.5
    Copyright (c) Microsoft Corporation. All rights reserved.
     
    Opened \\.\com1
    Waiting to reconnect...
    Connected to Windows XP 2600 x86 compatible target, ptr64 FALSE
    Kernel Debugger connection established.
    Symbol search path is: *** Invalid ***
    ****************************************************************************
    * Symbol loading may be unreliable without a symbol search path.           *
    * Use .symfix to have the debugger choose a symbol path.                   *
    * After setting your symbol path, use .reload to refresh symbol locations. *
    ****************************************************************************
    Executable search path is:
    *********************************************************************
    * Symbols can not be loaded because symbol path is not initialized. *
    *                                                                   *
    * The Symbol Path can be set by:                                    *
    *   using the _NT_SYMBOL_PATH environment variable.                 *
    *   using the -y  argument when starting the debugger. *
    *   using .sympath and .sympath+                                    *
    *********************************************************************
    *** ERROR: Symbol file could not be found.  Defaulted to export symbols for
    ntkrnlpa.exe -
    Windows XP Kernel Version 2600 UP Free x86 compatible
    Built by: 2600.xpsp_sp2_gdr.050301-1519
    Kernel base = 0x804d7000 PsLoadedModuleList = 0x805531a0
     

    Well, so far we know that the machines are connected. Pressing Ctrl + Break in Windbg, we will make the system freeze in the TARGET machine and the control is passed to the debugger. The debugger is ready to receive your commands when you get a command prompt KD indicated by the letters at Command window bottom left.

    Just to make a simple test, type “lm” command and hit enter. This command lists the modules loaded by the system. Note that the Useless driver is not on this list yet. This happens because the driver instance is configured to have its execution started manually, so, the driver has not yet been loaded by the system. Then, select the item Open Source File… from File menu and open Useless.c file. Click on the DriverEntry function name and hit F9. Although there is no visible sign, we put a break-point on this function. The fact of having no visual change is due to the fact that our module has not been loaded yet. We can be sure that the breakpoint is installed listing the breakpoints with the “bl” command.

    kd> bl
     0 e f9fb3430     0001 (0001) Useless!DriverEntry

    Now we launch the “g” command that will cause the system to return to its normal execution.

    Once the system is loaded, we will start the driver through the “net start Useless” command . When the driver starts, the DriverEntry entry point runs and consequently, we have its execution stopped at our breakpoint. The TARGET machine will freeze while the debugger has control over the system. Note that now our module is loaded, the breakpoints are easily identified by lines with red background color.

    Well, the first steps have already been done, the commands and details on how to debug the kernel for Windows would be outside the scope of this post. But a good tip on how to obtain tons of details about this subject is the Windows 2000 Kernel Debugging book. The book is not one of my favorites; it gives a good introduction to the subject besides talking about how to use and build Debug Extensions, but does not bring the used techniques by real Kernel Debugging ninja masters. Another excellent information source on this subject is the discussion list Windows Debugger Users List dedicated to Windbg. That’s all without forgetting the Help.

    This was an initial post about the subject, wait for future posts where I will give the steps about how to use Windbg with VMware and how to debug Windows Kernel with one machine using SoftIce (God rest his soul).

    Have fun… 😉

  • Off-topic HP 50G

    Finally, the exam period has ended. Now I can return to normal life, reintegrate into the society and why not, write posts. For those who did not know, I’m studying computer engineering at Universidade São Judas Tadeu. Despite my thirty-years-old, I’m still in the third year due to a hectic life that a programmer is suppose to have. I’m sure many of you know exactly what I’m talking about. I had to interrupt my course several times because of lack of money or overwork. Anyway, these past few weeks I was in a rush and I could not compose a decent post. So, you will have to be glad for some funny facts about my new best friend, the HP 50G.

    I usually say that a programmer is not a name of a profession, but a name of a disease.”Programmer: A person who suffers for programming”. One of the symptoms that I find most decisive for a programmer their great ability to associate different things with programming, even involuntarily. An example? Easy! When I was studying Industrial Informatics at ETE, there was a teacher who used to speak slowly, about 3 seconds among sentences. He looked like an android. I used to imagine that characteristic was due to the fact the teacher had little RAM, thus took a while to load a new sentence from the HD to be processed by the speech synthesizer. At that time, we said if we had paid attention, we could see a blinking LED in his ear during those breaks. Fortunately, it could be easily solved if there had been a second thread to put the next phrase in RAM as the current phrase was used by the main thread. I do not know what you think about it, but it seems disease for me. :-S

    Studying for Computational Numerical Calculus tests and armed with a HP 50G, it was inevitable to program it to automate some steps. The exercises in this subject consist basically of arithmetic, but they are long and full of little rules. Baing a Programming carrier since the age of 13, I have downloaded the manuals and got to work. When an HP is bought, it comes with a “Quick Start” document having 120 pages; but don’t worry, you can download the complete PDF manual having 918 pages in Portuguese.

    As it might be expected, I’ve found many sites and tutorials on the subject, even several in Portuguese. The site hpcalc.org was a major contributor. On the page about programming you can find a lot of things. And the best thing, it’s all for free.

    We can program the HP either in UserRPL or SystemRPL. Programming in SystemRPL gives us a performance gaining of almost 10 times higher than in UserRPL. However, everything in life has a price. The excerpt below was taken from one of the several PDFs I’ve found.

    Strange! I could swear I have already read something like that somewhere.

    Because I was unable to download a WinDbg version to debug my HP, I decided to program in UserRPL anyway. The language is basically composed of a sequence of keys that were pressed during normal use of the calculator, but we can still use execution blocks, repeating loops (for/while), conditional execution (if, else), sub-programs execution and many other things that I had no patience to read. It’s funny to mix things like IF and ELSE commands that do array operations as if they were as simple as adding one to one.

    HP can be programmed on itself, I mean using its own keyboard. But writing on that mini keyboard is similar to play Decathlon on Atari. It works, but you know what will end up happening. Another super uncomfortable thing is trying to understand what is wrong in your program just looking at the source code (which is not indented) on a small LCD screen. One of the facilities is a USB cable that connects the HP to your PC.

    To access the stored directories and variables in the calculator, you’ll have to download the software that makes this connection. But if you have an x64 machine (even HP), there will not be drivers available to make this connection. If this is your case, you can use a virtual machine that is running a 32-bit operating system. Wow! That really works!

    When connected, it displays a kind of “Explorer” where you can browse the folders and edit variables and programs. With a double-click on the programs, an excellent development environment called “Notepad” opens with its program. Don’t think of indenting your program. When the program is sent to HP, it takes its own indentation, which is not obviously the same as we would like to take.

    Well, at least it was interesting to learn more of this. It was really worth spending that money buying something I can program and be able to keep my addiction. But it still does not stop there. If you take a look at the quantity and variety of applications to download from hpcalc.org, you will have an idea whatelse it can do besides calculating the matrix determinant. If you’re curious, you can download a calculating emulator on your PC and make a Test Drive.

  • Kernel + Visual Studio 2005

    Driver or low-level software developer is used to build their projects on the command line, use text editors like Notepad or Norton Editor to code their drivers. It’s like my friend Thiago says: “Knife in the teeth and blood in the eyes”. Using the command TYPE | MORE to see the compilation error files shows how superior human beings we are, technology dominants who don’t under-utilize our brains, don’t need those superfluous tools like graphical interface with syntax coloring, IntelliSence or even auto-complete. We are at the top of the food chain.

    If you really believe that, then it is better you leave this post right here. Today I going to defend the use of tools that help, and much, when a driver is coded and it is needed to deal with functions with large number of parameters and endless structures.

    Using or not using the Visual Studio to generate drivers is a kind of discussion that tends to be infinite, such as the use of C++ for Kernel Mode development. On the one hand, there are those ones who argue that the environment is almost never perfectly configured to compile drivers. I’ve read posts from real authorities on the subject by talking about how many days were needed to find a bug that was generated by a compiler optimization or even a bad define that was generated by the Wizard. Those who say that use Visual Studio as development environment requires a minimum knowledge of each parameter used in the call to cl.exe; that the ideal is to use the good old Build that parse files SOURCES, DIR and MAKEFILE and be quite sure about the environment set by the DDK shortcuts is correct. On the other hand, there are those ones who do not give up the convenience of having an integrated environment, the facility just about pressing a key to see the detected error file line , the use of syntax coloring, IntelliSence, auto-complete and many other advantages that Visual Studio offers.

    I have been doing this for some time and I remember when the DDK started to bring the compiler embedded into the Windows XP kit. The main purpose of this change in the DDK was a trial to separate the driver development environment from application development environment. This link has already created many problems. The Windows NT 4.0 DDK was based on VC 4.2, but with the arrival of VC 5.0 and later VC 6.0, the symbol table format has been changed and WinDbg stopped working. At that time, I used to utilize SoftIce much more than WinDbg to debug drivers. I continued using the Visual Studio without even noticing this problem. I only had symbol problems when Visual Studio came on version 7.0. The VToolsD does not support the new symbol format yet. Conclusion, I still use VC 6.0 to compile VXDs. Actually, it’s not impossible to use VC 7.0 for this, but we won’t able to debug it.

    Later, when we did the upgrade from VS2003 to VS2005, the most drastic changes have turned my life become a little bluer. Since this time, I started using the best of both worlds, that is, the assurance of having a properly configured environment and all the tools convenience that the VS2005 editor could offer.

    How can we do it? OK, let’s use the project created in post Getting Started as a starting point. Initially we will need to download the file DDKBUILD.CMD from OSR Online and save it in a directory that would be in your machine PATH. That CMD will need the WNETBASE environment variable configured to the DDK installation base directory. This file is a way to make an external build with Visual Studio. To do this, create a Makefile project in Visual Studio as shown below.

    After entering in your new project name folder, where it will be created, just click on “OK”. Even without setting up anything, click “Finish” at the next window. After creating the project, add the files in Solution Explorer. Then edit the project properties as it is shown below. Note that in the “Include Search Path” I’m assuming that DDK installation was performed in the C:\WinDDK\3790. This field has no influence over the compilation process; it just tells IntelliSence which directories should be used to serve as sources for its database.

    From this point, we can build the project like a User Mode project. The images below do not require comments. I suppose it’s not necessary saying that drivers cannot be debugged using the Visual Studio environment. Remember that Kernel debugging requires special debuggers for that purpose as I mentioned in my last post.

    One particularly interesting window that has been added to Visual Studio 2005 is the “Code Definition Window”, displaying where symbols have been defined as you write them in the code window. See the example when I write a call to IoSetCompletionRoutine.

    At last, take a look at the options offered by DDKBUILD. You can list your choices by simply opening a command prompt window and running DDKBUILD without any parameter. Note that we can compile drivers also using the PREfast.

    That’s it… Have fun! 😉

  • Serial Killers

    There’s no doubt, they’re really giving up producing serial ports on notebooks and desktops. In this post, I will talk about some problems we encounter when debugging that driver that only reproduces the issue on that machine that has no serial ports. What alternatives do we have with this regard?

    This month new computers have arrived here in the company. In these machines, we put some of our products in beta version. For any reason, only on new machines one of our drivers was not working as it should. As the quotes of the programmer’s code of ethics, the blame is on the trainee who did the tests until otherwise could be proved. After several unsuccessful attempts to discover what was happening, I had no doubts, let’s debug it. Avoiding moving the victim to my desk to connect the serial cable, I decided to install SoftIce. But life is a surprise box and we got a nice BSOD when SoftIce was started. Wow! This is rare, but it happens. In these cases, we don’t have much choice; we really have to use Windbg. The PCs we got were Dell Dimension 5150 model. Take a look at its cabinet back in the picture and answer quickly: where is the serial port? That’s it, there is none. By consulting the manufacturer’s Web site, we found that the computer had 8 USB ports but had neither a parallel nor a serial port.

    At this moment, we made a circle and talk all together: “Oh God, what do we do now?” Some issues that happen in real machines are also reproduced in virtual ones, especially if the driver you are developing is a filter or a driver that does not deal directly with the hardware. Just for a test, we installed VMware on a new machine and fortunately the problem was reproduced. That’s one of those occasions that we get happy when the problem appears. Thereafter, I just used the old trick about having virtual serial port in a VM and redirect the data stream to a named pipe. This could become a post. 😉

    Well, after connecting the debugger, having the break-point set, it did not take long to find the problem, generating a new version, testing, making it to work and live happily ever after. But not always the history is solved with these few steps. Some virtual machines do not support USB devices. Even VMware that offers this feature still does not support human interface devices (HID) like USB keyboards and mice. Not to mention the psychological and esoteric issues involving race conditions and/or a good joint action with Murphy. What can we do in these cases besides sitting and crying?

    Fortunately, technology at the service of humanity predicted situations like these. In these cases, we traditionally have two alternatives:

    1) Describe the bug you want to delete on a sheet of paper. It is recommended that this description has sections like “Go away strange bug …”. Sew a piece of paper inside a frog’s mouth and positive thinking in solving the problem; throw the frog into a river without seeing where it would fell. After seven days, do a “Rebuild All” in your project (A reboot before the build is recommended). If the problem persists, repeat the steps. Formatting the machine helps to remove bad fluids and scare evil and haunt spirits away that torment your code. Consult a software healer for best results.

    2) Use a FireWire card and make a Windbg connection using an IEEE 1394 cable. This option is only available if the machine being debugged is a Windows XP or higher. These cards are installed on your PCI or PCMCIA bus. I did not have any chance of using this connection type to debug a machine, but it is certainly very fast and comfortable, since the data is transmitted at a rate of up to 400Mbps.

    Can I use one of those famous serial ports to USB converters that are sold at Santa Ifigenia? Although it’s not required to install a driver on your system, these adapters use drivers to work. All USB stack is mounted to make these devices work. On a machine that is being debugged in Kernel, all the code that deals with serial communication or firewire is hard-coded in the system and it works with fixed standard addresses . These adapters can be used without problems by the debugger machine, but not by the debugee one.

    What if I use a PCI multiport serial card? That depends on what I/O addresses and interrupts the card. Normally these cards use different addresses of the standards in order to not to create any compatibility issues with I/O addresses that probably pre-exist on the machine. If the card offers the option of using standard addresses, there is no problem.

    Windows Vista will support Kernel Debug via USB 2.0 port, though some conditions are required. USB cable must be special for this purpose, the debugee computer USB interface must support Kernel Debug, and last but not least, the debugger computer USB controller should be Extended Host Controller Interface (EHCI) compliant.

    If you are interested in acquiring IEEE 1394, remember that you must have, at least, two interfaces such that there is a link between the debugger and debugee machine. Although I have seen some lost comments on the Internet about FireWire x USB converter cables (for use in debugger machine), as far as I could see, they are electrically impossible to be built. That’s because the entire protocol is different. Whereas USB is a “Master x Slave” protocol, FireWire is “Peer to Peer” one. It would require some intelligent hardware along the way to do all translation.

    The company I work for is acquiring these interfaces for PCMCIA FireWire in order to eliminate the problem of debugging customer’s notebook that is crippled serial ports. I think soon we’ll give up the frog and all. I will make some comparisons with the good old serial cable and give some news on this subject.



  • Driver plus plus

    Developing low-level software is really good. I personally love the kind of work I do. I have close friends who marvel at C++ beauty, how things appear to fit perfectly among STL, iterators and templates. My business is definitely another. Despite using C/C++, Assembly and appreciating these languages a lot, I don’t deeply dedicate myself to study C++. My practical side to solve problems leads me to do some things that would make my fried Slug want to beat me, but fortunately he is a calm person. 😛

    After my brother (Kabloc) had read my post Getting Started…, he asked me whether it’s be possible tp use C++ instead of C for developing drivers. In this post I will summarize the problems to get an object-oriented Blue Screen. I will not opine whether C++ is better or worse than C to write drivers. This is a discussion that seems to have no end. If you participate in any discussion list about driver development, you know what I mean. I personally prefer create classes, namespaces and templates that address in a modular way to my problems. That seems to be more comfortable. In fact, we can feel a certain tendency in Kernel Mode development for object-oriented programming. This is something increasingly present with DDIs (device-driver interfaces) using COM model for communication between layers in Kernel and the coming of WDF. Remember that using COM model does not mean using COM, but only the concept of derived interfaces well known as IUnknown to implement reference counters and exchange interfaces.

    First of all, let us build the sample project created in my previous post to show a driver that makes use of a class. As the tradition dictates, we’ll start thinking it’s easy and simply use the CPP file extension at source below and see what happens.

    #include  
     
    //-f--> A class with a very original name
    class MyClass
    {
    public:
        MyClass()
        {
            DbgPrint("Constructor %p\n", this);
        }
     
        ~MyClass()
        {
            DbgPrint("Destructor %p\n", this);
        }
     
        VOID SayHello(VOID)
        {
            DbgPrint("Hello from %p\n", this);
        }
    };
     
     
    /****
    ***
    **      DriverEntry 
    */
     
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT  pDriverObject,
                         IN PUNICODE_STRING pusRegistryPath)
    {
        MyClass Instance;
     
        //-f--> A life sign
        DbgPrint("DriverEntry called\n");
     
        //-f--> Hello...
        Instance.SayHello();
     
        //-f--> Everything is fine so far
        return STATUS_SUCCESS;
    }

    Round #1…

    Compiling - krnclass.cpp for i386
    ...\ntddk.h(2152) : error C2220: warning treated as error - no object
                        file generated
    ...\ntddk.h(2152) : error C4162: '_ReturnAddress' : no function with
                        C linkage found
    ...\ntddk.h(6889) : error C4162: '_InterlockedExchange' : no function
                        with C linkage found
    ...\ntddk.h(6915) : error C4162: '_InterlockedIncrement' : no function
                        with C linkage found
    ...\ntddk.h(6928) : error C4162: '_InterlockedDecrement' : no function
                        with C linkage found
    ...\ntddk.h(6942) : error C4162: '_InterlockedExchangeAdd' : no function
                        with C linkage found
    ...\ntddk.h(6972) : error C4162: '_InterlockedCompareExchange' : no
                        function with C linkage found
    ...\ntddk.h(7024) : error C4162: '_InterlockedOr' : no function with C
                        linkage found
    ...\ntddk.h(7034) : error C4162: '_InterlockedAnd' : no function with C
                        linkage found
    ...\ntddk.h(7044) : error C4162: '_InterlockedXor' : no function with C
                        linkage found

    We find some definitions in ntddk.h that need to be compiled in C, and not in C++. This problem will also happen with the driver’s entry point DriverEntry. DDK expects to find this exported symbol as C. But this is still very easy to solve, just change the way we include this header and the way we declare our entry point so, that it’ll look as shown below.

    extern "C"
    {
        #include 
    }
     
    ...
     
    extern "C"
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT  pDriverObject,
                         IN PUNICODE_STRING pusRegistryPath)
    {

    So, it has compiled properly. Loading this driver, we can see the following messages in DebugMon.

    Are we done? Do we already have a driver in C++? Not yet. We can already enjoy some concepts like classes, templates and overloads, for example, but let’s see what happens when we try to use the new operator.

    extern "C"
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT  pDriverObject,
                         IN PUNICODE_STRING pusRegistryPath)
    {
        MyClass *pInstance = NULL;
     
        //-f--> Creating an instance dynamically
        pInstance = new MyClass();
     
        //-f--> Crashphobia
        if (!pInstance)
            return STATUS_NO_MEMORY;
     
        //-f--> Hello from heap
        pInstance->SayHello();
     
        //-f--> Releasing
        delete pInstance;
     
        //-f--> Everything is fine so far
        return STATUS_SUCCESS;
    }
     

    Round #2…

    Linking Executable - objchk_wxp_x86\i386\krnclass.sys for i386
    krnclass.obj : error LNK2019: unresolved external symbol "void * __cdecl
                   operator new(unsigned int)" (??2@YAPAXI@Z) referenced in
                   function _DriverEntry@8
    krnclass.obj : error LNK2019: unresolved external symbol "void __cdecl
                   operator delete(void *)" (??3@YAXPAX@Z) referenced in
                   function "public: void * __thiscall MyClass::`scalar
                   deleting destructor'(unsigned int)" (??_GMyClass@@QAEPAXI@Z)
    objchk_wxp_x86\i386\krnclass.sys : error LNK1120: 2 unresolved externals

    Oops! To resolve these dependencies, we have to overload new and delete operators so, that allocations would be made through the ExAllocatePool(). Let’s pass an additional parameter to the new operator so that we can choose between NonPagedPool, PagedPool and so on …

    typedef unsigned int size_t;
     
    //-f--> Overloading the new operator
    __inline void* __cdecl operator new(size_t size,
                                        POOL_TYPE pool)
    {
        return ExAllocatePool(pool, size);
    }
     
    //-f--> Overloading the delete operator
    __inline void __cdecl operator delete(void *pVoid)
    {
        ExFreePool(pVoid);
    }
     
    ...
     
        //-f--> We should specify the pool type here
        pInstance = new(NonPagedPool) MyClass();
     
    ...

    Now it compiles again and the memory allocations are made in the way it should do, but there is another problem that happens when you try to create static or global objects. Let’s demonstrate this by creating a global instance and again, trying to compile this example.

    Round #3…

    Linking Executable - objchk_wxp_x86\i386\krnclass.sys for i386
    krnclass.obj : error LNK2019: unresolved external symbol _atexit
                   referenced in function _$E1
    objchk_wxp_x86\i386\krnclass.sys : error LNK1120: 1 unresolved externals

    Since we have no support to C++ in Kernel, we have no run-time that implements all static object initialization by calling all global constructors and destructors of them. This is a process somewhat complicated and it will require some more concepts. There is a very good article from Matt Pietrek that describes this process. Looks like this will give us a lot of work, but fortunately there is a MSI that brings an implementation of Kernel C++ run-time at Hollis Technology Solutions site . The package is an open source, and thus, it brings all the source code with it (including an example) and the libraries of this implementation.

    This run-time implementation is broader than described in this post and we will have enough to play with C++ in Kernel. For C users, it brings even the definitions of malloc() and free(). The only uncomfortable thing I found in this package is a need to replace the definition of our DriverEntry() entry point to CPP_DRIVER_ENTRY.

    #include 
     
    ...
     
    /****
    ***
    **      DriverEntry 
    */
    CPP_DRIVER_ENTRY(IN PDRIVER_OBJECT  pDriverObject,
                     IN PUNICODE_STRING pusRegistryPath)
    {
     
    ...


    I’ll leave an example for downloading about how to use this package, admitting that you have installed MSI on C:\Library\HtsCpp. This example may also serve as the basis for future posts that would use object orientation feature. Anyway, the following is a preview of how your SOURCES file should be.

    TARGETNAME=KrnClass
    TARGETPATH=obj
    TARGETTYPE=DRIVER
     
    !if "$(DDKBUILDENV)" == "fre"
    BUILD_CONFIG=libFre
    !else
    BUILD_CONFIG=libChk
    !endif
     
    TARGETLIBS=C:\Library\HtsCpp\$(BUILD_CONFIG)\i386\HtsCpp.lib
     
    INCLUDES=C:\Library\HtsCpp\sys\inc;
     
    SOURCES=KrnClass.cpp

    See you! 🙂

    KrnClass.zip

  • RtlGetModuleBase & RtlGetProcAddress

    In the post ExAllocatePool (WithoutTag), I talked a little about the conflicts on using new APIs in drivers and making them incompatible with legacy systems. Our initial proposal was to have a single binary that would be able to run either in Windows NT and newer systems. We reached a solution that cannot be considered ideal, that old functions are always used on systems that support newer APIs.

    Thinking about solving this limitation, the DDK brought us MmGetSystemRoutineAddress(). Analogous to GetProcAddress() exported by kernel32.dll, MmGetSystemRoutineAddress() dynamically obtains a function address from its exported name. But the world will not still be safe while Windows NT survives. This new function has only been implemented since Windows 2000.

    We don’t have an alternative to Windows NT, so let’s make one. With one or two PE concepts, we implemented this function version. PE structure carries tons of rules, but for our need we can implement a light version. If you want details about the rules adopted by PE, you can take a look at the article An In-Depth Look into the Win32 Portable Executable File Format by Matt Pietrek.

    Well, now that we already have read the entire article and already known everything about PE, follow the basic algorithm prototype about how to walk through PE structure, looking for a specific function exported by name. This function is not provided by Windows NT DDK and is written in the example source code available for downloading.

    NTSTATUS RtlGetProcAddress(IN PVOID     pBaseAddress,
                               IN LPCSTR    pszFunctionName,
                               IN NTPROC    *pProcedure);

    Notice that the input parameters are the base address, the name of desired function and ultimately the address to the pointer that will get the obtained function address. But where will I get this base address from? Remember the functions we are looking for are exported by ntoskrnl.lib and they are implemented in the ntoskrnl.exe module. To make sure the function we’re looking for is in fact exported by this module, use the “Dependency Walker” to see this module export table. As I said before, some functions are implemented as macros, thus, its definition will be in a header file and not in the export table.

    To get the module base address that exports these functions, we use ZwQuerySystemInformation() in which, although not documented by Microsoft, there are already several publications that comment about it. Thus, we’ll define the RtlGetModuleBase() which will behave similar to the well-known GetModuleHandle(). This function is also defined in the example available for downloading.

    NTSTATUS
    NTAPI
    ZwQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
                             IN OUT PVOID SystemInformation,
                             IN ULONG SystemInformationLength,
                             OUT PULONG ReturnLength OPTIONAL)

    There are many undocumented features and settings that can be extremely useful. The book Windows NT/2000 Native API Reference by Gary Nebbett is excellent to make use of these functions. He brings prototypes, enums, structures used in calls, descriptions of what each function does and each parameter. Here in our example, we only use the statements below for information about the modules loaded into the system address space.

    typedef struct _SYSTEM_MODULE_INFORMATION   // Information Class 11
    {
        ULONG Reserved[2];
        PVOID Base;
        ULONG Size;
        ULONG Flags;
        USHORT Index;
        USHORT Unknown;
        USHORT LoadCount;
        USHORT ModuleNameOffset;
        CHAR ImageName[256];
     
    } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

    The structure “Base” member above brings us the module base address containing PE structure. In the sample code, is RtlGetModuleBase() routine definition that has the following prototype.

    NTSTATUS RtlGetModuleBase(IN LPCSTR     pszModuleName,
                              OUT PVOID*    ppBaseAddress);

    With the union of its powers, now we can know whether a certain API is implemented in the current system and if so, get its address. So, it is perfectly possible to have a single binary that can run on both Windows NT using ExFreePool() and in later systems using ExFreePoolWithTag(). Below it is a very basic example as always. Of course, we can create a single allocation routine that would do the dirty work.

    #include "GetProcAddr.h"
     
    //-f--> Type for the ExFreePoolWithTag routine
    typedef VOID (NTAPI* PF_EX_FREE_POOL_WITH_TAG)
    (
        IN PVOID  P,
        IN ULONG  Tag 
    );
     
     
    VOID OnDriverUnload(PDRIVER_OBJECT     pDriverObj)
    {
        //-f--> That routine, even empty, is here just
        //      to allow the driver to be unloaded.
    }
     
     
    /****
    ***
    **           There once was a Driver...
    **
    */
    NTSTATUS DriverEntry(PDRIVER_OBJECT     pDriverObj,
                         PUNICODE_STRING    pusRegistryPath)
    {
        NTSTATUS                    nts;
        PVOID                       pBaseAddress, pTemp;
        PF_EX_FREE_POOL_WITH_TAG    pfExFreePoolWithTag;
     
        //-f--> Set the unload callback routine
        pDriverObj->DriverUnload = OnDriverUnload;
     
        //-f--> Get the module base address
        nts = RtlGetModuleBase("ntoskrnl.exe",
                               &pBaseAddress);
     
        //-f--> Testing the routine's return doesn't hurt,
        //      but not doing this can kill your system.
        if (!NT_SUCCESS(nts))
            return nts;
     
        //-f--> Allocating memory for a test using the Free routine
        pTemp = ExAllocatePoolWithTag(NonPagedPool,
                                      10,
                                      'tseT');
     
        //-f--> Get the function API address
        nts = RtlGetProcAddress(pBaseAddress,
                                "ExFreePoolWithTag",
                                (NTPROC*)&pfExFreePoolWithTag);
     
        if (NT_SUCCESS(nts))
        {
            //-f--> If that routine is implemented by the system, so
            //      we get a success return code here.
            pfExFreePoolWithTag(pTemp,
                                'tseT');
        }
        else
        {
            //-f--> Who has no dog, hunts like a cat.
            ExFreePool(pTemp);
        }
     
        return STATUS_SUCCESS;
    }

    Have fun! 🙂

    ExGetProc.zip