Home    Training    Downloads    Tutorials    Arbitary    Get Fate    Proxy Info
 
Training session 40: Assembly Language
Difficulty: Medium
Learn this brilliant art
Creator: m101


There are many reason why people either want to learn Assembly language, or dont want to learn it. In my experience there are a three general groups. The first group says "I know C, why should i bother learning Assembly?", the second says "I want to learn Assembly, but the other tutorials out there are for TASM or are really old, i want to learn Assembly for Windows", and the last group wishes to learn Assembly, but are generally too brain dead to learn another language first.

For this tutorial, i am aiming at the first two groups of people, those who want to learn modern Assembly, and those who want a reason to learn it. For the rest of this text i will refer to Assembly as simply ASM.

My personal main use for ASM is to disassemble binaries, and take a peek inside other peoples code. I was once asked by a C coder to make up some undocumented API for a DLL, which was easy to do if you can understand ASM, but for a pure C coder, it was nearly impossible. Basically, ASM is used when speed counts. For example, if you were coding a keylogger, it would have a number of key requirements, firstly to work at the lowest level possible to capture all keystrokes, secondly to be as fast as possible so that it cannot be noticed on either fast or slow machines, and lastly that it is small enough that no one will notice that change in space on the hdd. More recently, ASM has been used to shorten shell code for exploits, and to find exploits in binaries. ASM is the most important thing for a person to know to crack the copy protections on the latest games and applications. Another use that is now somewhat forgotten is for coding virii, as the size, speed, stealth and effectiveness of an ASM coded virus is much greater than 99% of the virii coded these days.

Hopefully i just listed atleast one thing that interests you to learn the language, if not, there is one last reason which should be taken into consideration. Programming languages such as C, C++, Delphi and VB all take your code, and compile it into ASM. Although the compilers may be highly optimised, and you can use inline ASM in your code quite often, there is no where asmuch control available to you unless you code the ASM directly.

Thats enough reasonning for now. The first thing you have to understand in ASM is the registers, and how they relate to opcodes. Here are the most common registers you will deal with:
EAX: Accumulator  
     Made up of: AX, AH, AL
     Common uses: Math operations, I/O operations
EBX: Base
     Made up of: BX, BH, BL
     Common uses: Base or Pointer
ECX: Counter
     Made up of: CX, CH, CL
     Common uses: Loops and Repeats
EDX: Displacement
     Made up of: DX, DH, DL
     Common uses: Various data, character output

Each register is 32 bit, that means 32 bits of data can fit into each one. EAX looks like this:
[       EAX      ]

[    ][ AH ][ AL ]

      [    AX    ]

This means that EAX can be accessed as either 8 bits, 16 bits, or 32 bits. There are ways to manipulate the registers to view it diferently, but youll learn that later. Here are the rest of the registers used more for control:

Segment Registers:
CS: Code Segment  The memory block that stores code
DS: Data Segment  The memory block that stores data
ES: Extra Segment  Commonly used for video stuff
SS: Stack Segment  Register used by the processor to store return addresses

Index Registers:
ESI: Source Index  Used to specify the source of an array
EDI: Destination Index  Used to specify the destination of an array
EIP: Instruction Pointer  Stores the address of the next instruction

Stack Registers:
EBP: Base pointer  Used with ESP for stack operations
ESP: Stack Pointer 

You wont be using most of these that much at first, except ESI and EDI. If your used to variables, your probably wondering what the hell im talking about. In ASM there is no such thing as a variable, string, or an array. Everything is just data. In C you allocated extra memory using malloc() or similar functions, and then placed variables like integers, floats, or strings in the space. Doing this, you might have memory looking like this:
[T][h][i][s][ ][i][s][][a][][s][t][r][i][n][g][\0][][][][][][125][][064][][028][][][]

[                     string                     ]          [int]  [int]  [int]

Now, in assembly, you would see a chunk of memory as this:
[AE][C0][00][2A][90][64][4D][86][2D][90][90][90][FF][BE][B2][3C][6D][00][00][76][5D]

This is where it becomes interesting, you can interpret any bit of data any way you want, for example you could take [64] as being an integer, a character, an instruction, or join it to the [90] before it and take it as a larger number, and basically do whatever you choose with it.

Ok, dont worry if you dont have a clue about what im talking about, you should be able to decipher it a bit later.

The next thing you should begin to understand is opcodes, or instructions. These are similar to what you find in other languages, for example 'if' is an instuction in C, while in ASM, you could use 'cmp' to do a very similar thing.

