Vlad Ioan Topan

My playground

Posts Tagged ‘Windows

Compiling a tiny executable (or DLL) in FASM (or MSVC) + templates – part II: MSVC

with one comment

Since creating tiny executables and DLLs in FASM was pretty straight-forward, we’ll challenge ourselves a bit: we’ll do it in MSVC. To be fully honest, creating a tiny executable using MSVC is actually more than a bit of a challenge, but it is doable.

An empty “int main(…) {return 0;}” program compiled with Microsoft’s Visual C++ compiler is already around 38 KB (using VS 2008, but other versions should yield similar results) due to the CRT (also calledcrt0, which implements (parts of) the C language runtime) code included in the executable. The CRT is responsible for things such as implementing the C API for working with files (fopen & co.), strings (strcpy & co.) etc., the malloc-based memory allocator, the well-known int main(…) entrypoint, etc.

[Sidenote] All Windows (PE) executables actually have a WinMain entrypoint, where a CRT stub is placed which, among many other things, parses the single-string command line and splits it into “parameters” passed as argv[] to main().

If we remove the CRT, we have to use Windows API functions to replace it (on Windows, obviously).

[Sidenote] We could alternatively link against a dynamic version of the runtime, but the code would still be much bigger than it needs to be, with the added pain of having a dependency on the Microsoft Visual C++ Redistributables, which have caused plenty of annoyance due to the somewhat cryptic error messages reported about some MSVCR##.DLL missing when the packages aren’t installed on the user’s machine.

The file management functions have good equivalents in the Windows API (start from CreateFile). The strings APIs are somewhat harder to find, but present. Memory allocation APIs are plentiful (LocalAlloc or HeapAlloc are good starts, or even VirtualAlloc for more complicated things). The fact that the WinMain() standard entrypoint does not provide “digested” arguments (like C’s argv/argc main() arguments) can also be handled using Windows API calls, but for some reason only the WideChar variant of CommandLineToArgv (i.e. CommandLineToArgvW) is implemented, so we’ll work with WideChar functions in the example.

Let’s create a 64-bit basic DLL loader and a sample DLL. First, the loader’s source code:

#include <windows.h>

int 
CALLBACK 
WinMain(
    _In_ HINSTANCE hInstance,
    _In_ HINSTANCE hPrevInstance,
    _In_ LPSTR lpCmdLine,
    _In_ int nCmdShow
    )
{
    WCHAR *cmdline;
    int argc;
    WCHAR **argv;
    
    /// we aren't interested in any of the standard WinMain parameters
    UNREFERENCED_PARAMETER(hInstance);
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
    UNREFERENCED_PARAMETER(nCmdShow);
    
    /// get the WideChar command line, split it
    cmdline = GetCommandLineW();
    argv = CommandLineToArgvW(cmdline, &argc);
   
    /// assume the first parameter is a DLL name, load it
    LoadLibraryW(argv[1]);

    /// free the "digested" parameters
    LocalFree(argv);
    
    ExitProcess(0);
}

In the interest of keeping things simple, this code is fugly and evil (it doesn’t check error codes), but it does work.

We have a standard WinMain entrypoint. We get the WideChar version of the command line using GetCommandLineW(), then
split it using CommandLineToArgvW() into the more familiar (to C devs at least) argc/argv pair. We call LoadLibraryW on
the first argument, which we assume is the DLL name, then free the argv obtained from CommandLineToArgvW() and exit.

The DLL is as basic as possible, just a header and a source (the header is given to serve as a template, it’s not actually necessary in this case).

The win64dll.h file:

#pragma once

#ifdef AWESOME_EXPORTS
#define AWESOME_API __declspec(dllexport)
#else
#define AWESOME_API __declspec(dllimport)
#endif

And the .c:

#include "win64dll.h"
#include <windows.h>

