FASM: Flat Assembler, also known as "FASM": Sample Code

Goal: Enrich own understanding of the Flat Assember (FASM) code constructs to enhance malware analysis and forward-engineering skills especially with PE files. I find it to be extremely helpful to have code samples ready to use/analyze.
SourceBetamaster

Why FASM?
FASM is a 32-bit, open-source, cross-platform assembler, targeting the IA-32 and x86-64 architectures (in addition, FASMARM – in unofficial port of FASM, targets the ARM architecture). It is very lightweight, fast, and rather simple to leverage in Windows API programming challenges.

I. Simple Application: Hello World

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
format PE console
entry start
 
include 'win32a.inc'
 
;======================================
section '.data' data readable writeable
;======================================
 
hello_newline    db "Hello World!",10,0
hello_no_newline db "Hello World! (without a new line)",0
 
;=======================================
section '.code' code readable executable
;=======================================
 
start:
 
        ccall   [printf],hello_newline      ; Print 'Hello World!' and start a new line.
        ccall   [printf],hello_no_newline   ; Print 'Hello World!' without starting a new line.
 
        ccall   [getchar]                   ; I added this line to exit the application AFTER the user pressed any key.
        stdcall [ExitProcess],0             ; Exit the application
 
;====================================
section '.idata' import data readable
;====================================
 
library kernel,'kernel32.dll',\
        msvcrt,'msvcrt.dll'
 
import  kernel,\
        ExitProcess,'ExitProcess'
 
import  msvcrt,\
        printf,'printf',\
        getchar,'_fgetchar


II. Create a process


01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
format PE GUI 4.0
entry start
 
include 'win32a.inc'
 
start:
 invoke CreateProcessA,txt_location,0,0,0,0,CREATE_NEW_CONSOLE,0,0,StartupInfo,ProcessInfo
 call [ExitProcess]
 
; Custom Data: Contains the location of notepad.exe, StartupInfo and ProcessInfo:
section '.data' data readable writeable
 txt_location db 'C:\Windows\System32\notepad.exe',0
 StartupInfo STARTUPINFO
 ProcessInfo PROCESS_INFORMATION
 
; Imported functions and corresponding names of DLL files:
section '.idata' import data readable writeable
 library kernel,'KERNEL32.DLL'
 
 import kernel,\
 CreateProcessA, "CreateProcessA",\
 ExitProcess,'ExitProcess'


III. Kill a process

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
format PE GUI 4.0
entry start
 
include 'win32a.inc'
 
;================== code =====================
section '.code' code readable executable
;=============================================
 
start:
        invoke GetCurrentProcess                                                ; Retrieve a pseudo handle for current process
        invoke OpenProcessToken,eax,TOKEN_QUERY_TOKEN_ADJUST_PRIVILEGES,phToken ; Open access token associated with this process
        invoke LookupPrivilegeValue,0,Privilege ,pLocalId                       ; Retrieve the locally unique identifier (LUID)
        mov    [PrivilegeCount],1                                               ; [PrivilegeCount] = 1
        mov    [Attributes],2                                                   ; [Attributes]     = 2
        invoke AdjustTokenPrivileges,[phToken],0,PrivilegeCount ,0,0,0          ; Enable privileges on our token
 
        mov    [prcs.dwSize],sizeof.PROCESSENTRY32                              ; Store the required size of PROCESSENTRY32 in prcs.dwSize
        invoke CreateToolhelp32Snapshot, TH32CS_SNAPPROCESS, 0                  ; Take a snapshot of the specified processes (get all running processes)
        mov    [hSnapshot], eax                                                 ; Save the snapshot handle
        invoke Process32First,[hSnapshot],prcs                                  ; Retrieve information about the first process encountered in our system snapshot
.loop:
        mov    edi,PrcList                                                      ; EDI = filename of process we want to kill
        invoke StrStrI,prcs.szExeFile, edi                                      ; Compare the current process name with the one we want to kill
        cmp    eax,0                                                            ; - || -
        je     .next                                                            ; Jump = Not equal, continue with the next process
        call   kill                                                             ; Else : Kill the process
.next:
        invoke Process32Next,[hSnapshot],prcs                                   ; Retrieve the next process in our snapshot
        cmp    eax,0                                                            ; Check if there are still processes we didn't check
        jne    .loop                                                            ; Jump = Continue the loop with the current process
        invoke ExitProcess,0                                                    ; Else : No more processes. Exit.
