skip to Main Content

Windows Development Setup Guide

This blog entry contains a list of applications and instructions how to install them for setting up Windows as a development machine.

Install Chocolatey

Open a cmd.exe terminal as Administator and run:

@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"

Now you are ready to install all other applications using a simple command on the shell. Chocolatey also takes care of updating them.

To get rid of having to confirm every action:

choco feature enable -n allowGlobalConfirmation

Communication

Skype

choco install skype

Programming

git – distributed version-control system

choco install git

Go – Golang programming language

choco install golang

Graphviz – Graph Visualization Software useful for Golangs profiling visualization

choco install graphviz

Node.js

choco install nodejs
choco install gradle
choco install yarn

Android Studio

choco install adb
choco install android-sdk
choco install androidstudio

Python 3

choco install python pip
pip install virtualenv

Java

choco install jre8
choco install jdk8

Visual Studio Code

choco install vscode
code --install-extension casian.plsql
code --install-extension codezombiech.gitignore
code --install-extension DavidAnson.vscode-markdownlint
code --install-extension hnw.vscode-auto-open-markdown-preview
code --install-extension jebbs.plantuml
code --install-extension joaompinto.asciidoctor-vscode
code --install-extension mitaki28.vscode-clang
code --install-extension ms-python.python
code --install-extension ms-vscode.cpptools
code --install-extension ms-vscode.Go
code --install-extension PeterJausovec.vscode-docker
code --install-extension robertohuertasm.vscode-icons
code --install-extension streetsidesoftware.code-spell-checker
code --install-extension wayou.vscode-todo-highlight
code --install-extension xaver.clang-format
code --install-extension yzane.markdown-pdf
code --install-extension zxh404.vscode-proto3

Visual Studio – Free Community Edition

choco install visualstudiocommunity2013

System

ConEmu – Replacement for the built in Terminal

choco install conemu

KeePassXC – Password manager

choco install keepassxc

VeraCrypt – disk encryption

choco install veracrypt

Total Commander – dual pane file manager as Explorer replacement

choco install totalcommander

Rufus – create bootable USB flash drives

choco install rufus

WinCDEmu – CD/DVD/BD emulator

choco install wincdemu

Usability

Launchy – program launcher

choco install launchy

Notepad++ – Notepad replacement

choco install notepadplusplus

neovim – modern VIM version

choco install neovim
pip install neovim

Meld – A visual Two- and three-way visual diff and merge tool

choco install meld

f.lux – makes the color of your computer’s display adapt to the time of day, warm at night and like sunlight during the day

choco install f.lux

Virtualization

docker – lightweight software container isolation

choco install docker
choco install docker-compose

VirtualBox – operating system virtualization

choco install virtualbox

Network

Google Chrome

choco install googlechrome

Chromium

choco install chromium

Firefox

choco install firefox

Flash Player Plugin

choco install flashplayerplugin

Putty – SSH and Telnet client

choco install putty

Command-line tools for network access

choco install curl nmap openssl.light wget whois

Syncthing – Decentralized file sync

choco install synctrayzor

Multimedia

VLC – Multimedia player for videos

choco install vlc

XnView MP – Image viewer

choco install xnview

ImageMagick – Image processing

choco install imagemagick

RawTherapee – Photo editor

choco install rawtherapee

GIMP – Image editor

choco install gimp

HandBrake – video converter

choco install handbrake

Office

LibreOffice – Free Office suite

choco install libreoffice

Evince – document viewer for multiple document formats

choco install evince

Haroopad – Markdown editor

choco install haroopad

Pandoc – Universal document converter

choco install pandoc

Ghostscript – PostScript and PDF utilities

choco install ghostscript

calibre – e-book library management

choco install calibre

Git configuration

# Ignore file mode differences
git config --global core.fileMode false
# Better cross-platform line ending handling
git config --global core.autocrlf input
# fix go get redirect errors
git config --global http.https://gopkg.in.followRedirects true

How to get started with Golang

There are multiple resources available to learn Go. The Go Playground allows you to write code in the browser and test it, without that you need to install anything locally.

