├── .gitattributes ├── README.md ├── go.bat ├── release └── spe32_test.exe ├── spe32.asm └── spe32_test.asm /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple Polymorphic Engine — SPE32 2 | 3 | **Simple Polymorphic Engine (SPE32)** is a simple polymorphic engine 4 | for encrypting code and data. 5 | 6 | SPE32 allows you to encrypt any data and generate a **unique** 7 | decryption code for this data. The encryption algorithm uses 8 | randomly selected instructions and encryption keys. 9 | 10 | The generated decryption code will be different each time. 11 | 12 | ## Polymorphic decryption code as viewed in x86dbg debugger 13 | 14 | ![Polymorphic code in x86dbg debugger](https://www.pelock.com/img/en/products/simple-polymorphic-engine/simple-polymorphic-engine-spe32-poly-engine-x86dbg-debugger-1.png) 15 | 16 | ## Another polymorphic code mutation, this time with junk instructions 17 | 18 | ![Polymorphic code in x86dbg debugger with junk instructions](https://www.pelock.com/img/en/products/simple-polymorphic-engine/simple-polymorphic-engine-spe32-poly-engine-x86dbg-debugger-junk-code-2.png) 19 | 20 | ## SPE32 features and status 21 | 22 | The SPE32 engine is an amateur project that can be used to demonstrate what 23 | polymorphic engines are. I wrote it some time ago, but I thought 24 | it would be a good idea to make it public. 25 | 26 | The entire code was written in a **32-bit assembler** for the [MASM compiler](http://www.masm32.com/). 27 | 28 | Features: 29 | 30 | * entire code is position independent (delta offset is used to access data) 31 | * XOR, ADD, SUB used for encryption 32 | * junk opcodes generation - ADD,ADC,SUB,SBB,ROL,ROR,RCR,RCL,SHL,SHR,NOT,NEG,DEC,INC 33 | 34 | I don't provide technical support for SPE32, use it at your own risk. 35 | 36 | ## Fully fledged commercial polymorphic engine 37 | 38 | If you are looking for professional solution take a look at our **Poly Polymorphic Engine**. 39 | 40 | * https://www.pelock.com/products/poly-polymorphic-engine 41 | 42 | Poly Polymorphic Engine is the **only commercial polymorphic engine** available on the market. 43 | It's a highly specialized cryptographic solution which is used in anti-cracking software 44 | protection systems and anti-reverse engineering systems. Due to the complicated nature of 45 | their code, polymorphic engines aren't publicly available, and creating one requires 46 | highly specialized knowledge in low level assembly programming and reverse engineering 47 | as well as an extensive testing process. 48 | 49 | ![Poly Polymorphic Engine](https://www.pelock.com/img/en/products/poly-polymorphic-engine/poly-polymorphic-engine.svg) 50 | 51 | Bartosz Wójcik 52 | 53 | * Visit my site at — https://www.pelock.com 54 | * Twitter — https://twitter.com/PELock 55 | * GitHub — https://github.com/PELock -------------------------------------------------------------------------------- /go.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set file=spe32_test 3 | c:\masm32\bin\ml.exe /c /coff /Cp %file%.asm 4 | c:\masm32\bin\link.exe /OPT:NOWIN98 /SECTION:.text,RWE /SUBSYSTEM:WINDOWS,4.0 %file%.obj 5 | del *.obj 6 | :End 7 | pause 8 | cls -------------------------------------------------------------------------------- /release/spe32_test.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PELock/Simple-Polymorphic-Engine-SPE32/101cdd582c5e3d503df32eb5bd6ad5f8f9c3aab7/release/spe32_test.exe -------------------------------------------------------------------------------- /spe32.asm: -------------------------------------------------------------------------------- 1 | 2 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 3 | ; 4 | ; SIMPLE POLYMORPHIC ENGINE v1.0 5 | ; 6 | ; Features: 7 | ; 8 | ; - entire code is position independent (delta offset is used to access data) 9 | ; - XOR, ADD, SUB used for encryption 10 | ; - junk opcodes generation - add,adc,sub,sbb,rol,ror,rcr,rcl,shl,shr,not,neg,dec,inc 11 | ; 12 | ; API: 13 | ; 14 | ; push dwRandomSeed 15 | ; push iFlags 16 | ; push lpEncryptor 17 | ; push lEncryptor 18 | ; push lpDestination 19 | ; push lpSource 20 | ; push cSize 21 | ; call SPME32 22 | ; 23 | ; Parameters: 24 | ; 25 | ; dwRandomSeed - random seed 26 | ; iFlags - see below 27 | ; lpEncryptor - buffer to store encryptor body 28 | ; lEncryptor - size of buffer to store encryptor body 29 | ; lpDestination - pointer to buffer that will recieve poly decryptor body 30 | ; it must be large enough 31 | ; lpSource - pointer to buffer that will be encrypted, and after decryption 32 | ; poly decryptor jumps there (+delta offset) 33 | ; cSize - size of code or data to encrypt (in DWORDs units) 34 | ; 35 | ; Returned value: 36 | ; 37 | ; eax - size of poly decryptor 38 | ; 39 | ; Bartosz Wójcik | https://www.pelock.com 40 | ; 41 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 42 | 43 | PRESERVE_REGS equ 00000000000000000000000000000001b 44 | PRESERVE_FLAGS equ 00000000000000000000000000000010b 45 | DEBUG_MODE equ 00000000000000000000000000000100b 46 | 47 | GEN_JUNKS equ ON ; junk generator ON/OFF 48 | JUNKS equ 2 ; junks per call to _gen_junks proc 49 | REG_STATE equ 1 ; save and restore after decryption reg state 50 | 51 | ; x86 registers IDs 52 | _EAX equ 0 53 | _ECX equ 1 54 | _EDX equ 2 55 | _EBX equ 3 56 | _ESP equ 4 57 | _EBP equ 5 58 | _ESI equ 6 59 | _EDI equ 7 60 | 61 | ; helper macro to put int3 in the output code 62 | @bpx macro 63 | mov al,0CCh 64 | stosb 65 | endm 66 | 67 | SPE32 proc near 68 | 69 | pop eax ; return address 70 | 71 | pop ecx ; code size (in DWORD units) 72 | pop esi ; source 73 | pop edi ; destination of poly decryptor 74 | pop edx ; buffer size 75 | pop ebx ; encryptor buffer 76 | pop dword ptr[ebp+_spe32_flags] ; extra flags 77 | pop dword ptr[ebp+_spe32_seed] ; random seed 78 | 79 | push eax ; save return address 80 | 81 | push edi ; save stdcall registers 82 | push ebx 83 | push esi 84 | 85 | mov dword ptr[ebp+_spe32_encryptor],ebx 86 | 87 | fill_nops: 88 | mov byte ptr[ebx+edx-1],90h ;\ 89 | dec edx ; > fill encryptor buffer with NOPs 90 | jne fill_nops ;/ 91 | 92 | choose_rnd_regs: 93 | 94 | pushad 95 | 96 | get_random_for_reg: 97 | mov al,7 98 | call brandom32 99 | xchg eax,ecx 100 | jecxz get_random_for_reg 101 | 102 | lea edx, [ebp+used_registers] ; point to registers 103 | mangle_regs: 104 | push edx 105 | 106 | mov eax,dword ptr[edx] 107 | xchg al,ah 108 | rol eax,8 109 | xchg al,ah 110 | 111 | mov dword ptr[edx],eax 112 | inc edx 113 | 114 | mov eax,dword ptr[edx] 115 | rol eax,16 116 | xchg al,ah 117 | mov dword ptr[edx],eax 118 | inc edx 119 | 120 | mov eax,dword ptr[edx] 121 | ror eax,16 122 | xchg al,ah 123 | mov dword ptr[edx],eax 124 | 125 | pop edx 126 | 127 | loop mangle_regs 128 | 129 | popad 130 | 131 | call _debug_mode 132 | 133 | IFDEF REG_STATE 134 | mov edx,dword ptr[ebp+_spe32_flags] 135 | test edx,PRESERVE_REGS 136 | je __check_flags 137 | 138 | mov al,60h ; pushad 139 | stosb 140 | 141 | __check_flags: 142 | 143 | test edx,PRESERVE_FLAGS 144 | je __skip_save_all 145 | 146 | mov al,9Ch ; pushfd 147 | stosb 148 | 149 | __skip_save_all: 150 | ENDIF 151 | call _gen_junks 152 | 153 | mov al,0B8h ; mov preg,offset source 154 | or al,byte ptr[ebp+preg] ; 155 | stosb ; 156 | 157 | mov byte ptr[ebx],al 158 | inc ebx 159 | mov dword ptr[ebx],esi 160 | add ebx,4 161 | 162 | mov eax,esi ; source offset 163 | 164 | neg eax ; neg 165 | stosd 166 | 167 | mov ax,0D8F7h ; neg preg 168 | or ah,byte ptr[ebp+preg] 169 | stosw 170 | call _gen_junks 171 | 172 | mov al,03h ; add preg,ebp 173 | stosb ; lame way ;) 174 | mov al,byte ptr[ebp+preg] 175 | shl al,3 176 | or al,_EBP 177 | or al,11000000b 178 | stosb 179 | 180 | call _gen_junks 181 | 182 | mov al,0B8h ; mov creg,size_fo_code 183 | or al,byte ptr[ebp+creg] 184 | stosb 185 | 186 | mov byte ptr[ebx],al 187 | inc ebx 188 | 189 | mov dword ptr[ebx],ecx 190 | add ebx,4 191 | 192 | mov eax,ecx ; ecx size 193 | stosd 194 | 195 | mov dword ptr[ebp+__loop_here],edi 196 | 197 | ; 8Bh 000b 00 000 198 | ; ^vreg ^preg 199 | mov ax,008Bh ; mov vreg,[preg] 200 | or ah,byte ptr[ebp+vreg] 201 | shl ah,3 202 | or ah,byte ptr[ebp+preg] 203 | stosw 204 | 205 | mov word ptr[ebx],ax 206 | add ebx,2+100-3-5-1-1-10-3 207 | push ebx 208 | 209 | push ecx 210 | 211 | _get_passes: 212 | mov al,7 213 | call brandom32 214 | xchg eax,ecx 215 | jecxz _get_passes 216 | 217 | __gen_: 218 | push ecx 219 | 220 | call _gen_junks 221 | 222 | ;██████ MAKE XOR,ADD,SUB ███████████████████████████████████████████████████████████████████████ 223 | mov al,81h 224 | stosb 225 | 226 | mov byte ptr[ebx-2],al 227 | 228 | mov al,(_crypt_opcodes_len)/2 229 | call brandom32 230 | 231 | mov ax,word ptr[ebp+eax*2+_crypt_opcodes] 232 | or al,byte ptr[ebp+vreg] 233 | mov byte ptr[ebx-1],al 234 | shr eax,8 235 | or al,byte ptr[ebp+vreg] 236 | stosb 237 | 238 | call random32 239 | stosd 240 | 241 | mov dword ptr[ebx],eax 242 | sub ebx,6 243 | 244 | call _gen_junks 245 | 246 | pop ecx 247 | loop __gen_ 248 | 249 | 250 | pop ecx 251 | 252 | pop ebx 253 | add ebx,4 254 | 255 | mov al,89h ; mov [preg],vreg 256 | stosb 257 | 258 | mov byte ptr[ebx],al 259 | inc ebx 260 | 261 | mov al,byte ptr[ebp+vreg] 262 | shl al,3 263 | or al,byte ptr[ebp+preg] 264 | stosb 265 | 266 | mov byte ptr[ebx],al 267 | inc ebx 268 | 269 | ;██████ DECREMENT COUNTER REGISTER █████████████████████████████████████████████████████████████ 270 | 271 | __make_inc: 272 | mov al,4 273 | call brandom32 274 | dec eax 275 | je __sub_1 276 | dec eax 277 | je __sub_2 278 | 279 | mov al,48h ; dec creg 280 | or al,byte ptr[ebp+creg] 281 | stosb 282 | 283 | mov byte ptr[ebx],al 284 | inc ebx 285 | 286 | jmp __make_inc_exit 287 | __sub_1: 288 | mov ax,0E883h ; sub creg,1 289 | or ah,byte ptr[ebp+creg] 290 | stosw 291 | 292 | mov word ptr[ebx],ax 293 | inc ebx 294 | inc ebx 295 | 296 | mov al,1 297 | stosb 298 | 299 | mov byte ptr[ebx],al 300 | inc ebx 301 | 302 | jmp __make_inc_exit 303 | 304 | __sub_2: 305 | mov ax,0C083h ; add creg,-1 306 | or ah,byte ptr[ebp+creg] 307 | stosw 308 | 309 | mov word ptr[ebx],ax 310 | inc ebx 311 | inc ebx 312 | 313 | mov al,-1 314 | stosb 315 | 316 | mov byte ptr[ebx],al 317 | inc ebx 318 | 319 | call _gen_junks 320 | 321 | __make_inc_exit: 322 | mov ax,0C083h ; add preg,4 323 | or ah,byte ptr[ebp+preg] 324 | mov word ptr[ebx],ax 325 | inc ebx 326 | inc ebx 327 | mov byte ptr[ebx],4 328 | inc ebx 329 | 330 | mov al,4 331 | call brandom32 332 | dec eax 333 | je __inc_preg_1 334 | dec eax 335 | je __inc_preg_2 336 | 337 | mov ax,0C083h ; add preg,4 338 | or ah,byte ptr[ebp+preg] 339 | stosw 340 | mov al,4 341 | stosb 342 | jmp __test_counter 343 | 344 | __inc_preg_1: 345 | call _gen_junks 346 | 347 | mov ax,0E883h ; sub preg,-4 348 | or ah,byte ptr[ebp+preg] 349 | stosw 350 | mov al,-4 351 | stosb 352 | jmp __test_counter 353 | 354 | __inc_preg_2: 355 | call _gen_junks 356 | 357 | mov al,8Dh ; lea preg,[preg+4] 358 | stosb 359 | 360 | mov al,byte ptr[ebp+preg] 361 | shl al,3 362 | or al,byte ptr[ebp+preg] 363 | or al,01000000b 364 | stosb 365 | 366 | mov al,4 367 | stosb 368 | 369 | __test_counter: 370 | call _gen_junks 371 | 372 | mov al,(_test_table_len/4) 373 | call brandom32 374 | 375 | mov eax,[ebp+eax*4+offset _test_table] 376 | lea eax,[eax+ebp] 377 | jmp eax 378 | 379 | __test_0: 380 | call _gen_junks 381 | 382 | mov ax,0F883h ; cmp creg,0 383 | or ah,byte ptr[ebp+creg] 384 | stosw 385 | sub eax,eax 386 | stosb 387 | jmp __test_counter_exit 388 | 389 | __test_1: 390 | call _gen_junks 391 | 392 | mov al,85h 393 | stosb 394 | 395 | mov al,byte ptr[ebp+creg] ; test creg,creg 396 | shl al,3 397 | or al,byte ptr[ebp+creg] 398 | or al,11000000b 399 | 400 | stosb 401 | jmp __test_counter_exit 402 | 403 | __test_2: 404 | call _gen_junks 405 | 406 | mov al,8Bh 407 | stosb 408 | 409 | mov al,byte ptr[ebp+jrg1] 410 | 411 | shl al,3 412 | or al,byte ptr[ebp+creg] ; mov jrg1,creg 413 | or al,11000000b ; mov reg,reg 414 | stosb 415 | 416 | mov ax,0F883h ; cmp jrg,0 417 | or ah,byte ptr[ebp+jrg1] 418 | stosw 419 | sub eax,eax 420 | stosb 421 | jmp __test_counter_exit 422 | 423 | __test_3: 424 | 425 | mov al,50h 426 | or al,byte ptr[ebp+creg] ; push creg 427 | stosb 428 | 429 | call _gen_junks 430 | 431 | mov al,58h ; pop jrg2 432 | or al,byte ptr[ebp+jrg2] 433 | stosb 434 | 435 | mov al,85h 436 | stosb 437 | 438 | mov al,byte ptr[ebp+jrg2] ; test jrg2,jrg2 439 | shl al,3 440 | or al,byte ptr[ebp+jrg2] 441 | or al,11000000b 442 | 443 | stosb 444 | 445 | __test_counter_exit: 446 | 447 | mov ax,0F883h ; cmp creg,0 448 | or ah,byte ptr[ebp+creg] 449 | mov word ptr[ebx],ax 450 | inc ebx 451 | inc ebx 452 | 453 | mov byte ptr[ebx],0 454 | inc ebx 455 | 456 | mov ax,850Fh 457 | stosw 458 | 459 | mov word ptr[ebx],ax 460 | inc ebx 461 | inc ebx 462 | 463 | mov eax,12345678 464 | 465 | __loop_here equ dword ptr $-4 466 | 467 | sub eax,edi 468 | sub eax,4 469 | stosd ; jne _decrypt_rest 470 | 471 | mov eax,dword ptr[ebp+_spe32_encryptor] 472 | add eax,6 473 | 474 | sub eax,ebx 475 | 476 | mov dword ptr[ebx],eax 477 | add ebx,4 478 | 479 | call _gen_junks 480 | 481 | ;██████ POP ALL REGISTERS ██████████████████████████████████████████████████████████████████████ 482 | __pop_regs: 483 | 484 | mov edx,[ebp+_spe32_flags] 485 | 486 | IFDEF REG_STATE 487 | test edx,PRESERVE_REGS 488 | je __check_rflags 489 | mov al,61h 490 | stosb 491 | __check_rflags: 492 | test edx,PRESERVE_FLAGS 493 | je __skip_restore_all 494 | mov al,9Dh ; pushad,pushfd 495 | stosb 496 | __skip_restore_all: 497 | ENDIF 498 | 499 | ; @bpx 500 | 501 | call _debug_mode ; set int 3 502 | 503 | mov byte ptr[ebx],0C3h ; ret 504 | 505 | mov al,0E9h ; jmp decrypted_code 506 | stosb 507 | 508 | pop eax ; eax pointer to code 509 | sub eax,edi ; edi current position 510 | sub eax,4 ; size of jmp - 1 511 | stosd ; save it 512 | 513 | mov ax,25FFh 514 | stosw 515 | 516 | stosd 517 | 518 | call _gen_junks 519 | ;int 3 520 | pop ebx 521 | call ebx 522 | 523 | pop eax 524 | sub edi,eax 525 | xchg edi,eax 526 | 527 | ret 528 | 529 | ;█ S U B R O U T I N E S ███████████████████████████████████████████████████████████████████████ 530 | 531 | brandom32 proc near 532 | 533 | push edx 534 | and eax,000000FFh ; al - param 535 | push eax 536 | call random32 537 | pop ecx 538 | sub edx,edx 539 | div ecx 540 | xchg eax,edx ; calc modulo n 541 | pop edx 542 | 543 | ret 544 | 545 | brandom32 endp 546 | 547 | ; WhizKid random num generator 548 | random32 proc near 549 | 550 | push edx 551 | push ecx 552 | 553 | mov eax,[ebp+offset _spe32_seed] ; Move bits 31-0 of old seed to EAX 554 | ; Move bits 38-32 of old seed to DL, set DH = 0 555 | movzx edx, byte ptr [ebp+offset _spe32_seed+4] 556 | ; Shift bits 32-1 to bits 31-0 557 | shrd eax, edx, 1 558 | mov dword ptr[ebp+offset _spe32_seed], eax ; Save bits 31-0 of new seed 559 | adc dh, 0 ; DH = bit shifted out of EAX 560 | shr dl, 1 ; Shift bits 38-33 of old seed to bits 37-32 561 | mov cl, dl ; Get bit 35 of old seed to the lsb of CL 562 | shr cl, 2 563 | and cl, 1 ; CL = bit 35 of old seed 564 | xor dh, cl ; xor it with old bit 0 565 | shl dh, 6 566 | or dl, dh ; store it in bit 38 ... 567 | mov byte ptr [ebp+offset _spe32_seed+4],dl ; ... of new seed 568 | 569 | pop ecx 570 | pop edx 571 | ret 572 | 573 | _spe32_seed dd 987374832 ; seed for random proc 574 | db 11101b ; at least one of the 39 bits must be non-zero! 575 | 576 | random32 endp 577 | 578 | _debug_mode proc near 579 | 580 | mov edx,dword ptr[ebp+_spe32_flags] 581 | test edx,DEBUG_MODE 582 | je _skip_debug_mark 583 | 584 | @bpx 585 | 586 | _skip_debug_mark: 587 | ret 588 | 589 | _debug_mode endp 590 | 591 | ;██████ JUNK GEN ███████████████████████████████████████████████████████████████████████████████ 592 | 593 | _gen_junks proc near 594 | 595 | IFDEF GEN_JUNKS 596 | push ecx ; save global size of code 597 | 598 | IFDEF JUNKS 599 | mov al,JUNKS 600 | __gen_junk_passes: 601 | call brandom32 602 | xchg eax,ecx 603 | jecxz __gen_junk_passes 604 | 605 | _gen_junks_loop: 606 | push ecx 607 | ENDIF 608 | 609 | mov al,(_junk_table_len/4) 610 | call brandom32 611 | 612 | mov eax,[ebp+eax*4+offset _junk_table] 613 | lea eax,[eax+ebp] 614 | jmp eax 615 | 616 | __junk_1 label near 617 | mov al,81h 618 | stosb 619 | 620 | mov al,3 621 | call brandom32 622 | 623 | mov al,byte ptr[ebp+eax*2+_crypt_opcodes] 624 | push eax 625 | 626 | mov al,2 627 | call brandom32 628 | xchg eax,ecx 629 | 630 | pop eax 631 | 632 | jecxz __junk_1_1 633 | 634 | or al,byte ptr[ebp+jrg1] 635 | jmp __junk_1_2 636 | __junk_1_1: 637 | or al,byte ptr[ebp+jrg2] 638 | __junk_1_2: 639 | stosb 640 | jmp __junk_key 641 | 642 | __junk_2 label near 643 | 644 | __junk_3 label near 645 | mov al,0E8h ; call $+7 646 | stosb 647 | 648 | mov al,2 649 | call brandom32 650 | 651 | test eax,eax 652 | je __call_2 653 | 654 | sub eax,eax 655 | mov al,2 656 | stosd 657 | 658 | mov al,2 659 | call brandom32 660 | xchg eax,ecx 661 | jecxz __junk_3_2 662 | 663 | mov ax,9066h ; 32bit nop 664 | stosw 665 | jmp __exit_from_call 666 | 667 | __call_2: 668 | sub eax,eax 669 | stosd 670 | __junk_3_1: 671 | 672 | mov al,0Bh ; range 673 | call brandom32 674 | 675 | add al,74h ; jxx $+3 676 | mov ah,01h 677 | stosw 678 | 679 | call random32 680 | and eax,8 681 | 682 | add al,40h ; inc,dec jreg1 683 | or al,byte ptr[ebp+jrg1] 684 | stosb 685 | 686 | jmp __exit_from_call 687 | __junk_3_2: 688 | mov ax,01EBh ; jmp $+3 689 | stosw 690 | 691 | mov al,0C3h ; ret 692 | stosb 693 | jmp __junk_gen_exit 694 | 695 | __exit_from_call: 696 | 697 | mov al,2 698 | call brandom32 699 | test eax,eax 700 | je __exit_1_1 ; select stack adjust method(pop or add esp) 701 | 702 | mov ax,0C483h ; add esp,4 703 | stosw 704 | 705 | mov al,04 706 | stosb 707 | jmp __junk_gen_exit 708 | 709 | __exit_1_1: 710 | 711 | mov al,2 712 | call brandom32 713 | xchg eax,ecx 714 | 715 | mov al,58h 716 | jecxz __exit_1_1_1 717 | 718 | or al,byte ptr[ebp+jrg1] ; pop jrg1 719 | jmp __exit_1_1_2 720 | __exit_1_1_1: 721 | or al,byte ptr[ebp+jrg2] ; pop jrg2 722 | __exit_1_1_2: 723 | stosb 724 | jmp __junk_gen_exit 725 | 726 | __junk_key: 727 | call random32 728 | stosd 729 | jmp __junk_gen_exit 730 | 731 | __junk_4 label near 732 | mov al,0E8h ; call $+6 733 | stosb 734 | 735 | sub eax,eax 736 | inc eax 737 | stosd 738 | 739 | call random32 740 | stosb ; db trash 741 | jmp __exit_from_call ; adjust stack 742 | 743 | ;█ MOV DRx,JRGx █████████████████████████████████████████████████████████████████████████████████ 744 | __junk_5 label near 745 | ; 746 | ; mov al,2 747 | ; call brandom32 748 | ; xchg eax,ecx 749 | ; 750 | ; mov al,0Fh 751 | ; 752 | ; jecxz __mov_drX_reg 753 | ; 754 | ; mov ah,23h ; mov drX,reg 755 | ; jmp __mov_reg_drX 756 | ; 757 | ;__mov_drX_reg: 758 | ; mov ah,21h ; mov reg,drX 759 | ;__mov_reg_drX: 760 | ; stosw 761 | ; mov al,7 ; select random drX 762 | ; call brandom32 763 | ; 764 | ; shl al,3 765 | ; or al,11000000b 766 | ; 767 | ; push eax 768 | ; 769 | ; mov al,2 770 | ; call brandom32 771 | ; xchg eax,ecx 772 | ; 773 | ; pop eax 774 | ; 775 | ; jecxz __mov_drX_jrg1 776 | ; 777 | ; or al,byte ptr[ebp+jrg2] 778 | ; jmp __mov_drX_jrg2 779 | ;__mov_drX_jrg1: 780 | ; or al,byte ptr[ebp+jrg1] 781 | ;__mov_drX_jrg2: 782 | ; stosb 783 | 784 | ;█ JMP $+3 █████████████████████████████████████████████████████████████████████████████████████ 785 | 786 | __junk_6 label near 787 | 788 | mov ax,02EBh ; jmp $+4 789 | stosw 790 | 791 | mov al,2 792 | call brandom32 793 | xchg eax,ecx 794 | jecxz __fake_vxdcall 795 | 796 | call random32 797 | jmp __skip_shit 798 | __fake_vxdcall: 799 | mov ax,20CDh ; VxDCall ??????? 800 | __skip_shit: 801 | stosw ; dw RND 802 | 803 | jmp __junk_gen_exit 804 | 805 | ;█ FAKE MOV ████████████████████████████████████████████████████████████████████████████████████ 806 | ; mov jrg1,anyreg 807 | ; mov jrg2,anyreg 808 | 809 | __junk_7 label near 810 | 811 | mov al,8Bh 812 | stosb 813 | 814 | mov al,6 815 | call brandom32 816 | 817 | mov dl,byte ptr[ebp+eax+used_registers] 818 | 819 | mov al,2 820 | call brandom32 821 | 822 | xchg eax,ecx 823 | jecxz _use_jrg1 824 | 825 | mov al,byte ptr[ebp+jrg2] 826 | jmp _build_mov_jrg 827 | 828 | _use_jrg1: 829 | 830 | mov al,byte ptr[ebp+jrg1] 831 | 832 | _build_mov_jrg: 833 | 834 | shl al,3 835 | or al,dl 836 | or al,11000000b ; mov reg,reg 837 | stosb 838 | jmp __junk_gen_exit 839 | 840 | ;█ Jxx $+2 █████████████████████████████████████████████████████████████████████████████████████ 841 | 842 | __junk_8 label near 843 | 844 | mov al,0Bh 845 | call brandom32 846 | 847 | add al,74h ; jxx $+2 848 | stosw 849 | 850 | jmp __junk_gen_exit 851 | 852 | ;█ ROx,RCx,SHx JRG1,BYTE ████████████████████████████████████████████████████████████████████████ 853 | 854 | __junk_9 label near 855 | 856 | mov al,0C1h 857 | stosb 858 | 859 | mov al,_junk_opcodes_3_len 860 | call brandom32 861 | push eax 862 | 863 | call random32 864 | and eax,8 865 | 866 | pop edx 867 | 868 | add al,byte ptr[ebp+edx+_junk_opcodes_3] 869 | or al,byte ptr[ebp+jrg1] 870 | stosb 871 | 872 | call random32 873 | stosb 874 | 875 | jmp __junk_gen_exit 876 | 877 | ;█ AND,OR,NEG,NOT JRG2, ANY ████████████████████████████████████████████████████████████████████ 878 | 879 | __junk_10 label near 880 | 881 | mov al,_junk_opcodes_2_len 882 | call brandom32 883 | 884 | mov al,byte ptr[ebp+eax+_junk_opcodes_2] 885 | stosb 886 | 887 | mov al,7 888 | call brandom32 889 | xchg eax,edx 890 | 891 | mov al,byte ptr[ebp+jrg2] 892 | shl al,3 893 | or al,dl 894 | or al,11000000b 895 | stosb 896 | 897 | jmp __junk_gen_exit 898 | 899 | ;█ BT,BTR,BTS,BTC JRGX,ANY █████████████████████████████████████████████████████████████████████ 900 | 901 | __junk_11 label near 902 | 903 | mov al,0Fh 904 | stosb 905 | 906 | mov al,4 907 | call brandom32 908 | 909 | mov al,byte ptr[ebp+eax+__bt_opcodes] 910 | 911 | __junk_11_end: 912 | stosb 913 | 914 | mov al,7 915 | call brandom32 916 | shl al,3 917 | or al,11000000b 918 | xchg eax,edx 919 | 920 | mov al,2 921 | call brandom32 922 | xchg eax,ecx 923 | jecxz __junk_11_jrg1 924 | 925 | or dl,byte ptr[ebp+jrg2] 926 | 927 | jmp __junk_11_jrg2 928 | 929 | __junk_11_jrg1: 930 | or dl,byte ptr[ebp+jrg1] 931 | 932 | __junk_11_jrg2: 933 | xchg eax,edx 934 | stosb 935 | 936 | jmp __junk_gen_exit 937 | 938 | __junk_gen_exit: 939 | 940 | IFDEF JUNKS 941 | pop ecx 942 | dec ecx 943 | jne _gen_junks_loop 944 | ENDIF 945 | pop ecx 946 | ENDIF 947 | ret 948 | _gen_junks endp 949 | 950 | IFDEF GEN_JUNKS 951 | 952 | _junk_table dd offset __junk_1 953 | dd offset __junk_2 954 | dd offset __junk_3 955 | dd offset __junk_3 956 | dd offset __junk_4 957 | dd offset __junk_5 958 | dd offset __junk_6 959 | dd offset __junk_7 960 | dd offset __junk_8 961 | dd offset __junk_9 962 | dd offset __junk_10 963 | dd offset __junk_11 964 | _junk_table_len equ $-_junk_table 965 | 966 | ; 3bytes 967 | ; prefix 0C1h 968 | _junk_opcodes_3 db 0C0h ; rol,ror reg,byte 969 | db 0D0h ; rcl,rcr reg,byte 970 | db 0E0h ; shl,shr reg,byte 971 | _junk_opcodes_3_len equ $-_junk_opcodes_3 972 | 973 | db 0F7h,0D0h ; not reg 974 | db 0F7h,0D8h ; neg reg 975 | 976 | __bt_opcodes db 0A3h ; bt jrgx,any 977 | db 0ABh ; bts jrgx,any 978 | db 0B3h ; btr jrgx,any 979 | db 0BBh ; btc jrgx,any 980 | 981 | ; 2bytes 982 | ; MOD/R Cx 983 | _junk_opcodes_2 db 03Bh ; cmp 984 | db 02Bh ; sub 985 | db 003h ; add 986 | db 01Bh ; sbb 987 | db 013h ; adc 988 | db 023h ; and 989 | db 00Bh ; or 990 | _junk_opcodes_2_len equ $-_junk_opcodes_2 991 | 992 | ENDIF 993 | 994 | _test_table dd offset __test_0 995 | dd offset __test_1 996 | dd offset __test_2 997 | dd offset __test_3 998 | _test_table_len equ $-_test_table 999 | 1000 | _spe32_encryptor dd 0 1001 | _spe32_flags dd 0 1002 | 1003 | used_registers label near 1004 | kreg db 0 ; key r 1005 | preg db 1 ; pointer r 1006 | creg db 2 ; counter r 1007 | vreg db 3 ; value r 1008 | jrg1 db 6 ; junk reg 1 1009 | jrg2 db 7 ; junk reg 2 1010 | 1011 | ; 6bytes 1012 | 1013 | _crypt_opcodes label near 1014 | _sub db 0E8h,0C0h 1015 | _add db 0C0h,0E8h 1016 | _xor db 0F0h,0F0h 1017 | _crypt_opcodes_len equ $-_crypt_opcodes 1018 | 1019 | SPE32 endp -------------------------------------------------------------------------------- /spe32_test.asm: -------------------------------------------------------------------------------- 1 | 2 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 3 | ; 4 | ; SIMPLE POLYMORPHIC ENGINE v1.0 5 | ; 6 | ; The SPE32 engine is an amateur project that can be used to demonstrate what 7 | ; polymorphic engines are. I wrote it some time ago, but I thought 8 | ; it would be a good idea to make it public. 9 | ; 10 | ; Bartosz Wójcik | https://www.pelock.com 11 | ; 12 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 13 | 14 | .686 ; Pentium 4 instructions 15 | .mmx ; +MMX 16 | .xmm ; +SSE, +SSE2 17 | .model flat,stdcall 18 | 19 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 20 | ; 21 | ; libraries 22 | ; 23 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 24 | 25 | includelib c:\masm32\lib\kernel32.lib 26 | includelib c:\masm32\lib\user32.lib 27 | includelib c:\masm32\lib\gdi32.lib 28 | 29 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 30 | ; 31 | ; headers 32 | ; 33 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 34 | 35 | include c:\masm32\include\kernel32.inc 36 | include c:\masm32\include\user32.inc 37 | include c:\masm32\include\gdi32.inc 38 | 39 | include c:\masm32\include\windows.inc 40 | 41 | POLY_DECRYPTOR_BUFFER_SIZE equ 255 42 | 43 | .data 44 | szCpt db 'SPE32 - visit https://www.pelock.com',0 45 | szTest db 'SIMPLE POLYMORPHIC ENGINE v1.0 - Bartosz Wojcik',0 46 | .code 47 | 48 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 49 | ; 50 | ; SPE32 engine code (.code section must be writeable) 51 | ; 52 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 53 | 54 | include spe32.asm 55 | 56 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 57 | ; 58 | ; applicatin entrypoint main() 59 | ; 60 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 61 | 62 | _start: 63 | 64 | ;────────────────────────────────────────────────────────────────────────────────────────────── 65 | ; calculate delta offset 66 | ;────────────────────────────────────────────────────────────────────────────────────────────── 67 | call _delta 68 | _delta: pop ebp 69 | sub ebp,offset _delta 70 | 71 | ;────────────────────────────────────────────────────────────────────────────────────────────── 72 | ; random generator within SPE32 seed 73 | ;────────────────────────────────────────────────────────────────────────────────────────────── 74 | call GetTickCount 75 | lea eax,[eax*8+eax] 76 | lea ebx,[eax*8+edx] ; store random seed in EBX 77 | 78 | ;────────────────────────────────────────────────────────────────────────────────────────────── 79 | ; allocate executable memory for temporary encryptor code 80 | ;────────────────────────────────────────────────────────────────────────────────────────────── 81 | push PAGE_EXECUTE_READWRITE 82 | push MEM_RESERVE or MEM_COMMIT 83 | push POLY_DECRYPTOR_BUFFER_SIZE 84 | push 0 85 | call VirtualAlloc 86 | mov edi,eax 87 | 88 | ;────────────────────────────────────────────────────────────────────────────────────────────── 89 | ; encrypt sample_code_to_encrypt() function code and generate polymorphic 90 | ; decryption code 91 | ;────────────────────────────────────────────────────────────────────────────────────────────── 92 | push eax ; save allocated memory pointer 93 | 94 | push ebx ; random seed 95 | push PRESERVE_REGS or PRESERVE_FLAGS ; flags 96 | push edi ; buffer to store encryptor body (temp buffer) 97 | push POLY_DECRYPTOR_BUFFER_SIZE ; size of buffer to store encryptor body 98 | push offset output_poly_decryptor ; pointer to buffer that will recieve poly decryptor body 99 | push offset sample_code_to_encrypt ; pointer to buffer that will be encrypted 100 | push sample_code_to_encrypt_len/4 ; size of code or data to encrypt (in DWORDs units) 101 | call SPE32 ; encrypt code/data and generate 102 | ; polymorphic decryptor 103 | 104 | ;────────────────────────────────────────────────────────────────────────────────────────────── 105 | ; execute polymorphic decryptor code 106 | ;────────────────────────────────────────────────────────────────────────────────────────────── 107 | 108 | ; for debugging purposes 109 | int 3 110 | 111 | ; jump to the decryption code 112 | jmp output_poly_decryptor 113 | 114 | exit: 115 | 116 | ;────────────────────────────────────────────────────────────────────────────────────────────── 117 | ; release the memory 118 | ;────────────────────────────────────────────────────────────────────────────────────────────── 119 | pop eax ; restore allocated memory pointer 120 | 121 | push MEM_RELEASE 122 | push 0 123 | push eax 124 | call VirtualFree 125 | 126 | push 0 127 | call ExitProcess 128 | 129 | ;────────────────────────────────────────────────────────────────────────────────────────────── 130 | ; this buffer will receive the decryptor body 131 | ;────────────────────────────────────────────────────────────────────────────────────────────── 132 | output_poly_decryptor: 133 | 134 | db 1000h dup(0) 135 | 136 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 137 | ; 138 | ; this code is going to be encrypted 139 | ; 140 | ;██████████████████████████████████████████████████████████████████████████████████████████████ 141 | 142 | align 16 143 | sample_code_to_encrypt: 144 | 145 | push MB_ICONINFORMATION 146 | push offset szTest 147 | push offset szCpt 148 | push 0 149 | call MessageBoxA 150 | 151 | jmp exit 152 | 153 | dd 10 dup(90h) ; safe space alignment 154 | 155 | sample_code_to_encrypt_len equ $-sample_code_to_encrypt 156 | 157 | end _start 158 | --------------------------------------------------------------------------------