The best thing from here is for me to show you some assembly, and then try to explain to you what it is doing so that you can get an idea of what ASM looks like in use, and what is happening:
00401477 8D3544324000            lea esi, dword ptr [00403244]
0040147D 8D3D44324000            lea edi, dword ptr [00403244]
00401483 E885000000              call 0040150D
Ok, this needs a bit of an explanation. The first represents this:
Address  Data                    Assembly Intrstuction

00401477 8D3544324000            lea esi, dword ptr [00403244]
Now, to understand this, ill put it into a way C programmers can understand:
char str[50];
char *ptr;
char esi;

ptr=str;
esi = *ptr;

Your probably still having problems to understand what im saying, so lets break up what the command means:

lea:
This acts pretty much like an = sign

esi:
The register to manipulate

dword ptr [00403244]:
The tricky one, this says the contents of the memory location at 00403244h which happens to be the address to the string

So this basically means this:
esi = *ptr
Now the next line is:
0040147D 8D3D44324000            lea edi, dword ptr [00403244]

Yet again this just means:
edi = *ptr

The next line is:
00401483 E885000000              call 0040150D

This is just like calling a function in C, except that you call a memory address, and you arent dealing with parameters in the same way. After this jumps we run into this code:
0040150D 33C9                    xor ecx, ecx
0040150F AC                      lodsb
00401510 3C00                    cmp al, 00
00401512 7426                    jz 0040153A
00401514 3C3A                    cmp al, 3A
00401516 7F04                    jg 0040151C
00401518 2C30                    sub al, 30
0040151A EB02                    jmp 0040151E
0040151C 2C37                    sub al, 37
0040151E C0E004                  shl al, 04
00401521 8AD8                    mov bl, al

Now to explain it, the first line is:
0040150D 33C9                    xor ecx, ecx

This does exactly what it says, performs an xor on ecx, and stores the result in ecx. If you xor a value with the same value it will always return 0, so this is a quick way to make a value equal to zero.
0040150F AC                      lodsb

This one is more interesting, what it does is loads a byte from the location set by ESI into AL and increments ESI. This instruction can be interpretted in english as Load Byte. This can be represented in C as the following:
char str[50];
int i;
char *ptr;
char AL;

ptr = str;
AL = *(ptr + i);
i++;

Yet again i will say dont worry if this isnt making too much sense, you will start to understand later. The next line is:
00401510 3C00                    cmp al, 00

This one is pretty simple to understand, it compares AL, to 0 and stores the result in the relevant flag. This can be interepretted in C as the following in most situations:
if (AL == 0)

The next line is:
00401512 7426                    jz 0040153A

This is used in conjunction with the previous line. It basically interprets as 'jump if zero'. So joined with the previous line it can be interpreted as this:
if (AL == 0) {
  goto 0040153A;
 }

I beleive it is worth mentionning that unlike higher level languages, goto does infact have major use, and is actually used in pretty much every comparison to decide on what to do. The next two lines are:
00401514 3C3A                    cmp al, 3A
00401516 7F04                    jg 0040151C

You should be able to work out what this does, but if you cant, it basically compares al to 3Ah, and if AL is greater, it jumps. Here is it in C:
if (AL > '\x3a') {
  goto 0040151C;
 }

The nest line is:
00401518 2C30                    sub al, 30

This should also be pretty easy to work out, it gets the value from AL, subtracts 30h from it, and stores the result in AL. In C this is:
AL -= 48

Just remember that the 30h is hexidecimal, so since it is decimal in C, it translates to 48. The next line is:
0040151A EB02                    jmp 0040151E

Yet again this should be pretty self explanitory, it means an unconditional jump, or in other words, a goto. In C this is:
goto 0040151E

The next line is:
0040151C 2C37                    sub al, 37

Just to make sure you understand it, here it is in C:
AL -= 55

Here is the next line is:
0040151E C0E004                  shl al, 04

This one is yet another more difficult to explain instruction. It performs a bitwise shift left on AL by 4 bytes. This would be the following in C:
AL <<= 4

Dont get the << confused with any C++ instructions. The next line is:
00401521 8AD8                    mov bl, al

This instruction is extremely similar to LEA, but diferent still. In this particular case it means the following in C:
BL = AL

However, this is not the case when we use larger registers. For example, if EBX = '12345678' and you did 'LEA EAX, EBX' would result in EAX would be '12345678', but however if you did 'MOV, EAX, EBX' it would be '78563412'. Although its not a big issue, you will see later when to use what, and why to use what.

Now youve been introduced to a bit of ASM, you should be starting to get an idea of what it does, how it does it, why it does it, and most importantly how you can do it.

