News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

My First Assembly Program

Started by reconmax, April 07, 2007, 12:00:44 AM

Previous topic - Next topic

reconmax

PWDGEN is a password generator I wrote in x86 Assembly using MASM32. I decided to write this program to learn more about assembly programming. It has been a long time since I have programmed in assembly and I have always missed it.

I decided to write a password generator after hearing a well-known security expert discussing personal password policies on his podcast.

The idea is to construct an algorithm you can easily remember and use it to generate passwords for various accounts you have on the internet. For example, if you need a password for a web-site at
www.somewebsite.com, you might apply your secret password algorithm to the seed value, "somewebsite" to obtain a password you don't have to remember. You simply have to remember the algorithm you used to generate it and you can use the same algorithm over and over.

I really like the idea of a personal password policy and I have my very own which I use regularly. It is different than the one implemented in PWDGEN. 

The algorithm implemented in PWDGEN yields an eight character password. It is;

(Cap3rd + last + 2nd + count%4 + count%3 + 1st + !||$(odd or even) + CapCountAlphaPointer)

1st Character - Capatilize the 3rd character of the seed value if it is an alphabetic character, otherwise just use the third character.
2nd character - Take the last character, if it is alphabetic, change it to lower-case, if its not alphabetic, just use the last character.
3rd character - Take the 2nd character, if it is alphabetic, change it to lower-case, if its not alphabetic, just use the 2nd character.
4th character - Create a numeric character by using a modulus operation on the length of the seed value, divide the seed value by four and use the remainder as the 4th character.
5th character - Create a numeric character by using a modulus operation on the length of the seed value, divide the seed value by three and use the remainder as the 4th character.
6th character - Take the 1st character, if it is alphabetic, change it to lower-case, if its not alphabetic, just use the 1st character.
7th character - Select a special character by determining if the length of the seed value is odd or even, for odd use "!", for even use "$".
8th character - Use the length of the seed value to select a letter from the alphabet and capitalize it. Start counting from "A".

So if we use "somewebsite" as our seed value, we get;

Meo32s!K

Now, I know its probably a bad idea to to actually document your secret algorithm in an assembly language application and I'm sure the security expert I mentioned earlier would cringe at the thought. Anyone capable of dis-assembling the program could determine the algorithm and use it to break your passwords if they got their hands on it.



However, it was a fun exercise and I'm on my way to doing some more assembly programming. I was thinking about adding functionality to let a user personalize the algorithm.
I will post the source in the next post...

reconmax



reconmax

Ok. Here are the files. Any pointers would be appreciated...

makefile
pwdgen.rc
pwdgen.asm


thanks,

reconmax




----------------START MAKEFILE-----------------------
NAME=PWDGEN
$(NAME).exe: $(NAME).obj $(NAME).res
        Link /SUBSYSTEM:WINDOWS /VERSION:4.0 /LIBPATH:c:\masm32\lib /DEBUG $(NAME).obj $(NAME).res
$(NAME).res: $(NAME).rc
        rc $(NAME).rc
$(NAME).obj: $(NAME).asm
        ml /c /coff /Cp /Zi /Zf /I"c:\masm32\include" $(NAME).asm
-----------------END MAKEFILE--------------------------

-----------------START PWDGEN.RC--------------------------
#define IDD_DIALOG1 101
#define IDC_GRP1 1001
#define IDC_EDT1 1002
#define IDC_EDT2 1003
#define IDC_BTN1 1004
IDD_DIALOG1 DIALOGEX 5,5,216,78
CAPTION "  Password Generator"
FONT 8,"MS Sans Serif",0,0
STYLE 0x10CB0800
EXSTYLE 0x00000088
BEGIN
  CONTROL "Enter Seed Value",IDC_GRP1,"Button",0x50000007,1,0,213,74,0x00000000
  CONTROL "",IDC_EDT1,"Edit",0x50010000,12,15,192,11,0x00020000
  CONTROL "",IDC_EDT2,"Edit",0x50010000,12,57,192,11,0x00020000
  CONTROL "GO",IDC_BTN1,"Button",0x50010000,85,34,44,12,0x00000000
END

-----------------END PWDGEN.RC--------------------------

-----------------START PWDGEN.ASM--------------------------
-----------------END PWDGEN.ASM--------------------------
.386
.model flat, stdcall  ;32 bit memory model
option casemap :none  ;case sensitive

include windows.inc
include kernel32.inc
include user32.inc
include Comctl32.inc
include shell32.inc

includelib kernel32.lib
includelib user32.lib
includelib Comctl32.lib
includelib shell32.lib

DlgProc         PROTO   :HWND,:UINT,:WPARAM,:LPARAM
ToLower         PROTO   :BYTE
ToUpper         PROTO   :BYTE
GetMod         PROTO   :BYTE,:BYTE
IsEven         PROTO   :BYTE

.const

IDD_DIALOG1         equ 101