kill:
        invoke OpenProcess,PROCESS_TERMINATE,0,[prcs.th32ProcessID]             ; Open the process with terminate privileges
        invoke TerminateProcess,eax,0                                           ; Terminate it (Kill process)
        retn                                                                    ; And return (= exit as well)
 
;=================== data ====================
section '.data' data readable writeable
;=============================================
 
TOKEN_QUERY_TOKEN_ADJUST_PRIVILEGES =28h
TH32CS_SNAPPROCESS = 2
 
struct PROCESSENTRY32
        dwSize dd ?
        cntUsage dd ?
        th32ProcessID dd ?
        th32DefaultHeapID dd ?
        th32ModuleID dd ?
        cntThreads dd ?
        th32ParentProcessID dd ?
        pcPriClassBase dd ?
        dwFlags dd ?
        szExeFile db 260 dup(?)
ends
 
PrivilegeCount dd ?
pLocalId       dd ?
Attributes     dd ?
phToken        dd ?
hSnapshot      dd ?
prcs           PROCESSENTRY32
 
PrcList        db 'calc.exe',0
Privilege      db 'SeDebugPrivilege',0
 
;=============================================
section '.idata' import data readable
;=============================================
 
library         kernel32,'KERNEL32.DLL',\
                advapi32,'ADVAPI32.DLL',\
                shell32,'SHELL32.DLL'
 
include 'API\kernel32.inc'
include 'API\advapi32.inc'
include 'API\shell32.inc'


III. WriteProcessMemory

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
format PE GUI 4.0
entry start
 
include 'win32a.inc'
 
;================== code =====================
section '.code' code readable executable
;=============================================
 
proc start
 
        invoke FindWindow, NULL, WindowTitle           ; Find the window titled 'Notepad'
        test eax,eax                                   ; Test whether a window with that title was found or not
        jnz .ju1                                       ; Don't jump = The window was not found
        invoke MessageBox,0, message1, caption, MB_OK  ; - Display an error message (Window not found)
        jmp .exit                                      ; - Exit the application
.ju1:                                                  ; Jumped     = The window was found
        invoke GetWindowThreadProcessId, eax, ProcID   ; Get the ProcessID via the window handle
        invoke OpenProcess, 0x1F0FFF, FALSE, [ProcID]  ; Open the process using PROCESS_ALL_ACCESS (0x1F0FFF) and get a handle
        mov dword[ProcHandle],eax                      ; Save the handle
 
        ; VirtualAllocEx: Reserves/commits a region of memory within the virtual address space of out target process
        ; We should do this in order to avoid potential access violations (which might cause crashes)
        invoke VirtualAllocEx,dword [ProcHandle], 0, patchSize, MEM_COMMIT, PAGE_READWRITE
        cmp eax, 0                                     ; EAX == 0 : Failed to reserve the memory region
        jnz .cont                                      ; EAX != 0 : Continue with further steps
        invoke MessageBox,0, message4, caption, MB_OK  ; Display an error: VirtualAllocEx failed to reserve the memory region
        jmp .exit                                      ; Exit the application
.cont:
        invoke WriteProcessMemory, dword[ProcHandle], dword[startAddress], patchBytes, patchSize, patchResult
        cmp [patchResult],patchSize                    ; Compare the number of patched bytes with the length of our new bytes
        je .ju2                                        ; Don't jump = Failed to patch the target
        invoke MessageBox,0, message3, caption, MB_OK  ; - Display an error message (An error occured)
        jmp .exit                                      ; - Exit the application
.ju2:                                                  ; Jumped     = Target patched successfully.
        invoke MessageBox,0, message2, caption, MB_OK  ; Display: The target has been patched successfully
.exit:                                                 ; Jumper: Here we're going to exit our application
        invoke  ExitProcess, 0                         ; ExitProcess
 
endp
 
;=================== data ====================
section '.data' data readable writeable
;=============================================
 
WindowTitle     db 'Notepad', 0                        ; Holds the window title   of the target application
ProcID          dd ?                                   ; Holds the process ID     of the target application
ProcHandle      db ?                                   ; Holds the process handle of the target application
 