When doing simple programming in Win32 ASM, you dont use that many diferent instructions as you would if you were programming highly advanced things, so for now, we will try to keep it as simple as possible. Go and get yourself a copy of MASM32, if you cant find one now using google, give up, this tutorial is too advanced for you, go and get a guide to using google.

Once youve got a copy of MASM, open it up, play with it a bit to get a feel of it. The first program you will make will simply display a message box. The code to do this is as follows:
.386 
.model flat,stdcall 
option casemap:none 
include \masm32\include\windows.inc 
include \masm32\include\kernel32.inc 
include \masm32\include\user32.inc 
includelib \masm32\lib\kernel32.lib 
includelib \masm32\lib\user32.lib 

.data 
msgboxcaption  db "m101's Assembly Tutorial",0 
msgboxtext db "Wow, you did something right for once",0 

.code 
start: 
invoke MessageBox, NULL, addr msgboxtext, addr msgboxcaption, MB_OK 
invoke ExitProcess, NULL 
end start 

Note:
If your having problems compiling it is either because you dont know how to use MASM, in which case read the help file, or your MASM folder doesnt correspond with the includes in the source. I recommend placing MASM32 in 'c:\masm32'.
Now, although i could explain to you what .386 .data .model and .code do, it is beyond the scope of this tutorial, and a little too much for you to pickup right now. The two important bits we are interested in is the .code section, and the includes. The includes are very similar to #inculde in C, except refer to exact DLL's to include. As you can see, we declare the start of our program with 'start:' and end it with 'end start'. The first interesting line is the following:
invoke MessageBox, NULL, addr msgboxtext, addr msgboxcaption, MB_OK 

Invoke is actually a macro to make you C coders feel a little more comfortable. To make you C coders understand this a little more, it looks like this:
MessageBox (NULL, msgboxtext, msgboxcaption, MB_OK) 

This translates to the following in normal ASM:
push MB_OK
push addr msgboxcaption
push addr msgboxtext
push NULL
call MessageBox

Ok, now what this means is that we push the values to the stack in reverse order, and then call the desired function. So the first line is:
push MB_OK

This pushes the constant MB_OK onto the stack. Heres the next line:
push addr msgboxcaption

This pushes the address of the first byte in the message box caption to the stack. The next two lines are self explanitory. The last line is:
call MessageBox

When the program is compiled, it replaces the value of MessageBox with the address in the import table. Dont worry about this too much, but its worth mentioning that your not actually using an inbuilt function in MASM called MessageBox, you are calling a DLL function directly.

The next instruction in our code is:
invoke ExitProcess, NULL 

This is the same as the one before, it pushes the paramater NULL to the stack, and then calls the function to exit the application.

I beleive i should give an explanation of how to include other functions into your programs. After adding the appropriate includes, you simply apply the syntax directly into an invoke statement. For example:
The GetDriveType function determines whether a disk drive is a removable, fixed, CD-ROM, RAM disk, or network drive. 

UINT GetDriveType(

    LPCTSTR lpRootPathName 	// address of root path 
   );	

Parameters

lpRootPathName

Points to a null-terminated string that specifies the root directory of the disk to return information about. If lpRootPathName is NULL, the function uses the root of the current directory. 

Return Values

The return value specifies the type of drive. It can be one of the following values: 

Value	Meaning
0	The drive type cannot be determined.
1	The root directory does not exist.
DRIVE_REMOVABLE	The drive can be removed from the drive.
DRIVE_FIXED	The disk cannot be removed from the drive.
DRIVE_REMOTE	The drive is a remote (network) drive.
DRIVE_CDROM	The drive is a CD-ROM drive.
DRIVE_RAMDISK	The drive is a RAM disk.

So to call GetDriveType in ASM we would say:
invoke GetDriveType, addr StringOfDriveLetterToQuery

As with most calls that return a value, the return value for this function is placed in EAX. For those of you who dont understand, if you were to call 'GetDriveType("D:")' and D drive was infact a cd drive, then the return value of DRIVE_CDROM would be placed in the register EAX.

The following is the basic shell needed to make a window. Dont be worried that it looks somewhat dificult to understand, most of it is irrelivent for you to know at this point in time:
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib

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

