Warning: INSERT command denied to user 'dbo292345962'@'74.208.16.27' for table 'watchdog' query: INSERT INTO watchdog (uid, type, message, variables, severity, link, location, referer, hostname, timestamp) VALUES (0, 'php', '%message in %file on line %line.', 'a:4:{s:6:\"%error\";s:12:\"user warning\";s:8:\"%message\";s:398:\"INSERT command denied to user 'dbo292345962'@'74.208.16.27' for table 'captcha_sessions'\nquery: INSERT into captcha_sessions (uid, sid, ip_address, timestamp, form_id, solution, status, attempts) VALUES (0, 'd50b20fb0f8e7ab727d736c117215392', '54.198.94.76', 1414013961, 'comment_form', 'dc5a9a7f1680f824624b66b7be83e9cd', 0, 0)\";s:5:\"%file\";s:62:\"/homepages/25/d199835659/htdocs/ID/modules/captcha/captcha.inc\";s:5:\"%line\";i:99;} in /homepages/25/d199835659/htdocs/ID/includes/database.mysql.inc on line 135
Introduction to MASM32 | Inferno Development

Introduction to MASM32

ASM is machine language that your computer reads with all computer programs. Every program that is compiled from any language such as C++ or Delphi is then converted to PC ASM through your compiler. PC ASM is what your CPU reads and it is quite difficult to read; however, with MASM32 you can code ASM in a similar fashion to C++ but without the complexity and hassle of PC ASM that your processor reads.

In ASM the PC has registers which are segments of memory that your CPU uses to handle memory. There is also stack data, and of course hard disk and RAM memory. The advantage of ASM is that it can work directly with memory and is considered the fastest type of code as long as it is coded correctly. By contrast, it also makes it a very difficult language, but we will try and simplify the process in this MASM32 Tutorial.

We won't delve into too much detail about MASM's internal workings and how ASM is interpreted by the computer, because the complexity can confuse many people. The basic understanding is that ASM commands are converted into simple electronic signals by your CPU that handle memory.

Getting Started

If you want to try out the examples in this tutorial, I recommend downloading RadAsm from http://www.radasm.com/ . Download the IDE pack, install it, and then download the Programming pack and install that too. Before you try and compile download the MASM32 compiler at the top of the page. Install MASM32 compiler, and then adjust your RadAsm settings so that RadAsm knows the locations of the MASM32 directories.

Here's the basic skeleton of a MASM program:
Skeleton:

.386
.model flat,stdcall
option casemap:none
// the model of your program will usually be flat, stdcall
// There is stdcall syntax and C syntax of summoning functions
// the stdcall syntax means you call your program arguments from
// RIGHT to LEFT rather than LEFT to RIGHT which is the C syntax.
.data
// This is your initialized variables that you will use.
// The format is: NameOfVariable db "Message",0
// the comma 0 is the null terminator indicating end of the message.
.data?
// This is your uninitialized variables that you will use.
.const
// Constant variables example: BUFFER_SIZE   equ 1024
.code
 start:
// Your code and everything goes in here.
 end start

The Registers:
eax -> This is the standard register that you will mostly be using.
ecx -> This is a counter register which is used in loops.

Comments

  ; The semicolon ; indicates a comment (to the right), which is // in C++ or other languages.

Basic Commands

  mov [destination],[source]
  ; This is a copy function, it copies from:
  ; Either memory to register
  ; register to memory
  ; register to register
  ; IT CANNOT COPY FROM MEMORY TO MEMORY. so don't try mov hInst, hInst2
  ; because they are both variables.
  ; example: mov eax,hInst ;copies the value of hInst to the register eax.
  invoke [function][arguments,]
  ; Calls a function with arguments
  call [function]
  ; calls a function you have to push the arguments beforehand.
  push [object]
  ; This pushes/adds the object into the stack
  pop [object]
  ; This pops the object from the stack
  inc [register]
  ; increments register
  dec [register]
  ; decrements register
  add [register]
 Two ways to call a function:
   Standard Old way:
     push MB_OK
     push offset ClassName
     push offset AppName
     push 0
     call MessageBox
     ; This is a C syntax call from Right to Left.
     ; Reverse the order to work with stdcall.
     ; But this is messy and not a great method.
   New Way:
     invoke MessageBox,0,offset ClassName,offset Appname,MB_OK
     ; This is great! So how do we get the return value of this??
     ; Once you invoke this function the return value is stored in eax.
     ; mov RetValue,eax
     ; Now RetValue has the returned data, which you can check:
     ; .if(RetValue==IDOK)

We just discussed a few ways to use ASM. Of course, there is many more properties, methods, and functions that exist in ASM, but these are the most common methods.

First Windows Program

Next we'll discuss how to create your first Windows Program in MASM32. This is going to look quite complex at first, but I assure you, it is extremely simple and I will explain each line. Do not be afraid of the length and size of the code, it will all make sense once you read through this tutorial. I chose this program, because it is quite a simple program, and yet has enough examples of every ASM concept.

The following program will kill the process notepad.exe if it is running. You can change it to whatever program by editing the db variables.

.586
.model flat,stdcall
option casemap:none

.586 is a later processor, but you can experiment trying to be compatible to older processors such as .386 or .486 instruction sets.

   include windows.inc
   include user32.inc
   include kernel32.inc
   include shlwapi.inc
   
   includelib user32.lib
   includelib kernel32.lib
   includelib shlwapi.lib

We included the windows library for windows functions, and various windows libraries that also have specific functions. The .inc extension is similar to .h in C++, which is a header or include file. The .lib extension indicates library files.

Your WinMain function

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

We create the prototype WinMain, which isn't defined yet, we just want to let the program know that we will be using the WinMain function later in the program. WinMain is a specific function that the Windows Operating System uses for most of your code.

.data
   ClassName db "MainWinClass",0
   AppName  db "Main Window",0
   ProcessName db "notepad.exe",0
   started db "KillProcess",0
   startedtext db "KillProcess has started!",0
   quittext db "KillProcess is suiciding!",0
   successtext db "KillProcess has succeeded in killing notepad.exe!",0
   failedtext db "KillProcess has failed and brought shame to our family!",0
.data?
   hInstance HINSTANCE ?
   CommandLine LPSTR ?

We express our data here. Usually these are constants and texts that we will be using throughout the program. The .data? variables are undeclared global (the whole program can see them) variables that we will use.

.code

start:
        invoke GetModuleHandle, NULL
        mov    hInstance,eax
       
        invoke GetCommandLine
        mov    CommandLine,eax
       
        invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
        invoke ExitProcess,eax

We start our main code, and we invoke or launch some standard windows functions and add the returned values to hInstance and CommandLine.

Shutting Off a Win32 Process

KillProcess proc lpszExecutable:LPSTR
        LOCAL bLoop:BOOL
        LOCAL bResult:BOOL
        LOCAL pe32:PROCESSENTRY32
        LOCAL hProcess:HANDLE
        LOCAL hProcesses:HANDLE
        mov bLoop,TRUE
        mov bResult,FALSE
        mov pe32.dwSize,SIZEOF PROCESSENTRY32
        invoke CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS,0
        mov hProcess,eax
        mov hProcesses,eax

We declare some variables in our KillProcess process function. Which has an argument called lpszExecutable, of the type LPSTR (which is a type of pointer string in windows).
We declare some local variables using the keyword LOCAL, with types BOOL, PROCESSENTRY32, and HANDLE.
We use the mov command to move values of TRUE, or the SIZEOF PROCESSENTRY32 into their appropriate variables.

SIZEOF PROCESSENTRY32 is required because PROCESSENTRY32 is a structure and we want to declare the size of the structure we will be using in our functions. This is required by windows functions.
Many of the types and arguments you will see for each function are just peices of rules that Windows requires from the programmer in order to use certain functions. You can always look them up in MSDN, although you will have to convert them to ASM.

We invoke the function CreateToolhelp32Snapshot, with arguments TH32CS_SNAPPROCESS which is a definition number and 0. The value returned by CreateToolhelp32Snapshot is stored in eax register. So we mov the returned value into a variable we can use for later called hProcess and hProcesses.

Basic Task Manager Processes

        invoke Process32First,hProcesses,ADDR pe32
        .IF eax
                .WHILE bLoop
                        invoke CompareString,LOCALE_USER_DEFAULT,NORM_IGNORECASE,ADDR pe32.szExeFile,-1,lpszExecutable,-1
                        .IF eax==2
                                invoke OpenProcess,PROCESS_TERMINATE,FALSE,ADDR pe32.th32ProcessID
                                .IF eax!=NULL
                                        invoke TerminateProcess,hProcess,0
                                        invoke CloseHandle,hProcess
                                        mov bResult,TRUE;
                                .endif
                        .endif
                        invoke Process32Next,hProcesses,ADDR pe32
                        mov bLoop,eax
                .endw
                invoke CloseHandle,hProcesses
        .endif
        mov eax,bResult
        ret
KillProcess endp

We invoke Process32First with the variable hProcesses, and we reference the pe32 structure we had started declaring. This is called a struct because it is a blob of data that contains many properties. Earlier we defined dwSize for pe32, since it now contains information we have to use a reference when showing it to other functions. We don't want to literally send the whole struct into the other function, we just want to reference it, so the function can see it and edit the variable/struct from inside the function.

After that, the code checks if eax exists, and then loops as long as bLoop is TRUE. We CompareString to find the program we are looking for, it continues to loop until it finds the program we're looking for in the process list, which is found from Process32 functions.

If the returned value of CompareString is 2, we call OpenProcess, and prepare to terminate it. If we can open this process, then we can go ahead and Terminate it.

If we successfully terminated the program we will equate bResult to true, so we will know later that we were successful.

After we end our if statements using endif, we use Process32Next to continue to the next Process. If there is a next process, we continue to loop using bLoop as true; if not, bLoop will be set as false and the loop will end.

We of course call CloseHandle to stop any memory leaks and clean up our mess. The method ret is used to indicate the end the KillProcess function.

Windows Process Handling

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
        LOCAL wc:WNDCLASSEX
        LOCAL msg:MSG
        LOCAL hwnd:HWND
       
        mov   wc.cbSize,SIZEOF WNDCLASSEX
        mov   wc.style, CS_HREDRAW or CS_VREDRAW
        mov   wc.lpfnWndProc, OFFSET WndProc
        mov   wc.cbClsExtra,NULL
        mov   wc.cbWndExtra,NULL
        push  hInstance
        pop   wc.hInstance
        mov   wc.hbrBackground,COLOR_BTNFACE+1
        mov   wc.lpszMenuName,NULL
        mov   wc.lpszClassName,OFFSET ClassName
       
        invoke LoadIcon,NULL,IDI_APPLICATION
        mov   wc.hIcon,eax
        mov   wc.hIconSm,eax
       
        invoke LoadCursor,NULL,IDC_ARROW
        mov   wc.hCursor,eax
       
        invoke RegisterClassEx, addr wc
        INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
           hInst,NULL
        mov   hwnd,eax
       
        invoke ShowWindow, hwnd,SW_SHOWNORMAL
        invoke UpdateWindow, hwnd
       
        .WHILE TRUE
                invoke GetMessage, ADDR msg,NULL,0,0
                .BREAK .IF (!eax)
                invoke TranslateMessage, ADDR msg
                invoke DispatchMessage, ADDR msg
        .ENDW
       
        mov     eax,msg.wParam
        ret
WinMain endp

WinMain is a standard design of all Windows Main functions. The idea is to declare some information for the Windows Operating system, and register our program as a process in the operating system. We then show the window, and start the process loop that handles all incoming and outgoing messages of your program.

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
       
        LOCAL bResult:BOOL
        LOCAL bLoop:BOOL
        .IF uMsg==WM_DESTROY
                invoke PostQuitMessage,NULL
        .ELSEIF uMsg==WM_CREATE
                mov eax,FALSE
                mov bResult,eax
                invoke MessageBox,0,OFFSET startedtext,OFFSET started,MB_OK
                invoke KillProcess,OFFSET ProcessName
                mov bResult,eax
                .IF bResult==FALSE
                        invoke MessageBox,0,OFFSET failedtext,OFFSET started,MB_OK
                .ELSE
                        invoke MessageBox,0,OFFSET successtext,OFFSET started,MB_OK
                .ENDIF
                mov bLoop,FALSE
                .WHILE !bLoop
                        invoke GetAsyncKeyState,VK_ESCAPE
                        .IF  eax < 0
                                invoke MessageBox,0,OFFSET quittext,OFFSET started,MB_OK
                                invoke SendMessage,hWnd,WM_DESTROY,0,0
                                mov bLoop,TRUE
                        .ENDIF
                .ENDW
                ret
        .ELSE
                invoke DefWindowProc,hWnd,uMsg,wParam,lParam           
                ret
        .ENDIF
       
        xor eax,eax
        ret
WndProc endp


end start

The WndProc is a standard windows function which we use to handle all the messages that windows or other programs send us. If windows or a program, sends us the WM_DESTROY message, it means someone wants our program to end, and we should handle our shut down operations. If we receive WM_CREATE it means our program just started and we should create the GUI (Graphical User Interface) of the program if it has one.
Otherwise we just run the DefWindowProc (Default Window Process) if no message is being received.

In WM_CREATE we first define bResult as FALSE, so we know when it is true. We invoke a MessageBox to show the user and then launch our KillProcess function. We show a different message box on fail and on the success of KillProcess. We use GetAsyncKeyState,VK_ESCAPE and loop it to wait for the user to press his keyboard Escape key, if that is the case, we shut down our program by sending a message to ourselves called WM_DESTROY. We also show a small good bye message box too.

When you compile that program, you will understand it a little better. Of course, for many it will be confusing but playing around with the code will allow you to learn how ASM works and pretty soon you will understand it.

Also be advised, ASM is a very difficult language, so don't expect to understand it immediately, it may take some time to sink in.

lainhe's picture

my name lainhe, i'm chinese.i

my name lainhe, i'm chinese.i use masm32 assembler write program,and learn it has a long time.i hope get the informations about the win32 windows api,and write midi by keybord can use the sound card play music.

Post new comment

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account associated with the e-mail address you provide, it will be used to display your avatar.