Golang Resources

Free books

Example code

If you want to start developing Golang more seriously, you will not get around using an IDE that offers you autocompletion and also Debugging capabilities.

IDEs

Install the Golang runtime environment by following the instructions at https://golang.org/doc/install. If you are installing Go on Windows you can use the MSI Installer which also sets environment variables in the system. These environment variables are needed to access go from the command line.

Setup

go get -u github.com/ajstarks/svgo/benchviz
go get -u github.com/golang/lint/golint
go get -u golang.org/x/tools/cmd/benchcmp

Mac OS X Development Setup Guide

This blog entry contains a list of applications and instructions how to install them for setting up a Mac as a development machine. Some applications need to be installed manually, for the rest I recommend using Homebrew – a package manager for Mac OS X. If you plan to start with a fresh Mac OS X install, follow the instructions on Apple Support.

Setting up brew

Open a terminal and install the Command Line Tools for Xcode that are needed for the Homebrew installation

xcode-select --install

Install Homebrew:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Disable Analytics that are sent to Google:

brew analytics off

To extend the amount of available packages (especially GUI applications), also install homebrew-cask:

brew tap caskroom/cask

Check if the system setup is correct:

brew doctor

Now you are ready to install all other applications using a simple command on the shell. Brew also takes care of updating them.

Update existing applications

Replace the installed applications by newer versions:

brew install bash ctags git openssh python

Communication

Skype

brew cask install skype

Programming

Go Golang programming language

brew install go

Graphviz Graph Visualization Software useful for Golangs profiling visualization

brew install graphviz

Mercurial

brew install mercurial

Node.js and useful apps for it

brew install nodejs
brew install flow gradle watchman

Android Studio

brew cask install android-studio

Python 3

brew install python3
pip2 install virtualenv
pip3 install virtualenv

Visual Studio Code

brew cask install visual-studio-code
code --install-extension casian.plsql
code --install-extension codezombiech.gitignore
code --install-extension DavidAnson.vscode-markdownlint
code --install-extension hnw.vscode-auto-open-markdown-preview
code --install-extension jebbs.plantuml
code --install-extension joaompinto.asciidoctor-vscode
code --install-extension mitaki28.vscode-clang
code --install-extension ms-python.python
code --install-extension ms-vscode.cpptools
code --install-extension ms-vscode.Go
code --install-extension PeterJausovec.vscode-docker
code --install-extension robertohuertasm.vscode-icons
code --install-extension streetsidesoftware.code-spell-checker
code --install-extension wayou.vscode-todo-highlight
code --install-extension xaver.clang-format
code --install-extension yzane.markdown-pdf
code --install-extension zxh404.vscode-proto3

Protocol buffers version 3 protoc compiler

brew install protobuf

neovim – modern VIM version

brew install neovim
pip2 install neovim
pip3 install neovim
brew cask install vimr

Meld – A visual Two- and three-way visual diff and merge tool

brew cask install meld

System

fish – User-friendly command line shell

brew install fish

iTerm 2 – Replacement for the built in Terminal

brew cask install iterm2

appcleaner – Uninstall unwanted apps

brew cask install appcleaner

KeePassXC – Password manager

brew cask install keepassxc

NTFS-3G – Read-Write NTFS Driver

brew cask install osxfuse
brew tap homebrew/fuse
brew install ntfs-3g

VeraCrypt – disk encryption

brew cask install veracrypt

Commander One – dual pane file manager as Finder replacement

brew cask install commander-one

Usability

f.lux – makes the color of your computer’s display adapt to the time of day, warm at night and like sunlight during the day

brew cask install flux

KeepingYouAwake – Menu bar utility to prevent your Mac from going into sleep mode

brew cask install keepingyouawake

htop – an interactive process viewer

brew install htop

Shortcat – Faster clicking without using the mouse

brew cask install shortcat

Virtualization

docker – lightweight software container isolation, client

