Domanda

Beh, sto studiando qualche assemblaggio in linea a Delfi e l'assemblaggio Crypto Routine sta andando tutto fantastico, finché non provo ad analizzare la corta cortaria nella casella di testo.

La violazione che ottengo è la seguente: Errore

Il codice completo è qui:

procedure TForm2.Button1Click(Sender: TObject);

var
len,keylen:integer;
name, key:ShortString;

begin

name :=  ShortString(Edit1.Text);
key := '_r <()<1-Z2[l5,^';
len := Length(name);
keylen := Length(key);

nameLen := len;
serialLen := keyLen;

asm

  XOR EAX,EAX
  XOR ESI,ESI
 XOR EDX,EDX
 XOR ECX,ECX


  @loopBegin:

        MOV EAX,ESI
        PUSH $019
        CDQ
        IDIV DWORD PTR DS:[serialLen]
        MOV EAX,ESI
        POP EBX
        LEA ECX,DWORD PTR DS:[key+EDX]
        CDQ
        IDIV DWORD PTR DS:[nameLen]
        LEA EAX,DWORD PTR DS:[name]
        MOVZX EAX,BYTE PTR DS:[name+EDX]
        MOVZX EDX,BYTE PTR DS:[ECX]
        XOR EAX,EDX
        CDQ
        IDIV EBX
        ADD DL,$041
        INC ESI
        CMP ESI,DWORD PTR DS:[serialLen]
        MOV BYTE PTR DS:[ECX],DL

        JL @loopBegin


end;

edit2.Text:= TCaption(key);


end;
.

Se metto un punto di interruzione sulla linea "edit2.text:= tcaption (tasto);"Posso vedere che la "chiave" a corto corta è stata correttamente crittografata correttamente, ma anche con molti personaggi strani dietro di esso.

I primi 16 caratteri è la vera crittografia.

Crittografia http://img831.imageshack.us/img831/365/29944312.PNG

bigger version: http://img831.imageshack.us/img831/365/29944312.png
.

Grazie!

È stato utile?

Soluzione

Qual è il codice

Per quelli di voi che non parlano assemblatore, questo è ciò che probabilmente il codice dovrebbe fare, a Pascal. "Probabilmente" perché l'originale contiene alcuni bug:

procedure TForm14.Button1Click(Sender: TObject);
var KeyLen:Integer;
    Name, Key:ShortString;
    i:Integer;
    CurrentKeyByte:Byte;
    CurrentNameByte:Byte;
begin
  Name := ShortString(Edit1.Text);
  Key := '_r <()<1-Z2[l5,^';
  keyLen := Length(key);

  asm int 3 end; // This is here so I can inspect the assembler output in the IDE
                 // for the "Optimised" version of the code

  for i:=1 to Length(Name) do
  begin
    CurrentKeyByte := Byte(Key[i mod KeyLen]);
    CurrentNameByte := Byte(Name[i]);
    CurrentNameByte := ((CurrentKeyByte xor CurrentNameByte) mod $019) + $041;
    Name[i] := AnsiChar(CurrentNameByte);
  end;

  Caption := Name;

end;
.