;#########################################################################

.data?

hInstance         dd ?

;#########################################################################


.data
   AppName db "PWDGEN",0
   sdlen BYTE 0
   
   
.data?
   sdbuffer db 55 dup(?)
   password db 55 dup(?)
   
.const
   IDC_EDT1 equ 1002
   IDC_EDT2 equ 1003
   IDC_BTN1 equ 1004
   

.code
   

start:

   invoke GetModuleHandle,NULL
   mov      hInstance,eax

    invoke InitCommonControls
   invoke DialogBoxParam,hInstance,IDD_DIALOG1,NULL,addr DlgProc,NULL
   invoke ExitProcess,0

;########################################################################

DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

   mov      eax,uMsg
   .if eax==WM_INITDIALOG

   .elseif eax==WM_COMMAND
      mov eax,wParam
   
            .IF ax==IDC_BTN1
                invoke GetDlgItemText,hWin,IDC_EDT1,ADDR sdbuffer,512
               
                first:
                ;Get the third character in sdbuffer
                ;check to see if it is a lower case alphabetic character
                ;If it is, Capitalize it
                ;If it is not a lower case letter, just leave it as is
                ;Place it in the first position of password
                mov ebx, offset sdbuffer
                xor eax, eax
                mov ah, byte ptr [ebx+2] ;move the 3rd char to ah
               
               
                invoke ToUpper, ah
               
                ;place the character in ah into the first position of password
               
                mov ecx, offset password
                mov byte ptr [ecx], ah   
               
               
            second:               
                 ;Find the last character in sdbuffer and
                 ;Place it in the 2nd position of password
            
                 mov esi, ebx
                next_byte: 
            cmp byte ptr [esi], 0
               je found_the_end
               inc esi
               inc sdlen
               jmp next_byte

            found_the_end: 
            dec esi
            
                ;now ebx points to beginning,
            ;and esi points to the end of string.          
                ;and sdlen recorded the length of sdbuffer
                ;Place last char the 2nd position of pwdbuffer
               
                mov ecx, offset password
                mov ah, byte ptr [esi]
               
                invoke ToLower,ah
                mov byte ptr [ecx+1], ah
               
                third:
                  ;find the 2nd character in sdbuffer and
                  ;place it in the 3rd porition password
                  mov ebx, offset sdbuffer
                  xor eax, eax
                  mov ah, byte ptr [ebx+1] ;move the 2nd char to ah
               
                  invoke ToLower,ah
               
                  mov ecx, offset password
                  mov byte ptr [ecx+2], ah ;move the char in ah to the 3rd position   
               
                 fourth:
                 ;The 4th character of password will be calculated
                 ;by taking the modulus value of the sdbuffer length
                 ;divided by the value 4, i.e. sdlen%4 or
                 ;the remainder of sdlength/4
                 mov al, 4
                 invoke GetMod, [sdlen], al
                 ;mov sdlen,0               ;don't re-initialize sdlen, will be used again
                 mov ecx, offset password
                 add ah, 30h               ;convert the value in ah to a numeric character
                 mov byte ptr [ecx+3], ah    ;move the character in ah to the 4th position
             
                 fifth:
                ;The 5th character of password will be calculated
                 ;by taking the modulus value of the sdbuffer length
                 ;divided by the value 3, i.e. sdlen%4 or
                 ;the remainder of sdlength/3
                 mov al, 3
                 invoke GetMod, [sdlen], al
                 mov ecx, offset password
                 add ah, 30h               ;convert the value in ah to a numeric character
                 mov byte ptr [ecx+4], ah    ;move the character in ah to the 4th position
             
         
            sixth:
            ;find the 1st character in sdbuffer and
                  ;place it in the 6th porition password
                  mov ebx, offset sdbuffer
                  xor eax, eax
                  mov ah, byte ptr [ebx] ;move the 1st char to ah
               
                  invoke ToLower,ah
               
                  mov ecx, offset password
                  mov byte ptr [ecx+5], ah ;move the char in ah to t41Hhe 6th position 
            
            seventh:
            ;Next Learn About Odd/Even, Look at least significant bit (LSB)
            ;Divide the length of the seed by 2, if the remainder is zero
            ;it must be even,
            ;if the length is an even number use '$' else use '!'
            invoke IsEven, [sdlen]
            cmp ah,1      ;If ISEven==true
            jne oddnum
            ;it must be even select '$'
            mov ecx, offset password
            mov ah, '$'
                  mov byte ptr [ecx+6], ah    ;move the character in ah to the 7th position
                  jmp eighth
            oddnum:
            ;it muist be odd select '!'
            mov ecx, offset password
            mov ah, '!'
                  mov byte ptr [ecx+6], ah    ;move the character in ah to the 7th position
            
            eighth:
            ;Use the length of the sed value sdbuffer as a pointer index
            ;to a letter in the alphabet starting with A=1, B=2, C=3, etc...
            ;Capitalize the letter and place it into the 8th position
            
            mov ah, byte ptr [sdlen]
            add ah, 40h
            mov ecx, offset password
                  mov byte ptr [ecx+7], ah
            
            mov sdlen,0               ;re-initialize sdlen
         
         ;(Cap3rd + last + 2nd + count%4 + count%3 + 1st + !||$(odd or even) + CapCountAlphaPointer)
         ;Place the constructed password in IDC_EDT2
         invoke SendDlgItemMessage, hWin, IDC_EDT2, WM_SETTEXT, 0, ADDR password
            .ENDIF
 
   .elseif eax==WM_CLOSE
      invoke EndDialog,hWin,0
   .else
      mov      eax,FALSE
      ret
   .endif
   mov      eax,TRUE

   ret

