; EntropyView - file entropy visualization ; rgimad 2021 ; header: use32 org 0 db 'MENUET01' ; magic dd 1 ; header version dd _start ; entry point dd _i_end ; program size dd _mem ; memory size dd _stacktop ; stack top addr dd cmdline ; buf for args dd 0 ; reversed __DEBUG__ = 1 ; 0 - disable debug output / 1 - enable debug output __DEBUG_LEVEL__ = DBG_ERR ; set the debug level DBG_ALL = 0 ; all messages DBG_INFO = 1 ; info and errors DBG_ERR = 2 ; only errors WND_START_X = 200 WND_START_Y = 200 WND_WIDTH = 540 WND_HEIGHT = 275 COL_KOEF = 7 COL_WIDTH = 2 HIST_Y = 230 HIST_X = 10 TMP_BUF_SIZE = 4096 include '../../macros.inc' purge mov, add, sub include '../../debug-fdo.inc' include '../../proc32.inc' _start: cmp byte [cmdline], 0 ; if no argument then print usage and exit jne @f mov dword [notify_struct.msg], msg_print_usage mcall 70, notify_struct mcall -1 @@: stdcall calculate_entropy ; print the byte table (for debug purposes) ; xor ecx, ecx ; .table_loop: ; cmp ecx, 256 ; jae .end_table_loop ; mov ebx, dword [byte_table + ecx*4] ; DEBUGF DBG_INFO, "number of bytes %x = %u\n", ecx, ebx ; inc ecx ; jmp .table_loop ; .end_table_loop: ; event loop: event_loop: mcall 10 ; wait for event cmp eax, 1 ; redraw event je on_redraw cmp eax,3 ; button event je on_button jmp event_loop on_button: mcall 17 ; 17 - get key code cmp ah, 1 ; if key with code 1 is not pressed then continue jne event_loop mcall -1 ; else exit ; define and draw window align 4 on_redraw: mcall 12, 1 ; begin redraw mcall 48, 3, sc,sizeof.system_colors mov edx, [sc.work] ; background color or edx, 0x34000000 ; window type mcall 0, , , , , wnd_title ; draw bottom line mov eax, 38 mov ebx, HIST_X shl ebx, 16 add ebx, HIST_X + COL_WIDTH*255 mov ecx, HIST_Y shl ecx, 16 add ecx, HIST_Y mov edx, 0x00FF0000 int 0x40 ; visualize table: xor ecx, ecx .table_loop: cmp ecx, 256 jae .end_table_loop mov ebx, dword [byte_table + ecx*4] ; ebx = frequency of ecx value mov esi, ecx imul esi, COL_WIDTH ; esi = x of column push COL_KOEF fild dword [esp] add esp, 4 push ebx fild dword [esp] add esp, 4 fyl2x ; fpu stack top = COL_KOEF*log_2(ebx) sub esp, 4 fistp dword [esp] pop eax mov ebp, eax ; ebp = height of column mov edi, HIST_Y sub edi, eax ; edi = y of left upper corner of column push ecx ; DEBUGF DBG_INFO, "drawing rect x = %u y = %u, height = %u\n", esi, edi, ebp mov eax, 13 mov ebx, esi add ebx, HIST_X shl ebx, 16 add ebx, COL_WIDTH - 1 mov ecx, edi shl ecx, 16 add ecx, ebp mov edx, 0x80000000 int 0x40 pop ecx inc ecx jmp .table_loop .end_table_loop: ; DEBUGF DBG_INFO, "esi = %u\n", esi mcall 12, 2 ; end draw jmp event_loop ; calculate entropy of file align 4 proc calculate_entropy stdcall stdcall _memset, byte_table, 0, 256*4 mov dword [file_size], 0 DEBUGF DBG_INFO, "starting reading blocks...\n" .read_block: mov eax, 70 mov ebx, fread_struct int 0x40 add dword [fread_struct.offset_low], ebx ; add how many was read ; mov ebp, dword [fread_struct.offset_low] ; DEBUGF DBG_INFO, "file pos = %u\n", ebp cmp eax, 6 ; if EOF its normal so skip next check je @f test eax, eax ; if error occured jnz .fail @@: mov edx, TMP_BUF_SIZE cmp eax, 6 jne @f mov edx, ebx ; if eof then use how many read, not max block size @@: xor ecx, ecx .buf_loop: cmp ecx, edx jae .end_buf_loop movzx ebx, byte [tmp_buf + ecx] shl ebx, 2 ; ebx *= 4; add ebx, byte_table inc dword [ebx] inc ecx jmp .buf_loop .end_buf_loop: cmp eax, 6 ; if EOF je .end_read jmp .read_block .end_read: mov eax, dword [fread_struct.offset_low] mov dword [file_size], eax DEBUGF DBG_INFO, "calculate_entropy end...\n" ret .fail: DEBUGF DBG_ERR, "error reading file, code = %u\n", eax mov dword [notify_struct.msg], msg_file_not_found mcall 70, notify_struct mcall -1 ret endp align 4 proc _memset stdcall, dest:dword, val:byte, cnt:dword ; doesn't clobber any registers ;DEBUGF DBG_INFO, "memset(%x, %u, %u)\n", [dest], [val], [cnt] push eax ecx edi mov edi, dword [dest] mov al, byte [val] mov ecx, dword [cnt] rep stosb pop edi ecx eax ret endp ; data: include_debug_strings ; for debug-fdo align 4 fread_struct: .subfunction dd 0 ; + 0 .offset_low dd 0 ; + 4 .offset_high dd 0 ; + 8 .size dd TMP_BUF_SIZE ; + 12 .buffer dd tmp_buf ; + 16 db 0 ; + 20 .filename: dd cmdline ; + 24 file_size dd 0 sc system_colors wnd_title db 'EntropyView 0.0.1', 0 msg_file_not_found db '"File not found" -tE', 0 msg_print_usage db '"Use from shell like:\nentropyview somefile.txt" -tI', 0 notify_struct: dd 7 ; run application dd 0 .msg dd ? dd 0 dd 0 db '/sys/@notify', 0 ; reverved data: align 16 _i_end: cmdline rb 1024 ; reserve for command line arguments tmp_buf rb TMP_BUF_SIZE ; temporary buffer for reading file byte_table rd 256 ; table which stores how many times each byte value(0-255) occured in the file rb 4096 ; for stack align 16 _stacktop: ; stack top label, stack grows downwards _mem: ; end