From 9d0b079eeff4326589a6934377796b55811639e1 Mon Sep 17 00:00:00 2001 From: lucic71 Date: Thu, 7 May 2020 10:08:46 +0300 Subject: [PATCH] added iocla2 --- .../Makefile | 13 + .../README | 106 ++ .../tema2.asm | 1067 +++++++++++++++++ 3 files changed, 1186 insertions(+) create mode 100644 Introducere-In-Organizarea-Calculatoarelor-Si-Limbaj-De-Asamblare-2/Makefile create mode 100644 Introducere-In-Organizarea-Calculatoarelor-Si-Limbaj-De-Asamblare-2/README create mode 100644 Introducere-In-Organizarea-Calculatoarelor-Si-Limbaj-De-Asamblare-2/tema2.asm diff --git a/Introducere-In-Organizarea-Calculatoarelor-Si-Limbaj-De-Asamblare-2/Makefile b/Introducere-In-Organizarea-Calculatoarelor-Si-Limbaj-De-Asamblare-2/Makefile new file mode 100644 index 0000000..a2f639d --- /dev/null +++ b/Introducere-In-Organizarea-Calculatoarelor-Si-Limbaj-De-Asamblare-2/Makefile @@ -0,0 +1,13 @@ +CFLAGS=-m32 +AFLAGS=-f elf + +build: tema2 + +tema2: tema2.o include/macro.o include/utils.o + gcc $^ -o $@ $(CFLAGS) + +tema2.o:tema2.asm + nasm $^ -o $@ $(AFLAGS) + +clean: + rm -rf tema2.o tema2 \ No newline at end of file diff --git a/Introducere-In-Organizarea-Calculatoarelor-Si-Limbaj-De-Asamblare-2/README b/Introducere-In-Organizarea-Calculatoarelor-Si-Limbaj-De-Asamblare-2/README new file mode 100644 index 0000000..9d33da3 --- /dev/null +++ b/Introducere-In-Organizarea-Calculatoarelor-Si-Limbaj-De-Asamblare-2/README @@ -0,0 +1,106 @@ +Popescu Lucian Ioan 321CD + +I. Task1 and bruteforce_singlebyte_xor +-------------------------------------- + +For this task I used dynamic memory allocation using calloc because I decided +that using the stack for string manipulation operations would be too unpleasant. +The idea of my implementation is straightforward. Use one loop to try each key +in the range 0-255, use one more loop to iterate through each column of the +matrix and one final loop to iterate through each line of the matrix, even if +the image was represented as an array, I needed to get the message line number +at the end of the subroutine. +After each line is traversed, the dynamic allocated block, that contains now the +line with the xor operation applied on it, is checked to see it contains the +string 'revient' using a strstr version implemented by me. If it does, the +subroutine puts the key and the line in and stores the message in the +calloc'd block. +The strstr implementation works as following: iterate through each byte from +haystack, check if it's equal with the first byte in needle, if so iterate +through each byte from haystack and needle in parallel and check if they are +equal, if not continue. +In the end the message is printed using printf in solve_task1 and the control +is passed to the main program. + +II. Task2 +--------- + +I solved this task directly in solve_task2 label. For this I needed to call +the function defined in the previous task, namely bruteforce_singlebyte_xor in +order to get the key and the line. After that I decrypted the whole matrix and +inserted my message on the next line. In the end I encrypted the message using +the new generated key. + +III. Task3, morse_encrypt and morse binary tree +----------------------------------------------- + +The main idea here is that I managed to avoid a hardcoded solution, where I +would have written the morse encoding for each symbol in the alphabet. Thus +I created a binary tree which contains each symbol based on its encoding. The +tree works much like a Huffman tree. When traversed, it adds a '-' to the +symbol encoding if we go from the root to the right and it adds a '.' to the +symbol encoding if we go from the root to the left. +The algorithm for writing the morse code in our case works as follows: + -load a symbol from the source string + -if the symbol is comma then write the corresponding encoding + -if the symbol is not comma then do the following: + -find the position of the symbol in the binary tree + -make repeated divisions by 2 until the number is equal to 1 + -if the remained is equal to 1 then push a dash on the stack else + push dot + -finally, pop each dash and dot and write them in the image + -write a whitespace symbol(0x20) after each letter in the alphabet +The binary tree and its length are found in .rodata section. + +IV. Task4 and lsb_encode +------------------------ + +The implementation for lsb_encode is pretty short. It loads bytes from the msg +string and shifts left each bit into carry flag. If the carry is set, the +MSB was set and we set the LSB at the corresponding position in the image. If +the carry flag is not set, the MSB was not set and we reset the LSB at the +corresponding position in the image. I tried to find a better approach to this +solution, that would remove the three labels: ShiftBitToCarry, SetLSBOne and +SetLSBZero with only one label but I couldn't find it. The idea would sound +as following: (if CF == 1) then set LSB else reset LSB. The setCC instructions +in x86 operate only on bytes, not on bits. + +V. Task5 and lsb_decode +----------------------- + +Because I knew that the seeked string will contain maximum 20 bytes, I allocated +a 21 bytes string that will contain our decoded message at the end of the +subroutine. After that I took each group of 8 byts and substracted their LSB, +put it at the corresponding position in the new generated byte and stored the +byte in the allocated string. In the end I printed the message with printf and +free'd the memory. + +VI. Task6 and blur +------------------ + +Nothing special happens in solve_task6 label, as with the previous task. It +only calls the blur subroutine which worsk in the following way. Allocate space +for a new matrix. Copy the first and last lines and columns and for the inner +lines and columns apply the arithmetic mean between the upper, lower, right, +left and current element. I found very useful the lodsd and stosd instructions +because they did not only stored and loaded bytes from and but also +incremented correctly the streams of bytes. + +VII. Additional notes +--------------------- +I also created a convenience subroutine for printing a matrix that takes as +arguments the matrix to be printed, assuming that the height and width are +the same as the matrix received as command line argument. +For this homework I used some bytes stored in .rodata segment because they +were better suited to be declared there. The first two constants are used +through the whole homework, NULL being used when comparing with 0 and with +nullptr(see return value of strstr). MAX_KEY is used in task1 to define the +upper limit of the key used for bruteforce. PrintStringFormat and +PrintIntegerFormat are used when printing with printf in task1 or task5 for +example. MessageToSend is used in task2 and MorseCodeBinaryTree is used in +task3, they both are read only intended. + +VIII. Feedback +-------------- +Great homework!!! I enjoyed this introduction in steganography and I hope the +next homeworks will be as interesting as this one. diff --git a/Introducere-In-Organizarea-Calculatoarelor-Si-Limbaj-De-Asamblare-2/tema2.asm b/Introducere-In-Organizarea-Calculatoarelor-Si-Limbaj-De-Asamblare-2/tema2.asm new file mode 100644 index 0000000..ffe6208 --- /dev/null +++ b/Introducere-In-Organizarea-Calculatoarelor-Si-Limbaj-De-Asamblare-2/tema2.asm @@ -0,0 +1,1067 @@ +; Tema2 IOCLA - Popescu Lucian Ioan 321CD + +%include "include/io.inc" + +extern atoi +extern printf +extern exit + +; ---> my exports +extern calloc +extern free + +; Functions to read/free/print the image. +; The image is passed in argv[1]. +extern read_image +extern free_image +; void print_image(int* image, int width, int height); +extern print_image + +; Get image's width and height. +; Store them in img_[width, height] variables. +extern get_image_width +extern get_image_height + +section .rodata + NULL equ 0x00 + STACK_WORD equ 0x04 + MAX_KEY equ 0xFF + + PrintStringFormat db "%s", 0x0A, 0x00 + PrintIntegerFormat db "%d", 0x0A, 0x00 + + MessageToSend db "C'est un proverbe francais.", 0x00 + MessageToSendLength equ $ - MessageToSend + + MorseCodeBinaryTree db "**ETIANMSURWDKGOHVF*L*PJBXCYZQ**54*3***2*******16*" + db "******7***8*90", 0x00 + MorseCodeBinaryTreeLength equ $ - MorseCodeBinaryTree + +section .data + use_str db "Use with ./tema2 [opt_arg1] [opt_arg2]", 10, 0 + +section .bss + task: resd 1 + img: resd 1 + img_width: resd 1 + img_height: resd 1 + +section .text +global main +main: + ; Prologue + ; Do not modify! + push ebp + mov ebp, esp + + mov eax, [ebp + 8] + cmp eax, 1 + jne not_zero_param + + push use_str + call printf + add esp, STACK_WORD + + push -1 + call exit + +not_zero_param: + ; We read the image. You can thank us later! :) + ; You have it stored at img variable's address. + mov eax, [ebp + 12] + push DWORD[eax + 4] + call read_image + add esp, STACK_WORD + mov [img], eax + + ; We saved the image's dimensions in the variables below. + call get_image_width + mov [img_width], eax + + call get_image_height + mov [img_height], eax + + ; Let's get the task number. It will be stored at task variable's address. + mov eax, [ebp + 12] + push DWORD[eax + 8] + call atoi + add esp, STACK_WORD + mov [task], eax + + ; There you go! Have fun! :D + mov eax, [task] + cmp eax, 1 + je solve_task1 + cmp eax, 2 + je solve_task2 + cmp eax, 3 + je solve_task3 + cmp eax, 4 + je solve_task4 + cmp eax, 5 + je solve_task5 + cmp eax, 6 + je solve_task6 + jmp done + +solve_task1: + push ebp + mov ebp, esp + + ; OFFSET: + ; -4 the encoded message + sub esp, 4 + + ; Allocate space to store a xor'ed line. In this block of memory + ; we will search for 'revient'. + mov eax, [img_width] + inc eax ; +1 byte for the string terminator. + + ; Allocate blocks of size 1 + push dword 1 + push eax + call calloc + add esp, STACK_WORD * 2 + + mov [ebp - 4], eax + + push dword [ebp - 4] + push dword [img] + call bruteforce_singlebyte_xor + add esp, 8 + +PrintMessKeyLine: + ; Save the return value of bruteforce_singlebyte_xor. + push eax + + ; Print the message. + push dword [ebp - 4] + push PrintStringFormat + call printf + add esp, STACK_WORD * 2 + + ; Free the space allocated for a xor'ed line. + push dword [ebp - 4] + call free + add esp, STACK_WORD + + ; Print the key. + mov eax, [esp] + shr eax, 16 + + push eax + push PrintIntegerFormat + call printf + add esp, STACK_WORD * 2 + + ; Print the line. + pop eax + and eax, 0x0000FFFF + + push eax + push PrintIntegerFormat + call printf + add esp, STACK_WORD * 2 + +task1_done: + mov esp, ebp + pop ebp + jmp done +solve_task2: + push ebp + mov ebp, esp + + ; OFFSET: + ; -4 the encoded message + ; -8 the key and the line + ; -12 the size of the matrix (width * height) + sub esp, 12 + + ; Allocate space to store a xor'ed line. In this block of memory + ; we will search for 'revient'. + mov eax, [img_width] + inc eax ; +1 byte for the string terminator. + + ; Allocate blocks of size 1 + push dword 1 + push eax + call calloc + add esp, STACK_WORD * 2 + + mov [ebp - 4], eax + + push dword [ebp - 4] + push dword [img] + call bruteforce_singlebyte_xor + add esp, 8 + + ; Save the key and the line. + mov [ebp - 8], eax + + ; Free the space allocated for the decoded message. + push dword [ebp - 4] + call free + add esp, STACK_WORD + + ; Matrix base pointer. + mov ebx, [img] + + ; Index used to iterate through matrix. + mov ecx, [img_width] + imul ecx, [img_height] + + mov [ebp - 12], ecx + + ; Key used to xor each cell in the matrix. + mov edx, [ebp - 8] + shr edx, 16 + +DecryptMatrix: + ; Xor the entry and save it back at the same position. + mov eax, [ebx] + xor eax, edx + mov [ebx], eax + + ; Go th the next entry in the matrix. + add ebx, 4 + + ; Decrement the index. + dec ecx + cmp ecx, NULL + jnz DecryptMatrix + +GetAddressForWriting: + ; Get the line to write the message on + mov eax, [ebp - 8] + and eax, 0x0000FFFF + inc eax + + ; Move the pointer to the following position: + ; (img_width * (line + 1) * 4). + mov edi, [img] + imul eax, [img_width] + imul eax, 4 + + add edi, eax + + ; Move in the message to be written because we will use lodsb. + mov esi, MessageToSend + + ; Index for the WriteMessageToLineLoop loop + mov ecx, MessageToSendLength + + ; will load bytes from MessageToSend with lodsb. + ; will store doublewords from eax with lodsd. + xor eax, eax +WriteMessageToLineLoop: + lodsb + stosd + + dec ecx + cmp ecx, NULL + jnz WriteMessageToLineLoop + +GenerateNewKey: + mov eax, [ebp - 8] + shr eax, 16 + + shl eax, 1 + add eax, 3 + + mov ecx, 5 + xor edx, edx + div ecx + + sub eax, 4 + + ; will contain the key used to encrypt the matrix. + mov edx, eax + + ; Matrix base pointer. + mov ebx, [img] + + ; Matrix counter. + mov ecx, [ebp - 12] + +EncryptMatrix: + ; Xor the entry with the new generated key. + mov eax, [ebx] + xor eax, edx + mov [ebx], eax + + ; Go to the next entry in the matrix. + add ebx, 4 + + ; Decrement the index. + dec ecx + cmp ecx, NULL + jnz EncryptMatrix + + push dword [img] + call PrintImageWrapper + add esp, STACK_WORD + +task2_done: + mov esp, ebp + pop ebp + jmp done + +solve_task3: + ; Points to the beginning of 'argv'. + mov ebx, [ebp + 12] + + push ebp + mov ebp, esp + + mov eax, [ebx + 16] + push eax + call atoi + add esp, STACK_WORD + + push eax + push dword [ebx + 12] + push dword [img] + call morse_encrypt + add esp, 12 + + mov esp, ebp + pop ebp + + jmp done +solve_task4: + ; Points to the beginning of 'argv'. + mov ebx, [ebp + 12] + + push ebp + mov ebp, esp + + mov eax, [ebx + 16] + push eax + call atoi + add esp, STACK_WORD + + push eax + push dword [ebx + 12] + push dword [img] + call lsb_encode + add esp, STACK_WORD * 3 + + mov esp, ebp + pop ebp + + jmp done +solve_task5: + ; Points to the beginning of 'argv'. + mov ebx, [ebp + 12] + + push ebp + mov ebp, esp + + mov eax, [ebx + 12] + push eax + call atoi + add esp, STACK_WORD + + push eax + push dword [img] + call lsb_decode + add esp, STACK_WORD * 2 + + mov esp, ebp + pop ebp + + jmp done +solve_task6: + push ebp + mov ebp, esp + + push dword [img] + call blur + add esp, STACK_WORD + + mov esp, ebp + pop ebp + + jmp done + +done: + ; Free the memory allocated for the image. + push DWORD[img] + call free_image + add esp, STACK_WORD + + ; Epilogue + ; Do not modify! + xor eax, eax + leave + ret + + ; #arg1: image to process + ; #arg2: a string that will contain the searched text at the end + ; of this subroutine + ; + ; #returns: the key in the high part of and the line in the low + ; part of + ; + ; modified registers: , , , , +bruteforce_singlebyte_xor: + push ebp + mov ebp, esp + + ; OFFSET: + ; -4 saves the key used in bruteforce. + ; -8 saves a pointer to a xor'ed line. + sub esp, 8 + + mov eax, [ebp + 12] + mov [ebp - 8], eax + + xor eax, eax ; Used for arithmetic operations. + mov [ebp - 4],eax ; Key stored for bruteforce. + + xor ecx, ecx ; Iterator through lines. + xor edx, edx ; Iterator through columns. + +BruteforceKeyLoop: + mov ebx, [ebp + 8] ; matrix base pointer + +LineTraversal: + ; Put in to store the xor'ed bytes using stosb. + mov edi, [ebp - 8] + + ; restore column number to 0 + xor edx, edx +ColumnTraversal: + mov eax, [ebx + edx * 4] + + ; Xor with the key and store the result in + xor eax, [ebp - 4] + stosb + + inc edx + cmp edx, [img_width] + jl ColumnTraversal + +MessageCheck: + ; Save and . + push eax + push edx + + ; 'revient' string + push dword 0x00746e65 + push dword 0x69766572 + + push esp + push dword [ebp - 8] + call strstr + + ; Delete subroutine parameters. + add esp, STACK_WORD * 2 + ; Delete 'revient' string. + add esp, STACK_WORD * 2 + pop edx + + cmp eax, NULL + pop eax + jz MessageNotFound + +MessageFound: + ; Save the key in the high part of (bits 31-16). + mov eax, [ebp - 4] + shl eax, 16 + + ; Save the line in the low part of (bits 15-0) + mov ax, cx + + jmp bruteforce_singlebyte_xor_done + +MessageNotFound: + ; Move matrix base pointer to the beginning of the next line. + mov eax, [img_width] + imul eax, 4 + add ebx, eax + xor eax, eax + + inc ecx + + cmp ecx, [img_height] + jl LineTraversal + +LineTraversalDone: + ; Restore the line counter. + xor ecx, ecx + +BruteforceKeyIncrement: + inc byte [ebp - 4] + + mov eax, [ebp - 4] + cmp eax, MAX_KEY + jl BruteforceKeyLoop + +bruteforce_singlebyte_xor_done: + mov esp, ebp + pop ebp + + ret + + ; #arg1: haystack + ; #arg2: needle + ; + ; #returns: NULL if needle is not found in haystack + ; else the beginning of the needle in the haystack + ; modified registers: , , +strstr: + push ebp + mov ebp, esp + + mov esi, [ebp + 8] + mov edi, [ebp + 12] + +HaystackLoop: + mov al, [esi] + + ; *haystack != 0 + test al, al + jz ReturnNull + + ; *haystack != *needle + cmp al, [edi] + jnz HaystackIncrement + + ; compare(haystack, needle) == true + push edi + push esi + call HaystackNeedleCompare + pop esi + pop edi + + test al, al + jz HaystackIncrement + + mov eax, esi + jmp strstrExit + +HaystackIncrement: + inc esi + jmp HaystackLoop + +ReturnNull: + xor eax, eax + +strstrExit: + mov esp, ebp + pop ebp + + ret + + ; #arg1: haystack + ; #arg2: needle + ; + ; #returns: true if the first len(needle) bytes from arg1 and arg2 are + ; equal else NULL + ; modified registers: , , , +HaystackNeedleCompare: + push ebp + mov ebp, esp + + mov esi, [ebp + 8] + mov edi, [ebp + 12] + +CompareLoop: + ; *haystack + mov al, [esi] + + ; *needle + mov dl, [edi] + + ; loop while *haystack != 0 and *needle != 0 + test al, al + jz NeedleFinalCheck + + test dl, dl + jz NeedleFinalCheck + + ; *haystack != *needle + cmp al, dl + jz HaystackNeedleIncrement + + xor eax, eax + jmp CompareReturn + +HaystackNeedleIncrement: + inc esi + inc edi + + jmp CompareLoop + +NeedleFinalCheck: + ; return *needle == NULL + neg dl + sbb dl, dl + neg dl + xor dl, 1 + + mov eax, edx + +CompareReturn: + mov esp, ebp + pop ebp + + ret + + ; #arg1: image to be processed + ; #arg2: message to be encoded + ; #arg3: index of the first byte to be changed in the image + ; + ; #returns: nothing + ; modified registers: , , , , , +morse_encrypt: + push ebp + mov ebp, esp + + ; OFFSETS + ; -4 number of pushes on stack in EncodeSymbol label + sub esp, 4 + + ; Initialize the number of pushes to 0. + mov [ebp - 4], dword NULL + + ; Save the string to encode in + mov esi, [ebp + 12] + + ; Pointer to the beginning of where the message will be written. + mov ebx, [ebp + 8] + mov eax, [ebp + 16] + + imul eax, 4 + add ebx, eax + + xor eax, eax +MessageToEncodeLoop: + lodsb + + ; If we encounter the string terminator then stop. + test al, al + jz MessageToEncodeLoopDone + + ; If we encounter a ',' then write '--..--' + cmp al, 0x2C + jnz WriteNormalEncoding + +WriteCommaEncoding: + ; - + mov al, 0x2D + mov [ebx], eax + add ebx, 4 + + ; - + mov al, 0x2D + mov [ebx], eax + add ebx, 4 + + ; . + mov al, 0x2E + mov [ebx], eax + add ebx, 4 + + ; . + mov al, 0x2E + mov [ebx], eax + add ebx, 4 + + ; - + mov al, 0x2D + mov [ebx], eax + add ebx, 4 + + ; - + mov al, 0x2D + mov [ebx], eax + add ebx, 4 + + jmp WriteSpaceAfterSymbol + +WriteNormalEncoding: + ; Search for the letter in MorseCodeBinaryTree using scasb + mov ecx, MorseCodeBinaryTreeLength + mov edi, MorseCodeBinaryTree + + cld + repne scasb + + dec edi + + ; Calculate the index of that symbol in the tree which is represented as an array. + mov eax, MorseCodeBinaryTree + sub edi, eax + + mov eax, edi + + ; The symbol '*' in the MorseCodeBinaryTree is not a valid entry. To encode + ; a symbol, we need to perform multiple divisions by 2 since for each node + ; n, the left child will be on position 2*n and the right child will be on + ; position 2*n + 1. As we go to the right we write '-'. As we go to the left + ; we write '.'. +EncodeSymbol: + cmp eax, 1 + jz EncodeSymbolDone + + mov ecx, 2 + xor edx, edx + + div ecx + cmp edx, 1 + jz PushStackDash + +PushStackDot: + push dword 0x2E + inc dword [ebp - 4] + jmp PushStackDone + +PushStackDash: + push dword 0x2D + inc dword [ebp - 4] + +PushStackDone: + + jmp EncodeSymbol +EncodeSymbolDone: + + ;Write the encoded symbols to the desired position in the image. +WriteSymbolInsideImage: + pop eax + + mov [ebx], eax + add ebx, 4 + + dec dword [ebp - 4] + cmp [ebp - 4], dword NULL + jnz WriteSymbolInsideImage + + ; If we are not at the last element in the string to be encoded then we + ; write a space after we wrote a symbol. +WriteSpaceAfterSymbol: + cmp [esi], byte NULL + jz MessageToEncodeLoopReturn + + mov eax, 0x20 + mov [ebx], eax + add ebx, 4 + +MessageToEncodeLoopReturn: + xor eax, eax + jmp MessageToEncodeLoop + +MessageToEncodeLoopDone: + ; Write a NULL byte at the end of the encoding. + mov [ebx], dword NULL + + push dword [img] + call PrintImageWrapper + add esp, STACK_WORD + + mov esp, ebp + pop ebp + + ret + + ; #arg1: image to be processed + ; #arg2: message to be encoded + ; #arg3: starting index for encoding + ; + ; #returns: nothing + ; modified registers: , , , +lsb_encode: + push ebp + mov ebp, esp + + ; OFFSETS + ; -4 cotains the current encoded byte + + ; Save the string to be encoded in + mov esi, [ebp + 12] + + ; Move the matrix base pointer with byte_id positions. + mov eax, [ebp + 16] + + dec eax + imul eax, 4 + + mov ebx, [ebp + 8] + add ebx, eax + + xor eax, eax +WriteLSBLoop: + lodsb + mov [ebp - 4], eax + + mov ecx, 8 +ShiftBitToCarry: + shl al, 1 + jnc SetLSBZero + +SetLSBOne: + mov edx, [ebx] + or edx, 0x01 + mov [ebx], edx + add ebx, 4 + + jmp ShiftBitToCarryReload + +SetLSBZero: + mov edx, [ebx] + and edx, 0xFE + mov [ebx], edx + add ebx, 4 + +ShiftBitToCarryReload: + loop ShiftBitToCarry + + mov al, [ebp - 4] + test al, al + jnz WriteLSBLoop + + push dword [img] + call PrintImageWrapper + add esp, STACK_WORD + + mov esp, ebp + pop ebp + + ret + + ; #arg1: image to be processed + ; #arg2: starting index of the message to be decoded + ; + ; #returns: nothing + ; modified registers: , , , , +lsb_decode: + push ebp + mov ebp, esp + + ; OFFSETS + ; -4 address of the decoded string + sub esp, 4 + + ; Move matrix pointer to the desired index + mov eax, [ebp + 12] + dec eax + imul eax, 4 + + mov ebx, [ebp + 8] + add ebx, eax + + ; Allocate space for the decoded message. + push dword 1 + push dword 21 + call calloc + add esp, STACK_WORD * 2 + + mov edi, eax + mov [ebp - 4], eax + + ; Loop through 20 * 8 bytes because 20 is the maximum length of the + ; message and 8 is the number of bits in a byte. + mov ecx, 20 + +BytesIterator: + push ecx + mov ecx, 7 + + ; will be used to store each 8-bit sequence + xor edx, edx +FetchLSB: + mov eax, [ebx] + add ebx, 4 + + and eax, 0x01 + shl eax, cl + + or edx, eax + + dec ecx + cmp ecx, NULL + jge FetchLSB + +FetchLSBDone: + + mov eax, edx + stosb + + pop ecx + dec ecx + + cmp ecx, NULL + jnz BytesIterator +BytesIteratorDone: + +DecodedMessagePrint: + push dword [ebp - 4] + push PrintStringFormat + call printf + add esp, STACK_WORD * 2 + +MemoryFree: + mov eax, [ebp - 4] + + push eax + call free + add esp, STACK_WORD + + mov esp, ebp + pop ebp + + ret + + ; #arg1: image to be processed + ; + ; #returns: nothing + ; modified registers: , , , , , +blur: + push ebp + mov ebp, esp + + ; OFFSET + ; -4 pointer to a new created matrix + sub esp, 4 + + ; Create a new matrix in which we will save the blurred matrix. + ; The destination matrix will be saved in + mov eax, [img_width] + imul eax, [img_height] + + push dword 4 ; sizeof(int) + push eax + call calloc + add esp, STACK_WORD * 2 + + mov edi, eax + mov [ebp - 4], eax + + ; Source matrix will be saved in + mov esi, [ebp + 8] + + ; Copy the first line as it is. + mov ecx, [img_width] +CopySourceFirstLine: + lodsd + stosd + + loop CopySourceFirstLine + + ; will be the line counter. We also substract -2 because we don't + ; care about first and last line. + mov ecx, [img_height] + sub ecx, 2 + +LineTraversalSource: + ; Copy first column as it is + lodsd + stosd + + ; will be the column counter. We also substract -2 because we don't + ; care about first and last column. + mov edx, [img_width] + sub edx, 2 +ColumnTraversalSource: + mov eax, [esi] + + ; Add right and left element. + add eax, [esi + 4] + add eax, [esi - 4] + + push eax + + ; Add lower element. + mov eax, [img_width] + imul eax, 4 + add eax, esi + mov eax, [eax] + + add eax, [esp] + add esp, STACK_WORD + + push eax + + ; Add upper element. + mov eax, [img_width] + imul eax, 4 + neg eax + add eax, esi + mov eax, [eax] + + add eax, [esp] + add esp, STACK_WORD + + ; Divide by 5. + push edx + + mov ebx, 5 + xor edx, edx + div ebx + + pop edx + + ; Store the result + stosd + + ; Go to the next cell in source. + add esi, 4 + + ; Decrement the column counter and continue. + dec edx + cmp edx, 0 + jnz ColumnTraversalSource + +ColumnTraversalSourceDone: + ; Copy the last column as it is + lodsd + stosd + +LineTraversalSourceReload: + + dec ecx + cmp ecx, 0 + jnz LineTraversalSource + +LineTraversalSourceDone: + + ; Copy the last line as it is. + mov ecx, [img_width] +CopySourceLastLine: + lodsd + stosd + + loop CopySourceLastLine + +PrintBlurredImage: + push dword [ebp - 4] + call PrintImageWrapper + add esp, STACK_WORD + +FreeBlurredMatrix: + push dword [ebp - 4] + call free + add esp, STACK_WORD + + mov esp, ebp + pop ebp + + ret + + ; Convenience function for printing the image. + ; #arg1: image to be printed +PrintImageWrapper: + push ebp + mov ebp, esp + + push dword [img_height] + push dword [img_width] + push dword [ebp + 8] + call print_image + add esp, 12 + + mov esp, ebp + pop ebp + + ret