brew cask install docker
mkdir -p ~/.config/fish/completions
curl -o ~/.config/fish/completions/docker.fish https://raw.githubusercontent.com/docker/docker/master/contrib/completion/fish/docker.fish

VirtualBox – operating system virtualization

brew cask install virtualbox

Wine – runs Windows applications on non Windows systems

brew cask install xquartz
brew install wine winetricks

Network

Google Chrome – My default browser to replace Safari

brew cask install google-chrome

Firefox

brew cask install firefox

Command-line tools for network access

brew install axel curl ncftp nmap wget

VPN / Proxy tools

brew install corkscrew
brew cask install tunnelblick

Syncthing – Decentralized file sync

brew install syncthing
ln -sfv /usr/local/opt/syncthing/*.plist ~/Library/LaunchAgents

dnscrypt – Circumvent DNS blocking of ISPs

brew cask install dnscrypt

Multimedia

VLC – Multimedia player for videos

brew cask install vlc

VOX – Slim audio player

brew cask install vox

XnView MP – Image viewer

brew cask install xnviewmp

ImageMagick – Image processing

brew install imagemagick --with-librsvg

RawTherapee – Photo editor

brew cask install rawtherapee

GIMP – Image editor

brew cask install gimp

keycastr – keystroke visualizer

brew cask install keycastr

HandBrake – video converter

brew cask install handbrake

Office

LibreOffice – Free Office suite

brew cask install libreoffice

Haroopad – Markdown editor

brew cask install haroopad

Pandoc – Universal document converter

brew install pandoc

Ghostscript – PostScript and PDF utilities

brew install ghostscript

calibre – e-book library management

brew cask install calibre

Fish shell configuration

Set fish as your default shell:

chsh -s /usr/local/bin/fish

Update fish tab completion data by starting a new Terminal with fish and executing:

fish_update_completions

Install oh-my-fish plugin management:

curl -L http://get.oh-my.fish | fish

Install plugins based on your preference:

omf install brew extract tab

Edit the ~/.config/omf/init.fish and adjust to your own needs:

if status --is-interactive

set -gx fish_greeting ''
set -gx GOPATH ~/gocode
set -gx PATH $PATH $GOPATH/bin

end

Git configuration

# Ignore file mode differences
git config --global core.fileMode false
# Better cross-platform line ending handling
git config --global core.autocrlf input
# fix go get redirect errors
git config --global http.https://gopkg.in.followRedirects true

Adjust Mac OS X default settings

# Disable Game Center
launchctl unload -w /System/Library/LaunchAgents/com.apple.gamed.plist
# Avoid creation of .DS_Store files on network volumes
defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true
# Disable autocorrect
defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false
# Enable dark mode
defaults write NSGlobalDomain AppleInterfaceStyle Dark; killall Dock
# Ask for password screen lock delay
defaults -currentHost write com.apple.screensaver askForPasswordDelay -int 10
# Allow app installation from any source
sudo spctl --master-disable

Tune system settings

brew install m-cli
m dock magnification NO
m dock prune
m finder showhiddenfiles YES
m finder showextensions YES
m finder showdesktop YES
sudo m gatekeeper disable
m notification showcenter NO

Remove not needed Applications

sudo rm -rf /Applications/GarageBand.app
sudo rm -rf /Applications/iMovie.app
sudo rm -rf /Applications/iTunes.app
sudo rm -rf "/Library/Application Support/GarageBand"
sudo rm -rf "/Library/Application Support/Logic"
sudo rm -rf "/Library/Audio/Apple Loops"

Install DejaVu fonts

wget http://sourceforge.net/projects/dejavu/files/dejavu/2.37/dejavu-fonts-ttf-2.37.tar.bz2
tar -xf dejavu-fonts-ttf-2.37.tar.bz2
cp dejavu-fonts-ttf-2.37/ttf/*.ttf ~/Library/Fonts/
rm -rf dejavu-fonts-ttf-2.37/ dejavu-fonts-ttf-2.37.tar.bz2

iTerm2 theming

Download iTerm2-Color-Schemes and unpack it. Import the unpacked schemes folder it into iTerm Preferences/Profiles/Colors settings. Try different themes or have a look at http://iterm2colorschemes.com/ for a gallery. I prefer the theme Solarized Dark Higher Contrast, which is based on Solarized.
You can get the original Solarized theme at http://ethanschoonover.com/solarized/files/solarized.zip

Restore function keys

  • Apple Menu -> System Preferences -> Keyboard
  • Tick “Use All F1, F2, etc keys as standard function keys”

Changelog

2018-02-12
* A lot of updates

2017-02-28
* VIM replaced by neovim

2017-02-05
* Visual Studio Code added

Common mistakes in software licensing systems

Leaving debug information in the binaries

The default compiler settings leave more information in the binary than you want someone to have. Especially for Mac compiled binaries, the amount of contained information is dangerous. Try to inspect your compiled binary with a hexeditor or load it into the free version of IDA Pro and scroll through it. It is not uncommon that a text search for serial or license will show the name and address of the internal function that may be visibly named ‘bool IsLicensed()’.

Leaving a key generator in the binary

A common mistake is to leave a key generator function in the binary. A user enters a name and Serial and tries to register your product. The mistake is now to use an internal function that takes the name as a parameter and returns a valid serial like ‘String GetSerial(String name)’. To check if the entered serial is valid, a simple string comparison is done now. A cracker may be able to rip that valid serial returning function and put it into a keygenerator.

Having one attack point

If you have an internal function like ‘bool IsLicensed()’, all a cracker needs to do is find and identify this function and change the code to always return true. This can be done by just patching 3 byte in your binary. If there is only one point in your code that does call this function, a cracker can crack your program by patching just the conditional jump after the IsLicensed call to jump without any condition, this is a 1 byte patch.

Giving immediate feedback on a registration try

While it might seem a good idea at first to give the user an immediate feedback on the product registration, it’s also the point of attack for every cracker. “Your serial is invalid” is a typical example. It’s better to ask the user for a program restart and do the serial check somewhere in the program initialization.

Using text references

If you want to show that your program is Unregistered, try to not use text but an image resource to do so. The first thing a cracker does after loading your product in a Disassembler, is looking for text references for typical words like: license, registered, serial, trial

Not obfuscating Java or .Net bytecode

The standard bytecode of a compiled Java or .Net compile contains all class, function and variable names that you used in your source code. Using a bytecode obfuscator like Proguard for Android will get rid of this by renaming all classes to a,b,c,… The functionality of your program is still given.

Relying only on a commercial software licensing product to secure your app

This may save you time implementing your own solution and prevent some of the listed mistakes, your used commercial software like Armadillo is also a very attractive target for the cracking community. Usually the teams will built their own tools to defeat such software in a generic way in seconds. At the end, this may end in the fastest of all ways to crack your software.

Blacklisting of serials

While this might seem a good idea at first, it can do more harm than good. A cracker that did not posses a valid serial before is given now one for free. All he need to do is change one byte of the blacklisted serial in the binary to make this serial work again.

Hidden menu entries or parameter to generate a valid serial or license

Security by obscurity is a bad idea in that case. A cracker will find it and abuse it.

How to detect if your Windows application is running under Wine

In 2005, Microsoft started the anti-piracy initiative called Genuine Advantage. To be able to download from Microsoft Download Center, you would have had to pass the validation. It was the first time that Microsoft acknowledged the existence of Wine, by blocking its access to the downloads if a Wine specific registry key was found by the ActiveX control or their standalone tool.

These are some ways to detect Wine:

Registry

Check for the existence of “SOFTWARE\Wine\Wine\Config”

Presence of Wine specific API exports

wine_get_version in ntdll.dll (https://www.winehq.org/pipermail/wine-devel/2008-September/069387.html)

Running processes

On a normal Windows system there will always be some specific processes running like csrss.exe (Client/Server Runtime Subsystem), dwm.exe (Desktop Window Manager), explorer.exe (File Explorer) and winlogon.exe (Winlogon). Some of those exes are just present in a specific range of Windows versions, so you have to consider those when checking for their presence. Not having them present could also mean that your application is running on a newer Windows that does not use them anymore. A normal Windows should generally speaking have more then 10 processes running, even if you don’t have any programs running and under a non administrator account that does not allow you to view the list of running system processes. Having not much processes could as well mean that your program is running inside a sandbox.

Missing API functions or functionality

When you search for “unsupported” in the Wine source you will find easily places that have been identified to miss functionality to behave exactly like Windows. The file dlls\ntdll\om.c contains the API NtQueryObject and by looking at the code it sesms like it is missing support for some values in the main switch. This API is not officially documented by Microsoft but…

API code

The API entry code generated by gcc will be different than the one that Microsoft Visual Studio compiler generates.

API files

The Wine dll files are compiled different than the native Windows ones, there is another number of PE sections in files like kernel32.dll

Creating small executables with Microsoft Visual Studio

Starting with an empty project, I will show you how to use Microsoft Visual Studio 2010 to compile your C code without the usual bloating that the compiler adds automatically. This article will just feature C code, I may extend this blog entry for usage with C++ at a later point.

In the empty workspace, create a new file called tinyexe.c with following content:

#include <windows.h>

void main()
{
  MessageBoxA(0, "Hello", "world!", MB_OK);
  ExitProcess(0);
}

Switch the solution configuration from Debug to Release and compile the project (F7 is the default key for this). The output will be a 6.656 byte sized exe file. Could have been worse I would say 🙂 Let’s have a look at what is inside the exe, I am using the file view of Total Commander which will give you a nice view of the file content and showing zero bytes as whitespace.

This is the portable executable header, containing 5 section definitions (.text, .rdata, .data, .rsrc, .reloc).

The code section contains way more code than needed for calling the 2 Windows APIs in our code.

This section contains the import table, import address table as well as a reference to a .pdb debug info file. In the list of imported API functions you will see way more APIs than the 2 that we actually intended to use. The reference to mscvrt.dll means that this exe uses functions of the Microsoft Visual C Run-Time Library, which we did not intend to do. The Visual Studio compiler adds the crt library initialization code by default which then calls our main function.

At the end of this exe file you can see a manifest xml file followed by relocation data, both features we do not need.

Lets see how we can pimp that exe (without using external tools) now:

  • To get rid of the console window that pops up on program start set the project option Linker/System/Subsystem to Windows (/SUBSYSTEM:WINDOWS)
  • Set the project option Linker/Advanced/Entry Point to main. This will remove the crt library initialization code and since we don’t use any C standard library functions also the reference to the msvcrt dll.
  • Set Linker/Debugging/Generate Debug Info to No. This will remove the .pdb debug information file reference.
  • Set Linker/Manifest File/Generate Manifest to No. Now the manifest xml is removed.
  • Set Linker/Advanced/Randomized Base Address to No. We don’t need relocations for a normal non library project.

Compile the project again and the resulting exe file will now be 2.048 byte small and look like this:

Between the DOS stub and PE header you can find the undocumented Rich Signature from Microsoft, which is present in newer Visual Studio compiler versions and is not needed, so you could zero those bytes out.

Creating small executables with Qt Creator and MingW

Starting with an empty Plain C Project in Qt Creator IDE and gcc from MinGW as compiler, I will show you how to generate small binaries that are independent from MinGW dlls. At the writing of this article the app versions that I used were Qt Creator 2.6.2 with Qt 5.0.1 and gcc 4.7.2.

Replace the code of the main.c with following:

#include <windows.h>

void main()
{
  MessageBoxA(0, "Hello", "world!", MB_OK);
  ExitProcess(0);
}

Switch the build configuration in menu Projects from Debug to Release and compile the project (Ctrl + B is the default shortcut for this). This will result in a 9.728 byte big exe file. The file content, split in parts, looks like this:

This is the portable executable header, containing 8 section definitions (.text, .data, .rdata, .eh_fram, .bss, .idata, .CRT, .tls).

The code section is nearly as twice as huge as the one generated by Visual Studio compiler and of cause way more than we want inside our exe for calling 2 API functions.

In the import section you can see that it not only includes the Microsoft Visual C Run-Time Library, but also the MingW runtime.

Let’s pimp the project to remove all the stuff that we did not want included in the exe file:

  • Open the .pro file of your project and replace it with following:
CONFIG -= qt
DEFINES -= QT_LARGEFILE_SUPPORT UNICODE
SOURCES += main.c
QMAKE_CFLAGS += -fno-asynchronous-unwind-tables
QMAKE_LFLAGS += -static-libgcc -nostdlib
LIBS = -lkernel32 -lmsvcrt -luser32
  • If you try to build the project now you will get an linker error about undefined reference to `__main’. To fix this issue we just rename the main function in our c file:
#include <windows.h>

void __main()
{
  MessageBoxA(0, "Hello", "world!", MB_OK);
  ExitProcess(0);
}

Recompile the project and your compiled exe will have a size of 2.048 byte and look so fresh and so clean like this:

Creating the smallest possible Windows executable using assembly language

Using nasm, we can build the smallest possible native exe (without using a packer, dropper or anything like that) file that will work on all Windows versions. This is what one of the possible solution binary looks like:

The code for this little cutie:

IMAGEBASE equ 400000h

BITS 32
ORG IMAGEBASE
; IMAGE_DOS_HEADER
  dw "MZ"                       ; e_magic
  dw 0                          ; e_cblp

; IMAGE_NT_HEADERS - lowest possible start is at 0x4
Signature:
  dw 'PE',0                     ; Signature

; IMAGE_FILE_HEADER
  dw 0x14c                      ; Machine = IMAGE_FILE_MACHINE_I386
  dw 0                          ; NumberOfSections
user32.dll:
  dd 'user'                     ; TimeDateStamp
  db '32',0,0                   ; PointerToSymbolTable
  dd 0                          ; NumberOfSymbols
  dw 0                          ; SizeOfOptionalHeader
  dw 2                          ; Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE

; IMAGE_OPTIONAL_HEADER32
  dw 0x10B                      ; Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC
kernel32.dll:
  db 'k'                        ; MajorLinkerVersion
  db 'e'                        ; MinorLinkerVersion
  dd 'rnel'                     ; SizeOfCode
  db '32',0,0                   ; SizeOfInitializedData
  dd 0                          ; SizeOfUninitializedData
  dd Start - IMAGEBASE          ; AddressOfEntryPoint
  dd 0                          ; BaseOfCode
  dd 0                          ; BaseOfData
  dd IMAGEBASE                  ; ImageBase
  dd 4                          ; SectionAlignment - overlapping address with IMAGE_DOS_HEADER.e_lfanew
  dd 4                          ; FileAlignment
  dw 0                          ; MajorOperatingSystemVersion
  dw 0                          ; MinorOperatingSystemVersion
  dw 0                          ; MajorImageVersion
  dw 0                          ; MinorImageVersion
  dw 4                          ; MajorSubsystemVersion
  dw 0                          ; MinorSubsystemVersion
  dd 0                          ; Win32VersionValue
  dd 0x40                       ; SizeOfImage
  dd 0                          ; SizeOfHeaders
  dd 0                          ; CheckSum
  dw 2                          ; Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
  dw 0                          ; DllCharacteristics
  dd 0                          ; SizeOfStackReserve
  dd 0                          ; SizeOfStackCommit
  dd 0                          ; SizeOfHeapReserve
  dd 0                          ; SizeOfHeapCommit
  dd 0                          ; LoaderFlags
  dd 2                          ; NumberOfRvaAndSizes

; IMAGE_DIRECTORY_ENTRY_EXPORT
  dd 0                          ; VirtualAddress
  dd 0                          ; Size

; IMAGE_DIRECTORY_ENTRY_IMPORT
  dd IMAGE_IMPORT_DESCRIPTOR - IMAGEBASE ; VirtualAddress

Start:
  push  0                       ; = MB_OK - overlapps with IMAGE_DIRECTORY_ENTRY_IMPORT.Size
  push  world
  push  hello
  push  0
  call  [MessageBoxA]
  push  0
  call  [ExitProcess]

kernel32.dll_iat:
ExitProcess:
  dd impnameExitProcess - IMAGEBASE
  dd 0
kernel32.dll_hintnames:
  dd impnameExitProcess - IMAGEBASE
  dw 0

impnameExitProcess:             ; IMAGE_IMPORT_BY_NAME
  dw 0                          ; Hint, terminate list before
  db 'ExitProcess'              ; Name
impnameMessageBoxA:             ; IMAGE_IMPORT_BY_NAME
  dw 0                          ; Hint, terminate string before
  db 'MessageBoxA', 0           ; Name

user32.dll_iat:
MessageBoxA:
  dd impnameMessageBoxA - IMAGEBASE
  dd 0
user32.dll_hintnames:
  dd impnameMessageBoxA - IMAGEBASE
  dd 0

IMAGE_IMPORT_DESCRIPTOR:
; IMAGE_IMPORT_DESCRIPTOR for kernel32.dll
  dd kernel32.dll_hintnames - IMAGEBASE ; OriginalFirstThunk / Characteristics
world:
  db 'worl'                     ; TimeDateStamp
  db 'd!',0,0                   ; ForwarderChain
  dd kernel32.dll - IMAGEBASE   ; Name
  dd kernel32.dll_iat - IMAGEBASE ; FirstThunk

; IMAGE_IMPORT_DESCRIPTOR for user32.dll
  dd user32.dll_hintnames - IMAGEBASE ; OriginalFirstThunk / Characteristics
hello:
  db 'Hell'                     ; TimeDateStamp
  db 'o',0,0,0                  ; ForwarderChain
  dd user32.dll - IMAGEBASE     ; Name
  dd user32.dll_iat - IMAGEBASE ; FirstThunk

; IMAGE_IMPORT_DESCRIPTOR empty one to terminate the list all bytes after the end will be zero in memory
times 7 db 0                    ; fill up exe to be 268 byte, smallest working exe for win7 64bit

Save the file as tinyexe.asm and assemble it with:

nasm -f bin -o tinyexe.exe tinyexe.asm

Some short facts about this binary:

  • As Ange Albertini found out, the smallest possible universal exe that works for all Windows version up to Windows 7 64 bit (Still needs to be tested on Windows 8 tho) is 268 byte
    There is still room for optimization in this code (like moving code into header, using smaller opcodes for it or exiting the program without the call to ExitProcess), but the resulting binary can’t be smaller anyway
  • Some fields in the header can be abused to store code or data, I use them to store the 2 imported dll names. Peter Ferrie did some nice work on figuring the details out of what fields can be reused
  • Some lists like the import descriptor one use an empty entry to mark the end of the list, so we can reuse the extra length definition of this list for other data if the value inside this field is high enough to point after the end of such lists
  • The imported dlls can be imported without using the .dll at the end of the string
  • We don’t need a linker for this project, even the assembler does not have to do much work beside resolving symbolic names and calculating the memory locations and translating the push and call instruction to opcode
  • The binary works when run with Wine, whether the exe works on Win 9x and Win 2k I still need to verify

Converting a DOS intro to JavaScript/HTML5

One day I had the idea of converting my fr29b DOS intro to JavaScript. Using the canvas element of HTML5, this should be an easy task and offer a good performance as well. To make the port as similar as possible, the standard VGA DOS palette should be supported. Drawing the ARGB values into the canvas can be speed up by using JavaScript typed arrays with an int32 view to write into the image data buffer. The DOS palette can be found in DOSBox source code and converted to a JavaScript usable format with this small code:

#include <stdio.h>

static unsigned char vga_palette[256][3]= {
  // put array content from file DOSBox source file src\ints\int10_modes.cpp here
};

int main() {
  for (int i = 0; i < 256; i++)
    printf("0xFF%02X%02X%02X,\n", vga_palette[i][0], vga_palette[i][1], vga_palette[i][2]);
}

The initial framework JavaScript code:

<canvas height="200" id="vga" width="320">
<script type="text/javascript">
vgapalette=[
0xFF000000,
0xFF00002A,
0xFF002A00,
// ... full palette that was giving out by the conversion tool here
];

var canvas = document.getElementById('vga');
var ctx = canvas.getContext('2d');
var imageData = ctx.getImageData(0, 0, 320, 200);
var buf = new ArrayBuffer(imageData.data.length);
var buf8 = new Uint8ClampedArray(buf);
var buf32 = new Uint32Array(buf);
var dosvmem = new ArrayBuffer(320*200);
for (i = 0; i < 320*200; i++) { // init screen with black
  buf32[i] = 0xFF000000;
  dosvmem[i] = 0;
}

The DOSBox VGA palette is given in 6-bit RGB and needs to be converted to modern RGB 8-bit:

for (i = 0; i < 256; i++) {
  color = vgapalette[i];
  r = (color >> 16) & 0xff;
  r = (r << 2) | (r >> 4)
  g = (color >> 8) & 0xff;
  g = (g << 2) | (g >> 4)
  b = (color >> 0) & 0xff;
  b = (b << 2) | (b >> 4)
  colornew = (r << 16) + (g << 8) + (b << 0) + 0xFF000000;
  vgapalette[i] = colornew;
}

The main loop and the effect itself:

setInterval(function() {
  offset = Math.floor(Math.random() * 103981) & 0xffff; // generate random offset to screen
  for (i = 0; i < 140; i++, offset += 180) {
    for (j = 0; j < 140; j++, offset++) {       if (offset > 320*200) { // offset is outside of screen?
        if (offset <= 0xffff { // no 16 bit overflow?
          continue;
        }
        offset -= 0xffff; // simulate overflow
      }
      colorindex = (((dosvmem[offset] + 1) & 0xff) | 0x80); // increase palette index
      dosvmem[offset] = colorindex; // store the new index
      color = vgapalette[colorindex]; // get argb color value from palette
      buf32[offset] = color; // set pixel on screen
    }
  }

  imageData.data.set(buf8);
  ctx.putImageData(imageData, 0, 0);
}, 1000 / 35); // 35 fps

Analysis of the 624 (Six-2-Four) packer

The 624 packer is a executable packer that got released in 1997 by Kim Holviala. It only supports DOS .com files and was targeted to compress 4kb demoscene intros but offers a decent compression of files from 1 kb to 20 kb size.

  • Uses LZSS (Lempel–Ziv–Storer–Szymanski) compression algorithm
  • The assembly unpacking stub is 127 byte small
  • Fixed length huffmann codes are used to store the length and offset of a match
  • Packed data is stored as a bit stream. This allows for a shorter unpacker stub and higher compression ratio but slightly slower decompression
  • 1 byte matches are stored using 6 bit, 1 to mark a match, 1 to store the length as a marker for 1 byte length and the remaining 4 bit to encode the offset of the match, therefor up to 16 byte backwards in the output buffer
  • The storing of output bytes is using a byte addressing instruction. This allows the compressor to use RLE to compress a run of a literal by storing offset 1 and the amount of bytes to copy as match length

Later someone released a rewrite of this packer in assembly as version 1.1. In this version the unpacking stub had been optimized to 116 byte and the compression was notable faster.

Ideas to improve the compression ratio:

  • With the current implementation the first byte is always a literal, therefor the bit in front to mark it as literal is not needed. The unpacking stub could jump at beginning of execution directly to the code to copy the literal to the output buffer
  • A match will probably be followed by a literal. The bit to mark the literal can be skipped and the unpacker adjusted to expect a literal after a match without changing the size of the unpacker stub
  • A run of literals could be encoded with the length of it. The following compressed flag of the match following the literal run would not need to be saved
  • Huffman codes can be replaced by [gamma encoding](https://en.wikipedia.org/wiki/Universal_code_(data_compression)), which would result in a smaller unpacker stub but may depend on the input file to compress to improve the overall compression ratio

The packer versions to download:

Back To Top