Con le ottimizzazioni accese, il codice Assembler generato da questo è in realtà più breve rispetto al codice proposto, non contiene alcun codice ridondante e sono disposto a scommettere è più veloce. Ecco alcune ottimizzazioni che ho notato nel codice generato dalphi ( rispetto al codice Assembler proposto dall'OP ):

    .
  • Delphi ha invertito il loop (fino a 0). Ciò consente di salvare un'istruzione "cmp" perché il compilatore può semplicemente "DEC ESI" e loop sulla bandiera Zero.
  • Utilizzato "XOR EDX" e "Div Ebx" per la seconda divisione, salvando una piccola quantità di cicli.

Perché il codice di assemblatore fornito è in mancanza?

Ecco il codice Assembler originale, con commenti. L'errore è alla fine della routine, nell'istruzione "CMP" - si confronta ESI alla lunghezza della chiave, non alla lunghezza del nome. Se il tasto è più lungo del nome, la "crittografia" continua sopra la parte superiore del nome, la sovrascrittura delle cose (tra le cose che viene sovrascritta è il terminatore nullo per la stringa, causando il debugger di mostrare carattere divertente dopo il carattere corretto).

Mentre la sovrascrittura di EBX ed ESI non è consentita, questo non è ciò che sta causando il codice all'AV, probabilmente perché il codice Delphi circostante non ha usato EBX o ESI (solo provarlo).

asm

 XOR EAX,EAX ; Wasteful, the first instruction in Loop overwrites EAX
 XOR ESI,ESI
 XOR EDX,EDX ; Wasteful, the first CDQ instruction in Loop overwrites EDX
 XOR ECX,ECX ; Wasteful, the first LEA instruction overwrites ECX


 @loopBegin:
       ; Etering the loop, ESI holds the index for the next char to be
       ; encrypted.

       MOV EAX,ESI ; Load EAX with the index for the next char, because
                   ; we intend to do some divisions (setting up the call to IDIV)
       PUSH $019   ; ? pushing this here, so we can pop it 3 lines later... obfuscation
       CDQ         ; Sign-extend EAX (required for IDIV)
       IDIV DWORD PTR DS:[serialLen] ; Divide EAX by the length of the key.
       MOV EAX,ESI ; Load the index back to EAX, we're planning on an other IDIV. Why???
       POP EBX     ; Remember the PUSH $019?
       LEA ECX,DWORD PTR DS:[key+EDX] ; EDX is the result of "ESI mod serialLen", this
                                      ; loads the address of the current char in the
                                      ; encryption key into ECX. Dividing by serialLen
                                      ; is supposed to make sure we "wrap around" at the
                                      ; end of the key
        CDQ ; Yet some more obfuscation. We're now extending EAX into EDX in preparation for IDIV.
            ; This is obfuscation becasue the "MOV EAX, ESI" instruction could be written right here
            ; before the CDQ.
        IDIV DWORD PTR DS:[nameLen] ; We divide the current index by the length of the text
                                    ; to be encrypted. Once more the code will only use the reminder,
                                    ; but why would one do this? Isn't ESI (the index) always supposed to
                                    ; be LESS THEN nameLen? This is the first sign of trouble.
        LEA EAX,DWORD PTR DS:[name] ; EAX now holds the address of NAME.
        MOVZX EAX,BYTE PTR DS:[name+EDX] ; EAX holds the current character in name
        MOVZX EDX,BYTE PTR DS:[ECX]      ; EDX holds the current character in Key
        XOR EAX,EDX ; Aha!!!! So this is an obfuscated XOR loop! EAX holds the "name[ESI] xor key[ESI]"
        CDQ         ; We're extending EAX (the XOR result) in preparation for a divide
        IDIV EBX    ; Divde by EAX by EBX (EBX = $019). Why????
        ADD DL,$041 ; EDX now holds the remainder of our previous XOR, after the division by $019;
                    ; This is an number from $000 to $018. Adding $041 turns it into an number from
                    ; $041 to $05A (ASCII chars from "A" to "Z"). Now I get it. This is not encryption,
                    ; this is a HASH function! One can't un-encrypt this (information is thrown away at
                    ; the division).
        INC ESI     ; Prep for the next char


        ; !!! BUG !!!
        ;
        ; This is what's causing the algorithm to generate the AV. At this step the code is
        ; comparing ESI (the current char index) to the length of the KEY and loops back if
        ; "ESI < serialLen". If NAME is shorter then KEY, encryption will encrypt stuff beyond
        ; then end of NAME (up to the length of KEY). If NAME is longer then KEY, only Length(Key)
        ; bytes would be encrypted and the rest of "Name" would be ignored.
        ;
        CMP ESI,DWORD PTR DS:[serialLen]


        MOV BYTE PTR DS:[ECX],DL ; Obfuscation again. This is where the mangled char is written
                                 ; back to "Name".

        JL @loopBegin            ; Repeat the loop.
.

I miei 2 centesimi di consiglio

Assembler deve essere utilizzato per le ottimizzazioni velocità e nient'altro . Mi guarda come se il OP abbia provato a utilizzare il montaggio per offuscare ciò che il codice sta facendo. Non mi ha aiutato, ci sono voluti solo pochi minuti per capire esattamente ciò che il codice sta facendo e sono non un esperto di assembler.

Altri suggerimenti

Prima di tutto, è necessario preservare EDI ed ESI.Solo EAX, EDX e ECX, può essere utilizzato senza conservazione (tranne quando lo carica e ne è necessario conservare).

Prova ad aggiungere un po 'di spinta EDI, spingere ESI e POP ESI, Pop EDI attorno al tuo codice.

Non è possibile semplicemente co-optare i registri per i propri scopi in Inline ASM senza preservare (salvataggio e ripristino) il contenuto del registro.

Nel tuo codice si sta calpestando su EAX (che tiene "Self") ed EDX (che - con il registro predefinito Register , più probabile tiene "mittente").

E come capisco che altri registri possono essere utilizzati anche per le variabili locali.

Suggerimento: cosa succede se ESI o EAX o qualunque cosa tiene sé?Il tuo assemblatore lo spazzalo.Prossima linea che stai cercando di usare Modifica2, che richiede l'accesso a sé, che è ... Beh, non più con noi.

Entrambi compilatore e usi registri.Devi giocare bene e collaborare con il compilatore, il che significa salvare / ripristinare i valori dei registri.

Altrimenti penso che sia necessario scaricare il codice di assemblatore per separare la routine, quindi non ci sarà alcun codice Pascal, che può utilizzare anche i registri.Nota, che è comunque necessario conformare il protocollo della Convenzione della chiamata: non tutti i registri possono essere utilizzati liberamente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top