An asm keygenerator code
("Hypersnap-DX version 3.02 Key generator")
by +SNiKkEL
(28 July 1997 ~
Updated 25 January 1998)
Courtesy of Fravia's page of reverse engineering
Well, another of these stupid protections with crackers' handles inside them...
a "blacklist" of names as +SNiKkEL calls it...
study the asm code, understand +SNiKkEL's reverse engineering effort and
learn!
Here is +SNiKkEL's email snippet:
...thanx to +ORC and you I can now write something like this source
code for a license code generator... for educational purposes.
I put some comments with it so it's pretty much self explanatory...
Indeed it is, a bright essay, by the way... May be we should from now on leave the "deep explanations"
stuff (with heavy code disassembly) and
simply publish good commented ASM code of the complete solution... lusers would not be able to follow (and this would be nice :-) yet people
that understand a little our work would enjoy it much more...
(dunno, it's
just a suggestion, let me know what you think :-)
HERE WE GO:
.model small
.stack 100h
.data
;******************************************************************************
; variables for code gen
;
;******************************************************************************
header DB ' Hypersnap-DX 3.02 license generator by +SNiKkEL',0ah,0dh,0ah,0dh,'$'
info DB 0ah,0dh,' for some reason they decided to insert a ',027h,'-',027h,' into the code',0ah,0dh
DB ' invalid names are:',0ah,0dh
DB ' xygorf, Saltine, super user, tHATDUDE, ED!SON and hacker... sigh',0ah,0dh
db 0ah,0dh,'enter any name:',0ah,0dh,' $'
notright db 0ah,0dh,' your name must contain at least one letter',0ah,0dh,'$'
should_be DB 'WORDXCJOSEFMENGELEJOSE',0 ;this is the regcode before 'encryption'
;WOR = world license (SIT = site license) DXC = some check
;the rest is the name; snikkel will be SNIKKELSNIKKELSN
;the alphabet will be A t/m F + L t/m o + U t/m Z (over 16 chars)
;according to this principle: divide total letters in name by 2
;sub 2 from answer and get 4 chars from beginning of name+answer
;put those 4 after first 6 chars, then put the last 6 letters in the
;name at the end (spaces, numbers etc are ignored, all letters must be capitalized)
fifthchar db 0ah,0dh,0ah,0dh,'what would you like to be the 5th letter in your code?',0ah,0dh
db ' enter anything from a to z',0ah,0dh,' $'
wrong db 'anything from a to z, isn',027h,'t that enuff?',0ah,0dh,' $'
wagain db 'why don',027h,'t you just fuck off',0ah,0dh,'$'
whatkind db 0ah,0dh,'would you like a site or a worldwide license? (s or w)',0ah,0dh,' $'
personals db 0ah,0dh,0ah,0dh,' your personal unlimited site license code is:',0ah,0dh,0ah,0dh,' $'
personalw db 0ah,0dh,0ah,0dh,' your personal unlimited world-wide license code is:',0ah,0dh,0ah,0dh,' $'
to_enter DB 'S2345678901234-6789012345',0ah,0dh,0ah,0dh,'$' ;the code will be put here
;the S is the fifth char on which the 1st letter depends
encodestr DB 'XCFNAKSHIPZUJLDORGVQTEWYBM',0 ;according to this the letters will be 'encoded'
checks Dw 0 ;checksum (last char) will be put here
keyb db 033h,033h,034h dup (0) ;keyboard buffer, place for input
;******************************************************************************
; end of data, begin of code
;******************************************************************************
.code
start: JMP begin
;******************************************************************************
; calculate code proc
;******************************************************************************
calculate PROC near
mov ax,@data
mov ds,ax
mov es,ax
xor bx,bx
mov cx,00001h
xor dx,dx
go: mov si,offset should_be
add si,bx
MOV al,byte ptr [si] ;put byte of name you want in al
cmp al,000h
jz done
mov si,offset to_enter
cmp cx,00010h
jnz dont_use_the_2D_for_calculating
inc dx ;make it skip the '-' for calculating next
inc dx
dont_use_the_2D_for_calculating:
add si,bx
add si,dx
mov ah,byte ptr [si] ;put byte in ah for substracting (adding)
inc al
cmp bx,00000h
jz fifth
jmp continue
fifth: mov si,offset to_enter
add si,00004h ;put the 1st char in should_be
MOV [si],ah ;in the right place fer output
sub dx,001h
continue: sub ah,041h
sub al,041h
add al,ah
cmp al,01ah
jge rotate
jmp continue2
rotate: sub al,01ah
continue2: mov si,offset encodestr
mov ah,000h
add si,ax
MOV al,byte ptr [si]
cmp cx,0000eh
jnz dont_overwrite_the_2D_check
inc cx
dec dx ; make it read the char before the '-' for calculating
dont_overwrite_the_2D_check:
cmp cx,00005h
jg fifth2
jz incdx
jmp continue3
incdx: inc dx
fifth2: mov si,offset to_enter
add si,cx
MOV byte ptr [si],al
inc bx
inc cx
jmp go
continue3: mov si,offset to_enter
add si,bx
MOV byte ptr [si],al
inc bx
inc cx
jmp go
done: RET ;return
calculate ENDP
;******************************************************************************
; this part asks for name
;******************************************************************************
input PROC near
mov ax,@data
mov ds,ax
mov es,ax
MOV ah,09h
mov dx,offset info ;spam info
int 21h
mov dx,offset keyb
mov ah,0ah
int 21h ;and get user name
MOV AH,09H
MOV DX,offset fifthchar ;display fifth char message
INT 21H
xor cx,cx
get5char: mov ax,0c07h ;clear keyb buffer & wait for input
int 21h
cmp al,061h ; 'a'
jge letsee
cmp al,041h ; 'A'
jge letsee2
jmp wrongg
letsee: cmp al,07bh ;'z'
jge wrongg
sub al,020h
jmp putitin
letsee2: cmp al,05bh ;'Z'
jge wrongg
putitin: mov si,offset to_enter
MOV byte ptr [si],al
MOV AH,09H
MOV DX,offset whatkind ;display question
INT 21H
getregmode: mov ax,0c07h ;clear keyb buffer & wait for input
int 21h
cmp al,073h ; 's'
jz sitelic
cmp al,041h ; 'S'
jz sitelic
cmp al,077h ;'w'
jz worldlic
cmp al,057h ;'W'
jz worldlic
jmp getregmode
sitelic: mov si,offset should_be
MOV byte ptr [si],'S'
MOV byte ptr [si+1],'I'
MOV byte ptr [si+2],'T'
ret
worldlic: mov si,offset should_be
MOV byte ptr [si],'W'
MOV byte ptr [si+1],'O'
MOV byte ptr [si+2],'R'
ret
wrongg: cmp cx,001h
jz wrongagain
mov ah,09h
mov dx,offset wrong
int 21h
inc cx
jmp get5char
wrongagain: mov ah,09h
mov dx,offset wagain
int 21h
jmp exit
ret
input endp
;******************************************************************************
; calculate checksum
;******************************************************************************
checksum PROC near
mov ax,@data
mov ds,ax
mov es,ax
xor cx,cx
mov di,offset checks
go2: mov si,offset should_be
xor ax,ax
cmp cx,016h
jz cal_char
add si,cx
MOV al,byte ptr [si] ;put byte of calculated in al
sub al,041h
push ax
push cx
mov ax,cx
mov cx,00002h
div cx
pop cx
pop ax
test dx,dx
jz nodouble
add ax,ax
nodouble: cmp ax,0001ah
jb allrighty
sub ax,00019h
allrighty: add [di],ax
inc cx
jmp go2
cal_char: mov ax,[di]
mov cx,01ah
xor dx,dx
div cx
mov bx,dx
inc bl
mov si,offset to_enter+017h ;added one here, made it read the last char
mov bh,byte ptr [si]
sub bh,041h
add bl,bh
cmp bl,01ah
jge rotate2
jmp go_on
rotate2: sub bl,01ah
go_on: mov si,offset encodestr
mov bh,000h
add si,bx
MOV bl,byte ptr [si]
mov si,offset to_enter+018h ;added one here cause of the '-'
mov byte ptr [si],bl
RET
checksum endp
;******************************************************************************
; check and shape up user input
;******************************************************************************
read_input proc near
mov ax,@data
mov ds,ax
mov es,ax
xor dx,dx
xor ax,ax
xor cx,cx
mov si,offset keyb
mov al,byte ptr [si+1] ;get number of chars put in by user
cmp al,000h
jz step_no_input ;number is zero
mov bx,ax
add si,2 ;move si to beginning of input
loopstart: cmp bx,000h
jnz notalldone
jmp reformat
step_no_input: jmp no_input
notalldone: mov al,byte ptr [si]
cmp al,061h ; 'a' checking for letters or other chars
jge letsee3
cmp al,041h ; 'A'
jge letsee4
jmp nolet
letsee3: cmp al,07bh ;'z'
jge nolet
sub al,020h ;capitalize
jmp putitinmem
letsee4: cmp al,05bh ;'Z'
jge nolet
putitinmem: mov di,si
sub di,dx
mov byte ptr [di],al
dec bx
inc si
jmp loopstart
nolet: inc dx
dec bx
inc si
jmp loopstart
reformat: xor bx,bx
mov si,offset keyb
mov bl,byte ptr [si+1] ;get number of chars put in by user
sub bx,dx ;substract number of not-letters
cmp bl,000h
jz no_input
cmp bl,010h
jg strip ;if name is over 16, strip 6th to ...
mov si,offset keyb ;if name is =<16 chars, repeat till full
add si,002h
mov di,offset should_be
add di,006h
mov al,010h
div bl ;full times to repeat is in al, remaining is in ah
;(bl= number of valid letters in code)
loopje: mov si,offset keyb ;if name is =< 16 chars, repeat till full
add si,002h
mov cl,bl
repz movsb ;put it in once
dec al ;one done
cmp al,000h ;check if needs repeating
jz last_time ;no, go put in remaining
jmp loopje ;yes, do it again
last_time: mov si,offset keyb
add si,002h
mov cl,ah
repz movsb ;put in the remaining chars
ret
strip: mov si,offset keyb
add si,002h
mov di,offset should_be
add di,006h
mov cl,006h
repz movsb ;put 1st 6 in place
xor ax,ax
mov al,bl
mov cl,002h
div cl
mov si,offset keyb
xor cx,cx
mov cl,al
add si,cx ;put next 4 in place
mov cl,004h
repz movsb
sub bl,004h ;six from end, the two non chars
;from beginning 'keyb' counted
mov si,offset keyb
add si,bx
mov cl,006h
repz movsb
ret
no_input: mov dx,offset notright
mov ah,009h
int 21h
jmp exit
read_input endp
;******************************************************************************
; spam the code
";------------------------------------------------------------------------------.class" tppabs="http://fravia.org/;******************************************************************************.class"
spam PROC near
mov ax,@data
mov ds,ax
mov es,ax
mov di,offset should_be
mov al,byte ptr[di]
cmp al,'S'
MOV AH,09H
jnz wormessage
MOV DX,offset personals ;display personal message
INT 21H
jmp dispcode
wormessage: MOV DX,offset personalw ;display personal message
INT 21H
dispcode: MOV AH,09H
MOV DX,offset to_enter ;display right code
INT 21H
RET
spam endp
;******************************************************************************
; the main program
;******************************************************************************
begin PROC near
mov ax,@data
mov ds,ax
mov es,ax
MOV AH,09H
MOV DX,offset header ;display header
INT 21H
CALL input ;get user input
call read_input
CALL calculate ;calculate code from input
call checksum ;calculate last char
CALL spam ;spam calculated code
exit: MOV AX,4C00H ;and exit
INT 21H
begin ENDP
END START
Well, +Snikkel sent an update on 25 January 1998... here it is, with his email:
here's the update to the hypersnap thingy.
severely,
+SNiKkEL
;hypersnap 3 keygen by +SNiKkEL
;16 bit exe, only tried with tasm
.model small
.stack 100h
.data
;******************************************************************************
; variables for code gen
;
;******************************************************************************
header DB ' Hypersnap-DX 3.08 license generator by +SNiKkEL',0ah,0dh,0ah,0dh,'$'
info DB 0ah,0dh,' this one works all seasons ;)',0ah,0dh
DB ' invalid names are:',0ah,0dh,0ah,0dh
db ' Marcko, jackkuo, Monkey, abel, ALI-BABA, Unlimited World-Wide Lic, xygorf,',0ah,0dh
db ' Gone Hyper, ^SaTaNa, -M-O-A-, Hypersnap, Alexander Chen, Saltine,',0ah,0dh
DB ' super user, tHATDUDE, ED!SON and hacker... sjees',0ah,0dh
db 0ah,0dh,'enter any name:',0ah,0dh,' $'
notright db 0ah,0dh,' your name must contain at least one letter',0ah,0dh,'$'
should_be DB 'WORDXCJOSEFMENGELEJOSE',0 ;this is the regcode before 'encryption'
;WOR = world license (SIT = site license) DXC = some check
;the rest is the name; snikkel will be SNIKKELSNIKKELSN
;the alphabet will be A t/m F + L t/m o + U t/m Z (over 16 chars)
;according to this principle: divide total letters in name by 2
;sub 2 from answer and get 4 chars from beginning of name+answer
;put those 4 after first 6 chars, then put the last 6 letters in the
;name at the end (spaces, numbers etc are ignored, all letters must be capitalized)
fifthchar db 0ah,0dh,0ah,0dh,'what would you like to be the 5th letter in your code?',0ah,0dh
db ' enter anything from a to z',0ah,0dh,' $'
wrong db 'anything from a to z, isn',027h,'t that enuff?',0ah,0dh,' $'
wagain db 'why don',027h,'t you just fuck off',0ah,0dh,'$'
whatkind db 0ah,0dh,'would you like a site or a worldwide license? (s or w)',0ah,0dh,' $'
personals db 0ah,0dh,0ah,0dh,' your personal unlimited site license code is:',0ah,0dh,0ah,0dh,' $'
personalw db 0ah,0dh,0ah,0dh,' your personal unlimited world-wide license code is:',0ah,0dh,0ah,0dh,' $'
to_enter DB '1234-5678-9012-3456-7890-1234',0ah,0dh,0ah,0dh,'$' ;the code will be put here
encodestr DB 'XCFNAKSHIPZUJLDORGVQTEWYBM',0 ;according to this the letters will be 'encoded'
checks Dw 0 ;checksum (last char) will be put here
keyb db 033h,033h,034h dup (0) ;keyboard buffer, place for input
temp DB 'S23412341234123412341234',0 ;place for temporary key without dashes
;the S is the fifth char on which the 1st letter depends
;it gets put in the fifth place in the code
;******************************************************************************
; end of data, begin of code
;******************************************************************************
.code
start: JMP begin
;******************************************************************************
; calculate code proc
;******************************************************************************
calculate PROC near
mov ax,@data
mov ds,ax
mov es,ax
xor bx,bx
mov cx,00001h
xor dx,dx
go: mov si,offset should_be
add si,bx
MOV al,byte ptr [si] ;put byte of name you want in al
cmp al,000h
jz done
mov si,offset temp
add si,bx
add si,dx
mov ah,byte ptr [si] ;put byte in ah for substracting (adding)
inc al
cmp bx,00000h
jz fifth
jmp continue
fifth: mov si,offset temp
add si,00004h ;put the 1st char in should_be
MOV [si],ah ;in the right place fer output
sub dx,001h
continue: sub ah,041h
sub al,041h
add al,ah
cmp al,01ah
jge rotate
jmp continue2
rotate: sub al,01ah
continue2: mov si,offset encodestr
mov ah,000h
add si,ax
MOV al,byte ptr [si]
do_not_loop: cmp cx,00005h
jg fifth2
jz incdx
jmp continue3
incdx: inc dx
fifth2: mov si,offset temp
add si,cx
MOV byte ptr [si],al
inc bx
inc cx
jmp go
continue3: mov si,offset temp
add si,bx
MOV byte ptr [si],al
inc bx
inc cx
jmp go
done: RET
calculate ENDP
;******************************************************************************
; this part asks for name
;******************************************************************************
input PROC near
mov ax,@data
mov ds,ax
mov es,ax
MOV ah,09h
mov dx,offset info ;spam info
int 21h
mov dx,offset keyb
mov ah,0ah
int 21h ;and get user name
MOV AH,09H
MOV DX,offset fifthchar ;display fifth char message
INT 21H
xor cx,cx
get5char: mov ax,0c07h ;clear keyb buffer & wait for input
int 21h
cmp al,061h ; 'a'
jge letsee
cmp al,041h ; 'A'
jge letsee2
jmp wrongg
letsee: cmp al,07bh ;'z'
jge wrongg
sub al,020h
jmp putitin
letsee2: cmp al,05bh ;'Z'
jge wrongg
putitin: mov si,offset temp
MOV byte ptr [si],al
MOV AH,09H
MOV DX,offset whatkind ;display question
INT 21H
getregmode: mov ax,0c07h ;clear keyb buffer & wait for input
int 21h
cmp al,073h ; 's'
jz sitelic
cmp al,041h ; 'S'
jz sitelic
cmp al,077h ;'w'
jz worldlic
cmp al,057h ;'W'
jz worldlic
jmp getregmode
sitelic: mov si,offset should_be
MOV byte ptr [si],'S'
MOV byte ptr [si+1],'I'
MOV byte ptr [si+2],'T'
ret
worldlic: mov si,offset should_be
MOV byte ptr [si],'W'
MOV byte ptr [si+1],'O'
MOV byte ptr [si+2],'R'
ret
wrongg: cmp cx,001h
jz wrongagain
mov ah,09h
mov dx,offset wrong
int 21h
inc cx
jmp get5char
wrongagain: mov ah,09h
mov dx,offset wagain
int 21h
jmp exit
ret
input endp
;******************************************************************************
; calculate checksum
;******************************************************************************
checksum PROC near
mov ax,@data
mov ds,ax
mov es,ax
xor cx,cx
xor dx,dx ;(?, dx=0002 gave me an illegal opcode in windows with DIV CX)
mov di,offset checks
go2: mov si,offset should_be
xor ax,ax
cmp cx,016h
jz cal_char
add si,cx
MOV al,byte ptr [si] ;put byte of calculated in al
sub al,041h
push ax
push cx
mov ax,cx
mov cx,00002h
div cx
pop cx
pop ax
test dx,dx
jz nodouble
add ax,ax
nodouble: cmp ax,0001ah
jb allrighty
sub ax,00019h
allrighty: add [di],ax
inc cx
jmp go2
cal_char: mov ax,[di]
mov cx,01ah
xor dx,dx
div cx
mov bx,dx
inc bl
mov si,offset temp+016h
mov bh,byte ptr [si]
sub bh,041h
add bl,bh
cmp bl,01ah
jge rotate2
jmp go_on
rotate2: sub bl,01ah
go_on: mov si,offset encodestr
mov bh,000h
add si,bx
MOV bl,byte ptr [si]
mov si,offset temp+017h
mov byte ptr [si],bl
RET
checksum endp
;******************************************************************************
; check and shape up user input
;******************************************************************************
read_input proc near
mov ax,@data
mov ds,ax
mov es,ax
xor dx,dx
xor ax,ax
xor cx,cx
mov si,offset keyb
mov al,byte ptr [si+1] ;get number of chars put in by user
cmp al,000h
jz step_no_input ;number is zero
mov bx,ax
add si,2 ;move si to beginning of input
loopstart: cmp bx,000h
jnz notalldone
jmp reformat
step_no_input: jmp no_input
notalldone: mov al,byte ptr [si]
cmp al,061h ; 'a' checking for letters or other chars
jge letsee3
cmp al,041h ; 'A'
jge letsee4
jmp nolet
letsee3: cmp al,07bh ;'z'
jge nolet
sub al,020h ;capitalize
jmp putitinmem
letsee4: cmp al,05bh ;'Z'
jge nolet
putitinmem: mov di,si
sub di,dx
mov byte ptr [di],al
dec bx
inc si
jmp loopstart
nolet: inc dx
dec bx
inc si
jmp loopstart
reformat: xor bx,bx
mov si,offset keyb
mov bl,byte ptr [si+1] ;get number of chars put in by user
sub bx,dx ;substract number of not-letters
cmp bl,000h
jz no_input
cmp bl,010h
jg strip ;if name is over 16, strip 6th to ...
mov si,offset keyb ;if name is =<16 chars, repeat till full
add si,002h
mov di,offset should_be
add di,006h
mov al,010h
div bl ;full times to repeat is in al, remaining is in ah
;(bl= number of valid letters in code)
loopje: mov si,offset keyb ;if name is =< 16 chars, repeat till full
add si,002h
mov cl,bl
repz movsb ;put it in once
dec al ;one done
cmp al,000h ;check if needs repeating
jz last_time ;no, go put in remaining
jmp loopje ;yes, do it again
last_time: mov si,offset keyb
add si,002h
mov cl,ah
repz movsb ;put in the remaining chars
ret
strip: mov si,offset keyb
add si,002h
mov di,offset should_be
add di,006h
mov cl,006h
repz movsb ;put 1st 6 in place
xor ax,ax
mov al,bl
mov cl,002h
div cl
mov si,offset keyb
xor cx,cx
mov cl,al
add si,cx ;put next 4 in place
mov cl,004h
repz movsb
sub bl,004h ;six from end, the two non chars
;from beginning 'keyb' counted
mov si,offset keyb
add si,bx
mov cl,006h
repz movsb
ret
no_input: mov dx,offset notright
mov ah,009h
int 21h
jmp exit
read_input endp
;******************************************************************************
; spam the code
";------------------------------------------------------------------------------.class" tppabs="http://fravia.org/;******************************************************************************.class"
spam PROC near
mov ax,@data
mov ds,ax
mov es,ax
mov di,offset should_be
mov al,byte ptr[di]
cmp al,'S'
MOV AH,09H
jnz wormessage
MOV DX,offset personals ;display personal message
INT 21H
jmp dispcode
wormessage: MOV DX,offset personalw ;display personal message
INT 21H
dispcode: MOV AH,09H
MOV DX,offset to_enter ;display right code
INT 21H
RET
spam endp
;******************************************************************************
; put stuff in place
;******************************************************************************
move_stuff proc near
mov ax,@data
mov ds,ax
mov es,ax
xor dx,dx
mov si,offset temp
mov di,offset to_enter
agin: mov cx,00004h ;copy 4
repz movsb
cmp dx,00005h
jz yes
inc dx
inc di ;skip 1
jmp agin
yes: ret
move_stuff endp
;******************************************************************************
; main program
;******************************************************************************
begin PROC near
mov ax,@data
mov ds,ax
mov es,ax
MOV AH,09H
MOV DX,offset header ;display header
INT 21H
CALL input ;get user input
call read_input
CALL calculate ;calculate code from input
call checksum ;calculate last char
call move_stuff ;move from temp into to_enter
CALL spam ;spam calculated code
exit: MOV AX,4C00H ;and exit
INT 21H
begin ENDP
END START
(c) +SNikkel 1997. All rights reserved.
You are deep inside fravia's page of reverse engineering,
choose your way out:
homepage
links
anonymity
+ORC
students' essays
tools cocktails
antismut CGI scripts
Javascript wars
search_forms
mail_fravia+
is reverse engineering legal?