HOME - ASSEMBLER - VB



x86 Assembler (MASM)

COLLATZ PROBLEM

If n is even then divide by 2. If n is odd multiply by 3 and add 1.
A chain is defined as the number of iterations of this method for the calculation to end at 1.
I wrote the following code to solve a problem for a maths challenge.

; longest chain starting with number under 1,000,000
       xor edi, edi
align 4
start: mov ecx, 1000000         ; set main loop counter
       jmp outer                ; loop entry
inner: bt eax, 0                ; test even number
       jnc @f                   ; if no carry number is even
       lea eax, [eax*2+eax+1]   ; number is odd perform 3n+1
   @@: shr eax, 1               ; numbers are all even now so div by 2
       inc esi                  ; increment present number chain
       cmp eax, 1               ; if number is 1 we are done with it
       jnz inner                ; continue chain
       cmp esi, edi             ; if chain > longest_chain
       jb outer                 ; no, goto outer
       mov edi, esi             ; yes, update longest_chain
       mov ebx, ecx             ; save number having longest chain
outer: xor esi, esi             ; reset inner loop counter
       dec ecx                  ; decrement outer loop counter
       mov eax, ecx             ; save as next number to iterate
       cmp ecx, 500000          ; assume longest chain > 500000
       jnz inner                ; if outer loop counter > 0 continue
       print str$(ebx)          ; print result
       exit






SPIRAL DIAGONALS

Consider a 1001x1001 numerical spiral such as the 9x9 example below.

                73 74 75 76 77 78 79 80 81
                72 43 44 45 46 47 48 49 50
                71 42 21 22 23 24 25 26 51
                70 41 20  7  8  9 10 27 52
                69 40 19  6  1  2 11 28 53
                68 39 18  5  4  3 12 29 54
                67 38 17 16 15 14 13 30 55
                66 37 36 35 34 33 32 31 56
                65 64 63 62 61 60 59 58 57


Calculate sum of the diagonals in the 1001x1001 spiral.

start: mov ecx, 1       ; first diagonal spiral number
       xor ebx, ebx     ; determines distance to next diagonal
       mov eax, ecx     ; begin accumulating sum
inner: add ebx, 2       ; update distance between diagonals
       mov edx, 4       ; will use distance for 4 iterations
outer: add ecx, ebx     ; go to next diagonal
       cmp ecx, 1002001 ; last one?
       ja gotit         ; yes, go away
       add eax, ecx     ; no, add to sum
       dec edx          ; decrement inner loop counter
       jz inner         ; if zero, reset counter
       jmp outer        ; next number
gotit: print str$(eax)  ; print result
       exit






KEY GENERATOR

During a recent hacking challenge, the task of reversing an application and providing a key generator to register the application provided an opportunity to write my first key generator. The application was designed for the challenge and I do not condone reversing or "keygenning" applications that are not developed for this purpose.

start:
    mov str1, input("Enter username : ")         ; I used a 3 character username
    mov eax, str1             ; IIRC the algorithm actually required less work for > 3 characters
    mov ebx, [eax]
    mov ecx, 2                ; #loop iterations
l1: xor eax, eax              ; 1st iteration    ; 2nd iteration
    ror ebx, 8                ; ebx=41004342     ; ebx=42410043 last char
    mov al, bl                ; ax=0042 mid char ; ax=0043
    rol ax, 4                 ; ax=0420          ; ax=0430
    add al, ah                ; bits swapped
    push ecx                  ; preserve count
    print right$(hex$(eax),2) ; #1 & #2
    pop ecx
    dec ecx
    jnz l1

    mov ecx, 2                ; #loop iterations
l2: xor eax, eax              ; 1st iteration    ; 2nd iteration
    ror ebx, 8                ; ebx=41004342     ; ebx=42410043 last char
    mov al, bl                ; ax=0042 mid char ; ax=0043
    cmp al, 61h               ; determine case
    jb @f
    ; lower case, change to upper-20h -eliminates extra jmp
    sub al, 40h
@@: add al, 25h               ; if upper then al=67
    rol ax, 4                 ; ax=0670
    add al, ah                ; ax=0076 bits swapped
    push ecx                  ; preserve count
    print right$(hex$(eax),2) ; #3 & #4
    pop ecx
    ror ebx, 16               ; ebx=43420041     ; 41434200
    dec ecx
    jnz l2
    rol ebx, 16               ; correct ebx, ebx=42004143

    xor eax, eax
    mov al, bl                ; ax=0043
    cmp al, 61h               ; determine case
    jb @f
    sub al, 40h               ; lower case, change to upper-20h
@@: add al, 23h               ; if upper then al=66
    rol ax, 4                 ; ax=0660
    add al, ah                ; ax=0066 bits swapped
    print right$(hex$(eax),2) ; #5

    xor eax, eax
    rol ebx, 8                ; ebx=41004342
    mov al, bl                ; ax=0042 mid char
    rol ax, 4                 ; ax=0420
    add al, ah                ; ax=0024 bits swapped
    print right$(hex$(eax),2) ; #6

    xor eax, eax
    ror ebx, 8                ; ebx=42410043
    mov al, bl                ; ax=0043
    rol ax, 4                 ; ax=0430
    add al, ah                ; ax=0034
    ror al, 4                 ; ax=4003

    print right$(hex$(eax),1) ; #7
    print SADD("789ABCDEF11112131415161722353781") ; #8

    ror ebx, 16               ; manipulate ebx to spew 9th string section
    print right$(hex$(ebx),2) ; #9
    ror ebx, 12               ; bl=10th string section
    print right$(hex$(ebx),1) ; #10
    exit






SIMPLE DLL

A simple example of a Dynamic Link Library.
This is the first of three files. Save this as mydll.asm.

.386
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data

AppName db "my DLL", 0
dllMsg  db "This function was called from the DLL.", 0

.code

DllEntry proc hInstance:HINSTANCE, reason:DWORD, reserved1:DWORD
  mov  eax, TRUE
  ret
DllEntry Endp

functionOne proc
  invoke MessageBox, NULL, addr dllMsg, addr AppName, MB_OK
  ret	
functionOne endp

PassParam proc para1:DWORD
  invoke MessageBox, NULL, para1, addr AppName, MB_OK
  ret 	
PassParam endp

End DllEntry



Next we need to create our def file. All exported functions should be listed. Save this one as mydll.def.

LIBRARY   	mydll 
EXPORTS   	functionOne
	  	PassParam



Now we create the driver for testing the dll. Save as usedll.asm.

.386
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc

includelib mydll.lib
includelib \masm32\lib\kernel32.lib

functionOne PROTO
PassParam   PROTO :DWORD

.data
strParam db "1 Param passed", 0

.code
	
start:
  invoke functionOne
  invoke PassParam, addr strParam 
  invoke ExitProcess, NULL
end start



Finally we can compile mydll.dll and the usedll.exe program.

; DLL
ml /c /coff /Cp mydll.asm
link /DLL /SUBSYSTEM:WINDOWS /DEF:mydll.def /LIBPATH:c:\masm32\lib mydll.obj 

; usedll
ml /c /coff /Cp usedll.asm
link /SUBSYSTEM:WINDOWS usedll.obj







HOME - ASSEMBLER - VB