.data
ClassName db "SimpleWinClass",0
AppName  db "Just another window",0

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?
hwndEdit2 HWND ?
.code
start:
	invoke GetModuleHandle, NULL
	mov    hInstance,eax
	invoke GetCommandLine
	mov    CommandLine,eax
	invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
	invoke ExitProcess,eax

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,WS_EX_CONTROLPARENT	 or DS_CENTER,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,370,100,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

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
	.IF uMsg==WM_DESTROY
		invoke PostQuitMessage,NULL
	.ELSEIF uMsg==WM_CREATE
		invoke SetFocus, hwndEdit
	.ELSEIF uMsg==WM_COMMAND
		mov eax,wParam
		.IF lParam==0
				invoke DestroyWindow,hWnd
		.ELSE
			.ENDIF
	.ELSE
		invoke DefWindowProc,hWnd,uMsg,wParam,lParam		
		ret
	.ENDIF
	xor eax,eax
	ret
WndProc endp
end start

All of this is basically what you dont see when you load up another language and create yourself a new form. In ASM you have full control over it, but for now, your can probably just play and try to make it look diferent.

The next thing i will show you is how to add a button to the form and make it show our little message box. From here i would recommend you get yourself an ASM reference, a windows api reference and some spare time to study this code:
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib

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

.data
ClassName db "SimpleWinClass",0
AppName  db "More windows",0
ButtonText db "A Button",0
ButtonID equ 1
ButtonClassName db "button",0
msgboxcaption  db "m101's Assembly Tutorial",0 
msgboxtext db "Wow, you did something right for once",0 


.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?
hwndEdit2 HWND ?
.code
start:
	invoke GetModuleHandle, NULL
	mov    hInstance,eax
	invoke GetCommandLine
	mov    CommandLine,eax
	invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
	invoke ExitProcess,eax

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,WS_EX_CONTROLPARENT	 or DS_CENTER,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,325,100,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

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
	.IF uMsg==WM_DESTROY
		invoke PostQuitMessage,NULL
	.ELSEIF uMsg==WM_CREATE
		invoke SetFocus, hwndEdit
		invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
                        WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
                        80,25,150,25,hWnd,ButtonID,hInstance,NULL
		mov  hwndButton,eax
	.ELSEIF uMsg==WM_COMMAND
		mov eax,wParam
		.IF lParam==0
				invoke DestroyWindow,hWnd
		.ELSE
			.IF ax==ButtonID
				shr eax,16
				.IF ax==BN_CLICKED
	                            invoke MessageBox, NULL, addr msgboxtext, addr msgboxcaption, MB_OK 
				.ENDIF
			.ENDIF
		.ENDIF
	.ELSE
		invoke DefWindowProc,hWnd,uMsg,wParam,lParam		
		ret
	.ENDIF
	xor eax,eax
	ret
WndProc endp
end start

Dont expect to understand this instantly, just study it, and youll get the idea. From here i recommend you take the last two bits of code and play around with them a bit to make it do anything apart from what it does now, and ofcourse, anything but crashing. To do this play with other DLL calls and try a bit of data manipulation.

Youll probably find the following list useful:

JCC - Jump if Condition Is Met
77 cb		JA rel8			Jump short if above (CF=0 and ZF=0)
73 cb		JAE rel8		Jump short if above or equal (CF=0)
72 cb		JB rel8			Jump short if below (CF=1)
76 cb		JBE rel8		Jump short if below or equal (CF=1 or ZF=1)
72 cb		JC rel8			Jump short if carry (CF=1)
E3 cb		JCXZ rel8		Jump short if CX register is 0
E3 cb		JECXZ rel8		Jump short if ECX register 0
74 cb		JE rel8			Jump short if equal (ZF=1)
7F cb		JG rel8			Jump short if greater (ZF=0 and SF=OF)
7D cb		JGE rel8		Jump short if greater or equal (SF=0F)
7C cb		JL rel8			Jump short if less (SF<>OF)
7E cb		JLE rel8		Jump short if less or equal (ZF=1 or SF<>OF)
76 cb		JNA rel8		Jump short if not above (CF=1 or ZF=1)
72 cb		JNAE rel8		Jump short if not above or equal (CF=1)
73 cb		JNC rel8		Jump short if not carry (CF=0)
75 cb		JNE rel8		Jump short if not equal (ZF=0)
7E cb		JNG rel8		Jump short if not greater (ZF=1 or SF<>OF)
7C cb		JNGE rel8		Jump short if not greater or equal (SF<>OF)
7D cb		JNL rel8		Jump short if not less (SF=OF)
7F cb		JNLE rel8		Jump short if not less or equal (ZF=0 and SF=OF)
71 cb		JNO rel8		Jump short if not overflow (OF=1)
7B cb		JNP rel8		Jump short if not parity (PF=1)
79 cb		JNS rel8		Jump short if not sign (SF=0)
75 cb		JNZ rel8		Jump short if not zero (ZF=0)
70 cb		JO rel8			Jump short if overflow (OF=1)
7A cb		JP rel8			Jump short if parity (PF=1)
7A cb		JPE rel8		Jump short if parity even (PF=1)
7B cb		JPO rel8		Jump short if parity odd (PF=0)
78 cb		JS rel8			Jump short if sign (SF=1)
74 cb		JZ rel8			Jump short if zero (ZF=0)