BOOL APIENTRY 
DllMain( 
    HMODULE hModule,
    DWORD  dwReason,
    LPVOID lpReserved
    )
{
    UNREFERENCED_PARAMETER(hModule);
    UNREFERENCED_PARAMETER(lpReserved);

    switch (dwReason)
    {
        case DLL_PROCESS_ATTACH:
            MessageBox(0, "Hello!", "Hello!", MB_OK);
            break;
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}

Now for the hard part: compiling without the CRT. Since it’s easier to compile from the command line, or at least easier to write command line arguments than project settings/checkboxes in an article, let’s start off with compiling the loader above (presumably called loader.c) with the CRT and go from there:

cl.exe loader.c /link shell32.lib

Assuming your environment is set up correctly (see sidenote below about setting up the environment), this will produce a ~32 KB executable (on VS 2010 at least). The /link shell32.lib parameter is necessary because that lib contains the CommandLineToArgvW function we used. To get rid of the CRT, the /NODEFAULTLIB parameter is used. We’ll also need to explicitly define WinMain as the entrypoint, and add kernel32.lib to the library list, since it’s one of the “default” libs which is no longer automatically linked:

cl.exe loader.c /link shell32.lib kernel32.lib /nodefaultlib /entry:WinMain

[Sidenote] The linker parameters (the ones after /link) are NOT case-sensitive, either /nodefaultlib or /NODEFAULTLIB will work.

This should produce a 2560 byte executable, more than 12 times smaller than the CRT-based one, and doing exactly the same thing.

[Sidenote Q&A] Q. How to tell which .lib files are needed?
A. When the necessary .lib is not given as a command line argument, the compiler complains with an error message such as:

loader.obj : error LNK2019: unresolved external symbol __imp__LoadLibraryW@4 referenced in function _WinMain@16

This means the LoadLibraryW() function is missing it’s .lib; to find it, simply search for the LoadLibraryW text in the lib folder of the SDK (in a path similar to: “C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1\Lib“) and use the lib it’s found in (in this case, kernel32.lib). As an alternative to searching in the (binary) .lib files, you can check the MSDN reference for the given function (search online for something like “MSDN LoadLibraryW”), which gives the lib filename in the “Library” section of the “Requirements” table at the bottom.

Compiling the DLL needs a few more paramters:

cl.exe win64dll.c /link shell32.lib kernel32.lib user32.lib /nodefaultlib /entry:DllMain /dll /out:win64dll.dll
  • user32.lib is needed for MessageBoxA
  • the /dll switch tells the linker to create a DLL
  • the exact name must be specified (via /out:win64dll.dll), because the linker defaults to creating .exe-s

This should yield a 3072 byte DLL. It’s slightly larger than the executable because of the export section (and the fact that each section’s size is rounded up to the FileAlignment (PE header) value, which defaults to 0x200 == 512, exactly the difference which we got, which also covers the small difference in size between the actual code produced).

After building the executable and the DLL, running:

loader.exe win64dll.dll

should pop up a “Hello!” message box, then exit.

[Sidenote] Setting up the cl.exe environment involves:

  • adding the VC\BIN subfolder of the MS Visual Studio installation to the %PATH% environment variable (should look like “C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin”)
  • adding to the %INCLUDE% environment variable the INCLUDE subfolders of:
    • the MS Platform SDK installation (e.g. “C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include”)
    • the MS Visual Studio installation (e.g. “C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\Include”)
  • adding to the %LIB% environment variable the LIB subfolders of the VS and PSDK

The easiest way to do this is via a setupvc.bat file containing:

@echo off
SET VS_PATH=C:\Program Files (x86)\Microsoft Visual Studio 10.0
SET SDK_PATH=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A
SET PATH=%VS_PATH%\VC\bin;%VS_PATH%\Common7\IDE;%PATH%
SET LIB=%VS_PATH%\VC\ATLMFC\LIB;%VS_PATH%\VC\LIB;%SDK_PATH%\LIB
SET INCLUDE=%VS_PATH%\VC\ATLMFC\INCLUDE;%VS_PATH%\VC\INCLUDE;%SDK_PATH%\include

After adjusting the paths as needed by your setup, run this before running cl.exe from the command line.

The first part of this text deals with tiny executables in FASM.

Written by vtopan

February 17, 2014 at 10:23 PM

Posted in C, programming, Snippets

Tagged with , , , , ,

Recovering data from a dead Windows (NTFS) disk using Linux

with one comment

At some point in your IT-enthusiast life you must’ve had at least one dead HDD, off of which Windows wouldn’t boot anymore. Up until a while ago, particularly if the partitions were formatted with NTFS, the situation was pretty much hopeless. Nowadays, with very-much-improved NTFS support under Linux (and rather tolerant to faults compared to its native counterpart under Windows), it isn’t always so. If the HDD is in a “coma” (i.e. almost dead, but not still “sort of” kicking), booting off a Linux live CD might still help recover (some of) the data. Basic steps:

  1. Get a Linux live CD distribution which has good built in NTFS support (most of them have basic support by now) and ddrescue
  2. Boot off the live CD and use ddrescue to get a binary image of each partition or mount the partition(s) and copy the files to a safe place
  3. [If using the dd(rescue) approach] mount the images as drives under Windows and copy the files or be brave and mount the partition in a VM and try to actually boot it, at least as far as a command prompt (safe mode) or use a backup/partitioning tool to write the images to another disk

If you’re not paranoid about security (by nature or by job description), i.e. you don’t use EFS for your most sensitive data, you’re pretty much off the hook. If you’ve made the punishable-by-huge-amounts-of-pain mistake of using EFS and your disk crashed, as is my case, hope is as dimmed as the foresight of the folks who designed NTFS and used more than the actual user password to encrypt the data. As it turns out, to decrypt the files you need a certificate which can only be generated on the machine which encrypted the files, which is

Linux live CDs with NTFS support

I’ve tried SystemRescueCd, Trinity Rescue Kit, RIP Linux and plain vanilla Knoppix, and Trinity Rescue Kit appears to be the best: it has ntfstools / Linux-NTFS installed, and it didn’t hang on boot because of the failing HDD (other distros did). As a sidenote, I haven’t managed to boot the GUI (X) of any of the distros, as my laptop monitor/graphics card seems to be uncooperative with the standard drivers/VESA mode, but apart from the visual partition manager, everything works fine from the console anyway.

When choosing a distro, the main points to check are if it has the ntfs-3g driver (as recent a version as possible, as it keeps getting better at a fast pace) and the ntfstools / Linux-NTFS suite I mentioned earlier, especially if you’ve used EFS to encrypt your data (in which case the only viable solution appears to be ntfsdecrypt from that suite, which needs the certificate with which the files were encrypted, which in it’s turn needs you to boot the (dead) machine, but it appears to be the only way to get the data back).

Using dd/ddrescue to recover (NTFS) partitions

dd / ddrescue

The tool to move binary data from one place to another under Linux is dd. It also has a data-recovery-oriented cousin called ddrescue, which basically does the same thing, but is more fault-tolerant.
Basic dd usage:

dd if=/source of=/destination

if stands for input file and of for output file, and neither of them has to be an actual file (in the Windows sense); in the above example, /dev/sda1 is the first partition on the sda disk.
To back up just the MBR of the disk (the first 512 bytes) use:

dd if=/dev/sda of=/mnt/sdb1/saved/mbr.bin bs=512 count=1

This assumes that source disk is sda and that sdb1 is the partition to which you want to back up the data, so in your particular case they may need to be changed. See the next section if you’re not sure which disk is mapped to which name.
ddrescue uses fixed-position input (first) and output (second) arguments:

ddrescue -v /source /destination

The -v option makes ddrescue verbose (i.e. periodically print progress).
Note: by default, dd prints no progress/info until it’s job is finished. To check up on it’s progress, open another console (the terminals are mapped to Alt+N shortcuts in Linux, N >= 1, usually up to 4) and send it the USR1 signal. To do that, first you need to find it’s PID using ps:

ps -A|grep dd

Then, assuming the PID of the dd process is 3456, use kill:

kill -USR1 3456

That won’t actually kill the process, in spite of it’s name; it will just send it the USR1 signal, which makes dd print it’s current status (switch to the dd terminal to see it). The command’s name (“kill”) comes from it’s most frequent usage, which is to send a process the KILL signal (i.e. “kill” it).

Linux drive mapping

Linux maps your disks under /dev with names following the (“regex-like”) pattern [hs]d[abcd]. An h prefix means an (older) IDE disk, meanwhile an s prefix means a serial disk (usually an internal SATA or external USB disk). The individual partitions follow the disk naming + a digit to designate the partition number. So, for example, if you have a SATA disk with two partitions, the disk would be /dev/sda, the first partition would be /dev/sda1 and the second partition /dev/sda2.
To see the available disks/partitions, use ls (the Linux equivalent of dir):

ls /dev/sd*
ls /dev/hd*

To get extended disk info, use hdparm:

hdparm -I /dev/sda

The disks (actually the partitions) found under /dev need to be mounted before the files on them can be read/written; up until that point they are just huge blobs of binary data.

Note: for the rest of this writing, for simplicity’s sake, I’ll assume that sda is the broken disk and it has wto partitions, and that the recovered files/image go to sdb.

There are two ways to mount NTFS partitions: either using the default NTFS driver which comes with mount (ignores many problems, doesn’t care if Windows was improperly stopped & the drive was left “unclean”, read-only mode by default) or the ntfs-3g driver (more sensitive, read-write by default). Use the plain mount for the broken disk and the ntfs-3g version for the drives to which you need read-write access.
First off, you need to make appropriate folders for the partitions to be mounted under; standard practice is to do it under the /mnt folder. e.g.:

mkdir /mnt/sda1
mkdir /mnt/sda2
mkdir /mnt/sdb1

Note that the /mnt folder may not exist, in which case it must be created first: mkdir /mnt
Next, mount partitions from the broken disk (read-only):

mount /dev/sda1 /mnt/sda1
mount /dev/sda2 /mnt/sda2

The syntax of the mount command is straight-forward: mount /what /where; /what is the device, /where is the mount point in the filesystem. It takes other arguments, such as -t type to set the filesystem type, but NTFS is (nowadays) recognized automatically. The naming convention for the mount points is at your choice (you could mount the thing on something like /my/broken/disk/partition/number/1), but sticking to the “standard” /mnt path and using the original device’s name (or the partition letter if you’re more accustomed to that and a lazy typist, such as /mnt/c) is easier, and the help you find on the net will make more sense.
Last step in the mount process: mounting the destination disk in read-write mode (default for ntfs-3g):

ntfs-3g /dev/sdb1 /mnt/sdb1

or

mount -t ntfs-3g /dev/sdb1 /mnt/sdb1

The syntax is similar to the mount command; to check if the distro you chose has the ntfs-3g command built in, simply try to run it. If it doesn’t, choose another distro.

Copying the data

Run either dd or ddrescue (the latter is preferred if the disk is only partially readable):

dd if=/dev/sda1 of=/mnt/sdb1/saved/part1.bin

or

ddrescue -n /dev/sdb1 /mnt/sdb1/saved/part1.bin

WARNING: pay attention not to pass as the destination to dd/ddrescue entire disks unless you actually want their contents overwritten (which will be the case when you restore the saved image to a new disk); be sure to add a file name otherwise. The -n option prevents ddrescue from retrying error areas, which is usually what you want. If you have a disk which does yield data after enough retries, don’t use it.

Mounting the (NTFS) partition(s) from Linux/Windows

You can mount the newly backed-up partitions from Linux using the loop feature:

mount -o loop /mnt/sdb1/saved/part1.bin /mnt/part1

The partition can also be mounted directly from Windows using the ImDisk Virtual Disk Driver (free) or using some rather expensive commercial tools (google for alternatives).

Backing up/restoring partitions/whole disks

Alternatively, you can use the dd command to copy the entire disk and write the image to a fresh (identical) disk. Writing an image to a partition/disk using dd simply requires passing the disk as the of argument:
Restoring a partition:

dd if=/mnt/sdb1/saved/part1.bin of=/dev/sdc1

Restoring an entire disk:

dd if=/mnt/sdb1/saved/whole-disk.bin of=/dev/sdc

WARNING: be careful when overwriting raw partition/disk contents; choose other recovery methods unless you understand exactly what you’re doing.

Recovering files from raw data/deleted files: data carving

If the partition table/NTFS structure is broken and you can’t mount the partitions but you can read the binary data, you can use TestDisk to recover some of the files (the ones with a specific structure, such as images and music, are more likely to be found as opposed to, say, plain text files). This is basically the same thing that file recovery programs (such as Recuva) do on the unused space of a disk to recover deleted files.

Recovering EFS encrypted files

As I’ve mentioned in the opening paragraph, to recover EFS encrypted files, even under Linux, you need a recovery certificate. If you don’t have one, EFS file recovery software might help, but I’ve had little luck using them. I know of no open source/free software which does that, so you’ll probably have to use commercial software such as Advanced EFS Data Recovery from ElcomSoft (demo version available). The link called “encrypted file system recovery” from the following section details the process of manually extracting the required information for EFS recovery.

Further reading

Moral of the story

  • ALWAYS BACK UP YOUR IMPORTANT DATA. Seriously. Now. Go get some storage space (USB flash drive, external hard disk, even DVDs if you make a new one often enough, as they tend not to last very long) and copy your data on it. GO!
  • Don’t use EFS under NTFS. Use an alternative encryption solution, e.g. TrueCrypt. There are portable (i.e. works-from-flash-drive) editions of most encryption tools should the need arise, and they are reliable (I’ve used TrueCrypt without problems for quite a while now).
  • If you MUST use EFS, create a recovery certificate using CIPHER /R:filename (details here) and store it in a safe place.

Written by vtopan

November 15, 2009 at 11:51 PM

Listing the modules (DLLs) of the current process without API functions

with one comment

There is a simple way to walk the list of loaded modules (DLLs) of the current Windows process without calling any API functions. It also works with other processes, but it obviously involves reading the respective process’ memory space, which in turn involves using the aptly-named ReadProcessMemory function, defeating the whole purpose of not using APIs.

The PEB and the TIB

The PEB (Process Enviroment Block), briefly documented here (the page which passes as “documentation” on MSDN just… isn’t) is a structure (stored for each process in it’s own memory space) which holds various process parameters used by the OS such as the PID, a flag set if the process is being debugged, some localization information etc. The PEB is pointed to by the TIB (Thread Information Block), which is always located at FS:[0] (if that sounds like black magic, either pick up a book on assembly language and/or x86 processor architecture, or ignore that piece of information and use the code below to get to it).

One of the PEB entries is a list of, well, the loaded modules of the process. Actually, a PEB member points to a structure called LoaderData (it’s type being PEB_LDR_DATA), again “almost documented” by MS, which points to the list we’re interested in, looking something like this:

typedef struct LDR_DATA_ENTRY {
  LIST_ENTRY              InMemoryOrderModuleList;
  PVOID                   BaseAddress;
  PVOID                   EntryPoint;
  ULONG                   SizeOfImage;
  UNICODE_STRING          FullDllName;
  UNICODE_STRING          BaseDllName;
  ULONG                   Flags;
  SHORT                   LoadCount;
  SHORT                   TlsIndex;
  LIST_ENTRY              HashTableEntry;
  ULONG                   TimeDateStamp;
  } LDR_DATA_ENTRY, *PLDR_DATA_ENTRY;

It’s a linked list (the LIST_ENTRY structure contains the forward pointer called Flink) which contains serveral useful pieces of information about each module, among which it’s image base (BaseAddress), virtual address of the entrypoint (EntryPoint) (NOT the RVA you find in the PE header, but the actual computed VA) and DLL name with (FullDllName) and without (BaseDllName) the path, as UNICODE_STRINGs. The list is circularly linked and has a sentinel element with the BaseAddress member set to 0.

The list entries should be of the LDR_DATA_TABLE_ENTRY data type described by MS here, but the actual structure found in-memory doesn’t have the first member (BYTE Reserved1[2]). An alternative (and more complete) definition of the structure can be found here, but it has three LIST_ENTRY members at the beginning instead of just one.

Getting a pointer to the list

We retrieve the pointer to the list from the PEB using inline assembly from the C source code:

__declspec(naked)
PLDR_DATA_ENTRY firstLdrDataEntry() {
   __asm {
      mov eax, fs:[0x30]  // PEB
      mov eax, [eax+0x0C] // PEB_LDR_DATA
      mov eax, [eax+0x1C] // InInitializationOrderModuleList
      retn
      }
   }

There are actually three lists of modules, sorted by three different criterias; the one we’re using is sorted by the order in which the modules were loaded.

Example

Using the structure defined above and the firstLdrDataEntry function, it becomes trivial to walk the list of loaded modules:

void main() {
   PLDR_DATA_ENTRY cursor;
   cursor = firstLdrDataEntry();
   while (cursor->BaseAddress) {
      printf( "Module [%S] loaded at [%p] with entrypoint at [%p]\n",
              cursor->BaseDllName.Buffer, cursor->BaseAddress,
              cursor->EntryPoint);
      cursor = (PLDR_DATA_ENTRY)cursor->InMemoryOrderModuleList.Flink;
      }
   }

Written by vtopan

May 27, 2009 at 11:22 PM