caption         db 'Information', 0                    ; The caption displayed in all MessageBoxes
message1        db 'Unable to find the window', 0      ; Message: Window not found
message2        db 'Patched successfully',0            ; Message: Target patched successfully
message3        db 'Patching: An error occured',0      ; Message: An error occured while patching the target
message4        db 'VirtualAllocEx failed',0           ; Message: Failed to successfully execute VirtualAllocEx
 
startAddress    dd 0x00401090                          ; The memory address we're starting to write from
patchBytes      db 0x2F,0x66                           ; These bytes will be written into the memory of our target executable
patchSize       =  $ - patchBytes                      ; Holds the number of bytes we're going to write
patchResult     dd ?                                   ; Holds the number of successfully written bytes
 
;=============================================
section '.idata' import data readable
;=============================================
 
library         kernel32,'KERNEL32.DLL',\
                user32,'USER32.DLL'
 
import          kernel32,\
                ExitProcess,'ExitProcess',\
                OpenProcess,'OpenProcess',\
                VirtualAllocEx, "VirtualAllocEx",\
                WriteProcessMemory,'WriteProcessMemory'
 
import          user32,\
                FindWindow,'FindWindowA',\
                GetWindowThreadProcessId,'GetWindowThreadProcessId',\
                MessageBox,'MessageBoxA'


IV. Copy a file


1
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
format PE GUI 4.0
entry start
 
include 'win32ax.inc'
 
;================== code =====================
section '.code' code readable executable
;=============================================
 
proc start
        mov [lpFileOp.wFunc],FO_COPY             ; We want the shell to copy a file
        mov [lpFileOp.fFlags],FOF_SILENT         ; .. silently
        mov [lpFileOp.pFrom],SzFileFrom          ; The file which is going to be copied
        mov [lpFileOp.pTo],SzFileTo              ; The name of the new file
 
        invoke SHFileOperationA,lpFileOp         ; Execute the operation
 
        invoke ExitProcess,NULL                  ; Exit this program
endp
 
;=================== data ====================
section '.data' data readable writeable
;=============================================
 
FO_COPY    = 2
FOF_SILENT = 4
SzFileFrom db 'source.txt',0
SzFileTo   db 'target.txt',0
 
struct  SHFILEOPSTRUCT
        hWnd dd ?
        wFunc dd ?
        pFrom dd MAX_PATH
        pTo dd MAX_PATH
        fFlags dw ?
        fAnyOperationsAborted dd ?
        hNameMappings dd ?
        lpszProgressTitle dd ?
ends
 
lpFileOp SHFILEOPSTRUCT
 
;=============================================
section '.idata' import data readable
;=============================================
 
library         kernel32,'KERNEL32.DLL',\
                shell32,'SHELL32.DLL'
 
import          kernel32,\
                ExitProcess,'ExitProcess'
 
import          shell32,\
                SHFileOperationA,'SHFileOperationA'

V.  Read a file

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
format pe console 4.0
include 'WIN32AX.INC'
 
.data
        FileTitle db 'file.txt',0
        hFile dd ?
        nSize dd ?
        lpBytesRead dd ?
        lpBuffer rb 8192
 
        MessageBoxCaption db 'Output:',0
.code
        main:
        invoke  CreateFile, FileTitle, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ; Open the file (to get its handle)
        ; TODO: TestApiError
        mov [hFile], eax ; Save the file's handle to hFile
        invoke  GetFileSize, [hFile], 0 ; Determine the file size
        ; TODO: TestApiError
        mov [nSize], eax ; Save the file size given by EAX
        invoke  ReadFile, [hFile], lpBuffer, [nSize], lpBytesRead, 0 ; Now read the full file
        ; TODO: TestApiError
        invoke CloseHandle, [hFile] ; Handle should be closed after the file has been read
        invoke MessageBox, NULL, addr lpBuffer, addr MessageBoxCaption, MB_OK ; Easy way of outputing the text
        invoke  ExitProcess, 0
 
.end main

VI. Write a file

01
02
03
04
05
06
07
08
09
10
11
12
13
14
format pe console 4.0
include 'WIN32AX.INC'
 
.data
 buf db 'TEST'
 bufsize = $ - buf
 byteswritten dd ?
.code
 main:
 invoke  CreateFile, 'test.txt', GENERIC_WRITE, 0, 0, 4, FILE_ATTRIBUTE_NORMAL, 0
 invoke  WriteFile, eax, buf, bufsize, byteswritten, 0
 invoke  ExitProcess, 0
 
.end main

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s