0F 87 cw/cd	JA rel16/32		Jump near if above (CF=0 and ZF=0)
0F 83 cw/cd	JAE rel16/32		Jump near if above or equal (CF=0)
0F 82 cw/cd	JB rel16/32		Jump near if below (CF=1)
0F 86 cw/cd	JBE rel16/32		Jump near if below or equal (CF=1 or ZF=1)
0F 82 cw/cd	JC rel16/32		Jump near if carry (CF=1)
0F 84 cw/cd	JE rel16/32		Jump near if equal (ZF=1)
0F 84 cw/cd	JZ rel16/32		Jump near if 0 (ZF=1)
0F 8F cw/cd	JG rel16/32		Jump near if greater (ZF=0 and SF=OF)
0F 8D cw/cd	JGE rel16/32		Jump near if greater or equal (SF=OF)
0F 8C cw/cd	JL rel16/32		Jump near if less (SF<>OF)
0F 8E cw/cd	JLE rel16/32		Jump near if less or equal (ZF=1 or SF<>OF)
0F 86 cw/cd	JNA rel16/32		Jump near if not above (CF=1 or ZF=1)
0F 82 cw/cd	JNAE rel16/32		Jump near if not above or equal (CF=1)
0F 83 cw/cd	JNB rel16/32		Jump near if not below (CF=0)
0F 87 cw/cd	JNBE rel16/32		Jump near if not below or equal (CF=0 and ZF=0)
0F 83 cw/cd	JNC rel16/32		Jump near if not carry (CF=0)
0F 85 cw/cd	JNE rel16/32		Jump near if not equal (ZF=0)
0F 8E cw/cd	JNG rel16/32		Jump near if not greater (ZF=1 or SF<>OF)
0F 8C cw/cd	JNGE rel16/32		Jump near if not greater or equal (SF<>OF)
0F 8D cw/cd	JNL rel16/32		Jump near if not less (SF=OF)
0F 8F cw/cd	JNLE rel16/32		Jump near if not less or equal (ZF=0 and SF=OF)
0F 81 cw/cd	JNO rel16/32		Jump near if not overflow (OF=0)
0F 8B cw/cd	JNP rel16/32		Jump near if not parity (PF=0)
0F 89 cw/cd	JNS rel16/32		Jump near if not sign (SF=0)
0F 85 cw/cd	JNZ rel16/32		Jump near if not zero (ZF=0)
0F 80 cw/cd	JO rel16/32		Jump near if overflow (OF=1)
0F 8A cw/cd	JP rel16/32		Jump near if parity (PF=1)
0F 8A cw/cd	JPE rel16/32		Jump near if parity even (PF=1)
0F 8B cw/cd	JPO rel16/32		Jump near if parity odd (PF=0)
0F 88 cw/cd	JS rel16/32		Jump near if sign (SF=1)
0F 84 cw/cd	JZ rel16/32		Jump near if 0 (ZF=1)




JMP - Jump
EB cb		JMP rel8		Jump short, relative, displacement rel to next instruct
E9 cw		JMP rel16		Jump near, relative, displacement rel to next instruct
FF /4		JMP r/m16		Jump near, absolute indirect, address given in r/m16
FF /4		JMP r/m32		Jump near, absolute indirect, address given in r/m32
EA cb		JMP ptr16:16		Jump far, absolute, address given in operand
EA cb		JMP ptr16:32		Jump far, absolute, address given in operand
FF /5		JMP m16:16		Jump far, absolute indirect, address given in m16:16
FF /5		JMP m16:32		Jump far, absolute indirect, address given in m16:32
 

The next step is to grab yourself a disassembler such Win32DASM or IDA and start taking apart other peoples code. Try to work out what is happenning, even if you have no idea what the code means, just get yourself a list of ASM instructions and match them to the code, and comment everything you can.

After you can understand other peoples code, its time to start to code yourself, pull out MASM again and start by doing simple things such as data input, then move onto file access, further to networking, and then to my personal favourite, self modifying code.

The following are two examples of code i have written for various purposes that you can have a look through:

File 1:

;Trend Officescan Password Decrypter by m101 for Phrozen Crew

.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib




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


