├── .gitignore ├── README.md ├── in ├── bubble_sort ├── header └── header_pol ├── main.py ├── modules ├── __pycache__ │ ├── engine.cpython-36.pyc │ └── engine.cpython-37.pyc └── engine.py ├── out ├── encrypted └── not_encrypted ├── src ├── all_nop.asm ├── bubble_sort.asm ├── header.asm └── header_pol.asm └── tests ├── old_bubble.asm └── simple.asm /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
6 | Quickstart 7 | • 8 | Documentation 9 | • 10 |
11 | 12 |  13 |  14 |  15 | 16 | # Polymorphic engine 17 | ## First some history 18 | First virus have no protection from av scanner. When av company catched virus they insert signature of this virus in database and av already new that this program is virus just with getting hash sum of the program. 19 | 20 | So Virus Exchange makes disguise code to prevent this. Idea is encrypt virus! Now only decryptor is naked, so only decryptor needs be polymorphic. 21 | ## Result 22 | This project makes header-file (decryptor) polymorphic, body code is encrypted with simple xor-cipher, and python file makes this encrypting, polymorphism and 23 | merges this two files. 24 | ## Documentation :pencil2: 25 | ### Used polymorphic methods: 26 | - Adding nop. 27 | - Add push and pop register to the stack. 28 | - Adding push and pop register in between them nop. 29 | - Adding on top of adding and subtracting the same random number from some register. 30 | - Divide addition / subtraction by addition / subtraction of 2 other numbers. 31 | - Dividing addition / subtraction by adding / subtracting 3 other numbers. 32 | - Divide addition / subtraction into successive addition of subtraction of other numbers. 33 | - Dividing when multiplying two numbers one of them by two others. 34 | - Replacement of registers at cmp. 35 | - Mul pattern. 36 | ### Encrypting: 37 | Here we using xor-cipher, with ```0x8E4E54DE6596DAEC``` 8 byte key 38 | #### Without encrypting: 39 |  40 | The body code in this program 52 nop (Opcode of the mnemonic nop is 90) 41 | #### With encrypting: 42 |  43 | So when program stats, first-things-first it decrypt body code and after run this decrypted code. 44 | ## Quickstart 45 | 46 | ### Prerequisites :page_with_curl: 47 | 48 | - nasm-packages 49 | - python3 50 | 51 | ### Installing :tongue: 52 | ``` 53 | $ git clone https://github.com/lurak/Polymorphic_engine 54 | ``` 55 | ### Usage :zap: 56 | - Change ```src/bubble_sort.asm``` on some script 57 | - Run main.py 58 | #### REMARK 59 | The algorithm of decrypting assume that your program size divided by 8 (length of key), so if your code don't divides by 8 60 | just add some ```nop``` to your program. 61 | ### Authors 62 | - Ihor Titov (polymorphism) 63 | - Danylo Sluzhynskyi (encrypting) 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /in/bubble_sort: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurak/Polymorphic_engine/8597a91310d64ae34e3bf41d33aa3ad8547450be/in/bubble_sort -------------------------------------------------------------------------------- /in/header: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurak/Polymorphic_engine/8597a91310d64ae34e3bf41d33aa3ad8547450be/in/header -------------------------------------------------------------------------------- /in/header_pol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurak/Polymorphic_engine/8597a91310d64ae34e3bf41d33aa3ad8547450be/in/header_pol -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | from modules.engine import SimplePol 4 | 5 | out_name = "encrypted" 6 | header_name = "header" 7 | main_name = "all_nop" 8 | temp_key = b'\x8eNT\xdee\x96\xda\xec' 9 | 10 | 11 | def compile_file(file): 12 | compile_str = f"nasm -fbin -o in/{file} src/{file}.asm" 13 | os.system(compile_str) 14 | return os.path.getsize(f"in/{file}") 15 | 16 | 17 | def change_asm_file(file, template, to): 18 | with open(file, 'r+', encoding='utf8') as asm: 19 | asm_txt = asm.read() 20 | asm_txt = re.sub(template, to, asm_txt) 21 | asm.seek(0) 22 | asm.write(asm_txt) 23 | asm.truncate() 24 | 25 | 26 | a = SimplePol(f"src/{header_name}.asm") 27 | a.polymorph() 28 | # HERE polymorphism header_name function 29 | header_name += "_pol" 30 | header_size = compile_file(header_name) 31 | 32 | change_asm_file(f"src/{main_name}.asm", r'(org)\s+(0[xX])?[a-fA-F0-9]+', f"org {hex(header_size + 0x00400000)}") 33 | 34 | file_size = compile_file(main_name) 35 | 36 | change_asm_file(f"src/{header_name}.asm", r'(mov)\s+(rax)\s*(,)\s*(0[xX])?[a-fA-F0-9]+', 37 | f"mov rax, {hex(header_size + file_size + 0x00400000)}") 38 | change_asm_file(f"src/{header_name}.asm", r'(mov)\s+(rcx)\s*(,)\s*(0[xX])?[a-fA-F0-9]+', f"mov rcx, {hex(file_size)}") 39 | compile_file(header_name) 40 | 41 | print(f"header size: {header_size}") 42 | print(f"file size: {file_size}") 43 | print(f"header_size + file_size: {header_size + file_size}") 44 | 45 | i = 0 46 | with open(f"in/{main_name}", 'r+b') as out: 47 | main = list(out.read()) 48 | # XOR 49 | while i < file_size: 50 | main[i] = main[i] ^ temp_key[len(temp_key) - 1 - (i % 8)] 51 | i += 1 52 | 53 | with open(f"out/{out_name}", "wb+") as out, open(f"in/{header_name}", "rb") as header: 54 | out.write(header.read()) 55 | out.write(bytearray(main)) 56 | 57 | a_bytes_little = (header_size + file_size).to_bytes(8, 'little') 58 | with open(f"out/{out_name}", 'r+b') as out: 59 | out.seek(0x60) 60 | out.write(a_bytes_little) 61 | out.write(a_bytes_little) 62 | -------------------------------------------------------------------------------- /modules/__pycache__/engine.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurak/Polymorphic_engine/8597a91310d64ae34e3bf41d33aa3ad8547450be/modules/__pycache__/engine.cpython-36.pyc -------------------------------------------------------------------------------- /modules/__pycache__/engine.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurak/Polymorphic_engine/8597a91310d64ae34e3bf41d33aa3ad8547450be/modules/__pycache__/engine.cpython-37.pyc -------------------------------------------------------------------------------- /modules/engine.py: -------------------------------------------------------------------------------- 1 | import re 2 | import random 3 | 4 | 5 | class SimplePol: 6 | """ 7 | Class to make from one asm file another one but polymorphic to the input file. 8 | """ 9 | 10 | def __init__(self, path): 11 | """ 12 | Initialisation of path to file and lists for parsing. 13 | :param path: string. 14 | """ 15 | self.stack_register = None 16 | self.add_sub_register = None 17 | self.border_pos = None 18 | self.all_registers_lst = ['rdx', 'rax', 'rcx', 'rsi', 'r11', 'rdi', 'rbx', 'r8', 'r10', 'r9', 'r12', 'r13', 19 | 'r14', 'r15', 'rbp', 'rsp'] 20 | self.path = path 21 | self.content = list() 22 | self.mov_xor_jmp_je_jk_lst = list() 23 | self.add_sub_lst = list() 24 | self.add_sub_lst_im = list() 25 | self.add_sub_lst_reg = list() 26 | self.register_lst = list() 27 | self.mul_lst = list() 28 | self.cmp_lst = list() 29 | 30 | def reader(self): 31 | """ 32 | Read asm file and parse it by \n. 33 | :return: None. 34 | """ 35 | with open(self.path) as f: 36 | for line in f: 37 | self.content.append(line.strip().split('\n')) 38 | 39 | def parser(self, word, lst): 40 | """ 41 | Find some command in the asm file. 42 | :param word: string 43 | :param lst: list of strings 44 | :return: None. 45 | """ 46 | for i in range(len(self.content)): 47 | if re.match(word, self.content[i][0]): 48 | lst.append(self.content[i]) 49 | 50 | def parser_register(self): 51 | """ 52 | Find all registers that used in asm file. 53 | :return: None 54 | """ 55 | for i in range(len(self.content)): 56 | length = len(self.content[i][0]) 57 | register = str() 58 | while length != 0: 59 | if self.content[i][0][length - 1] == ',': 60 | while self.content[i][0][length - 1] != ' ' and self.content[i][0][length - 1] != '\t': 61 | length -= 1 62 | if self.content[i][0][length - 1].isalnum(): 63 | register += self.content[i][0][length - 1] 64 | else: 65 | break 66 | break 67 | length -= 1 68 | if register: 69 | register = register[::-1] 70 | self.register_lst.append(register) 71 | self.register_lst = list(set(self.register_lst)) 72 | trash = list() 73 | for i in range(len(self.register_lst)): 74 | if len(self.register_lst[i]) > 3 or len(self.register_lst[i]) < 2: 75 | trash.append(self.register_lst[i]) 76 | for i in range(len(trash)): 77 | self.register_lst.remove(trash[i]) 78 | 79 | def parser_commands(self): 80 | """ 81 | Find all mov, cmp, jmp,je,jk commands in asm file. 82 | :return: None 83 | """ 84 | self.parser(r"mov|jmp|je|jk|xor", self.mov_xor_jmp_je_jk_lst) 85 | 86 | def parser_add_sub(self): 87 | """ 88 | Find all add and sub commands in asm file. 89 | :return: None 90 | """ 91 | self.parser(r"add|sub", self.add_sub_lst) 92 | 93 | def parser_cmp(self): 94 | """ 95 | Find all cmp commands in asm file. 96 | :return: None 97 | """ 98 | self.parser(r"cmp", self.cmp_lst) 99 | 100 | def parser_mul(self): 101 | """ 102 | Find in asm file all mul commands amd related nov commands. 103 | :return: None 104 | """ 105 | self.parser(r"mul", self.mul_lst) 106 | for i in range(len(self.mul_lst)): 107 | index = self.content.index(self.mul_lst[i]) 108 | self.mul_lst.insert(i, self.content[index - 1]) 109 | self.mul_lst.insert(i, self.content[index - 2]) 110 | 111 | def set_border(self): 112 | """ 113 | Function to detect the first command in asm code 114 | :return: None 115 | """ 116 | for i in range(len(self.content)): 117 | if self.content[i] in self.mov_xor_jmp_je_jk_lst or self.content[i] in self.cmp_lst or \ 118 | self.content[i] in self.mul_lst or self.content[i] in self.add_sub_lst: 119 | self.border_pos = self.content[i] 120 | break 121 | 122 | def classification_add_sub(self): 123 | """ 124 | Function to divide to different lists add and sub command. Add and sub with 125 | immediate and add with register. 126 | :return: None 127 | """ 128 | for i in range(len(self.add_sub_lst)): 129 | if re.search(r', ?[0-9]+', self.add_sub_lst[i][0]): 130 | self.add_sub_lst_im.append(self.add_sub_lst[i]) 131 | else: 132 | self.add_sub_lst_reg.append(self.add_sub_lst[i]) 133 | 134 | @staticmethod 135 | def number_division(number): 136 | """ 137 | Return a random number where param number is sup. 138 | :param number: int 139 | :return: None 140 | """ 141 | return random.randrange(number) 142 | 143 | @staticmethod 144 | def line_maker(line, number, reverse=False): 145 | """ 146 | Function to generate new line of asm code with add or sub and new 147 | numeric value. 148 | :param line: string 149 | :param number: int 150 | :param reverse: bool 151 | :return: string 152 | """ 153 | new_line = str() 154 | i = 0 155 | while line[i] != ',': 156 | new_line += line[i] 157 | i += 1 158 | new_line += ',' 159 | new_line += str(number) 160 | if reverse and new_line[0] == 'a': 161 | new_line = list(new_line) 162 | new_line[0], new_line[1], new_line[2] = 's', 'u', 'b' 163 | new_line = ''.join(new_line) 164 | elif reverse and new_line[0] == 's': 165 | new_line = list(new_line) 166 | new_line[0], new_line[1], new_line[2] = 'a', 'd', 'd' 167 | new_line = ''.join(new_line) 168 | return new_line 169 | 170 | def nope_adder(self, element): 171 | """ 172 | Add to asm code nop. 173 | :param element: list of elements 174 | :return: None 175 | """ 176 | index = self.content.index(element) 177 | self.content.insert(index, ['nop']) 178 | 179 | def division_adder_im(self, element): 180 | """ 181 | Extract a number from a line and choose how to divide it. 182 | :param element: list 183 | :return: None 184 | """ 185 | length = len(element[0]) 186 | number = str() 187 | exact_number = str() 188 | while element[0][length - 1] != ',': 189 | number += element[0][length - 1] 190 | length -= 1 191 | number = number.split() 192 | for i in range(len(number)): 193 | if number[i].isdecimal(): 194 | exact_number = number[i] 195 | break 196 | number = int(exact_number[::-1]) 197 | div = self.number_division(number) 198 | choice = random.choice([1, 2, 3]) 199 | if choice == 1: 200 | self.division_adder_im_2(element, div, number) 201 | elif choice == 2: 202 | self.division_adder_sub(element, div, number) 203 | else: 204 | self.division_adder_im_3(element, div, number) 205 | 206 | def division_adder_im_2(self, element, div, number): 207 | """ 208 | Add to asm code divided command of add or sub like: 209 | add eax 5 210 | add eax 3 211 | Instead of add eax 8 212 | :param element: list 213 | :param div: number 214 | :param number: number 215 | :return: None 216 | """ 217 | new_line = self.line_maker(element[0], div) 218 | self.content.insert(self.content.index(element), [new_line]) 219 | self.content[self.content.index(element)] = \ 220 | [self.line_maker(element[0], number - div)] 221 | 222 | def division_adder_im_3(self, element, div, number): 223 | """ 224 | Add to asm code divided command of add or sub like: 225 | add eax 1 226 | add eax 4 227 | add eax 3 228 | Instead of add eax 8 229 | :param element: list 230 | :param div: number 231 | :param number: number 232 | :return: None 233 | """ 234 | if div == 0: 235 | new_div = 0 236 | else: 237 | new_div = self.number_division(div) 238 | self.content.insert(self.content.index(element), [self.line_maker(element[0], new_div)]) 239 | self.content.insert(self.content.index(element), [self.line_maker(element[0], div - new_div)]) 240 | self.content[self.content.index(element)] = \ 241 | [self.line_maker(element[0], number - div)] 242 | 243 | def division_adder_sub(self, element, div, number): 244 | """ 245 | Function which transform single add or sub line. 246 | F.E.: 247 | Make from add eax, 10: 248 | add eax, 13 249 | sub eax, 3 250 | :param element: list of string 251 | :param div: number 252 | :param number: number 253 | :return: None 254 | """ 255 | new_div = random.randint(number + 1, number + div + 1) 256 | self.content.insert(self.content.index(element), [self.line_maker(element[0], new_div)]) 257 | self.content[self.content.index(element)] = \ 258 | [self.line_maker(element[0], new_div - number, True)] 259 | 260 | def add_sub_adder(self, element): 261 | """ 262 | Function which add two lines with add some number to eax and sub 263 | this number from eax register. 264 | :param element: list of elements 265 | :return: None 266 | """ 267 | reg = str() 268 | if not self.add_sub_register: 269 | for i in range(len(self.all_registers_lst)): 270 | if self.all_registers_lst[i] not in self.register_lst\ 271 | and self.all_registers_lst[i] != self.stack_register: 272 | reg = self.all_registers_lst[i] 273 | self.add_sub_register = self.all_registers_lst[i] 274 | break 275 | else: 276 | reg = self.add_sub_register 277 | index = self.content.index(element) 278 | number = self.number_division(10) 279 | self.content.insert(index, ['sub {}, {}'.format(reg, str(number))]) 280 | self.content.insert(index, ['add {}, {}'.format(reg, str(number))]) 281 | 282 | def stack_adder(self, element): 283 | """ 284 | Add to asm code push and pop of some register. 285 | :param element: list of elements 286 | :return: None 287 | """ 288 | reg = str() 289 | if not self.stack_register: 290 | for i in range(len(self.all_registers_lst)): 291 | if self.all_registers_lst[i] not in self.register_lst\ 292 | and self.add_sub_register != self.all_registers_lst[i]: 293 | reg = self.all_registers_lst[i] 294 | self.stack_register = self.all_registers_lst[i] 295 | break 296 | else: 297 | reg = self.stack_register 298 | index = self.content.index(element) 299 | self.content.insert(index, [f'pop {reg}']) 300 | self.content.insert(index, [f'push {reg}']) 301 | 302 | def stack_nop_adder(self, element): 303 | """ 304 | Add to code push pop of the register and nop between them. 305 | :param element: list of string 306 | :return: None 307 | """ 308 | reg = str() 309 | if not self.stack_register: 310 | for i in range(len(self.all_registers_lst)): 311 | if self.all_registers_lst[i] not in self.register_lst \ 312 | and self.add_sub_register != self.all_registers_lst[i]: 313 | reg = self.all_registers_lst[i] 314 | self.stack_register = self.all_registers_lst[i] 315 | break 316 | else: 317 | reg = self.stack_register 318 | index = self.content.index(element) 319 | self.content.insert(index, [f'pop {reg}']) 320 | self.content.insert(index, ['nop']) 321 | self.content.insert(index, [f'push {reg}']) 322 | 323 | def swap_of_reg(self, element): 324 | """ 325 | Swap to registers in cmp command 326 | :param element: list of elements 327 | :return: None 328 | """ 329 | if len(element[0]) > 16: 330 | return 0 331 | l_reg = str() 332 | f_reg = str() 333 | length = len(element[0]) - 1 334 | while element[0][length] != ',': 335 | l_reg += element[0][length] 336 | length -= 1 337 | while element[0][length] != 'p': 338 | f_reg += element[0][length] 339 | length -= 1 340 | if l_reg[-1] == ' ': 341 | l_reg = l_reg[:-1] 342 | l_reg = l_reg[::-1] 343 | if f_reg[-1] == ' ': 344 | f_reg = f_reg[:-1] 345 | f_reg = f_reg[::-1] 346 | f_reg = f_reg[:-1] 347 | if f_reg.isdecimal() or l_reg.isdecimal(): 348 | return 0 349 | self.content[self.content.index(element)] = [f"cmp {l_reg}, {f_reg}"] 350 | 351 | def commands_transformer(self): 352 | """ 353 | Modify every mov, jmp, jk, je command. 354 | :return: None 355 | """ 356 | for i in range(len(self.mov_xor_jmp_je_jk_lst)): 357 | choice = random.choice([1, 2, 3, 4]) 358 | if choice == 1: 359 | self.nope_adder(self.mov_xor_jmp_je_jk_lst[i]) 360 | elif choice == 2: 361 | self.add_sub_adder(self.mov_xor_jmp_je_jk_lst[i]) 362 | elif choice == 3: 363 | self.stack_nop_adder(self.mov_xor_jmp_je_jk_lst[i]) 364 | else: 365 | self.stack_adder(self.mov_xor_jmp_je_jk_lst[i]) 366 | 367 | def add_sub_transformer(self): 368 | """ 369 | Modify every add and sub command. 370 | :return: None 371 | """ 372 | self.set_border() 373 | for i in range(len(self.add_sub_lst_im)): 374 | choice = random.choice([1, 2, 3]) 375 | if choice == 1: 376 | self.nope_adder(self.add_sub_lst_im[i]) 377 | elif choice == 2: 378 | self.stack_adder(self.add_sub_lst_im[i]) 379 | else: 380 | self.division_adder_im(self.add_sub_lst_im[i]) 381 | for i in range(len(self.add_sub_lst_reg)): 382 | choice = random.choice([1, 2, 3]) 383 | if choice == 1: 384 | self.nope_adder(self.add_sub_lst_reg[i]) 385 | elif choice == 2: 386 | self.stack_adder(self.add_sub_lst_reg[i]) 387 | else: 388 | self.add_sub_adder(self.add_sub_lst_reg[i]) 389 | 390 | def mul_transform(self): 391 | """ 392 | Function to transform a mul command. 393 | :return: None 394 | """ 395 | for i in range(2, len(self.mul_lst), 3): 396 | choice = random.choice([i - 1, i - 2]) 397 | element = self.mul_lst[choice] 398 | length = len(element[0]) 399 | number = str() 400 | register = str() 401 | while element[0][length - 1] != ',': 402 | number += element[0][length - 1] 403 | length -= 1 404 | number = int(number[::-1]) 405 | div = self.number_division(number) 406 | line = self.line_maker(element[0], div) 407 | self.content[self.content.index(element)] = [line] 408 | while element[0][length - 1] != ' ': 409 | register += element[0][length - 1] 410 | length -= 1 411 | register = register[::-1] 412 | self.content.insert(self.content.index([line]) + 1, ['add {} {}'.format(register, str(number - div))]) 413 | 414 | def cmp_transform(self): 415 | """ 416 | Function to transform cmp command. 417 | :return: None 418 | """ 419 | for i in range(len(self.cmp_lst)): 420 | choice = random.choice([1, 2, 3]) 421 | choice = 3 422 | if choice == 1: 423 | self.nope_adder(self.cmp_lst[i]) 424 | elif choice == 2: 425 | self.stack_adder(self.cmp_lst[i]) 426 | else: 427 | self.swap_of_reg(self.cmp_lst[i]) 428 | 429 | def polymorph(self): 430 | """ 431 | Make code polymorphous and write it to new asm file. 432 | :return: None 433 | """ 434 | self.reader() 435 | self.parser_add_sub() 436 | self.parser_mul() 437 | self.parser_commands() 438 | self.parser_register() 439 | self.parser_cmp() 440 | self.set_border() 441 | self.classification_add_sub() 442 | self.commands_transformer() 443 | self.add_sub_transformer() 444 | self.mul_transform() 445 | self.cmp_transform() 446 | content = str() 447 | for i in range(len(self.content)): 448 | content += self.content[i][0] 449 | if i != len(self.content) - 1: 450 | content += '\n' 451 | with open(f"{self.path[:-4]}_pol.asm", 'w') as f: 452 | f.write(content) 453 | 454 | 455 | if __name__ == "__main__": 456 | a = SimplePol("simple.asm") 457 | a.polymorph() 458 | print(a.register_lst) 459 | -------------------------------------------------------------------------------- /out/encrypted: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurak/Polymorphic_engine/8597a91310d64ae34e3bf41d33aa3ad8547450be/out/encrypted -------------------------------------------------------------------------------- /out/not_encrypted: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurak/Polymorphic_engine/8597a91310d64ae34e3bf41d33aa3ad8547450be/out/not_encrypted -------------------------------------------------------------------------------- /src/all_nop.asm: -------------------------------------------------------------------------------- 1 | bits 64 2 | org 0x4000b4 ; DYNAMICALLY CHANGING 3 | ; Program start 4 | nop 5 | nop 6 | nop 7 | nop 8 | nop 9 | nop 10 | nop 11 | nop 12 | nop 13 | nop 14 | nop 15 | nop 16 | nop 17 | nop 18 | nop 19 | nop 20 | nop 21 | nop 22 | nop 23 | nop 24 | nop 25 | nop 26 | nop 27 | nop 28 | nop 29 | nop 30 | nop 31 | nop 32 | nop 33 | nop 34 | nop 35 | nop 36 | nop 37 | nop 38 | nop 39 | nop 40 | nop 41 | nop 42 | nop 43 | nop 44 | nop 45 | nop 46 | nop 47 | nop 48 | nop 49 | nop 50 | nop 51 | nop 52 | nop 53 | nop 54 | nop 55 | nop 56 | ; EXIT 57 | mov rax,60 58 | mov rdi, 0 59 | syscall 60 | 61 | ; File size calculation 62 | filesize equ $ - $$ 63 | -------------------------------------------------------------------------------- /src/bubble_sort.asm: -------------------------------------------------------------------------------- 1 | bits 64 2 | org 0x4000b3 ; DYNAMICALLY CHANGING 3 | 4 | mov r9, 0 5 | mov r10, len 6 | sub r10,1 7 | outer_loop: 8 | cmp r9,r10 9 | je done 10 | mov r8, 0 11 | inner_loop: 12 | mov rax, qword array 13 | mov rsi, [rax + r8*8] 14 | mov rdi, [rax + (r8 + 1)*8] 15 | cmp rsi, rdi 16 | jl skip 17 | 18 | mov rbx, [rax + r8*8] 19 | mov rcx, [rax + (r8 + 1)*8] 20 | mov [rax + r8*8], rcx 21 | mov [rax + (r8 + 1)*8], rbx 22 | skip: 23 | mov r11, r10 24 | sub r11, r9 25 | sub r11, 1 26 | cmp r8, r11 27 | je inner_loop_done 28 | inc r8 29 | jmp inner_loop 30 | inner_loop_done: 31 | inc r9 32 | jmp outer_loop 33 | 34 | done: 35 | mov r9,0 36 | mov r10, len 37 | push rbx 38 | print_loop: 39 | cmp r9,r10 40 | je codeEnd 41 | mov r11, qword array 42 | mov rax, [r11 + r9*8] 43 | call _print_RAX 44 | inc r9 45 | jmp print_loop 46 | 47 | _print_RAX: 48 | mov rcx, digit_space 49 | mov rbx,10 50 | mov [rcx],rbx 51 | inc rcx 52 | mov [digit_space_pos], rcx 53 | _print_RAX_loop: 54 | mov rdx,0 55 | mov rbx,10 56 | div rbx 57 | push rax 58 | add rdx, 48 59 | mov rcx,[digit_space_pos] 60 | mov [rcx],dl 61 | inc rcx 62 | mov [digit_space_pos], rcx 63 | 64 | pop rax 65 | cmp rax,0 66 | jne _print_RAX_loop 67 | 68 | _print_RAX_loop2: 69 | mov rcx, [digit_space_pos] 70 | mov rax, 1 71 | mov rdi, 1 72 | mov rsi, rcx 73 | mov rdx, 1 74 | syscall 75 | mov rcx, [digit_space_pos] 76 | dec rcx 77 | mov [digit_space_pos], rcx 78 | cmp rcx, digit_space 79 | jge _print_RAX_loop2 80 | ret 81 | nop 82 | nop 83 | nop 84 | nop 85 | codeEnd: 86 | mov rax,60 87 | mov rdi, 0 88 | syscall 89 | 90 | ; section .data 91 | array: dq 7, 9, 8, 1220, 3, 0 92 | len equ ($ - array)/ 8 93 | 94 | digit_space: dq 100 95 | digit_space_pos: dq 8 96 | 97 | ; File size calculation 98 | filesize equ $ - $$ 99 | 100 | -------------------------------------------------------------------------------- /src/header.asm: -------------------------------------------------------------------------------- 1 | ;name: elf64header.asm 2 | ; 3 | ;build: nasm -fbin -o header header.asm && chmod +x header 4 | bits 64 5 | org 0x00400000 ;Program load offset 6 | 7 | ;64-bit ELF header 8 | ehdr: 9 | ;ELF Magic + 2 (64-bit), 1 (LSB), 1 (ELF ver. 1), 0 (ABI ver.) 10 | db 0x7F, "ELF", 2, 1, 1, 0 ;e_ident 11 | 12 | times 8 db 0 ;reserved (zeroes) 13 | 14 | dw 2 ;e_type: Executable file 15 | dw 0x3e ;e_machine: AMD64 16 | dd 1 ;e_version: current version 17 | dq _start ;e_entry: program entry address (0x78) 18 | dq phdr - $$ ;e_phoff program header offset (0x40) 19 | dq 0 ;e_shoff no section headers 20 | dd 7 ;e_flags no flags 21 | dw ehdrsize ;e_ehsize: ELF header size (0x40) 22 | dw phdrsize ;e_phentsize: program header size (0x38) 23 | dw 1 ;e_phnum: one program header 24 | dw 0 ;e_shentsize 25 | dw 0 ;e_shnum 26 | dw 0 ;e_shstrndx 27 | ehdrsize equ $ - ehdr 28 | 29 | ;64-bit ELF program header 30 | phdr: 31 | dd 1 ;p_type: loadable segment 32 | dd 7 ;p_flags read and execute 33 | dq 0 ;p_offset 34 | dq $$ ;p_vaddr: start of the current section 35 | dq $$ ;p_paddr: 36 | dq filesize ;p_filesz 37 | dq filesize ;p_memsz 38 | dq 0x200000 ;p_align: 2^11=200000=11 bit boundaries 39 | 40 | ;program header size 41 | phdrsize equ $ - phdr 42 | 43 | _start: 44 | mov r10, 0x8E4E54DE6596DAEC ; set the key 45 | mov rax, 0x400203 ; starting address DYNAMICALLY CHANGING 46 | mov rcx, 0x160 ; length of not_encrypted block DYNAMICALLY CHANGING 47 | 48 | ; now decrypt the code, starting from the last byte 49 | decryptLoop: 50 | sub rax, 8 ; move to the next byte 51 | mov rbx,[rax] 52 | 53 | xor rbx, r10 ; decrypt qword 54 | ; xor rbx, r10 55 | mov qword [rax], rbx 56 | sub rcx, 8 57 | jnz decryptLoop 58 | ; File size calculation 59 | filesize equ $ - $$ -------------------------------------------------------------------------------- /src/header_pol.asm: -------------------------------------------------------------------------------- 1 | ;name: elf64header.asm 2 | ; 3 | ;build: nasm -fbin -o header header.asm && chmod +x header 4 | bits 64 5 | org 0x00400000 ;Program load offset 6 | 7 | ;64-bit ELF header 8 | ehdr: 9 | ;ELF Magic + 2 (64-bit), 1 (LSB), 1 (ELF ver. 1), 0 (ABI ver.) 10 | db 0x7F, "ELF", 2, 1, 1, 0 ;e_ident 11 | 12 | times 8 db 0 ;reserved (zeroes) 13 | 14 | dw 2 ;e_type: Executable file 15 | dw 0x3e ;e_machine: AMD64 16 | dd 1 ;e_version: current version 17 | dq _start ;e_entry: program entry address (0x78) 18 | dq phdr - $$ ;e_phoff program header offset (0x40) 19 | dq 0 ;e_shoff no section headers 20 | dd 7 ;e_flags no flags 21 | dw ehdrsize ;e_ehsize: ELF header size (0x40) 22 | dw phdrsize ;e_phentsize: program header size (0x38) 23 | dw 1 ;e_phnum: one program header 24 | dw 0 ;e_shentsize 25 | dw 0 ;e_shnum 26 | dw 0 ;e_shstrndx 27 | ehdrsize equ $ - ehdr 28 | 29 | ;64-bit ELF program header 30 | phdr: 31 | dd 1 ;p_type: loadable segment 32 | dd 7 ;p_flags read and execute 33 | dq 0 ;p_offset 34 | dq $$ ;p_vaddr: start of the current section 35 | dq $$ ;p_paddr: 36 | dq filesize ;p_filesz 37 | dq filesize ;p_memsz 38 | dq 0x200000 ;p_align: 2^11=200000=11 bit boundaries 39 | 40 | ;program header size 41 | phdrsize equ $ - phdr 42 | 43 | _start: 44 | nop 45 | mov r10, 0x8E4E54DE6596DAEC ; set the key 46 | nop 47 | mov rax, 0x4000f4 ; starting address DYNAMICALLY CHANGING 48 | nop 49 | mov rcx, 0x40 ; length of not_encrypted block DYNAMICALLY CHANGING 50 | 51 | ; now decrypt the code, starting from the last byte 52 | decryptLoop: 53 | nop 54 | sub rax, 8 ; move to the next byte 55 | add rdx, 3 56 | sub rdx, 3 57 | mov rbx,[rax] 58 | 59 | xor rbx, r10 ; decrypt qword 60 | ; xor rbx, r10 61 | add rdx, 4 62 | sub rdx, 4 63 | mov qword [rax], rbx 64 | nop 65 | sub rcx, 8 66 | jnz decryptLoop 67 | ; File size calculation 68 | filesize equ $ - $$ -------------------------------------------------------------------------------- /tests/old_bubble.asm: -------------------------------------------------------------------------------- 1 | ; ---------------------------------------------------------------------------------------- 2 | ; Bubble sort of array, with syscalls 3 | ; 4 | ; nasm -felf64 bubble_sort.asm && ld bubble_sort.o && ./a.out 5 | ; nasm -felf64 -g -F dwarf bubble_sort.asm && ld bubble_sort.o && gdb a.out 6 | ; ---------------------------------------------------------------------------------------- 7 | BITS 64 8 | 9 | section .data 10 | array: dq 7, 9, 8, 120, 2, 1 11 | len equ ($ - array)/ 8 12 | 13 | section .bss 14 | digit_space resb 100 15 | digit_space_pos resb 8 16 | section .text 17 | 18 | global _start 19 | default rel 20 | 21 | _start: 22 | mov r9, 0 ; r9 = i 23 | mov r10, len ; r10 = len 24 | sub r10,1 25 | outer_loop: 26 | cmp r9,r10 ; if i < 10 -> outer_loop done 27 | je done 28 | mov r8, 0 ; r8 = j 29 | inner_loop: 30 | mov rax, qword array 31 | mov rsi, [rax + r8*8] ; rsi = array[j] 32 | mov rdi, [rax + (r8 + 1)*8] ; rdi = array[j+1] 33 | cmp rsi, rdi ; if (rsi > rdi){swapping}; else skip 34 | jl skip 35 | ; swapping 36 | mov rbx, [rax + r8*8] ; temp1 = d[j] 37 | mov rcx, [rax + (r8 + 1)*8] ; temp2 = d[j+1] 38 | mov [rax + r8*8], rcx ; d[j] = temp2 39 | mov [rax + (r8 + 1)*8], rbx ; d[j+1]= temp1 40 | skip: 41 | mov r11, r10 ; r11 = len - i - 1 42 | sub r11, r9 43 | sub r11, 1 44 | cmp r8, r11 ; if j < len - i - 1 -> inner_loop done i+= 1 45 | je inner_loop_done 46 | inc r8 ; else j += 1 47 | jmp inner_loop 48 | inner_loop_done: 49 | inc r9 50 | jmp outer_loop 51 | 52 | done: 53 | mov r9,0 54 | mov r10, len 55 | push rbx ; align stack 56 | print_loop: 57 | cmp r9,r10 58 | je exit 59 | mov r11, qword array 60 | mov rax, [r11 + r9*8] 61 | call _print_RAX 62 | inc r9 63 | jmp print_loop 64 | 65 | _print_RAX: 66 | mov rcx, digit_space 67 | mov rbx,10 68 | mov [rcx],rbx 69 | inc rcx 70 | mov [digit_space_pos], rcx 71 | _print_RAX_loop: 72 | mov rdx,0 73 | mov rbx,10 74 | div rbx 75 | push rax 76 | add rdx, 48 77 | mov rcx,[digit_space_pos] 78 | mov [rcx],dl 79 | inc rcx 80 | mov [digit_space_pos], rcx 81 | 82 | pop rax 83 | cmp rax,0 84 | jne _print_RAX_loop 85 | 86 | _print_RAX_loop2: 87 | mov rcx, [digit_space_pos] 88 | mov rax, 1 89 | mov rdi, 1 90 | mov rsi, rcx 91 | mov rdx, 1 92 | syscall 93 | mov rcx, [digit_space_pos] 94 | dec rcx 95 | mov [digit_space_pos], rcx 96 | cmp rcx, digit_space 97 | jge _print_RAX_loop2 98 | ret 99 | exit: 100 | mov rax,60 101 | mov rdi, 0 102 | syscall 103 | 104 | -------------------------------------------------------------------------------- /tests/simple.asm: -------------------------------------------------------------------------------- 1 | ;name: elf64header.asm 2 | ; 3 | ;build: nasm -fbin -o header header.asm && chmod +x header 4 | bits 64 5 | org 0x00400000 ;Program load offset 6 | 7 | ;64-bit ELF header 8 | ehdr: 9 | ;ELF Magic + 2 (64-bit), 1 (LSB), 1 (ELF ver. 1), 0 (ABI ver.) 10 | db 0x7F, "ELF", 2, 1, 1, 0 ;e_ident 11 | 12 | times 8 db 0 ;reserved (zeroes) 13 | 14 | dw 2 ;e_type: Executable file 15 | dw 0x3e ;e_machine: AMD64 16 | dd 1 ;e_version: current version 17 | dq _start ;e_entry: program entry address (0x78) 18 | dq phdr - $$ ;e_phoff program header offset (0x40) 19 | dq 0 ;e_shoff no section headers 20 | dd 7 ;e_flags no flags 21 | dw ehdrsize ;e_ehsize: ELF header size (0x40) 22 | dw phdrsize ;e_phentsize: program header size (0x38) 23 | dw 1 ;e_phnum: one program header 24 | dw 0 ;e_shentsize 25 | dw 0 ;e_shnum 26 | dw 0 ;e_shstrndx 27 | ehdrsize equ $ - ehdr 28 | 29 | ;64-bit ELF program header 30 | phdr: 31 | dd 1 ;p_type: loadable segment 32 | dd 7 ;p_flags read and execute 33 | dq 0 ;p_offset 34 | dq $$ ;p_vaddr: start of the current section 35 | dq $$ ;p_paddr: 36 | dq filesize ;p_filesz 37 | dq filesize ;p_memsz 38 | dq 0x200000 ;p_align: 2^11=200000=11 bit boundaries 39 | 40 | ;program header size 41 | phdrsize equ $ - phdr 42 | 43 | _start: 44 | mov r10, 0x8E4E54DE6596DAEC ; set the key 45 | mov rax, 0x400203 ; starting address DYNAMICALLY CHANGING 46 | mov rcx, 0x160 ; length of not_encrypted block DYNAMICALLY CHANGING 47 | 48 | ; now decrypt the code, starting from the last byte 49 | decryptLoop: 50 | sub rax, 8 ; move to the next byte 51 | mov rbx,[rax] 52 | 53 | xor rbx, r10 ; decrypt qword 54 | ; xor rbx, r10 55 | mov qword [rax], rbx 56 | sub rcx, 8 57 | jnz decryptLoop 58 | ; File size calculation 59 | filesize equ $ - $$ --------------------------------------------------------------------------------