comrade's bureau


comments?

Flat Assembler Extras

These page contains various include files, interesting macros, and modifications to FASM.

Sections

  1. Macros and Include Files
  2. IDE Modifications
  3. Gems
    1. Code Obfuscation
    2. Self-Encrypting Code
  4. Past Versions

Macros and Include Files

The base package for FASM contains many useful macros to construct Windows resource sections, import tables, etc. The include files also cover the base of the Win32 platform. To complement this base set, I created another package that contains more macros, and definitions for more Win32 features. You can download it here.

Extract the package to the root of your FASM installation.

The package also contains INCLUDE/EQUATES/TLHELP32.INC, which is a hand-translated include file of the Toolhelp APIs (tlhelp32.h).

The INCLUDE/WIN32AM.INC and INCLUDE/WIN32WM.INC are my minimal include files. These are virtually identical to the INCLUDE/WIN32A.INC and INCLUDE/WIN32W.INC files in the base FASM package, except mine don't automatically include everything under INCLUDE/EQUATES/. This speeds up compilation.

The INCLUDE/MACRO/macros.inc is a macro file with many useful macros for debugging, such as quickly showing a message box with some integer value. Here is a complete example:

; using macros
; 04.07.2008

format PE GUI 4.0
entry start

include "%include%/win32a.inc"
include "%include%/macro/macros.inc"    ; include our magic macros file

section ".code" code readable executable
start:
        push    ebx esi edi

        ;
        ; Show a fixed string messagebox.
        ;
        showmsg "Hello!"

        ;
        ; Show a simple integer.
        ;
        mov     ebx,-5
        showint "value of ebx in decimal",ebx
        showuint "value of ebx in unsigned decimal",ebx
        showhex "value of ebx in hexadecimal",ebx

        ;
        ; Show a string pointer.
        ;
        mov     ebx,Hello
        showstr "string pointed to by ebx",ebx
        msgbox  ebx

        ;
        ; Show a custom-formatted message.
        ;
        mov     ebx,Hello
        mov     esi,10
        mov     edi,17
        showfmt "ebx is '%s',esi is %u, and edi is %u",ebx,esi,edi

        ;
        ; Set the last error to 'Access denied.'
        ;
        stdcall [SetLastError],5
        lasterr

        ;
        ; The following macros generate simple code to convert a 7-bit ASCII character to uppercase/lowercase.
        ;
        mov     al,'a'
        ucase   al      ; al is now 'A'
        lcase   al      ; al is now back to 'a'


        pop     edi esi ebx

        stdcall [ExitProcess],0

section ".data" data readable writeable import
        library kernel32,"kernel32.dll",user32,"user32.dll"
        include "%include%/api/kernel32.inc"
        include "%include%/api/user32.inc"

        ;
        ; Use the DATE and TIME variables that were defined by macros.inc to record the date and time this file
        ; was compiled at. Credits to Privalov for the date conversion macros.
        ;
        Hello   db      "hallo! this was compiled at: ",DATE," ",TIME,0

Running this code will produce a series of message boxes displaying the needed values.

IDE Modifications

This section contains some modifications I made to the FASM IDE for Windows (FASMW.EXE). Notably:

  1. Add configurable, external debugger support. You configure the path to your debugger, press F8, and the IDE will automatically compile the file, and launch the debugger.
  2. Display the name of the file being currently editted in the program's title bar.
  3. Default all "Save modified file?" message boxes to 'Yes'. For some reason, the author decided there are times when you don't want to save your changes by default. This differs from other applications which always pick the safest option: save your work.
  4. Show the length of currently selected text in the status bar. This is useful in measuring string lengths quickly, and then using them somewhere in the code.
  5. Map Ctrl-W to close file. This is a common keyboard shortcut that FASMW IDE does not have.
  6. Unmap Escape from closing the file. I frequently press Esc to close some dialog, and end-up closing the IDE by mistake.
  7. Change the GUI font to Tahoma, instead of Win95-esque MS Sans Serif.

