Courtesy of reverser's page
of reverse engineering
Well, Edi found
the encryption routine and writes: "it took me 2 hours only to UNDERSTAND what
is done in 30 lines of assembler... everyone should study this
compact code, it was real tasteful :-)" I agree completely with him,
in fact I believe we should now slowly proceed (say before the end of September :-)
to the 'real' task: reversing the encryption routines used by our stegonating targets!
Back to Advanced Steganography
Edi to reverser+: 26 March 1998
Edi:
Dear reverser+,
First of all I want to thank you for setting up such nice "gates"
to advanced pages. Every one of the 3 was great fun, and they showed
me a important thing:
You can do everything if you just try hard enough!
I found the advanced steganography page. I don't think
it would have been possible without the help you provided on the
starting page, especially without Flynn's light version I wouldn't
write this now. After studying the text I thougt I just need a
working bruteforcer to crack the steganos encrypted file.
But I had to work more: first of all, the file offsets were wrong,
so I had to reverse engineer steganos again, on my own. I found
the encryption routine (it took me 2 hours only to UNDERSTAND what
is done in 30 lines of assembler... everyone should study this
compact code, it was real tasteful :-) and wrote my own bruteforcer,
first in Pascal, which was way too slow, then in C, too slow again,
and finally I decided to write it in assembler. When you have to
try 26^8 possible keys, you need to have
1.) a fast machine
2.) a good and fast algorythm to check the keys
I don't have #1, so I made #2. And the only way to achieve this is
programming in assembler. My program is not perfect, there must
still be ways left to speed it up somewhere, but it works fine for me
now (I had to correct several fatal bugs in the past few days :)
Started it in the evening, I came back in the morning and guess what,
I saw the right key!
Have a look at this self-explaining (I hope) program. You have
to know the file name to use it, but a check to see if you get
a filename is easy to implement.
---- start of brute.asm ---
brute segment para 'CODE'
org 100h
assume cs:brute, ds:brute, es:brute, ss:brute
start: jmp init
start_message db '[start]',13,10,'$'
end_message db '[end]',13,10,'$'
to_decode db 12 dup (0)
found db 'Found a key: $'
passwd db 8 dup ('a')
db 13,10,'$'
xorvals db 8 dup (0)
key db 256 dup (0)
filehandle dw 0
key_stage1 db 256 dup (0)
filename db 'adva.sef',0
x db 0
y db 0
cte db 0
counter dw 0
start1 equ 's'
start2 equ 'a'
start3 equ 'a'
start4 equ 'a'
start5 equ 'a'
start6 equ 'a'
start7 equ 'a'
start8 equ 'a'
main proc near
mov ah,09h
mov dx,offset start_message
int 21h
mov ah,3dh
mov al,10000000b
mov dx,offset filename
int 21h ; open file
mov [filehandle],ax
mov bx,ax
mov ah,42h
mov al,0
mov cx,0
mov dx,019h
int 21h ; seek to 0x19h
mov bx,[filehandle]
mov ah,3fh
mov cx,12
mov dx,offset to_decode
int 21h ; read encoded filename (max. 12 chars)
mov ah,3eh
mov bx,[filehandle]
int 21h ; close file
cld
xor al,al
mov di,offset key_stage1
@prepare_stage1:
stosb
inc dx
inc al
jnz @prepare_stage1
xor dl,dl
mov byte ptr [offset passwd], start1-1
@loop_1:
inc byte ptr [offset passwd]
mov dh, byte ptr [offset passwd]
mov byte ptr [xorvals],dh
xor dl,dh
mov byte ptr [offset passwd+1],start2-1
@loop_2:
inc byte ptr [offset passwd+1]
mov dh, byte ptr [offset passwd+1]
shl dh,1
mov byte ptr [xorvals+1],dh
xor dl,dh
mov byte ptr [offset passwd+2],start3-1
@loop_3:
inc byte ptr [offset passwd+2]
mov dh, byte ptr [offset passwd+2]
shl dh,1
add dh, byte ptr [offset passwd+2]
mov byte ptr [xorvals+2],dh
xor dl,dh
mov byte ptr [offset passwd+3],start4-1
@loop_4:
inc byte ptr [offset passwd+3]
mov dh, byte ptr [offset passwd+3]
shl dh,2
mov byte ptr [xorvals+3],dh
xor dl,dh
mov byte ptr [offset passwd+4],start5-1
@loop_5:
inc byte ptr [offset passwd+4]
mov dh, byte ptr [offset passwd+4]
shl dh,2
add dh, byte ptr [offset passwd+4]
mov byte ptr [xorvals+4],dh
xor dl,dh
mov byte ptr [offset passwd+5],start6-1
@loop_6:
inc byte ptr [offset passwd+5]
mov dh, byte ptr [offset passwd+5]
shl dh,3
sub dh, byte ptr [offset passwd+5]
sub dh, byte ptr [offset passwd+5]
mov byte ptr [xorvals+5],dh
xor dl,dh
mov byte ptr [offset passwd+6],start7-1
@loop_7:
inc byte ptr [offset passwd+6]
mov dh, byte ptr [offset passwd+6]
shl dh,3
sub dh, byte ptr [offset passwd+6]
mov byte ptr [xorvals+6],dh
xor dl,dh
mov byte ptr [offset passwd+7],start8-1
@loop_8:
inc byte ptr [offset passwd+7]
mov dh, byte ptr [offset passwd+7]
shl dh,3
xor dl,dh
cmp dl,08ah ; checksum of pw
jne @bad_key
call prepare_key
call decode ; we know the filename, so why not
cmp al,'a' ; implement it into the code :-?
jne @bad_key
call decode
cmp al,'d'
jne @bad_key
jmp @checkit ; few filenames will start with
; 'ad', so time doesn't really
; matter here. We need to put the
; check for the next chars elsewhere
; because of the relative jumps below...
@good_key:
call printpass
@bad_key:
xor dl,dh
cmp byte ptr [offset passwd+7],'z'
jb @loop_8
xor dl, byte ptr [xorvals+6]
cmp byte ptr [offset passwd+6],'z'
jb @loop_7
xor dl, byte ptr [xorvals+5]
cmp byte ptr [offset passwd+5],'z'
jnb @loophelp_6
jmp @loop_6
@loophelp_6:
xor dl, byte ptr [xorvals+4]
cmp byte ptr [offset passwd+4],'z'
jnb @loophelp_5
jmp @loop_5
@loophelp_5:
xor dl, byte ptr [xorvals+3]
cmp byte ptr [offset passwd+3],'z'
jnb @loophelp_4
jmp @loop_4
@loophelp_4:
xor dl, byte ptr [xorvals+2]
cmp byte ptr [offset passwd+2],'z'
jnb @loophelp_3
jmp @loop_3
@loophelp_3:
xor dl, byte ptr [xorvals+1]
cmp byte ptr [offset passwd+1],'z'
jnb @loophelp_2
jmp @loop_2
@loophelp_2:
call printstat ; show the user how much is left
xor dl, byte ptr [xorvals]
cmp byte ptr [offset passwd],'z'
jnb @loophelp_1
jmp @loop_1
@loophelp_1:
mov ah,09h
mov dx,offset end_message
int 21h
mov ax,4c00h
int 21h
main endp
@checkit:
call decode
cmp al,'v'
jne @checkit_bad_key
call decode
cmp al,'a'
jne @checkit_bad_key
call decode
cmp al,'.'
jne @checkit_bad_key
call decode
cmp al,'t'
jne @checkit_bad_key
call decode
cmp al,'x'
jne @checkit_bad_key
call decode
cmp al,'t'
jne @checkit_bad_key
jmp @good_key
@checkit_bad_key:
jmp @bad_key
printstat proc near
push dx
mov ah,09h
mov dx,offset passwd
int 21h
pop dx
ret
printstat endp
printpass proc near
push dx
mov ah,09h
mov dx,offset found
int 21h
mov ah,09h
mov dx,offset passwd
int 21h
pop dx
ret
printpass endp
decode proc near
xor ah,ah
mov al, [x] ; al = x
inc ax
xor ah,ah
mov di, offset key
add di, ax
xor bh, bh
mov bl, [y] ; bl = y
add bl, [di]
xor bh,bh
mov di, offset key
mov si, di
add di, ax
add si, bx
mov ch, [di]
mov cl, [si]
mov [di], cl
mov [si], ch
mov byte ptr [x], al
mov byte ptr [y], bl
add byte ptr [cte], 0dh
add cl,ch ; cl = xorindex
xor ch,ch
mov di, offset to_decode
add di, [counter]
mov al, byte ptr [di]
mov di, offset key
add di, cx
mov ah, [di]
xor ah, [cte]
xor al, ah
inc byte ptr [counter]
ret
decode endp
prepare_key proc near
mov byte ptr [counter], 0
mov byte ptr [cte],028h
mov byte ptr [x],0
mov byte ptr [y],0
mov cx,128
mov si,offset key_stage1
mov di,offset key
rep movsw
mov cx,0 ; cx=i
xor ax,ax ; ax=old
@prepare_key_loop:
mov di, offset key
add di, cx
mov bl, byte ptr [di]
add ax,bx
mov bx, cx
and bl, 7d
add bx, offset passwd
mov bl, byte ptr [bx]
add ax,bx
and ax, 000ffh
mov di,offset key
mov si,di
add di,cx
add si,ax
mov bh,[di]
mov bl,[si]
mov [di],bl
mov [si],bh
inc cl
jnz @prepare_key_loop
retn
prepare_key endp
init:
mov ah,4ah
mov bx,offset end_
add bx,15
mov cl,4
shr bx,cl
inc bx
int 21h
mov sp,offset end_
jmp main
init_end label near
dw (256-((init_end-init) shr 1)) dup (?)
end_ equ this byte
brute ends
end start
--- end of brute.asm ---
The above program checks every possible key. Let it run over night
like I did, go to bed and dream of reverser's next puzzle (I hope I
don't have to brute force it, I want to THINK :-)
Habi d'ere,
Edi
(c) 1998 Edi All rights reversed
You are deep inside reverser's page of reverse engineering,
choose your way out:
Back to Advanced Steganography
homepage
links
anonymity
+ORC
students' essays
academy database
tools
cocktails
javascripts wars
antismut CGI-scripts
search_forms
mail_fravia+
Is reverse engineering legal?