Problēmas ar vienkāršāko decompiler

link: https://www.backerstreet.com/decompiler/simple_problems.htm

Aplūkosim problēmas, kas ir ieviests ar vienkāršu decompiler aprakstīts iepriekš, un mēģināt atrast iespējamo risinājumu. Sāksim ar ievadinstruktāža mēs decompiled:

0x004011E5:  or byte [ebp-0x3], 0x8  ->  L4011E5:    ebp[-0x3] |= 0x8;
  • EBP ir procesors reģistrā, līdz ar to nav zināms, vispārējs sastādītājs; tādēļ, lai mūsu programma sastādīta, mums ir nepieciešams atzīt EBP. Šajā gadījumā, mēs varam atzīt, EBP jābūt rādītāju uz dažu baitu, kas ir:
        unsigned char *ebp;
        ebp[-0x3] |= 0x8;
    
  • EBP ir galvenokārt izmanto, lai norādītu uz rāmja vietējo procedūru, lai minētais apgalvojums ir, iespējams, mēģina piekļūt vietējo mainīgais, kas tika atzīts baita lieluma. Tomēr, var būt arī citi vietējo mainīgie, kas ir dažādu izmēru, un tie visi ir piekļūt, izmantojot EBP (dažādu nobīdes no EBP), tāpēc, paziņojot, EBP kā neparakstīts char rādītāju nestrādās par tiem citiem mainīgajiem. Mēs varam atrisināt šo problēmu, liekot lielumu katra piekļūšana caur reģistrā, pamatojoties uz izmēru oriģinālā instrukcija:
        char *bp;
        *(char *)(ebp-0x3) |= 0x8;
    

    Piekļūšana dažādu mainīgo izmantot citu izmeta:

        *(short *)(ebp-0x8) += 10;
    
  • Lai gan parasti EBP satur adreses, ir gadījumi, kad kompilators varētu to izmantot, lai turiet ciparu konstante (rāmis-mazāk funkcijas EBP izmanto tāpat kā visi citi reģistrā). Ja EBP izmanto aritmētiskās darbības, kas nav + vai -, kompilators sūdzēties, ja mēs paziņojam, tā char *. Tāpēc mums ir nepieciešams atzīt to kā int. Tas nav problēma, kad izmantojot vairākumu pieeja iepriekš, jo pievienojot un atņemot no skaitlim ir būtībā tāda pati kā pievienojot un atņemot no char *.
  • Viena lietošanas veida, ka nav viegli tulkots, izmantojot iepriekš minētās metodes ir tiem, instrukcijas, kas nosaka reģistru adresi, lai izmantotu vēlāk. Šīs instrukcijas var nošķirt no instrukcijas, ka slodze ir nemainīga ciparu daži vēlāk aprēķins:
    8D 3C 85 DC 68 40 00       lea edi, [eax*4+0x4068DC] // A
    8D 3C 85 04 00 00 00       lea edi, [eax*4+4]        // B
    

    Tulkošanas par šiem diviem norādījumiem, ir diezgan atšķirīgs:

       edi = &var_4068DC[eax*4];    // A
       edi = 4 + eax * 4;           // B
    

    Kāpēc šāda atšķirība? Jo vienā gadījumā daži atmiņas jomā var piekļūt, tādējādi mums ir nepieciešams veikt šo adresi no atmiņas zonas, un indekss ir (patiesībā, mēs droši vien būtu noņemt pavairošanu, pārāk, jo tas ir kā masīvs integers parasti piekļūt, lai instrukcija būtu jākļūst: edi = &var_4068DC[eax];). Otrajā gadījumā, daži ciparu aprēķins ir veikts, un kompilators izvēlējās izmantot vienu lea mācību vietā ilgstošāku secība mul un add. Risinot šo problēmu, nav viegli.

Šie ir tikai daži piemērs. Kā jums ir redzams, kontroles plūsmas instrukcijas (lec, zvani) nav īstenoti ļoti labi, un, izmantojot mehāniskās tulkošanas metodi, kas aprakstīta iepriekš ātri rada nesalasāmas radīts C kodu, kas var kļūt uzpūsts, kad recompiled, lai mašīna kodu pēc tam, kad tulkojums.

Mēs skaidri ir nepieciešams labāks risinājums.