.data
EditClassName db "edit",0
MAXSIZE equ 260
ClassName db "SimpleWinClass",0
AppName  db "Trend Officescan Password Decrypter by m101 for Phrozen Crew",0
ButtonText db "Decrypt Passwords",0
ButtonID equ 1
ButtonClassName db "button",0
IDM_GETTEXT equ 3
ofn   OPENFILENAME <>
FilterString db "ofcscan.ini",0,"ofcscan.ini",0,0
buffer db MAXSIZE dup(0)
hMapFile HANDLE 0
Accesdenied db "Access Denied",0
fhandle         dd ?
fsize         dd ?
bwrite   dd  ?
memptr	 dd  ?
patchoffset equ 0ab1ch
patchbytes db 0ebh  
lengthpatch equ 1h
patched db "File Succesfully Patched",0
org_val db "Unload_Pwd="
org_val2 db "Uninstall_Pwd="
org_val3 db "Master_Pwd="
len equ 0bh
FUnload_Pwd db "Unload Password:",0
Unload_Pwd db "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"
FMaster_Pwd db "Master Password:",0
Master_Pwd db "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"
FUninstall_Pwd db "Unintall Password:",0
Uninstall_Pwd db "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"
EditID equ 2
EditID2 equ 3
EditID3 equ 4
EditIDb equ 5
EditID2b equ 6
EditID3b equ 7
table db 41h,2Dh,43h,15h,07h,0B5h,9Eh,0F3h,6Ch,78h,0CDh,0Eh,0B5h,5Bh,75h,0D2h,82h,0BEh,13h,76h,0c1h,3dh,0ch,69h,0e1h,38h,2fh,0c7h,0h,0ebh,1ch,0aeh,0c6h,0cdh,55h,1dh,1dh,72h,7eh,0b5h

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?
hwndEditb HWND ?
hwndEdit2 HWND ?
hwndEdit2b HWND ?
hwndEdit3 HWND ?
hwndEdit3b HWND ?
.code
start:
	invoke GetModuleHandle, NULL
	mov    hInstance,eax
	invoke GetCommandLine
	mov    CommandLine,eax
	invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
	invoke ExitProcess,eax

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,WS_EX_CONTROLPARENT	 or DS_CENTER,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,403,150,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

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
	.IF uMsg==WM_DESTROY
		invoke PostQuitMessage,NULL
	.ELSEIF uMsg==WM_CREATE
		invoke CreateWindowEx,NULL, ADDR EditClassName,NULL,\
                        WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
                        ES_AUTOHSCROLL or ES_READONLY,\
                        150,3,230,25,hWnd,EditID3,hInstance,NULL
		mov  hwndEdit3,eax
		invoke CreateWindowEx,NULL, ADDR EditClassName,NULL,\
                        WS_CHILD or WS_VISIBLE or ES_LEFT or\
                        ES_AUTOHSCROLL or ES_READONLY,\
                        20,7,129,25,hWnd,EditID3b,hInstance,NULL
		mov  hwndEdit3b,eax
		invoke CreateWindowEx,NULL, ADDR EditClassName,NULL,\
                        WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
                        ES_AUTOHSCROLL or ES_READONLY,\
                        150,32,230,25,hWnd,EditID2,hInstance,NULL
		mov  hwndEdit2,eax
		invoke CreateWindowEx,NULL, ADDR EditClassName,NULL,\
                        WS_CHILD or WS_VISIBLE or ES_LEFT or\
                        ES_AUTOHSCROLL or ES_READONLY,\
                        20,35,129,25,hWnd,EditID2b,hInstance,NULL
		mov  hwndEdit2b,eax
		invoke CreateWindowEx,NULL, ADDR EditClassName,NULL,\
                        WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
                        ES_AUTOHSCROLL or ES_READONLY,\
                        150,62,230,25,hWnd,EditID,hInstance,NULL
		mov  hwndEdit,eax
		invoke CreateWindowEx,NULL, ADDR EditClassName,NULL,\
                        WS_CHILD or WS_VISIBLE or ES_LEFT or\
                        ES_AUTOHSCROLL or ES_READONLY,\
                        20,65,129,25,hWnd,EditIDb,hInstance,NULL
		mov  hwndEditb,eax
		invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
                        WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
                        20,92,360,25,hWnd,ButtonID,hInstance,NULL
		mov  hwndButton,eax
		invoke SetFocus, hwndButton
            invoke SetWindowText,hwndEdit3b,ADDR FMaster_Pwd
            invoke SetWindowText,hwndEdit2b,ADDR FUninstall_Pwd
            invoke SetWindowText,hwndEditb,ADDR FUnload_Pwd

	.ELSEIF uMsg==WM_COMMAND
		mov eax,wParam
		.IF lParam==0
			.IF ax==IDM_GETTEXT
			.ELSE
				invoke DestroyWindow,hWnd
			.ENDIF
		.ELSE
			.IF ax==ButtonID
				shr eax,16
				.IF ax==BN_CLICKED
                  		mov ofn.lStructSize,SIZEOF ofn
                  		push hWnd
                  		pop  ofn.hWndOwner
                  		push hInstance
                  		pop  ofn.hInstance
                  		mov  ofn.lpstrFilter, OFFSET FilterString
                  		mov  ofn.lpstrFile, OFFSET buffer
                  		mov  ofn.nMaxFile,MAXSIZE
	       			invoke GetOpenFileName, ADDR ofn
                        	invoke CreateFile, addr buffer, GENERIC_READ or GENERIC_WRITE, NULL, NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
                        	mov  fhandle,eax
                           	cmp  eax,0FFFFFFFFh
                        	jnz  file_is_here
	                        invoke MessageBox, NULL,ADDR Accesdenied, addr AppName, MB_OK
                              jmp finished