You can download the modified FASMW.EXE binary file here (55 KB), version 0.93.15.1 (that is, the 0.93.15.0 that comes with FASM 1.67.26, plus these modifications).
Alternatively, you can compile it yourself. Get the base FASMW 1.67.26 distribution, and apply the following diff file using GNU's patch utility. The patch is relative to FASM/SOURCE, so apply the patch from that directory, like so patch.exe -p3 <fasmw-0.93.15.1.patch. After applying the patch, simply recompile SOURCE/IDE/FASMW/FASMW.ASM.

Gems

This section contains various gems and tricks possible with FASM, mostly thanks due its advanced macro capabilities.

Code Obfuscation

This trick involves creating macros that override the default behaviour of various common instructions, such as jmp, call, add, etc. The overriden instruction preserves the functionality of the original instruction, with some extra junk that makes the disassembly much harder to read and analyze, even for advanced disassemblers such as IDA.

Consider the following macro:

macro add dest,src {
    local .._add,.._over,.._quit
    jmp  .._over
    db $E9
  .._add:
    add dest,src
    jmp .._quit
  .._over:
    jmp .._add
    db $EB
  .._quit:

In this macro, we create a junk jmp ($E9) opcode just before the actual add instruction. When a disassembler processes this code, it will miss the add instruction, and actually disassemble some junk jump that makes no sense. Obviously, the code size blows up and performance decreases with this kind of substitution macro.

I originally pioneered this technique as part of the protection in Lokomotiv trainer engine project. Here is the full set of substitution macros that I created for it:

macro jmp dest {
    push dest
    retn
    db $E9
}
macro call dest {
    local ..ret
    push ..ret
    jmp  dest
    ..ret:
}
macro mov dest,src {
    local .._mov,.._over,.._quit
    jmp  .._over
    db $EB
  .._mov:
    mov dest,src
    jmp .._quit
  .._over:
    jmp .._mov
    db $74
  .._quit:
}
macro add dest,src {
    local .._add,.._over,.._quit
    jmp  .._over
    db $E9
  .._add:
    add dest,src
    jmp .._quit
  .._over:
    jmp .._add
    db $EB
  .._quit:
}
macro sub dest,src {
    local .._sub,.._over,.._quit
    jmp  .._over
    db $75
  .._sub:
    sub dest,src
    jmp .._quit
  .._over:
    jmp .._sub
    db $0F,$85
  .._quit:
}
macro cmp dest,src {
    local .._cmp,.._over,.._quit
    jmp  .._over
    db $0F,$84
  .._cmp:
    cmp dest,src
    jmp .._quit
  .._over:
    jmp .._cmp
    db $7A
  .._quit:
}

Simply paste these macros into a separate file and include it before your code, and then assemble your program with FASM as usual. Disassemble the output file to see the abomination.

Self-Encrypting Code

This is another technique I created as part of the protection for the Lokomotiv trainer engine project in early 2004. Coincidentally, someone had the same idea on the FASM board a couple of months later.

This technique involves FASM's ability to manipulate the bytes of the code it had already assembled. In this case, we use a simple cryptor to encrypt a chunk of assembled code during compile time. At run-time, we run a short loop that decrypts the code in memory.

Consider a simple Hello World message box, with the encrypting macro setup:

; selfencrypt
; 04.07.2008

format PE GUI 4.0
entry start

include "%include%/win32a.inc"

;
; This is the encryption macro.
; It is a simple XOR with 0xAA (10101010 in binary).
;
macro encrypt dstart,dsize {
    local ..char,..key,..shift
    repeat dsize
        load ..char from dstart+%-1
        ..char = ..char xor $AA
        store ..char at dstart+%-1
    end repeat
}

section ".code" code readable writeable executable
start:
        ;
        ; This will be the only non-encrypted part of the code.
        ; Here we will decrypt the code at run-time.
        ;
        mov     edx,real_start
        xor     eax,eax
        mov     ecx,code_size
@@:     xor     byte [edx],$AA
        inc     edx
        loop    @B

real_start:
        ;
        ; Everything from here on will be encrypted.
        ;
        stdcall [MessageBox],0,HelloWorld,HelloWorld,MB_ICONASTERISK

        stdcall [ExitProcess],0

        ;
        ; Encrypt everything from real_start to here.
        ;
        display "Encrypting code... "
        code_size = $ - real_start
        encrypt real_start,code_size
        display "done",13,10

section ".data" data readable writeable import
        library kernel32,"kernel32.dll",user32,"user32.dll"
        include "%include%/api/kernel32.inc"
        include "%include%/api/user32.inc"

        HelloWorld      db      "Hello World!",0

One particular thing to note is that the .code section is marked as writeable. This is needed so the code can be decrypted and written back at run-time.

You can find a more elaborate encryption algorithm as part of Lokomotiv trainer engine.

Past Versions

This sections contains an archive of past versions of FASM. The author used to keep a limited archive here, but it is no longer maintained. Here is mine (thanks to FASM forum members for helping me build it):

Name Description Date Size
fasmw16727.zip 2008-07-13 820.3 KB
fasm16727.zip 2008-07-13 272.2 KB
fasm-1.67.27.tar.gz 2008-07-12 190.1 KB
fasm-1.67.27.tgz 2008-07-12 182.4 KB
fasmw16726.zip 2008-01-29 819.9 KB
fasm16726.zip 2008-01-29 271.8 KB
fasm-1.67.26.tar.gz 2008-01-28 186.2 KB
fasm-1.67.26.tgz 2008-01-28 180.3 KB
fasm-1.67.25.tar.gz 2007-12-31 181.5 KB
fasm-1.67.25.tgz 2007-12-31 178.2 KB
fasmw16725.zip 2007-12-31 826.6 KB
fasm16725.zip 2007-12-31 275.9 KB
fasm-1.67.24.tgz 2007-12-05 178.1 KB
fasm-1.67.24.tar.gz 2007-12-05 181.4 KB
fasmw16724.zip 2007-12-05 826.4 KB
fasm16724.zip 2007-12-05 275.8 KB
fasmw16723.zip 2007-11-11 823.2 KB
fasm-1.67.23.tgz 2007-11-10 176.0 KB
fasm-1.67.23.tar.gz 2007-09-08 178.9 KB
fasm16723.zip 2007-09-08 272.7 KB
fasmw16722.zip 2007-08-06 822.6 KB
fasm16722.zip 2007-08-06 272.2 KB
fasm-1.67.22.tar.gz 2007-08-06 178.4 KB
fasm-1.67.22.tgz 2007-08-06 175.5 KB
fasmw167.zip 2007-03-11 821.5 KB
fasmw166.zip 2006-06-02 764.1 KB
fasmw165.zip 2006-02-21 757.4 KB
fasmw164-8.zip 2005-12-09 745.8 KB
fasm164.zip 2005-12-09 175.4 KB
fasmw164-9.zip 2005-10-28 745.8 KB
fasm-1.6.4-libc.tgz 2005-08-14 106.2 KB
fasm162.zip 2005-06-27 165.6 KB
fasm160.zip 2005-03-15 162.0 KB
fasm159.zip 2005-02-20 191.5 KB
fasmw158.zip 2005-02-12 638.9 KB
fasm158.zip 2005-02-12 154.1 KB
fasm157.zip 2005-01-19 153.1 KB
fasm156.zip 2004-11-24 154.2 KB
fasm155.zip 2004-09-12 155.9 KB
fasm154-8.zip 2004-08-18 152.9 KB
fasmw154-7.zip 2004-08-04 586.5 KB
fasm-1.54-7.tar.gz 2004-08-04 142.4 KB
fasm154-7.zip 2004-08-04 153.2 KB
fasmc154-7.zip 2004-08-04 154.7 KB
fasm-1.54-5.tar.gz 2004-08-03 142.2 KB
fasmw154-5.zip 2004-08-03 586.4 KB
fasm154-5.zip 2004-08-03 153.1 KB
fasmc154-5.zip 2004-08-03 154.6 KB
fasm153.zip 2004-07-22 151.0 KB
fasm152-26.zip 2004-05-06 150.8 KB
fasmw152-26.zip 2004-05-06 580.8 KB
fasmw152.zip 2004-04-27 572.8 KB
fasm152-24.zip 2004-04-27 150.9 KB
fasmc152.zip 2004-04-27 152.3 KB
fasm-1.52.tar.gz 2004-04-21 140.1 KB
fasm-1.51.tar.gz 2004-02-16 139.2 KB
fasmc151.zip 2004-02-16 150.5 KB
fasmw151.zip 2004-02-16 562.0 KB
fasm151-2.zip 2004-02-16 148.9 KB
fasm151.zip 2004-01-31 148.7 KB
fasm-1.43.tar.gz 2003-12-29 126.5 KB
fasm-1.50.tar.gz 2003-12-08 136.1 KB
fasm150.zip 2003-12-08 146.9 KB
fasmw150.zip 2003-12-08 557.2 KB
fasmc150.zip 2003-12-08 148.4 KB
fasmw149.zip 2003-10-14 551.3 KB
fasmc149.zip 2003-10-14 143.7 KB
fasm149.zip 2003-10-14 142.4 KB
fasm-1.49.tar.gz 2003-10-13 131.8 KB
fasmw149-090.zip 2003-09-14 548.2 KB
fasm148.zip 2003-08-25 236.8 KB
fasm-1.47.tar.gz 2003-06-28 128.2 KB
fasmw147.zip 2003-06-28 544.2 KB
fasm147.zip 2003-06-28 234.9 KB
fasm146.zip 2003-04-09 234.6 KB
fasmw146.zip 2003-04-09 542.3 KB
fasm-1.46.tar.gz 2003-04-08 125.8 KB
fasmw145.zip 2003-02-09 571.2 KB
fasm145-2.zip 2003-02-09 234.3 KB
fasm-1.45.tar.gz 2003-02-08 125.9 KB
fasm145.zip 2003-02-06 234.4 KB
fasm144.zip 2003-01-19 234.5 KB
fasm143-26.zip 2003-01-10 233.7 KB
fasmw143.zip 2003-01-08 357.6 KB
fasm143-16.zip 2002-12-30 262.2 KB
fasm-1.42.tar.gz 2002-12-04 120.3 KB
fasmw142.zip 2002-12-04 170.3 KB
fasm142.zip 2002-12-04 251.9 KB
fasmw141-045.zip 2002-11-22 170.3 KB
fasm141.zip 2002-11-21 251.6 KB
fasmw141-041.zip 2002-11-14 168.5 KB
fasm141-19.zip 2002-11-14 251.4 KB
fasm-1.41.tar.gz 2002-11-14 120.1 KB
fasm140.zip 2002-08-21 201.1 KB
fasm140-20.zip 2002-08-21 201.1 KB
fasm140.tar.gz 2002-08-20 82.2 KB
fasm139.zip 2002-07-09 203.5 KB
fasm139.tar.gz 2002-07-09 89.1 KB
fasm137.zip 2002-06-12 195.7 KB
fasm136.zip 2002-05-23 169.7 KB
fasm135.zip 2002-05-06 167.4 KB
fasm134.zip 2002-04-19 168.5 KB
fasm132.zip 2002-03-06 167.2 KB
fasm131.zip 2002-02-03 166.0 KB
fasm120.zip 2001-11-18 145.0 KB
fasm114.zip 2001-10-17 142.7 KB
fasm113.zip 2001-08-23 142.3 KB
fasm111.zip 2001-06-25 118.7 KB
fasm110.zip 2001-03-22 119.0 KB
fasm130.zip 2001-01-18 164.6 KB
fasm109.zip 2001-01-04 114.7 KB
fasm108-repaired.zip 2000-11-16 116.2 KB
fasm108-corrupt.zip 2000-11-16 114.3 KB
fasm107.zip 2000-10-19 114.1 KB
fasm106.zip 2000-08-23 109.7 KB
fasm105.zip 2000-08-16 108.8 KB
fasm104.zip 2000-08-10 108.1 KB
fasm103.zip 2000-07-15 61.5 KB
fasm102.zip 2000-07-02 62.9 KB
fasm101.zip 2000-06-27 60.8 KB
fasm10.zip 2000-05-28 60.8 KB

Comments

[an error occurred while processing this directive]