DlgProc endp
ToLower proc char:BYTE
            mov ah, char
              chk_uprcse_ltr:
               cmp ah, 41h
               jl not_uprcse_ltr
               cmp ah, 5Ah
               jg not_uprcse_ltr
               is_uprcse_ltr:
               add ah, 20h      ;lower case letter
               not_uprcse_ltr:
               nop
   ret

ToLower endp
ToUpper proc char:BYTE
         mov ah, char
         chk_lwrcse_ltr:
            cmp ah, 61h
            jl not_lwrcse_ltr
            cmp ah, 7Ah
            jg not_lwrcse_ltr
            is_lwrcse_ltr:
            sub ah, 20h      ;upper case letter
            not_lwrcse_ltr:
            nop
   ret

ToUpper endp
GetMod proc dvdnd:BYTE, dvsr:BYTE
           xor eax, eax
           xor ebx,ebx
           mov al, dvdnd
           mov bl, dvsr
            div bl
           
   ret

GetMod endp
IsEven proc dvdnd:BYTE
           xor eax, eax
           xor ebx,ebx
           mov al, dvdnd
           mov bl, 2
            div bl
         ;Remainder is in ah
         cmp ah, 0
         je evennum
         mov ah, 0
         jmp LeaveIsEven
         evennum:   
         mov ah,1   ;Number is even so return true
         LeaveIsEven:
   ret

IsEven endp
end start

MichaelW

Your GetMod procedure is returning the quotient instead of the remainder. DIV returns the quotient in AL/AX/EAX and the remainder in DL/DX/EDX.

Bit 0 is set for odd numbers and clear for even numbers. With just two logical operations you can produce a result of 1 for even and 0 for odd.
eschew obfuscation

reconmax

Quote from: MichaelW on April 07, 2007, 04:18:06 AM
Your GetMod procedure is returning the quotient instead of the remainder. DIV returns the quotient in AL/AX/EAX and the remainder in DL/DX/EDX.

Bit 0 is set for odd numbers and clear for even numbers. With just two logical operations you can produce a result of 1 for even and 0 for odd.


Thanks. I'll check it out.

For the GetMod proc, doesn't the DIV op return its results based on the size of the data it is executed on? Since in this case, the dividend and the divisor are both BYTES (8-bits), aren't the return values confined to the AX register (quotient in AL and remainder in AH)?

MichaelW

Sorry, I'm only half awake. Yes, for a byte division the quotient is returned in AL and the remainder in AH.
eschew obfuscation

reconmax

Wow! I just found masm32.lib. I see that I could have used it to do some of the work like;

(szLen) get the length of the sdbuffer
(szLower & szUpper) convert case
(InString) isolate individual characters in sdbuffer

reconamx


reconmax

Quote from: reconmax on April 07, 2007, 04:45:13 AM
Quote from: MichaelW on April 07, 2007, 04:18:06 AM
Your GetMod procedure is returning the quotient instead of the remainder. DIV returns the quotient in AL/AX/EAX and the remainder in DL/DX/EDX.

Bit 0 is set for odd numbers and clear for even numbers. With just two logical operations you can produce a result of 1 for even and 0 for odd.


Thanks. I'll check it out.

For the GetMod proc, doesn't the DIV op return its results based on the size of the data it is executed on? Since in this case, the dividend and the divisor are both BYTES (8-bits), aren't the return values confined to the AX register (quotient in AL and remainder in AH)?

What about the odd/even thing you are describing above? Are you saying I could determine the odd/even nature of a number in a better/easier way? Are you saying that some flag bits are set or something? Which flags and which operation would cause it? Sorry, but I don't understand what two logical ops to perform or how to observe the resulting bit you mention...

And thanks for you help...

reconmax

MichaelW

The bit values, starting with bit 7, are 128, 64, 32, 16, 8, 4, 2, and 1. Since all of the other bit values are even, bit 0 alone determines whether the number is odd or even. One method would be to isolate bit 0 by ANDing the value with 1, and then XOR the result with 1.

1 XOR 1 = 0
0 XOR 1 = 1
eschew obfuscation