file_is_here:
				      invoke GetFileSize, fhandle, 0
                              mov fsize, eax
				      invoke GlobalAlloc, 0, fsize
                              mov  memptr,eax
                              invoke ReadFile, fhandle, memptr, fsize, offset bwrite, 0
                              lea  esi, org_val
                              xor ebx, ebx
read_ok:
        mov  edi,memptr
        mov  ecx,fsize
        mov  al, byte ptr [esi]

loop_:
        repnz scasb
        cmp  ecx,0
        jz   not_found
       

here_is_something:

        push ecx
        push edi
        push esi
	  dec  edi
        mov  ecx,len
        cmp ebx, 1h
        jne cont11
        mov ecx, 0eh
cont11:
        repz cmpsb
        cmp  ecx,0
        jz   patch

not_that:

        pop  esi
        pop  edi
        pop  ecx
        jmp  loop_

patch:
        mov esi, edi
cmp ebx, 0h
jne patch2
        lea edi, Unload_Pwd
        inc ebx
        jmp loopy
patch2:
cmp ebx, 1h
jne patch3
        lea edi, Uninstall_Pwd
        inc ebx
        jmp loopy
patch3:
        lea edi, Master_Pwd
        inc ebx
        jmp loopy
loopy:
        cmp ebx, 3h
        jne loopy2
        inc esi
loopy2:
        lodsb
        stosb
        cmp al, 0dh
        jne loopy2
        cmp ebx, 3h
        jne loopy3
        dec edi
loopy3:
        dec edi
        mov al, 0h
        stosb
        
not_found:
cmp ebx, 1h
jne not_found2
                              lea  esi, org_val2
                              jmp read_ok
not_found2:
cmp ebx, 2h
jne not_found3
                              lea esi, org_val3
                              jmp read_ok
not_found3:

lea esi, Unload_Pwd
lea edi, Unload_Pwd
call crypter
lea esi, Master_Pwd
lea edi, Master_Pwd
call crypter
lea esi, Uninstall_Pwd
lea edi, Uninstall_Pwd
call crypter

invoke GlobalFree, memptr
invoke CloseHandle, fhandle

	                        invoke SetWindowText,hwndEdit,ADDR Unload_Pwd
	                        invoke SetWindowText,hwndEdit2,ADDR Uninstall_Pwd
	                        invoke SetWindowText,hwndEdit3,ADDR Master_Pwd
finished:


				.ENDIF
			.ENDIF
		.ENDIF
	.ELSE
		invoke DefWindowProc,hWnd,uMsg,wParam,lParam		
		ret
	.ENDIF
	xor eax,eax
	ret
WndProc endp


crypter proc
xor ecx,ecx
wopp:
lodsb
cmp al, 0h
je convv
cmp al, 3ah
jg charr
sub al, 30h
jmp burpp
charr:
sub al, 37h
burpp:
shl al, 4h
mov bl,al
lodsb
cmp al, 3ah
jg charr2
sub al, 30h
jmp burpp2
charr2:
sub al, 37h
burpp2:
or al, bl
xor al, [ecx+table]
stosb
inc ecx
jmp wopp
convv:
mov al,0h
stosb
ret
crypter endp



end start

File 2:

;SpamAgent v1.52.02 Crack by m101 for Phrozen Crew

.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib

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

.data
MAXSIZE equ 260
ClassName db "SimpleWinClass",0
AppName  db "SpamAgent v1.52.02 cracked by m101 for Phrozen Crew",0
ButtonText db "Crack Program",0
ButtonID equ 1
ButtonClassName db "button",0
IDM_GETTEXT equ 3
ofn   OPENFILENAME <>
FilterString db "SpamAgent.exe",0,"SpamAgent.exe",0,0
buffer db MAXSIZE dup(0)
hMapFile HANDLE 0
Accesdenied db "Access Denied",0
fhandle         dd ?
fsize         dd ?
bwrite   dd  ?
patchoffset equ 4324h
patchoffset2 equ 4a2dh
patchoffset3 equ 400h
patchbytes db 0e9h,0d7h,30h,0eeh,0ffh
patchbytes2 db 6ah,88h,40h
patchbytes3 db 0c7h,05h,33h,09h,41h,00h,8bh,0e6h,90h,90h
temp1 db 66h,0c7h,05h,37h,09h,41h,00h,90h,90h
temp2 db 0c7h,05h,8ah,13h,41h,00h,8bh,0e6h,90h,90h
temp3 db 66h,0c7h,05h,8eh,13h,41h,00h,90h,90h
temp4 db 0bh,0c0h,0ffh,0e0h,00h,00h
lengthpatch equ 5h
lengthpatch2 equ 3h
lengthpatch3 equ 2bh
patched db "File Succesfully Patched",0


.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?
hwndEdit2 HWND ?
.code
start:
	invoke GetModuleHandle, NULL
	mov    hInstance,eax
	invoke GetCommandLine
	mov    CommandLine,eax
	invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
	invoke ExitProcess,eax

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,WS_EX_CONTROLPARENT	 or DS_CENTER,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,370,100,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

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
	.IF uMsg==WM_DESTROY
		invoke PostQuitMessage,NULL
	.ELSEIF uMsg==WM_CREATE
		invoke SetFocus, hwndEdit
		invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
                        WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
                        80,25,180,25,hWnd,ButtonID,hInstance,NULL
		mov  hwndButton,eax
	.ELSEIF uMsg==WM_COMMAND
		mov eax,wParam
		.IF lParam==0
			.IF ax==IDM_GETTEXT
			.ELSE
				invoke DestroyWindow,hWnd
			.ENDIF
		.ELSE
			.IF ax==ButtonID
				shr eax,16
				.IF ax==BN_CLICKED
                  		mov ofn.lStructSize,SIZEOF ofn
                  		push hWnd
                  		pop  ofn.hWndOwner
                  		push hInstance
                  		pop  ofn.hInstance
                  		mov  ofn.lpstrFilter, OFFSET FilterString
                  		mov  ofn.lpstrFile, OFFSET buffer
                  		mov  ofn.nMaxFile,MAXSIZE
	       			invoke GetOpenFileName, ADDR ofn
                        	invoke CreateFile, addr buffer, GENERIC_READ or GENERIC_WRITE, NULL, NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
                        	mov  fhandle,eax
                           	cmp  eax,0FFFFFFFFh
                        	jnz  file_is_here
	                        invoke MessageBox, NULL,ADDR Accesdenied, addr AppName, MB_OK
                              jmp finished
file_is_here:
                              invoke SetFilePointer, fhandle, patchoffset, 0, 0
                              mov fsize, eax
                              invoke WriteFile, fhandle, ADDR patchbytes, lengthpatch, ADDR bwrite, 0
                              invoke SetFilePointer, fhandle, patchoffset2, 0, 0
                              mov fsize, eax
                              invoke WriteFile, fhandle, ADDR patchbytes2, lengthpatch2, ADDR bwrite, 0

                              invoke SetFilePointer, fhandle, patchoffset3, 0, 0
                              mov fsize, eax
                              invoke WriteFile, fhandle, ADDR patchbytes3, lengthpatch3, ADDR bwrite, 0

	                        invoke MessageBox, NULL,ADDR patched, addr AppName, MB_OK
                        	invoke ExitProcess,NULL
finished:


				.ENDIF
			.ENDIF
		.ENDIF
	.ELSE
		invoke DefWindowProc,hWnd,uMsg,wParam,lParam		
		ret
	.ENDIF
	xor eax,eax
	ret
WndProc endp
end start

Lastly, you shouldnt stress yourself too much over learning this, it can take sometime to get used to. I recommend you google for 'win32.hlp' to get a list of references to diferent calls, its actually an old Win32 programmers reference. If this tutorial seems somewhat empty to you, that is because ASM isnt a language that i recommend you just read about, it really has to be used to get a hang of. Happy coding!
Name

URL or Email

Message